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