Как корректно получить остатки и движения с детализацией до регистратора в 1С

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

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

Почему в регистрах накопления нет «остатков по регистратору»?

Прежде всего, нам необходимо понять внутреннюю архитектуру платформы «1С:Предприятие». Регистры накопления хранят остатки в специальных итоговых таблицах только в разрезе измерений (например, Номенклатура, Склад). Регистратор не является измерением — это системное поле, которое указывает, какой документ сделал запись в таблицу движений. Рассмотрим ситуацию: на складе лежит 10 единиц товара. Эти 10 единиц могли быть сформированы сотней разных поступлений. Система не хранит информацию о том, какой именно документ «отвечает» за текущий остаток, если только вы не используете партионный учет, где документ прихода явно указан в измерении Партия.

Когда мы запрашиваем остатки «по регистратору», мы на самом деле хотим увидеть состояние регистра на момент времени сразу после проведения конкретного документа. Выясним, какими инструментами это можно реализовать.

Метод 1: Использование виртуальной таблицы ОстаткиИОбороты

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


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

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

  1. Периодичность: Мы используем значение Авто или Регистратор. Это заставляет систему рассчитывать итоги на момент каждого документа.
  2. Поле ПериодСекунда: Рекомендуется всегда выбирать это поле вместе с регистратором, чтобы система компоновки данных (СКД) могла правильно выстроить хронологическую цепочку.
  3. Особенности вывода: По умолчанию виртуальная таблица выдает начальный остаток только для первой записи в периоде, а конечный — только для последней. Чтобы «растянуть» остатки по каждой строке, нам потребуется помощь СКД.

Метод 2: Настройка ролей полей в Системе компоновки данных (СКД)

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

Рассмотрим по шагам, как это сделать:

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

Благодаря этим настройкам СКД самостоятельно проанализирует движения и «протянет» остаток от документа к документу, вычисляя его по формуле Остаток_Предыдущий + Приход - Расход. Для более детального изучения различных математических операций в компоновке можно использовать примеры расчета нарастающего итога и дельты в СКД.

Метод 3: Использование «ДвиженияИГраницыПериода»

Часто возникает проблема: если по товару не было движений за выбранный период, он вообще не попадает в выборку с периодичностью Регистратор, хотя остаток по нему есть. Чтобы этого избежать, в параметрах виртуальной таблицы следует использовать метод дополнения ДвиженияИГраницыПериода.

Это добавит в результат запроса две технические записи:

Посмотрим на пример условия в параметрах таблицы:


РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
    &НачалоПериода, 
    &КонецПериода, 
    Регистратор, 
    ДвиженияИГраницыПериода, 
    Номенклатура = &Номенклатура)

Метод 4: Оптимизация производительности (UNION ALL)

На очень больших объемах данных виртуальная таблица ОстаткиИОбороты может работать медленно, так как она выполняет сложные расчеты «на лету». В высоконагруженных системах практикуется метод объединения (ОБЪЕДИНИТЬ ВСЕ) из трех разных источников:

  1. Выборка начальных остатков из таблицы .Остатки (с пустым регистратором).
  2. Выборка движений из основной таблицы регистра или таблицы .Обороты.
  3. Выборка конечных остатков из таблицы .Остатки на дату конца периода.

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

Важные нюансы и рекомендации

Проанализируем несколько критических моментов, которые помогут избежать ошибок в отчетах:

1. Фильтрация данных. Никогда не накладывайте условия на номенклатуру или склад через конструкцию ГДЕ после основного запроса. Это заставит систему сначала выбрать ВСЕ остатки по ВСЕМ товарам из базы, а потом отсечь лишнее. Всегда используйте параметры виртуальной таблицы:


// ПРАВИЛЬНО
ОстаткиИОбороты(,, Авто,, Номенклатура В (&СписокНоменклатуры))

// НЕПРАВИЛЬНО
ИЗ Регистр.ОстаткиИОбороты(,, Авто,,) ГДЕ Номенклатура = &Номенклатура

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

3. Иерархия в отчете. С точки зрения методологии учета, лучше всего строить отчет с иерархией группировок: Склад -> Номенклатура -> Регистратор. В этом случае на уровнях «Склад» и «Номенклатура» будут выводиться суммарные остатки, а при раскрытии группировки «Регистратор» пользователь увидит детальную историю изменения этих остатков. Это избавляет от визуального нагромождения данных и делает отчет понятным.

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

← На главную