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

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

При разработке внешних печатных форм в среде «1С:Предприятие 8» на базе Библиотеки стандартных подсистем (БСП) программисты часто сталкиваются с жестким требованием системы: стандартный механизм печати ожидает обязательного возврата заполненного объекта ТабличныйДокумент. Если мы попытаемся вывести данные напрямую в сторонний формат (например, сформировать файл MS Word или Excel) и оставим результирующий табличный документ пустым, подсистема печати БСП выдаст неприятную ошибку:

{ОбщийМодуль.УправлениеПечатью.Модуль(1522)}: В обработчике печати не был сформирован табличный документ для: ...

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

Способ 1. Использование клиентского метода и формы-заглушки (Классический метод)

Этот способ основан на перенаправлении логики выполнения команды. Вместо стандартного серверного вызова мы регистрируем команду печати с типом запуска на клиенте, открываем форму нашей внешней обработки и уже из модуля этой формы генерируем офисный документ с помощью COM-соединения.

Проанализируем пошагово реализацию этого механизма. Для начала настроим функцию регистрации внешней печатной формы в модуле объекта обработки. Обратите внимание на заполнение свойств команды печати:


Функция СведенияОВнешнейОбработке() Экспорт
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработкеФайла("2.2.2.1");
    
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидДополнительнойОбработкиПечатнаяФорма();
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь;
    
    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Печать договора в MS Word";
    НоваяКоманда.Идентификатор = "ДоговорWord";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипЗапускаВызовКлиентскогоМетода();
    НоваяКоманда.Модификатор = "Печать";
    
    Возврат ПараметрыРегистрации;
КонецФункции

Благодаря использованию типа запуска ВызовКлиентскогоМетода, система при нажатии кнопки печати не будет пытаться выполнить серверную процедуру Печать модуля объекта и ожидать заполнения табличного документа. Вместо этого управление передается в модуль формы внешней обработки.

Теперь разберем, как должна выглядеть процедура Печать в модуле основной формы обработки. Мы получаем макет из двоичных данных, сохраняем его во временный файл на диске клиента и заполняем параметры через COM-объект Word.Application:


&НаКлиенте
Процедура Печать(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
    
    СсылкаНаОбъект = ОбъектыНазначения[0];
    ДанныеДляЗаполнения = ПолучитьДанныеДляЗаполненияНаСервере(СсылкаНаОбъект);
    
    // Получаем двоичные данные макета (.docx) из обработки
    МакетФайл = ПолучитьМакетНаСервере("ДоговорШаблон");
    ИмяФайлаШаблона = ПолучитьИмяВременногоФайла("docx");
    МакетФайл.Записать(ИмяФайлаШаблона);
    
    Попытка
        MSWord = Новый COMОбъект("Word.Application");
        Документ = MSWord.Documents.ADD(ИмяФайлаШаблона);
    Исключение
        ВызватьИсключение "Не удалось запустить MS Word. Проверьте, установлено ли приложение на локальном компьютере.";
    КонецПопытки;
    
    Попытка
        // Заменяем текстовые маркеры в шаблоне на реальные данные
        Для каждого ЭлементСтруктуры Из ДанныеДляЗаполнения Цикл
            СтрокаПоиска = "{" + ЭлементСтруктуры.Ключ + "}";
            Замена = Документ.Content.Find;
            
            Замена.Execute(
                СтрокаПоиска,       // Текст поиска
                Ложь,               // Учитывать регистр
                Истина,             // Искать слово целиком
                Ложь,               // Регулярные выражения
                Неопределено,       // Созвучные слова
                Неопределено,       // Все формы слова
                Истина,             // Направление вперед
                Неопределено,       // Поведение при поиске
                Ложь,               // Форматирование
                ЭлементСтруктуры.Значение, // Текст замены
                2                   // Режим замены: 2 - заменить все вхождения
            );
        КонецЦикла;
        
        // Делаем документ видимым для пользователя
        MSWord.Application.Visible = Истина;
        MSWord.Activate();
        
        // Лайфхак для принудительного вывода окна Word на передний план
        MSWord.Application.WindowState = 2; // Сворачиваем окно
        MSWord.Application.WindowState = 1; // Разворачиваем во весь экран
        
    Исключение
        Сообщить(ОписаниеОшибки());
        MSWord.Application.Quit();
    КонецПопытки;
    
КонецПроцедуры

&НаСервере
Функция ПолучитьМакетНаСервере(ИмяМакета)
    Возврат РеквизитФормыВЗначение("Объект").ПолучитьМакет(ИмяМакета);
КонецФункции

Критический недостаток этого подхода: Данное решение жестко привязано к операционной системе Windows и установленному пакету Microsoft Office на клиентском компьютере. При работе через Web-клиент, под управлением macOS или ОС семейства Linux (что крайне актуально в рамках импортозамещения) этот код завершится критической ошибкой.

Способ 2. Использование штатной коллекции «ОфисныеДокументы» на сервере (Современный кроссплатформенный подход)

Выясним, как решить задачу современными средствами самой БСП без написания клиентских форм и использования нестабильных COM-объектов. В последних версиях БСП разработчики предусмотрели штатный механизм передачи файлов Word и OpenOffice без принудительной генерации ТабличныйДокумент.

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

Посмотрим на пример реализации серверного метода печати в модуле объекта внешней обработки:


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

При использовании этого подхода БСП «под капотом» автоматически создаст пустой макет печатной формы для прохождения системных проверок на сервере, но на клиенте сразу откроет готовый сформированный документ Microsoft Word или выведет диалоговое окно для сохранения файла на диск.

Преимущества работы с офисными макетами средствами БСП

Для генерации файлов формата .docx непосредственно на сервере без COM-соединений в БСП используется встроенный функционал по работе с XML-структурами офисных пакетов. Разберем основные преимущества этого метода:

  1. Кроссплатформенность: Генерация файлов происходит на сервере приложений 1С. Сервер может работать под управлением ОС Linux, а клиенты могут использовать любые операционные системы и веб-браузеры. Присутствие установленного Microsoft Office на компьютере сервера или клиента не требуется вообще.
  2. Производительность: Метод работает в разы быстрее, чем инициализация тяжелого COM-процесса WINWORD.EXE. Это снижает общую нагрузку на процессор и оперативную память сервера.
  3. Безопасность: Исключена проблема зависших процессов Word в диспетчере задач операционной системы при возникновении непредвиденных исключений в коде 1С.

Рекомендация по оптимизации для высоконагруженных систем

В процессе работы серверного механизма БСП метод УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента() может отнимать значительную долю процессорного времени (до 60–70% всего времени формирования печатной формы). Это происходит из-за того, что системе приходится при каждом обращении распаковывать zip-архив docx-шаблона и анализировать его XML-структуру в оперативной памяти.

Чтобы существенно ускорить печать, мы можем произвести первичную инициализацию макета один раз на этапе разработки в режиме отладки. Полученную готовую структуру XML можно преобразовать в строку при помощи метода ЗначениеВСтрокуXML() и сохранить результат как отдельный текстовый макет внутри нашей обработки. При выводе документов на печать на сервере достаточно будет быстро восстановить готовую XML-структуру макета вызовом ЗначениеИзСтрокиXML(), минуя медленный этап распаковки архива docx.

← На главную