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