Атол, отрезать чек или как гора родила мышь

Опубликовано Valery - сб, 03/19/2022 - 09:06


Вот такой простой чек нельзя сформировать даже на флагманских ККТ Атол (платформа 5.0) - ККТ Атол не умеют НЕ отрезать фискальные чеки и при этом отрезать нефискальные чеки (слип и купон)

Пролог

С появлением платформы 5.0 на ККТ Атол, у представителей сервисных служб и разработчиков верхнего ПО, появились вопросы к логике программистов, которые создавали эту самую пятую платформу. Ранее уже рассматривалась "уникальная" 19 таблица. Сегодня расскажу об еще одном "уникальном" решении разработчиков платформы 5.0, причем речь пойдет не грубой ошибке, а именно о сознательном отключении одной из самых востребованных функций ККТ. Наверно звучит нелогично, но похоже, логика теряется там, где начинается пятая платформа. На этот раз расскажу, как программисты внутреннего ПО ККТ Атол на платформе 5.0 видят работу с отрезчиком.
 

Немного лирики

Для начала, попытаюсь, на условно-виртуальной аналогии, показать, как работает отрезчик на платформе 5.0. Представим, что программистам Атол поручили создать одноименный браузер. Браузер получился на редкость шустрый, легкий и при этом со множеством полезных примочек и фич. Правда у браузера есть одна особенность, чтобы браузер заработал на компьютере пользователя, требуется три монитора, ибо запуск на одном мониторе будет с сильно "порезанным" функционалом. И все бы ничего, но эта особенность браузера явно не указана, а чтобы это узнать, требуется ознакомится с малопонятной, однако очень полезной документацией. Благо у мощного браузера Атол, есть не менее мощная техническая поддержка, которая мгновенно готова прийти на помощь нуждающимся и выслать документацию о стопитсот страниц. То есть полноценная работа начального уровня с браузером Атол, доступна только тем, кто от корки до корки изучил документацию к браузеру.  

 

Формирование слипов банковского терминала и их отрезка


Согласно документации, на ККТ платформа 5.0 метод Cut() не поддерживается

Прежде чем перейти к техническим аспектам проблемы, расскажу о ее сути. В любом современном ККТ с отрезчиком, для разработчиков верхнего ПО есть команда - Cut(). Это стандартная команда, ее суть - отрезать документ, в том месте, где надо разработчику верхнего ПО (читай пользователю). В принципе, команда довольно избыточна, ведь если кассовый чек (документ) сформировался, то ККТ сам понимает, что чек надо отрезать и дополнительные команды на отрезку не требуются, но, с одной оговоркой - кроме безналичных расчетов, там без команды Cut не обойтись. В 2021 году доля безналичных расчетов составила 73% всех розничных расчетов. То есть программисты платформы 5.0 сознательно, отказались от полнофункциональной работы с 73% всех кассовых чеков формируемых на ККТ!

Классический алгоритм формирования чека безналичной оплаты несколько иной, чем обычного чека, отсюда и возникновение проблемы. Сперва верхнее ПО отправляет на банковский терминал команду на формирование оплаты по банковскому терминалу, а после успешно проведенной транзакции, в ответ получает текстовый файл, который надо распечатать на принтере ККТ. Это два одинаковых документа, так называемые слипы, один из которых продавец оставляет себе, а другой вместе с чеком отдается покупателю. Вот тут то и возникает необходимость в команде Cut, то есть требуется отрезать слип в нужном месте, чтобы отделить слип покупателя от слипа продавца.


Отрывок из документации ДТО 10. Логика разработчиков платформы 5.0 такова, что текстовая информация должна формироваться ТОЛЬКО в составе нефискального документа, ради этого даже убрали команду Cut

Сильно утрируя, логика разработчиков пятой платформы такова - если между слипами отправить команду на печать чека, то ККТ автоматически отрежет ленту после печати слипа. Переводя на общепонятный язык, чтобы сформировать чек безналичного платежа, требуется отправить на печать вместо одного чека - сразу три подряд. Другого решения нет и не предусмотрено. С точки зрения отсутствия логики, это вполне логично - чтобы сформировать чек покупателю, пробей еще два добавочных, либо положи рядом с ККТ ножницы и разрезай слипы руками.

 

Техническая часть вопроса.

Данный пункт будет интересен только разработчикам верхнего ПО или специалистам, хотя бы издалека знакомыми с азами программирования. Не специалистам рекомендуется пролистать данный пункт и сразу перейти к Заключению. 

В качестве документации будем использовать описание драйвера ККТ v.10, а в качестве инструмента проверки будем использовать встроенный в драйвер инструмент "Скрипты драйвера"  


Чтобы проверить работу приведенных ниже скриптов, следует воспользоваться вкладкой "Скрипты драйвера", вставить скопированный скрипт и выполнить его.

 Все скрипты проверены на ККТ Атол Fprint-22ПТК и гарантированно рабочие, если у вас они не работают - ищете проблему на своей стороне.

У данной проблемы всего два варианта решения  - других решений нет (проверено на прошивках ККТ вплоть до 5.8.20).

 

Первый вариант

Ничего не делать, а отрезать банковские слипы канцелярскими ножницами. Именно так работает большинство ККТ, разработчики которого не смогли осилить документацию по протоколу платформы 5.0.

Выглядит это так:

 

/* печатаем построчно слип продавца (в примере печатается только одна строка слипа).  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа продавца");
Fptr.printText();

/* печатаем построчно слип покупателя (в примере печатается только одна строка слипа).  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа клиента");
Fptr.printText();

/* формируем чек продажи по безналичном расчету цена - 100 руб, количество - 5,565  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_RECEIPT_TYPE, Fptr.LIBFPTR_RT_SELL);
Fptr.openReceipt();
Fptr.setParam(Fptr.LIBFPTR_PARAM_COMMODITY_NAME, "Фискальный чек"); Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 100);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 5.655);
Fptr.setParam(Fptr.LIBFPTR_PARAM_TAX_TYPE, Fptr.LIBFPTR_TAX_VAT10);
Fptr.registration(); Fptr.setParam(Fptr.LIBFPTR_PARAM_PAYMENT_TYPE, Fptr.LIBFPTR_PT_ELECTRONICALLY);
Fptr.closeReceipt();

Важно!!! Бездумное выполнение данного скрипта сформирует фискальный документ на сумму 5,565*100=565 руб 50 коп. Если надо сформировать чек на 0 руб 00 коп, следует заменить  строки 
Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 100);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 5.655);

на  строки 

строки Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 0);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 1.000);

Суть этого скрипта такова - слип покупателя и  продавца печатается построчно методом printText() с параметром LIBFPTR_PARAM_TEXT,  в котором находится строка для печати слипа. Именно так формируются чеки на большинстве ККТ Атол с пятой платформой, в том числе и в 1С. 


Пример кассового чека, построчная печать методом printText(), слип надо отрезать ножницами.

Рассмотренный пример - классическая потеря заголовка фискального чека, при печати методом printText(). Возможно именно жалобы на потерю заголовка, вынудили разработчиков платформы 5.0 пойти на крайнюю меру и убрать команду Cut. 

 

Второй вариант (рекомендуемый разработчиком платформы 5.0)

Отрезать слип(ы) путем вставки его в нефискальный документ - это больше похоже на использование костылей, но другого пути нет. В общем случае это выглядит так

 

/* открываем нефискальный документ для отрезки слипа продавца */
Fptr.beginNonfiscalDocument();

/* печатаем построчно слип продавца (в примере печатается только одна строка слипа).  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа продавца");
Fptr.printText();

/* закрываем нефискальный документ для отрезки слипа продавца, собственно в этом месте будет отрезан слип */
Fptr.endNonfiscalDocument();

/* открываем нефискальный документ для отрезки слипа покупателя */
Fptr.beginNonfiscalDocument();

/* печатаем построчно слип покупателя (в примере печатается только одна строка слипа).  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа клиента");
Fptr.printText();

/* закрываем нефискальный документ для отрезки слипа покупателя, собственно в этом месте будет отрезан слип */
Fptr.endNonfiscalDocument();

/* формируем чек продажи по безналичном расчету цена - 100 руб, количество - 5,565  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_RECEIPT_TYPE, Fptr.LIBFPTR_RT_SELL);
Fptr.openReceipt();
Fptr.setParam(Fptr.LIBFPTR_PARAM_COMMODITY_NAME, "Обычный фискальный чек"); Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 100);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 5.655);
Fptr.setParam(Fptr.LIBFPTR_PARAM_TAX_TYPE, Fptr.LIBFPTR_TAX_VAT10);
Fptr.registration();
Fptr.setParam(Fptr.LIBFPTR_PARAM_PAYMENT_TYPE, Fptr.LIBFPTR_PT_ELECTRONICALLY);
Fptr.closeReceipt();

Важно!!! Бездумное выполнение данного скрипта сформирует фискальный документ на сумму 5,565*100=565 руб 50 коп. Если надо сформировать чек на 0 руб 00 коп, следует заменить  строки 
Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 100);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 5.655);

на  строки 

строки Fptr.setParam(Fptr.LIBFPTR_PARAM_PRICE, 0);
Fptr.setParam(Fptr.LIBFPTR_PARAM_QUANTITY, 1.000);

Суть данного скрипта такова слип печатается с теле нефискального документа, а значит проблем с отрезкой слипа покупателя и продавца действительно нет, вот только появляются другие проблемы - дублирование информации и повышенный расход чековой ленты.


Пример кассового чека, сформированного по рекомендуемой методике от производителя.  

Даже без средств измерения - видно, расход чековой ленты по заводской методике, больше в 2 раза чем требуется. И хотя данный способ формирования чека безналичной оплаты рекомендуется компанией Атол, данный способ более не приемлем для применения, чем приемлем.

 

Мой вариант эмуляции команды Cut

Для упрощения, не будем рассматривать формирование фискальной, так как она была рассмотрена ранее. У метода закрытия документа libfptr_end_nonfiscal_document() есть параметр LIBFPTR_PARAM_PRINT_FOOTER - печатать подвал документа. Благодаря этому параметру можно значительно уменьшить количество дублирующей информации и сократить размер нефискального документа (чека). Кроме того, если не используется клише, то его желательно убрать, но не отключать совсем - тогда чек уменьшится на ширину заголовка. В окончательном варианте скрипт формирования (без формирования фискальной части чека) безналичного документа будет выглядеть следующим образом.

 

/* открываем нефискальный документ для отрезки слипа продавца */
Fptr.beginNonfiscalDocument();

/* печатаем построчно слип продавца (в примере печатается только одна строка слипа).  */
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа продавца");
Fptr.printText();

/* отключаем печать подвала нефискального документа */
Fptr.setParam(Fptr.LIBFPTR_PARAM_PRINT_FOOTER, false);

/* закрываем нефискальный документ для отрезки слипа продавца, собственно в этом месте будет отрезан слип */
Fptr.endNonfiscalDocument();

/* не открываем нефискальный документ, так как отрезка слипа покупателя от фискального чека не требуется и даже наоборот. Печатаем построчно слип покупателя методом printText()  */ 
Fptr.setParam(Fptr.LIBFPTR_PARAM_TEXT, "одна строка банковского слипа клиента");
Fptr.printText();

При таком алгоритме формирования безналичного фискального документа (чека) мы получим сразу три плюса:
- во-первых, не будет печататься подвал чека (смотрим libfptr_set_param_bool(fptr, LIBFPTR_PARAM_PRINT_FOOTER, false); ), что значительно уменьшает размер слипа продавца;
- во-вторых, слип продавца отрежется отрезчиком ККТ, то есть мы получим псевдокоманду Cut;
- в-третьих, слип покупателя сформированный методом Fptr.printText(); не отрежется от чека покупателя, что будет хорошо, как для покупателя, так и для ресурса отрезчика.

Из минусов данного метода - "потеря" клише у фискального чека, если таковое было и использовалось. 

 


Варианты размеров слипов клиента и продавца при печати разными вариантами

1. Методом printText(), но при этом требуетя отрезать слип ножницами самостоятельно;
2. Методом endNonfiscalDocument(), при этом одна я та же информация дублируется на слипах дважды, а с учетом фискального документа - трижды;
3.  Методом endNonfiscalDocument() при установленном параметре LIBFPTR_PARAM_PRINT_FOOTER = false, то есть отключена печать подвала;
4.  Методом endNonfiscalDocument() при установленном параметре LIBFPTR_PARAM_PRINT_FOOTER = false, то есть отключена печать подвала при отсутствии заголовка (не отключенным заголовком, а именно отсутствующем).

 

Заключение.

В данной статье было рассмотрено взаимоисключающее требование разработчиков пятой платформы, которое звучит так - "Не рекомендуется печатать информацию на чековой ленте вне открытых документов (чека или нефискального документа)."

Почему взаимоисключающее, да все очень просто, при формировании безналичного документа (чека) требуется чтобы один слип (тот что остается у продавца) отрезался, а другой не отрезался от чека (тот что уходит покупателю вместе с фискальным чеком). Выполнить это условие и требование разработчиков пятой платформы - априори нельзя.

Попробую предположить, что же заставило пойти разработчиков платформы 5.0 на столь "необдуманный" шаг.

Версия 1 (самая вероятная)

Как ни странно, но разработчиков пятой платформы, на отказ от команды Cut вынудили разработчики верхнего ПО. Проблема в так называемом "двойном отрезе", характерном для разработчиков верхнего ПО, которые не имеют доступа к реальным результатам эксплуатации ККТ.

В отличии от конкурентов/коллег на ККТ Атол установлены довольно хлипкие двигатели отрезчика. Именно поэтому на Атолах проблема "двойного отреза" проявляется более радикально - сгорает двигатель отрезчика, банально перегревается, так как не рассчитан на "двойной отрез". По логике, можно на уровне железа ККТ решить эту проблему, но разработчики пятой платформы пошли своим путем.

Версия  2 (более-менее правдоподобная)

Довольно давно, некоторые разработчики кассового ПО стали использовать ККТ в качестве фишкомета (печатать фишки/предчеки). Такой подход в ККТ, приводит к тому, что на фискальном чеке отсутствовал заголовок, по причине того, что заголовок печатается заранее и соответственно уходит вместе с фишкой (предчеком). Соответственно жалобы так или иначе выливались на производителя ККТ, и отвлекали тех. поддержку на объяснения причин и следствий "потери" заголовка.

В случае если использовать нефискальный чек вместо команды  Cut, то заголовок у фискального чека будет по определению. Фактически команду Cut отдали в угоду завершенности фискального чека.

Версия 3  

Отключение команды Cut делает невозможным подделку чека. Ибо поддельный чек может выдать отрезка чека "не в том месте". Версия так себе, больше для массовки, учитывая, что кассовый чек легко проверить на сервисе ОФД, а так же тот факт, что для тех кто переделывает внутреннее ПО ККТ для подделки чека, заставить ККТ реагировать на команду Cut - не такая и проблема. 

Версия 4

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

Версия 5 (фантастическая)

В рядах компании Атол появился саботажник, который делает все возможное, чтобы дискредитировать продукцию компании Атол. Как внедренец, могу подтвердить, основной вал жалоб на продукцию Атол идет именно по формированию чеков безналичного расчета, причем как от разработчиков верхнего ПО, так и конечных пользователей.

Теги