Как правильно рассчитать итоги по реквизиту в иерархии СКД без учета детальных записей

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

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

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

Почему стандартные функции дают сбой в иерархии

Рассмотрим типовую ситуацию. Мы строим отчет по взаиморасчетам, где детальными записями являются документы-регистраторы, а группировкой — ДоговорКонтрагента. У договора есть реквизит ПлановаяСумма. Если мы просто укажем в ресурсах Сумма(ПлановаяСумма), то СКД сложит это значение столько раз, сколько документов-регистраторов попало в отчет по этому договору. Это классическая ошибка дублирования итогов.

Для решения этой проблемы часто применяют функцию ВЫЧИСЛИТЬВыражениеСГруппировкойМассив. Казалось бы, логика проста: собрать массив минимальных значений по договору и просуммировать их на уровне выше. Однако, как только мы включаем иерархию по полю ДоговорКонтрагента, механизм "ломается".

Выясним причину: в СКД при расчете иерархических уровней контекст вычисления "схлопывается". Поле, по которому строится иерархия, на родительских узлах принимает значение самого родителя. В итоге функция ВЫЧИСЛИТЬВыражениеСГруппировкойМассив не может корректно проитерировать подчиненные элементы, так как для системы они становятся неотличимы от контекста текущей группы. Все значения подменяются значением родителя, и итоговая сумма превращается в минимум или максимум одного значения.

Способ №1: Метод дублирующего поля (самый надежный)

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

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

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

Способ №2: Разделение наборов данных

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

Выполним следующие шаги:

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

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

Способ №3: Использование функции ВычислитьВыражение с контекстом

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


Сумма(ВычислитьВыражениеСГруппировкойМассив("Минимум(ПлановаяСумма)", "ДоговорКонтрагента", , "Группировка"))

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

Важные нюансы при работе с иерархией в ресурсах

Разберем несколько критических моментов, о которых стоит помнить:

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

← На главную