В процессе сопровождения конфигураций, особенно таких регламентированных как 1С:Зарплата и Управление Персоналом (ЗУП) или ЗГУ, мы часто сталкиваемся с ситуацией, когда продвинутые пользователи хотят самостоятельно редактировать печатные формы. Типовой функционал БСП (Библиотеки Стандартных Подсистем) предоставляет отличную возможность: пользовательские макеты печати (в формате Word/Office Open XML). Пользователь может открыть макет, подвигать текст, изменить шрифт.
Однако возникает классическая проблема: пользователю не хватает стандартных полей. Он хочет вывести "Дополнительный реквизит", "Отчество водителя" или "Специфический номер приказа", но этих данных нет в стандартном наборе параметров, который 1С передает в макет. В этой статье мы подробно разберем, как с помощью расширения конфигурации внедрить свои параметры в типовой механизм печати, не ломая при этом логику обновлений.
Прежде чем писать код, давайте разберемся, как система понимает, что и куда печатать. Когда пользователь нажимает кнопку "Печать", происходит следующее:
ПользовательскиеМакетыПечати.{Фамилия} и заменяет их на значения из подготовленных данных.Главная загвоздка: если пользователь напишет в Word-файле {МойСуперПараметр}, но программист не добавил этот параметр в коллекцию данных на шаге 3, то при печати этот текст так и останется фигурных скобках или будет пустым. Наша задача — вмешаться в шаг 3.
Наиболее правильный и современный подход — использование расширений. Это позволяет не снимать конфигурацию с поддержки. Рассмотрим пошаговый алгоритм действий.
Мы будем перехватывать процедуру печати в модуле менеджера того объекта (документа или справочника), печатную форму которого мы хотим доработать.
Создадим новое расширение и добавим в него нужный нам документ, например, Документ.ПриемНаРаботу. Нам не нужны все реквизиты, достаточно добавить сам объект и его Модуль менеджера.
Откроем модуль менеджера документа в основной конфигурации и найдем экспортную процедуру Печать. Обычно она выглядит примерно так:
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// ... вызов функций формирования данных ...
// ... заполнение коллекции печатных форм ...
КонецПроцедуры
Или же внутри этой процедуры вызывается процедура формирования данных, например УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию (для MXL) или специализированные методы для Word.
Нам необходимо использовать аннотацию &После (или &Вместо, если требуется кардинальная переработка, но &После безопаснее). Однако, поскольку данные формируются внутри процедуры, просто выполнить код "после" может быть недостаточно, если данные уже уничтожены. Но чаще всего мы можем перехватить управление в момент формирования печатной формы.
Рассмотрим более гибкий вариант. В большинстве современных конфигураций (включая ЗУП) данные для печати готовятся отдельными запросами. Мы можем перехватить процедуру печати, позволить типовому коду отработать, а затем найти в КоллекцияПечатныхФорм нужную нам форму и, если это табличный документ, добавить параметры. Но для Word (Office Open XML) подход немного другой — данные передаются структурой.
Давайте рассмотрим универсальный пример внедрения через изменение параметров источника данных. Предположим, мы нашли функцию, которая готовит данные. Но проще всего поступить так: перехватить процедуру печати и дополнить данные до вывода или модифицировать их после (если архитектура позволяет).
В случае с макетами Office Open XML, данные часто собираются в Области (Area) или структуры параметров. Если мы говорим о стандартной БСП, то часто используется механизм УправлениеПечатью.ВывестиМассивОбъектовВOpenOfficeXML.
Если мы не можем легко вклиниться в середину типовой функции, мы можем использовать подход создания Внешней печатной формы, которая будет использовать тот же пользовательский макет. Но автор вопроса просил решение через расширение. Давайте реализуем перехват получения данных.
Посмотрим на пример кода, который нужно поместить в модуль менеджера документа в расширении:
&Вместо("Печать")
Процедура Расш_Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода)
// 1. Сначала даем отработать типовому механизму
ПродолжитьВызов(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
// 2. Ищем нужную нам печатную форму в коллекции
// Имя макета ("ПФ_DOC_ТрудовойДоговор") нужно знать точно (как в конфигураторе)
НужнаяПечатнаяФорма = УправлениеПечатью.НайтиПечатнуюФормуВКоллекции(
КоллекцияПечатныхФорм, "ПФ_DOC_ТрудовойДоговор");
Если НужнаяПечатнаяФорма <> Неопределено Тогда
// ВАЖНЫЙ МОМЕНТ:
// Для макетов Word в типовых конфигурациях данные часто уже "запекаются" в двоичные данные
// внутри ПродолжитьВызов, если это стандартная печать.
// Если это так, то менять что-то "После" уже поздно для Word-макета.
КонецЕсли;
КонецПроцедуры
Внимание! Вышеописанная проблема (данные уже выведены) является ключевой. Поэтому для Word-макетов нам часто приходится копировать логику формирования данных в расширение или внешнюю обработку. Однако, в БСП есть механизмы Переопределяемый модулей. Но давайте рассмотрим вариант, когда мы добавляем данные в источник.
В ЗУП 3.1 данные для печати часто готовятся в менеджере объекта функцией вроде ПодготовитьДанныеДляПечати. Перехватив её (через &После), мы можем обогатить возвращаемую структуру.
&После("ПодготовитьДанныеДляПечати")
Процедура Расш_ПодготовитьДанныеДляПечати(МассивОбъектов, ПараметрыПечати, Результат)
// Результат - это обычно ТаблицаЗначений или Структура с данными по сотрудникам
// Обходим результат и добавляем свои поля
Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") Тогда
Если Результат.Колонки.Найти("МойНовыйРеквизит") = Неопределено Тогда
Результат.Колонки.Добавить("МойНовыйРеквизит");
КонецЕсли;
Для Каждого СтрокаДанных Из Результат Цикл
// Вычисляем значение вашего параметра
// Например, получаем значение доп. реквизита
СтрокаДанных.МойНовыйРеквизит = ПолучитьЗначениеМоегоРеквизита(СтрокаДанных.Ссылка);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
После того как вы добавите колонку МойНовыйРеквизит в таблицу данных, типовой механизм печати (который выполняется следом) увидит эту колонку. Теперь, если в макете Word будет стоять тег {МойНовыйРеквизит}, 1С успешно подставит туда значение.
Теперь, когда программная часть готова, давайте настроим работу со стороны пользователя. Это именно то, чего хотел автор вопроса — дать возможность привилегированному пользователю самому "играть со шрифтами".
{МойНовыйРеквизит}.Теперь макет помечен специальной пиктограммой (зеленый карандаш), что означает использование пользовательской версии. При печати сработает ваше расширение, добавит данные в таблицу, а механизм БСП подставит их в пользовательский макет.
Если по каким-то причинам расширения использовать нельзя (политика безопасности или жесткий запрет), можно решить задачу через ВПФ. Это безопасный "песочный" метод.
Логика следующая:
СведенияОВнешнейОбработке.Печать.Печать мы сами формируем запрос к данным, получаем все, что нужно (стандартные поля + наши специфические).Для этого нужно использовать метод БСП:
Макет = УправлениеПечатью.МакетПечатнойФормы(
"ВнешняяОбработка.ИмяВашейОбработки", // Или путь к документу, если мимикрируем
"ИмяМакета"
);
Однако, пользовательские макеты привязываются к идентификаторам объектов метаданных. Если вы хотите, чтобы пользователь правил макет именно для вашей ВПФ, вам придется либо:
УправлениеПечатью.МакетПечатнойФормы("Документ.ПриемНаРаботу", "ПФ_DOC_ТрудовойДоговор"). Тогда пользователь будет править макет типового документа через "Администрирование", а печататься он будет через вашу кнопку с вашими дополнительными параметрами.Разберем несколько тонкостей, которые помогут избежать ошибок:
{Параметр} должны совпадать полностью.{Параметр}, а внутри это {<span lang=...>Пара</span>метр}. 1С такой тег не найдет.
Alt+F9, чтобы убедиться, что внутри нет полей mergefield (хотя 1С обычно работает с простым текстом).Чтобы разрешить пользователю редактировать макет и при этом использовать нестандартные данные, не нужно "взламывать" регистр макетов. Достаточно:
&После добавить в результирующую таблицу нужные колонки и заполнить их.{ИмяКолонки} в Word.Этот метод является наиболее "чистым" с точки зрения архитектуры 1С и позволяет обновлять типовую конфигурацию без конфликтов.