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