Как получить список товаров без движения и с нулевыми остатками в 1С?

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

В практике программирования на платформе 1С часто возникает задача анализа складских запасов, а именно — поиск так называемых «неликвидов». Это товары, которые либо лежат на складе бездыханным грузом (нет продаж/списаний), либо вовсе отсутствуют, но числятся в справочнике и должны быть проанализированы. В этой статье мы разберем, как правильно составить запрос для получения таких данных, и почему стандартные подходы с виртуальными таблицами иногда могут выдавать неверный результат.

Проблема использования виртуальных таблиц при наличии возвратов

Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке получить товары без движений за период через виртуальную таблицу ОстаткиИОбороты, система может «схлопывать» данные. Например, если в течение периода был приход товара и его последующий полный возврат поставщику, то при отсутствии периодичности в параметрах виртуальной таблицы итоговые поля КоличествоПриход и КоличествоРасход могут выглядеть специфически, а конечный остаток будет равен нулю.

Если мы просто напишем условие ГДЕ КоличествоКонечныйОстаток = 0, мы рискуем получить в отчет товары, по которым на самом деле активность была (приход и возврат), но итоговый результат обнулился. Наша же задача — найти именно «мертвые» позиции, к которым никто не прикасался.

Решение 1: Метод левого соединения от справочника Номенклатура

Проанализируем наиболее надежный способ получения полной картины. Мы должны взять за основу справочник Номенклатура и «приклеить» к нему данные о движениях. Если данных о движениях в регистре нет, значит, товар не двигался.

Рассмотрим по шагам построение такого запроса:

  1. Выбираем все элементы справочника Номенклатура (исключая группы и помеченные на удаление).
  2. Левым соединением подключаем виртуальную таблицу ОстаткиИОбороты регистра накопления (например, ТоварыНаСкладах или ПартииТоваровНаСкладах).
  3. В параметрах виртуальной таблицы обязательно указываем границы периода.
  4. Накладываем условие, что данных в регистре либо вообще нет (ЕСТЬ NULL), либо обороты равны нулю.

Пример программного кода запроса:


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

В данном примере условие ТоварыОбороты.Номенклатура ЕСТЬ NULL найдет те товары, по которым вообще никогда не было записей в регистре или не было остатков и движений в выбранном периоде. Условие по оборотам отсечет товары, которые имеют остаток, но не двигались.

Решение 2: Использование временных таблиц и метода исключения

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

Разберем алгоритм:

  1. Создаем временную таблицу ВТ_ТоварыСДвижениями, куда выбираем всю номенклатуру, у которой КоличествоПриход > 0 или КоличествоРасход > 0 за период.
  2. Во втором запросе выбираем всю номенклатуру из справочника и проверяем, что ее нет во временной таблице.
  3. Дополнительно проверяем конечный остаток, если нам нужно разделить товары на «совсем пустые» и «залежавшиеся».

Пример реализации через временные таблицы:


// Шаг 1: Получаем те товары, по которым была хоть какая-то активность
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ТоварыНаСкладах.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_Движения
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
    ТоварыНаСкладах.Период МЕЖДУ &НачалоПериода И &КонецПериода;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Выбираем все остальное
ВЫБРАТЬ
    СпрНоменклатура.Ссылка КАК Товар
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
ГДЕ
    НЕ СпрНоменклатура.ЭтоГруппа
    И НЕ СпрНоменклатура.Ссылка В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Движения КАК ВТ)

Этот метод работает быстрее, так как платформа эффективнее обрабатывает оператор В (ВЫБРАТЬ...) или соединение по индексу временной таблицы, чем сложное условие ЕСТЬ NULL в большом левом соединении.

Важные нюансы при работе с остатками

Учет складов: Если в вашем отчете есть фильтр по конкретному складу, помните, что при левом соединении справочника Номенклатура со складом возникнет нюанс: справочник «не знает» о складах. Если вам нужно получить остатки по товарам в разрезе конкретного склада, которые не двигались именно там, условие по складу нужно ставить внутри параметров виртуальной таблицы, а не в предложении ГДЕ основного запроса. В противном случае левое соединение превратится во внутреннее, и вы потеряете товары с нулевыми остатками.

Тип номенклатуры: Выясним причину появления лишних данных в отчетах. Часто в справочнике Номенклатура содержатся услуги, работы или наборы. По ним складской учет не ведется. Чтобы отчет был чистым, всегда добавляйте фильтр по типу номенклатуры:

И СпрНоменклатура.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Товар)

Заключение

Подведем итог. Чтобы корректно решить проблему «товаров без движения», необходимо:

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

← На главную