Как правильно составить запрос к остаткам номенклатуры по документу в 1С, если остатки уходят в ноль

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке учетных систем на платформе 1С часто возникает задача отобразить список материалов или товаров из документа вместе с актуальными остатками на складах и в резерве. Популярная ошибка начинающих разработчиков — выбор виртуальной таблицы остатков РегистрНакопления.ВнутренниеЗаказы.Остатки в качестве первой (ведущей) таблицы в секции ИЗ.

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

Причина возникновения проблемы

Разберем ситуацию подробно. Когда в секции ИЗ указывается виртуальная таблица остатков регистра накопления, платформа 1С возвращает только те записи (измерения и ресурсы), по которым итоговый остаток не равен нулю.

Если по заказу или акту диагностики создается подчиненный документ (например, «Передача заказа» или «Реализация товаров»), который списывает товар со склада или закрывает потребность заказа, остаток по данному измерению становится равным нулю. В этот момент запись полностью исчезает из виртуальной таблицы Остатки(). Поскольку к этой таблице далее применяется ЛЕВОЕ СОЕДИНЕНИЕ, итоговый результат запроса получается абсолютно пустым, несмотря на то, что сам документ-основание содержит список номенклатуры.

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

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

  1. Выбор исходных данных: В качестве первой таблицы выбираем табличную часть документа («Товары», «Материалы» или «Услуги»).
  2. Группировка и временная таблица: Данные табличной части документа группируем по номенклатуре (и при необходимости по характеристикам) и помещаем во временную таблицу (например, ВТ_Требования). Это необходимо для исключения дублей и корректного подсчета требуемого количества.
  3. Соединение с остатками: Из созданной временной таблицы выполняем ЛЕВОЕ СОЕДИНЕНИЕ с виртуальными таблицами остатков склада и резерва.
  4. Оптимизация передачи параметров: В параметры виртуальных таблиц остатков передаем отбор по списку номенклатуры из временной таблицы с помощью условия Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Требования). Это существенно ускоряет выполнение запроса.
  5. Расчет недостачи в запросе: Вычисляем нехватку материалов непосредственно в запросе с помощью конструкции ВЫБОР КОГДА, избегая лишних циклов обхода на клиенте.

Пример реализации пакетного запроса

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


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

Запрос.УстановитьПараметр("ДокументСсылка", ТекущийДокумент);
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
Запрос.УстановитьПараметр("Дата", Новый Граница(КонецДня(РабочаяДата), ВидГраницы.Включая));

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

Рекомендации по оптимизации работы с таблицей формы

Выясним дополнительные аспекты, влияющие на скорость и стабильность работы формы при переходе между строками:

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

2. Отказ от вызова метода СоздатьКолонки() в цикле: Метод СоздатьКолонки() пересоздает элементы формы с нуля, что вызывает визуальное «мигание» элементов и снижает производительность. Настройте состав колонок элемента формы заранее в дизайнере, а результат запроса загружайте напрямую через метод Загрузить() или связыванием реквизита формы.

3. Использование класса Граница: Чтобы учесть все движения регистра точно на конец дня включительно, передавайте в виртуальную таблицу параметр даты в виде Новый Граница(КонецДня(Дата), ВидГраницы.Включая).

← На главную