Как вытащить регистратор из таблицы «ОстаткиИОбороты» и получить корректные остатки в 1С?

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

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

В чем заключается ошибка и почему искажаются остатки?

Проанализируем типичный запрос, в котором возникают некорректные остатки:


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

В данном примере допущены основные системные ошибки:

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

Способ 1. Перенос условий в параметры виртуальной таблицы

Рассмотрим, как правильно передавать условия. Любые отборы по регистраторам или документам необходимо задавать непосредственно в параметрах виртуальной таблицы в поле Условие, а не в секции ГДЕ основного запроса.

Посмотрим на исправление запроса:


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

Способ 2. Правильная настройка ролей полей в СКД

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

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

В этом случае СКД включит встроенные алгоритмы расчета итогов и не станет рассчитывать остаток как простую сумму значений строк регистраторов.

Способ 3. Разделение на остатки и обороты (Схема ОБЪЕДИНИТЬ ВСЕ)

Наиболее производительным и архитектурно правильным решением является разделение источников данных. В одном запросе объединяются итоговые остатки из таблицы Остатки и детальные движения из таблицы Обороты.

Разберем пример такого построения запроса:


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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ТоварыОбороты.Номенклатура,
    ТоварыОбороты.Склад,
    ТоварыОбороты.Регистратор,
    ТоварыОбороты.ПериодСекунда,
    0,
    ТоварыОбороты.ВНаличииПриход,
    ТоварыОбороты.ВНаличииРасход
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ТоварыОбороты

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

← На главную