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

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

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

Анализ исходной проблемы

В типовом коде формирования печатной формы для каждого документа из переданного массива МассивОбъектов выполняется отдельный цикл. Внутри этого цикла последовательно выводятся:

  1. Область шапки с реквизитами текущего документа.
  2. Строки табличной части конкретного документа.
  3. Подвал с итоговыми суммами и подписями.
  4. Горизонтальный разделитель страниц с помощью метода ТабличныйДокумент.ВывестиГоризонтальныйРазделительСтраниц().

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

Пошаговый алгоритм переработки процедуры печати

Разберем подробно изменения, которые необходимо внести в алгоритм формирования печатной формы:

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

Пример реализации функции формирования сводной печатной формы

Посмотрим на практическую реализацию функции, формирующей единый табличный документ:


Функция СформироватьПечатнуюФорму(МассивОбъектов, ОбъектыПечати) Экспорт

    ТабличныйДокумент = Новый ТабличныйДокумент;
    ТабличныйДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_РеализацияТоваров_СводнаяСпецификация";
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |   Документ.Ссылка КАК Ссылка,
        |   Документ.Дата КАК Дата,
        |   Документ.Организация КАК Поставщик,
        |   Документ.Контрагент КАК Получатель,
        |   Документ.УчитыватьНДС КАК УчитыватьНДС,
        |   Документ.ЦенаВключаетНДС КАК ЦенаВключаетНДС,
        |   Документ.Номер КАК Номер
        |ИЗ
        |   Документ.РеализацияТоваров КАК Документ
        |ГДЕ
        |   Документ.Ссылка В(&МассивОбъектов)
        |   И Документ.Проведен
        |
        |УПОРЯДОЧИТЬ ПО
        |   Ссылка,
        |   Дата
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |   ТаблицаТовары.Номенклатура КАК Номенклатура,
        |   ТаблицаТовары.Номенклатура.Представление КАК Товар,
        |   ВЫРАЗИТЬ(ТаблицаТовары.Номенклатура.НаименованиеПолное КАК СТРОКА(200)) КАК НоменклатураПредставление,
        |   ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Характеристика) КАК ХарактеристикаПредставление,
        |   ВЫБОР
        |       КОГДА ТаблицаТовары.Упаковка <> ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
        |           ТОГДА ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Упаковка.ЕдиницаИзмерения)
        |       ИНАЧЕ ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Номенклатура.ЕдиницаИзмерения)
        |   КОНЕЦ КАК ЕдиницаИзмерения,
        |   СУММА(ТаблицаТовары.Количество) КАК Количество,
        |   СУММА(ТаблицаТовары.КоличествоУпаковок) КАК КоличествоУпаковок,
        |   МАКСИМУМ(ВЫБОР
        |           КОГДА ТаблицаТовары.Количество = 0
        |               ТОГДА ТаблицаТовары.Количество
        |           ИНАЧЕ ТаблицаТовары.Сумма / ТаблицаТовары.Количество
        |       КОНЕЦ) КАК Цена,
        |   СУММА(ТаблицаТовары.Сумма) КАК Сумма,
        |   СУММА(ТаблицаТовары.СуммаНДС) КАК СуммаНДС,
        |   ТаблицаТовары.СтавкаНДС КАК СтавкаНДС
        |ИЗ
        |   Документ.РеализацияТоваров.Товары КАК ТаблицаТовары
        |ГДЕ
        |   ТаблицаТовары.Ссылка В(&МассивОбъектов)
        |   И ТаблицаТовары.Ссылка.Проведен
        |
        |СГРУППИРОВАТЬ ПО
        |   ТаблицаТовары.Номенклатура,
        |   ТаблицаТовары.Номенклатура.Представление,
        |   ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Характеристика),
        |   ВЫБОР
        |       КОГДА ТаблицаТовары.Упаковка <> ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
        |           ТОГДА ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Упаковка.ЕдиницаИзмерения)
        |       ИНАЧЕ ПРЕДСТАВЛЕНИЕ(ТаблицаТовары.Номенклатура.ЕдиницаИзмерения)
        |   КОНЕЦ,
        |   ВЫРАЗИТЬ(ТаблицаТовары.Номенклатура.НаименованиеПолное КАК СТРОКА(200)),
        |   ТаблицаТовары.СтавкаНДС
        |
        |УПОРЯДОЧИТЬ ПО
        |   Номенклатура
        |АВТОУПОРЯДОЧИВАНИЕ";

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

    Макет = ПолучитьМакет("Макет");
    ОбластьШапка  = Макет.ПолучитьОбласть("Шапка");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");

    ВыборкаПоДокументам     = Результаты[0].Выбрать();
    ВыборкаПоТабличнымЧастям = Результаты[1].Выбрать();

    // Заполняем реквизиты шапки из первого документа массива
    Если ВыборкаПоДокументам.Следующий() Тогда
        ОбластьШапка.Параметры.Номер = ВыборкаПоДокументам.Номер;
        ОбластьШапка.Параметры.Дата  = Формат(ВыборкаПоДокументам.Дата, "ДЛФ=DD");
        ТабличныйДокумент.Вывести(ОбластьШапка);
    КонецЕсли;

    ИтогоСуммаБезНДС = 0;
    ИтогоСуммаСНДС   = 0;
    ИтогоНДС         = 0;

    // Выводим сгруппированные строки всех документов
    Пока ВыборкаПоТабличнымЧастям.Следующий() Цикл
        
        ОбластьСтрока.Параметры.Заполнить(ВыборкаПоТабличнымЧастям);
        ОбластьСтрока.Параметры.Товар = ФормированиеПечатныхФормСервер.ПолучитьПредставлениеНоменклатурыДляПечати(
            ВыборкаПоТабличнымЧастям.НоменклатураПредставление,
            ВыборкаПоТабличнымЧастям.ХарактеристикаПредставление
        );

        СтавкаНДСЧисло = ОбработкаТабличнойЧастиТоварыКлиентСерверПовтИсп.ПолучитьСтавкуНДСЧислом(ВыборкаПоТабличнымЧастям.СтавкаНДС) * 100;

        Если ВыборкаПоДокументам.ЦенаВключаетНДС Тогда
            ЦенаБезНдс  = Окр(ВыборкаПоТабличнымЧастям.Цена * 100 / (100 + СтавкаНДСЧисло), 2);
            СуммаБезНдс = ВыборкаПоТабличнымЧастям.Сумма - ВыборкаПоТабличнымЧастям.СуммаНДС;
            СуммаСНдс   = ВыборкаПоТабличнымЧастям.Сумма;
        Иначе
            ЦенаБезНдс  = ВыборкаПоТабличнымЧастям.Цена;
            СуммаБезНдс = ВыборкаПоТабличнымЧастям.Сумма;
            СуммаСНдс   = ВыборкаПоТабличнымЧастям.Сумма + ВыборкаПоТабличнымЧастям.СуммаНДС;
        КонецЕсли;

        ИтогоСуммаБезНДС = ИтогоСуммаБезНДС + СуммаБезНдс;
        ИтогоСуммаСНДС   = ИтогоСуммаСНДС + СуммаСНдс;
        ИтогоНДС         = ИтогоНДС + ВыборкаПоТабличнымЧастям.СуммаНДС;

        ОбластьСтрока.Параметры.ЦенаБезНдс  = ЦенаБезНдс;
        ОбластьСтрока.Параметры.СуммаБезНдс = СуммаБезНдс;
        ОбластьСтрока.Параметры.СуммаСНдс   = СуммаСНдс;

        ТабличныйДокумент.Вывести(ОбластьСтрока);
        
    КонецЦикла;

    // Заполнение и вывод подвала
    ОбластьПодвал.Параметры.ИтогоСуммаБезНДС = ИтогоСуммаБезНДС;
    ОбластьПодвал.Параметры.ИтогоСуммаСНДС   = ИтогоСуммаСНДС;
    ОбластьПодвал.Параметры.ИтогоСуммаБезНДСПрописью = ФормированиеПечатныхФормСервер.СформироватьСуммуПрописью(ИтогоСуммаСНДС);
    ОбластьПодвал.Параметры.ИтогоСуммаСНДС           = ИтогоСуммаСНДС;

    Руководители = ФормированиеПечатныхФормСервер.ОтветственныеЛицаОрганизаций(ВыборкаПоДокументам.Поставщик, ВыборкаПоДокументам.Дата);
    ОбластьПодвал.Параметры.ПостДиректор = ФормированиеПечатныхФормСервер.ФамилияИнициалыФизЛица(Руководители.Руководитель);

    ПредставлениеПоставщика = ФормированиеПечатныхФормСервер.ОписаниеОрганизации(
        ФормированиеПечатныхФормСервер.СведенияОЮрФизЛице(ВыборкаПоДокументам.Поставщик, ВыборкаПоДокументам.Дата), "ПолноеНаименование,");
    ОбластьПодвал.Параметры.Поставщик = ПредставлениеПоставщика;

    ПредставлениеПолучателя = ФормированиеПечатныхФормСервер.ОписаниеОрганизации(
        ФормированиеПечатныхФормСервер.СведенияОЮрФизЛице(ВыборкаПоДокументам.Получатель, ВыборкаПоДокументам.Дата), "ПолноеНаименование,");
    ОбластьПодвал.Параметры.Покупатель = ПредставлениеПолучателя;

    ТабличныйДокумент.Вывести(ОбластьПодвал);

    // Регистрация области печати в БСП для каждого объекта
    Для Каждого ДокументСсылка Из МассивОбъектов Цикл
        УправлениеПечатью.ЗадатьОбластьПечатиДокумента(ТабличныйДокумент, 1, ОбъектыПечати, ДокументСсылка);
    КонецЦикла;

    ТабличныйДокумент.АвтоМасштаб = Истина;
    Возврат ТабличныйДокумент;

КонецФункции

Важные нюансы и рекомендации

При объединении строк нескольких документов следует учитывать следующие особенности:

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