Почему в СКД неправильно рассчитываются начальные и конечные остатки таблицы ОстаткиИОбороты и как это исправить

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

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

Анализ проблемы и типичные ошибки в запросе

Рассмотрим типовой пример запроса к регистру накопления, в котором проявляется проблема:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ДолгТараОстаткиИОбороты.Контрагент,
    ДолгТараОстаткиИОбороты.КоличествоПриход,
    ДолгТараОстаткиИОбороты.КоличествоРасход,
    ДолгТараОстаткиИОбороты.Регистратор,
    ДолгТараОстаткиИОбороты.КоличествоНачальныйОстаток,
    ДолгТараОстаткиИОбороты.КоличествоКонечныйОстаток,
    ДолгТараОстаткиИОбороты.Маршрут,
    ДолгТараОстаткиИОбороты.НомерДоставки,
    ДолгТараОстаткиИОбороты.ПериодСекунда,
    ДолгТараОстаткиИОбороты.Склад,
    ДолгТараОстаткиИОбороты.Регистратор.Сделка КАК ЗаказПокупателя
ИЗ
    РегистрНакопления.ДолгТара.ОстаткиИОбороты(, , Авто, , ) КАК ДолгТараОстаткиИОбороты
ГДЕ
    ДолгТараОстаткиИОбороты.Контрагент.Наименование <> " "
    И ДолгТараОстаткиИОбороты.Регистратор.Сделка <> ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)

Выделим ключевые причины, из-за которых расчет итогов по остаткам дает сбой:

  1. Использование ключевого слова РАЗЛИЧНЫЕ: Механизм СКД при формировании итогов и расчете начальных и конечных остатков генерирует подзапросы и рассчитывает агрегаты. Наличие директивы РАЗЛИЧНЫЕ ломает внутренний механизм СКД по разбору периодов, в результате чего платформа начинает просто суммировать поля остатков.
  2. Фильтрация по реквизитам регистратора в секции ГДЕ: Остатки в регистрах накопления физически хранятся исключительно в разрезе измерений регистра. Реквизиты документов (например, Регистратор.Сделка) не являются измерениями. Когда мы отсекаем часть документов через ГДЕ, мы разрываем непрерывную цепочку движений. СКД не может вычислить срез остатка на начало периода без отсеченных движений, так как такого остатка физически не существует в базе.
  3. Отбор по измерениям вне параметров виртуальной таблицы: Условие по контрагенту также наложено в блоке ГДЕ, а не передано в параметры виртуальной таблицы, что заставляет СУБД сначала сформировать полную таблицу итогов, а затем отсечь строки.

Способ 1. Изменение структуры регистра накопления

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

  1. Добавим в регистр накопления ДолгТара новое измерение Сделка (или ЗаказПокупателя).
  2. Перепроведем документы, чтобы движения заполнили новое измерение.
  3. В запросе СКД установим отбор непосредственно в параметрах виртуальной таблицы:

ВЫБРАТЬ
    ДолгТараОстаткиИОбороты.Контрагент КАК Контрагент,
    ДолгТараОстаткиИОбороты.Сделка КАК ЗаказПокупателя,
    ДолгТараОстаткиИОбороты.ПериодСекунда КАК ПериодСекунда,
    ДолгТараОстаткиИОбороты.Регистратор КАК Регистратор,
    ДолгТараОстаткиИОбороты.КоличествоНачальныйОстаток КАК КоличествоНачальныйОстаток,
    ДолгТараОстаткиИОбороты.КоличествоПриход КАК КоличествоПриход,
    ДолгТараОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
    ДолгТараОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
ИЗ
    РегистрНакопления.ДолгТара.ОстаткиИОбороты(, , Авто, , Сделка <> ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)) КАК ДолгТараОстаткиИОбороты

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

Способ 2. Разделение данных на независимые наборы (Остатки и Обороты)

Если менять структуру регистра нельзя, но нужно вывести остатки по контрагенту в целом, а обороты — только по определенным заказам, используем разделение на три набора данных в схеме компоновки:

  1. Набор 1 (Начальный остаток): запрос к таблице Остатки на дату начала периода без отборов по регистраторам.
  2. Набор 2 (Обороты): запрос к таблице Обороты с отбором по Регистратор.Сделка.
  3. Набор 3 (Конечный остаток): запрос к таблице Остатки на дату окончания периода без отборов по регистраторам.
  4. Свяжем полученные наборы данных на вкладке «Связи наборов данных» по общему полю Контрагент.

Способ 3. Корректная настройка ролей полей и ресурсов в СКД

Если детальные записи выводятся с регистратором и периодичностью ПериодСекунда, необходимо правильно описать роли полей на вкладке «Наборы данных»:

  1. Уберем из запроса ключевое слово РАЗЛИЧНЫЕ.
  2. Для поля ПериодСекунда установим роль Период, Порядок = 1.
  3. Для поля Регистратор установим роль Период, Порядок = 2.
  4. Для поля ЗаказПокупателя (если это реквизит регистратора) укажем роль Измерение с указанием родителя Регистратор.
  5. Для полей остатков настроим роли: для начального — НачальныйОстаток (с привязкой к ПериодСекунда), для конечного — КонечныйОстаток.
  6. На вкладке «Ресурсы» проверим, чтобы остатки рассчитывались не через банальное суммирование Сумма(КоличествоНачальныйОстаток) для всех уровней, а только для соответствующих группировок.

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

← На главную