В розничной торговле алкоголем периодически возникает крайне неприятная ситуация: кассир пробивает бутылку крепкого алкоголя, кассовый аппарат успешно фискализирует чек (данные уходят в ОФД и записываются в фискальный накопитель), но в этот же момент заканчивается чековая лента. На этапе печати дополнительного слип-чека с QR-кодом ЕГАИС принтер ККТ выдает ошибку отсутствия бумаги.
Программа 1С:Розница реагирует на эту ошибку непредсказуемо для пользователя: транзакция в ЕГАИС аннулируется (система отправляет запрос на отмену продажи в УТМ), однако чек в фискальном накопителе (ФН) остается закрытым и успешно переданным в налоговую. В итоге мы получаем опасную рассинхронизацию: по данным ФН и ОФД товар продан, а по данным ЕГАИС — продажа отменена, и акцизная марка остается заблокированной либо зависает на балансе. Разберем детально, почему это происходит и как решить данную проблему в коде 1С.
Проанализируем архитектурную проблему типового механизма интеграции ККТ и ЕГАИС в 1С:Розница. Дело в том, что разработчики 1С объединили процесс фискализации чека и печать нефискальных документов (слип-чеков ЕГАИС, банковских слипов эквайринга) в единую неделимую транзакцию на стороне платформы. С точки зрения кода, весь этот процесс считается одной операцией ПечатьЧека.
Давайте рассмотрим стандартный порядок действий системы при продаже алкоголя:
НачатьФискализациюЧекаНаФискальномУстройстве.ФискализацияЧека (или СформироватьЧек).PrintText (или ПечатьТекста).И вот на шаге 6 происходит сбой — в принтере физически кончается бумага. Драйвер возвращает ошибку "Нет бумаги". Для 1С эта ошибка означает, что весь процесс печати чека завершился со статусом Ложь. Система переходит в обработчик ошибки:
Процедура ПечатьЧека_ПослеОшибкиПечатиЧека(ПараметрыВыполнения, ДополнительныеПараметры) Экспорт
Если в чеке присутствует алкогольная продукция, эта процедура автоматически отправляет команду отмены проведения чека в ЕГАИС (через УТМ). Но сам чек в ККТ уже пробит на шаге 5! Отменить его физически в кассе невозможно — операция фискализации необратима, можно сделать только чек возврата. В результате мы получаем критический рассинхрон данных.
Если проанализировать стек вызовов общего модуля ККТ и РМК, мы увидим следующую цепочку действий. В форме РМК запускается процедура ПробитьЧекККМ, которая вызывает клиентский метод менеджера оборудования:
МенеджерОборудованияКлиент.НачатьВыполнениеКомандыПечатиЧека_ЗавершениеПечати
Внутри этой процедуры происходит формирование шаблона квитанции ЕГАИС и отправка ее на печать текстовым блоком:
ВремВходныеПараметры.Добавить(СформироватьШаблонИнфоКвитанции(ДополнительныеПараметры, ШиринаСтроки));
Результат = ОбработчикДрайвераМодуль.ВыполнитьКоманду("PrintText", ВремВходныеПараметры...);
Если метод PrintText возвращает ошибку отсутствия бумаги, то переменная Результат принимает значение Ложь. Из-за этого вся цепочка процедур возвращает ошибку в форму РМК. Система считает, что чек не пробит, инициирует отмену в ЕГАИС, а на экране кассира зависает ошибка «Чек не пробит». Кассир заправляет новую ленту и пытается пробить чек повторно, что приводит к повторной фискализации (двойной продаже) и ошибке в ЕГАИС «Марка уже продана».
Существует несколько способов исправления этой ошибки — от доработки кода конфигурации до настройки параметров самого кассового аппарата.
Для того чтобы решить проблему в коде раз и навсегда, необходимо разделить результат фискализации чека и результат печати текстовых нефискальных документов (слипов). Если шаг фискализации прошел успешно, то ошибка последующей печати текста не должна приводить к отмене ЕГАИС.
Разберем, как изменить логику. Нам нужно модифицировать общий модуль, отвечающий за завершение печати чека (например, МенеджерОборудованияКлиент или непосредственно логику в ПодключаемоеОборудованиеУниверсальныйДрайверКлиент).
В процедуре обработки печати текстовых документов после фискализации необходимо игнорировать неуспешный результат выполнения команды PrintText, если ККТ уже подтвердил закрытие фискального документа. Пример схемы доработки кода:
// Перед отправкой нефискального слипа запоминаем, что фискализация уже успешно прошла
Если ФискализацияВыполненаУспешно Тогда
Попытка
// Пытаемся напечатать слип ЕГАИС
РезультатПечатиСлипа = ОбработчикДрайвераМодуль.ВыполнитьКоманду("PrintText", ВремВходныеПараметры...);
Исключение
// Игнорируем ошибку печати текста, так как фискальный чек уже в ФН
РезультатПечатиСлипа = Истина;
КонецПопытки;
// Принудительно устанавливаем успешный статус всей операции,
// чтобы предотвратить вызов отмены ЕГАИС
Результат = Истина;
КонецЕсли;
Такой подход гарантирует, что даже если бумага закончилась во время печати QR-кода, 1С зафиксирует успешную продажу. Кассир просто заменит ленту и сможет распечатать копию чека или продолжить работу, при этом транзакция в ЕГАИС останется подтвержденной.
Более надежный способ на уровне логики РМК — перед вызовом процедуры отмены транзакции ЕГАИС в ПечатьЧека_ПослеОшибкиПечатиЧека программно опрашивать состояние ККТ. Нам нужно узнать номер последнего фискального документа и проверить, закрыт ли текущий чек в кассе.
Для этого используется запрос состояния ККТ через метод GetCurrentStatus (Получить текущее состояние):
РезультатКоманды = ОбработчикДрайвераМодуль.ВыполнитьКоманду("GetCurrentStatus", ВходныеПараметры, ВыходныеПараметры...);
Если драйвер ККТ возвращает информацию о том, что последний документ успешно фискализирован и его сумма совпадает с суммой текущего чека в 1С, мы блокируем вызов отмены транзакции в ЕГАИС и принудительно проводим документ Чек ККМ в базе 1С как успешно пробитый.
Часто проблему можно решить без изменения кода 1С, настроив само оборудование через тест драйвера ККТ (например, для ККТ АТОЛ или Штрих-М):
Рекомендуем использовать комбинацию настройки драйвера ККТ (блокировка по датчику окончания бумаги) и программной доработки обработки ошибок нефискальной печати в 1С. Это полностью исключит расхождения между ОФД и ЕГАИС при любых сбоях печатающего механизма.