Как приостановить выполнение серверной процедуры при ошибке ККТ (например, закончилась бумага)

Программист 1С v8.3 (Управляемые формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← На главную

В процессе автоматизации розничной торговли часто возникает ситуация, когда при фискализации чека в 1С:Розница или другой конфигурации на базе БПО (Библиотеки подключаемого оборудования) происходит сбой на стороне контрольно-кассовой техники (ККТ). Типичный пример — в устройстве закончилась чековая лента. Если ошибка возникает внутри серверного модуля, мы не можем напрямую вывести пользователю интерактивное окно с вопросом «Вставьте бумагу и нажмите ОК», так как сервер 1С не поддерживает взаимодействие с интерфейсом клиента.

Разберем, как можно программно «приостановить» выполнение серверной процедуры, чтобы дать кассиру время на обслуживание аппарата, и какие риски при этом следует учитывать.

Причина проблемы: Серверный контекст и отсутствие диалогов

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

Метод «активного ожидания» на сервере

Рассмотрим вариант решения, предложенный в обсуждении. Мы можем создать итеративный цикл, который будет удерживать поток выполнения серверной процедуры, периодически пытаясь повторить операцию фискализации. Это позволяет не выходить из модуля и не прерывать текущий контекст выполнения.

Посмотрим на пример кода, реализующий такую логику:


Процедура РекурсияФискализации(ОбъектДрайвера, Параметры, ПараметрыПодключения, ВходныеПараметры, ВыходныеПараметры, ДлительностьПаузы)
    
    КонечныйМомент = ТекущаяДата() + ДлительностьПаузы;
    Успешно = Ложь;
    
    Пока ТекущаяДата() <= КонечныйМомент Цикл
        
        // Попытка выполнить фискализацию
        Результат = ФискализацияЧека(ОбъектДрайвера, Параметры, ПараметрыПодключения, ВходныеПараметры, ВыходныеПараметры);
        
        Если Результат = Истина Тогда
            Успешно = Истина;
            Прервать; // Выходим из цикла, если чек пробит успешно
        Иначе
            // Ошибка может быть вызвана отсутствием бумаги. 
            // Ждем 3-5 секунд перед следующей итерацией, чтобы не перегружать процессор
            ПаузаНаСервере(3); 
        КонецЕсли;
        
    КонецЦикла;

    Если Не Успешно Тогда
        ВызватьИсключение "Не удалось пробить чек за отведенное время. Проверьте ККТ!";
    КонецЕсли;
    
КонецПроцедуры

В данном коде мы используем ТекущаяДата() для контроля времени ожидания. Важно понимать, что этот метод является «жестким», так как рабочий процесс сервера (rphost) в это время будет занят выполнением цикла, потребляя ресурсы процессора.

Как реализовать паузу на сервере без лишней нагрузки

Поскольку в языке 1С нет встроенной функции Sleep() для сервера, программисты часто прибегают к хитростям. Использование пустого цикла крайне нежелательно. Разберем более изящный способ приостановить выполнение потока, используя системные вызовы:


Процедура ПаузаНаСервере(Секунды)
    КомандаСистемы = "ping -n 1 -w " + Формат(Секунды * 1000, "ЧГ=0") + " 127.0.0.1";
    ЗапуститьПриложение(КомандаСистемы, , Истина);
КонецПроцедуры

Этот метод заставляет серверный процесс ожидать завершения внешней команды ping, что практически не нагружает центральный процессор, в отличие от бесконечного цикла Пока ... Цикл.

Риски двойной фискализации и работа с ЕГАИС

Проанализируем критически важный момент, упомянутый участниками обсуждения. При работе с подакцизным товаром (алкоголь) или просто при передаче данных в ОФД, простая циклическая отправка команды ФискализироватьЧек может быть опасна. Рассмотрим ситуацию:

  1. Программа отправила команду в ККТ.
  2. ККТ записала данные в фискальный накопитель и отправила их в ОФД.
  3. В этот момент произошел замин бумаги, и принтер выдал ошибку.
  4. Программа 1С получила статус «Ошибка» и, согласно нашему циклу, отправила команду ПОВТОРНО.

В результате мы можем получить двойную продажу. В случае с алкоголем это приведет к ошибке в ЕГАИС («Марка уже продана»), а в обычном чеке — к необоснованному списанию остатков и расхождению в кассовой дисциплине.

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

Правильная архитектура решения

Вместо того чтобы «замораживать» сервер, правильнее следовать стандартам разработки 1С:

  1. Вынос обработки на клиент: Ошибка ККТ должна возвращаться из серверного вызова на клиент. На клиенте мы показываем стандартное окно ПоказатьВопрос. Кассир спокойно меняет ленту, нажимает «Повторить», и только тогда инициируется новый вызов сервера.
  2. Использование настроек драйвера: У многих современных ККТ (например, Атол) в параметрах можно включить опцию «Автоматическое восстановление печати». В этом случае касса сама допечатает чек после вставки бумаги, а драйвер вернет в 1С успешный статус выполнения команды, даже если была задержка.
  3. Транзакционность: Помните, что пока ваша процедура «висит» в цикле ожидания на сервере, если она запущена внутри транзакции (например, в процедуре ОбработкаПроведения), все таблицы базы данных, задействованные в документе, будут заблокированы для других пользователей.

Резюме

Мы рассмотрели возможность приостановки серверного кода через циклы ожидания. Это решение имеет право на жизнь в специфических условиях (например, для систем самообслуживания), но требует осторожности. Рекомендуется: использовать паузу через ЗапуститьПриложение, обязательно проверять статус ККТ перед повтором команды и стремиться к выносу обработки интерактивных ситуаций на сторону клиента.

← На главную