Как объединить и просуммировать номенклатуру из табличных частей нескольких документов в 1С

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

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

Почему обращение через точку к табличной части не работает

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


ВЫБРАТЬ
    ЛистДоставкиРеализации.Реализации.Товары.(
        Номенклатура КАК РеализацииНоменклатура,
        Количество КАК РеализацииКоличество
    ) КАК Номенклатура
ИЗ
    Документ.ЛистДоставки.Реализации КАК ЛистДоставкиРеализации
ГДЕ
    ЛистДоставкиРеализации.Ссылка = &Документ

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

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

Способ 1. Использование внутреннего соединения табличных частей

Рассмотрим наиболее производительный и универсальный вариант запроса. Мы выбираем строки из табличной части листа доставки и соединяем их с табличной частью товаров накладных.


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

Разберем по шагам, как работает этот запрос:

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

Способ 2. Отбор через подзапрос с условием «В»

Если в документе-контейнере одна и та же накладная может быть случайно выбрана несколько раз, прямое соединение приведет к задвоению строк. Чтобы исключить эту проблему, сделаем выборку напрямую из товаров реализаций, а список документов ограничим подзапросом с ключевым словом РАЗЛИЧНЫЕ:


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

Способ 3. Передача массива ссылок через параметры запроса

Когда список накладных уже получен во встроенном языке (например, передан из формы или обработан в коде), можно передать готовый массив ссылок прямо в параметр запроса:


// Получаем массив ссылок из табличной части документа
МассивРеализаций = Объект.Реализации.ВыгрузитьКолонку("Реализация");

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

Запрос.УстановитьПараметр("МассивДокументов", МассивРеализаций);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

Способ 4. Программное объединение через ТаблицуЗначений

Если объединение необходимо выполнить без использования запроса, применим объект ТаблицаЗначений и встроенный метод Свернуть():


ТаблицаИтогов = Новый ТаблицаЗначений;
ТаблицаИтогов.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаИтогов.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
ТаблицаИтогов.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));

Для Каждого СтрокаДоставки Из Объект.Реализации Цикл
    Если ЗначениеЗаполнено(СтрокаДоставки.Реализация) Тогда
        ТаблицаТоваров = СтрокаДоставки.Реализация.Товары.Выгрузить();
        Для Каждого СтрТовар Из ТаблицаТоваров Цикл
            ЗаполнитьЗначенияСвойств(ТаблицаИтогов.Добавить(), СтрТовар);
        КонецЦикла;
    КонецЕсли;
КонецЦикла;

// Сворачиваем строки по номенклатуре с суммированием количества и суммы
ТаблицаИтогов.Свернуть("Номенклатура", "Количество, Сумма");

Важно: программный обход через точку в цикле порождает множество мелких обращений к базе данных (проблема N+1). Поэтому для оптимизации быстродействия всегда рекомендуется отдавать предпочтение языку запросов.

Важные нюансы и учетные разрезы

При объединении документов на практике обратим внимание на следующие особенности конфигураций 1С:

  1. Характеристики и серии: если на предприятии ведется учет по характеристикам или сериям, их обязательно нужно добавлять в список полей выборки и в секцию СГРУППИРОВАТЬ ПО, иначе товары с разными свойствами ошибочно схлопнутся в одну строку.
  2. Единицы измерения и упаковки: в современных конфигурациях количество может указываться в упаковках с различными коэффициентами. В таком случае необходимо суммировать не просто колонку Количество, а базовое количество (либо умножать количество на коэффициент упаковки).
  3. Услуги: если в документе реализации присутствуют услуги, они могут храниться в отдельной табличной части Услуги либо в табличной части Товары с признаком услуги. При необходимости их отсекают условием по типу номенклатуры.
← На главную