Как в СКД рассчитать начальный остаток при детализации по документам?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При построении отчетов по материальным потокам в системе компоновки данных (СКД) разработчики часто сталкиваются с задачей вывода движений в хронологическом порядке. Если для укрупненных группировок (например, по номенклатуре или складу) расчет входящего и исходящего остатка формируется штатно, то при добавлении в структуру отчета группировки по регистратору расчет начального остатка для каждого конкретного документа может сбиваться, дублироваться или вовсе обнуляться.

Ситуация дополнительно усложняется, когда данные собираются не из классического регистра накопления остатков, а из регистров сведений (например, отдельных таблиц ожидаемой приемки и отгрузки). В таких случаях механизм виртуальных таблиц недоступен, и разработчик вынужден моделировать поведение регистратора вручную. Разберем по шагам, почему возникает эта проблема и как настроить расчет остатка по документам несколькими надежными способами.

Причины некорректного расчета остатков по регистратору

Проанализируем механику работы СКД при расчете периодических итогов. Для того чтобы платформа могла рассчитать входящее сальдо на каждый документ, ей необходимо четко понимать строгую хронологическую последовательность записей. Здесь возникают следующие препятствия:

  1. Коллизии по времени: В платформе 1С стандартная точность поля типа Дата составляет одну секунду. Если в пределах одной секунды зарегистрировано несколько документов, СКД без явных дополнительных настроек не может определить их взаимный порядок, из-за чего входящие остатки между ними распределяются непредсказуемо.
  2. Появление пустых строк регистратора: При использовании стандартных ролей остатков платформа стремится зафиксировать срез на границу периода. Если движений в периоде не было, но есть входящий остаток, СКД формирует фиктивную строку с незаполненным регистратором (со значением NULL).
  3. Нарушение иерархии группировок: Механизм ролей СКД рассчитывает остатки по документу корректно только тогда, когда регистратор подчинен календарному периоду (например, периоду-секунде или дню), либо когда поле периода выведено в этой же группировке.

Способ 1. Настройка ролей полей и упорядочивания в наборе данных

Рассмотрим классический способ, основанный на правильном распределении ролей полей компоновки данных. Если в наборе данных присутствуют поля ПериодСекунда (или Период) и Регистратор, платформе необходимо явно подсказать порядок их вложенности и правила сортировки.

Выполним следующую последовательность действий на вкладке «Наборы данных»:

  1. Найдем поле ПериодСекунда (или Период). В колонке «Роль» укажем тип Период, порядковый номер 1 и установим флаг Обязательное.
  2. Для поля Регистратор откроем настройку роли: выберем тип Период, укажем порядковый номер 2, установим признак Обязательное, а также взведем флаг Игнорировать NULL (это исключит появление пустых паразитных строк в отчете).
  3. Если в запросе присутствует поле НомерСтроки, добавим его в роли как Период с порядковым номером 3 и признаком Обязательное для полного исключения коллизий.
  4. В свойствах поля Регистратор настроим колонку «Выражение упорядочивания». Зададим явную сортировку: ПериодСекунда Возр, Регистратор.МоментВремени Возр
  5. В настройках структуры отчета для всех уровней группировок с периодом и регистратором установим автосортировку (или оставим сортировку пустой, чтобы СКД применила заданные выражения упорядочивания).

Благодаря такой настройке платформа связывает дату и документ в единую последовательную цепочку, что позволяет штатным механизмам рассчитать начальный остаток для каждой отдельной строки документа.

Способ 2. Расчет через функции выражений СКД (нарастающий итог)

В случаях, когда данные берутся из нескольких регистров сведений или произвольных таблиц, штатный механизм ролей остатков может работать нестабильно. Рассмотрим альтернативный и очень гибкий способ — расчет начального остатка с помощью языка выражений СКД на вкладке «Ресурсы».

В этом подходе мы отказываемся от настройки ролей остатков в наборе данных и рассчитываем входящее и исходящее сальдо программно через функцию ВычислитьВыражение.

Для ресурса НачальныйОстаток в таблице ресурсов укажем формулу расчета для группировки по документу:


ЕСТЬNULL(ВычислитьВыражение("Сумма(Приход - Расход)", , , "Первая", "Предыдущая"), 0) + &НачальныйОстатокОтчета

Разберем параметры функции: выражение суммирует оборот с первой по предыдущую строку относительно текущей позиции, формируя входящее сальдо непосредственно перед проведением текущего документа. К полученному нарастающему итогу прибавляется входящий остаток на дату начала отчета, переданный через параметр &НачальныйОстатокОтчета.

Для исходящего остатка текущей строки документа на вкладке «Ресурсы» пропишем формулу:


ВычислитьВыражение("Сумма(Приход - Расход)", , , "Первая", "Текущая") + &НачальныйОстатокОтчета

Важный момент: расчет нарастающего итога через язык выражений жестко привязан к физическому порядку строк в результирующей таблице. Поэтому в отчете должна быть строго настроена сортировка строк по хронологии (по дате документа и моменту времени).

Способ 3. Расчет остатков во временных таблицах запроса

Если требуется гарантировать одинаковый результат расчета независимо от настроек пользователя в структуре отчета СКД, перенесем логику вычисления остатка непосредственно в текст запроса.

Посмотрим, как это реализовать:

  1. Формируем временную таблицу всех движений (объединяя приходы и расходы из регистров сведений) с фиксацией момента времени каждого документа.
  2. Рассчитываем общее входящее сальдо на дату начала отчета в отдельной таблице.
  3. Соединяем таблицу движений саму с собой по условию предшествования:
    
    ВТ_Движения1.Период > ВТ_Движения2.Период 
    ИЛИ (ВТ_Движения1.Период = ВТ_Движения2.Период И ВТ_Движения1.Регистратор > ВТ_Движения2.Регистратор)
    
  4. Суммируя обороты предшествующих записей и прибавляя сальдо на начало отчета, получаем готовые поля НачальныйОстаток и КонечныйОстаток прямо в выборке запроса. В СКД эти поля выводятся как простые числовые ресурсы с агрегатной функцией Сумма() или Максимум().

Архитектурные рекомендации

Построение отчетов по остаткам и движениям на основе регистров сведений имеет существенный минус: отсутствие готовых итогов. Для вычисления остатка на любой момент времени СУБД вынуждена сканировать и агрегировать все строки от начала ведения базы, что при росте документооборота приводит к замедлению работы отчета.

В типовой архитектуре 1С учет материальных ценностей, ожидаемых приемок и отгрузок рекомендуется вести с использованием регистров накопления вида «Остатки». В таком случае расчет входящих и исходящих остатков на любую точку времени (включая срез на каждый регистратор) полностью берет на себя виртуальная таблица ОстаткиИОбороты с периодичностью Авто или Регистратор, исключая необходимость сложных ручных настроек.

← На главную