Работа с облачными кассами (такими как Атол Онлайн, Orange Data или Бизнес.Ру) принципиально отличается от работы с локальным фискальным регистратором. Если в случае с обычной кассой мы используем драйвер и синхронные методы, то облачный сервис требует взаимодействия через HTTP API. В данной статье мы подробно разберем, как построить архитектуру обмена данными, реализовать авторизацию и правильно сформировать JSON-пакеты для пробития чеков.
Прежде чем приступать к написанию кода, проанализируем специфику облачных решений. Большинство сервисов работают по асинхронной схеме. Это означает, что процесс фискализации разделен на несколько этапов:
token).uuid), но не сам фискальный признак.uuid, чтобы узнать результат операции.Рассмотрим подробнее каждый из этих шагов на практических примерах кода.
Для работы с любым облачным API нам потребуется объект HTTPСоединение. Поскольку все современные сервисы работают по протоколу HTTPS, обязательным условием является использование объекта ЗащищенноеСоединениеOpenSSL. Выясним, как правильно инициализировать соединение и получить токен доступа.
Посмотрим на пример процедуры авторизации:
// Создаем защищенное соединение
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("api.service.ru", , , , , , Защита);
// Подготавливаем данные для авторизации (обычно JSON с логином и паролем)
ДанныеАвторизации = Новый Структура;
ДанныеАвторизации.Вставить("login", "vash_login");
ДанныеАвторизации.Вставить("pass", "vash_password");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеАвторизации);
СтрокаЗапроса = ЗаписьJSON.Закрыть();
// Формируем запрос
Запрос = Новый HTTPЗапрос("/auth/login");
Запрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Отправляем запрос и получаем ответ
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
Результат = ПрочитатьJSON(ЧтениеJSON);
ТокенДоступа = Результат.token; // Сохраняем токен для дальнейших запросов
ЧтениеJSON.Закрыть();
Иначе
Сообщить("Ошибка авторизации: " + Ответ.КодСостояния);
КонецЕсли;
Самый трудоемкий этап — правильное формирование структуры чека. Согласно требованиям ФФД 1.05 и 1.2, необходимо передавать множество обязательных реквизитов. Разберем типичную структуру объекта items (товары). Обратите внимание, что ставки НДС передаются строковыми константами (например, vat20), а не числами.
Проанализируем пример формирования структуры данных чека:
ДанныеЧека = Новый Структура;
ДанныеЧека.Вставить("external_id", Строка(ДокументСсылка.Номер)); // Уникальный ID в вашей системе
ДанныеЧека.Вставить("timestamp", Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy HH:mm:ss"));
// Данные покупателя обязательны для электронных чеков
Покупатель = Новый Структура;
Покупатель.Вставить("email", "client@mail.ru");
Покупатель.Вставить("phone", "79991234567");
ДанныеЧека.Вставить("receipt", Новый Структура("client, items, total", Покупатель, Новый Массив, 0));
// Заполнение товарных позиций
Для Каждого СтрокаТЧ Из ДокументСсылка.Товары Цикл
Позиция = Новый Структура;
Позиция.Вставить("name", СтрокаТЧ.Номенклатура.Наименование);
Позиция.Вставить("price", СтрокаТЧ.Цена);
Позиция.Вставить("quantity", СтрокаТЧ.Количество);
Позиция.Вставить("sum", СтрокаТЧ.Сумма);
Позиция.Вставить("measurement_unit", "шт");
Позиция.Вставить("payment_method", "full_payment"); // Способ расчета
Позиция.Вставить("payment_object", "commodity"); // Предмет расчета
// Налоги
Налог = Новый Структура("type", "vat20");
Позиция.Вставить("vat", Налог);
ДанныеЧека.receipt.items.Добавить(Позиция);
ДанныеЧека.receipt.total = ДанныеЧека.receipt.total + СтрокаТЧ.Сумма;
КонецЦикла;
После формирования JSON мы отправляем его на сервер. В ответ сервис возвращает uuid. Важно понимать, что в этот момент чек еще не пробит — он только встал в очередь на кассу.
Рассмотрим, как отправить запрос с использованием полученного ранее токена:
Запрос = Новый HTTPЗапрос("/v5/sell"); // Пример пути для Атол Онлайн v5
Запрос.Заголовки.Вставить("Token", ТокенДоступа);
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеЧека);
Запрос.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть());
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
РезультатЗапроса = ПрочитатьJSON(ЧтениеJSON);
Если РезультатЗапроса.status = "wait" Тогда
ИдентификаторЧека = РезультатЗапроса.uuid;
// Теперь нужно запустить цикл ожидания или обработчик ожидания для проверки статуса
КонецЕсли;
Если вы работаете с маркированными товарами (система "Честный ЗНАК"), в структуру каждой позиции item необходимо добавить реквизит marking_code. Выясним основные моменты:
Base64 или в виде шестнадцатеричной строки (Hex), предварительно очищенной от спецсимволов.item_code для маркировки), сервер вернет код 400. Обязательно логгируйте тело ответа сервера для отладки.Проанализируем несколько технических нюансов, которые помогут сделать интеграцию более надежной:
external_id. Это защитит вас от двойного пробития чека при сетевых сбоях: если сервис получит повторный запрос с тем же ID, он просто вернет статус уже созданного чека.ЗаписьJSON 1С корректно формирует текст, однако при ручном формировании строки следите, чтобы отсутствовал BOM (Byte Order Mark), так как многие веб-серверы его не воспринимают.Таким образом, мы рассмотрели полный цикл работы с API облачной кассы. Используя объекты HTTPСоединение и ЗаписьJSON, можно реализовать гибкую систему фискализации, не привязанную к конкретному рабочему месту с физическим оборудованием.