При автоматизации розничной торговли, интернет-магазинов или курьерских служб разработчики часто сталкиваются со следующей проблемой: физические онлайн-кассы (ККТ) подключены к локальным компьютерам в точках продаж, на складах или в офисах, где отсутствует выделенный статический IP-адрес (компьютеры находятся за NAT провайдера). При этом центральная учетная система (например, облачная 1С или CRM) развернута на сервере с публичным IP-адресом и должна отправлять команды на пробитие чеков напрямую на эти кассы.
Стандартная «Push-модель», при которой облачный сервер пытается сам инициировать соединение с локальной кассой, в таких условиях не работает без покупки дорогостоящих «белых» IP-адресов или сложной настройки VPN/SSH-туннелей. В этой статье мы подробно разберем, как решить эту задачу с помощью «Pull-модели» (обратного вызова), готовых облачных мостов и современных облегченных туннелей.
Для начала проанализируем разницу в архитектурных подходах передачи команд на ККТ:
Рассмотрим подробнее три основных практических сценария реализации такой схемы.
Популярный программный продукт KkmServer поддерживает штатный режим работы по Pull-модели, который называется «Обратный вызов». При такой настройке локально установленный кассовый сервер сам опрашивает центральную базу данных.
Разберем по шагам, как организовать очередь чеков на стороне 1С (или любого другого веб-сервиса) для работы с обратным вызовом:
Шаг 1. Создание HTTP-сервиса на стороне 1С (или веб-сервера)
Вам необходимо реализовать API-эндпоинт, который будет принимать запросы от KkmServer. Локальный сервер кассы будет периодически присылать POST-запрос с данными о своем состоянии.
Посмотрим на пример реализации обработки такого запроса в HTTP-сервисе 1С:
// Метод HTTP-сервиса для обработки обратного вызова KkmServer
Функция ПолучитьКомандуДляККМ(Запрос)
// Читаем JSON, пришедший от локального KkmServer (содержит статус кассы)
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку("UTF-8");
ДанныеКассы = ДесериализоватьJSON(СтрокаJSON);
ИдентификаторКассы = ДанныеКассы.УникальныйИдентификаторККМ;
ОтветСтруктура = Новый Структура;
// Ищем в нашей базе подготовленные к печати чеки для этой конкретной кассы
ЗапросОчереди = Новый Запрос;
ЗапросОчереди.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ОчередьЧеков.Ссылка КАК Ссылка,
| ОчередьЧеков.ТелоКоманды KkmServer КАК ДанныеЧека
|ИЗ
| Справочник.ОчередьЧековККМ КАК ОчередьЧеков
|ГДЕ
| ОчередьЧеков.ИдентификаторКассы = &ИдентификаторКассы
| И ОчередьЧеков.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековОчереди.Подготовлен)";
ЗапросОчереди.УстановитьПараметр("ИдентификаторКассы", ИдентификаторКассы);
РезультатЗапроса = ЗапросОчереди.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
// Помещаем JSON-команду пробития чека в ответ KkmServer'у
ДанныеКоманды = ДесериализоватьJSON(Выборка.ДанныеЧека);
ОтветСтруктура.Вставить("Command", ДанныеКоманды);
// Фиксируем транзакцию: меняем статус чека в очереди на "Отправлен"
ОбъектОчереди = Выборка.Ссылка.ПолучитьОбъект();
ОбъектОчереди.Статус = Перечисления.СтатусыЧековОчереди.ОтправленВККМ;
ОбъектОчереди.Записать();
Иначе
// Если команд на печать нет, возвращаем пустой ответ
ОтветСтруктура.Вставить("Command", Неопределено);
КонецЕсли;
// Формируем HTTP-ответ
ТелоОтвета = СериализоватьВJSON(ОтветСтруктура);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(ТелоОтвета, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ.Заголовки.Вставить("Content-Type", "application/json");
Возврат Ответ;
КонецФункции
Шаг 2. Настройка KkmServer на локальном компьютере
В настройках локального KkmServer в разделе «Обратный вызов» необходимо указать URL вашего HTTP-сервиса (например, https://my-server.ru/hs/kkm-api/v1/poll) и интервал опроса (например, каждые 3–5 секунд). Теперь локальный сервер будет самостоятельно стучаться в вашу 1С, забирать команды на фискализацию и возвращать результаты выполнения.
Если вы не хотите самостоятельно программировать веб-сервисы, разрабатывать очереди задач и обрабатывать JSON-пакеты обмена на низком уровне, можно применить готовые облачные платформы-посредники. Рассмотрим наиболее популярные варианты:
1cfresh. Синхронизация происходит по встроенным регламентным заданиям в фоновом режиме, забирая заказы из облака и фискализируя их локально без внешнего вмешательства.Если вам все же необходимо сохранить классическую Push-модель (когда облачный сервер мгновенно отправляет POST-запрос на локальный IP-адрес кассы), но вы не хотите настраивать сложные корпоративные сети IPSec или OpenVPN, отличным выходом будет использование современных легковесных туннелей приложений.
Проанализируем работу бесплатного и безопасного инструмента — Cloudflare Tunnel (cloudflared):
KkmServer на порту 5893) устанавливается консольный агент cloudflared.kassa1.yourfirm.ru).https://kassa1.yourfirm.ru будут автоматически, безопасно и с минимальной задержкой перенаправляться внутри туннеля на локальный адрес http://localhost:5893 кассового компьютера.Этот способ полностью решает проблему «серого» IP-адреса, обеспечивает сквозное шифрование трафика и избавляет от необходимости администрировать сложные сетевые маршруты. Аналогичным образом можно использовать легковесную утилиту с открытым исходным кодом FRP (Fast Reverse Proxy), развернув ее клиентскую часть на кассовом ПК, а серверную — на вашем VPS с белым IP.
Выбор конкретного решения зависит от квалификации вашей команды разработки и архитектуры системы: