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