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

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

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

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

Почему стандартный запрос к таблице ОстаткиИОбороты может ошибаться?

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

Проанализируем причину: виртуальная таблица без периодичности агрегирует данные. Если КоличествоПриход составило 10 единиц, а затем КоличествоРасход (или возврат) составило те же 10 единиц, то поле КоличествоОборот покажет 0. Для системы это выглядит так, будто ничего не происходило. Именно поэтому добавление периодичности ДЕНЬ или АВТО внезапно «оживляет» отчет — записи перестают схлопываться в одну строку.

Решение 1. Классическое объединение через левое соединение

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

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


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

СГРУППИРОВАТЬ ПО
    СпрНоменклатура.Ссылка,
    СпрНоменклатура.Артикул,
    ТоварыНаСкладах.Склад

Важный нюанс: Чтобы исключить ситуацию с возвратами, проанализируем условие в блоке ГДЕ. Мы проверяем отдельно КоличествоПриход = 0 и КоличествоРасход = 0, а не просто суммарный Оборот. Это гарантирует, что товар действительно не «шевелился».

Решение 2. Использование временных таблиц для ускорения (рекомендуется)

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

Разберем этот метод по шагам:

  1. Создаем временную таблицу ВТ_Движения, куда помещаем только те товары, у которых обороты не равны нулю.
  2. Выбираем все товары из справочника Номенклатура.
  3. Используем условие ГДЕ НЕ Ссылка В (ВЫБРАТЬ Номенклатура ИЗ ВТ_Движения).

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

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

Этот способ работает быстрее, так как поиск по индексированной временной таблице или через оператор В эффективнее для СУБД, чем выполнение сложного соединения с NULL-проверками по всей базе номенклатуры.

Решение 3. Поиск даты последнего движения (Анализ «глубины» неликвида)

Для бизнеса часто недостаточно знать, что движений не было в текущем месяце. Нужно понимать, когда товар продавался в последний раз. Если последнее движение было год назад — это критический неликвид. Выясним, как получить дату последней активности.

Для этого нам придется обратиться к физической таблице регистра накопления. Посмотрим на пример кода:


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

Соединив этот результат с таблицей текущих остатков, мы получим мощный отчет: Товар | Остаток | Дата последней продажи | Кол-во дней без движения. Именно такие отчеты ценятся отделом закупок и руководством.

Практические советы и особенности реализации

При разработке отчета «Товары без движения» обратим внимание на следующие технические моменты:

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

← На главную