При разработке сложных аналитических отчетов в системе компоновки данных (СКД) часто возникает задача, когда логика расчета ресурса на низких уровнях иерархии напрямую зависит от итогов на верхних уровнях. Классический пример из производственной сферы: если на уровне готового изделия план производства уже выполнен (остаток к производству равен нулю), то и для всех его комплектующих, независимо от их собственного дефицита, отчет должен показывать «ноль» к производству в контексте данной сборки. Разберем, как реализовать такую «каскадную» логику расчета.
Рассмотрим ситуацию, описанную в теме. У нас есть дерево изделий. Если на Уровне 1 потребность в производстве закрыта (осталось произвести 0), то нижестоящие уровни (компоненты) не должны предлагать что-либо производить, даже если расчет по ним самим показывает остаток. Проблема заключается в том, что в СКД ресурсы по умолчанию рассчитываются «снизу вверх» — от детальных записей к общим итогам. Чтобы заставить систему смотреть «сверху вниз», нам потребуется использовать специальные функции языка выражений СКД.
Попытки использовать простое условие через Уровень() часто приводят к тому, что на подчиненных уровнях возвращается NULL или некорректное значение, так как контекст вышестоящей группировки недоступен напрямую в простом выражении ресурса.
Основным инструментом для решения подобных задач является функция ВычислитьВыражение. Она позволяет вычислить агрегатную функцию в контексте любой доступной группировки. Проанализируем, как правильно составить выражение для ресурса.
Допустим, наш ресурс называется ОсталосьПроизвести. Нам нужно, чтобы на подчиненных уровнях система проверяла значение этого же ресурса у родителя. Общая схема выражения в поле «Ресурсы» будет выглядеть следующим образом:
ВЫБОР
КОГДА ВычислитьВыражение("Сумма(ОсталосьПроизвести)", "ИмяВышестоящейГруппировки", "Группировка") = 0
ТОГДА 0
ИНАЧЕ Сумма(ОсталосьПроизвести)
КОНЕЦ
Разберем параметры функции ВычислитьВыражение, которые мы использовали:
"Сумма(ОсталосьПроизвести)" — это то, что мы хотим посчитать на верхнем уровне."ИмяВышестоящейГруппировки" — здесь нужно указать имя группировки, заданное в настройках СКД (на вкладке «Настройки» в структуре отчета). Если мы хотим обратиться к родителю в иерархическом справочнике, можно использовать ключевое слово "Иерархия"."Группировка" — указывает системе, что расчет должен производиться в контексте указанной группировки.Если уровней вложенности много и условие должно проверяться на каждом из них (например, Уровень 3 зависит от Уровня 2, который в свою очередь зависит от Уровня 1), логику следует сделать более универсальной. Рассмотрим пример, где мы проверяем «нулевой» остаток на конкретном уровне:
ВЫБОР
КОГДА СистемныеПоля.Уровень = 1 ТОГДА
Сумма(ОсталосьПроизвести)
КОГДА СистемныеПоля.Уровень = 2 ТОГДА
ВЫБОР
КОГДА ВычислитьВыражение("Сумма(ОсталосьПроизвести)", "ГруппировкаУровень1", "Группировка") = 0
ТОГДА 0
ИНАЧЕ Сумма(ОсталосьПроизвести)
КОНЕЦ
КОГДА СистемныеПоля.Уровень = 3 ТОГДА
ВЫБОР
КОГДА ВычислитьВыражение("Сумма(ОсталосьПроизвести)", "ГруппировкаУровень2", "Группировка") = 0
ТОГДА 0
ИНАЧЕ Сумма(ОсталосьПроизвести)
КОНЕЦ
ИНАЧЕ 0
КОНЕЦ
Важный нюанс: Чтобы это выражение работало корректно, в таблице ресурсов на вкладке «Рассчитывать по...» должны быть установлены флажки для тех группировок, к которым применяется данный расчет. Если оставить поле пустым (рассчитывать везде), СКД может запутаться в контекстах на общих итогах.
В более сложных случаях, когда иерархия динамическая или заранее неизвестно количество уровней, можно применить функцию ВычислитьВыражениеСГруппировкойМассив. Она позволяет собрать значения ресурсов со всех вышестоящих уровней в массив, а затем проверить, есть ли среди них хотя бы один «ноль».
Проанализируем пример такого подхода:
ВЫБОР
КОГДА "0" В ВычислитьВыражениеСГруппировкойМассив("Строка(Сумма(ОсталосьПроизвести))", "Иерархия")
ТОГДА 0
ИНАЧЕ Сумма(ОсталосьПроизвести)
КОНЕЦ
Здесь мы преобразуем суммы в строки для упрощения поиска в массиве (так как поиск в массивах СКД иногда капризен к типам данных). Если в цепочке родителей хотя бы один уровень имеет итоговый остаток 0, то и текущий уровень принудительно обнуляется.
Иногда удобнее вынести часть логики в Вычисляемые поля. Посмотрим, как это сделать. Мы можем создать поле НужноПроизвестиНаВерхнемУровне и прописать в его выражении:
ВычислитьВыражение("Сумма(ОсталосьПроизвести)", "Группировка1", "Группировка")
Затем в ресурсах использовать это вычисляемое поле. Это делает структуру отчета более прозрачной и облегчает отладку, так как вы сможете вывести промежуточное значение родительского ресурса в отдельную колонку и проверить, правильно ли оно определяется на каждом уровне.
ВычислитьВыражение возвращает NULL, убедитесь, что имя группировки во втором параметре в точности совпадает с именем в настройках СКД (регистр важен).СистемныеПоля.Уровень начинает отсчет с 0 или 1 в зависимости от наличия общих итогов. Рекомендуется сначала просто вывести это поле в отчет, чтобы понять текущую нумерацию.ВычислитьВыражение по именованным группировкам на очень больших объемах данных (десятки тысяч строк иерархии) может замедлить отчет. В таких случаях старайтесь максимально подготовить данные еще на уровне запроса.Подводя итог, можно сказать, что механизм ресурсов в СКД обладает достаточной гибкостью для реализации любой бизнес-логики, связанной с иерархией. Главное — правильно определить контекст вычислений и использовать соответствующие функции языка выражений компоновки данных.