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

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

В практике автоматизации складского учета часто возникает задача: при расчете необходимости заказа товара нужно учитывать не только остатки конкретной позиции, но и остатки всех её аналогов (взаимозаменяемых товаров). Если на складе нет «Товара 1», но есть избыток «Товара 2», который является полным аналогом, система не должна предлагать закупку. Рассмотрим, как реализовать этот алгоритм с помощью механизма временных таблиц в языке запросов 1С.

Анализ исходной ситуации

Представим ситуацию: у нас есть нетиповая конфигурация, где лимиты хранения задаются в регистре сведений ЛимитыНоменклатуры, а фактические остатки хранятся в регистре накопления МатериалыНаСкладах. Связь аналогов реализована через реквизит Аналог в справочнике Номенклатура.

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

Шаг 1: Формирование списка целевой номенклатуры и её аналогов

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


ВЫБРАТЬ
    СпрНом.Ссылка КАК Номенклатура
ПОМЕСТИТЬ ВТ_СписокНоменклатуры
ИЗ
    Справочник.Номенклатура КАК СпрНом
ГДЕ
    СпрНом.Ссылка В (&Номенклатура)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Таб.Ссылка
ИЗ
    Справочник.Номенклатура КАК Таб
ГДЕ
    Таб.Аналог В (&Номенклатура)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Влож.Номенклатура
ПОМЕСТИТЬ ВТ_ИтоговаяНоменклатура
ИЗ
    ВТ_СписокНоменклатуры КАК Влож
СГРУППИРОВАТЬ ПО
    Влож.Номенклатура
ИНДЕКСИРОВАТЬ ПО
    Номенклатура

Важный момент: Мы используем ИНДЕКСИРОВАТЬ ПО, чтобы последующие соединения с виртуальными таблицами остатков работали максимально быстро. Группировка позволяет избавиться от дублей, если одна и та же позиция попала в список дважды.

Шаг 2: Получение лимитов и рекомендованных партий

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


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

Шаг 3: Агрегация остатков основной номенклатуры и аналогов

Самая ответственная часть — суммирование остатков. Выясним причину, почему обычное соединение может не подойти: если мы просто соединим таблицы, мы получим разрозненные строки. Нам же нужно «схлопнуть» данные аналога в строку основной номенклатуры. Рассмотрим способ с использованием ОБЪЕДИНИТЬ ВСЕ внутри подзапроса:


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

Шаг 4: Учет резервов и финальный расчет

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

В итоговом запросе мы соединяем таблицу лимитов с нашими агрегированными остатками и резервами. Основное условие заказа: если СуммарныйОстаток - Резерв < Лимит, то позиция должна попасть в отчет.


ВЫБРАТЬ
    ЛИМИТЫ.Номенклатура КАК Номенклатура,
    ВЫБОР 
        КОГДА ЕСТЬNULL(ОСТАТКИ.ОбщийОстаток, 0) = 0 ТОГДА 0 
        ИНАЧЕ ЕСТЬNULL(ОСТАТКИ.ОбщаяСтоимость, 0) / ЕСТЬNULL(ОСТАТКИ.ОбщийОстаток, 0) 
    КОНЕЦ КАК СредняяЦена,
    ЛИМИТЫ.РекомендованныйЗаказ КАК ТребуетсяЗаказать
ИЗ
    ЛИМИТЫ КАК ЛИМИТЫ
ЛЕВОЕ СОЕДИНЕНИЕ ОСТАТКИ КАК ОСТАТКИ 
    ПО ЛИМИТЫ.Номенклатура = ОСТАТКИ.Номенклатура
ГДЕ
    ЕСТЬNULL(ОСТАТКИ.ОбщийОстаток, 0) < ЛИМИТЫ.Лимит

Тонкости и нюансы реализации

Разберем несколько важных моментов, которые помогут сделать решение более надежным:

  1. Транзитивность аналогов: В нашем примере рассматривается связь первого уровня (А -> Б). Если в системе существуют цепочки (А -> Б -> В), стандартный запрос их не увидит. В таких случаях рекомендуется формировать полный список аналогов программно в коде на языке 1С и передавать его в запрос как массив.
  2. Коэффициенты пересчета: Если аналоги не равноценны (например, один товар в литрах, другой в килограммах), при суммировании остатков необходимо умножать КоличествоОстаток на соответствующий коэффициент из регистра сведений или реквизита номенклатуры.
  3. Свободный остаток: Помните, что для закупки важен именно свободный остаток. Формула должна выглядеть так: ОстатокНаСкладах - РезервыПоЗаказам + ОжидаемыеПоступления. Только такая детализация даст отделу снабжения корректную картину.
  4. Работа с иерархией: Если в параметрах передается группа номенклатуры, используйте оператор В ИЕРАРХИИ. Однако будьте осторожны: на больших объемах данных поиск по иерархии внутри виртуальных таблиц может замедлять выполнение. В таких случаях лучше сначала выгрузить все элементы группы в плоскую временную таблицу.

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

← На главную