Как программно сформировать заказы поставщикам, сгруппировав товары по контрагентам из табличной части?

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

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

Подготовка данных: использование таблицы значений

Для того чтобы сгруппировать товары по поставщику, нам необходимо выгрузить данные из табличной части в объект ТаблицаЗначений. В исходной таблице может не быть колонки «Поставщик» отдельно, поэтому сначала нужно ее добавить и заполнить данными из справочника Номенклатура.

Рассмотрим пошагово процесс подготовки данных:

  1. Выгружаем данные из табличной части формы в ТаблицаЗначений.
  2. Добавляем новую колонку Поставщик.
  3. Заполняем эту колонку, обращаясь к реквизиту Поставщик элемента номенклатуры.
  4. Сворачиваем таблицу методом Свернуть, чтобы суммировать количество и цену для одинаковых товаров одного поставщика.

Посмотрим, как это выглядит в коде:


ТаблЗнач = ЭтотОбъект.ТЧ.Выгрузить();
ТаблЗнач.Колонки.Добавить("Поставщик");
Для Каждого СтрТаб Из ТаблЗнач Цикл
    СтрТаб.Поставщик = СтрТаб.Номенклатура.Поставщик;
КонецЦикла;
// Сворачиваем, чтобы объединить одинаковые позиции и подготовить список поставщиков
ТаблЗнач.Свернуть("Поставщик, Номенклатура", "Количество, Сумма");

Алгоритм формирования документов с группировкой

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

Разберем логику обхода данных:


// Создаем копию для получения уникального списка поставщиков
ТаблЗначСв = ТаблЗнач.Скопировать();
ТаблЗначСв.Свернуть("Поставщик", "");

// Перебираем уникальных поставщиков
Для Каждого СтрСв Из ТаблЗначСв Цикл
    СтруктураПоиска = Новый Структура("Поставщик", СтрСв.Поставщик);
    НайденныеСтроки = ТаблЗнач.НайтиСтроки(СтруктураПоиска);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Создаем новый документ для текущего поставщика
        ДокументЗаказПоставщику = Документы.ЗаказПоставщику.СоздатьДокумент();
        ДокументЗаказПоставщику.Дата = ТекущаяДата();
        ДокументЗаказПоставщику.Контрагент = СтрСв.Поставщик;
        ДокументЗаказПоставщику.Склад = Склад;
        
        // Добавляем все найденные строки в один документ
        Для Каждого СтрНайденыш Из НайденныеСтроки Цикл
            НоваяСтрока = ДокументЗаказПоставщику.Товары.Добавить();
            НоваяСтрока.Номенклатура = СтрНайденыш.Номенклатура;
            НоваяСтрока.Количество = СтрНайденыш.Количество;
            НоваяСтрока.Сумма = СтрНайденыш.Сумма;
        КонецЦикла;
        
        // Записываем документ один раз после заполнения всех строк
        ДокументЗаказПоставщику.Записать();
    КонецЕсли;
КонецЦикла;

Почему важно правильно записывать документы

Важное примечание: Обратите внимание на то, где именно в коде вызывается метод Записать(). В первом варианте кода, с которым столкнулся автор, запись документа происходила внутри цикла по строкам товара. Это приводит к лишним обращениям к базе данных и может вызвать блокировки таблиц.

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

Рекомендации по дальнейшей оптимизации

Хотя предложенный метод с ТаблицаЗначений отлично работает для небольших объемов данных, для сложных конфигураций и больших массивов номенклатуры рекомендуется использовать запросы. Запрос позволяет:

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

← На главную