При автоматизации розничных магазинов на базе конфигурации 1С:Управление торговлей 10.3 в терминальном режиме часто возникает проблема: к серверу подключаются несколько пользователей с разных физических рабочих станций, но программа не позволяет привязать отдельный фискальный регистратор к конкретному пользователю или рабочему месту. При настройке кассы под одной учетной записью у других кассиров флаги подключения сбиваются, а 1С выдает ошибки о недоступности COM-порта.
Разберем, почему возникает этот конфликт, и рассмотрим по шагам, как программно и аппаратно разделить торговое оборудование между терминальными сессиями.
Проанализируем архитектуру подсистемы торгового оборудования в обычных формах 1С:УТ 10.3. Привязка настроек оборудования осуществляется к имени компьютера с помощью стандартной платформенной функции ИмяКомпьютера(). В условиях локальной работы этого достаточно, однако при подключении через Remote Desktop Protocol (RDP) функция возвращает сетевое имя самого сервера терминалов, а не физического компьютера пользователя.
В результате все пользователи в терминале получают одинаковое имя компьютера. Программа считает, что все кассиры работают за одним физическим ПК, и при открытии документов пытается одновременно подключить все зарегистрированные кассы и сканеры к одним и тем же портам сервера, вызывая ошибку блокировки порта.
Для корректного разделения рабочих мест в терминале необходимо определять сетевое имя клиентской рабочей станции, с которой инициирована RDP-сессия. В операционной системе Windows для этого используется переменная окружения CLIENTNAME.
Рассмотрим доработку общего модуля или модуля обработки обслуживания торгового оборудования. Найдем функцию ПолучитьИмяКомпьютераТО() и модифицируем её так, чтобы она считывала имя клиентской машины через WScript.Shell:
Функция ПолучитьИмяКомпьютераТО() Экспорт
Если мИмяКомпьютера = Неопределено Тогда
Попытка
WSS = Новый COMОбъект("WScript.Shell");
WSSE = WSS.Environment("Process");
мИмяКомпьютера = ВРег(WSSE.Item("ClientName"));
Исключение
мИмяКомпьютера = "";
КонецПопытки;
Если ПустаяСтрока(мИмяКомпьютера) Или мИмяКомпьютера = "CONSOLE" Тогда
мИмяКомпьютера = ВРег(ИмяКомпьютера());
КонецЕсли;
КонецЕсли;
Возврат мИмяКомпьютера;
КонецФункции
Разберем логику работы этого фрагмента:
WScript.Shell, который считывает значение переменной ClientName из окружения текущего процесса терминальной сессии."CONSOLE". В этом случае срабатывает стандартный вызов ИмяКомпьютера().Если требуется сохранить стандартный алгоритм привязки к серверу, но исключить попытки одновременного подключения чужих устройств, применим альтернативный вариант с добавлением реквизита в регистр сведений.
ИмяКлиента (тип: Строка).СерверТО в процедуре ПодключитьОборудование установим проверку соответствия клиента:
// Проверка соответствия физического клиента в терминальной сессии
Если ЗначениеЗаполнено(СтрокаТО.ИмяКлиента) Тогда
Попытка
WshShell = Новый COMОбъект("WScript.Shell");
ИмяКомпьютераКлиента = ВРег(WshShell.ExpandEnvironmentStrings("%CLIENTNAME%"));
Исключение
ИмяКомпьютераКлиента = "";
КонецПопытки;
Если Не СтрокаТО.ИмяКлиента = ИмяКомпьютераКлиента Тогда
Продолжить; // Пропускаем оборудование, подключенное к другому клиенту
КонецЕсли;
КонецЕсли;
При частых разрывах RDP-соединений или нестабильной работе проброса портов через \\tsclient\COMx наиболее надежным решением является отказ от виртуальных COM-портов в пользу прямого сетевого подключения.
Рассмотрим шаги по сетевой интеграции касс:
При таком подходе терминальный сервер обращается к кассам напрямую по сетевому сокету, что устраняет зависимость от имени сеанса и конфликты совместного доступа к COM-портам.
После внесения программных изменений настроим рабочие места по следующему алгоритму: