Как создать внешнюю печатную форму (ВПФ) в формате ODT без использования стандартных функций БСП?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Промышленность, строительство и АПК
← На главную

Часто при работе с отраслевыми решениями, такими как «ПС:Управление мебельной фабрикой ERP» (базирующимися на ядре 1С:ERP), программисты сталкиваются с тем, что привычные общие модули Библиотеки стандартных подсистем (БСП) переименованы, сильно модифицированы или частично отсутствуют. Например, в базе может не оказаться общего модуля ДополнительныеОтчетыИОбработки или не работать стандартная экспортная процедура СведенияОВнешнейОбработке. Для подобных случаев подойдёт обработка для ручной регистрации внешних печатных форм.

Проанализируем ситуацию: если готовых примеров и стандартных обработчиков нет, нам придется реализовывать механизм печати самостоятельно. Рассмотрим подробно два рабочих метода формирования документов в формате ODT (OpenDocument Text): классический через COM-объект и более современный серверный метод через работу с ZIP-архивами.

Особенности подключения в отраслевых конфигурациях

Разберем по шагам специфику работы с ВПФ, когда стандартная БСП недоступна:

  1. Регистрация обработки часто происходит через кастомный справочник внешних обработок, созданный разработчиком отраслевого решения.
  2. Если механизмы регистрации сломаны, печатную форму можно подключить, добавив команду напрямую в интерфейс документа через Расширение конфигурации.
  3. Макет документа ODT всегда загружается в обработку как объект с типом Двоичные данные.

Способ 1: Заполнение ODT через COM-объект LibreOffice на клиенте

Этот подход во многом аналогичен созданию печатной формы на базе MS Word, но использует API OpenOffice/LibreOffice. Рассмотрим алгоритм действий:

  1. При нажатии на кнопку печати серверный метод обработки собирает все необходимые данные из документа (выполняет запросы к базе).
  2. Управление передается на сторону клиента. Важно: для этого способа на компьютере пользователя обязательно должен быть установлен LibreOffice или OpenOffice.
  3. На клиенте двоичные данные макета сохраняются во временный файл ODT. Для этого используем функцию ПолучитьИмяВременногоФайла("odt").
  4. Далее система инициализирует COM-объект com.sun.star.ServiceManager.
  5. Служба открывает временный документ в скрытом режиме, находит специальные текстовые маркеры (теги) и заменяет их на реальные данные, полученные с сервера. После замены документ выводится на экран пользователя.

Данный метод рабочий, но имеет недостатки: он требует обязательной установки стороннего ПО на клиентские машины и может работать медленно из-за особенностей COM-соединения.

Способ 2: Продвинутая генерация ODT на сервере (Без COM-объектов)

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

Разберем этот процесс детально:

  1. На сервере макет (двоичные данные) выгружается во временный файл с расширением ZIP.
  2. С помощью платформенного объекта ЧтениеZipФайла архив распаковывается во временную директорию.
  3. Текст всего документа ODT хранится в распакованной папке в файле content.xml.
  4. С помощью объектов ЧтениеТекста и ЗаписьТекста мы читаем этот XML-файл как обычную строку.
  5. Функция СтрЗаменить находит расставленные в документе теги (например, {Организация}, {НомерДокумента}) и подставляет нужные значения.
  6. Измененный файл content.xml сохраняется, и папка снова запаковывается объектом ЗаписьZipФайла в исходный формат ODT.
  7. Готовый файл передается на клиент и открывается через ЗапуститьПриложение().

Посмотрим на пример реализации данного алгоритма в коде:


// 1. Получаем макет из внешней обработки
Макет = ПолучитьМакет("МакетДоговораODT");
ИмяАрхиваZIP = ПолучитьИмяВременногоФайла("zip");
Макет.Записать(ИмяАрхиваZIP);

// 2. Распаковываем ODT (ZIP) во временную папку
ПапкаРаспаковки = ПолучитьИмяВременногоФайла("");
СоздатьКаталог(ПапкаРаспаковки);

ЧтениеАрхива = Новый ЧтениеZipФайла(ИмяАрхиваZIP);
ЧтениеАрхива.ИзвлечьВсе(ПапкаРаспаковки);
ЧтениеАрхива.Закрыть();

// 3. Читаем файл content.xml
ПутьККонтенту = ПапкаРаспаковки + "\content.xml";
ТекстДок = Новый ЧтениеТекста(ПутьККонтенту, КодировкаТекста.UTF8);
ТекстXML = ТекстДок.Прочитать();
ТекстДок.Закрыть();

// 4. Заменяем теги на данные из базы
ТекстXML = СтрЗаменить(ТекстXML, "{НомерДокумента}", ДанныеПечати.Номер);
ТекстXML = СтрЗаменить(ТекстXML, "{ДатаДокумента}", Формат(ДанныеПечати.Дата, "ДЛФ=DD"));
ТекстXML = СтрЗаменить(ТекстXML, "{Контрагент}", ДанныеПечати.КонтрагентНаименование);

// 5. Записываем изменения обратно в content.xml
ЗаписьДок = Новый ЗаписьТекста(ПутьККонтенту, КодировкаТекста.UTF8);
ЗаписьДок.Записать(ТекстXML);
ЗаписьДок.Закрыть();

// 6. Запаковываем обратно в ODT
ИмяГотовогоФайла = ПолучитьИмяВременногоФайла("odt");
ЗаписьАрхива = Новый ЗаписьZipФайла(ИмяГотовогоФайла);
ЗаписьАрхива.Добавить(ПапкаРаспаковки + "\*", РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
ЗаписьАрхива.Записать();

Этот способ абсолютно независим от наличия БСП, COM-объектов или установленного на сервере офисного пакета. Он работает максимально быстро и надежно.

Решение проблемы с печатью "непроведенных" документов

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

В модуле формы вашей внешней обработки создайте команду с типом вызова ВызовКлиентскогоМетода. В клиентской процедуре формы пропишите собственную логику получения ссылки на текущий объект (документ) и прямой вызов вашей серверной процедуры генерации ODT. Таким образом, вы полностью перехватываете управление процессом печати на себя, минуя любые проверки стандартных подсистем конфигурации.

← На главную