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

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Создание сотен фиктивных документов в базе 1С:Бухгалтерия только ради фискализации — крайне неэффективное решение. Это приводит к раздуванию базы данных, путанице в регистрах учета и необходимости последующего удаления этих документов. В данной статье мы подробно разберем, как реализовать прямую фискализацию реестров на ККМ (на примере АТОЛ 55Ф) без создания документов в базе данных.

Почему создание фиктивных документов — это плохой путь?

Рассмотрим стандартную ситуацию: ежедневно в компанию поступает реестр из банка, содержащий 200–250 оплат от физических лиц. Если программно создавать документы под каждую транзакцию:

  1. Растет объем базы данных. Каждый документ создает движения по регистрам бухгалтерии, расчетов и НДС.
  2. Требуется очистка базы. Бухгалтерам придется регулярно удалять или помечать на удаление эти документы, что замедляет работу системы.
  3. Медленная скорость работы. Проведение документа, подготовка XML-пакета чека по стандартной схеме БПО и его проведение занимают значительное время. При массовой печати это превращается в узкое горлышко.

Выясним, как обойти это ограничение и отправить данные напрямую на фискальный накопитель (ФН) и в ОФД.

Вариант 1. Прямая отправка JSON-заданий через драйвер АТОЛ 10 (Native-компонента)

Самый надежный, быстрый и гибкий способ — это прямое взаимодействие с драйвером ККТ АТОЛ 10-й версии. Современные драйверы АТОЛ поддерживают работу с JSON-заданиями. Вместо пошаговой отправки низкоуровневых команд (открытие чека, добавление позиции, оплата, закрытие чека) мы можем передать драйверу один структурированный JSON-пакет, содержащий всю информацию о чеке.

Рассмотрим по шагам, как реализовать этот метод в обработке 1С:

  1. Подключение внешней компоненты драйвера:

    Для начала нам необходимо загрузить Native-компоненту драйвера АТОЛ. Ее можно хранить непосредственно в макете нашей внешней обработки.

    
    // Попытка подключения компоненты из макета обработки
    Если Не ПодключитьВнешнююКомпоненту("ОбщийМакет.ДрайверАТОЛККТ10", "Atol", ТипВнешнейКомпоненты.Native) Тогда
        // Если в макете нет, пробуем загрузить системную компоненту
        Если Не ПодключитьВнешнююКомпоненту("AddIn.Atol.Fptr") Тогда
            ВызватьИсключение "Не удалось подключить драйвер АТОЛ ККТ 10! Проверьте установку локальных драйверов на ПК.";
        КонецЕсли;
    КонецЕсли;
    
    // Создание объекта драйвера
    Драйвер = Новый ("AddIn.Atol.Fptr");
    
  2. Инициализация связи с ККТ:

    Установим параметры соединения с кассой. Это может быть USB, COM-порт или сетевое IP-подключение.

    
    // Настройка параметров подключения (пример для USB-подключения)
    Драйвер.setParam(Драйвер.LIBFPTR_PARAM_COMM_CHANNEL, Драйвер.LIBFPTR_PORT_USB);
    Драйвер.open();
    
    Если Не Драйвер.isOpened() Тогда
        ВызватьИсключение "Касса не подключена или занята другим процессом!";
    КонецЕсли;
    
  3. Формирование JSON-строки чека:

    Сформируем JSON-структуру чека. Важно учесть требования ФЗ-54. Поскольку оплаты пришли по банку, покупатель отсутствует физически. Мы обязаны отправить электронный чек, указав контакты покупателя (Email или телефон) в теге 1008.

    
    // Формируем структуру JSON-задания чека продажи (sell)
    ЗаданиеСтруктура = Новый Структура;
    ЗаданиеСтруктура.Вставить("type", "sell");
    ЗаданиеСтруктура.Вставить("electronically", Истина); // Электронный чек без печати на бумаге
    ЗаданиеСтруктура.Вставить("taxationType", "osn");     // Система налогообложения (например, ОСН)
    
    // Информация о клиенте (Тег 1008)
    КлиентИнфо = Новый Структура;
    КлиентИнфо.Вставить("emailOrPhone", СтрокаРеестра.КонтактыКлиента); // Например: "client@mail.ru" или "+79991112233"
    ЗаданиеСтруктура.Вставить("clientInfo", КлиентИнфо);
    
    // Позиции чека
    МассивПозиций = Новый Массив;
    Позиция = Новый Структура;
    Позиция.Вставить("type", "position");
    Позиция.Вставить("name", "Оплата по договору № " + СтрокаРеестра.НомерДоговора);
    Позиция.Вставить("price", СтрокаРеестра.Сумма);
    Позиция.Вставить("quantity", 1);
    Позиция.Вставить("amount", СтрокаРеестра.Сумма);
    Позиция.Вставить("department", 1);
    Позиция.Вставить("paymentMethod", "fullPayment"); // Полный расчет
    Позиция.Вставить("paymentObject", "service");     // Услуга
    
    // Налоговая ставка
    НалогДетали = Новый Структура;
    НалогДетали.Вставить("type", "vat20"); // НДС 20%
    Позиция.Вставить("tax", НалогДетали);
    
    МассивПозиций.Добавить(Позиция);
    ЗаданиеСтруктура.Вставить("items", МассивПозиций);
    
    // Способ оплаты (Безналичные / Электронные)
    МассивОплат = Новый Массив;
    Оплата = Новый Структура;
    Оплата.Вставить("type", "electronically");
    Оплата.Вставить("sum", СтрокаРеестра.Сумма);
    МассивОплат.Добавить(Оплата);
    ЗаданиеСтруктура.Вставить("payments", МассивОплат);
    
    // Преобразуем структуру 1С в JSON-строку
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, ЗаданиеСтруктура);
    JSONСтрока = ЗаписьJSON.Закрыть();
    
  4. Отправка задания в кассу:

    Вызовем метод processJson, который передаст задание в ККТ АТОЛ:

    
    Драйвер.setParam(Драйвер.LIBFPTR_PARAM_JSON_DATA, JSONСтрока);
    Если Драйвер.processJson() <> 0 Тогда
        КодОшибки = Драйвер.getParamInt(Драйвер.LIBFPTR_PARAM_ERROR_CODE);
        ОписаниеОшибки = Драйвер.getParamString(Драйвер.LIBFPTR_PARAM_ERROR_DESCRIPTION);
        Сообщить("Ошибка фискализации: " + ОписаниеОшибки + " (Код: " + КодОшибки + ")");
    Иначе
        // Получаем результат работы
        РезультатJSON = Драйвер.getParamString(Драйвер.LIBFPTR_PARAM_JSON_DATA);
        Сообщить("Чек успешно пробит! Результат ККТ: " + РезультатJSON);
    КонецЕсли;
    

После завершения цикла обработки реестра обязательно закройте соединение с драйвером с помощью вызова метода Драйвер.close().

Вариант 2. Фискализация через XML-пакеты БПО (Библиотека подключаемого оборудования)

Проанализируем ситуацию, когда политика безопасности или требования ИТ-департамента запрещают прямое подключение внешних компонент в обход стандартной подсистемы БПО 1С. В этом случае мы можем использовать функции интеграции БПО без создания реальных документов базы данных.

В БПО фискализация происходит посредством передачи подготовленного XML-пакета, формат которого стандартизирован (структура CheckPackage). Мы можем программно собрать данный XML-пакет по данным нашей таблицы реестра и передать его менеджеру оборудования.

Разберем этот алгоритм по шагам:

  1. Получение ссылки на подключенное оборудование:

    Для отправки команд нам потребуется ссылка на элемент справочника подключаемого оборудования ККТ.

    
    // Находим подключенное устройство (кассу АТОЛ 55Ф)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
        |	ПодключаемоеОборудование.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.ПодключаемоеОборудование КАК ПодключаемоеОборудование
        |ГДЕ
        |	НЕ ПодключаемоеОборудование.ПометкаУдаления
        |	И ПодключаемоеОборудование.УстройствоАктивно";
    РезультатЗапроса = Запрос.Выполнить();
    Если РезультатЗапроса.Пустой() Тогда
        ВызватьИсключение "Активное подключаемое оборудование ККТ не найдено!";
    КонецЕсли;
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    ИДУстройства = Выборка.Ссылка;
    
  2. Формирование XML-пакета чека:

    Сформируем строку XML вручную через объект ЗаписьXML или с использованием сериализатора XDTO.

    
    ЗаписьXML = Новый ЗаписьXML;
    ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
    ЗаписьXML.УстановитьСтроку(ПараметрыЗаписиXML);
    
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    ЗаписьXML.ЗаписатьНачалоЭлемента("CheckPackage");
    
    // Шапка чека
    ЗаписьXML.ЗаписатьНачалоЭлемента("Parameters");
    ЗаписьXML.ЗаписатьАтрибут("CashierName", "Администратор");
    ЗаписьXML.ЗаписатьАтрибут("CustomerEmail", СтрокаРеестра.Email);
    ЗаписьXML.ЗаписатьАтрибут("TaxVariant", "1"); // Например, УСН доход
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Parameters
    
    // Позиции чека
    ЗаписьXML.ЗаписатьНачалоЭлемента("Positions");
    ЗаписьXML.ЗаписатьНачалоЭлемента("FiscalItem");
    ЗаписьXML.ЗаписатьАтрибут("Name", "Оплата услуг по реестру");
    ЗаписьXML.ЗаписатьАтрибут("Quantity", "1");
    ЗаписьXML.ЗаписатьАтрибут("Price", Строка(СтрокаРеестра.Сумма));
    ЗаписьXML.ЗаписатьАтрибут("Amount", Строка(СтрокаРеестра.Сумма));
    ЗаписьXML.ЗаписатьАтрибут("TaxSide", "0"); // Без НДС или соответствующая ставка
    ЗаписьXML.ЗаписатьАтрибут("PaymentMethod", "4"); // Полный расчет
    ЗаписьXML.ЗаписатьАтрибут("PaymentSubject", "4"); // Услуга
    ЗаписьXML.ЗаписатьКонецЭлемента(); // FiscalItem
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Positions
    
    // Оплата чека
    ЗаписьXML.ЗаписатьНачалоЭлемента("Payments");
    ЗаписьXML.ЗаписатьНачалоЭлемента("Payment");
    ЗаписьXML.ЗаписатьАтрибут("Type", "1"); // Безналичная оплата
    ЗаписьXML.ЗаписатьАтрибут("Amount", Строка(СтрокаРеестра.Сумма));
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Payment
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Payments
    
    ЗаписьXML.ЗаписатьКонецЭлемента(); // CheckPackage
    
    XMLСтрокаПакета = ЗаписьXML.Закрыть();
    
  3. Вызов фискализации через методы БПО:

    Для отправки пакета на ККТ используем стандартные методы БПО клиентской части:

    
    ПараметрыОперации = Новый Структура;
    ПараметрыОперации.Вставить("Электронно", Истина);
    ПараметрыОперации.Вставить("АдресПолучателя", СтрокаРеестра.Email);
    
    Оповещение = Новый ОписаниеОповещения("ПослеФискализацииЧека", ЭтотОбъект);
    
    МенеджерОборудованияКлиент.НачатьФискализациюЧекаНаФискальномУстройстве(
        Оповещение, 
        УникальныйИдентификатор, 
        ИДУстройства, 
        XMLСтрокаПакета, 
        ПараметрыОперации
    );
    

Преимущество этого метода в том, что все настройки портов, скоростей и параметров подключения ККТ берутся из стандартного справочника оборудования 1С. Вам не нужно зашивать IP-адреса и COM-порты в код обработки.

Вариант 3. Использование локального Web-сервера АТОЛ

Рассмотрим современную альтернативу для клиент-серверных баз 1С (особенно если сервер 1С находится в облаке или в другом ЦОД, а ККТ подключена к локальному компьютеру бухгалтера). Прямое подключение COM/Native-компоненты на сервере в этом случае невозможно.

Для решения этой проблемы компания АТОЛ поставляет встроенный Web-сервер (входит в дистрибутив ДККТ 10). Web-сервер запускается как локальная служба на ПК, к которому подключена касса АТОЛ 55Ф (по умолчанию используется порт 16730).

В этом сценарии 1С выступает в роли обычного HTTP-клиента. Алгоритм действий выглядит так:

  1. Наша обработка в 1С парсит файл реестра и для каждого платежа формирует стандартную структуру JSON-задания (аналогично Варианту 1).
  2. Через стандартный объект 1С HTTPСоединение мы отправляем POST-запрос на адрес локального веб-сервера.
  3. Веб-сервер АТОЛ принимает задание, выстраивает его в очередь выполнения и передает на ККТ.
  4. 1С может в фоновом режиме опрашивать веб-сервер, отправляя GET-запросы, чтобы узнать статус фискализации конкретного чека по его UUID.

Посмотрим на пример отправки запроса к Web-серверу АТОЛ в коде 1С:


// Создаем HTTP-соединение с компьютером, где запущена служба АТОЛ
Соединение = Новый HTTPСоединение("localhost", 16730);

// Формируем POST-запрос
Запрос = Новый HTTPЗапрос("/api/v1/requests");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(JSONСтрока, КодировкаТекста.UTF8);

Попытка
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    Если Ответ.КодСостояния = 201 Тогда // Создано
        Сообщить("Задание успешно отправлено на Web-сервер ККТ!");
    Иначе
        Сообщить("Ошибка Web-сервера. Код ответа: " + Ответ.КодСостояния);
    КонецЕсли;
Исключение
    Сообщить("Не удалось связаться с Web-сервером ККТ: " + ОписаниеОшибки());
КонецПопытки;

Критически важные нюансы ФЗ-54 при работе с реестрами

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

Мы подробно разобрали три эффективных способа фискализации реестров платежей на оборудовании АТОЛ без захламления базы данных лишними документами. Выберите наиболее подходящий вариант под архитектуру вашей системы 1С и приступайте к реализации!

← На главную