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