Макет конфигурации в серверном коде: от ПолучитьМакет до файла у пользователя

· 9 мин

Содержание

Макет на сервере 1С получают методом ПолучитьМакет("ИмяМакета") у менеджера объекта (Обработки.ЗагрузкаПрайса.ПолучитьМакет("Шаблон")) или у самого объекта, а общий макет — функцией глобального контекста ПолучитьОбщийМакет("ИмяМакета"). Вызов делают в процедуре с директивой &НаСервере или &НаСервереБезКонтекста, в общем модуле с флагом «Сервер» или в модуле менеджера.

На тонком клиенте и в веб-клиенте эти методы недоступны. Поэтому типовая схема такая: сервер получает макет, при необходимости превращает его в файл или табличный документ и отдаёт клиенту результат. Тема общая для платформы 8.3 и не зависит от конфигурации.

Почему макет живёт только на сервере

Макеты — часть метаданных конфигурации. В клиент-серверном варианте конфигурация хранится в базе, а работает с ней рабочий процесс кластера. Тонкий клиент получает только формы и то, что ему явно передали.

Отсюда три следствия, которые полезно держать в голове:

  • 🖥️ Где вызывать. Всё, что начинается с ПолучитьМакет, работает в серверном контексте и в толстом клиенте. В модуле управляемой формы на клиенте этого метода нет.
  • 📦 Что передавать. Сам макет «по ссылке» на клиент не уходит. Уходит копия значения: табличный документ, строка, адрес во временном хранилище.
  • 🗂️ Чья файловая система. Если сервер записывает макет в файл, файл появляется на машине с рабочим процессом, а не на компьютере бухгалтера.

В файловом варианте «сервер» — это тот же процесс на компьютере пользователя. Поэтому код, который пишет макет в C:\Temp и открывает его, в файловой базе работает, а после перехода на клиент-сервер ломается. Тестируйте серверную логику на клиент-серверной копии.

Где лежит макет и каким методом его брать

Где лежит макетКак получить на сервере
Общие → Общие макетыПолучитьОбщийМакет("ИмяМакета")
Макет документа, справочника, отчётаДокументы.ИмяДокумента.ПолучитьМакет("ИмяМакета")
Макет обработки из конфигурацииОбработки.ИмяОбработки.ПолучитьМакет("ИмяМакета")
Макет внешней обработки или отчётаРеквизитФормыВЗначение("Объект").ПолучитьМакет("ИмяМакета")
Макет с учётом правок пользователя (типовые на БСП)УправлениеПечатью.МакетПечатнойФормы("Документ.Имя.ИмяМакета")

Две последние строки — то, на чём чаще всего спотыкаются.

Внешняя обработка. Её нет в коллекции Обработки, обратиться к менеджеру по имени нельзя. Поэтому в форме внешней обработки объект достают из реквизита формы: РеквизитФормыВЗначение("Объект"). Это работает только в процедуре &НаСервере — с контекстом формы.

Изменённые печатные формы. В типовых конфигурациях пользователь может поправить макет в режиме 1С:Предприятие: Администрирование → Печатные формы, отчеты и обработки → Макеты печатных форм. Прямой ПолучитьМакет вернёт исходный макет из конфигурации и правки проигнорирует. Функция БСП УправлениеПечатью.МакетПечатнойФормы сначала ищет пользовательский вариант.

Как получить макет в двоичные данные: порядок действий

Макет типа «Двоичные данные» — это любой файл, вшитый в конфигурацию: шаблон Word или Excel, zip-архив, картинка, внешняя компонента, XSD-схема. В конфигураторе его создают как макет с типом «Двоичные данные» и загружают из файла.

На сервере его получают так:

  1. Убедитесь, что процедура выполняется на сервере: директива &НаСервере в форме или серверный общий модуль.
  2. Возьмите макет у менеджера объекта или через ПолучитьОбщийМакет.
  3. Проверьте тип результата, если код универсальный.
  4. Работайте с данными: читайте поток, пишите во временный файл или кладите во временное хранилище.
&НаСервереБезКонтекста
Функция ШаблонДоговора()

    ДД = Документы.ДоговорАренды.ПолучитьМакет("ШаблонWord");

    Если ТипЗнч(ДД) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Макет ШаблонWord должен иметь тип «Двоичные данные»";
    КонецЕсли;

    Возврат ДД;

КонецФункции

Директива &НаСервереБезКонтекста здесь выбрана намеренно. Данные формы на сервер не передаются, вызов получается легче. &НаСервере нужна только тогда, когда без формы не обойтись — например, для внешней обработки.

Какой тип вернёт ПолучитьМакет

Тип результата задаётся типом макета в конфигураторе:

Тип макета в конфигуратореЧто вернёт метод
Табличный документТабличныйДокумент
Текстовый документТекстовыйДокумент
Двоичные данныеДвоичныеДанные
Схема компоновки данныхСхемаКомпоновкиДанных
Графическая схемаГрафическаяСхема

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

Двоичные данные макета: потоки и чтение без лишних файлов

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

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

Шаблон письма, JSON с настройками или SQL-скрипт удобно хранить как двоичные данные и читать в строку:

ДД = ПолучитьОбщийМакет("НастройкиОбменаJSON");
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДД, КодировкаТекста.UTF8);

Если макет хранится как «Текстовый документ», строку получают иначе: ПолучитьОбщийМакет("Имя").ПолучитьТекст().

Распаковать zip из макета через поток

ДД = ПолучитьОбщийМакет("КомплектШаблонов");
Поток = ДД.ОткрытьПотокДляЧтения();
Архив = Новый ЧтениеZipФайла(Поток);

Для Каждого Элемент Из Архив.Элементы Цикл
    Сообщить(Элемент.ПолноеИмя);
КонецЦикла;

Архив.Закрыть();
Поток.Закрыть();

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

Внешняя компонента из макета

Частый приём практика: внешнюю компоненту не сохраняют во временный файл вручную, а подключают прямо из общего макета:

Подключено = ПодключитьВнешнююКомпоненту("ОбщийМакет.КомпонентаШтрихкодов",
    "Штрихкод", ТипВнешнейКомпоненты.Native);

Платформа сама распакует компоненту. Ручная запись в КаталогВременныхФайлов() здесь лишняя.

Диагностика: выберите симптом

Запись макета в файл на сервере

Иногда без файла не обойтись: внешняя программа принимает только путь, нужно положить шаблон в общий сетевой каталог, или COM-объект открывает документ по имени файла.

Безопасный шаблон кода:

ДД = Обработки.ВыгрузкаВБанк.ПолучитьМакет("ШаблонВыписки");
ИмяФайла = ПолучитьИмяВременногоФайла("xml");

Попытка
    ДД.Записать(ИмяФайла);
    // работа с файлом: передача во внешнюю программу, разбор и т.п.
Исключение
    УдалитьФайлы(ИмяФайла);
    ВызватьИсключение;
КонецПопытки;

УдалитьФайлы(ИмяФайла);

Что здесь важно:

  • 📁 ПолучитьИмяВременногоФайла даёт уникальное имя в каталоге временных файлов сервера. Два пользователя одновременно не перезапишут файл друг друга.
  • 🧹 УдалитьФайлы вызывается и при ошибке. Иначе каталог временных файлов рабочего процесса со временем распухает.
  • 🔐 Файл пишется от имени учётной записи, под которой запущена служба сервера 1С. Если нужен конкретный каталог, у этой учётной записи должны быть права на запись туда.

Не записывайте макеты в каталог установки платформы и в каталог кластера. Пишите только во временный каталог или в отдельную папку, выделенную под обмен.

Табличный макет в файл Excel

Для печатной формы схема другая: заполняете табличный документ из макета и сохраняете уже результат.

Макет = Документы.СчетНаОплату.ПолучитьМакет("ПечатнаяФорма");
ТабДок = Новый ТабличныйДокумент;
ТабДок.Вывести(Макет.ПолучитьОбласть("Шапка"));

ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);

Имена макета и областей здесь условные — подставьте свои из конфигуратора.

Как передать полученный макет на клиент

Клиенту нужен не файл на сервере, а данные. Способ передачи зависит от типа макета.

Двоичные данные — через временное хранилище

Сервер кладёт данные во временное хранилище и возвращает адрес. Клиент по адресу сохраняет файл у себя.

&НаСервере
Функция АдресШаблонаНаСервере()
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    ДД = ОбработкаОбъект.ПолучитьМакет("ШаблонЗагрузки");
    Возврат ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура СкачатьШаблон(Команда)
    Адрес = АдресШаблонаНаСервере();
    ПолучитьФайлССервераАсинх(Адрес, "Шаблон загрузки.xlsx");
КонецПроцедуры

Второй параметр ПоместитьВоВременноеХранилище — УникальныйИдентификатор формы. Данные живут, пока открыта форма, и не висят в памяти до конца сеанса.

Асинхронный метод ПолучитьФайлССервераАсинх есть на платформе с номером не ниже 8.3.18. В типовых конфигурациях на БСП удобнее вызвать ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "Шаблон загрузки.xlsx") — функция сама учитывает веб-клиент и настройки работы с файлами.

Табличный документ — значением из серверной функции

Табличный документ передаётся между клиентом и сервером напрямую. Сервер возвращает его, клиент показывает:

&НаСервереБезКонтекста
Функция ПечатнаяФормаНаСервере(Ссылка)
    Макет = Документы.СчетНаОплату.ПолучитьМакет("ПечатнаяФорма");
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Вывести(Макет.ПолучитьОбласть("Шапка"));
    Возврат ТабДок;
КонецФункции

&НаКлиенте
Процедура Печать(Команда)
    ПечатнаяФормаНаСервере(Объект.Ссылка).Показать("Счёт на оплату");
КонецПроцедуры

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

Сравнение способов передачи

СпособКогда подходитНа что смотреть
Возврат значения из серверной функцииТабличный документ, строка, небольшая структураВсё уходит одним вызовом, крупные данные тормозят форму
Временное хранилищеДвоичные данные, файлы любого размераПривязывайте к идентификатору формы, иначе память занята до конца сеанса
Реквизит формыТабличный документ, который пользователь редактируетРеквизит передаётся при каждом серверном вызове с контекстом
Файл на сервереОбмен с внешней программой на сервереПользователю такой файл недоступен

Производительность и обработка ошибок при получении макета

Не берите макет в цикле

Каждый вызов ПолучитьМакет читает макет из метаданных и создаёт копию. Для печати пакета из 300 документов вызывайте его один раз до цикла. То же с областями: ПолучитьОбласть("Строка") — один раз, а в цикле только заполняйте параметры и выводите.

Макет = Документы.СчетНаОплату.ПолучитьМакет("ПечатнаяФорма");
ОбластьСтроки = Макет.ПолучитьОбласть("Строка");

Для Каждого СтрокаТЧ Из Товары Цикл
    ОбластьСтроки.Параметры.Заполнить(СтрокаТЧ);
    ТабДок.Вывести(ОбластьСтроки);
КонецЦикла;

Осторожно с кешированием

Соблазн положить ПолучитьМакет в общий модуль с повторным использованием возвращаемых значений понятен. Но табличный документ — изменяемый объект. Первый же вызывающий код, который заполнит области в «кешированном» макете, испортит его для всех следующих. Кешируйте только неизменяемые вещи: строку из текстового макета, фиксированную структуру настроек.

Проверка, что макет существует

Если имя макета приходит параметром, проверьте его по метаданным до вызова:

Если Метаданные.Документы.СчетНаОплату.Макеты.Найти(ИмяМакета) = Неопределено Тогда
    ВызватьИсключение СтрШаблон("Макет %1 не найден в документе", ИмяМакета);
КонецЕсли;

Для общих макетов — Метаданные.ОбщиеМакеты.Найти(ИмяМакета).

Запись ошибок в журнал

Ошибку на сервере пользователь видит кратко, а разработчику нужны подробности. Пишите их в журнал регистрации:

Попытка
    ДД = ПолучитьОбщийМакет(ИмяМакета);
Исключение
    ЗаписьЖурналаРегистрации("Макеты.Получение", УровеньЖурналаРегистрации.Ошибка,,,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    ВызватьИсключение;
КонецПопытки;

Журнал открывается в режиме 1С:Предприятие через Администрирование → Обслуживание → Журнал регистрации. Фильтруйте по событию «Макеты.Получение».

Крупные двоичные макеты

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

Частые вопросы о макетах на сервере

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

Можно ли получить макет внешней обработки без открытия её формы?
Да. На сервере создайте объект обработки через ВнешниеОбработки.Создать и вызовите у него ПолучитьМакет. В режиме с профилями безопасности для этого нужны соответствующие разрешения.
Почему ПолучитьОбщийМакет не работает в веб-клиенте?
Веб-клиент, как и тонкий, не имеет доступа к метаданным конфигурации. Вызывайте функцию в серверной процедуре и передавайте результат на клиент.
Можно ли изменить макет конфигурации из кода?
Нет. Изменения в полученной копии в конфигурацию не сохраняются. Для пользовательских правок в типовых конфигурациях есть механизм макетов печатных форм БСП, который хранит изменённые варианты в базе.
Нужно ли удалять временное хранилище вручную?
Если хранилище привязано к идентификатору формы, данные удалятся при закрытии формы. Без привязки они живут до конца сеанса; освободить память раньше можно методом УдалитьИзВременногоХранилища.
Чем ПолучитьМакет у менеджера отличается от вызова у объекта?
Результат одинаковый. Менеджер удобен в серверном общем модуле и в &НаСервереБезКонтекста, объект — в формах внешних обработок, где менеджера нет.