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