Как отобразить документы из расширения в дереве подчиненности (связанных документах) 1С?

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

При разработке расширений для конфигураций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с досадным ограничением: новые документы, созданные в расширении, не отображаются в стандартном дереве подчиненности (форме связанных документов). Это происходит потому, что состав стандартного объекта КритерийОтбора.СвязанныеДокументы (или СтруктураПодчиненности) нельзя изменять в расширении. Платформа просто не позволяет добавить новый документ в список состава критерия, так как это потребовало бы реструктуризации индексов основной базы данных.

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

Почему стандартный механизм не видит документы расширения?

Разберем ситуацию подробнее. Типовые конфигурации (УТ 11, ERP, БП 3.0), построенные на базе Библиотеки стандартных подсистем (БСП), используют объект метаданных КритерийОтбора для быстрого поиска ссылок. Когда вы нажимаете кнопку "Связанные документы", система выполняет запрос к этому критерию. Поскольку ваш новый документ из расширения не входит в "белый список" этого критерия в основной конфигурации, система игнорирует его реквизиты, даже если в них записана ссылка на родительский документ.

Для решения этой задачи мы рассмотрим два основных пути: частичная модификация кода поиска через расширение и использование вспомогательного регистра для хранения метаданных связей.

Способ 1. Программное дополнение дерева через расширение формы

Проанализируем программный подход, который позволяет "вклиниться" в процесс построения дерева. Основная логика вывода дерева в БСП обычно сосредоточена в общей форме СвязанныеДокументы или соответствующей обработке. Нам необходимо расширить методы, отвечающие за поиск родительских и дочерних объектов.

Рассмотрим пример кода, который можно внедрить в расширение общей формы. Мы будем использовать аннотацию &ИзменениеИКонтроль, чтобы дополнить стандартный список реквизитов, по которым ищутся связи.


&НаСервере
&ИзменениеИКонтроль("ВывестиРодительскиеОбъекты")
Процедура А_ВывестиРодительскиеОбъекты(ТекущийОбъект, ДеревоРодитель, ВыведенныеОбъекты)
    // Получаем метаданные объекта для анализа его реквизитов
    МетаданныеОбъекта = ТекущийОбъект.Метаданные();
    СписокРеквизитов  = Новый СписокЗначений;

    // Перебираем реквизиты, чтобы найти ссылки на другие документы
    Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
        // Если реквизит не входит в стандартный критерий, проверяем его вручную
        Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Состав.Содержит(Реквизит) Тогда
            // Здесь мы можем добавить проверку: является ли этот реквизит ссылкой на документ
            // Или использовать вспомогательный регистр, как предложено в обсуждении
#Вставка
            // Пример логики: ищем связь в нашем специальном регистре метаданных
            Выборка = РегистрыСведений.А_СвязанныеРеквизиты.Выбрать(Новый Структура("Реквизит", Реквизит.Имя));
            Если НЕ Выборка.Следующий() Тогда
                Продолжить;
            КонецЕсли;
#КонецВставки
        КонецЕсли;

        // Далее идет стандартная логика обработки типа реквизита и добавления в дерево
        // ... (пропущенный стандартный код)
    КонецЦикла;
КонецПроцедуры

Способ 2. Использование вспомогательного регистра метаданных

Выясним причину, по которой использование прямого перебора всех документов может быть неэффективным. Если документов в расширении много, постоянный поиск по всем таблицам замедлит работу формы. Опытные разработчики предлагают использовать вспомогательный Регистр сведений (назовем его А_СвязанныеРеквизиты), в котором будут храниться настройки: какой реквизит какого документа расширения должен учитываться в структуре подчиненности.

Структура такого регистра может быть следующей:

  1. Реквизит (Измерение, Строка) — имя реквизита документа.
  2. Тип (Ресурс, Строка) — тип объекта (например, "Документы").
  3. Вид (Ресурс, Строка) — конкретный вид документа (например, "А_МойНовыйДокумент").
  4. ТЧ (Ресурс, Строка) — имя табличной части, если реквизит находится в ней.

Имея такой регистр, мы можем переопределить функцию поиска объектов по критерию отбора. В расширении для общего модуля или формы используем следующий код:


&НаСервере
&Вместо("ОбъектыПоКритериюОтбора")
Функция А_ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора)
    // Сначала получаем стандартные данные через "ПродолжитьВызов"
    Результат = ПродолжитьВызов(ЗначениеКритерияОтбора);
    
    // Если результат пустой или нам нужно добавить свои данные, создаем таблицу
    Если Результат = Неопределено Тогда
        Результат = Новый ТаблицаЗначений;
        Результат.Колонки.Добавить("Ссылка");
    КонецЕсли;

    // Читаем наши настройки из регистра сведений
    ВыборкаНастроек = РегистрыСведений.А_СвязанныеРеквизиты.Выбрать();
    Пока ВыборкаНастроек.Следующий() Цикл
        // Формируем динамический запрос к документу из расширения
        ИмяТаблицы = ВыборкаНастроек.Тип + "." + ВыборкаНастроек.Вид;
        Если ЗначениеЗаполнено(ВыборкаНастроек.ТЧ) Тогда
            ИмяТаблицы = ИмяТаблицы + "." + ВыборкаНастроек.ТЧ;
        КонецЕсли;

        ТекстЗапроса = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    Т.Ссылка КАК Ссылка
        |ИЗ
        |    " + ИмяТаблицы + " КАК Т
        |ГДЕ
        |    Т." + ВыборкаНастроек.Реквизит + " = &Критерий";

        Запрос = Новый Запрос(ТекстЗапроса);
        Запрос.УстановитьПараметр("Критерий", ЗначениеКритерияОтбора);
        
        ВыборкаДокументов = Запрос.Выполнить().Выбрать();
        Пока ВыборкаДокументов.Следующий() Цикл
            // Добавляем найденные документы в общую таблицу, если их там еще нет
            Если Результат.Найти(ВыборкаДокументов.Ссылка, "Ссылка") = Неопределено Тогда
                Результат.Добавить().Ссылка = ВыборкаДокументов.Ссылка;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Способ 3. Использование механизма "Найти ссылки"

Проанализируем еще один вариант, который не требует создания регистров. Платформа 1С имеет встроенный метод НайтиСсылки(). Мы можем вызвать его программно для текущего документа, и он вернет все объекты в базе данных, которые ссылаются на наш документ, включая те, что созданы в расширениях.

Важный нюанс: метод НайтиСсылки работает медленнее, чем запрос к проиндексированному критерию отбора, поэтому его рекомендуется использовать только в тех случаях, когда количество связей невелико, либо ограничивать область поиска массивом типов документов из вашего расширения.

Пример реализации через поиск ссылок:

  1. Создаем массив, содержащий одну ссылку — наш текущий документ.
  2. Вызываем НайтиСсылки(МассивСсылок).
  3. Полученную таблицу ссылок фильтруем, оставляя только нужные типы документов.
  4. Добавляем результат в дерево подчиненности формы.

Рекомендации по оптимизации

Рассмотрим важные моменты, которые помогут избежать проблем с производительностью:

Подведем итог: несмотря на жесткое ограничение платформы по расширению состава КритериевОтбора, гибкость языка 1С позволяет реализовать обходной путь. Наиболее стабильным и "чистым" решением является перехват процедуры заполнения дерева в форме СвязанныеДокументы с последующим добавлением данных через прямой запрос к таблицам документов расширения.

← На главную