Макет конфигурации в серверном коде: от ПолучитьМакет до файла у пользователя
Содержание
Макет на сервере 1С получают методом ПолучитьМакет("ИмяМакета") у менеджера объекта (Обработки.ЗагрузкаПрайса.ПолучитьМакет("Шаблон")) или у самого объекта, а общий макет — функцией глобального контекста ПолучитьОбщийМакет("ИмяМакета"). Вызов делают в процедуре с директивой &НаСервере или &НаСервереБезКонтекста, в общем модуле с флагом «Сервер» или в модуле менеджера.
На тонком клиенте и в веб-клиенте эти методы недоступны. Поэтому типовая схема такая: сервер получает макет, при необходимости превращает его в файл или табличный документ и отдаёт клиенту результат. Тема общая для платформы 8.3 и не зависит от конфигурации.
Почему макет живёт только на сервере
Макеты — часть метаданных конфигурации. В клиент-серверном варианте конфигурация хранится в базе, а работает с ней рабочий процесс кластера. Тонкий клиент получает только формы и то, что ему явно передали.
Отсюда три следствия, которые полезно держать в голове:
- 🖥️ Где вызывать. Всё, что начинается с
ПолучитьМакет, работает в серверном контексте и в толстом клиенте. В модуле управляемой формы на клиенте этого метода нет. - 📦 Что передавать. Сам макет «по ссылке» на клиент не уходит. Уходит копия значения: табличный документ, строка, адрес во временном хранилище.
- 🗂️ Чья файловая система. Если сервер записывает макет в файл, файл появляется на машине с рабочим процессом, а не на компьютере бухгалтера.
В файловом варианте «сервер» — это тот же процесс на компьютере пользователя. Поэтому код, который пишет макет в C:\Temp и открывает его, в файловой базе работает, а после перехода на клиент-сервер ломается. Тестируйте серверную логику на клиент-серверной копии.
Где лежит макет и каким методом его брать
| Где лежит макет | Как получить на сервере |
|---|---|
| Общие → Общие макеты | ПолучитьОбщийМакет("ИмяМакета") |
| Макет документа, справочника, отчёта | Документы.ИмяДокумента.ПолучитьМакет("ИмяМакета") |
| Макет обработки из конфигурации | Обработки.ИмяОбработки.ПолучитьМакет("ИмяМакета") |
| Макет внешней обработки или отчёта | РеквизитФормыВЗначение("Объект").ПолучитьМакет("ИмяМакета") |
| Макет с учётом правок пользователя (типовые на БСП) | УправлениеПечатью.МакетПечатнойФормы("Документ.Имя.ИмяМакета") |
Две последние строки — то, на чём чаще всего спотыкаются.
Внешняя обработка. Её нет в коллекции Обработки, обратиться к менеджеру по имени нельзя. Поэтому в форме внешней обработки объект достают из реквизита формы: РеквизитФормыВЗначение("Объект"). Это работает только в процедуре &НаСервере — с контекстом формы.
Изменённые печатные формы. В типовых конфигурациях пользователь может поправить макет в режиме 1С:Предприятие: Администрирование → Печатные формы, отчеты и обработки → Макеты печатных форм. Прямой ПолучитьМакет вернёт исходный макет из конфигурации и правки проигнорирует. Функция БСП УправлениеПечатью.МакетПечатнойФормы сначала ищет пользовательский вариант.
Как получить макет в двоичные данные: порядок действий
Макет типа «Двоичные данные» — это любой файл, вшитый в конфигурацию: шаблон Word или Excel, zip-архив, картинка, внешняя компонента, XSD-схема. В конфигураторе его создают как макет с типом «Двоичные данные» и загружают из файла.
На сервере его получают так:
- Убедитесь, что процедура выполняется на сервере: директива
&НаСерверев форме или серверный общий модуль. - Возьмите макет у менеджера объекта или через
ПолучитьОбщийМакет. - Проверьте тип результата, если код универсальный.
- Работайте с данными: читайте поток, пишите во временный файл или кладите во временное хранилище.
&НаСервереБезКонтекста
Функция ШаблонДоговора()
ДД = Документы.ДоговорАренды.ПолучитьМакет("Шаблон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С:Предприятие через Администрирование → Обслуживание → Журнал регистрации. Фильтруйте по событию «Макеты.Получение».
Крупные двоичные макеты
Макет на десятки мегабайт увеличивает размер конфигурации и время её загрузки при обновлении. Каждая передача на клиент гонит эти мегабайты по сети. Большие шаблоны и дистрибутивы лучше хранить в присоединённых файлах или в отдельном справочнике, а в макетах оставить то, что действительно является частью конфигурации. Ориентир простой: если файл меняется чаще, чем выходит релиз вашей конфигурации, ему не место в макете.
Частые вопросы о макетах на сервере
Эти вопросы обычно возникают, когда базовая схема уже заработала: внешние обработки без формы, веб-клиент, правка макетов и очистка памяти.
Можно ли получить макет внешней обработки без открытия её формы?
ВнешниеОбработки.Создать и вызовите у него ПолучитьМакет. В режиме с профилями безопасности для этого нужны соответствующие разрешения.Почему ПолучитьОбщийМакет не работает в веб-клиенте?
Можно ли изменить макет конфигурации из кода?
Нужно ли удалять временное хранилище вручную?
УдалитьИзВременногоХранилища.Чем ПолучитьМакет у менеджера отличается от вызова у объекта?
&НаСервереБезКонтекста, объект — в формах внешних обработок, где менеджера нет.