В процессе автоматизации розничной торговли часто возникает ситуация, когда при фискализации чека в 1С:Розница или другой конфигурации на базе БПО (Библиотеки подключаемого оборудования) происходит сбой на стороне контрольно-кассовой техники (ККТ). Типичный пример — в устройстве закончилась чековая лента. Если ошибка возникает внутри серверного модуля, мы не можем напрямую вывести пользователю интерактивное окно с вопросом «Вставьте бумагу и нажмите ОК», так как сервер 1С не поддерживает взаимодействие с интерфейсом клиента.
Разберем, как можно программно «приостановить» выполнение серверной процедуры, чтобы дать кассиру время на обслуживание аппарата, и какие риски при этом следует учитывать.
Проанализируем ситуацию: большинство операций по проведению документов и подготовке данных для ККТ происходит на сервере. Однако само обращение к драйверу оборудования выполняется на стороне клиента. Проблема возникает тогда, когда сложная бизнес-логика (например, распределение чека по нескольким организациям или работа с алкогольной продукцией) требует многократных вызовов сервера внутри одной операции. Если на каком-то этапе связь с устройством прерывается или принтер выдает ошибку, выполнение кода обрывается, что может привести к «зависшим» чекам: в базе 1С документ может не провестись, а в фискальном накопителе операция уже зафиксируется (или наоборот).
Рассмотрим вариант решения, предложенный в обсуждении. Мы можем создать итеративный цикл, который будет удерживать поток выполнения серверной процедуры, периодически пытаясь повторить операцию фискализации. Это позволяет не выходить из модуля и не прерывать текущий контекст выполнения.
Посмотрим на пример кода, реализующий такую логику:
Процедура РекурсияФискализации(ОбъектДрайвера, Параметры, ПараметрыПодключения, ВходныеПараметры, ВыходныеПараметры, ДлительностьПаузы)
КонечныйМомент = ТекущаяДата() + ДлительностьПаузы;
Успешно = Ложь;
Пока ТекущаяДата() <= КонечныйМомент Цикл
// Попытка выполнить фискализацию
Результат = ФискализацияЧека(ОбъектДрайвера, Параметры, ПараметрыПодключения, ВходныеПараметры, ВыходныеПараметры);
Если Результат = Истина Тогда
Успешно = Истина;
Прервать; // Выходим из цикла, если чек пробит успешно
Иначе
// Ошибка может быть вызвана отсутствием бумаги.
// Ждем 3-5 секунд перед следующей итерацией, чтобы не перегружать процессор
ПаузаНаСервере(3);
КонецЕсли;
КонецЦикла;
Если Не Успешно Тогда
ВызватьИсключение "Не удалось пробить чек за отведенное время. Проверьте ККТ!";
КонецЕсли;
КонецПроцедуры
В данном коде мы используем ТекущаяДата() для контроля времени ожидания. Важно понимать, что этот метод является «жестким», так как рабочий процесс сервера (rphost) в это время будет занят выполнением цикла, потребляя ресурсы процессора.
Поскольку в языке 1С нет встроенной функции Sleep() для сервера, программисты часто прибегают к хитростям. Использование пустого цикла крайне нежелательно. Разберем более изящный способ приостановить выполнение потока, используя системные вызовы:
Процедура ПаузаНаСервере(Секунды)
КомандаСистемы = "ping -n 1 -w " + Формат(Секунды * 1000, "ЧГ=0") + " 127.0.0.1";
ЗапуститьПриложение(КомандаСистемы, , Истина);
КонецПроцедуры
Этот метод заставляет серверный процесс ожидать завершения внешней команды ping, что практически не нагружает центральный процессор, в отличие от бесконечного цикла Пока ... Цикл.
Проанализируем критически важный момент, упомянутый участниками обсуждения. При работе с подакцизным товаром (алкоголь) или просто при передаче данных в ОФД, простая циклическая отправка команды ФискализироватьЧек может быть опасна. Рассмотрим ситуацию:
В результате мы можем получить двойную продажу. В случае с алкоголем это приведет к ошибке в ЕГАИС («Марка уже продана»), а в обычном чеке — к необоснованному списанию остатков и расхождению в кассовой дисциплине.
Как этого избежать? Перед каждой повторной попыткой фискализации в цикле необходимо проверять состояние ККТ. Используйте методы драйвера для получения статуса последней операции. В современных версиях БПО реализованы механизмы проверки по уникальному идентификатору чека, чтобы ККТ могла понять: это новая продажа или попытка допечатать старую.
Вместо того чтобы «замораживать» сервер, правильнее следовать стандартам разработки 1С:
ПоказатьВопрос. Кассир спокойно меняет ленту, нажимает «Повторить», и только тогда инициируется новый вызов сервера.ОбработкаПроведения), все таблицы базы данных, задействованные в документе, будут заблокированы для других пользователей.Мы рассмотрели возможность приостановки серверного кода через циклы ожидания. Это решение имеет право на жизнь в специфических условиях (например, для систем самообслуживания), но требует осторожности. Рекомендуется: использовать паузу через ЗапуститьПриложение, обязательно проверять статус ККТ перед повтором команды и стремиться к выносу обработки интерактивных ситуаций на сторону клиента.