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