Как в СКД распределить показатель вышестоящей группировки по подчиненным строкам?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке аналитических отчетов в 1С часто возникает задача: рассчитать агрегированный показатель на уровне родительской группировки (например, средний остаток задолженности по клиенту или соглашению) и затем распределить это значение по детальным записям или подчиненной группировке (например, по документам реализации) пропорционально их выручке или себестоимости.

Рассмотрим структуру типового отчета со следующей иерархией группировок:

  1. Организация
  2. Клиент
  3. Соглашение
  4. Реализация (подчиненная группировка / детальные записи)

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

Разберем способы реализации такого механизма средствами системы компоновки данных и альтернативные подходы.

Способ 1. Использование функции ВычислитьВыражение на вкладке «Ресурсы»

Самое компактное и гибкое решение без изменения структуры запроса заключается в настройке формул ресурсов для разных уровней группировок СКД.

Проанализируем механику: на уровне группировки Соглашение рассчитывается исходная база (средний долг), а на уровне группировки Реализация формула обращается к итогам вышестоящего уровня через функцию ВычислитьВыражение.

Разберем настройку по шагам:

  1. Перейдем на вкладку Ресурсы в схеме компоновки данных.
  2. Добавим поле СреднийДолг для вышестоящих группировок (в колонке Рассчитывать по... укажем Организация, Клиент, Соглашение и общий итог): Среднее(КонечныйОстаток) или при расчете по количеству дней периода: Сумма(КонечныйОстаток) / Количество(ДнейВПериоде)
  3. Добавим еще одну строку для поля СреднийДолг, но в колонке Рассчитывать по... укажем только группировку Реализация (или детальные записи):
    
    Выбор
        Когда ВычислитьВыражение("Сумма(Выручка)", "Соглашение") = 0 Тогда
            0
        Иначе
            ВычислитьВыражение("Сумма(СреднийДолг)", "Соглашение") * Сумма(Выручка) / ВычислитьВыражение("Сумма(Выручка)", "Соглашение")
    Конец
    

Посмотрим, как работает это выражение:

  1. ВычислитьВыражение("Сумма(СреднийДолг)", "Соглашение") — извлекает расчетное значение среднего долга из родительской группировки Соглашение.
  2. Сумма(Выручка) — берет сумму выручки текущей строки (конкретного документа Реализация).
  3. ВычислитьВыражение("Сумма(Выручка)", "Соглашение") — определяет общую сумму выручки по всему соглашению, выступающую базой распределения.
  4. Конструкция Выбор Когда ... = 0 защищает расчет от ошибки деления на ноль, если общая сумма реализации по соглашению отсутствует.

Важно: имя группировки во втором параметре функции ВычислитьВыражение должно строго совпадать с именем поля группировки в настройках отчета.

Ограничение распределения через формулы СКД: проблема округления

Выясним важный нюанс математического распределения в СКД. Вычисления по формулам ресурсов выполняются независимо для каждой строки. Из-за этого при округлении до копеек сумма распределенных значений подчиненных строк может отличаться от исходной суммы на уровне родительской группировки на 1–2 копейки.

В стандартном языке выражений СКД нет встроенного механизма, который отслеживает накопленный остаток и относит копейки погрешности на последнюю или наибольшую строку. Если в ТЗ критично строгое равенство копейка в копейку, рассмотрим альтернативные варианты реализации.

Способ 2. Расчет коэффициентов на уровне запроса

Если требуется зафиксировать распределение до вывода в компоновку, выполним расчет в тексте запроса набора данных:

  1. Во временной таблице рассчитываем средний остаток долга, сгруппированный до уровня Соглашение.
  2. Во второй временной таблице собираем обороты продаж по документам и считаем общую сумму продаж по соглашению с помощью аналитических функций или связки группировок.
  3. Соединяем таблицы по соглашению и вычисляем распределенный долг прямо в запросе:
    
    ВЫБОР
        КОГДА ПродажиПоСоглашению.ВсегоВыручка = 0 ТОГДА
            0
        ИНАЧЕ
            ОстаткиПоСоглашению.СреднийДолг * ПродажиПоДокументам.Выручка / ПродажиПоСоглашению.ВсегоВыручка
    КОНЕЦ КАК СреднийДолг
    

Способ 3. Программное распределение через «Набор данных — Объект»

Для абсолютной точности копеек перенесем распределение в модуль объекта отчета:

  1. Формируем промежуточный результат запроса в таблицу значений.
  2. Обходим группировки и вызываем типовой алгоритм распределения пропорционально коэффициентам (где остаток от округления относится на максимальную строку).
  3. Передаем готовую таблицу значений в СКД через внешний набор данных НаборДанных1:
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ВнешниеНаборы = Новый Структура("ТаблицаДанных", ГотоваяТаблицаЗначений);
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборы);
    

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

← На главную