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