При разработке тиражируемых решений или инструментов администратора часто возникает задача создания одной обработки, которая должна одинаково успешно запускаться в различных конфигурациях, например, в «Бухгалтерии предприятия» и «Управлении торговлей». Основная сложность заключается в том, что при попытке обращения к общему модулю или объекту метаданных, который отсутствует в текущей конфигурации, платформа выдает ошибку компиляции и отказывается открывать форму. Разберем подробно, как обойти эти ограничения и создать по-настоящему универсальный инструмент.
Прежде чем выполнять специфический код, нам необходимо понять, в какой среде запущена обработка. Рассмотрим ситуацию, когда поведение формы должно меняться в зависимости от прикладного решения. Проанализируем способ проверки через метаданные конфигурации. Это наиболее надежный метод, не зависящий от наличия внедренных библиотек.
Для определения конфигурации воспользуемся обращением к свойству Метаданные.Имя. Посмотрим на пример реализации логики управления интерфейсом в обработчике ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ИмяКонфигурации = Метаданные.Имя;
Если ИмяКонфигурации = "БухгалтерияПредприятия" Тогда
// Логика для БП
Элементы.ГруппаЗагрузкаБП.Видимость = Истина;
Элементы.ГруппаВыгрузкаУТ.Видимость = Ложь;
ИначеЕсли ИмяКонфигурации = "УправлениеТорговлей" Тогда
// Логика для УТ
Элементы.ГруппаЗагрузкаБП.Видимость = Ложь;
Элементы.ГруппаВыгрузкаУТ.Видимость = Истина;
Иначе
Сообщить("Внимание: данная конфигурация не поддерживается в полном объеме.");
КонецЕсли;
КонецПроцедуры
Главная проблема «универсальности» — это жесткие ссылки на общие модули в коде. Если вы напишете МодульОбмена.ВыполнитьВыгрузку(), и этого модуля не окажется в базе, форма не откроется. Выясним, как решают эту задачу разработчики фирмы «1С» в Библиотеке стандартных подсистем (БСП).
Для безопасного обращения к функционалу используется программный интерфейс модуля ОбщегоНазначения. Рассмотрим алгоритм действий:
Проанализируем пример кода, который позволяет безопасно инициализировать параметры, используя методы БСП:
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
// Получаем программный доступ к модулю по его строковому имени
МодульУправлениеКИ = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
// Теперь мы можем вызывать экспортные методы модуля через переменную
ДополнительныеПараметры = МодульУправлениеКИ.ПараметрыКонтактнойИнформации();
ДополнительныеПараметры.ТипПомещения = "Офис";
МодульУправлениеКИ.ПриСозданииНаСервере(ЭтотОбъект, Объект, ДополнительныеПараметры);
КонецЕсли;
Этот подход позволяет платформе игнорировать отсутствие модуля при предварительной проверке кода, так как поиск модуля УправлениеКонтактнойИнформацией будет происходить только в момент выполнения строки кода ОбщегоНазначения.ОбщийМодуль().
Если в вашей конфигурации не используется БСП или вы разрабатываете максимально автономную обработку, рассмотрим метод использования функций Выполнить() и Вычислить(). Это позволяет полностью скрыть вызовы специфических процедур от компилятора 1С.
Посмотрим, как можно реализовать вызов функции загрузки данных, которая существует только в определенных базах:
ИмяМодуля = "МодульИнтеграцииСМаркетплейсами";
Если Метаданные.ОбщиеМодули.Найти(ИмяМодуля) <> Неопределено Тогда
ПараметрыВызова = "Параметр1, Параметр2";
ТекстВызова = ИмяМодуля + ".ВыполнитьЗагрузкуДанных(" + ПараметрыВызова + ")";
Попытка
Выполнить(ТекстВызова);
Исключение
ЗаписьЖурналаРегистрации("Ошибка универсальной обработки",
УровеньЖурналаРегистрации.Ошибка, , , ПодробноеОписаниеОшибки());
КонецПопытки;
КонецЕсли;
Важно: использование Выполнить() затрудняет отладку (не работает переход по F12) и может незначительно снижать производительность при массовых вызовах, поэтому применяйте этот метод только для «точек входа» в специфический код конфигурации.
Часто универсальная выгрузка требует наличия на форме полей, тип которых зависит от конфигурации (например, ссылка на справочник Склады в УТ и отсутствие такового в специализированной базе). Если вы просто добавите реквизит в редакторе формы, обработка не запустится там, где этого типа нет.
Разберем, как программно добавлять реквизиты и элементы на форму. Используем метод ИзменитьРеквизиты(). Проанализируем последовательность действий:
&НаСервере
Процедура ДобавитьСпецифичноеПоле()
// Проверяем наличие типа в метаданных
Если Метаданные.Справочники.Найти("Склады") <> Неопределено Тогда
// 1. Описываем новый реквизит
МассивДобавляемыхРеквизитов = Новый Массив;
ТипСклада = Новый ОписаниеТипов("СправочникСсылка.Склады");
МассивДобавляемыхРеквизитов.Add(Новый РеквизитФормы("ВыбранныйСклад", ТипСклада, , "Склад выгрузки"));
// 2. Добавляем реквизит на форму
ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
// 3. Создаем элемент управления (поле ввода) для этого реквизита
ЭлементСклад = Элементы.Добавить("ВыбранныйСклад", Тип("ПолеФормы"), Элементы.ГруппаПараметры);
ЭлементСклад.Вид = ВидПоляФормы.ПолеВвода;
ЭлементСклад.ПутьКДанным = "ВыбранныйСклад";
КонецЕсли;
КонецПроцедуры
При реализации обмена между разными конфигурациями мы часто сталкиваемся с тем, что имена реквизитов совпадают, а типы или их состав — нет. Чтобы код не «падал» при обращении к несуществующему свойству объекта, рассмотрим метод ЗаполнитьЗначенияСвойств().
Этот метод является встроенным механизмом «безопасного» копирования данных. Проанализируем его преимущество: он копирует только те свойства, которые есть и в источнике, и в приемнике, игнорируя всё остальное без вызова исключений.
// Допустим, ОбъектПриемник — это ДокументОбъект в текущей базе,
// а СтруктураДанных — полученная информация из другой базы.
ЗаполнитьЗначенияСвойств(ОбъектПриемник, СтруктураДанных);
// Даже если в структуре есть поле "СтавкаНДС", а в документе его нет, ошибки не будет.
Создание универсальной формы для выгрузки и загрузки — это всегда баланс между гибкостью и сложностью поддержки. Подведем итоги того, что мы узнали:
Применяя эти методы в совокупности, вы сможете создать мощный и стабильный инструмент, который будет работать в любой современной конфигурации на платформе 1С:Предприятие 8.3.