Как сформировать единую печатную форму из нескольких документов в 1С?

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

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

Основная проблема заключается в том, что типовые механизмы печати обычно ориентированы на один документ. Если мы хотим получить единую сводную форму, нам потребуется вмешаться в стандартную логику и создать собственное решение. Наиболее эффективным и правильным подходом для таких задач является разработка внешней печатной формы (ВПФ) — для этого подойдёт редактор печатных форм 1С без программирования. Это позволяет добавить новую функциональность без изменения типовой конфигурации, что значительно упрощает дальнейшие обновления системы.

Ключевой подход: Внешняя Печатная Форма (ВПФ)

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

  1. Безопасно: не требует изменения типовой конфигурации, что исключает проблемы при обновлении.
  2. Гибко: позволяет реализовать любую логику формирования печатной формы.
  3. Переносимо: легко подключается к другим базам данных с аналогичной конфигурацией.

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

Шаг 1: Подключение к механизму печати и получение массива документов

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


Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт

Давайте разберем параметры этой процедуры:

Наша ВПФ должна иметь схожую экспортируемую процедуру, чтобы система могла ее вызвать и передать ей массив документов. Внутри этой процедуры мы и будем реализовывать всю логику.

Шаг 2: Сбор данных из нескольких документов с помощью запроса

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

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

Использование цикла для формирования запроса

Мы будем перебирать МассивОбъектов, чтобы сформировать список ссылок, который затем будет использоваться в условии ГДЕ нашего запроса. Давайте посмотрим на пример запроса:


// В процедуре вашей внешней печатной формы

// ... получение МассивОбъектов ...

Если МассивОбъектов.Количество() = 0 Тогда
    Возврат;
КонецЕсли;

// Создаем временную таблицу для ссылок на документы
// Это более эффективный способ передачи массива ссылок в запрос,
// чем длинное условие "В ()" при большом количестве документов.
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ДокСсылки.Ссылка
    |ПОМЕСТИТЬ ВТ_Документы
    |ИЗ
    |    &МассивОбъектов КАК ДокСсылки;
    |
    |ВЫБРАТЬ
    |    ПередачаТоваровМеждуОрганизациямиТовары.Ссылка,
    |    ПередачаТоваровМеждуОрганизациямиТовары.Номенклатура,
    |    ПередачаТоваровМеждуОрганизациямиТовары.Номенклатура.НаименованиеПолное КАК НоменклатураНаименование,
    |    ПередачаТоваровМеждуОрганизациямиТовары.Количество,
    |    ПередачаТоваровМеждуОрганизациямиТовары.ЕдиницаИзмерения,
    |    ПередачаТоваровМеждуОрганизациямиТовары.Цена,
    |    ПередачаТоваровМеждуОрганизациямиТовары.Сумма
    |ИЗ
    |    Документ.ПередачаТоваровМеждуОрганизациями.Товары КАК ПередачаТоваровМеждуОрганизациямиТовары
    |ГДЕ
    |    ПередачаТоваровМеждуОрганизациямиТовары.Ссылка В (ВЫБРАТЬ Ссылка ИЗ ВТ_Документы)";

Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);

РезультатЗапроса = Запрос.Выполнить();
ТаблицаТоваров = РезультатЗапроса.Выгрузить();

В этом примере мы сначала помещаем массив ссылок на документы во временную таблицу ВТ_Документы. Затем мы выбираем все строки табличной части "Товары" из документов "Передача товаров между организациями", используя условие ГДЕ, которое ссылается на нашу временную таблицу. Это позволяет получить данные из всех выбранных документов одним запросом.

После выполнения запроса мы получим ТаблицаТоваров, которая будет содержать все позиции номенклатуры из всех выбранных документов. Если необходимо, мы можем дополнительно обработать эту таблицу, например, сгруппировать строки по номенклатуре и суммировать количества и суммы, если одна и та же номенклатура встречается в разных документах или даже в одном, но в разных строках, и нам нужна сводная строка.


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

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

Шаг 3: Разработка макета печатной формы

Для визуализации данных нам потребуется макет печатной формы. Макет создается в конфигураторе 1С непосредственно в вашей внешней печатной форме. Он представляет собой табличный документ, похожий на лист Excel, который разделен на области. Обычно выделяют следующие области:

  1. Заголовок: Содержит название печатной формы (например, "Сводный Отчет по Передаче Товаров").
  2. Шапка: Включает общую информацию по документам, например, названия организаций (отправитель и получатель), если они одинаковы для всех выбранных документов, как в нашем случае.
  3. ШапкаТаблицы: Заголовки колонок табличной части (Номенклатура, Количество, Цена, Сумма).
  4. Строка: Область для вывода одной строки товаров из нашей агрегированной таблицы.
  5. Итого: Область для вывода общих сумм или количества товаров.
  6. Подвал: Дополнительная информация, подписи и т.д.

В каждой области мы размещаем параметры (имена, заключенные в квадратные скобки, например, [ОрганизацияОтправитель], [НоменклатураНаименование]), куда будут подставляться данные из нашей программы.

Шаг 4: Вывод данных на макет

После того как мы собрали все данные в ТаблицаТоваров и подготовили макет, мы приступаем к формированию итогового табличного документа. Это делается с использованием объекта ТабличныйДокумент.


// В процедуре вашей внешней печатной формы, после получения ТаблицаТоваров

// Получаем макет
Макет = ПолучитьМакет("ВашМакетПечатнойФормы"); // Имя макета, которое вы дали в конфигураторе

// Создаем новый табличный документ
ТабДокумент = Новый ТабличныйДокумент;
ТабДокумент.ИмяПараметровПечати = "ПараметрыПечати_СводнаяПередача"; // Имя для сохранения настроек печати

// Получаем данные для шапки из первого документа в массиве
// Это допустимо, поскольку автор уточнил, что организации везде одинаковые.
Если МассивОбъектов.Количество() > 0 Тогда
    ПервыйДокументСсылка = МассивОбъектов[0];
    ПервыйДокументОбъект = ПервыйДокументСсылка.ПолучитьОбъект();

    // Выводим заголовок
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.ТекстЗаголовка = "Сводная передача товаров между организациями";
    ТабДокумент.Вывести(ОбластьЗаголовок);

    // Выводим шапку
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьШапка.Параметры.ОрганизацияОтправитель = ПервыйДокументОбъект.Организация;
    ОбластьШапка.Параметры.ОрганизацияПолучатель = ПервыйДокументОбъект.ОрганизацияПолучатель;
    // Можно добавить другие параметры шапки из первого документа, если они актуальны
    ТабДокумент.Вывести(ОбластьШапка);

    ПервыйДокументОбъект = Неопределено; // Освобождаем объект
КонецЕсли;

// Выводим шапку табличной части
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ТабДокумент.Вывести(ОбластьШапкаТаблицы);

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

// Выводим итоговую область (если есть)
ОбластьИтого = Макет.ПолучитьОбласть("Итого");
ОбластьИтого.Параметры.ИтоговаяСумма = ТаблицаТоваров.Итог("Сумма"); // Если суммы были сгруппированы
ТабДокумент.Вывести(ОбластьИтого);

// Добавляем табличный документ в коллекцию печатных форм
КоллекцияПечатныхФорм.Добавить(ТабДокумент, "СводнаяПередачаТоваров", "Сводная передача товаров");

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

Важные аспекты вывода шапки:

В нашем случае, как было уточнено в исходном сообщении, организации-отправители и получатели для всех выбранных документов одинаковы. Это значительно упрощает формирование шапки: мы можем взять данные для шапки из первого документа в массиве МассивОбъектов. Если бы организации были разными, нам пришлось бы либо формировать сводную шапку с указанием "Различные организации", либо выводить шапку для каждого документа отдельно, что не соответствовало бы задаче "одна печатная форма".

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

Дополнительные нюансы и расширения

Использование Системы Компоновки Данных (СКД)

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

Если мы решили использовать СКД, логика будет следующей:

  1. Создаем схему компоновки данных в макете ВПФ.
  2. В схеме описываем набор данных (ваш запрос к табличным частям документов).
  3. Программно формируем КомпоновщикМакета и ПроцессорКомпоновки, передавая ему ссылки на документы как параметр.
  4. Получаем результат в виде ТабличныйДокумент.

Обработка различий в шапке

Если бы организации или другие ключевые реквизиты шапки документов отличались, то вариантов могло быть несколько:

В нашем случае, поскольку организации одинаковые, мы упростили задачу и взяли данные из первого документа.

Оптимизация производительности

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


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

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

Заключение

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

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

← На главную