Как организовать ссылку на объект из одного расширения в другом расширении 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с расширениями конфигурации — мощный инструмент адаптации типовых решений без снятия с поддержки. Однако, когда архитектура доработку усложняется и появляется несколько расширений, разработчики часто сталкиваются с неочевидными ограничениями платформы. Одно из таких ограничений — невозможность в конфигураторе одного расширения (назовем его Расширение2) выбрать в качестве типа данных объект, добавленный в другое расширение (Расширение1).

Разберем подробно, почему возникает эта проблема, почему попытки обмануть платформу через XML не работают, и какие существуют профессиональные способы решения этой задачи.

Суть проблемы и архитектура платформы

Рассмотрим ситуацию, описанную в задаче. У нас есть:

  1. Основная конфигурация (на поддержке, неизменяемая).
  2. Расширение1: в него добавлен новый объект, например, Документ.Документ1.
  3. Расширение2: в него добавлен РегистрСведений.Регистр1.

Задача: сделать так, чтобы измерение регистра в Расширении2 имело тип ссылки на Документ1 из Расширения1.

При попытке сделать это в конфигураторе вы обнаружите, что Документ1 просто отсутствует в списке доступных типов для Расширения2. Платформа видит только объекты основной конфигурации и собственные объекты текущего расширения.

Это происходит потому, что расширения конфигурации проектировались как независимые сущности, накладываемые на основную конфигурацию. Механизм расширений не подразумевает иерархии зависимостей «Расширение зависит от Расширения». При компиляции метаданных каждое расширение проверяется на целостность относительно основной конфигурации, но не относительно соседних расширений.

Почему не работает правка XML?

Многие разработчики пытаются обойти это ограничение, выгружая расширение в XML и вручную прописывая GUID или имя типа из соседнего расширения. Давайте проанализируем, к чему это приводит.

Если вы отредактируете файл Configuration.xml внутри выгрузки расширения и насильно укажете тип, загрузка может пройти успешно. Объект даже может отобразиться в дереве метаданных как «захваченный» или существующий. Однако при попытке обновить конфигурацию базы данных (F7) вы получите ошибку:

Ошибка проверки метаданных: Не найден объект Документ1

Платформа выполняет строгую проверку типов. В контексте Расширения2 метаданные Расширения1 не существуют. Следовательно, тип данных считается битым. Исправить это «волшебным тегом» невозможно — это жесткое ограничение ядра платформы 1С:Предприятие.

Решение 1: Использование обобщенных типов (Слабая типизация)

Самый распространенный способ решения этой задачи без объединения расширений — отказ от строгой типизации в пользу обобщенной.

Вместо того чтобы указывать конкретный тип ДокументСсылка.Документ1 (который невидим), мы можем использовать тип, который гарантированно существует в любой конфигурации — ДокументСсылка (без уточнения вида документа) или, в крайних случаях, ЛюбаяСсылка.

Как это реализовать:

  1. Откройте Расширение2.
  2. Найдите измерение вашего регистра.
  3. В свойстве «Тип» выберите ДокументСсылка (этот тип находится в ветке стандартных реквизитов или общих типов, он включает в себя ссылки на абсолютно все документы системы).

Преимущества:

Недостатки и риски:

Чтобы нивелировать недостатки, в форме записи регистра или форме списка необходимо добавить программный отбор типов. Рассмотрим пример кода для модуля формы:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Ограничиваем выбор типа только нужным документом, 
    // используя его имя в виде строки (так как Тип("...") сработает в Предприятии)
    
    МассивТипов = Новый Массив;
    // Проверяем, существует ли тип в системе (подключено ли Расширение1)
    ТипДокумента1 = Тип("ДокументСсылка.Документ1");
    
    Если ТипДокумента1 <> Неопределено Тогда
        МассивТипов.Добавить(ТипДокумента1);
        Элементы.Измерение1.ОграничениеТипа = Новый ОписаниеТипов(МассивТипов);
    Иначе
        // Если расширение с документом отключено, можно скрыть поле или выдать ошибку
        Элементы.Измерение1.Доступность = Ложь;
    КонецЕсли;

КонецПроцедуры

Решение 2: Программное взаимодействие при проведении

Если ваша задача состоит в том, чтобы Расширение1 писало данные в регистр из Расширения2 (например, при проведении Документа1), то прямая видимость типов в конфигураторе не обязательна.

В режиме «1С:Предприятие» все расширения сливаются в единую конфигурацию. Это значит, что программный код Расширения1 может видеть и писать в регистры Расширения2.

Алгоритм действий:

  1. В Расширении2 создайте регистр сведений. Измерение типизируйте как ДокументСсылка (как описано выше) или УникальныйИдентификатор (если хотите хранить только ID).
  2. В Расширении1 перехватите событие проведения Документа1 или подпишитесь на событие записи.
  3. Используйте метод НаборыЗаписей или менеджер записи для формирования движений.

Пример кода в модуле Расширения1 (обратите внимание, что компилятор может ругаться на неизвестные объекты, если проверять синтаксис строго, поэтому иногда используют Выполнить или получение метаданных через строку, но часто достаточно просто писать код, если вы уверены в именах):


&После("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведения(Отказ, Режим)
    
    // Проверяем, есть ли в системе регистр из Расширения2
    Если Метаданные.РегистрыСведений.Найти("РегистрСведений1") <> Неопределено Тогда
        
        // Создаем набор записей через менеджер, используя строковое имя
        Набор = РегистрыСведений["РегистрСведений1"].СоздатьНаборЗаписей();
        
        // Устанавливаем отбор - в режиме Предприятия это сработает
        Набор.Отбор.Измерение1.Установить(Ссылка);
        
        НовЗапись = Набор.Добавить();
        НовЗапись.Измерение1 = Ссылка;
        НовЗапись.Ресурс1 = 100;
        
        Набор.Записать();
        
    КонецЕсли;

КонецПроцедуры

Этот подход позволяет сохранить независимость расширений. Если Расширение2 (с регистром) будет удалено, проверка Метаданные.Найти вернет Неопределено, и код просто не выполнится, не вызывая критических ошибок.

Решение 3: Объединение расширений (Архитектурно верный подход)

Если объекты двух расширений тесно связаны (один ссылается на другой в метаданных), это верный признак того, что логически они представляют собой единый функциональный блок.

Разделение на «Адаптацию» и «Дополнение» имеет смысл для управления порядком вызовов, но если возникает зависимость данных, лучшим решением будет объединение функционала в одно расширение.

Почему это лучше:

Как объединить:

  1. Выгрузите оба расширения в файлы.
  2. Сравните и объедините одно расширение с другим внутри конфигуратора, перенеся все объекты в одно главное расширение.
  3. Удалите лишнее расширение из базы.

Итог

Попытки «протащить» ссылки между независимыми расширениями через XML обречены на провал из-за механизма проверки метаданных платформой. У вас есть два пути:

  1. Технический (Weak Typing): Использовать тип ДокументСсылка (или СправочникСсылка) в метаданных принимающего расширения и накладывать ограничения программно в формах. Это подходит, если слияние расширений невозможно по административным причинам.
  2. Архитектурный (Merge): Объединить зависимые расширения в одно. Это наиболее правильный способ с точки зрения проектирования системы на 1С.
← На главную