При автоматизации ежедневной работы пользователей в 1С часто возникает задача пакетной печати: бухгалтер или менеджер выделяет в журнале или форме списка несколько документов и отправляет их на принтер либо открывает для предварительного просмотра. Однако стандартный обход выделенных строк в цикле с вызовом типовых процедур формирования печатных форм приводит к тому, что система открывает отдельное окно предварительного просмотра для каждого документа. Разберем, почему возникает такое поведение и как правильно объединить печать в один общий табличный документ.
Проанализируем типовой код, который разработчики часто пытаются применить в форме списка документов (например, в конфигурации «Управление производственным предприятием»):
Процедура ДействияФормыДействиеПечатьВД(Кнопка)
Если ЭтаФорма.ЭлементыФормы.Список.ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого ДокументСсылка Из ЭтаФорма.ЭлементыФормы.Список.ВыделенныеСтроки Цикл
УниверсальныеМеханизмы.НапечататьДокументИзФормыСписка(ДокументСсылка.ПолучитьОбъект());
КонецЦикла;
КонецПроцедуры
Процедура УниверсальныеМеханизмы.НапечататьДокументИзФормыСписка внутри себя обращается к функции печати конкретного объекта, получает готовый макет и сразу же открывает общую форму предпросмотра ОбщиеФормы.ПечатьДокументов. При итерации по списку выделенных строк на каждом шаге цикла инициируется отдельный диалог показа. В результате рабочий стол пользователя заполняется десятками открытых окон.
Чтобы избежать открытия множества окон, необходимо придерживаться другого принципа: собрать все макеты в один результирующий ТабличныйДокумент, разделить их горизонтальными разделителями страниц и только затем передать сформированный результат в форму отображения.
Разберем по шагам правильный алгоритм групповой печати на форме списка документов в толстом клиенте:
ТабличныйДокумент.ВыделенныеСтроки табличного поля списка.Вывести().ВывестиГоризонтальныйРазделительСтраниц(). Важно не ставить разделитель после самого последнего документа, чтобы не печатать пустой лист.УниверсальныеМеханизмы.НапечататьДокумент() для итогового табличного документа.Посмотрим на пример программной реализации обработчика кнопки формы списка:
Процедура ДействияФормыПечатьПакета(Кнопка)
ВыделенныеСтроки = ЭтаФорма.ЭлементыФормы.Список.ВыделенныеСтроки;
КоличествоДокументов = ВыделенныеСтроки.Количество();
Если КоличествоДокументов = 0 Тогда
Возврат;
КонецЕсли;
ТабДокИтоговый = Новый ТабличныйДокумент;
Индекс = 0;
Для Каждого Ссылка Из ВыделенныеСтроки Цикл
Индекс = Индекс + 1;
ДокОбъект = Ссылка.ПолучитьОбъект();
// Вызываем функцию печати, формирующую печатную форму
ТабДокТекущий = ДокОбъект.Печать("СчетЗаказ");
Если ТабДокТекущий <> Неопределено Тогда
ТабДокИтоговый.Вывести(ТабДокТекущий);
// Добавляем разделитель страниц между документами
Если Индекс < КоличествоДокументов Тогда
ТабДокИтоговый.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ТабДокИтоговый.ВысотаТаблицы > 0 Тогда
// Открываем единую форму предварительного просмотра УПП
УниверсальныеМеханизмы.НапечататьДокумент(ТабДокИтоговый, 1, , "Групповая печать");
КонецЕсли;
КонецПроцедуры
Если конфигурация разработана с использованием Библиотеки стандартных подсистем (БСП) на управляемых формах, механизм пакетного вывода реализован разработчиками платформы штатно. Подсистема «Управление печатью» принимает в команду не одну ссылку, а целый массив объектов печати.
Рассмотрим, как выглядит вызов команды печати на клиенте:
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// ПараметрКоманды автоматически содержит массив ссылок на выделенные строки
УправлениеПечатьюКлиент.ВыполнитьКомандуПечати(
"Документ.ЗаказПокупателя",
"СчетЗаказ",
ПараметрКоманды,
ПараметрыВыполненияКоманды.Источник
);
КонецПроцедуры
В модуле менеджера объекта процедура печати принимает массив документов и формирует общий табличный документ для всей переданной коллекции:
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "СчетЗаказ") Тогда
ТабДок = СформироватьПечатнуюФорму(МассивОбъектов, ОбъектыПечати);
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"СчетЗаказ",
"Счет на оплату",
ТабДок
);
КонецЕсли;
КонецПроцедуры
Проанализируем технические детали, которые необходимо учитывать при объединении макетов:
ВывестиГоризонтальныйРазделительСтраниц() делит макет на страницы для печатающего устройства, однако свойства страницы (такие как ОриентацияСтраницы, АвтоМасштаб, поля документа) задаются для всего объекта ТабличныйДокумент в целом. Если объединяются документы с разной ориентацией (например, альбомная накладная и книжное приложение), итоговый документ примет единые параметры (как правило, первого выведенного макета).СсылкаНаОбъект строго одну ссылку. Пакетная печать из выделенных строк типовым механизмом ВПФ не предусмотрена — обработка будет вызываться поочередно для каждого объекта. Для массовой печати в таких системах решение оформляют либо в виде доработки формы журнала документов, либо в виде отдельной сервисной обработки с табличной частью для подбора документов.Ссылка.ПолучитьОбъект() считывает из базы данных всю структуру объекта со всеми табличными частями. Если планируется массовая печать сотен документов за один раз, вызовы ПолучитьОбъект() в цикле создадут повышенную нагрузку на сервер СУБД и память клиентского приложения. В высоконагруженных сценариях предпочтительно получать все данные для печати одним запросом по всему массиву ссылок.