Почему при работе через RDP ломается изъятие денег из кассы ККМ АТОЛ и как это исправить?

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

При переносе информационной базы 1С (например, конфигурации 1С:Розница) с локального компьютера на терминальный сервер (RDP) технические специалисты часто сталкиваются со странным поведением торгового оборудования. Все базовые функции — пробитие чеков, открытие и закрытие смены, внесение денег — продолжают работать в штатном режиме, но при попытке выполнить операцию изъятия (выплаты) наличных программа аварийно завершает работу с системной ошибкой. Проанализируем, почему возникает эта проблема, как она связана с переходом на RDP и как правильно скорректировать программный код для восстановления работоспособности оборудования.

Суть технической проблемы и анализ ошибки 0x80070057

В процессе выполнения операции изъятия денег из кассы система 1С обращается к внешней обработке обслуживания торгового оборудования. В момент передачи параметров драйверу ККТ происходит аварийная остановка со следующим системным сообщением:


{ВнешняяОбработка.АТОЛФискальныеРегистраторы.МодульОбъекта(5004)}: Ошибка при вызове метода контекста (setParam)
    Объект.Драйвер.setParam(Объект.Драйвер.LIBFPTR_PARAM_SUM, Сумма);
по причине:
Произошла исключительная ситуация (0x80070057)

Код ошибки 0x80070057 в операционной системе Windows расшифровывается как E_INVALIDARG (недопустимый аргумент или неверный параметр). Это означает, что COM-объект драйвера ККТ АТОЛ получил на вход данные, которые не соответствуют ожидаемому формату, типу данных или допустимому диапазону значений.

Драйвер АТОЛ 10-й версии осуществляет строгую валидацию всех параметров перед их отправкой в физическую память ККТ. Для параметра суммы операции LIBFPTR_PARAM_SUM драйвер ожидает исключительно положительное вещественное число. Передача отрицательного числа напрямую нарушает внутренние бизнес-правила API драйвера, что мгновенно генерирует исключение на уровне платформы Windows.

Почему локально всё работало, а при переносе на RDP сломалось?

На первый взгляд кажется, что причиной сбоя послужил именно переход в терминальный режим (RDP) и проброс виртуальных COM-портов. На самом деле здесь имеет место классическая ложная корреляция. При переносе базы данных на сервер администрирования произошло сопутствующее изменение, которое и привело к активации скрытой ошибки в кодовой базе 1С:

  1. Смена поколения драйвера ККТ. При работе на локальном компьютере использовался устаревший драйвер АТОЛ 8-й версии. В кодовой ветке обработки обслуживания для этого драйвера (ИспользуемыйДрайверККМ = 1) разработчик предусмотрел защиту от отрицательных чисел, принудительно вычисляя абсолютное значение суммы с помощью конструкции МодульСумма = Макс(Сумма, -Сумма);.
  2. Переход на АТОЛ 10 на сервере. При развертывании системы на Windows Server 2012 R2 (или более новой ОС) системные администраторы установили актуальный драйвер АТОЛ 10, так как 8-я версия официально не поддерживается современными серверными операционными системами. Соответственно, в настройках подключения торгового оборудования в 1С тип драйвера был изменен.
  3. Ошибка во второй ветке кода. Переключение на АТОЛ 10 активировало альтернативную ветку программного кода обработки (ИспользуемыйДрайверККМ = 2). В этой ветке разработчик сторонней обработки забыл реализовать аналогичное приведение числа по модулю. В результате при изъятии денег переменная Сумма, имеющая отрицательное значение в бизнес-логике 1С, без изменений передавалась напрямую в метод setParam драйвера АТОЛ 10, вызывая фатальный сбой.

Поскольку операция внесения денег передает в процедуру изначально положительное число, она продолжала успешно работать как локально, так и на сервере.

Пошаговое исправление исходного кода

Разберем, как выглядит проблемный участок кода в модуле внешней обработки обслуживания ККТ:


ИначеЕсли ИспользуемыйДрайверККМ = 2 Тогда
    // Устанавливаем пользователя/кассира
    КАС_УстановитьКассираДляОперации(Объект, Пароль);
    Если Сумма > 0 Тогда
        Объект.Драйвер.setParam(Объект.Драйвер.LIBFPTR_PARAM_SUM, Сумма);
        Объект.Драйвер.cashIncome();
    ИначеЕсли Сумма < 0 Тогда
        // Ошибка: в метод setParam передается отрицательное значение переменной Сумма!
        Объект.Драйвер.setParam(Объект.Драйвер.LIBFPTR_PARAM_SUM, Сумма); 
        Объект.Драйвер.cashOutcome();
    КонецЕсли;

Для исправления этой ошибки нам необходимо исключить передачу отрицательного знака в параметр LIBFPTR_PARAM_SUM. ККТ АТОЛ самостоятельно понимает характер операции (выплата/изъятие денежных средств из денежного ящика) благодаря вызову специализированного метода драйвера cashOutcome(). Сумма выплаты при этом обязана быть строго положительной.

Скорректируем алгоритм, добавив получение модуля числа:


ИначеЕсли ИспользуемыйДрайверККМ = 2 Тогда
    // Устанавливаем пользователя/кассира
    КАС_УстановитьКассираДляОперации(Объект, Пароль);
    Если Сумма > 0 Тогда
        Объект.Драйвер.setParam(Объект.Драйвер.LIBFPTR_PARAM_SUM, Сумма);
        Объект.Драйвер.cashIncome();
    ИначеЕсли Сумма < 0 Тогда
        // Вычисляем модуль числа для корректной работы драйвера АТОЛ 10
        ПоложительнаяСумма = Макс(Сумма, -Сумма);
        Объект.Драйвер.setParam(Объект.Драйвер.LIBFPTR_PARAM_SUM, ПоложительнаяСумма); 
        Объект.Драйвер.cashOutcome();
    КонецЕсли;

Использование функции Макс(Сумма, -Сумма) — это стандартный и надежный способ получения абсолютного значения числа (математического модуля) в среде встроенного языка 1С, гарантирующий корректную передачу данных в COM-объект.

Рекомендации по обеспечению стабильности ККТ АТОЛ в среде RDP

Раз уж мы коснулись работы торгового оборудования в терминальном режиме, рассмотрим несколько важных архитектурных нюансов. Проброс физических COM-портов через стандартный механизм RDP-клиента (COM Port Redirection) является крайне нестабильным решением, которое часто приводит к "зависанию" кассы, задержкам при печати чеков и периодической потере связи.

Для оптимизации работы ККТ в многопользовательской серверной среде рекомендуем применить следующие подходы:

  1. Использование удаленного подключения ККТ (TCP/IP / RPC-сервер). Драйвер АТОЛ 10-й версии обладает встроенным механизмом работы по сети. Вместо проброса портов через RDP выполните следующие действия:
    • На локальном компьютере кассира, к которому касса подключена физически по USB, запустите службу «Сервер ККТ АТОЛ» (утилита fptr10_server.exe).
    • В настройках торгового оборудования внутри сеанса 1С на сервере выберите способ подключения "Сеть" или "Удаленное подключение".
    • Укажите локальный IP-адрес компьютера кассира в локальной сети и порт (по умолчанию 16710). Данные будут передаваться напрямую по протоколу TCP/IP, минуя нестабильные шлюзы RDP.
  2. Переход на Native-компоненту 1С. При интеграции ККТ старайтесь избегать использования COM-объектов (таких как Новый COMОбъект("AddIn.Fptr10")). В многопользовательской RDP-среде COM-технология требует регистрации библиотек в реестре операционной системы под учетной записью администратора и часто конфликтует при одновременном обращении разных пользователей. Применение современной Native-компоненты (технология Native API от 1С), которая поставляется в виде zip-архива напрямую в конфигурацию, позволяет изолировать сеансы пользователей и обеспечивает стабильную кроссплатформенную работу без дополнительных манипуляций с реестром Windows Server.

Реализация предложенных исправлений в кодовой части интеграции с драйвером АТОЛ 10 полностью решает проблему аварийного завершения сеанса 1С при инкассации, а оптимизация сетевого подключения кассы сделает работу кассиров быстрой и бесперебойной.

← На главную