Как правильно проверить остатки товара в документе реализации с помощью запроса в 1С

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

При изучении основ разработки на платформе «1С:Предприятие 8» одной из первых серьезных задач становится реализация механизма контроля остатков. Начинающие разработчики часто сталкиваются с ситуацией, когда запрос, написанный для проверки наличия товара на складе, работает некорректно или вовсе не возвращает данных. Давайте подробно разберем, почему это происходит, и как построить эффективный и правильный алгоритм проверки.

Анализ типичной ошибки: почему «простой» запрос не работает

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

Проанализируем ключевой момент: в базе данных табличная часть документа — это не отдельная табличка для каждого конкретного «Молотка» или «Расходной накладной №1». Это одна огромная таблица, в которой хранятся строки всех документов данного вида. Каждая строка содержит скрытое или явное поле Ссылка, указывающее на конкретный документ-владелец.

Если мы просто перечислим источники данных через запятую или попытаемся соединить их без жесткого фильтра по конкретной ссылке на документ, СУБД попытается сопоставить все строки всех накладных со всеми остатками. Это приводит к катастрофическому падению производительности и логическим ошибкам. Кроме того, обращение через точку вида РасходнаяНакладнаяСостав.Наименование.Ссылка является избыточным, если поле Наименование уже имеет ссылочный тип СправочникСсылка.Номенклатура.

Правильный подход: использование временных таблиц

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

Разберем по шагам создание запроса:

  1. Выгрузка состава документа во временную таблицу: Мы выбираем данные из табличной части только текущего документа, используя параметр &Ссылка. На этом же этапе крайне важно выполнить группировку по номенклатуре, так как пользователь может ввести одну и ту же позицию в разные строки документа.
  2. Получение остатков из регистра: Мы соединяем подготовленную временную таблицу с виртуальной таблицей остатков.
  3. Обработка NULL: Если товара на складе совсем нет, регистр не вернет строку, и в результате соединения мы получим значение NULL. Его обязательно нужно преобразовать в 0 с помощью функции ЕСТЬNULL.

Рассмотрим пример реализации такого запроса:


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

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

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

Важные нюансы и оптимизация

Проанализируем детали, которые делают этот код профессиональным:

1. Параметры виртуальной таблицы: Обратите внимание, что фильтр по номенклатуре мы передаем во второй параметр виртуальной таблицы Остатки(). Это критически важно. Если этого не сделать, система сначала получит остатки по всем товарам, которые есть в базе, и только потом отсечет лишние через ЛЕВОЕ СОЕДИНЕНИЕ. Передача фильтра заставляет СУБД работать только с нужными записями.

2. Момент времени: В качестве первого параметра виртуальной таблицы мы передаем &МоментВремени. Это объект, который включает в себя дату, время и ссылку на сам документ. В режиме проведения это позволяет системе получить актуальные остатки на точку входа документа в последовательность, исключая влияние его собственных движений (если они уже были записаны).

3. Использование ЛЕВОГО СОЕДИНЕНИЯ: Мы используем именно ЛЕВОЕ СОЕДИНЕНИЕ от таблицы документа к таблице остатков. Если использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ, то товары, которых вообще нет на складе (ноль остатка в регистре), просто не попадут в выборку, и проверка их «пропустит».

Методика проведения: старая vs новая

Выясним причину, почему место вызова запроса имеет значение. В 1С существует два основных подхода к контролю:

Старая методика: Сначала делаем запрос к остаткам, проверяем их, и если всё хорошо — записываем движения. Плюс: мы не делаем лишних записей в БД. Минус: в многопользовательской среде между проверкой и записью может пройти доля секунды, за которую другой пользователь успеет списать этот же товар.

Новая методика: Мы сначала записываем движения документа (даже если они уводят остаток в минус), а затем одним запросом проверяем, не появились ли после этого «отрицательные» остатки в регистре. Это более современный и отказоустойчивый метод для высоконагруженных систем.

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

Рекомендации по улучшению кода

Для того чтобы ваш код соответствовал стандартам разработки 1С, рассмотрим следующие советы:

Таким образом, правильная проверка остатков — это не просто сравнение двух цифр, а грамотное построение запроса с использованием временных таблиц, параметров виртуальных таблиц и обязательной обработкой пустых значений (NULL). Помните, что запрос должен всегда ограничиваться данными конкретного документа через параметр ссылки, иначе вы рискуете получить непредсказуемые результаты.

← На главную