При разработке внешних печатных форм (ВПФ) или модификации типовых механизмов вывода документов в 1С:Предприятие разработчики часто сталкиваются с коварной проблемой. Печатная форма отлично формируется, без ошибок выводится на экран в стандартную форму предварительного просмотра и успешно отправляется на физический принтер. Однако при попытке сохранить документ в файл (PDF, Excel и др.) или отправить его по электронной почте с помощью стандартных кнопок БСП (Библиотеки Стандартных Подсистем) ничего не происходит — программа просто игнорирует нажатие клавиш без вывода каких-либо предупреждений.
В этой статье мы подробно разберем, почему возникает это поведение, заглянем во внутренние механизмы работы подсистемы печати БСП и рассмотрим два надежных способа решения этой технической проблемы с примерами готового кода.
Для того чтобы понять суть проблемы, нам необходимо проанализировать, как Библиотека Стандартных Подсистем обрабатывает табличные документы при их выводе на экран и последующем сохранении. Для простого вывода на печать платформе 1С достаточно передать заполненный объект типа ТабличныйДокумент. Но когда пользователь нажимает кнопку «Сохранить» или «Отправить по почте», БСП запускает более сложные алгоритмы анализа.
Выделим две основные причины сбоя:
ДокументСсылка.РеализацияТоваровУслуг). Эта разметка выполняется с помощью вызова процедуры УправлениеПечатью.ЗадатьОбластьПечатиДокумента(). Метод создает в табличном документе скрытые служебные именованные области вида Печать_Документ_1, Печать_Документ_2 и т. д.
Когда мы пишем код вида рез = Новый ТабличныйДокумент; и копируем туда области из исходного документа, все скрытые системные области и метаданные полностью уничтожаются. БСП пытается прочитать структуру документа рез для разделения его на файлы по документам-источникам, не находит нужных служебных областей и молча прерывает выполнение операции.ЗаполнитьЗначенияСвойств(рез, стр.ТабличныйДокумент) не решает проблему. Этот метод копирует только простые свойства первого уровня. Сложные составные объекты, такие как поля страницы (Поля.Лево, Поля.Право и т.д.), являются коллекциями «только для чтения» для данного метода и не переносятся автоматически. Также теряются важнейшие свойства, отвечающие за поведение печати: КлючПараметровПечати (или ИмяПараметровПечати), АвтоМасштаб, а также повторяющиеся при печати строки и колонки (ПовторятьПриПечатиСтроки).Теперь, когда мы выяснили точную причину сбоя, рассмотрим эффективные варианты ее устранения.
Самый простой, быстрый и архитектурно правильный способ — отказаться от создания абсолютно нового объекта ТабличныйДокумент. Вместо создания нового экземпляра через оператор Новый, мы будем вносить все необходимые изменения непосредственно в существующий табличный документ, который уже был подготовлен типовым механизмом конфигурации и передан в КоллекцияПечатныхФорм.
Давайте проанализируем пример кода, в котором мы аккуратно дописываем свою дополнительную область (например, блок с рекламой или важным предупреждением для клиента) в конец оригинального документа:
Для каждого СтрПечать Из КоллекцияПечатныхФорм Цикл
// Получаем ссылку на оригинальный табличный документ, созданный системой
ТабДок = СтрПечать.ТабличныйДокумент;
// Получаем область нашего макета, которую нужно добавить
Макет = ПолучитьМакет("МойДополнительныйМакет");
ОбластьПодвала = Макет.ПолучитьОбласть("ДополнительныйБлок");
// Выводим область непосредственно в исходный документ
ТабДок.Вывести(ОбластьПодвала);
КонецЦикла;
Преимущества данного подхода: мы гарантированно сохраняем все созданные БСП скрытые области печати, параметры разметки страниц, установленные шрифты, настройки принтера и масштабирования. Документ будет без проблем сохраняться в любом доступном формате и корректно прикрепляться к исходящим письмам.
Бывают ситуации, когда логика доработки требует радикального изменения структуры печатной формы (например, если нам нужно полностью перегруппировать строки, объединить ячейки или собрать один документ из нескольких разных источников). В этом случае избежать создания нового объекта ТабличныйДокумент не удастся.
Рассмотрим по шагам, как правильно пересобрать документ, не нарушив механизмы БСП.
Шаг 1. Ручное копирование параметров страницы и свойств печати. Нам необходимо вручную перенести все ключевые настройки из исходного документа в новый:
НовыйТабДок = Новый ТабличныйДокумент;
// Копируем базовые свойства отображения и масштабирования
НовыйТабДок.ОриентацияСтраницы = ИсходныйТабДок.ОриентацияСтраницы;
НовыйТабДок.АвтоМасштаб = ИсходныйТабДок.АвтоМасштаб;
НовыйТабДок.ИмяПараметровПечати = ИсходныйТабДок.ИмяПараметровПечати; // КлючПараметровПечати в новых версиях БСП
// Копируем параметры полей страницы вручную
НовыйТабДок.Поля.Лево = ИсходныйТабДок.Поля.Лево;
НовыйTabДок.Поля.Право = ИсходныйТабДок.Поля.Право;
НовыйТабДок.Поля.Верх = ИсходныйТабДок.Поля.Верх;
НовыйТабДок.Поля.Низ = ИсходныйТабДок.Поля.Низ;
// Восстанавливаем сквозные строки и колонки, если они заданы
НовыйТабДок.ПовторятьПриПечатиСтроки = ИсходныйТабДок.ПовторятьПриПечатиСтроки;
НовыйТабДок.ПовторятьПриПечатиКолонки = ИсходныйТабДок.ПовторятьПриПечатиКолонки;
Шаг 2. Задание областей печати документов для БСП. Этот шаг является самым критичным для работы функций отправки и сохранения. Нам необходимо зафиксировать начальную строку вывода для каждого документа и вызвать системный метод интеграции БСП. Для этого в процедуру печати обязательно должен передаваться параметр ОбъектыПечати.
Проанализируем пример комплексного кода:
// Предположим, что у нас есть МассивОбъектов (ссылки на печатаемые документы)
// и ОбъектыПечати (служебный СписокЗначений БСП)
НовыйТабДок = Новый ТабличныйДокумент;
Для каждого СсылкаНаДокумент Из МассивОбъектов Цикл
// Запоминаем строку, с которой начинается вывод текущего документа
НомерСтрокиНачало = НовыйТабДок.ВысотаТаблицы + 1;
// ...
// Здесь располагается ваш алгоритм вывода областей в НовыйТабДок
// ...
// Важнейший вызов БСП: регистрируем область печати для конкретного документа
УправлениеПечатью.ЗадатьОбластьПечатиДокумента(
НовыйТабДок,
НомерСтрокиНачало,
ОбъектыПечати,
СсылкаНаДокумент
);
КонецЦикла;
// Назначаем новое имя файла для сохранения по умолчанию
СтрПечать.ИмяФайлаПечатнойФормы = "Счет_на_оплату";
СтрПечать.ТабличныйДокумент = НовыйТабДок;
Использование вызова УправлениеПечатью.ЗадатьОбластьПечатиДокумента() восстанавливает скрытые связи в структуре результирующего файла. Теперь БСП «видит», какие именно строки принадлежат конкретному документу базы данных, что полностью возвращает работоспособность функциям отправки почты и экспорта на диск.