Разработка и Конфигурация · 12 мин
Как обратиться к регистру накопления в 1С
Как обратиться к регистру накопления в 1С: выборка записей, остатки, обороты через запросы и встроенный язык. Примеры кода, ошибки и проверка результата.
Регистр накопления — один из основных объектов хранения количественных и суммовых данных в 1С: остатки товаров, взаиморасчёты, движения денежных средств. Чтобы прочитать или изменить данные регистра, разработчик обращается к нему через менеджер регистра РегистрыНакопления.ИмяРегистра либо через текст запроса на встроенном языке запросов. Выбор способа зависит от задачи: для агрегированных данных (остатки, обороты) почти всегда используется запрос к виртуальным таблицам, а для записи движений — набор записей.
Ошибки при обращении к регистрам накопления — частая причина медленных отчётов и неверных остатков. Типичные проблемы: чтение физической таблицы вместо виртуальной, отсутствие отборов, обращение к регистру в цикле. Ниже разобраны рабочие способы обращения к регистру с примерами кода, условиями выбора и проверкой результата.
Структура регистра накопления: что нужно знать перед обращением
Перед обращением к регистру важно понимать его состав. Регистр накопления состоит из измерений (разрезы учёта: номенклатура, склад, контрагент), ресурсов (числовые показатели: количество, сумма) и реквизитов (дополнительные атрибуты движения). Каждая запись привязана к регистратору — документу, который её создал, и содержит вид движения: Приход или Расход.
Регистры бывают двух видов: остатки и обороты. Для регистра остатков платформа автоматически рассчитывает виртуальную таблицу Остатки, для оборотного регистра такой таблицы нет — доступны только Обороты. Вид регистра задаётся в конфигураторе и определяет, какие виртуальные таблицы доступны в запросах. Проверить вид регистра можно в дереве конфигурации: свойства объекта, поле «Вид регистра».
Обращение через запрос: остатки, обороты и движения
Основной способ чтения данных регистра — запрос. Менеджер регистра здесь не нужен: в тексте запроса указывается полное имя таблицы вида РегистрНакопления.ТоварыНаСкладах.Остатки. Точка после имени регистра открывает доступ к виртуальным таблицам.
Получение остатков на дату
Виртуальная таблица Остатки принимает параметры: период (дата или граница, на которую считаются остатки) и условие отбора по измерениям. Параметры указываются в скобках после имени таблицы. Всегда передавайте период явно — без него платформа построит остатки на текущую дату, что не всегда совпадает с логикой задачи.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.Склад КАК Склад,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("Склад", Склад);
Результат = Запрос.Выполнить().Выгрузить();
Обратите внимание на имена полей: ресурсы в виртуальных таблицах получают суффиксы — КоличествоОстаток в таблице остатков, КоличествоПриход и КоличествоРасход в таблице оборотов. Обращение к ресурсу без суффикса в виртуальной таблице вызовет ошибку исполнения запроса.
Получение оборотов за период
Таблица Обороты принимает четыре параметра: начало периода, конец периода, периодичность (День, Месяц, Регистратор и др.) и условие отбора. Если нужна детализация до документов, в параметре периодичности укажите Регистратор — в выборке появится поле Регистратор со ссылкой на документ.
Запрос.Текст =
"ВЫБРАТЬ
| Обороты.Номенклатура КАК Номенклатура,
| Обороты.КоличествоПриход КАК Приход,
| Обороты.КоличествоРасход КАК Расход,
| Обороты.КоличествоОборот КАК Оборот
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Обороты";
Чтение физической таблицы движений
Если нужны сами записи (например, для анализа движений конкретного документа), обращайтесь к таблице без виртуального суффикса: РегистрНакопления.ТоварыНаСкладах. Здесь доступны поля Период, Регистратор, ВидДвижения, измерения, ресурсы и реквизиты. Обязательно накладывайте отбор по регистратору или периоду — выборка всей таблицы движений на крупной базе может выполняться минутами и блокировать других пользователей.
Обращение через встроенный язык без запроса
Для операций с записями используется менеджер регистра РегистрыНакопления.ИмяРегистра. Он предоставляет методы СоздатьНаборЗаписей() и СоздатьМенеджерЗаписи(). Набор записей — основной инструмент: он всегда привязан к регистратору через отбор и позволяет прочитать, изменить или полностью заменить движения документа.
НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Сообщить(Строка(Запись.Номенклатура) + ": " + Запись.Количество);
КонецЦикла;
Менеджер записи (СоздатьМенеджерЗаписи()) применяется редко — он работает с одной строкой регистра и требует заполнения полного ключа записи. В типовых задачах (проведение, корректировка движений) практически всегда достаточно набора записей.
Для быстрой проверки остатка по одной позиции есть метод Остатки() менеджера регистра, но в прикладном коде его используют ограниченно: запрос к виртуальной таблице гибче и позволяет получить данные по произвольному списку измерений одним обращением к базе.
Запись движений: набор записей и движения документа
Стандартный способ формирования движений — обработка проведения документа. В модуле объекта документа коллекция Движения уже содержит наборы записей по всем регистрам, отмеченным в конфигураторе как движения этого документа. Обращение выглядит так: Движения.ТоварыНаСкладах.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ТоварыНаСкладах.Записывать = Истина;
Для Каждого СтрокаТовары Из Товары Цикл
Движение = Движения.ТоварыНаСкладах.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = СтрокаТовары.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = СтрокаТовары.Количество;
КонецЦикла;
КонецПроцедуры
Строка Записывать = Истина обязательна: без неё платформа не запишет набор при проведении. Период каждого движения должен совпадать с датой документа — иначе остатки на дату документа не сойдутся с движениями, и контроль остатков будет работать некорректно.
При записи набора вручную (вне проведения) помните: метод Записать() по умолчанию замещает все существующие движения этого регистратора в регистре. Если нужно добавить записи к существующим, сначала прочитайте набор, добавьте строки и только потом записывайте.
Выбор способа обращения под задачу
Разные задачи требуют разных подходов, и неверный выбор — источник проблем с производительностью. Ориентируйтесь на тип данных, которые нужны: агрегаты читаются запросом к виртуальным таблицам, отдельные записи — набором записей или запросом к физической таблице, запись — только через наборы записей.
Как выбрать действие
Отдельно стоит сказать про обращение к регистру в цикле — антипаттерн, который встречается чаще всего. Если внутри цикла по строкам документа выполняется запрос остатков, время проведения растёт линейно от числа строк. Правильный подход: собрать список номенклатуры, выполнить один запрос с условием Номенклатура В (&СписокНоменклатуры), выгрузить результат в таблицу значений и искать в ней через Найти() или соединение запроса с временной таблицей.
Типичные ошибки и как их избежать
Большинство проблем при работе с регистрами накопления повторяются от проекта к проект. Ниже — те, что встречаются чаще всего и дают самые тяжёлые последствия.
Ещё одна группа ошибок связана с границами периодов. При передаче даты в параметр виртуальной таблицы остатков помните: остатки рассчитываются на начало указанного момента. Чтобы включить движения всего дня, передавайте КонецДня(Дата) или объект Граница с видом ВидГраницы.Включая — это особенно важно при контроле остатков перед списанием в момент проведения.
Проверка результата после обращения
После реализации обращения к регистру результат нужно проверить, а не полагаться на отсутствие ошибок. Запрос может выполниться успешно, но вернуть пустую или неверную выборку из-за неправильных параметров.
Как проверить результат
Результат.Пустой() = Ложь, суммы и количества сходятся с отчётом по регистру в пользовательском режиме
Пустая выборка при заведомо существующих движениях — проверяйте параметры периода и отборы
Остаток на дату документа изменился ровно на величину движения
Остаток не изменился (не установлено Записывать = Истина) или изменился дважды (движения задвоены)
Запрос по крупной таблице выполняется за секунды, отборы переданы в параметры виртуальной таблицы
Запрос выполняется десятки секунд — вероятно, отбор в ГДЕ или чтение без отборов
Поле Период каждой записи равно дате документа-регистратора
Период отличается от даты документа — остатки на дату документа не сойдутся
Универсальный способ сверки — стандартный отчёт «Универсальный отчёт» или консоль запросов в режиме предприятия: выполните тот же текст запроса интерактивно и сравните с тем, что возвращает код. Расхождение почти всегда означает разницу в параметрах: другая дата, другой отбор, другая граница.
FAQ
Чем отличается обращение к регистру сведений от регистра накопления?
У регистра накопления есть вид движения (Приход/Расход), обязательный регистратор и виртуальные таблицы остатков и оборотов. Регистр сведений хранит независимые записи, может существовать без регистратора (независимый режим), и у него нет таблиц Остатки/Обороты — вместо них СрезПервых и СрезПоследних для периодических регистров.
Как получить остатки на дату документа, включая его собственные движения?
Передайте в параметр виртуальной таблицы объект Граница: Новый Граница(МоментВремениДокумента, ВидГраницы.Включая). При передаче просто даты или момента времени движения документа в расчёт не попадут, поскольку они записываются на тот же момент.
Можно ли обратиться к регистру накопления из внешней обработки?
Да, код ничем не отличается: те же РегистрыНакопления.ИмяРегистра и запросы к виртуальным таблицам. Ограничение одно — в безопасном режиме (по умолчанию для внешних обработок) недоступны некоторые операции, но чтение и запись регистров через стандартные методы работают.
Почему запрос к таблице Остатки возвращает отрицательные значения?
Отрицательный остаток означает, что расход превысил приход: либо документы списания проведены без контроля остатков, либо есть движения более поздней датой, а вы смотрите остаток на ранний момент. Проверьте хронологию документов и включите контроль остатков в обработке проведения расходных документов.
Как очистить все движения документа по регистру?
Создайте набор записей, установите отбор по регистратору и вызовите Записать() без чтения и добавления строк — пустой набор заместит существующие движения. Альтернатива: Движения.ИмяРегистра.Очистить() в модуле документа с последующей записью.
Что важно запомнить
Чтение агрегатов — запросом к виртуальным таблицам Остатки и Обороты с параметрами периода и отбора. Чтение и запись движений — набором записей с обязательным отбором по регистратору. Не обращайтесь к регистру в цикле, передавайте отборы в параметры виртуальных таблиц и проверяйте результат сверкой с отчётом.