С введением обязательной маркировки товаров перед разработчиками 1С встала задача корректной передачи сведений о маркированных изделиях в фискальный накопитель. В формате фискальных документов (ФФД) версии 1.05 за передачу кода маркировки отвечал тег 1162 («Код товара»). При работе с торговым оборудованием марки «Штрих-М» программисты часто сталкиваются с ситуацией, когда данные в драйвер вроде бы уходят, но в ОФД и на чеке признак маркировки не появляется. Выясним причины этой проблемы, разберем правильную последовательность вызова методов драйвера и приведем примеры готового кода для интеграции.
Проанализируем ситуацию, описанную разработчиками. Чаще всего при попытке зафиксировать продажу маркированного товара (например, обуви или табака) на старых прошивках и драйверах возникает ошибка «Неверное значение в поле длины» или данные попросту игнорируются ККТ. Это происходит по трем основным причинам:
FNOperation() приводит к тому, что драйвер очищает эти свойства или не связывает их с текущей позицией в чеке.DrvFR v4.14.0.792 и прошивках конца 2018 — начала 2020 года.Рассмотрим самый простой и надежный способ передачи данных, который поддерживается драйверами ШТРИХ-М версии 4.14.0.792 и выше. В данном сценарии нам не нужно вручную формировать шестнадцатеричные (HEX) байты — драйвер сделает это самостоятельно на основе переданных параметров GTIN и SerialNumber.
Разберем по шагам правильную последовательность действий в коде 1С:
FNOperation() для открытия фискальной операции по позиции.MarkingType. Обратите внимание: значения типов маркировки жестко регламентированы. Например, для обуви следует передавать значение 17485 (что соответствует шестнадцатеричному коду 44 4D — DM, DataMatrix), а не старый код 5408. Для меховых изделий используется код 21062 (HEX: 52 46 — RF).GTIN (строка из 14 символов) и серийный номер SerialNumber (строка из 13 символов). Выделять их из общего сканированного штрихкода маркировки придется программно.FNSendItemCodeData() для отправки сформированного тега в ФН.Посмотрим на пример практической реализации данного алгоритма на встроенном языке 1С:
// Предварительно выделяем GTIN и серийный номер из считанного штрихкода DataMatrix
// Например, для кода: 010290000072511921KUp"cEi>'KcVa91...
// GTIN (14 символов) будет: "02900000725119"
// Серийный номер (13 символов) будет: "KUp"cEi>'KcVa"
глФР.StringForPrinting = "Обувь женская кожаная";
глФР.Quantity = 1;
глФР.Price = 1500.00;
глФР.Department = 1;
глФР.Tax1 = 4; // Без НДС или соответствующая ставка
// Открываем операцию регистрации позиции
Result = глФР.FNOperation();
Если Result = 0 Тогда
// Заполняем параметры маркировки ПОСЛЕ вызова FNOperation()
глФР.MarkingType = 17485; // Код для обуви (DataMatrix)
глФР.GTIN = "02900000725119";
глФР.SerialNumber = "KUp""cEi>'KcVa"; // Обратите внимание на экранирование кавычек
// Фиксируем отправку кода маркировки в ФН
глФР.FNSendItemCodeData();
КонецЕсли;
В некоторых случаях (например, при работе на старых версиях прошивок ККТ, где штатные функции разбора строк работают некорректно, или на нетиповых конфигурациях 1С 7.7) может потребоваться ручное формирование структуры TLV (Tag-Length-Value) и отправка ее в кассу напрямую через буфер драйвера. Для этого используется метод FNSendTLVOperation().
Структура тега 1162 состоит из:
Рассмотрим по шагам функции перевода чисел в HEX-формат и реверсирования байт, а также саму процедуру записи произвольного тега на позицию:
// Функция перевода десятичного числа в шестнадцатеричную строку с заданной кратностью длины
Функция DecToHex(Знач Зн, Знач КратностьДлины = 1) Экспорт
КратностьДлины = Цел(КратностьДлины);
Если КратностьДлины < 1 Тогда
КратностьДлины = 1;
КонецЕсли;
ч = Число(Зн);
Рез = "";
к = КратностьДлины;
Пока Истина Цикл
Если к = 0 Тогда
к = КратностьДлины;
КонецЕсли;
к = к - 1;
д = ч / 16;
ц = Цел(д);
д = ч - ц * 16;
Рез = ?(д < 10, Формат(д, "ЧН=0"), ?(д = 10, "A", ?(д = 11, "B", ?(д = 12, "C", ?(д = 13, "D", ?(д = 14, "E", "F")))))) + Рез;
ч = ц;
Если ч = 0 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Пока к > 0 Цикл
к = к - 1;
Рез = "0" + Рез;
КонецЦикла;
Возврат Рез;
КонецФункции
// Функция изменения порядка байт на обратный (Little-Endian)
Функция ПолучитьБайтыВОбратномПорядке(Знач Стр)
Рез = "";
КоличествоБайт = СтрДлина(Стр);
Для ж = 1 По КоличествоБайт / 2 Цикл
Рез = Рез + Сред(Стр, КоличествоБайт - ж * 2 + 1, 2);
Стр = Лев(Стр, СтрДлина(Стр) - 2);
КонецЦикла;
Возврат Рез;
КонецФункции
// Процедура отправки сформированного тега в ФР
Процедура ЗаписатьПроизвольныйТэгНаПозицию(ФР, Знач НомерТэга_инт, Знач ЗначениеТэга_hex)
// Формируем HEX-код номера тега (для 1162 это будет "8A04")
НомерТэга_hex = ПолучитьБайтыВОбратномПорядке(DecToHex(НомерТэга_инт, 4));
// Вычисляем длину значения в байтах и переводим в HEX
ДлинаТэга_hex = ПолучитьБайтыВОбратномПорядке(DecToHex(Окр(СтрДлина(ЗначениеТэга_hex) / 2), 4));
// Собираем полную структуру TLV и передаем ее драйверу
ФР.TLVDataHex = НомерТэга_hex + ДлинаТэга_hex + ЗначениеТэга_hex;
ФР.FNSendTLVOperation();
КонецПроцедуры
Описанные выше алгоритмы и примеры кода актуальны для формата фискальных документов ФФД 1.05. Однако в рамках повсеместного перехода на ФФД 1.2 требования к работе с маркировкой существенно изменились. Проанализируем ключевые отличия, которые необходимо учитывать при обновлении кассового ПО:
GS (Group Separator, ASCII-код 29). Если сканер настроен неверно (например, работает в режиме простой эмуляции клавиатуры и отбрасывает этот символ), касса выдаст ошибку формата данных при попытке разобрать марку.BeginMarkingCodeCheck, AddMarkingCodeCheckResult и т.д.).Таким образом, если ваши клиенты продолжают работать на ФФД 1.05, использование методов FNSendItemCodeData() с явным указанием MarkingType, GTIN и SerialNumber после вызова FNOperation() полностью решает проблему незаполненного тега 1162. При планировании же перехода на ФФД 1.2 следует пересмотреть архитектуру взаимодействия с ККТ и перейти на использование современных методов драйверов Штрих-М версии 5.x, осуществляющих передачу полного кода маркировки с обязательной онлайн-проверкой.