Как добавить пользовательские параметры в макет печатной формы Word (Office Open XML) и перехватить печать в расширении?

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

В процессе сопровождения конфигураций, особенно таких регламентированных как 1С:Зарплата и Управление Персоналом (ЗУП) или ЗГУ, мы часто сталкиваемся с ситуацией, когда продвинутые пользователи хотят самостоятельно редактировать печатные формы. Типовой функционал БСП (Библиотеки Стандартных Подсистем) предоставляет отличную возможность: пользовательские макеты печати (в формате Word/Office Open XML). Пользователь может открыть макет, подвигать текст, изменить шрифт.

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

Суть проблемы и механизм работы БСП

Прежде чем писать код, давайте разберемся, как система понимает, что и куда печатать. Когда пользователь нажимает кнопку "Печать", происходит следующее:

  1. Система определяет, есть ли для данной печатной формы активный Пользовательский макет в регистре сведений ПользовательскиеМакетыПечати.
  2. Если пользовательский макет есть, система берет его (это файл .docx, хранящийся в базе как двоичные данные). Если нет — берет типовой макет из конфигурации.
  3. Затем запускается процедура подготовки данных. Система формирует структуру или таблицу значений с данными документа (ФИО, Дата, Номер, Должность и т.д.).
  4. Механизм печати ищет в Word-файле текстовые метки вида {Фамилия} и заменяет их на значения из подготовленных данных.

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

Решение через Расширение конфигурации

Наиболее правильный и современный подход — использование расширений. Это позволяет не снимать конфигурацию с поддержки. Рассмотрим пошаговый алгоритм действий.

Мы будем перехватывать процедуру печати в модуле менеджера того объекта (документа или справочника), печатную форму которого мы хотим доработать.

Шаг 1. Подготовка расширения

Создадим новое расширение и добавим в него нужный нам документ, например, Документ.ПриемНаРаботу. Нам не нужны все реквизиты, достаточно добавить сам объект и его Модуль менеджера.

Шаг 2. Анализ типового кода

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


Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
    // ... вызов функций формирования данных ...
    // ... заполнение коллекции печатных форм ...
КонецПроцедуры

Или же внутри этой процедуры вызывается процедура формирования данных, например УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию (для MXL) или специализированные методы для Word.

Шаг 3. Перехват и внедрение параметров

Нам необходимо использовать аннотацию &После (или &Вместо, если требуется кардинальная переработка, но &После безопаснее). Однако, поскольку данные формируются внутри процедуры, просто выполнить код "после" может быть недостаточно, если данные уже уничтожены. Но чаще всего мы можем перехватить управление в момент формирования печатной формы.

Рассмотрим более гибкий вариант. В большинстве современных конфигураций (включая ЗУП) данные для печати готовятся отдельными запросами. Мы можем перехватить процедуру печати, позволить типовому коду отработать, а затем найти в КоллекцияПечатныхФорм нужную нам форму и, если это табличный документ, добавить параметры. Но для Word (Office Open XML) подход немного другой — данные передаются структурой.

Давайте рассмотрим универсальный пример внедрения через изменение параметров источника данных. Предположим, мы нашли функцию, которая готовит данные. Но проще всего поступить так: перехватить процедуру печати и дополнить данные до вывода или модифицировать их после (если архитектура позволяет).

В случае с макетами Office Open XML, данные часто собираются в Области (Area) или структуры параметров. Если мы говорим о стандартной БСП, то часто используется механизм УправлениеПечатью.ВывестиМассивОбъектовВOpenOfficeXML.

Если мы не можем легко вклиниться в середину типовой функции, мы можем использовать подход создания Внешней печатной формы, которая будет использовать тот же пользовательский макет. Но автор вопроса просил решение через расширение. Давайте реализуем перехват получения данных.

Посмотрим на пример кода, который нужно поместить в модуль менеджера документа в расширении:


&Вместо("Печать")
Процедура Расш_Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода)
    
    // 1. Сначала даем отработать типовому механизму
    ПродолжитьВызов(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
    
    // 2. Ищем нужную нам печатную форму в коллекции
    // Имя макета ("ПФ_DOC_ТрудовойДоговор") нужно знать точно (как в конфигураторе)
    НужнаяПечатнаяФорма = УправлениеПечатью.НайтиПечатнуюФормуВКоллекции(
        КоллекцияПечатныхФорм, "ПФ_DOC_ТрудовойДоговор");
        
    Если НужнаяПечатнаяФорма <> Неопределено Тогда
        // ВАЖНЫЙ МОМЕНТ: 
        // Для макетов Word в типовых конфигурациях данные часто уже "запекаются" в двоичные данные 
        // внутри ПродолжитьВызов, если это стандартная печать.
        // Если это так, то менять что-то "После" уже поздно для Word-макета.
    КонецЕсли;

КонецПроцедуры

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

В ЗУП 3.1 данные для печати часто готовятся в менеджере объекта функцией вроде ПодготовитьДанныеДляПечати. Перехватив её (через &После), мы можем обогатить возвращаемую структуру.


&После("ПодготовитьДанныеДляПечати")
Процедура Расш_ПодготовитьДанныеДляПечати(МассивОбъектов, ПараметрыПечати, Результат)
    
    // Результат - это обычно ТаблицаЗначений или Структура с данными по сотрудникам
    // Обходим результат и добавляем свои поля
    
    Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") Тогда
        
        Если Результат.Колонки.Найти("МойНовыйРеквизит") = Неопределено Тогда
            Результат.Колонки.Добавить("МойНовыйРеквизит");
        КонецЕсли;
        
        Для Каждого СтрокаДанных Из Результат Цикл
            // Вычисляем значение вашего параметра
            // Например, получаем значение доп. реквизита
            СтрокаДанных.МойНовыйРеквизит = ПолучитьЗначениеМоегоРеквизита(СтрокаДанных.Ссылка);
        КонецЦикла;
        
    КонецЕсли;

КонецПроцедуры

После того как вы добавите колонку МойНовыйРеквизит в таблицу данных, типовой механизм печати (который выполняется следом) увидит эту колонку. Теперь, если в макете Word будет стоять тег {МойНовыйРеквизит}, 1С успешно подставит туда значение.

Работа с пользовательским макетом

Теперь, когда программная часть готова, давайте настроим работу со стороны пользователя. Это именно то, чего хотел автор вопроса — дать возможность привилегированному пользователю самому "играть со шрифтами".

  1. Запускаем 1С в режиме Предприятия.
  2. Переходим в раздел Администрирование — Печатные формы, отчеты и обработки — Макеты печатных форм.
  3. Находим нужный макет (например, "Трудовой договор (микропредприятия)"). Он будет иметь значок Word.
  4. Нажимаем кнопку Открыть или Изменить. Выбираем "Для просмотра и редактирования".
  5. Открывается Microsoft Word.
  6. В нужное место документа пользователь пишет: {МойНовыйРеквизит}.
  7. Сохраняем файл в Word и закрываем его.
  8. В 1С нажимаем "Записать и закрыть" в карточке макета.

Теперь макет помечен специальной пиктограммой (зеленый карандаш), что означает использование пользовательской версии. При печати сработает ваше расширение, добавит данные в таблицу, а механизм БСП подставит их в пользовательский макет.

Альтернативный вариант: Внешняя печатная форма (ВПФ)

Если по каким-то причинам расширения использовать нельзя (политика безопасности или жесткий запрет), можно решить задачу через ВПФ. Это безопасный "песочный" метод.

Логика следующая:

  1. Создаем внешнюю обработку.
  2. В модуле объекта реализуем функцию СведенияОВнешнейОбработке.
  3. Реализуем процедуру Печать.
  4. Внутри процедуры Печать мы сами формируем запрос к данным, получаем все, что нужно (стандартные поля + наши специфические).
  5. Важный нюанс: как заставить ВПФ использовать макет, который пользователь сохранил в регистр "Пользовательские макеты"?

Для этого нужно использовать метод БСП:


Макет = УправлениеПечатью.МакетПечатнойФормы(
    "ВнешняяОбработка.ИмяВашейОбработки", // Или путь к документу, если мимикрируем
    "ИмяМакета"
);

Однако, пользовательские макеты привязываются к идентификаторам объектов метаданных. Если вы хотите, чтобы пользователь правил макет именно для вашей ВПФ, вам придется либо:

Практические советы

Разберем несколько тонкостей, которые помогут избежать ошибок:

  1. Регистр букв имеет значение. Имя параметра в коде (в колонке Таблицы Значений) и имя в фигурных скобках {Параметр} должны совпадать полностью.
  2. Форматирование в Word. Иногда, когда вы копируете и вставляете теги в Word, внутрь фигурных скобок попадает невидимое форматирование (xml-теги Word). Визуально вы видите {Параметр}, а внутри это {<span lang=...>Пара</span>метр}. 1С такой тег не найдет.
    Решение: Наберите тег вручную от начала до конца или копируйте через "Блокнот" (очистку форматирования). Или нажмите в Word Alt+F9, чтобы убедиться, что внутри нет полей mergefield (хотя 1С обычно работает с простым текстом).
  3. Списки и таблицы. Если вам нужно вывести список (например, состав начислений), в макете Word нужно выделить строку таблицы, которая будет повторяться. В коде 1С данные для этой табличной части должны передаваться как вложенная таблица значений или массив структур. БСП умеет это обрабатывать, если структура данных корректна.

Итог

Чтобы разрешить пользователю редактировать макет и при этом использовать нестандартные данные, не нужно "взламывать" регистр макетов. Достаточно:

  1. Сделать Расширение.
  2. Найти функцию подготовки данных документа (обычно в модуле менеджера).
  3. Через аннотацию &После добавить в результирующую таблицу нужные колонки и заполнить их.
  4. Научить пользователя синтаксису {ИмяКолонки} в Word.

Этот метод является наиболее "чистым" с точки зрения архитектуры 1С и позволяет обновлять типовую конфигурацию без конфликтов.

← На главную