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