Как устранить задержки и правильно получить ответ от веб-сервера ККТ АТОЛ в 1С 7.7?

Программист 1С v7.7 Торговля и дистрибуция
← На главную

При интеграции платформы 1С:Предприятие 7.7 с современным торговым оборудованием разработчики часто используют Веб-сервер ККТ АТОЛ (входящий в состав Драйвера торгового оборудования ДТО 10). Данная технология позволяет отправлять команды на кассу по протоколу HTTP/JSON через порт 16732.

Однако при попытке отправить команду печати чека и сразу считать ответ программисты сталкиваются с неприятным поведением: система либо возвращает пустой результат, либо зависает на 15–20 секунд, выдавая ошибку «Порт недоступен», либо возвращает JSON-ответ со статусом inProgress. В этой статье мы подробно разберем, почему так происходит, и реализуем надежный механизм асинхронного взаимодействия с ККТ в среде 1С 7.7.

Выясняем причину: асинхронная архитектура Веб-сервера АТОЛ

Для начала проанализируем, как устроен обмен данными с веб-сервером ККТ. Веб-сервер АТОЛ работает по асинхронной схеме с использованием очереди задач. Это означает следующее:

  1. Когда 1С отправляет POST-запрос на создание задачи (например, пробитие чека), веб-сервер принимает его, мгновенно добавляет в свою внутреннюю очередь и возвращает уникальный идентификатор задачи — UID. В этот момент сама касса еще даже не начала печатать чек.
  2. После этого веб-сервер начинает поочередно отправлять задачи из очереди непосредственно на физическое устройство ККТ.
  3. Чтобы узнать результат выполнения, 1С должна отправить GET-запрос по адресу http://127.0.0.1:16732/requests/{UID}.
  4. Пока физическая касса занята печатью фискального документа (что может занимать от 1 до 10 секунд в зависимости от количества позиций в чеке), веб-сервер при опросе возвращает статус inProgress, а поле результата будет содержать null.
  5. Как только печать завершается, статус меняется на ready (успешно) или error (ошибка, например, закончилась чековая лента или пропала связь с кассой).

Таким образом, попытка получить ответ линейным кодом сразу же после отправки команды обречена на неудачу: физическое устройство физически не способно мгновенно напечатать чек. Нам необходимо организовать правильный цикл ожидания в коде 1С.

Решение проблемы: организация опроса (Polling) статуса задачи

Чтобы корректно дождаться окончания операции печати, нам нужно реализовать алгоритм опроса веб-сервера (так называемый Polling). Мы будем отправлять GET-запросы с определенным интервалом до тех пор, пока статус задачи не изменится с inProgress (или wait) на конечный статус.

При этом важно соблюдать три правила:

  1. Не перегружать процессор и веб-сервер. Запросы в цикле без пауз (микросекундные задержки) перегрузят локальную сеть и службу АТОЛ, что приведет к еще большим задержкам и ошибкам «Порт недоступен».
  2. Реализовать таймаут безопасности. Если касса отключится или возникнет аппаратный сбой, статус inProgress может остаться навсегда. Наш цикл должен принудительно прерываться, например, через 15–30 секунд ожидания.
  3. Корректно обрабатывать паузу в 1С 7.7. В платформе 7.7 нет встроенного метода Предупреждение с таймаутом, который бы не блокировал интерфейс всплывающим окном. Поэтому мы применим системный обходной путь.

Шаг 1. Реализация функции паузы (задержки) в 1С 7.7

Для организации микропаузы между запросами в цикле используем запуск консольной утилиты ping через стандартный COM-объект Windows Script Host. Это наиболее надежный и проверенный временем способ сделать паузу на заданное число миллисекунд в среде 1С 7.7, не нагружая процессор.

Рассмотрим пример функции задержки:


Процедура Пауза(Миллисекунды)
    // Создаем объект выполнения системных команд
    Шелл = СоздатьОбъект("WScript.Shell");
    // Используем ping на несуществующий IP-адрес с таймаутом ожидания
    // Параметр -n 1 указывает сделать 1 запрос, -w задает таймаут в миллисекундах
    Шелл.Run("ping -n 1 -w " + СокрЛП(Миллисекунды) + " 192.0.2.1", 0, 1);
КонецПроцедуры

Шаг 2. Разбор (парсинг) JSON-ответа

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

Вариант с использованием MSScriptControl.ScriptControl для точного разбора JSON:


Функция ПолучитьСтатусИзJSON(СтрокаJSON)
    // Создаем объект выполнения сценариев Windows для парсинга JSON через JavaScript
    Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
    Скрипт.Language = "JScript";
    
    // Формируем JS-код для извлечения статуса первой задачи в массиве results
    КодJS = "function getStatus(jsonStr) {
    |    try {
    |        var data = eval('(' + jsonStr + ')');
    |        return data.results[0].status;
    |    } catch(e) {
    |        return 'error';
    |    }
    |}";
    
    Скрипт.AddCode(КодJS);
    
    Попытка
        Возврат Скрипт.Run("getStatus", СтрокаJSON);
    Исключение
        Возврат "error";
    КонецПопытки;
КонецФункции

Если структура ответа гарантированно простая, мы можем применить более быстрый, строковый метод анализа:


Функция ПолучитьСтатусСтрокой(СтрокаJSON)
    СтрокаJSON = ВРег(СтрокаJSON);
    Если Найти(СтрокаJSON, """STATUS"":""READY""") > 0 Тогда
        Возврат "ready";
    ИначеЕсли Найти(СтрокаJSON, """STATUS"":""ERROR""") > 0 Тогда
        Возврат "error";
    ИначеЕсли Найти(СтрокаJSON, """STATUS"":""INPROGRESS""") > 0 Тогда
        Возврат "inProgress";
    ИначеЕсли Найти(СтрокаJSON, """STATUS"":""WAIT""") > 0 Тогда
        Возврат "wait";
    КонецЕсли;
    Возврат "unknown";
КонецФункции

Шаг 3. Реализация цикла опроса статуса задачи

Теперь объединим отправку HTTP-запросов, задержки и парсинг статуса в единый рабочий алгоритм. Напишем процедуру ожидания завершения задачи ККТ:


Функция ОжидатьВыполненияЗадачи(UID)
    
    // Задаем адрес обращения к веб-серверу АТОЛ
    АдресЗапроса = "http://127.0.0.1:16732/requests/" + UID;
    
    // Создаем HTTP-клиент
    WinHttpRequest = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
    
    МаксимальноеВремяОжидания = 30; // Максимум 30 секунд на операцию
    ИнтервалОпроса = 500; // Опрашиваем кассу каждые 500 миллисекунд
    ИтерацийПрошло = 0;
    МаксИтераций = (МаксимальноеВремяОжидания * 1000) / ИнтервалОпроса;
    
    Пока ИтерацийПрошло < МаксИтераций Цикл
        
        // Выполняем GET-запрос для проверки состояния
        Попытка
            WinHttpRequest.Open("GET", АдресЗапроса, 0);
            WinHttpRequest.Send();
            ОтветСервера = WinHttpRequest.ResponseText;
        Исключение
            Сообщить("Ошибка связи с Веб-сервером ККТ: " + ОписаниеОшибки(), "!");
            Возврат "ОшибкаСвязи";
        КонецПопытки;
        
        // Получаем текущий статус задачи
        ТекущийСтатус = ПолучитьСтатусИзJSON(ОтветСервера);
        
        Если (ТекущийСтатус = "ready") Тогда
            // Задача успешно выполнена ККТ
            Сообщить("Чек успешно пробит на ККТ.");
            Возврат ОтветСервера;
            
        ИначеЕсли (ТекущийСтатус = "error") Тогда
            // ККТ вернул ошибку выполнения задачи
            Сообщить("Ошибка выполнения операции на ККТ: " + ОтветСервера, "!");
            Возврат ОтветСервера;
            
        КонецЕсли;
        
        // Если статус "inProgress" или "wait", ждем перед следующей попыткой
        Пауза(ИнтервалОпроса);
        ИтерацийПрошло = ИтерацийПрошло + 1;
        
    КонецЦикла;
    
    Сообщить("Превышено время ожидания ответа от ККТ (Таймаут)!", "!");
    Возврат "Таймаут";
    
КонецФункции

Дополнительные рекомендации по работе с очередью задач АТОЛ

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

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

← На главную