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