При интеграции платформы 1С:Предприятие 7.7 с современным торговым оборудованием разработчики часто используют Веб-сервер ККТ АТОЛ (входящий в состав Драйвера торгового оборудования ДТО 10). Данная технология позволяет отправлять команды на кассу по протоколу HTTP/JSON через порт 16732.
Однако при попытке отправить команду печати чека и сразу считать ответ программисты сталкиваются с неприятным поведением: система либо возвращает пустой результат, либо зависает на 15–20 секунд, выдавая ошибку «Порт недоступен», либо возвращает JSON-ответ со статусом inProgress. В этой статье мы подробно разберем, почему так происходит, и реализуем надежный механизм асинхронного взаимодействия с ККТ в среде 1С 7.7.
Для начала проанализируем, как устроен обмен данными с веб-сервером ККТ. Веб-сервер АТОЛ работает по асинхронной схеме с использованием очереди задач. Это означает следующее:
UID. В этот момент сама касса еще даже не начала печатать чек.http://127.0.0.1:16732/requests/{UID}.inProgress, а поле результата будет содержать null.ready (успешно) или error (ошибка, например, закончилась чековая лента или пропала связь с кассой).Таким образом, попытка получить ответ линейным кодом сразу же после отправки команды обречена на неудачу: физическое устройство физически не способно мгновенно напечатать чек. Нам необходимо организовать правильный цикл ожидания в коде 1С.
Чтобы корректно дождаться окончания операции печати, нам нужно реализовать алгоритм опроса веб-сервера (так называемый Polling). Мы будем отправлять GET-запросы с определенным интервалом до тех пор, пока статус задачи не изменится с inProgress (или wait) на конечный статус.
При этом важно соблюдать три правила:
inProgress может остаться навсегда. Наш цикл должен принудительно прерываться, например, через 15–30 секунд ожидания.Предупреждение с таймаутом, который бы не блокировал интерфейс всплывающим окном. Поэтому мы применим системный обходной путь.Для организации микропаузы между запросами в цикле используем запуск консольной утилиты 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);
КонецПроцедуры
Поскольку в 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";
КонецФункции
Теперь объединим отправку 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;
КонецЦикла;
Сообщить("Превышено время ожидания ответа от ККТ (Таймаут)!", "!");
Возврат "Таймаут";
КонецФункции
При активной работе кассиров на торговой точке могут возникать нештатные ситуации, связанные с очередью печати веб-сервера. Рассмотрим основные правила профилактики проблем:
is_blocked: true). При этом все последующие чеки зависнут в статусе wait. Рекомендуется перед отправкой новых чеков проверять состояние очереди, отправляя запрос на http://127.0.0.1:16732/stat/requests.wait, её можно принудительно удалить из очереди, отправив HTTP-запрос методом DELETE на URL конкретной задачи /requests/{UID}. Обратите внимание, что задачи в статусе inProgress удалить таким образом нельзя — они уже обрабатываются физической кассой.inProgress, обновите Драйвер ККТ АТОЛ до стабильной актуальной версии.Применение предложенной асинхронной модели работы гарантирует стабильное пробитие фискальных документов в 1С 7.7 любой длины, исключая ложные сообщения об ошибках и зависание интерфейса программы у кассира.