Как в СКД вывести документы иерархично по реквизиту «Основание»?

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

В отличие от справочников, у документов в платформе 1С отсутствует встроенная (стандартная) иерархия. Однако на практике очень часто возникает необходимость вывести документы в виде древовидной структуры. Типичный пример — цепочки документов, когда один документ создается на основании другого (например, первоначальный «Проект договора» и подчиненные ему дополнительные соглашения, у которых заполнен реквизит Основание).

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

Решение 1. Настройка собственной иерархии через связи наборов данных

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

Рассмотрим по шагам процесс настройки этого механизма:

  1. Подготовка набора данных (запроса): Создадим один набор данных-запрос (например, с именем НаборДанных1). В запросе выберем ссылку на сам документ, реквизит его основания, а также все необходимые аналитические и числовые поля.

    Посмотрим на пример такого запроса:

    
    ВЫБРАТЬ
        ПроектДоговора.Ссылка КАК Ссылка,
        ПроектДоговора.Основание КАК ДокументОснование,
        ПроектДоговора.Контрагент КАК Контрагент,
        ПроектДоговора.Сумма КАК Сумма
    ИЗ
        Документ.ПроектДоговора КАК ПроектДоговора
    
  2. Настройка связи набора данных «сам с собой»: Перейдем на вкладку «Связи наборов данных» в конструкторе СКД и добавим новую строку со следующими параметрами:
    • Источник связи: НаборДанных1
    • Приемник связи: НаборДанных1
    • Выражение источник: Ссылка
    • Выражение приемник: ДокументОснование
    • Начальное значение связи: Значение(Документ.ПроектДоговора.ПустаяСсылка) (это важнейшая настройка, указывающая СКД, что построение дерева нужно начинать с документов, у которых нет вышестоящего основания).
  3. Настройка структуры отчета: Перейдем на вкладку «Настройки». Вместо стандартной группировки «Детальные записи» добавим новую группировку по полю Ссылка. В свойствах этой группировки (тип группировки) выберем значение «Иерархия». В выбранные поля добавим Ссылка, Контрагент и Сумма.

При такой настройке СКД автоматически построит дерево подчиненности. Документы, не имеющие основания, станут корневыми узлами, а документы-наследники расположатся на соответствующих подуровнях.

Решение 2. Корректный расчет ресурсов (сумм) без задвоения

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

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

Чтобы ресурсы считались правильно, настроим их следующим образом:

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

Решение 3. Избавление от дублирования записей («Лишней иерархии»)

При построении собственной иерархии часто возникает визуальный дефект: документ-родитель сначала отображается как папка (узел дерева), а затем этот же самый документ дублируется внутри своей же ветки как подчиненный элемент (детальная запись).

Проанализируем ситуацию и применим один из способов решения этой проблемы:

Способ А: Наложение отбора на уровне группировки

В настройках структуры отчета выберем нашу иерархическую группировку Ссылка. Перейдем во вкладку «Отбор» этой группировки и добавим системное поле:

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

Способ Б: Фильтрация через вычисляемое поле

Мы можем создать вычисляемое поле с использованием функции СКД ВычислитьВыражение:

ВычислитьВыражение("Ссылка", "", "Иерархия")

Затем в настройках отчета мы накладываем условие, отсекающее строки, у которых значение самого документа совпадает с вычисленным значением родителя на уровне детальных записей.

Решение 4. Альтернативный вариант подготовки данных в запросе (для высоконагруженных систем)

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

Для этого мы можем выполнить следующие шаги:

  1. С помощью временных таблиц в запросе определим связи документов и вычислим их уровень вложенности (например, Уровень 1, Уровень 2, Уровень 3).
  2. Сформируем специальное текстовое поле «Путь» (например, "000001/000005/000012"), которое будет содержать коды или уникальные идентификаторы всех родительских документов по цепочке.
  3. В СКД выведем обычный плоский список документов, но настроим сортировку отчета по созданному полю «Путь».
  4. Для визуальной имитации дерева создадим вычисляемое поле для наименования документа, в котором с помощью выражения добавим отступы (пробелы) перед названием документа в зависимости от его уровня вложенности:

СтрокаПовторить(" ", УровеньВложенности) + Представление(Ссылка)

Такой подход работает значительно быстрее на больших объемах данных, так как СУБД выполняет линейную сортировку по проиндексированному полю пути быстрее, чем СКД осуществляет рекурсивную сборку дерева на клиенте или сервере приложений.

← На главную