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