В процессе разработки на платформе 1С:Предприятие часто возникает задача предоставить «продвинутым» пользователям возможность самостоятельно изменять печатные формы, не прибегая к помощи конфигуратора. Особенно это актуально для внешних печатных форм (ВПФ), которые хранятся как отдельные файлы .epf. Однако при попытке программно изменить макет внутри уже созданного объекта внешней обработки программисты сталкиваются с определенными ограничениями платформы.
В данной статье мы подробно разберем, почему стандартный подход с методом ПолучитьМакет() не позволяет напрямую «перезаписать» макет, и рассмотрим эффективные способы решения этой задачи, включая использование механизмов БСП и создание собственных систем хранения пользовательских макетов.
Разберем ситуацию, с которой сталкивается разработчик. Когда мы используем конструкцию ВнешниеОбработки.Создать(ИмяФайла), платформа считывает структуру файла .epf и создает в оперативной памяти объект. Важно понимать: метаданные этого объекта (включая макеты) после создания доступны только для чтения. Даже если вы прочитаете новый макет из внешнего файла .mxl, вы не сможете «запихнуть» его обратно в структуру объекта так, чтобы штатный метод ПолучитьМакет("ИмяМакета") начал возвращать новую версию.
Рассмотрим пример кода, который часто пытаются использовать новички, и выясним, почему он не работает для сохранения изменений:
// Получаем макет из созданной обработки
МакетОбработки = Обработка.ПолучитьМакет("ОсновнойМакет");
// Пытаемся прочитать данные из временного файла пользователя
МакетОбработки.Прочитать(ИмяВременногоФайла);
// В этот момент МакетОбработки в памяти изменился,
// но он НЕ перезаписал макет внутри самого объекта "Обработка"
Проанализируем ситуацию: объект типа ТабличныйДокумент, который возвращает ПолучитьМакет(), является копией данных макета. Его изменение никак не влияет на описание самой обработки в памяти. Следовательно, нам нужны другие подходы.
Если ваша конфигурация построена на базе БСП (что справедливо для большинства современных типовых решений), то задача «дать пользователю редактировать макет» уже решена на системном уровне. В БСП существует подсистема «Печать», которая включает регистр сведений «Пользовательские макеты печати».
Рассмотрим, как это работает программно:
Чтобы ваша внешняя обработка поддерживала этот механизм, проанализируем функцию СведенияОВнешнейОбработке(). В ней необходимо правильно описать команды печати, чтобы система смогла идентифицировать макеты обработки как объекты, доступные для пользовательского редактирования.
Если конфигурация самописная или вы хотите реализовать свой узкоспециализированный механизм (например, для работы в РИБ), мы рекомендуем использовать архитектурный подход: «Разделение логики и оформления». Вместо того чтобы пытаться изменить сам файл .epf, мы будем хранить измененный макет в справочнике или регистре.
Разберем пошагово, как это реализовать:
Шаг 1. Создание хранилища
В справочнике, где вы регистрируете внешние печатные формы (или в отдельном регистре), добавьте реквизит с типом ХранилищеЗначения. Назовем его ПользовательскийМакет.
Шаг 2. Сохранение измененного макета
Когда пользователь отредактировал табличный документ в режиме предприятия, сохраним его в базу данных следующим кодом:
// Допустим, ТабДок - это отредактированный пользователем макет
НовоеХранилище = Новый ХранилищеЗначения(ТабДок);
ОбъектСправочника = СсылкаНаВнешнююФорму.ПолучитьОбъект();
ОбъектСправочника.ПользовательскийМакет = НовоеХранилище;
ОбъектСправочника.Записать();
Шаг 3. Загрузка макета при печати
Теперь самое главное — изменить логику получения макета в модуле самой обработки. Рассмотрим пример функции, которая выбирает актуальный макет:
Функция ПолучитьАктуальныйМакет(ИмяМакета, СсылкаНаВнешнююФорму)
// Сначала проверим, есть ли пользовательский макет в базе
ДанныеМакета = СсылкаНаВнешнююФорму.ПользовательскийМакет.Получить();
Если ТипЗнч(ДанныеМакета) = Тип("ТабличныйДокумент") Тогда
// Возвращаем сохраненный пользователем вариант
Возврат ДанныеМакета;
Иначе
// Если пользователь ничего не менял, берем стандартный из метаданных
Возврат ЭтотОбъект.ПолучитьМакет(ИмяМакета);
КонецЕсли;
КонецФункции
Выясним причину, почему в РИБ использование внешних файлов или динамическая модификация .epf через сторонние утилиты типа v8unpack крайне нежелательны. При использовании РИБ данные синхронизируются между узлами. Если вы будете программно менять файл на диске на одном узле, эти изменения не попадут на другие узлы автоматически.
Используя предложенный метод с ХранилищемЗначения в справочнике или регистре, вы гарантируете:
Подведем итоги нашего исследования. Напрямую подменить макет внутри объекта Обработка невозможно из-за ограничений объектной модели 1С. Однако задача решается путем изменения логики работы с макетами:
ХранилищеЗначения для хранения ТабличногоДокумента.ЭтотОбъект.ПолучитьМакет().Такой подход делает систему гибкой, безопасной для обновлений и удобной для конечного пользователя, освобождая программиста от рутинных задач по изменению шрифтов или добавлению логотипов в печатные формы.