При работе с розничными покупателями часто возникает задача повышения их лояльности. Один из самых эффективных способов — информирование клиента о состоянии его бонусного счета прямо в кассовом чеке. В типовых конфигурациях, таких как 1С:Управление торговлей 10.3 (УТ 10.3), стандартный механизм фискализации чеков не предусматривает автоматический вывод маркетинговой информации. В этой статье мы подробно разберем, как решить эту задачу программными методами, используя механизмы Библиотеки подключаемого оборудования (БПО) и возможности драйверов торгового оборудования АТОЛ.
В настройках драйвера ККТ (например, АТОЛ) существует штатная возможность редактирования клише — шапки и подвала чека (настройка рекламы). Однако этот способ подходит только для статической информации, например: "Спасибо за покупку!", "Ждем вас снова!" или адреса сайта компании. Бонусный баланс — это динамические данные, которые уникальны для каждого покупателя и рассчитываются в информационной базе 1С в момент оформления продажи. Следовательно, нам необходимо передавать эти данные на кассовый аппарат программно из кода 1С.
В некоторых неофициальных руководствах и на форумах программисты советуют записывать текст с бонусами в параметр CustomerInfo (связанный с тегом ФФД 1227 — "Покупатель"). Делать это категорически запрещено! Согласно требованиям Федеральной налоговой службы (ФНС) и формату фискальных данных, этот тег предназначен исключительно для передачи наименования организации-покупателя или ФИО физического лица при расчетах между организациями или ИП. Передача в этот тег постороннего текста вроде "Ваш баланс: 500 бонусов" является грубым нарушением правил оформления фискальных документов и может повлечь за собой штрафные санкции со стороны налоговых органов.
Современные версии БПО общаются с ККТ посредством XML-пакетов. Для вывода произвольного текста в тело чека используется специальный XML-элемент TextString. Главная сложность заключается в том, что в структуре XML-пакета чека (схема CheckPackage) нет отдельного узла "Подвал чека" для произвольного текста. Все текстовые строки должны передаваться внутри коллекции позиций чека Positions.
Давайте разберем по шагам, как правильно позиционировать этот текст, чтобы он выводился в самом конце чека — после списка товаров, но перед фискальным итогом.
Для этого нам необходимо перехватить формирование XML-пакета. Обычно этот процесс происходит в общем модуле МенеджерОборудованияВызовСервера в функции СформироватьXMLПакетДляФискализацияЧека (или аналогичной, в зависимости от версии БПО в вашей конфигурации). Нам нужно добавить нефискальные строки в массив позиций строго после того, как туда были добавлены все фискальные товары.
Рассмотрим пример кода, реализующий добавление информации о бонусах в XML-пакет:
// Находим место в коде, где завершается обход табличной части товаров
// и подготавливается запись закрывающего тега секции Positions.
// Перед закрытием узла "Positions" добавляем наш произвольный текст:
Если ЗначениеЗаполнено(ОбщиеПараметры.ДокументОснование) Тогда
// Получаем остаток бонусов по дисконтной карте документа
СсылкаНаДокумент = ОбщиеПараметры.ДокументОснование;
БалансБонусов = ПолучитьБалансБонусовПоКарте(СсылкаНаДокумент.ДисконтнаяКарта);
Если БалансБонусов > 0 Тогда
// Записываем разделительную линию для красоты визуального восприятия
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", "----------------------------------------");
ЗаписьXML.ЗаписатьКонецЭлемента; // TextString
// Записываем строку с бонусами
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", "Доступно бонусов: " + Строка(БалансБонусов));
ЗаписьXML.ЗаписатьКонецЭлемента; // TextString
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", "----------------------------------------");
ЗаписьXML.ЗаписатьКонецЭлемента; // TextString
КонецЕсли;
КонецЕсли;
Обратите внимание на поведение вашей модели ККТ. На некоторых прошивках (особенно на платформе АТОЛ 5.0) нефискальные строки TextString могут группироваться драйвером и выводиться в самом конце чека, даже после информации об оплатах. Это считается нормальным поведением кассового ядра.
Если вмешательство в структуру фискального XML-пакета кажется вам слишком рискованным или прошивка вашей кассы некорректно обрабатывает нефискальные строки внутри фискального документа, отличной альтернативой является печать **отдельного нефискального документа** (слипа) сразу после успешной печати основного чека.
Этот метод гарантирует, что фискальный документ будет пробит без ошибок, а вся маркетинговая информация распечатается на отдельной ленте, которую кассир оторвет и отдаст покупателю вместе с основным чеком.
Реализуется это отправкой отдельного XML-пакета нефискального документа через метод БПО НапечататьТекстовыйДокумент. Разберем пример реализации:
// Процедура печати маркетингового слипа на ККТ
Процедура НапечататьМаркетинговыйСлип(ИдентификаторУстройства, ДокументСсылка) Экспорт
// Получаем данные для печати
ТекстБонусов = "Текущий баланс карты: " + ПолучитьБалансБонусов(ДокументСсылка.ДисконтнаяКарта) + " руб.";
// Формируем XML-пакет нефискального документа
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.УстановитьСтроку(ПараметрыЗаписиXML);
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentPackage");
ЗаписьXML.ЗаписатьНачалоЭлемента("Positions");
// Заголовок слипа
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", "=== ИНФОРМАЦИЯ О БОНУСАХ ===");
ЗаписьXML.ЗаписатьКонецЭлемента;
// Информационная строка
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", ТекстБонусов);
ЗаписьXML.ЗаписатьКонецЭлемента;
// Пожелание клиенту
ЗаписьXML.ЗаписатьНачалоЭлемента("TextString");
ЗаписьXML.ЗаписатьАтрибут("Text", "Копите бонусы и оплачивайте ими до 50%!");
ЗаписьXML.ЗаписатьКонецЭлемента;
ЗаписьXML.ЗаписатьКонецЭлемента; // Positions
ЗаписьXML.ЗаписатьКонецЭлемента; // DocumentPackage
XMLПакет = ЗаписьXML.Закрыть();
// Отправляем сформированный пакет на ККТ через БПО
ПараметрыВывода = Неопределено;
Результат = МенеджерОборудованияКлиент.ВыполнитьКоманду(
ИдентификаторУстройства,
"PrintTextDocument",
XMLПакет,
ПараметрыВывода
);
КонецПроцедуры
В случаях, когда стандартные высокоуровневые функции БПО накладывают жесткие ограничения на форматирование или обрезают символы, разработчики прибегают к прямому низкоуровневому управлению драйвером ККТ. В УТ 10.3 при интеграции оборудования через Native или COM-компоненты можно получить прямой доступ к объекту драйвера АТОЛ и передать команды печати строк напрямую в буфер ККТ сразу после фискализации чека.
Рассмотрим, как выглядит низкоуровневое управление драйвером АТОЛ 10 для печати нефискального текста:
// Предположим, мы получили объект драйвера из подсистемы БПО 1С
// ОбъектДрайвера - это подключенный экземпляр AddIn.FptrAtolSingleTO или ДТО 10
Если ОбъектДрайвера <> Неопределено Тогда
// Подготавливаем параметры текста в драйвере
ОбъектДрайвера.setParam(ОбъектДрайвера.LIBFP_TEXT, "Начислено бонусов за покупку: +150");
ОбъектДрайвера.setParam(ОбъектДрайвера.LIBFP_TEXT_WRAP, 1); // Включаем автоперенос длинных строк
ОбъектДрайвера.setParam(ОбъектДрайвера.LIBFP_TEXT_ALIGN, 1); // Выравнивание по центру (0 - лево, 1 - центр, 2 - право)
// Даем команду драйверу на печать текстовой строки
ОбъектДрайвера.printText();
// Печатаем еще одну строку
ОбъектДрайвера.setParam(ОбъектДрайвера.LIBFP_TEXT, "Ваш новый баланс: 1250 бонусов");
ОбъектДрайвера.setParam(ОбъектДрайвера.LIBFP_TEXT_WRAP, 1);
ОбъектДрайвера.printText();
// Прокатываем ленту на одну строку вперед для удобства отрыва чека
ОбъектДрайвера.printReceiverPaper();
КонецЕсли;
При реализации любого из предложенных методов крайне важно соблюдать последовательность действий при тестировании:
fptr10.log в папке пользователя). Там будет подробно расписано, какой именно тег XML-пакета вызвал сбой оборудования.