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