Как реализовать пропорциональное распределение чисел в отчете СКД?

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

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

Метод 1. Программное распределение с помощью БСП

Если нам требуется «бухгалтерская» точность, при которой сумма распределенных частей должна строго равняться исходному числу (задача «последней копейки»), оптимально использовать возможности Библиотеки стандартных подсистем (БСП). Проанализируем использование функции ОбщегоНазначения.РаспределитьСуммуПропорциональноКоэффициентам (подробнее см. Справочник по методам БСП (с примерами использования)).

Алгоритм действий следующий:

  1. Подготавливаем таблицу значений, которая будет служить источником данных для СКД.
  2. Вызываем функцию распределения в модуле отчета или менеджере.
  3. Передаем готовую таблицу в СКД через «Набор данных - объект».

Рассмотрим пример кода для распределения суммы:


// Подготовим массив коэффициентов
МассивКоэффициентов = Новый Массив;
Для Каждого Строка Из ТаблицаДанных Цикл
    МассивКоэффициентов.Добавить(Строка.Коэффициент);
КонецЦикла;

// Распределяем число 100 пропорционально коэффициентам
МассивРезультатов = ОбщегоНазначения.РаспределитьСуммуПропорциональноКоэффициентам(100, МассивКоэффициентов);

// Записываем результат обратно в таблицу
Для Индекс = 0 По МассивРезультатов.ВТ - 1 Цикл
    ТаблицаДанных[Индекс].Результат = МассивРезультатов[Индекс];
КонецЦикла;

Преимущество этого метода в том, что функция БСП автоматически учитывает остатки от округления и распределяет их по элементам с наибольшей дробной частью, обеспечивая идеальный баланс итогов.

Метод 2. Распределение в вычисляемых полях СКД

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

Для реализации формулы Число * (Коэффициент / СуммаКоэффициентов) нам нужно знать общую сумму коэффициентов во всей группировке. В выражении вычисляемого поля напишем следующее:

СуммаДляРаспределения * Коэффициент / ВычислитьВыражение("Сумма(Коэффициент)", "ИмяГруппировки", "ОбщийИтог")

Важные нюансы использования:

Метод 3. Реализация логики распределения в запросе

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

Для этого нам понадобится предварительно вычислить итог коэффициентов во временной таблице. Рассмотрим пример логики:


// Шаг 1: Получаем данные и общую сумму коэффициентов
ВЫБРАТЬ
    Данные.Идентификатор,
    Данные.Коэффициент,
    Суммы.ОбщийКоэффициент,
    &ЧислоДляРаспределения КАК ИсходнаяСумма
ПОМЕСТИТЬ ВТ_Подготовка
ИЗ
    ВТ_ИсходныеДанные КАК Данные
    ЛЕВОЕ СОЕДИНЕНИЕ (
        ВЫБРАТЬ СУММА(Коэффициент) КАК ОбщийКоэффициент ИЗ ВТ_ИсходныеДанные
    ) КАК Суммы ПО ИСТИНА;

// Шаг 2: Расчет с учетом округления
ВЫБРАТЬ
    Идентификатор,
    ВЫРАЗИТЬ(ИсходнаяСумма * Коэффициент / ОбщийКоэффициент КАК ЧИСЛО(15, 2)) КАК Распределено
ИЗ
    ВТ_Подготовка

Чтобы решить проблему «последней копейки» в запросе без итераций, программисты часто применяют «хитрость»: для всех строк, кроме последней, расчет ведется обычным образом, а в последнюю строку помещается разница между общей суммой и суммой всех предыдущих строк. Для этого в запросе нужно определить порядковый номер строки или максимальный ID.

Меток 4. Работа с отрицательными коэффициентами и нулями

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

Рекомендации по обработке:

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

Итоги и рекомендации

Выясним, какой метод выбрать для вашей задачи. Если вы работаете в конфигурации, где подключена БСП (например, 1С:ERP или 1С:MES), и вам важна точность до копейки, используйте Метод 1. Если отчет строится «на лету» и небольшие погрешности округления не критичны для управленческого анализа, Метод 2 с вычисляемыми полями будет самым быстрым в реализации.

Помните, что при работе в MES-системах распределение часто идет не только по стоимостным показателям, но и по весу, объему или нормам времени. В таких случаях всегда проверяйте наличие специализированных процедур в общих модулях, так как они могут учитывать специфику производства, например, кратность упаковок или минимальные партии выпуска.

← На главную