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