При работе в терминальном режиме (RDP) разработчики часто сталкиваются с аппаратными ограничениями торгового оборудования. Драйвер АТОЛ ДТО-10 требует для своей работы запущенную фоновую службу fdsvc, которая не всегда корректно функционирует в мультипользовательской среде RDP без дополнительных сложных настроек. Из-за этого многие торговые точки продолжают использовать старый, проверенный временем драйвер АТОЛ ДТО-8. Однако при внедрении обязательной маркировки товаров возникает закономерный вопрос: как передать обязательный тег 1162 (код товарной номенклатуры) на ККТ, используя ДТО-8?
В этой статье мы подробно разберем, почему стандартный обмен через XML-пакеты в ДТО-8 не работает для маркированной продукции, как правильно преобразовать считанный код маркировки в байтовый формат и как передать эти данные на кассу напрямую через COM-объект драйвера.
В типовых конфигурациях 1С обмен с кассовым оборудованием реализован через промежуточные XML-файлы (так называемые XML-пакеты), которые передаются в библиотеку подключаемого оборудования (БСП). При этом для передачи маркировки используется атрибут productCode или структура GoodCodeData.
Попытка передать туда готовую Base64-строку вида AAUAAALBHl5BRGdvcFNx ни к чему не приводит — в ОФД чек все равно уходит без признака маркировки. Выясним причину этого поведения. Дело в том, что внутренняя библиотека-обертка 1С для работы с ДТО-8 просто "не знает" о существовании тега 1162 в контексте XML-структуры, либо некорректно транслирует типы данных. Для передачи тега 1162 требуется тип значения "массив байтов" (двоичные данные), в то время как XML-атрибуты передаются как обычные строки. Совместить стандартный XML-обмен БСП и отправку двоичных тегов в ДТО-8 напрямую не получится. Решением является отказ от XML-обертки и переход на прямую работу с COM-объектом драйвера.
Перед тем как отправить данные в ККТ, нам необходимо правильно сформировать значение тега 1162. Для табачной продукции по ФФД 1.05 код маркировки должен быть преобразован в шестнадцатеричный (HEX) вид по строго определенному шаблону.
Рассмотрим структуру байтового массива для табака:
00 05 (в некоторых новых спецификациях допускается единый префикс 44 4D, но 00 05 гарантированно поддерживается старыми прошивками).Разберем конкретный пример. Пусть сканер считал штрихкод пачки сигарет: 010000004621065421ADgopSq91...
Выполним преобразование по шагам:
00000046210654 (в десятичном виде это число 46210654). Переводим его в HEX: 2C11E5E. Дополняем нулями слева до 6 байт: 00 00 02 C1 1E 5E.ADgopSq. Переводим каждый символ в ASCII-код (в HEX):
4144676F70537141 44 67 6F 70 53 71.
00 05:
00 05 00 00 02 C1 1E 5E 41 44 67 6F 70 53 71
Если перевести этот массив байтов в формат Base64, то мы получим как раз строковое значение AAUAAALBHl5BRGdvcFNx. Но для ДТО-8 нам понадобится именно HEX-представление — строка байтов, разделенная пробелами.
Для прямого управления кассой нам необходимо подключить внешнюю компоненту и создать COM-объект драйвера ККТ. Посмотрим, как реализовать это в коде 1С:
Функция ПодключитьДрайверАтол8()
Попытка
// Пытаемся загрузить компоненту из системного реестра
Драйвер = Новый COMОбъект("AddIn.FprnM45");
Исключение
// Если объект не зарегистрирован, пробуем загрузить библиотеку явно
Попытка
ЗагрузитьВнешнююКомпоненту("FPRNM1C.dll");
Драйвер = Новый COMОбъект("AddIn.FprnM45");
Исключение
ЗаписьЖурналаРегистрации("ПодключениеККТ", УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось загрузить драйвер АТОЛ ДТО-8: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецПопытки;
Возврат Драйвер;
КонецФункции
Обратите внимание: чтобы избежать ошибок при работе в терминальных сессиях, библиотека FPRNM1C.dll должна быть установлена на сервере с помощью официального инсталлятора АТОЛ, либо находиться в каталоге платформы 1С или в папке с базой данных.
Теперь рассмотрим ключевую часть решения. Передача тегов позиций в ДТО-8 должна производиться строго внутри метода формирования товарной строки. Для этого используются методы BeginItem() и EndItem().
Чтобы драйвер понял, что мы передаем не текстовую строку, а именно массив байтов для тега 1162, нам необходимо установить свойство StreamFormat в значение 5 (двоичный формат данных).
Проанализируем пример кода фискализации позиции с передачей кода маркировки:
Процедура НапечататьЧекСМаркировкой(Драйвер, ДанныеЧека)
// Подготовка устройства к работе
Драйвер.DeviceEnabled = Истина;
Если Драйвер.ResultCode <> 0 Тогда
ВызватьИсключение "Ошибка подключения кассы: " + Драйвер.ResultDescription;
КонецЕсли;
// Входим в режим регистрации чеков (пароль по умолчанию "30" или "1")
Драйвер.Password = "30";
Драйвер.Mode = 1;
Драйвер.SetMode();
// Открываем чек продажи (1 - продажа, 0 - без предварительного сброса)
Драйвер.CheckType = 1;
Драйвер.CheckMode = 0;
Драйвер.OpenCheck();
// Обходим все позиции чека
Для Каждого СтрокаТовара Из ДанныеЧека.Товары Цикл
// Начинаем формирование фискальной строки
Драйвер.BeginItem();
// Заполняем базовые реквизиты номенклатуры
Драйвер.Name = СтрокаТовара.Наименование;
Драйвер.Price = СтрокаТовара.Цена;
Драйвер.Quantity = СтрокаТовара.Количество;
Драйвер.ItemType = 1; // 1 - Товар
Драйвер.PaymentMode = 4; // 4 - Полный расчет
Драйвер.TaxTypeNumber = 2; // Номер налоговой ставки в ККТ (например, НДС 20%)
// Если товар подлежит маркировке, передаем тег 1162
Если ЗначениеЗаполнено(СтрокаТовара.КодМаркировкиHex) Тогда
// Устанавливаем формат потока 5 (двоичный массив байтов)
Драйвер.StreamFormat = 5;
Драйвер.AttrNumber = 1162;
// Передаем HEX-строку, сформированную ранее (байты через пробел)
Драйвер.AttrValue = СтрокаТовара.КодМаркировкиHex;
// Записываем атрибут внутрь буфера текущей позиции
Драйвер.WriteAttribute();
КонецЕсли;
// Фиксируем позицию товара в чеке
Драйвер.EndItem();
КонецЦикла;
// Проводим оплату (Summ - сумма оплаты, TypeClose: 1 - наличные, 2 - безналичные)
Драйвер.TypeClose = ДанныеЧека.ТипОплаты;
Драйвер.Summ = ДанныеЧека.СуммаОплаты;
Драйвер.Delivery();
// Закрываем чек на фискальном накопителе
Драйвер.CloseCheck();
// Отключаем устройство для освобождения порта
Драйвер.DeviceEnabled = Ложь;
КонецПроцедуры
При реализации прямой работы с драйвером могут возникнуть стандартные ошибки ККТ. Рассмотрим наиболее частые из них:
WriteAttribute() до вызова метода BeginItem() или после завершения позиции EndItem(). На уровне протокола АТОЛ все дополнительные атрибуты конкретной позиции (включая тег 1162) должны передаваться строго во время наполнения буфера этой позиции.AttrValue. Она должна строго состоять из пар шестнадцатеричных символов, разделенных пробелами (например, "00 05 00 00 ..."). Наличие лишних пробелов в начале, в конце или двойных пробелов внутри строки приведет к отказу драйвера принимать атрибут. Также убедитесь, что свойство StreamFormat установлено в значение 5 непосредственно перед передачей атрибута.Рассмотренный метод прямой записи тега 1162 через драйвер АТОЛ ДТО-8 является отличным временным решением для конфигураций, работающих под управлением формата фискальных документов ФФД 1.05. Он позволяет избежать модернизации старых конфигураций 1С и сохраняет работоспособность ККТ в сложных RDP-окружениях.
Однако необходимо учитывать важный нюанс законодательства. При переходе торговой точки на формат ФФД 1.2 (который стал обязательным для большинства маркированных товаров, включая табак, обувь и одежду) концепция работы с маркировкой кардинально меняется:
Таким образом, описанный хак с ДТО-8 позволит вам решить проблему прямо сейчас на ФФД 1.05, но при переходе на ФФД 1.2 вам неизбежно придется обновить драйвер до версии ДТО-10. Для решения проблем работы ДТО-10 в среде RDP рекомендуется использовать интеграцию через встроенный Веб-сервер АТОЛ (по протоколу HTTP/JSON), что полностью снимает ограничения службы fdsvc и позволяет кассе бесперебойно работать в терминальном режиме.