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

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке отчетов на системе компоновки данных (СКД) мы часто сталкиваемся с задачей детализации движений по документам-регистраторам. Типичная ситуация: необходимо построить отчет по заказам (на производство или покупателя) и показать хронологию изменения остатка по каждому документу. Казалось бы, задача тривиальная — взять виртуальную таблицу ОстаткиИОбороты и вывести поля.

Однако на практике мы сталкиваемся с проблемой, которую описал автор темы: остатки начинают «скакать». Конечный остаток одной строки не совпадает с начальным остатком следующей. Например, первый документ закрыл остаток 7, а следующий документ показывает начальный остаток 0 или 3. Давайте разберемся, почему так происходит, и проанализируем методы решения этой задачи, чтобы получить корректный, непрерывный поток остатков.

Суть проблемы: почему рвутся цепочки остатков?

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

Предположим, у нас есть регистр с измерениями: Заказ, Номенклатура.

  1. Документ №1 делает приход по Товару А в рамках Заказа 1.
  2. Документ №2 делает расход по Товару Б в рамках того же Заказа 1.

Если мы строим отчет с группировкой по Заказу, а затем детальные записи по Регистратору, система видит это так:

Для СКД это два разных потока данных. Конечный остаток Товара А никак не перетекает в начальный остаток Товара Б. Именно поэтому мы видим нули или неожиданные цифры в колонке «Начальный остаток» следующей строки — система показывает остаток именно по тому набору измерений, который участвовал в движении этого документа.

Решение 1: Агрегация на уровне запроса (если детализация не нужна)

Если нам необходимо видеть общую картину по Заказу, игнорируя, какая именно номенклатура двигалась, самым простым решением будет исключение лишних измерений из выборки.

В конструкторе запроса схемы компоновки данных:

  1. Выбираем таблицу ОстаткиИОбороты.
  2. Настраиваем параметры виртуальной таблицы. В поле «Периодичность» указываем Регистратор.
  3. Важный момент: в запросе мы не выбираем поле Номенклатура. Мы группируем данные по Заказу и Регистратору, суммируя ресурсы.

Однако этот метод работает не всегда. Часто нам все же нужно видеть номенклатуру в других группировках или использовать её для расшифровки. Если мы просто уберем измерение, мы потеряем аналитику. Если оставим — получим разрыв остатков.

Решение 2: Расчет нарастающего итога через функции СКД

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

Мы будем имитировать поведение ведомости: текущий остаток = остаток на начало периода + все обороты с начала периода до текущего момента.

Шаг 1. Подготовка полей

В наборе данных запроса нам понадобятся:

Шаг 2. Настройка вычисляемых полей или ресурсов

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

Чтобы получить Конечный остаток по строке (нарастающим итогом внутри Заказа), используем следующую логику:

Конечный остаток = Остаток на начало отчета + Сумма всех оборотов от первой записи до текущей.

Формула для ресурса «КонечныйОстаток» (на уровне группировки по Регистратору):


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

Разберем параметры функции:

Чтобы получить Начальный остаток для текущей строки (чтобы он совпадал с конечным предыдущей), нам нужно просуммировать обороты до предыдущей строки:

Формула для ресурса «НачальныйОстаток»:


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

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

Технические нюансы настройки

Чтобы описанный выше метод работал корректно и строки не перемешивались, нарушая хронологию (что приведет к неверному нарастающему итогу), необходимо соблюсти несколько правил.

1. Настройка ролей полей

Система должна понимать хронологию документов. Зайдем на вкладку Наборы данных, выделим поле Регистратор (или ПериодСекунда, если вы его используете) и проверим колонку «Роль».

2. Порядок группировок

В настройках отчета структура должна быть следующей:

  1. Группировка Заказ.
  2. Вложенная группировка Регистратор (или Детальные записи, если они упорядочены).

Вычисление выражения с параметрами "Первая", "Текущая" корректно работает именно в рамках родительской группировки (Заказа).

3. Обработка NULL

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


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

Пример результата

Применив этот подход, мы получим следующую картину в отчете:

Заказ №1 (Начальный остаток: 0)

Как видите, несмотря на то, что во втором документе участвовал Товар Б, начальный остаток для него был взят как общий итог по Заказу (10), а не 0. Цепочка остатков стала непрерывной.

Заключение

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

← На главную