Как правильно сформировать штрихкод GS1 в 1С, передать спецсимвол FNC1 (GS) без ошибок и настроить ТСД?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При внедрении обязательной маркировки («Честный Знак», маркировка лекарственных препаратов, табака, обуви) и логистического учета разработчики 1С массово сталкиваются со спецификой штрихкодов стандартов GS1-128 и GS1 DataMatrix. Основная сложность заключается в корректной работе с управляющими символами-разделителями и настройке оборудования для сканирования готовой маркировки.

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

  1. Как правильно закодировать разделитель полей переменной длины в стандарте GS1.
  2. Почему 1С аварийно завершает работу (крэшится) при передаче строки со спецсимволом Символ(29) между сервером и клиентом и как это обойти.
  3. Почему терминалы сбора данных (ТСД) отказываются считывать корректно сформированные штрихкоды, если GTIN начинается с нуля.

---

1. Понимание структуры GS1: Когда нужен разделитель GS (ASCII 29) и FNC1

Прежде чем приступать к кодированию, проанализируем логику стандартов GS1. Штрихкод формата GS1 состоит из последовательности Идентификаторов Применения (AI — Application Identifiers) и идущих за ними значений.

Идентификаторы применения бывают двух типов:

Для указания окончания поля переменной длины используется специальный непечатный управляющий символ GS (Group Separator), имеющий код ASCII 29. В коде 1С он задается как Символ(29). В самом начале штрихкода также неявно присутствует стартовый символ FNC1, который сообщает сканеру, что перед ним именно код стандарта GS1.

Рассмотрим пример формирования строки штрихкода. Если у нас идет партия (длиной менее 20 символов), а за ней — вес товара, мы обязаны разделить их:


// Пример ручной склейки штрихкода со спецсимволом ASCII 29
СтрокаПартия = "LOT12345"; // Длина меньше 20 символов
Штрихкод = "[01]04601234567890" + "[10]" + СтрокаПартия;

// Если партия идет не в самом конце, добавляем разделитель GS (ASCII 29)
Если СтрДлина(СтрокаПартия) < 20 Тогда
    Штрихкод = Штрихкод + Символ(29);
КонецЕсли;

Штрихкод = Штрихкод + "[3103]000504"; // Добавляем следующий идентификатор применения

---

2. Почему падает 1С при передаче Символ(29) и как это исправить

Выясним причину технического сбоя, упомянутого в сообщении 5. Разработчик попытался передать сформированную строку со спецсимволом Символ(29) с сервера на клиент для отправки в компоненту печати, что вызвало моментальный краш платформы 1С.

Дело в том, что передача данных между контекстами сервера и клиента в управляемом приложении 1С выполняется посредством сериализации данных в XML (или JSON). Согласно стандарту XML 1.0, управляющие ASCII-символы в диапазонах 0-8, 11-12 и 14-31 являются запрещенными (illegal characters). Символ с кодом 29 попадает в этот запрещенный диапазон. Попытка упаковать такую строку в XML-пакет для передачи по сети вызывает критическую ошибку сериализатора XDTO и падение процесса 1С.

Рассмотрим три надежных способа обхода этой проблемы.

Способ А. Формирование картинки штрихкода на стороне сервера (Рекомендуемый)

Самый правильный и архитектурно чистый подход, используемый в современных конфигурациях на базе БПО (Библиотеки подключаемого оборудования) и УТ 11.4 / ERP. Вместо того чтобы передавать «опасную» строку со спецсимволами на клиент, мы генерируем картинку штрихкода непосредственно на сервере, используя внешнюю компоненту печати штрихкодов от 1С. Полученные двоичные данные картинки абсолютно безопасны для передачи на клиент.

Проанализируем пример кода генерации картинки на сервере:


Функция ПолучитьКартинкуШтрихкодаНаСервере(ЗначениеШтрихкода, ТипКода) Экспорт
    
    // Подключаем внешнюю компоненту печати штрихкодов из макета
    УстановитьРасширениеРаботыСФайлами();
    ИмяПути = КаталогВременныхФайлов() + "Barcode.dll";
    МакетКомпоненты = Справочники.ШаблоныЭтикетокИЦенников.ПолучитьМакетКомпоненты(); // или из ОбщиеМакеты
    МакетКомпоненты.Записать(ИмяПути);
    
    Попытка
        ПодключитьВнешнююКомпоненту(ИмяПути, "Barcode", ТипВнешнейКомпоненты.Native);
        Компонента = Новый("AddIn.Barcode.Barcode");
    Исключение
        ЗаписьЖурналаРегистрации("Печать Штрихкода", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        Возврат Неопределено;
    КонецПопытки;
    
    // Настраиваем параметры генерации картинки
    Компонента.Параметры.Ширина = 400;
    Компонента.Параметры.Высота = 150;
    Компонента.Параметры.ТипКода = ТипКода; // Например, 17 для GS1-128 или 24 для GS1-DataMatrix
    Компонента.Параметры.Штрихкод = ЗначениеШтрихкода;
    Компонента.Параметры.ОтображатьТекст = Истина;
    
    // Получаем двоичные данные картинки (PNG/BMP)
    ДвоичныеДанныеКартинки = Компонента.ПолучитьКартинку();
    
    Возврат ДвоичныеДанныеКартинки;
КонецФункции

Способ Б. Экранирование спецсимволов при передаче

Если вам все же необходимо пересылать строку на клиент для последующей обработки локальным драйвером торгового оборудования, примените механизм временного экранирования. Перед передачей строки с сервера замените Символ(29) на безопасную текстовую заглушку, а на стороне клиента, непосредственно перед отправкой в компоненту, выполните обратную замену.

Рассмотрим реализацию этого метода на практике:


// На СЕРВЕРЕ заменяем запрещенный символ на безопасный маркер
Функция ПодготовитьШКДляОтправкиНаКлиент(ИсходныйШтрихкод) Экспорт
    БезопасныйШтрихкод = СтрЗаменить(ИсходныйШтрихкод, Символ(29), "[GS]");
    Возврат БезопасныйШтрихкод;
КонецФункции

// На КЛИЕНТЕ производим обратную конвертацию непосредственно перед печатью
Процедура НапечататьШтрихкодНаКлиенте(БезопасныйШтрихкод)
    // Восстанавливаем символ ASCII 29 прямо на клиенте в локальной памяти
    ШтрихкодДляКомпоненты = СтрЗаменить(БезопасныйШтрихкод, "[GS]", Символ(29));
    
    // Передаем строку напрямую в объект локальной компоненты печати
    ОбъектКомпоненты.Штрихкод = ШтрихкодДляКомпоненты;
    ОбъектКомпоненты.Напечатать();
КонецПроцедуры

Способ В. Кодирование в Base64

Еще один надежный способ межконтекстной передачи строк со спецсимволами — кодирование строки в Base64. Строка Base64 состоит исключительно из безопасных латинских букв и цифр, что исключает любые ошибки XML-сериализации.


// Кодирование на сервере
ДвоичныеДанныеСтроки = ПолучитьДвоичныеДанныеИзСтроки(ШтрихкодСоСпецсимволом);
СтрокаBase64 = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанныеСтроки);

// Декодирование на клиенте
ДвоичныеДанныеИзBase64 = ПолучитьДвоичныеДанныеИзBase64Строки(СтрокаBase64);
ШтрихкодДляПечати = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеИзBase64);

---

3. Использование стандартных возможностей БПО и 1С:Печать штрихкодов

Разберем по шагам, как современные версии 1С (начиная с БПО и УТ 11.4) решают задачу автоматического разбора GS1. Разработчикам больше не требуется вручную определять длины полей и конструировать строки с символами Символ(29).

Современная «Компонента печати штрихкодов» от 1С умеет самостоятельно парсить входную строку в человекочитаемом формате (со скобками) и преобразовывать ее в корректный штрихкод со всеми необходимыми разделителями GS и лидирующим FNC1.

Посмотрим на пример работы с общим модулем ШтрихкодыУпаковокКлиентСервер, представленным в сообщении 15:


// Входная строка штрихкода в читаемом формате: (01)04601234567890(10)LOT12345(3103)000504
ЧтениеШтрихкода = ШтрихкодыУпаковокКлиентСервер.ПараметрыШтрихкода(СокрЛП(ВходнойШтрихкод));

Если НЕ ЧтениеШтрихкода.Результат = Неопределено Тогда
    Если ЧтениеШтрихкода.ТипШтрихкода = Перечисления.ТипыШтрихкодов.GS1_128 Тогда
        
        // Получаем специальный разделитель окончания строки переменной длины
        Разделитель = ШтрихкодыУпаковокКлиентСервер.СимволОкончанияСтрокиПеременнойДлины();
        
        // Метод автоматически уберет скобки (), расставит Символ(29) в нужные места
        ЗначениеШтрихкодаДляКомпоненты = ШтрихкодыУпаковокКлиентСервер.ШтрихкодGS1(
            ЧтениеШтрихкода.Результат, 
            Истина, 
            Разделитель
        );
    КонецЕсли;
КонецЕсли;

Передавая полученную строку ЗначениеШтрихкодаДляКомпоненты в компоненту печати штрихкодов с типом кода 17 (GS1-128) или 24 (GS1-DataMatrix), вы гарантированно получите стандартный штрихкод, полностью соответствующий спецификации GS1.

---

4. Решение проблемы со сканированием ведущих нулей на ТСД

Рассмотрим важнейшую проблему, описанную в сообщении 17: почему штрихкод вида [01]0460... (где GTIN товара начинается с нуля) не читается терминалом сбора данных, в то время как код вида [01]9460... распознается без каких-либо сложностей?

Проанализируем аппаратную и программную причины этой проблемы и пути их решения.

Причина А. Настройка сканера «Преобразование UPC в EAN» и срез ведущих нулей

Большинство современных ТСД и сканеров штрихкодов «из коробки» настроены по американским стандартам розничной торговли. В США базовым стандартом кодирования товаров является 12-значный формат UPC-A. Европейский стандарт EAN-13 и международный 14-значный GTIN-14 (используемый в GS1) шире на один или два знака.

Когда сканирующий модуль ТСД видит, что код начинается с нуля (например, 04601234567890), он ошибочно считает этот ноль «техническим префиксом заполнения» и автоматически отбрасывает (обрезает) его, преобразуя данные в стандарт UPC-A.

Что происходит в системе: Длина поля GTIN (идентификатор применения [01]) строго фиксирована спецификацией GS1 и составляет 14 символов. Так как сканер обрезал ведущий ноль, длина считанного значения GTIN составила 13 символов. Из-за этого вся последующая цепочка разбора GS1-кода в ТСД или в 1С ломается (сбивается смещение полей), софт считает штрихкод поврежденным и выдает ошибку чтения.

Причина Б. Отключенное распознавание символики GS1-128

Если на ТСД в настройках сканера включена только поддержка стандартного Code 128, но отключена поддержка GS1-128 (UCC/EAN-128), сканер не распознает логическую структуру данных, не видит маркер FNC1 и передает код как сплошной текст, попутно искажая управляющие символы и отбрасывая нули.

Пошаговая инструкция по настройке ТСД для устранения проблемы:

Для исправления этой ситуации необходимо перенастроить встроенный сканирующий модуль терминала (через утилиты DataWedge на устройствах Zebra, ScanService на Honeywell / Intermec или системное приложение настройки сканера на устройствах Urovo, Chainway, iData):

  1. Откройте приложение настройки сканера на вашем ТСД.
  2. Перейдите в раздел настройки символик (Symbology Settings или Decoder Settings).
  3. Найдите пункт GS1-128 (или UCC/EAN-128) и переведите его в состояние Enabled (Включено).
  4. Перейдите в настройки символик UPC/EAN.
  5. Найдите и отключите (Disabled) опции:
    • Convert UPC-A to EAN-13
    • Convert EAN-13 to UPC-A
    • Strip Leading Zero (Удалять ведущий ноль)
  6. Найдите параметр Transmit AIM ID (или Transmit Code ID Character) и включите его. Это позволит сканеру передавать в систему специальный префикс, подтверждающий, что считан именно корректный штрихкод GS1.
  7. Сохраните конфигурационный профиль сканера и протестируйте считывание штрихкода в 1С.

После отключения функций обрезки нулей сканер будет передавать полный 14-значный GTIN, начинающийся с 0, структура штрихкода GS1 будет сохранена в целости, и 1С сможет безошибочно распознавать отсканированные коды маркировки.

← На главную