Давайте рассмотрим такую ситуацию.
У нас две базы: одна основана на конфигурации "Управление торговлей" (далее по тексту УТ), а другая на конфигурации "Розница" (далее по тексту РТ). Между базами настроен типовой онлайн обмен. Обе конфигурации сняты с поддержки и мы вольны дорабатывать их как пожелаем. В базе "Розница" учет себестоимости не ведется.
Вдруг возникает необходимость определения себестоимости номенклатуры в базе РТ. Сразу скажу, что первая мысль которая приходит: "Наверное, в нашей архитектуре что-то не так!". Но сейчас мы не будем это обсуждать.
Вторая мысль, которая приходит: "Подключусь к базе УТ из базы РТ используя ComConnector и получу любые данные, которые потребуются". Если воплотить эту мысль в функцию ПолучитьСебестоимостьНоменклатуры(Номенклатура), реализованую в конфигурации РТ, то мы совершим 2 ошибки:
- Смешаем технические особенности написания кода при использовании ComConnector-а и требуемую логику работы
- Разместим логику работы не в подходящем месте - вдали от нужных данных
Как сделать лучше?
А давайте функцию по получению себестоимости реализуем в конфигурации УТ, в области видимости для внешних соединений (пусть это будет модуль внешнего соединения).
Процедура ПолучитьСебестоимостьНоменклатуры(Номенклатура) Экспорт
//Понятная всем реализация алгоритма получения себестоимости номенклатуры
Возврат Себестоимость;
КонецПроцедуры
В свою очередь, в конфигурации РТ добавим общий модуль "МодульПроксиУТ", и все описанные ниже функции разместим в нем. Слово "Прокси" в названии общего модуля - это напоминание того как на самом деле все устроено.
Функция ПолучитьСебестоимостьНоменклатуры(Номенклатура, СоединениеУТ = Неопределено) Экспорт //прокси-функция
//Соединямеся с УТ, если нам не передали соединение
Если СоединениеУТ = Неопределено Тогда
СоединениеУТ = ПолучитьСоединениеУТ();
КонецЕсли;
//Переводим входящие параметры в объекты понятные УТ
НоменклатураУТ = ПолучитьСсылкуУТ(СоединениеУТ, Номенклатура);
//Вызываем функцию, содержащую основную логику
Себестоимость = СоединениеУТ.ПолучитьСебестоимостьНоменклатуры(НоменклатураУТ);
//Обрабатываем результат и переводим в объекты понятные РТ, в данном примере этого не требуется
Возврат Себестоимость;
КонецФункции
Процедура ПолучитьСоединениеУТ() Экспорт
//Определяем данные для подключения к базе УТ и создаем соединение
Соединитель = Новый COMObject("V82.COMConnector");
Соединение = Соединитель.Connect(СтрокаПодключения);
Возврат Соединение;
КонецПроцедуры
Функция ПолучитьУзелОбменаУТ()
//Можно придумать более изящный способ
Возврат ПланыОбмена.ОбменУправлениеТорговлейРозничнаяТорговля.НайтиПоКоду("001");
КонецФункции
Функция ПолучитьСсылкуУТ(СоединениеУТ, СсылкаРТ)
Запрос = Новый Запрос();
Запрос.Текст = "ВЫБРАТЬ
| СоответствиеОбъектовДляОбмена.СобственнаяСсылка КАК СсылкаРТ,
| СоответствиеОбъектовДляОбмена.СсылкаВДругойИБ КАК СтроковаяСсылкаУТ
|ИЗ
| РегистрСведений.СоответствиеОбъектовДляОбмена КАК СоответствиеОбъектовДляОбмена
|ГДЕ
| СоответствиеОбъектовДляОбмена.УзелОбмена = &УзелОбменаУТ
| И СоответствиеОбъектовДляОбмена.СобственнаяСсылка = &СсылкаРТ";
Запрос.УстановитьПараметр("СсылкаРТ", СсылкаРТ);
Запрос.УстановитьПараметр("УзелОбменаУТ", ПолучитьУзелОбменаУТ());
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат СоединениеУТ.ЗначениеИзСтрокиВнутр(Выборка.СтроковаяСсылкаУТ);
Иначе
ВызватьИсключение "Понятный текст исключения";
КонецЕсли;
КонецФункции
Как использовать?
Получение себестоимости номенклатуры в РТ станет красивым и понятным (про производительность и архитектурность я молчу).
В случае если нам нужно получить себестоимость по одной номенклатуре, то достаточно:
Себестоимость = МодульПроксиУТ.ПолучитьСебестоимостьНоменклатуры(Номенклатура);
В случае если нам нужно получить себестоимость сразу по нескольким номенклатурам, то прозрачность кода несколько теряется:
СоединениеУТ = МодульПроксиУТ.ПолучитьСоединениеУТ();
Себестоимость1 = МодульПроксиУТ.ПолучитьСебестоимостьНоменклатуры(Номенклатура1, СоединениеУТ);
Себестоимость2 = МодульПроксиУТ.ПолучитьСебестоимостьНоменклатуры(Номенклатура2, СоединениеУТ);
Особенности прокси-функции
- Количество параметров в прокси-функции на 1 больше чем в реальной - последним параметром передается необязательный параметр соединения
- Первый логический блок функции содержит код по установлению соединения, в случае, если его не установили ранее
- Второй логический блок функции содержит код для перевода входящих параметров в понятные для УТ объекты
- Третий логический блок функции содержит, собственно, вызов реальной функции.
- Четвертый логический блок функции содержит код для перевода результата в понятные для РТ объекты и возвращает результат.
Особенности реализации примера
Справедливости ради нужно сказать, что текущий пример реализации не лишен недостатков. Например, при передаче пустых ссылок или ссылок на перечисления будут возникать проблемы. Так же в статье не описано, как реализовать четвертый логический блок код в прокси-функции, но в этом тоже нет ничего сложного. Наверняка есть и другие подводные камни, которые, я уверен, удастся всегда обойти.
Чего мы добились?
- Разделили технические особенности при работе с ComConnector-ом и основную логику работы
- Разместили код основной логики в правильном месте
- Ну и, как следствие, получили более понятный и удобный для поддержки код
Заключение
Статья не о том как получить себестоимость номенклатуры в РТ по данным УТ, а о том как, используя идею прокси-функций, писать более "чистый" код. Я считаю, что описанный подход нужно по возможности использовать всегда при интеграции с другими системами, а не только при использовании ComConnector-a.
Спасибо за внимание!