Современное законодательство обязывает бизнес применять контрольно-кассовую технику (ККТ) практически при любых расчетах с физическими лицами. Но что делать, если ваша компания не ведет физическую торговлю, а принимает платежи по безналичному расчету (например, через банковские реестры, эквайринг или СБП)? Покупать железный кассовый аппарат, подключать его к компьютеру бухгалтера и постоянно следить за его работоспособностью — не самое эффективное решение.
В таких случаях бизнес арендует облачные кассы в специализированных дата-центрах (например, сервис Ferma от OFD.ru на базе ККТ АТОЛ 42ФС). Физически касса находится у оператора фискальных данных, но программно она должна быть связана с вашей учетной системой. Давайте разберем по шагам, как правильно подружить облачную ККТ и конфигурацию 1С:Бухгалтерия предприятия 3.0, рассмотрим готовые интеграции и научимся писать собственное решение «в лоб» через HTTP API, если типовые механизмы вам не подходят.
Классический механизм работы 1С с торговым оборудованием базируется на использовании Библиотеки подключаемого оборудования (БПО). Типовой сценарий предполагает следующую схему:
CheckPackage), а драйвер транслирует их в ККТ.В случае с облачной ККТ эта цепочка рвется. Локального устройства нет, драйвер ставить некуда, а обращаться к кассе нужно через интернет по протоколам HTTP/HTTPS, передавая JSON-пакеты. Ниже мы детально проанализируем три основных способа решения этой задачи.
---
Если вы арендуете кассу в сервисе Ferma (ofd.ru), вам не обязательно писать код с нуля. Разработчики ОФД создали готовую внешнюю обработку «Коннектор 1С Ferma» (файл ferma.epf), которая закрывает большинство потребностей по автоматической отправке чеков.
Рассмотрим по шагам процесс подключения и настройки этой обработки:
ferma.epf.ferma.epf.После открытия обработки в интерфейсе 1С нам потребуется выполнить первичную авторизацию. Введите логин и пароль от личного кабинета Ferma, а также уникальный идентификатор вашей кассы (код группы ККТ). Коннектор позволяет автоматически сканировать базу 1С на наличие новых документов ПоступлениеНаРасчетныйСчет (оплаты от физлиц по банковским реестрам), формировать на их основе чеки и отправлять их в облако. Статус фискализации будет записываться непосредственно в лог-файлы или дополнительные свойства документов.
---
Начиная с современных релизов конфигурации 1С:Бухгалтерия предприятия 3.0, фирма «1С» активно развивает собственный встроенный сервис 1С-Облачная касса. Рассмотрим этот вариант подробнее.
Этот сервис разработан специально для сценариев удаленной фискализации. Если ваша касса арендована у сертифицированных партнеров 1С (таких как АТОЛ Онлайн, Orange Data, 1С-Рарус), система позволяет отправлять электронные чеки покупателям на e-mail или по SMS напрямую из документов расчетов без промежуточных обработок.
Для настройки этого механизма необходимо перейти в раздел Администрирование — Подключаемое оборудование, поставить флаг Удаленная фискализация (облачная касса) и настроить параметры подключения к вашему облачному провайдеру. Однако, если ваш провайдер (в данном случае OFD.ru) требует строго специфичной авторизации, которой нет в стандартном списке БПО, этот метод может не подойти. В таком случае мы переходим к самому гибкому и надежному варианту для программиста — написанию собственной интеграции.
---
Если перед нами стоит задача полностью контролировать процесс фискализации, кастомизировать структуру чека под сложные требования или обрабатывать нестандартные реестры платежей, лучшим решением будет написание собственной внешней обработки. Давайте подробно разберем, как реализовать этот алгоритм «в лоб» через HTTP-запросы.
Взаимодействие с облачным сервисом Ferma строится по протоколу, совместимому с API АТОЛ Онлайн. Нам предстоит решить три подзадачи:
AuthToken).Авторизация в сервисе Ferma выполняется путем отправки POST-запроса на адрес получения токена. Давайте напишем функцию в 1С, которая будет возвращать валидный токен:
Функция ПолучитьТокенАвторизации(Логин, Пароль) Экспорт
Результат = "";
Сервер = "ferma-at.ofd.ru";
Ресурс = "/possystem/v1/getToken";
// Формируем структуру запроса
СтруктураЗапроса = Новый Структура;
СтруктураЗапроса.Вставить("login", Логин);
СтруктураЗапроса.Вставить("password", Пароль);
// Преобразуем структуру в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураЗапроса);
СтрокаЗапросаJSON = ЗаписьJSON.Закрыть();
// Настраиваем защищенное соединение SSL
SSL = Новый ЗащищенноеСоединениеOpenSSL();
Попытка
HTTPСоединение = Новый HTTPСоединение(Сервер, 443,,,,, SSL);
HTTPЗапрос = Новый HTTPЗапрос(Ресурс);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапросаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
HTTPОтвет = HTTPСоединение.ОтправитьДляОбъекта(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку());
СоответствиеОтвета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Проверяем наличие токена в ответе
Если СоответствиеОтвета.Свойство("token") Тогда
Результат = СоответствиеОтвета.token;
КонецЕсли;
Иначе
ВызватьИсключение "Ошибка авторизации на сервере Ferma. Код ответа: " + HTTPОтвет.КодСостояния;
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ОблачнаяКасса.Авторизация", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Возврат Результат;
КонецФункции
Перейдем к формированию структуры чека. Согласно протоколу API Ferma, тело запроса должно содержать информацию об организации, типе чека, контактных данных покупателя и табличной части с товарами/услугами. Проанализируем пример формирования такого пакета в 1С:
Функция СформироватьПакетЧека(ДокументСсылка, АдресЭлПочты) Экспорт
Пакет = Новый Структура;
// 1. Общие параметры чека
Пакет.Вставить("timestamp", Формат(ТекущаяДата(), "ДФ='dd.MM.yyyy HH:mm:ss'"));
Пакет.Вставить("external_id", Строка(ДокументСсылка.УникальныйИдентификатор()));
// 2. Данные продавца и покупателя (чек)
ДанныеЧека = Новый Структура;
ДанныеКлиента = Новый Структура;
ДанныеКлиента.Вставить("email", АдресЭлПочты); // Email для отправки чека
ДанныеЧека.Вставить("client", ДанныеКлиента);
ДанныеКомпании = Новый Структура;
ДанныеКомпании.Вставить("inn", "7700000000"); // ИНН вашей организации
ДанныеКомпании.Вставить("payment_address", "www.mysite.ru"); // Адрес расчетов (сайт или облачный адрес)
ДанныеКомпании.Вставить("taxation_system", "usn_income"); // Система налогообложения (например, УСН доход)
ДанныеЧека.Вставить("company", ДанныеКомпании);
// 3. Табличная часть (предметы расчета)
МассивПредметов = Новый Массив;
// Допустим, мы берем данные из расшифровки платежа документа "Поступление на расчетный счет"
Для Каждого СтрокаТЧ Из ДокументСсылка.РасшифровкаПлатежа Цикл
ПредметРасчета = Новый Структура;
ПредметРасчета.Вставить("name", "Оплата по договору № " + СтрокаТЧ.ДоговорКонтрагента.Номер);
ПредметРасчета.Вставить("price", СтрокаТЧ.СуммаПлатежа);
ПредметРасчета.Вставить("quantity", 1);
ПредметРасчета.Вставить("sum", СтрокаТЧ.СуммаПлатежа);
ПредметРасчета.Вставить("payment_method", "full_payment"); // Полная оплата
ПредметРасчета.Вставить("payment_object", "service"); // Услуга
// Налоги (НДС)
ДанныеНалога = Новый Структура;
ДанныеНалога.Вставить("type", "none"); // Без НДС
ПредметРасчета.Вставить("vat", ДанныеНалога);
МассивПредметов.Добавить(ПредметРасчета);
КонецЦикла;
ДанныеЧека.Вставить("items", МассивПредметов);
// 4. Оплаты (безналичный расчет)
МассивОплат = Новый Массив;
Оплата = Новый Структура;
Оплата.Вставить("type", 1); // 1 - электронные/безналичные
Оплата.Вставить("sum", ДокументСсылка.СуммаДокумента);
МассивОплат.Добавить(Оплата);
ДанныеЧека.Вставить("payments", МассивОплат);
// Итоговая сумма чека
ДанныеЧека.Вставить("total", ДокументСсылка.СуммаДокумента);
Пакет.Вставить("receipt", ДанныеЧека);
// Преобразование в JSON строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Пакет);
СтрокаJSON = ЗаписьJSON.Закрыть();
Возврат СтрокаJSON;
КонецФункции
После подготовки токена и JSON-структуры чека мы отправляем POST-запрос на сервер фискализации. Обратите внимание, что API Ferma работает асинхронно: в ответ на запрос пробития чека сервер возвращает не сам чек, а уникальный идентификатор задачи (uuid). По этому идентификатору в дальнейшем нужно опрашивать систему, чтобы узнать результат операции.
Давайте реализуем отправку пакета чека на сервер:
Процедура ОтправитьЧекНаФискализацию(ДокументСсылка, Токен, КодГруппыКасс) Экспорт
Сервер = "ferma-at.ofd.ru";
// Адрес ресурса содержит код группы касс, полученный в ЛК Ferma
Ресурс = "/possystem/v1/" + КодГруппыКасс + "/sell";
СтрокаJSON = СформироватьПакетЧека(ДокументСсылка, "customer@email.ru");
SSL = Новый ЗащищенноеСоединениеOpenSSL();
Попытка
HTTPСоединение = Новый HTTPСоединение(Сервер, 443,,,,, SSL);
HTTPЗапрос = Новый HTTPЗапрос(Ресурс);
// Устанавливаем заголовки, включая Token авторизации
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.Заголовки.Вставить("Token", Токен);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
HTTPОтвет = HTTPСоединение.ОтправитьДляОбъекта(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Или HTTPОтвет.КодСостояния = 201 Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку());
СоответствиеОтвета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Если СоответствиеОтвета.Свойство("uuid") Тогда
ИдентификаторЗадачи = СоответствиеОтвета.uuid;
// Записываем UUID задачи в документ для последующего контроля статуса
ОбъектДокумента = ДокументСсылка.ПолучитьОбъект();
// Для этого можно задействовать дополнительные реквизиты или свойства
// В простейшем случае запишем информацию в комментарий к документу
ОбъектДокумента.Комментарий = "Отправлено в ККТ Ferma. UUID: " + ИдентификаторЗадачи;
ОбъектДокумента.Записать(РежимЗаписиДокумента.Запись);
ЗаписьЖурналаРегистрации("ОблачнаяКасса.ПечатьЧека", УровеньЖурналаРегистрации.Информация,,,
"Документ " + Строка(ДокументСсылка) + " успешно отправлен на фискализацию. UUID: " + ИдентификаторЗадачи);
КонецЕсли;
Иначе
ВызватьИсключение "Ошибка отправки чека. Код ответа сервера: " + HTTPОтвет.КодСостояния;
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ОблачнаяКасса.ПечатьЧека", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
---
Для надежного учета критически важно логировать отправку данных и сохранять результаты выполнения операций. Как справедливо заметили участники обсуждения на форуме, в типовой конфигурации 1С:Бухгалтерия 3.0 нет специализированных реквизитов под UUID облачной кассы. Изменять типовую конфигурацию ради этого — плохая практика, затрудняющая последующие обновления.
Рекомендуем использовать один из следующих подходов для хранения метаданных чеков:
ДополнительныеСведения): Это стандартный механизм платформы 1С, позволяющий добавлять любые свойства к документам в режиме «1С:Предприятие» без изменения конфигурации. Вы можете создать дополнительное свойство «UUID Облачного чека» и «Статус фискализации» и записывать туда данные программно.Мои_СтатусыФискализацииОблачныхЧеков. В нем в качестве измерения будет выступать документ расчетов, а в качестве ресурсов — статус (Отправлен, Ошибка, Фискализирован), дата отправки, текст ошибки и ссылка на электронный чек.---
Подводя итоги нашего разбора, определим оптимальный вектор интеграции облачной ККТ в 1С:Бухгалтерия 3.0 в зависимости от ваших задач: