Как программно получить список связанных документов в УТ 11 и ERP?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В современных конфигурациях 1С, таких как "Управление торговлей 11" (УТ 11), "Комплексная автоматизация" (КА) или ERP, задача получения структуры подчиненности (связанных документов) является весьма распространенной. Пользователи видят красивое дерево связей по кнопке "Отчеты - Связанные документы", но когда перед программистом встает задача получить этот список программным кодом, возникают нюансы.

Рассмотрим ситуацию, с которой часто сталкиваются разработчики: необходимо получить список связанных объектов для документов разных типов — например, РеализацияТоваровУслуг, ПриходныйКассовыйОрдер (ПКО) и ОперацияПоПлатежнойКарте — здесь пригодится обработка автоматического поиска и выгрузки связанных объектов.

Почему не работает стандартный подход "в лоб"?

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

Однако на практике мы сталкиваемся со следующей картиной:

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

Разберем причину такого поведения. КритерийОтбора работает как индекс: он ищет ссылки на переданный объект в реквизитах других объектов. Когда мы ищем связи для "Реализации", система находит ПКО, потому что в ПКО есть ссылка на Реализацию (в реквизите "Основание" или "ОбъектРасчетов"). Но когда мы ищем связи для ПКО, система ищет документы, которые ссылаются на ПКО. Чаще всего на платежные документы никто не ссылается (если это не возврат), поэтому список пуст.

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

Решение задачи: комбинированный алгоритм

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

Алгоритм действий будет следующим:

  1. Определяем тип исходного документа.
  2. Если это финансовый документ (оплата), нам нужно найти документ-основание (родителя). Для этого анализируем табличную часть с расшифровкой платежа.
  3. Если это товаросопроводительный документ (накладная), нам нужно найти подчиненные документы (оплаты, счета-фактуры). Для этого используем КритерийОтбора.

Шаг 1. Поиск документа-основания (Родителя)

Для документов типа ПриходныйКассовыйОрдер или ОперацияПоПлатежнойКарте в УТ 11 связь с основанием хранится, как правило, в табличной части РасшифровкаПлатежа. Прямой реквизит "ДокументОснование" в шапке часто отсутствует или используется для других целей, так как один платеж может закрывать несколько накладных.

Посмотрим на код, который извлекает основание платежа:


// Предположим, что в переменной СсылкаНаОбъект находится ссылка на ПКО или Эквайринговую операцию

Если ТипЗнч(СсылкаНаОбъект) = Тип("ДокументСсылка.ОперацияПоПлатежнойКарте") ИЛИ
    ТипЗнч(СсылкаНаОбъект) = Тип("ДокументСсылка.ПриходныйКассовыйОрдер") Тогда
        
    Запрос = Новый Запрос;
    // Формируем текст запроса динамически, подставляя имя таблицы документа
    // Это позволяет использовать один код для разных видов документов оплаты
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    ДокРасшифровкаПлатежа.ОснованиеПлатежа КАК ОснованиеПлатежа
    |ИЗ
    |    Документ." + СсылкаНаОбъект.Метаданные().Имя + ".РасшифровкаПлатежа КАК ДокРасшифровкаПлатежа
    |ГДЕ
    |    ДокРасшифровкаПлатежа.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
    ВыборкаДетальныеЗаписи = Запрос.Выполнить().Выбрать();
    
    // Если найдено основание, обновляем нашу ссылку, чтобы искать связи уже для основания
    Если ВыборкаДетальныеЗаписи.Следующий() Тогда
        СсылкаНаОбъект = ВыборкаДетальныеЗаписи.ОснованиеПлатежа;
    КонецЕсли;
    
КонецЕсли;

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

Шаг 2. Поиск подчиненных документов (Детей)

Теперь, когда у нас есть ссылка на документ товародвижения (например, РеализацияТоваровУслуг), мы можем воспользоваться стандартным механизмом платформы для поиска всех, кто на него ссылается.

Здесь КритерийОтбора.СвязанныеДокументы работает отлично. Однако, чтобы не тянуть в выборку лишние технические документы (например, записи книги продаж или движения по регистрам, если они регистраторы), полезно наложить фильтр по типу документа.


Если ТипЗнч(СсылкаНаОбъект) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
        
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    СвязанныеДокументы.Ссылка КАК Ссылка
    |ИЗ
    |    КритерийОтбора.СвязанныеДокументы(&Ссылка) КАК СвязанныеДокументы
    |ГДЕ
    |   (ТИПЗНАЧЕНИЯ(СвязанныеДокументы.Ссылка) = ТИП(Документ.ОперацияПоПлатежнойКарте)
    |    ИЛИ ТИПЗНАЧЕНИЯ(СвязанныеДокументы.Ссылка) = ТИП(Документ.ПриходныйКассовыйОрдер))";
        
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
    
    // Выгружаем результат в массив или список
    СписокСвязанных = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
    
    // Не забываем добавить и сам документ-основание в список, если это требуется по логике задачи
    СписокСвязанных.Добавить(СсылкаНаОбъект);

КонецЕсли;

Универсальный подход через Метаданные

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

Универсальный алгоритм поиска "родителей" выглядит так:

  1. Получаем метаданные текущего документа: Ссылка.Метаданные().
  2. Перебираем коллекцию Реквизиты. Проверяем каждый реквизит: является ли он ссылочного типа (ДокументСсылка)? Если да — читаем значение этого реквизита. Это потенциальный "родитель".
  3. Перебираем коллекцию ТабличныеЧасти. Для каждой ТЧ перебираем ее Реквизиты. Ищем те, что ссылаются на документы. Если находим — выполняем запрос к этой табличной части.

Такой подход используется в типовых подсистемах БСП (Библиотека Стандартных Подсистем), которые встроены в УТ 11 и ERP; подробнее изучить их можно, используя справочник по методам БСП.

Важные замечания по производительности

При реализации поиска связей стоит помнить о RLS (ограничении прав доступа на уровне записей). Запросы к критериям отбора, такие как КритерийОтбора.СвязанныеДокументы, при включенном RLS могут работать медленно, если в цепочке есть документы, недоступные пользователю.

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

← На главную