Как вывести остатки номенклатуры в печатной форме накладной в 1С 8.3?

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

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

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

Причины ошибки «Несоответствие типов» при вызове метода Остатки()

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


// Ошибочный вариант:
ТабОстатков = Остатки.Остатки(Фильтр, "Номенклатура", "Количество");
// Или:
ТабОстатков = Остатки.Остатки("Дата", ВыборкаСтрокТовары.Товар, "Номенклатура", "Количество");

Проанализируем сигнатуру метода РегистрыНакопления.<ИмяРегистра>.Остатки():

  1. Период — тип Дата, МоментВремени, Граница или Неопределено. Передача строкового литерала "Дата" или структуры отбора первым параметром вызывает исключение о несоответствии типов.
  2. Отбор — тип Структура. Ключами структуры должны быть строковые имена измерений регистра, а значениями — фильтрующие элементы (ссылки, массивы).
  3. Измерения — тип Строка. Список измерений, по которым группируются остатки, разделенный запятыми.
  4. Ресурсы — тип Строка. Список ресурсов регистра для расчета остатка через запятую.

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


Отбор = Новый Структура;
Отбор.Вставить("Организация", Шапка.Организация);
Отбор.Вставить("Номенклатура", ВыборкаСтрокТовары.Номенклатура);

ТаблицаОстатков = РегистрыНакопления.ТоварыОрганизацийБУ.Остатки(
    Шапка.МоментВремени, 
    Отбор, 
    "Номенклатура", 
    "Количество"
);

Однако вызов данного метода внутри цикла обхода строк табличной части документа — грубая архитектурная ошибка (проблема N+1 запросов к базе данных), приводящая к существенным задержкам при печати многострочных накладных.

Оптимальное решение: получение остатков единым запросом

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

Разберем по шагам создание запроса для модуля менеджера документа:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	РеализацияТовары.НомерСтроки КАК НомерСтроки,
|	РеализацияТовары.Номенклатура КАК Номенклатура,
|	РеализацияТовары.Количество КАК Количество,
|	РеализацияТовары.Сумма КАК Сумма,
|	РеализацияТовары.СуммаНДС КАК СуммаНДС,
|	ЕСТЬNULL(ТоварыОстатки.КоличествоОстаток, 0) КАК ПечОстатокТовара
|ИЗ
|	Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыОрганизацийБУ.Остатки(
|		&ПериодОстатков,
|		Организация = &Организация
|			И Номенклатура В
|				(ВЫБРАТЬ РАЗЛИЧНЫЕ
|					ДокТовары.Номенклатура
|				ИЗ
|					Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
|				ГДЕ
|					ДокТовары.Ссылка = &Ссылка)) КАК ТоварыОстатки
|	ПО РеализацияТовары.Номенклатура = ТоварыОстатки.Номенклатура
|ГДЕ
|	РеализацияТовары.Ссылка = &Ссылка
|УПОРЯДОЧИТЬ ПО
|	РеализацияТовары.НомерСтроки";

// Установка параметров запроса
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Запрос.УстановитьПараметр("Организация", СсылкаНаДокумент.Организация);

// Точка расчета остатков (на момент времени документа)
Запрос.УстановитьПараметр("ПериодОстатков", СсылкаНаДокумент.МоментВремени());

РезультатЗапроса = Запрос.Выполнить();
ВыборкаСтрокТовары = РезультатЗапроса.Выбрать();

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

В зависимости от бизнес-логики печатной формы точка расчета остатка может отличаться:

  1. Остаток на момент документа без учета его проведения: если накладная уже проведена, но требуется напечатать остаток, который был до списания, используем объект Граница с видом исключения:
    
    ГраницаОстатков = Новый Граница(СсылкаНаДокумент.МоментВремени(), ВидГраницы.Исключая);
    Запрос.УстановитьПараметр("ПериодОстатков", ГраницаОстатков);
    
  2. Остаток после проведения документа: передается СсылкаНаДокумент.МоментВремени() или граница ВидГраницы.Включая.
  3. Текущий оперативный остаток на складе: в параметр периода передается значение Неопределено или ТекущаяДата().

Вывод данных в табличный документ

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


ТабДокумент = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Печать");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

Пока ВыборкаСтрокТовары.Следующий() Цикл
    
    // Заполнение параметров макета из полей выборки
    ОбластьСтрока.Параметры.Заполнить(ВыборкаСтрокТовары);
    
    // Переопределение строкового представления при необходимости
    ОбластьСтрока.Параметры.Товар = СокрЛП(ВыборкаСтрокТовары.Номенклатура);
    
    // Значение ПечОстатокТовара заполнится автоматически методом Заполнить(),
    // так как имя поля в запросе совпадает с именем параметра в макете
    
    ТабДокумент.Вывести(ОбластьСтрока);
    
КонецЦикла;

Важные правила работы с остатками в печатных формах

При реализации печатных форм обратите внимание на следующие требования:

  1. Полный состав измерений: Регистры учета номенклатуры обычно содержат измерения Организация, Номенклатура, а также могут содержать Склад, Характеристика и Серия. Фильтрация только по номенклатуре вернет общий остаток по всей базе. Обязательно ограничивайте срез остатков организацией и складом документа.
  2. Условия в параметрах виртуальной таблицы: Все фильтры по номенклатуре и организации следует накладывать в круглых скобках параметров виртуальной таблицы Остатки(...), а не в секции ГДЕ или ПО. Это исключает избыточное чтение данных с сервера СУБД.
  3. Права доступа (RLS): Если печатная форма доступна пользователям с ограниченными правами, для чтения регистров без ошибок доступа может потребоваться включение привилегированного режима: УстановитьПривилегированныйРежим(Истина).
← На главную