При автоматизации бизнес-процессов часто возникает необходимость программной отправки чеков на фискальный регистратор (ККМ) без непосредственного участия кассира в интерфейсе 1С. Например, когда данные загружаются из внешней системы, а сотрудник лишь сканирует штрихкод бланка заказа для выдачи чека. В процессе реализации такой задачи разработчики регулярно сталкиваются с аппаратными и программными сбоями: касса перестает отвечать, блокируются COM-порты, либо система выдает ошибки об отсутствии необходимых методов у драйвера торгового оборудования.
В этой статье мы подробно разберем причины возникновения таких ошибок и рассмотрим надежные архитектурные решения для реализации автоматической печати чеков на примере оборудования АТОЛ и конфигурации 1С:Бухгалтерия предприятия 3.0.
Попытка напрямую обратиться к низкоуровневым методам внешней компоненты (например, вызвать ОбъектДрайвера.ПолучитьПараметрыККТ(...)) часто заканчивается аварийным завершением работы системы. Выясним причину такого поведения платформы:
ОбъектДрайвера инициализируется как Неопределено или пустой COM-объект, у которого отсутствуют требуемые методы.ВыполнитьКоманду(), принимающий строго определенные XML-пакеты. Прямые вызовы старых функций API драйверов больше не поддерживаются интеграционными библиотеками.Другая распространенная проблема: первый чек печатается успешно, но при попытке напечатать второй система выдает ошибку: «Выбранное устройство не может использоваться для подключения» или «Порт занят». Связь с кассой восстанавливается только после перезагрузки ККМ или перезапуска сеанса 1С.
Физический фискальный регистратор, подключенный по USB (в режиме эмуляции COM-порта), поддерживает только одно активное монопольное соединение. Когда ваш программный код инициирует подключение к ККМ, 1С захватывает COM-порт. Если в процессе выполнения кода произошла ошибка, или разработчик забыл вызвать метод закрытия соединения, порт остается заблокированным процессом 1С. Касса считает, что сессия продолжается, и отвергает любые новые попытки подключения.
---
Для гарантированного освобождения COM-порта и предотвращения блокировки ККМ весь программный код работы с торговым оборудованием должен быть обернут в безопасную конструкцию Попытка — Исключение, в которой блок отключения оборудования обязательно располагается в самом конце и выполняется при любом исходе операции.
Рассмотрим пример правильной структуры программного кода на стороне клиента:
&НаКлиенте
Процедура ПробитьЧекПрограммно(ДокументСсылка)
// 1. Получаем идентификатор устройства из справочника ПодключаемоеОборудование
ИдентификаторУстройства = ПолучитьИдентификаторККТДляРабочегоМеста();
Если Не ЗначениеЗаполнено(ИдентификаторУстройства) Тогда
Предупреждение("Для текущего рабочего места не настроена ККМ!");
Возврат;
КонецЕсли;
// 2. Подключаем оборудование через стандартный менеджер БСП
ПараметрыПодключения = Новый Структура;
РезультатПодключения = МенеджерОборудованияКлиент.ПодключитьУстройство(ИдентификаторУстройства, ПараметрыПодключения);
Если Не РезультатПодключения Тогда
ВызватьИсключение "Не удалось подключить фискальный регистратор.";
КонецЕсли;
// Используем Попытку для гарантированного отключения порта в случае сбоя
Попытка
// Подготавливаем структуру данных чека
ПараметрыФискализации = СформироватьСтруктуруЧека(ДокументСсылка);
// Вызываем фискализацию через стандартные механизмы
РезультатОперации = Неопределено;
МенеджерОборудованияКлиент.ФискализоватьЧек(ИдентификаторУстройства, ПараметрыФискализации, РезультатОперации);
Если Не РезультатОперации.Результат Тогда
ВызватьИсключение РезультатОперации.ОписаниеОшибки;
КонецЕсли;
ПоказатьОповещениеПользователя("Успешно", , "Чек успешно напечатан!");
Исключение
// Логируем ошибку, чтобы не потерять информацию
ЗаписатьЛогОшибки(ОписаниеОшибки());
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при печати чека: " + КраткоеПредставлениеОшибки(ОписаниеОшибки()));
КонецПопытки;
// 3. Важнейший шаг: Отключаем устройство при любом результате печати!
МенеджерОборудованияКлиент.ОтключитьУстройство(ИдентификаторУстройства);
КонецПроцедуры
---
Если данные чеков загружаются в 1С автоматически из внешней системы (на сервере), а печать должна происходить на компьютере кассира, напрямую отправлять команду печати из серверного кода нельзя. Лучшим архитектурным решением является использование Очереди чеков.
Разберем этот механизм по шагам:
РозничнаяПродажа (или чек). Информация о необходимости пробития чека записывается в специальный созданный вами регистр сведений (например, ОчередьПечатиЧеков) со статусом «В очереди».Пример реализации обработчика ожидания на клиенте:
&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
// Подключаем автоматический опрос очереди чеков каждые 10 секунд
ПодключитьОбработчикОжидания("ПроверитьОчередьЧековККТ", 10);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОчередьЧековККТ()
// Получаем первый документ в очереди, предназначенный для этой кассы
ДокументДляПечати = ПолучитьСледующийЧекИзОчередиНаСервере(ПараметрыСеанса.РабочееМестоКлиента);
Если ДокументДляПечати = Неопределено Тогда
Возврат; // Очередь пуста
КонецЕсли;
// Приостанавливаем обработчик на время печати, чтобы избежать наложений
ОтключитьОбработчикОжидания("ПроверитьОчередьЧековККТ");
// Печатаем чек
ПробитьЧекПрограммно(ДокументДляПечати);
// Возобновляем работу обработчика ожидания
ПодключитьОбработчикОжидания("ПроверитьОчередьЧековККТ", 10);
КонецПроцедуры
---
Если вы хотите полностью уйти от ограничений клиент-серверной архитектуры 1С и не держать постоянно открытый сеанс «Робота Кассира» на рабочем месте, рассмотрите использование встроенного Web-сервера АТОЛ (поставляется вместе с драйверами 10-й версии):
Этот подход гарантирует 100% стабильность работы, исключает конфликты блокировки портов внутри 1С и позволяет печатать чеки напрямую из фоновых и регламентных заданий на сервере без необходимости запуска тонких клиентов на рабочих местах пользователей.