К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как обратиться к регистру накопления в 1С

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

Регистр накопления — один из основных объектов хранения количественных и суммовых данных в 1С: остатки товаров, взаиморасчёты, движения денежных средств. Чтобы прочитать или изменить данные регистра, разработчик обращается к нему через менеджер регистра РегистрыНакопления.ИмяРегистра либо через текст запроса на встроенном языке запросов. Выбор способа зависит от задачи: для агрегированных данных (остатки, обороты) почти всегда используется запрос к виртуальным таблицам, а для записи движений — набор записей.

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

Структура регистра накопления: что нужно знать перед обращением

Перед обращением к регистру важно понимать его состав. Регистр накопления состоит из измерений (разрезы учёта: номенклатура, склад, контрагент), ресурсов (числовые показатели: количество, сумма) и реквизитов (дополнительные атрибуты движения). Каждая запись привязана к регистратору — документу, который её создал, и содержит вид движения: Приход или Расход.

Регистры бывают двух видов: остатки и обороты. Для регистра остатков платформа автоматически рассчитывает виртуальную таблицу Остатки, для оборотного регистра такой таблицы нет — доступны только Обороты. Вид регистра задаётся в конфигураторе и определяет, какие виртуальные таблицы доступны в запросах. Проверить вид регистра можно в дереве конфигурации: свойства объекта, поле «Вид регистра».

Обращение через запрос: остатки, обороты и движения

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

Получение остатков на дату

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,

| ТоварыНаСкладахОстатки.Склад КАК Склад,

| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК ТоварыНаСкладахОстатки";

Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("Склад", Склад);

Результат = Запрос.Выполнить().Выгрузить();

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

Получение оборотов за период

Таблица Обороты принимает четыре параметра: начало периода, конец периода, периодичность (День, Месяц, Регистратор и др.) и условие отбора. Если нужна детализация до документов, в параметре периодичности укажите Регистратор — в выборке появится поле Регистратор со ссылкой на документ.

Запрос.Текст =

"ВЫБРАТЬ

| Обороты.Номенклатура КАК Номенклатура,

| Обороты.КоличествоПриход КАК Приход,

| Обороты.КоличествоРасход КАК Расход,

| Обороты.КоличествоОборот КАК Оборот

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Обороты";

Чтение физической таблицы движений

Если нужны сами записи (например, для анализа движений конкретного документа), обращайтесь к таблице без виртуального суффикса: РегистрНакопления.ТоварыНаСкладах. Здесь доступны поля Период, Регистратор, ВидДвижения, измерения, ресурсы и реквизиты. Обязательно накладывайте отбор по регистратору или периоду — выборка всей таблицы движений на крупной базе может выполняться минутами и блокировать других пользователей.

Обращение через встроенный язык без запроса

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

НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);

НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл

Сообщить(Строка(Запись.Номенклатура) + ": " + Запись.Количество);

КонецЦикла;

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

Для быстрой проверки остатка по одной позиции есть метод Остатки() менеджера регистра, но в прикладном коде его используют ограниченно: запрос к виртуальной таблице гибче и позволяет получить данные по произвольному списку измерений одним обращением к базе.

Запись движений: набор записей и движения документа

Стандартный способ формирования движений — обработка проведения документа. В модуле объекта документа коллекция Движения уже содержит наборы записей по всем регистрам, отмеченным в конфигураторе как движения этого документа. Обращение выглядит так: Движения.ТоварыНаСкладах.

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

Движения.ТоварыНаСкладах.Записывать = Истина;

Для Каждого СтрокаТовары Из Товары Цикл

Движение = Движения.ТоварыНаСкладах.Добавить();

Движение.ВидДвижения = ВидДвиженияНакопления.Приход;

Движение.Период = Дата;

Движение.Номенклатура = СтрокаТовары.Номенклатура;

Движение.Склад = Склад;

Движение.Количество = СтрокаТовары.Количество;

КонецЦикла;

КонецПроцедуры

Строка Записывать = Истина обязательна: без неё платформа не запишет набор при проведении. Период каждого движения должен совпадать с датой документа — иначе остатки на дату документа не сойдутся с движениями, и контроль остатков будет работать некорректно.

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

Выбор способа обращения под задачу

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

Маршрут решения

Как выбрать действие

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

Отдельно стоит сказать про обращение к регистру в цикле — антипаттерн, который встречается чаще всего. Если внутри цикла по строкам документа выполняется запрос остатков, время проведения растёт линейно от числа строк. Правильный подход: собрать список номенклатуры, выполнить один запрос с условием Номенклатура В (&СписокНоменклатуры), выгрузить результат в таблицу значений и искать в ней через Найти() или соединение запроса с временной таблицей.

Типичные ошибки и как их избежать

Большинство проблем при работе с регистрами накопления повторяются от проекта к проект. Ниже — те, что встречаются чаще всего и дают самые тяжёлые последствия.

Типичные ошибки
01
Чтение виртуальной таблицы Остатки без параметра периода — остатки считаются на текущую дату, а не на дату документа, контроль остатков даёт неверный результат
02
Отбор по измерениям в секции ГДЕ вместо параметров виртуальной таблицы — запрос сначала рассчитывает остатки по всем измерениям, потом фильтрует, производительность падает в разы
03
Обращение к ресурсу без суффикса (Количество вместо КоличествоОстаток) — ошибка исполнения запроса
04
Запись набора без установки отбора по регистратору — риск затереть или продублировать чужие движения
05
Запрос к регистру внутри цикла по строкам — проведение документа на сотню строк занимает минуты
06
Использование таблицы Остатки у оборотного регистра — такой виртуальной таблицы нет, запрос не выполнится

Ещё одна группа ошибок связана с границами периодов. При передаче даты в параметр виртуальной таблицы остатков помните: остатки рассчитываются на начало указанного момента. Чтобы включить движения всего дня, передавайте КонецДня(Дата) или объект Граница с видом ВидГраницы.Включая — это особенно важно при контроле остатков перед списанием в момент проведения.

Проверка результата после обращения

После реализации обращения к регистру результат нужно проверить, а не полагаться на отсутствие ошибок. Запрос может выполниться успешно, но вернуть пустую или неверную выборку из-за неправильных параметров.

Контрольные точки

Как проверить результат

Содержимое выборки
Норма

Результат.Пустой() = Ложь, суммы и количества сходятся с отчётом по регистру в пользовательском режиме

Тревожный признак

Пустая выборка при заведомо существующих движениях — проверяйте параметры периода и отборы

Остатки после проведения
Норма

Остаток на дату документа изменился ровно на величину движения

Тревожный признак

Остаток не изменился (не установлено Записывать = Истина) или изменился дважды (движения задвоены)

Скорость выполнения
Норма

Запрос по крупной таблице выполняется за секунды, отборы переданы в параметры виртуальной таблицы

Тревожный признак

Запрос выполняется десятки секунд — вероятно, отбор в ГДЕ или чтение без отборов

Период движений
Норма

Поле Период каждой записи равно дате документа-регистратора

Тревожный признак

Период отличается от даты документа — остатки на дату документа не сойдутся

Универсальный способ сверки — стандартный отчёт «Универсальный отчёт» или консоль запросов в режиме предприятия: выполните тот же текст запроса интерактивно и сравните с тем, что возвращает код. Расхождение почти всегда означает разницу в параметрах: другая дата, другой отбор, другая граница.

FAQ

Чем отличается обращение к регистру сведений от регистра накопления?

У регистра накопления есть вид движения (Приход/Расход), обязательный регистратор и виртуальные таблицы остатков и оборотов. Регистр сведений хранит независимые записи, может существовать без регистратора (независимый режим), и у него нет таблиц Остатки/Обороты — вместо них СрезПервых и СрезПоследних для периодических регистров.

Как получить остатки на дату документа, включая его собственные движения?

Передайте в параметр виртуальной таблицы объект Граница: Новый Граница(МоментВремениДокумента, ВидГраницы.Включая). При передаче просто даты или момента времени движения документа в расчёт не попадут, поскольку они записываются на тот же момент.

Можно ли обратиться к регистру накопления из внешней обработки?

Да, код ничем не отличается: те же РегистрыНакопления.ИмяРегистра и запросы к виртуальным таблицам. Ограничение одно — в безопасном режиме (по умолчанию для внешних обработок) недоступны некоторые операции, но чтение и запись регистров через стандартные методы работают.

Почему запрос к таблице Остатки возвращает отрицательные значения?

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

Как очистить все движения документа по регистру?

Создайте набор записей, установите отбор по регистратору и вызовите Записать() без чтения и добавления строк — пустой набор заместит существующие движения. Альтернатива: Движения.ИмяРегистра.Очистить() в модуле документа с последующей записью.

Итог

Что важно запомнить

Чтение агрегатов — запросом к виртуальным таблицам Остатки и Обороты с параметрами периода и отбора. Чтение и запись движений — набором записей с обязательным отбором по регистратору. Не обращайтесь к регистру в цикле, передавайте отборы в параметры виртуальных таблиц и проверяйте результат сверкой с отчётом.