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