При доработке нетиповых конфигураций (например, на базе УТ 10.3) под требования 54-ФЗ программисты часто сталкиваются с необходимостью отражения специфических видов оплат, таких как «Бонусы», «Подарочные карты» или «Баллы». Несмотря на то, что драйверы ККТ АТОЛ (начиная с версий ДТО 9 и 10) позволяют использовать до 10 типов оплат, стандартные механизмы 1С накладывают жесткие ограничения на структуру передаваемых данных. Разберем детально, почему не получается передать шестой тип оплаты через XML и как решить эту задачу правильно с технической и юридической точек зрения.
Проанализируем ситуацию, с которой сталкивается разработчик при попытке расширить узел Payments в XML-пакете. Стандартная функция ПолучитьXMLПакетДляФискализацияЧека формирует структуру, которая затем передается компоненте драйвера. В типовом коде мы видим следующее наполнение:
ЗаписьXML.ЗаписатьНачалоЭлемента("Payments");
Если ВерсияФФД > 0 Тогда
// Атрибуты согласно ФФД 1.05
ЗаписьXML.ЗаписатьАтрибут("Cash", XMLСтрока(СуммаНаличными));
ЗаписьXML.ЗаписатьАтрибут("ElectronicPayment", XMLСтрока(СуммаЭлектронными));
ЗаписьXML.ЗаписатьАтрибут("Credit", XMLСтрока(СуммаПостоплатой));
ЗаписьXML.ЗаписатьАтрибут("AdvancePayment", XMLСтрока(СуммаПредоплатой));
ЗаписьXML.ЗаписатьАтрибут("CashProvision", XMLСтрока(СуммаПредоставлением));
КонецЕсли;
ЗаписьXML.ЗаписатьКонецЭлемента();
Разберем, почему добавление произвольного атрибута, например CashLessType6, приводит к тому, что ККТ перестает печатать подвал чека или выдает ошибку. Проблема заключается в том, что БПО (Библиотека подключаемого оборудования) и сами драйверы (DLL), поставляемые фирмой 1С, работают строго по определенной XSD-схеме. В этой схеме узел Payments имеет фиксированный набор атрибутов, соответствующих пяти типам оплаты, разрешенным ФФД 1.05 и 1.1/1.2:
Любой другой атрибут, не входящий в этот список, просто игнорируется парсером внутри драйвера или вызывает исключение при проверке XML на соответствие схеме. Именно поэтому попытка «попасть» в шестую строку таблицы оплат ККТ через XML-пакет в рамках стандартного вызова СформироватьЧек обречена на неудачу.
Прежде чем искать технические обходные пути, выясним причину такого ограничения. Согласно методическим рекомендациям ФНС, бонусы не являются платежным средством. Существует два легальных способа отражения бонусных программ в чеке:
Рассмотрим самый простой и надежный способ реализации. Поскольку атрибут CashProvision (Встречное предоставление) уже поддерживается 1С, мы можем направить сумму бонусов в него. Чтобы в чеке вместо надписи «Иная форма оплаты» выводилось слово «БОНУС», необходимо выполнить настройку на стороне самой кассы.
Выполним следующие шаги:
CashProvision.Пример модифицированного кода в 1С:
// СуммаБонусы — расчетное значение суммы, оплаченной баллами
ЗаписьXML.ЗаписатьАтрибут("CashProvision", XMLСтрока(СуммаБонусы));
Этот метод позволяет остаться в рамках стандартного обмена 1С и драйвера, обеспечивая при этом корректное отображение информации в чеке и передачу данных в ОФД под тегом 1217.
Проанализируем ситуацию, когда бухгалтерия настаивает на том, что бонусы не должны фигурировать как оплата. В этом случае нам необходимо распределить сумму бонусов пропорционально по строкам чека. Рассмотрим алгоритм:
Выясним общую сумму чека до применения бонусов. Допустим, она составляет 1000 рублей, а бонусов — 100. Это значит, что на каждую позицию нужно применить скидку в 10%. Важно следить за округлением, чтобы сумма скидок по строкам совпала с общей суммой бонусов. После этого в XML-пакет в узел Positions передаются цены уже с учетом скидки, а узел Payments содержит только ElectronicPayment или Cash на сумму 900 рублей.
Преимущество метода: Полное отсутствие проблем с типами оплат и 100% соответствие любым версиям ФФД.
Если вам критически важно использовать именно 6-й, 7-й или последующие типы оплат (например, если 5-й уже занят под подарочные сертификаты), стандартный XML-интерфейс 1С использовать не получится. В этом случае придется отказаться от функции МенеджерОборудованияВызовСервера.СформироватьЧек и взаимодействовать с драйвером напрямую через COM-объект или Native-компоненту.
Рассмотрим пример логики для ДТО 10 (фрагмент кода):
// Инициализация драйвера и открытие чека
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_RECEIPT_TYPE, Драйвер.LIBFPTR_RT_SELL);
Драйвер.openReceipt();
// Регистрация позиций...
// ...
// Регистрация оплаты 6-го типа (например, Бонусы)
Драйвер.setParam(Драйver.LIBFPTR_PARAM_PAYMENT_TYPE, 6); // Номер типа оплаты из Таблицы 12
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_PAYMENT_SUM, СуммаБонусов);
Драйвер.payment();
// Закрытие чека
Драйвер.closeReceipt();
При таком подходе вы полностью обходите ограничения XML-схемы 1С, так как напрямую командуете драйверу использовать конкретный индекс из таблицы типов оплат ККТ. Однако это потребует значительной переработки модуля обмена с оборудованием, так как вам придется вручную обрабатывать открытие смены, регистрацию каждой позиции и ошибки печати.
Выбор решения зависит от архитектуры вашей системы. Для большинства задач Решение №1 (использование CashProvision) является оптимальным балансом между трудозатратами и результатом. Оно не требует взлома логики БПО и легко поддерживается при обновлениях драйверов. Если же ваша компания ведет строгий учет бонусов как маркетинговых скидок, выбирайте Решение №2. Прямая работа с драйвером (Решение №3) оправдана только в исключительных случаях в высоконагруженных или сильно кастомизированных фронт-офисных решениях.
Помните, что при использовании дополнительных типов оплат (6–10) в АТОЛ, их наименования в Таблице 12 должны быть запрограммированы заранее, иначе в чеке будет печататься стандартный текст вроде «ТИП ОПЛАТЫ 6».