Как закодировать расширенную информацию документов в штрихкод в 1С при нехватке символов в EAN-13?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При автоматизации складских процессов и адресного хранения типового функционала штрихкодирования часто оказывается недостаточно. Классический штрихкод формата EAN-13 позволяет хранить всего 12 значащих цифр (13-й символ является контрольной суммой). Когда в один штрихкод требуется поместить признак операции, код организации, номер накладной, год, этаж сборки или сразу несколько номеров документов для групповой печати, емкость EAN-13 исчерпывается.

В этой статье мы подробно разберем, почему возникает данное ограничение, как правильно перейти на универсальный стандарт Code 128, как генерировать штрихкод через внешние компоненты и шрифты, а также рассмотрим альтернативные архитектурные решения.

---

Анализ проблемы: EAN-13 против Code 128 и GS1-128

Проанализируем структуру штрихкодов, чтобы понять, какой стандарт выбрать для решения складских задач:

  1. EAN-13: строго фиксированный формат, поддерживающий только цифры от 0 до 9 и ограниченный 12 значащими разрядами. Попытка записать в него составные текстовые или длинные числовые данные невозможна без сложного битового сжатия.
  2. EAN-128 (GS1-128): специализированный стандарт логистической маркировки, использующий идентификаторы применения (Application Identifiers, AI) и служебный код старта FNC1. Для внутренних задач склада (внутрифирменная маркировка) данный стандарт избыточен и сложен в поддержке.
  3. Code 128: универсальный линейный штрихкод высокой плотности. Он позволяет кодировать все символы таблицы ASCII (включая цифры, латинские буквы и любые знаки-разделители, такие как #, ;, ,). Именно этот стандарт является оптимальным для кодирования составных параметров документов.

Рассмотрим несколько вариантов решения задачи расширенного штрихкодирования в 1С.

---

Решение 1. Использование Code 128 с разделителями данных

Разберем наиболее прямолинейный и удобный подход: кодирование параметров через символы-разделители. Мы формируем строковый штрихкод вида "ПРЕМ#000123#2024#ЭТ2" или "W00001444C0016".

Преимущества такого подхода:

  1. Штрихкод легко читается разработчиком при отладке.
  2. При сканировании сканер передает в 1С готовую строку в процедуру ОбработкаВнешнегоСобытия без необходимости вручную декодировать контрольные разряды — контрольная сумма проверяется сканером на аппаратном уровне.
  3. Длина параметров может быть переменной, если использовать однозначные разделители (например, # или ;).

Посмотрим на пример разбора считанного штрихкода в процедуре обработки сканирования:


// Процедура разбора считанного штрихкода формата Code 128
Процедура ОбработатьШтрихкод(Знач СтрШК)
    СтрШК = СокрЛП(СтрШК);
    
    // Преобразуем строку с разделителями в список значений
    СписокПараметров = СоздатьОбъект("СписокЗначений");
    СтрШК = СтрЗаменить(СтрШК, "#", РазделительСтрок);
    
    Для Индекс = 1 По СтрКоличествоСтрок(СтрШК) Цикл
        ТекЗнач = СтрПолучитьСтроку(СтрШК, Индекс);
        СписокПараметров.ДобавитьЗначение(ТекЗнач);
    КонецЦикла;
    
    Если СписокПараметров.РазмерСписка() >= 4 Тогда
        ТипДокумента   = СписокПараметров.ПолучитьЗначение(1);
        НомерДокумента = СписокПараметров.ПолучитьЗначение(2);
        ГодДокумента   = СписокПараметров.ПолучитьЗначение(3);
        ЭтажСборки     = СписокПараметров.ПолучитьЗначение(4);
        
        Сообщить("Считан документ: " + ТипДокумента + " № " + НомерДокумента + " за " + ГодДокумента + " г., Этаж: " + ЭтажСборки);
    Иначе
        Предупреждение("Неверный формат штрихкода документа!");
    КонецЕсли;
КонецПроцедуры

---

Решение 2. Формирование штрихкода Code 128 через шрифт (для 1С 7.7)

Если в конфигурации не используется внешняя компонента 1CBarCod.ocx, штрихкод можно вывести при помощи специального TrueType-шрифта (например, Barcode или Code128). Для этого исходную строку необходимо преобразовать по алгоритму расчета контрольной суммы mod 103 и расстановки стартовых/стоповых символов.

Рассмотрим алгоритм подготовки строки для шрифта Code 128 на встроенном языке 1С 7.7:


// Функция определения типа символа
Функция ТипСимв(КодСмв)
    Если КодСмв < 32 Тогда 
        Возврат(1); // Служебная команда
    ИначеЕсли (48 <= КодСмв) И (КодСмв <= 57) Тогда 
        Возврат(3); // Цифра
    Иначе 
        Возврат(2); // Буква, знак
    КонецЕсли;    
КонецФункции

// Функция вычисления остатка от деления
Функция Мод(Ч, З)
    Возврат(Ч - Цел(Ч / З) * З);
КонецФункции

// Основная функция генерации строки штрихкода Code 128 для шрифта
Функция БарКод(Вход, БазаМодеС = 6)
    АскиБар = 
    "155515551449485845458494854548584944056416452065425461560506542164524212245605641254614650" +
    "11919191108980988109881889018890898001:0928120290:18212211829021281:0122209281:01218290:10" +
    "2305<0;0004=0<540=4<1<05<4105<0=441<4=0<14<50=4050<320=04830047407443074434470344704740113" +
    "13131100;0838030380;0308380023032203302";

    ВыхТ = СоздатьОбъект("ТаблицаЗначений");
    ВыхТ.НоваяКолонка("А",,,,"Аск", 4);

    Если Вход = "" Тогда 
        Возврат(""); 
    КонецЕсли;
    
    ВыхТ.УдалитьСтроки();
    Дл = СтрДлина(СокрЛП(Вход));
    
    ТекСимв = КодСимв(Сред(Вход, 1, 1));
    ТипТекСимв = ТипСимв(ТекСимв);
    
    Если Дл > 1 Тогда
        СлСимв = КодСимв(Сред(Вход, 2, 1));
        ТипСлСимв = ТипСимв(СлСимв);
    Иначе
        ТипСлСимв = 2;
    КонецЕсли;
    
    Моде = ТипТекСимв;
    Если (ТипТекСимв = 3) И (ТипСлСимв = 3) Тогда 
        Моде = 3; 
    КонецЕсли;
    
    ВыхТ.НоваяСтрока();
    ВыхТ.А = 102 + Моде;
    Вых = Симв(64 + Моде);    
    
    Для Сч = 1 По Дл Цикл
        ТекСимв = КодСимв(Сред(Вход, Сч, 1));
        Если ТекСимв > 127 Тогда 
            Сообщить("Символ № " + Сч + " со значением = " + ТекСимв + " не разрешен в штрихкоде");
            Продолжить;
        КонецЕсли;    
        
        ТипТекСимв = ТипСимв(ТекСимв);
        
        Если ТипТекСимв <> Моде Тогда
            Если ТипТекСимв < 3 Тогда
                ВыхТ.НоваяСтрока();
                Если Моде = 1 Тогда
                    ВыхТ.А = 100; // Переключение в режим B
                Иначе    
                    ВыхТ.А = 101; // Переключение в режим A
                КонецЕсли;
                Моде = ТипТекСимв;
            Иначе
                ДлМ = ?(Дл < Сч + БазаМодеС - 1, Дл, Сч + БазаМодеС - 1);
                СчЦ = 0;
                Для СчМ = Сч По ДлМ Цикл
                    МодМ = ТипСимв(КодСимв(Сред(Вход, СчМ, 1)));
                    Если МодМ = 3 Тогда 
                        СчЦ = СчЦ + 1;
                        Продолжить; 
                    Иначе
                        СчЦ = 0;
                        Прервать;
                    КонецЕсли;
                КонецЦикла;
                
                Если СчЦ - БазаМодеС = 0 Тогда
                    Моде = 3;
                    ВыхТ.НоваяСтрока();
                    ВыхТ.А = 99; // Переключение в режим C
                КонецЕсли;
            КонецЕсли;        
        КонецЕсли;        
        
        Если Моде = 3 Тогда
            СлСимв = КодСимв(Сред(Вход, Сч + 1, 1));
            ТипСлСимв = ТипСимв(СлСимв);
            Если (Сч = Дл) Или (ТипТекСимв <> 3) Или (ТипСлСимв <> 3) Тогда
                Моде = 2;
                ВыхТ.НоваяСтрока();
                ВыхТ.А = 100;   
            Иначе
                ВыхТ.НоваяСтрока();
                ВыхТ.А = Число(Симв(ТекСимв) + Симв(СлСимв));
                Сч = Сч + 1;
                Продолжить;
            КонецЕсли;
        КонецЕсли;
        
        ВыхТ.НоваяСтрока();
        Если Моде = 1 Тогда
            ВыхТ.А = ТекСимв + 64;
        Иначе
            ВыхТ.А = ТекСимв - 32;
        КонецЕсли;    
    КонецЦикла;
    
    ВыхТ.ВыбратьСтроки();
    Сум = 0;
    Ном = 0;
    Пока ВыхТ.ПолучитьСтроку() = 1 Цикл
        Если Ном > 0 Тогда 
            Сум = Мод(Сум + ВыхТ.А * Ном, 103);
            Вых = Вых + Сред(АскиБар, (ВыхТ.А + 1) * 3 - 2, 3);
        Иначе    
            Сум = Мод(ВыхТ.А, 103);
        КонецЕсли;
        Ном = Ном + 1;
    КонецЦикла;
    
    Возврат(Вых + Сред(АскиБар, (Сум + 1) * 3 - 2, 3) + "@");
КонецФункции

Сформированная строка передается в ячейку печатной формы, для которой установлен шрифт Barcode.

---

Решение 3. Упаковка множества реквизитов в стандартный EAN-13 (Битовое кодирование)

Если на предприятии принципиально используются сканеры, настроенные исключительно на EAN-13, либо требуется сохранить компактность штрихкода на термоэтикетках, параметры можно упаковать в 12 десятичных цифр с помощью шестнадцатеричной/позиционной конвертации.

Проанализируем схему распределения байт:

  1. 1 байт: признак перемещения (0/1) + код фирмы (до 127 организаций).
  2. 2 байта: номер документа (число от 0 до 65535).
  3. 1 байт: год (смещение от базового года, до 255 лет).
  4. 1 байт: номер этажа или склада (до 255).

Итого 5 байт (10 шестнадцатеричных символов), что в десятичном представлении дает число до 1 099 511 627 775, которое гарантированно помещается в 12 знаков EAN-13.

Посмотрим на пример функций кодирования и декодирования (1С:Предприятие 8 / управляемые формы):


&НаКлиенте
Функция Код(Значение, знач Байт)
    Р = DecToAny(Значение, 16); // Перевод в шестнадцатеричную систему
    Д = СтрДлина(Р);
    Байт = Байт * 2;
    Если Д < Байт Тогда
        Для Счетчик = 1 По Байт - Д Цикл
            Р = "0" + Р;
        КонецЦикла;
    КонецЕсли;
    Возврат Р;
КонецФункции

&НаКлиенте
Функция КодироватьВEAN13(ЭтоПеремещение, Фирма, Номер, Год, Этаж)
    Признак = ?(ЭтоПеремещение = 1, 128, 0);
    Р = Код(Признак + Фирма, 1);
    Р = Р + Код(Номер, 2);
    Р = Р + Код(Год, 1);
    Р = Р + Код(Этаж, 1);
    
    // Переводим 16-ричную строку обратно в десятичное 12-значное число
    Результат12Знаков = AnyToDec(Р, 16);
    
    // Дописываем контрольный символ EAN-13
    Возврат ДописатьКонтрольныйСимволEAN13(Результат12Знаков);
КонецФункции

&НаКлиенте
Функция ДекодироватьИзEAN13(знач ШтрихкодEAN13, ЭтоПеремещение, Фирма, Номер, Год, Этаж)
    // Убираем контрольный 13-й символ
    Зн = Сред(ШтрихкодEAN13, 1, 12);
    ШестнСтрока = DecToAny(Число(Зн), 16);
    ШестнСтрока = Код(ШестнСтрока, 5);
    
    Байт1 = AnyToDec(Сред(ШестнСтрока, 1, 2), 16);
    ЭтоПеремещение = ?(Байт1 > 127, 1, 0);
    Фирма = ?(ЭтоПеремещение = 0, Байт1, Байт1 - 128);
    Номер = AnyToDec(Сред(ШестнСтрока, 3, 4), 16);
    Год = AnyToDec(Сред(ШестнСтрока, 7, 2), 16);
    Этаж = AnyToDec(Сред(ШестнСтрока, 9, 2), 16); 
    
    Возврат Истина;
КонецФункции

---

Решение 4. Архитектурный подход через документ-агрегатор («Задание на сборку»)

При групповой печати перемещений попытка «впихнуть» в один линейный штрихкод список из 5–10 документов приводит к резкому росту длины штрихкода (до 15–20 см). Считывать такой широкий код ручным сканером крайне неудобно.

Наиболее масштабируемое решение — отказаться от кодирования всех реквизитов внутри самого штрихкода и применить агрегацию:

  1. В базе 1С создается отдельный документ или справочник — «Задание на сборку» (маршрутный лист).
  2. При групповой печати система формирует этот документ, записывая в его табличную часть ссылки на все сгруппированные перемещения, этажи и товары.
  3. Штрихкодируется исключительно уникальный номер задания на сборку (он короткий и легко кодируется стандартным EAN-13 или Code 128).
  4. Кладовщик сканирует один код маршрутного листа, после чего 1С автоматически открывает всё дерево связанных перемещений и блокирует повторное сканирование уже отработанных строк.

---

Резюме и рекомендации

  1. Для внутренних документов предприятия используем Code 128 — он снимает любые ограничения по длине и составу символов.
  2. Если используется внешняя компонента (например, 1CBarCod.ocx), достаточно просто передать строку с разделителями (# или ;), расчет контрольных сумм компонента выполнит самостоятельно.
  3. При использовании шрифтовой печати применяем функцию пересчета в формат Code 128.
  4. Для групповой сборки нескольких документов создаем агрегирующий документ («Задание на сборку»), чтобы не перегружать физический размер штрихкода на бумаге.
← На главную