gifts2017

Управление торговым оборудованием при размещении базы на сервере терминалов

Опубликовал Павел Егоров (SatanClaws) в раздел Администрирование - Системное

Решение проблем с настройкой торгового оборудования при работе с базой в сервере терминалов.

Как известно, стандартная подсистема торгового обрудования в УТ10 регистрирует оборудование "на компьютер". В УТ11 сделано лучше, но на УТ10 работает еще достаточное количество организаций.

Такой подход, отчасти, логичен, так как на одном компе могут работать несколько смен кассиров, каждый из которых работает под своим пользователем 1С - и все решается одной настройкой.

Но если же база целиком и полностью крутится на серваке (пользователи через Цитрикс/удаленный рабочий стол подключаются к серверу и работают там) - то возникают проблемы. Причем, порты пробрасываются без проблем, и у кого оборудование реально подключенно - у них проблем нет. Но у остальных - при входе в систему начинается ругань на тему невозможности открыть порт и т.п.

 

Хорошо, что все проблемы разруливаются с эффективностью и качеством хорошего хирурга - одним выверенным движением. Главное - знать где резать.

 

Итак, приступим:

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

Переопределяя эту функцию, можно добиваться необходимой "тонкости" настройки. Главное - знать откуда получать, скажем, имя пользователя системы или имя клиентского компа.

 

Меньше слов, больше дела:

 Функция ПолучитьИмяКомпьютераТО() Экспорт

 Если мИмяКомпьютера = Неопределено Тогда
  ДопИмя = "";
  
  // получим имя клиентского компа
  Попытка
  objShell = Новый COMОбъект("WScript.Shell");
  ДопИмя = ДопИмя + ":" + objShell.RegRead("HKEY_CURRENT_USER\Volatile Environment\CLIENTNAME");
  Исключение
  КонецПопытки;
  
  //получим параметры сервера
  Попытка
  objNet = Новый COMОбъект("WScript.NetWork");
  ИмяСервераТерминалов = objNet.ComputerName;
  ИмяПользователяWindows = objNet.UserName;
   
  ДопИмя = ДопИмя + "@" + ИмяСервераТерминалов + "\" + ИмяПользователяWindows;
  Исключение
  КонецПопытки;
  
  мИмяКомпьютера = ВРЕГ(ИмяКомпьютера() + ДопИмя);
 КонецЕсли;
 
 
 Возврат мИмяКомпьютера;

КонецФункции // ПолучитьИмяКомпьютераТО()

Пример излишне брутален, зато отлично показывает что откуда получать.

Все, что нужно - иметь Windows Script Host (что это такое и с чем его едят - можно прочитать, например, здесь: http://www.script-coding.com/WSH.html), который уже давно идет в винде"по дефолту".

 


Upd В Win7 ключ реестра HKCU\Volatile Environment:CLIENTNAME нужно смотреть как HKCU\Volatile Environment\xx:CLIENTNAME, где xx - номер терминальной сессии. В качестве решения можно использовать переменную среды:

objShell = Новый COMОбъект("WScript.Shell");
ДопИмя = ДопИмя + ":" + objShell.Environment("Process").Item("CLIENTNAME");


См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. Доржи Балбаров (Angeros) 01.08.12 04:41
Спасибо давно хотел решить эту проблему никак руки не доходили. А нельзя было поизящнее решить проблему с отсутствующей веткой реестра?
2. Павел Егоров (SatanClaws) 01.08.12 05:35
(1) Это про Попытка-Исключение?
Если использовать WMI вместо WHS - точно можно.
На WHS - разве что последовательно обращаясь к каждому уровню запрашиваемого пути, но тоже не факт. Проще в Попытку все обернуть.
3. Павел Егоров (SatanClaws) 01.08.12 05:38
(1) Кстати, для Win7 все-равно придется использовать WMI - там ключ реестра надо запрашивать немного другой:
HKEY_CURRENT_USER\Volatile Environment\xx\CLIENTNAME, где xx - это номер подключения
И пока я не нашел, как можно узнать номер текущего подключения - значит придется через WMI писать обход ветки реестра
4. Сергей Сергеев (Рамзес) 01.08.12 08:42
Лично я решил проблему, тупо закомментарив по три строки кода, отвечающего за "ругань" в следующих функциях модуля обработки "ТОСервер":
Функция ПодключитьКлиента(Клиент) Экспорт

	Результат = мНетОшибки;
	КонечныйРезультат = мНетОшибки;

	Клиенты   = ПолучитьПараметрСервераТО("Клиенты", "Соответствие");
	Если Клиенты[Клиент] <> Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	ВидТО = Неопределено;
	Для Каждого ВидТО Из Перечисления.ВидыТорговогоОборудования Цикл
		Если Клиент.ПоддерживаетсяВидТО(ВидТО) Тогда
			Результат = ПодключитьОборудование(ВидТО, Клиент);
			Если ЗначениеЗаполнено(Результат) Тогда
				КонечныйРезультат = мОшибкаНеизвестно;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

	Если ЗначениеЗаполнено(КонечныйРезультат) Тогда
		// { Админ [18.05.2012 17:24:45]  // отключил
		//мОписаниеОшибки = "Произошла ошибка при подключении торгового оборудования";
		//Ошибка = ПолучитьТекстОшибкиТО(КонечныйРезультат);
		//Сообщить(Ошибка, СтатусСообщения.Важное);
		// } Админ [18.05.2012 17:24:45]
	КонецЕсли;

	Возврат КонечныйРезультат;

КонецФункции // ПодключитьКлиента()
...Показать Скрыть


и

Функция ПодключитьОборудование(Вид, Клиент)

	Результат = мНетОшибки;
	ПоследняяОшибка = мНетОшибки;

	ТО      = ПолучитьТО();
	Клиенты = ПолучитьПараметрСервераТО("Клиенты",      "Соответствие");

	СтруктураПоиска = Новый Структура("Вид", Вид);
	СтрокиТО        = ТО.НайтиСтроки(СтруктураПоиска);
	Если СтрокиТО.Количество() = 0 Тогда
		Запрос = Новый Запрос(
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|    РегТО.Идентификатор       КАК Идентификатор,
		|    РегТО.Модель.Наименование КАК Наименование,
		|    РегТО.Модель              КАК Модель,
		|    РегТО.Параметры           КАК Параметры
		|ИЗ
		|    РегистрСведений.ТорговоеОборудование КАК РегТО
		|ГДЕ
		|    РегТО.Вид = &Вид
		|    И РегТО.Компьютер                      = &Компьютер
		|    И РегТО.Подключено
		|");
		Запрос.УстановитьПараметр("Вид"      , Вид);
		Запрос.УстановитьПараметр("Компьютер", ПолучитьИмяКомпьютераТО());
		СтрокиТО = Запрос.Выполнить().Выгрузить();
		СтрокаТО = Неопределено;
		Для Каждого СтрокаТО Из СтрокиТО Цикл
			Идентификатор = СтрокаТО.Идентификатор;
			Наименование  = СтрокаТО.Наименование;
			Обработка     = Неопределено;
			Параметры     = ?(ПустаяСтрока(СтрокаТО.Параметры),
			                  Новый Структура(),
			                  ЗначениеИзСтрокиВнутр(СтрокаТО.Параметры));
			Модель        = СтрокаТО.Модель.Модель;
			мМодельПодключаемогоТО = Модель;

			Результат = РаботаСТорговымОборудованием.ПолучитьОбработкуОбслуживанияТО(СтрокаТО.Модель, Обработка);
			Если ЗначениеЗаполнено(Результат) Тогда
				// { Админ [18.05.2012 17:24:45]  // отключил
				//Ошибка = ПолучитьТекстОшибкиТО(Результат);
				//Сообщить(мМодельПодключаемогоТО + ": " + Ошибка, СтатусСообщения.Важное);
				//ПоследняяОшибка = Результат;
				// } Админ [18.05.2012 17:24:45]
				Продолжить;
			КонецЕсли;

			Объект    = Неопределено;
			Результат = Обработка.СоздатьОбъектДрайвера(Объект, Модель, Параметры);
			Если ЗначениеЗаполнено(Результат) Тогда
				Ошибка = ПолучитьТекстОшибкиТО(Результат);
				Сообщить(мМодельПодключаемогоТО + ": " + Ошибка, СтатусСообщения.Важное);
				ПоследняяОшибка = Результат;
				Продолжить;
			КонецЕсли;

			Результат = Обработка.Подключить(Объект);
			Если ЗначениеЗаполнено(Результат) Тогда
				// { Админ [25.05.2012 17:24:45]  // отключил
				//мОписаниеОшибки = Объект.ОписаниеОшибки;
				//Ошибка = ПолучитьТекстОшибкиТО(Результат);
				//Сообщить(мМодельПодключаемогоТО + ": " + Ошибка, СтатусСообщения.Важное);
				//ПоследняяОшибка = Результат;
				// } Админ [25.05.2012 17:24:45]
				Продолжить;
			КонецЕсли;

			Оборудование                             = ТО.Добавить();
			Оборудование.Вид                         = Вид;
			Оборудование.Ссылки                      = 1;
			Оборудование.Идентификатор               = Идентификатор;
			Оборудование.Наименование                = Наименование;
			Оборудование.Обработка                   = Обработка;
			Оборудование.Объект                      = Объект;
			Оборудование.ИмяИсточникаВнешнегоСобытия = Обработка.ПолучитьИмяИсточникаВнешнегоСобытия(Объект);

			СообщенияКлиента = Клиенты[Клиент];
			Сообщения        = Обработка.ПолучитьОписаниеСобытий(Объект);
			Сообщения.Колонки.Добавить("Идентификатор");
			Сообщения.Колонки.Добавить("Источник");
			Сообщения.Колонки.Добавить("Вид");
			Сообщения.ЗаполнитьЗначения(Идентификатор, "Идентификатор");
			Сообщения.ЗаполнитьЗначения(Оборудование.ИмяИсточникаВнешнегоСобытия, "Источник");
			Сообщения.ЗаполнитьЗначения(Вид, "Вид");

			Если НЕ ЗначениеЗаполнено(СообщенияКлиента) Тогда
				Клиенты[Клиент] = Сообщения;
			Иначе
				Для Каждого СтрокаТаблицыИсточника Из Сообщения Цикл
					СтрокаТаблицыПриемника = Клиенты[Клиент].Добавить();
					ЗаполнитьЗначенияСвойств(СтрокаТаблицыПриемника, СтрокаТаблицыИсточника);
				КонецЦикла;
			КонецЕсли;

		КонецЦикла;
	Иначе
		СтрокаТО = Неопределено;
		Для Каждого СтрокаТО Из СтрокиТО Цикл
			Если СтрокаТО.Ссылки = 0 Тогда
				мМодельПодключаемогоТО = СтрокаТО.Объект.Модель;
				Результат = СтрокаТО.Обработка.Подключить(СтрокаТО.Объект);

				Если ЗначениеЗаполнено(Результат) Тогда
					мОписаниеОшибки = СтрокаТО.Объект.ОписаниеОшибки;
					Ошибка = ПолучитьТекстОшибкиТО(Результат);
					Сообщить(мМодельПодключаемогоТО + ": " + Ошибка, СтатусСообщения.Важное);
					ПоследняяОшибка = Результат;
					Продолжить;
				КонецЕсли;
				СтрокаТО.ИмяИсточникаВнешнегоСобытия = СтрокаТО.Обработка.ПолучитьИмяИсточникаВнешнегоСобытия(СтрокаТО.Объект);
			КонецЕсли;

			СообщенияКлиента = Клиенты[Клиент];
			Сообщения        = СтрокаТО.Обработка.ПолучитьОписаниеСобытий(СтрокаТО.Объект);
			Сообщения.Колонки.Добавить("Идентификатор");
			Сообщения.Колонки.Добавить("Источник");
			Сообщения.Колонки.Добавить("Вид");
			Сообщения.ЗаполнитьЗначения(СтрокаТО.Идентификатор, "Идентификатор");
			Сообщения.ЗаполнитьЗначения(СтрокаТО.ИмяИсточникаВнешнегоСобытия, "Источник");
			Сообщения.ЗаполнитьЗначения(СтрокаТО.Вид, "Вид");

			Если НЕ ЗначениеЗаполнено(СообщенияКлиента) Тогда
				Клиенты[Клиент] = Сообщения;
			Иначе
				Для Каждого СтрокаТаблицыИсточника Из Сообщения Цикл
					СтрокаТаблицыПриемника = Клиенты[Клиент].Добавить();
					ЗаполнитьЗначенияСвойств(СтрокаТаблицыПриемника, СтрокаТаблицыИсточника);
				КонецЦикла;
			КонецЕсли;

			СтрокаТО.Ссылки = СтрокаТО.Ссылки + 1;
		КонецЦикла;
	КонецЕсли;

	Возврат ПоследняяОшибка;

КонецФункции // ПодключитьОборудование()
...Показать Скрыть
5. Алексей Пантюхов (alexpvs) 01.08.12 11:25
// Функция возвращает строку c именем компьютера для нужд торгового оборудования.
//
// Возвращаемое значение:
// Строка - имя компьютера для торгового оборудования.
Такую проблему для терминального сервера решил следующим образом в модуле обработки "ТОСервер":
//
Функция ПолучитьИмяКомпьютераТО() Экспорт

Если мИмяКомпьютера = Неопределено Тогда
// НАЧАЛО ИЗМЕНЕНИЙ
//мИмяКомпьютера = ВРег(ИмяКомпьютера());
мИмяКомпьютера = ВРег(ИмяКомпьютера()) + "_" + ВРег(ИмяПользователя());
// КОНЕЦ ИЗМЕНЕНИЙ
КонецЕсли;

Возврат мИмяКомпьютера;

КонецФункции // ПолучитьИмяКомпьютераТО()

Таким образом, ТО настраивается для связки "компьютер" (в данном случае, один и тот же сервер терминалов) и конкретного пользователя 1С
6. Владимир Насыров (Spacer) 01.08.12 13:13
Зачем эти танцы с бубном?
"Как известно, стандартная подсистема торгового обрудования в 1С8.* регистрирует оборудование "на компьютер"
Кто вам такое сказал?
Стандартная подсистема регистрирует оборудование не "на компьютер", а "на рабочее место".
Для этого в подсистеме есть специальный справочник "РабочиеМеста".
Каждое рабочее место представляет собой связку "Пользователь+Компьютер".
Так что если специально не извращаться, а все делать по уму, то никаких проблем с этим не возникает.
7. Павел Егоров (SatanClaws) 01.08.12 20:24
(6) Это где? в УТ 11 (честно, с ней не приходилось сталкиваться)?
В УТ 10 нет никаких рабочих мест - а работают на УТ 10 еще ой как много контор.

Если в УТ 11 подсистему торгового оборудования заметно переписали - обновлю статью.
8. Павел Егоров (SatanClaws) 01.08.12 20:26
(5) собственно, упрощать пример никто не запрещает - я ж даже специально написал, что "пример излишне брутален".
9. Павел Егоров (SatanClaws) 01.08.12 20:29
(4) ругань - руганью, но
а) ком-порт пытается открыться (причем, монопольно)
б) не дай бог, на этом ком-порту окажется какое-то другое оборудование

Т.е., конечно, ком-портов можно создать ажно 255 штук, благо цитрикс позволяет маппить порты с переопределением имен. Но решение все-равно некрасивое до кривизны.
Позволяет ли вообще такие фокусы стандартный РДП - сходу не скажу.
Рамзес; +1 Ответить
10. Галина Орехова (orehova123) 02.08.12 01:51
спасибо автору и комментаторам, закину в свою "книгу знаний"
11. Владимир Насыров (Spacer) 02.08.12 03:06
(7) SatanClaws, да, в УТ 11. Я из нее перетаскивал систему подключения ТО в УПП под тонкий клиент управляемое приложение. Наверно действительно в УТ 10 такого еще не было. Поторопился я с категоричностью суждений.
12. Станислав Гирман (Niberu) 02.08.12 03:13
(5) alexpvs, давно-давно, для тис под 77 для сохранения настроек оборудования подобную связку ИмяКомпьютера&ИмяПользователя в имени файла первым делом приписал.
Сначала удивился, что в 8ке этого и сейчас нет,
но, спасибо (6) Spacer, оказывается есть.
13. Виталий Трач (vitalya24) 07.08.12 09:12
Интересная статья, кстати насчет торгового оборудования, сканера symbol ls1203, ls2208 и многое другое, если нужно обращайтесь, помогу в подборе и внедрении
14. Владимир Каракозов (karakozov) 08.08.12 09:14
Полезная информация, можно было б конечно и самому придти к решению.Но коллективный разум рулит.Автору плюс.
15. Arshat Amirzhan (Amirzhan) 16.10.12 23:49
Здравствуйте, спасибо за статью и код... сканеры мы настроили и ФР, но вот весы перестали работать... Весы Штрих-М, в плане обмена тупо говорит что нет доступных устройств. С типовой обработкой работает гуд, с вашей, возможность выгружать товары в весы пропала... че делать ?
16. Павел Егоров (SatanClaws) 18.10.12 04:50
(15) А точно отключение весов связано с этим?
Вернуть взад пробовали?
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа