Как построить и вывести иерархическое дерево подчиненности документов в отчете на СКД в 1С?

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

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

Наша задача заключается в том, чтобы получить все подчиненные документы для заданного документа (будь то заказ, реализация или любой другой) и представить их в отчете в виде иерархической структуры — для этого есть готовая обработка визуализации иерархических связей объектов в 1С. Мы будем строить эту структуру динамически, учитывая все уровни подчиненности – от прямых потомков до 'внуков' и далее.

Понимание подчиненности документов в 1С

Прежде чем приступить к кодированию, нам важно понять, как в 1С организуется подчиненность документов. Существуют два основных механизма:

  1. Через реквизит «ДокументОснование»: Многие документы имеют реквизит ДокументОснование, который ссылается на документ, послуживший основанием для его ввода. Это простой и явный способ установить связь. Например, «Реализация товаров и услуг» может иметь «Заказ покупателя» в качестве документа-основания.
  2. Через движения регистров: Более сложный, но универсальный способ — это когда документы связаны посредством записей в регистрах накопления или бухгалтерии. Например, документ «Поступление на расчетный счет» может быть подчинен документу «Реализация товаров и услуг» через регистр взаиморасчетов, если он частично или полностью оплачивает эту реализацию.

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

Шаг 1: Создание рекурсивной функции для построения дерева

Для начала нам необходимо создать функцию, которая будет рекурсивно обходить все уровни подчиненности, собирая информацию о документах и их уровне вложенности. Эта функция будет возвращать


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

Рассмотрим структуру нашей функции. Она должна принимать как минимум два параметра: ссылку на текущий документ и текущий уровень вложенности (глубину). Внутри функции мы будем создавать


ТаблицуЗначений
, добавлять в нее текущий документ с указанием его представления и отступа. Если вам в дальнейшем понадобится визуализировать подобные структуры из внешних источников, рекомендуем изучить пример того, как преобразуется JSON -> Дерево значений.

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


// Функция для построения дерева подчиненных документов
// Возвращает ТаблицуЗначений со структурой: Документ, Представление, Глубина
// Документ - Ссылка на документ
// Представление - Строка с отступами для вывода в отчет
// Глубина - Число, уровень вложенности
Функция ПостроитьДеревоПодчиненныхДокументов(ДокументСсылка, Глубина = 0) Экспорт

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

    Если ДокументСсылка = Неопределено Тогда
        Возврат ПеременнаяТаблицаЗначений;
    КонецЕсли;

    // Добавляем текущий документ в таблицу
    НоваяСтрока = ПеременнаяТаблицаЗначений.Добавить();
    НоваяСтрока.Документ = ДокументСсылка;
    
    // Формируем отступ для представления
    Отступ = "";
    Для Инд = 1 По Глубина Цикл
        Отступ = Отступ + "    "; // Используем 4 пробела для каждого уровня отступа
    КонецЦикла;
    
    НоваяСтрока.Представление = Отступ + "├ " + ДокументСсылка.Вид() + ": " + ДокументСсылка.Номер + " от " + Формат(ДокументСсылка.Дата, "ДФ=dd.MM.yyyy");
    НоваяСтрока.Глубина = Глубина;

    // Получаем коллекцию подчиненных документов
    КоллекцияПодчиненныхДокументов = ДокументСсылка.ПолучитьДокументыПодчиненные();

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

    Возврат ПеременнаяТаблицаЗначений;

КонецФункции

Важные моменты в функции:

  1. Метод ДокументСсылка.ПолучитьДокументыПодчиненные(): Этот метод является ключевым. Он автоматически анализирует связи документа, сформированные как через реквизит «ДокументОснование», так и через движения по регистрам.
  2. Глубина вложенности: Параметр Глубина позволяет нам отслеживать текущий уровень документа в иерархии и формировать соответствующий отступ в поле Представление.
  3. Форматирование представления: Мы используем пробелы и символ «├ » для наглядного отображения иерархии.
  4. Рекурсивный вызов: Функция вызывает саму себя для каждого подчиненного документа, пока не достигнет самых нижних уровней иерархии.

Шаг 2: Интеграция функции в Систему Компоновки Данных (СКД)

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

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

  1. Добавляем функцию в схему СКД:

    Откройте схему компоновки данных. Создайте новый набор данных – «Объект». В поле «Текст запроса» набора данных типа «Объект» укажем следующее:

    
    ВЫБРАТЬ
        ПодчиненныеДокументы.Документ,
        ПодчиненныеДокументы.Представление,
        ПодчиненныеДокументы.Глубина
    ИЗ
        &ПостроитьДерево(НачальныйДокумент, 0) КАК ПодчиненныеДокументы
    

    Здесь

    
    &ПостроитьДерево
    
    – это имя нашей функции, которую мы должны будем связать с фактическим вызовом.
    
    НачальныйДокумент
    
    – это параметр СКД.

  2. Добавляем параметры и поля:

    На вкладке «Параметры» добавьте параметр

    
    НачальныйДокумент
    
    . На вкладке «Поля» убедитесь, что у нас есть поля: Документ, Представление, Глубина.

  3. Настраиваем макет отчета:

    На вкладке «Настройки» выберите поля для вывода. Чтобы сделать отчет более профессиональным, вы можете выполнить программное изменение заголовка группировки отчета СКД, что позволит скрыть технические заголовки или адаптировать их под нужды пользователя.

Пример использования в модуле отчета

Предположим, у нас есть отчет, и его основной модуль выглядит примерно так:


// Модуль объекта отчета
Перем КомпоновщикМакета;
Перем МакетКомпоновки;
Перем ПроцессорКомпоновки;
Перем ПроцессорВывода;

Функция ПостроитьДеревоПодчиненныхДокументов(ДокументСсылка, Глубина = 0) Экспорт
    // ... код функции из Шага 1 ...
КонецФункции

Процедура ПриКомпоновкеРезультата(ДокументРезультат, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;

    Настройки = ЭтотОбъект.КомпоновщикНастроек.ПолучитьНастройки();
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(ЭтотОбъект.СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);

    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

    ПроцессорВывода.НачатьВывод();
    Пока Истина Цикл
        ЭлементРезультата = ПроцессорКомпоновки.Следующий();
        Если ЭлементРезультата = Неопределено Тогда
            Прервать;
        КонецЕсли;
        ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
    КонецЦикла;
    ПроцессорВывода.ЗакончитьВывод();

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

Дополнительные возможности и оптимизации

Мы можем расширить функциональность нашей функции и отчета:

  1. Фильтрация по типам документов: Если нам нужно включать в дерево не все подчиненные документы, а только определенные типы, мы можем добавить проверку типа документа внутри цикла.
  2. Добавление дополнительной информации: В
    
    ТаблицуЗначений
    
    можно добавить колонки с суммой документа, контрагентом или комментарием.
  3. Обработка циклических ссылок: Чтобы рекурсивная функция не ушла в бесконечный цикл при наличии перекрестных ссылок, рекомендуется вести список уже обработанных документов.

Реализация такого дерева подчиненности документов в отчете на СКД является мощным инструментом для анализа бизнес-процессов. В особо сложных случаях, когда требуется комбинировать различные подходы к выборке данных, можно использовать две разных схемы в отчете СКД, чтобы разделить логику построения дерева и формирования финального отчета. Используя предложенный подход, мы можем значительно повысить информативность наших отчетов и обеспечить более глубокое понимание взаимосвязей между объектами 1С.

← На главную