Как определить и зафиксировать основного поставщика номенклатуры на основе истории закупок

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

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

Анализ исходных данных и постановка задачи

Представим ситуацию: в системе накоплено большое количество документов ПриходМатериаловНаСклад. Нам необходимо проанализировать эти данные и для каждой номенклатуры выявить поставщика, который фигурирует чаще других или поставляет наибольший объем товара. Результаты анализа нужно распределить по регистрам сведений: основного поставщика записать в один регистр, а всех остальных — в другой (вспомогательный).

Разберем основные критерии, по которым можно определять «основного» поставщика:

  1. Количество документов поступления: поставщик, с которым мы чаще всего заключаем сделки.
  2. Общее количество товара: поставщик, который обеспечивает наибольший физический объем поставок.
  3. Сумма закупок: поставщик, которому мы платим больше всего денег (финансовый приоритет).

Шаг 1. Формирование запроса для сбора статистики

Проанализируем структуру запроса, который позволит нам собрать первичные данные. Нам необходимо сгруппировать данные по номенклатуре и контрагенту, вычислив агрегатные функции (количество ссылок на документы, сумму и общее количество единиц).


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

Обратим внимание на важный аспект: в блоке УПОРЯДОЧИТЬ ПО мы сначала сортируем результат по Номенклатура, а затем по выбранному критерию (например, количеству документов) в порядке убывания. Это позволит нам при обходе выборки понимать, что первая строка для каждой новой номенклатуры — это и есть наш «основной» поставщик.

Шаг 2. Программная обработка результатов и запись в регистры

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


Выборка = Запрос.Выполнить().Выбрать();

ТекущаяНоменклатура = Справочники.Номенклатура.ПустаяСсылка();

Пока Выборка.Следующий() Цикл
    
    Если Выборка.Номенклатура <> ТекущаяНоменклатура Тогда
        // Это первая строка для данной номенклатуры. 
        // Благодаря сортировке УБЫВ в запросе, этот поставщик - основной.
        ЗаписатьОсновногоПоставщика(Выборка.Номенклатура, Выборка.Контрагент);
        ТекущаяНоменклатура = Выборка.Номенклатура;
    Иначе
        // Все последующие строки для этой же номенклатуры - дополнительные поставщики.
        ЗаписатьВспомогательногоПоставщика(Выборка.Номенклатура, Выборка.Контрагент);
    КонецЕсли;
    
КонецЦикла;

Для записи данных в регистры сведений крайне рекомендуется использовать РегистрСведенийНаборЗаписей. Рассмотрим пример функции записи для основного поставщика:


Процедура ЗаписатьОсновногоПоставщика(Товар, Поставщик)
    Набор = РегистрыСведений.ОсновнойПоставщик.СоздатьНаборЗаписей();
    Набор.Отбор.Номенклатура.Установить(Товар);
    
    НоваяЗапись = Набор.Добавить();
    НоваяЗапись.Номенклатура = Товар;
    НоваяЗапись.Контрагент = Поставщик;
    
    Набор.Записать(ИСТИНА); // ИСТИНА означает замещение существующих записей по этому фильтру
КонецПроцедуры

Шаг 3. Продвинутая логика и оптимизация запроса

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

1. Ограничение периода анализа. Проанализируем только последние данные (например, за последний год). Добавим условие в ГДЕ:

ПриходМатериалов.Ссылка.Дата >= &ДатаНачала

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


ВЫБРАТЬ
    ...,
    (КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ПриходМатериалов.Ссылка) * 0.4 + СУММА(ПриходМатериалов.Количество) * 0.6) КАК Рейтинг
...
УПОРЯДОЧИТЬ ПО
    Номенклатура,
    Рейтинг УБЫВ

3. Использование временных таблиц для исключения цикла. Если номенклатуры очень много, программный перебор может быть медленным. Мы можем найти максимумы прямо в запросе, используя временные таблицы. Сначала выгружаем статистику во временную таблицу ВТ_Статистика, а затем соединяем её с самой собой по условию ВТ_Статистика.Количество = ВТ_Максимумы.МаксКоличество.

Архитектурные рекомендации

Для повышения надежности системы придерживайтесь следующих правил:

Таким образом, мы разобрали комплексный подход к определению основного контрагента: от построения эффективного запроса с группировкой и сортировкой до архитектурно правильной записи результатов в базу данных 1С.

← На главную