При автоматизации розничной торговли часто возникает необходимость оперативно получать данные о состоянии кассы прямо в интерфейсе 1С. Например, перед проведением выемки или для контроля текущей выручки. Популярное решение «распечатать X-отчет» подходит далеко не всегда, так как это расходует чековую ленту и отвлекает кассира. Разберем детально, как получить точную сумму наличных в денежном ящике ККТ АТОЛ программными методами из 1С с использованием Драйвера торгового оборудования 10-й версии (ДТО 10).
Рассмотрим классический способ интеграции, основанный на обращении к драйверу ККТ как к COM-объекту. Этот метод подходит для операционных систем семейства Windows при работе в 32-разрядных или 64-разрядных клиентах 1С.
Ниже представлен готовый код функции, которую можно использовать во внешней обработке или модуле конфигурации для прямого запроса к кассовому аппарату:
Функция ПолучитьСуммуВКассеАТОЛ() Экспорт
СуммаВДЯ = 0;
// Инициализируем COM-объект драйвера АТОЛ 10
Попытка
fptr = Новый COMОбъект("AddIn.Fptr10");
Исключение
ЗаписьЖурналаРегистрации("ККТ_АТОЛ", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось создать объект драйвера AddIn.Fptr10. Проверьте регистрацию DLL.");
ВызватьИсключение "Драйвер ККТ АТОЛ 10 не зарегистрирован в системе!";
КонецПопытки;
// Настраиваем подключение. В данном примере используется порт USB.
// Если подключение идет по COM-порту, настройки будут другими (рассмотрим ниже).
fptr.setSingleSetting(fptr.LIBFPTR_SETTING_PORT, Строка(fptr.LIBFPTR_PORT_USB));
fptr.applySingleSettings();
// Открываем соединение с ККТ
fptr.open();
Если fptr.isOpened() Тогда
Попытка
// Устанавливаем параметр запроса: получение суммы наличных в денежном ящике
fptr.setParam(fptr.LIBFPTR_PARAM_DATA_TYPE, fptr.LIBFPTR_DT_CASH_SUM);
fptr.queryData();
// Считываем полученное значение
СуммаВДЯ = fptr.getParamDouble(fptr.LIBFPTR_PARAM_SUM);
Исключение
ЗаписьЖурналаРегистрации("ККТ_АТОЛ", УровеньЖурналаРегистрации.Предупреждение, , ,
"Ошибка при чтении данных из ККТ: " + fptr.errorDescription());
КонецПопытки;
// Обязательно закрываем соединение с устройством, чтобы освободить порт
fptr.close();
Иначе
ЗаписьЖурналаРегистрации("ККТ_АТОЛ", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось открыть порт ККТ: " + fptr.errorDescription());
КонецЕсли;
// Очищаем COM-объект из памяти
fptr = Неопределено;
Возврат СуммаВДЯ;
КонецФункции
Выясним причину популярной ошибки: «Недопустимая строка с указанием класса (0x800401F3)», которая часто возникает при попытке выполнить строку fptr = Новый COMОбъект("AddIn.Fptr10"). Данная ошибка означает, что операционная система Windows не знает о существовании класса AddIn.Fptr10, так как библиотека драйвера не зарегистрирована в реестре.
Для устранения этой проблемы выполним следующие шаги по шагам:
C:\Program Files\ATOL\Drivers10\KKT\Langs\com\ (или Program Files (x86) для 32-битной версии).addin_fptr10_x86.dll.addin_fptr10_x64.dll.regsvr32 "C:\Program Files\ATOL\Drivers10\KKT\Langs\com\addin_fptr10_x86.dll"
Или для 64-разрядной версии:
regsvr32 "C:\Program Files\ATOL\Drivers10\KKT\Langs\com\addin_fptr10_x64.dll"
Использование технологии COM имеет существенный недостаток: оно жестко привязано к Windows и требует ручной регистрации библиотек с правами администратора на каждом рабочем месте. Разберем более современный альтернативный вариант подключения драйвера АТОЛ через технологию Native API.
Этот способ кроссплатформенный (работает на Windows и Linux) и не требует регистрации DLL в системном реестре. Подключение компоненты происходит на лету прямо из кода 1С:
Функция ПолучитьСуммуВКассеNativeAPI(ПутьККомпоненте) Экспорт
СуммаВДЯ = 0;
// Подключаем внешнюю компоненту по технологии Native API без обращения к реестру
РезультатПодключения = ПодключитьВнешнююКомпоненту(ПутьККомпоненте, "Fptr10", ТипВнешнейКомпоненты.Native);
Если РезультатПодключения Тогда
Попытка
// Создаем объект ККТ
fptr = Новый("AddIn.Fptr10.Fptr10");
Исключение
ВызватьИсключение "Не удалось инициализировать объект Native API AddIn.Fptr10.Fptr10";
КонецПопытки;
// Настройка параметров подключения и работа с ККТ аналогична COM-варианту
fptr.setSingleSetting(fptr.LIBFPTR_SETTING_PORT, Строка(fptr.LIBFPTR_PORT_USB));
fptr.applySingleSettings();
fptr.open();
Если fptr.isOpened() Тогда
fptr.setParam(fptr.LIBFPTR_PARAM_DATA_TYPE, fptr.LIBFPTR_DT_CASH_SUM);
fptr.queryData();
СуммаВДЯ = fptr.getParamDouble(fptr.LIBFPTR_PARAM_SUM);
fptr.close();
КонецЕсли;
fptr = Неопределено;
КонецЕсли;
Возврат СуммаВДЯ;
КонецФункции
В качестве параметра ПутьККомпоненте можно передавать как прямой путь к файлу fptr10.dll на диске, так и использовать макет внешней компоненты, упакованный в ZIP-архив с манифестом, что позволит платформе 1С автоматически подбирать нужную разрядность библиотеки под текущее окружение клиента или сервера.
Если мы работаем в типовой конфигурации 1С (например, «Розница 2.2» или выше), в которую уже встроена БСП (Библиотека стандартных подсистем), нам не обязательно вручную инициализировать внешние объекты АТОЛ и настраивать порты подключения. Выясним, как использовать штатные механизмы 1С для решения нашей задачи.
Интеграционная компонента 1С поддерживает отправку XML-запросов и получение детального статуса ККТ. Проанализируем пример получения данных через стандартные методы БСП:
Функция ПолучитьСуммуВКассеЧерезБСП(ИдентификаторУстройства)
СуммаНаличных = 0;
// Получаем объект драйвера из подсистемы БСП "ПодключаемоеОборудование"
ПараметрыПодключения = Новый Структура;
РезультатВыполнения = ПодключаемоеОборудованиеРТ.ПолучитьПараметрыПодключения(ИдентификаторУстройства, ПараметрыПодключения);
Если РезультатВыполнения Тогда
// Подключаем устройство программно средствами 1С
РезультатПодключения = МенеджерОборудованияКлиент.ПодключитьУстройство(ИдентификаторУстройства);
Если РезультатПодключения Тогда
ПараметрыККТ = "";
// Запрашиваем состояние ККТ. Метод возвращает XML-структуру с полными данными ККТ
РезультатЗапроса = МенеджерОборудованияКлиент.ВыполнитьКоманду(
ИдентификаторУстройства,
"GetStatus",
Новый Массив,
ПараметрыККТ
);
Если РезультатЗапроса Тогда
// Читаем XML и ищем тег CashDrawer (Денежный ящик)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ПараметрыККТ);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "CashDrawer" Тогда
// Считываем сумму наличных в денежном ящике
СуммаНаличных = Число(ЧтениеXML.ПолучитьАтрибут("CashSum"));
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Обязательно отключаем ККТ средствами 1С, чтобы освободить порт для других сеансов
МенеджерОборудованияКлиент.ОтключитьУстройство(ИдентификаторУстройства);
КонецЕсли;
КонецЕсли;
Возврат СуммаНаличных;
КонецФункции
При использовании прямого низкоуровневого кода (Методы 1 и 2) программисты часто сталкиваются с тем, что касса выдает ошибку занятости порта. Это происходит потому, что типовой механизм 1С при запуске рабочего места кассира (РМК) монопольно захватывает порт кассы для постоянной готовности к печати чеков.
Для решения этой проблемы применим несколько практических подходов:
МенеджерОборудованияКлиент.ОтключитьУстройство(Ид), выполнить низкоуровневую операцию получения суммы, закрыть свой драйвер методом fptr.close(), а затем вернуть кассу в управление 1С вызовом МенеджерОборудованияКлиент.ПодключитьУстройство(Ид).Разберем ситуацию, когда к одной рабочей станции подключено несколько кассовых аппаратов, и нам необходимо программно определить порты подключения или серийные номера ККТ. В драйверах ДТО 10 механизм поиска устройств претерпел значительные изменения по сравнению со старыми версиями. Посмотрим, как реализовать опрос портов на уровне кода 1С:
Процедура НайтиПодключенныеКассы()
fptr = Новый COMОбъект("AddIn.Fptr10");
// Запускаем процесс фонового поиска устройств на всех доступных портах
fptr.searchDevices();
// Организуем цикл для перебора всех найденных касс
Пока fptr.nextDevice() Цикл
// Получаем детальную информацию о каждом обнаруженном устройстве
СерийныйНомер = fptr.getParamString(fptr.LIBFPTR_PARAM_SERIAL_NUMBER);
ИмяПорта = fptr.getParamString(fptr.LIBFPTR_PARAM_PORT_NAME);
МодельККТ = fptr.getParamString(fptr.LIBFPTR_PARAM_MODEL_NAME);
Сообщить(СтрШаблон("Найден аппарат: %1, Серийный номер: %2, Порт подключения: %3",
МодельККТ, СерийныйНомер, ИмяПорта));
КонецЦикла;
fptr = Неопределено;
КонецПроцедуры
Таким образом, мы детально проанализировали различные варианты решения задачи: от прямого низкоуровневого обращения к драйверу ККТ через COM-соединение до использования кроссплатформенных технологий Native API и встроенной логики БСП. Выбор конкретного метода зависит от архитектуры вашей информационной системы, требований к кроссплатформенности и необходимости поддержки нескольких кассовых аппаратов на одном рабочем месте.