Как в СКД рассчитать отклонение себестоимости между последним и предпоследним периодами?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке отчетов по фактической себестоимости в системе компоновки данных (СКД) часто возникает задача не просто вывести данные по периодам (месяцам, кварталам или годам), но и наглядно показать динамику. Типовой сценарий: в колонках отображаются периоды, а в конце таблицы необходимо добавить вычисляемые колонки «Изменение в рублях» и «Изменение в %» между двумя последними значащими периодами. Рассмотрим, как решить эту задачу, переходя от «громоздких» формул к изящным механизмам платформы 1С.

Проблема «жесткого» кодирования периодов

Часто программисты пытаются решить задачу «в лоб», используя конструкцию ВЫБОР КОГДА в ресурсах. Проанализируем типичный пример такого кода, который может занимать десятки строк. В этом случае расчет привязывается к конкретным датам параметров, например, к текущему и предыдущему году:


ВЫРАЗИТЬ(ВЫБОР КОГДА 
    СУММА(ВЫБОР КОГДА ГОД(ПериодМесяц) + 1 = ГОД(&ДатаКонца) ТОГДА КоличествоВыпуск ИНАЧЕ 0 КОНЕЦ) = 0 
    ТОГДА 0 
    ИНАЧЕ (Сумма(ВЫБОР КОГДА ГОД(Period) = ГОД(&ДатаКонца) ТОГДА Стоимость ИНАЧЕ 0 КОНЕЦ) / ... )
КОНЕЦ, "Число(15,4)")

Основные недостатки такого подхода:

  1. Низкая гибкость: Если пользователь изменит периодичность (например, захочет сравнить не годы, а месяцы), формула перестанет работать корректно.
  2. Сложность поддержки: Огромные формулы на 30 и более строк трудно читать, в них легко допустить ошибку при проверке деления на ноль.
  3. Проблемы с иерархией: При использовании иерархических группировок (например, Продукция с иерархией) такие вычисления могут некорректно агрегировать данные на верхних уровнях.

Решение через функцию ВычислитьВыражение

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

Чтобы получить значение ресурса из предыдущей колонки в кросс-таблице, мы можем использовать относительную адресацию. Рассмотрим пример вычисления себестоимости предыдущего периода:


ВычислитьВыражение("Сумма(Стоимость) / Выбор Когда Сумма(КоличествоВыпуск) = 0 Тогда 1 Иначе Сумма(КоличествоВыпуск) Конец", 
    "Период", 
    "Группировка", 
    "Предыдущая", 
    "Предыдущая")

В этой формуле мы указываем системе, что расчет должен производиться в контексте группировки Период, а ключевое слово "Предыдущая" указывает на смещение относительно текущей колонки. Таким образом, СКД сама найдет «соседа» слева, независимо от того, какой сейчас год или месяц.

Использование агрегатных функций с фильтрами (для платформы 8.3.20+)

Если ваша платформа версии 8.3.20 и выше, мы можем значительно упростить выражения в ресурсах, используя встроенные фильтры. Это избавляет нас от громоздких ВЫБОР КОГДА внутри агрегатов. Посмотрим на разницу в написании:

Вместо старого варианта:

СУММА(ВЫБОР КОГДА Год(Период) = 2023 ТОГДА Стоимость ИНАЧЕ 0 КОНЕЦ)

Мы используем новый, более производительный синтаксис:

Сумма(Стоимость) ГДЕ Год(Период) = 2023

Это делает код чище и понятнее. Однако, для вычисления отклонения «последний минус предпоследний» нам все равно потребуется логика определения этих периодов.

Продвинутый метод: ВычислитьВыражениеСГруппировкойТаблицыЗначений

Если отчет предполагает сложную структуру, где периоды могут идти «с дырками» (например, есть данные за январь и март, но нет за февраль), лучше всего использовать функцию ВычислитьВыражениеСГруппировкойТаблицыЗначений. Этот метод позволяет «свернуть» данные во внутреннюю таблицу значений, отсортировать её и программно обратиться к любой строке.

Рассмотрим алгоритм действий:

  1. Создаем вычисляемое поле, например, СебестоимостьДляСравнения.
  2. В ресурсах для этого поля прописываем выражение, которое собирает все значения себестоимости в массив.
  3. Используем функцию Получить(Индекс), чтобы извлечь последнее и предпоследнее значение из этого массива.

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

Настройка ролей полей периодов

Проанализируем еще один важный аспект: роли полей. Чтобы функции смещения ("Предыдущая") работали корректно, СКД должна понимать хронологический порядок данных. Для этого в наборе данных для полей периодов (Месяц, Квартал, Год) необходимо настроить свойство «Роль».

Убедитесь, что для поля периода установлен флаг «Период» и указан правильный тип (например, 1 для основного периода). Это позволит системе правильно выстраивать последовательность колонок, даже если в некоторых периодах отсутствуют данные (пустые значения будут дополнены, если включена соответствующая настройка в СКД).

Итоговая формула отклонения

Выяснив все возможности, соберем итоговую формулу для ресурса ИзменениеСебестоимостиПроцент. Мы будем использовать ВычислитьВыражение, чтобы расчет был динамическим:


// Вычисляем разницу между текущей и предыдущей себестоимостью
(
  (Сумма(Стоимость) / Сумма(КоличествоВыпуск)) 
  - 
  ВычислитьВыражение("Сумма(Стоимость) / Сумма(КоличествоВыпуск)", "Период", "Группировка", "Предыдущая", "Предыдущая")
) 
/ 
ВычислитьВыражение("Сумма(Стоимость) / Сумма(КоличествоВыпуск)", "Период", "Группировка", "Предыдущая", "Предыдущая") * 100

Важно: Не забывайте добавлять проверки на деление на ноль (ЕСТЬNULL или ВЫБОР КОГДА), чтобы отчет не выдавал ошибку при отсутствии данных в предыдущем периоде.

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

← На главную