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