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