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