Макет в клиентском коде 1С 8.3: серверный вызов, временное хранилище и кэш

· 10 мин

Содержание

В тонком и веб-клиенте 1С 8.3 макет напрямую на клиенте не получить: метод ПолучитьМакет() и глобальный ПолучитьОбщийМакет() работают на сервере. Рабочая схема одна: серверная функция получает макет и возвращает его на клиент. Табличный или текстовый документ можно вернуть прямо как значение. Двоичные данные — значением или через временное хранилище, если файл крупный или его нужно сохранить на диск пользователя.

Какой способ выбрать, зависит от типа макета и от того, что вы с ним делаете дальше. Для печатной формы хватает серверного вызова без контекста. Для шаблона Word или Excel, который пользователь скачивает, удобнее временное хранилище. Для внешней обработки нужен серверный вызов с контекстом формы.

ЗадачаСпособГде выполняется
Заполнить и показать табличный документФункция &НаСервереБезКонтекста возвращает ТабличныйДокументСервер → клиент
Отдать пользователю файл-шаблон (docx, xlsx)Двоичные данные → ПоместитьВоВременноеХранилище → адрес на клиентСервер → хранилище → клиент
Макет внешней обработки или отчёта&НаСервере + РеквизитФормыВЗначение("Объект")Сервер, с контекстом формы
Многократный вывод без лишних вызововПолучить один раз и кэшировать в клиентской переменной формыКлиент
Обычное приложение, толстый клиентПрямой вызов ПолучитьМакет() из модуля объектаКлиент (только толстый)
Какой у вас случай?

Почему ПолучитьМакет() не вызывается на клиенте

Макет — часть метаданных конфигурации. Доступ к нему дают менеджеры (Документы.ИмяДокумента, Обработки.ИмяОбработки) и объекты прикладных типов. В управляемом приложении менеджеры на клиенте урезаны: ссылки и ПустаяСсылка() доступны, а ПолучитьМакет() — нет.

Если написать такой код в процедуре с директивой &НаКлиенте, тонкий клиент упадёт при выполнении с ошибкой вида Метод объекта не обнаружен (ПолучитьМакет). То же с ПолучитьОбщийМакет() для общих макетов.

Что при этом доступно на клиенте:

  • ✅ сам объект ТабличныйДокумент и его методы ПолучитьОбласть(), Вывести(), Присоединить();
  • ✅ параметры областей: Область.Параметры.ИмяПараметра = Значение;
  • ✅ ПолучитьИзВременногоХранилища(Адрес) — чтобы забрать то, что положил сервер;
  • ❌ получение макета из метаданных: только сервер.

Отсюда простой вывод: сервер «достаёт» макет, клиент с ним работает. Вся инструкция ниже — вариации этой схемы.

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

Как получить макет на клиенте через серверную функцию

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

Шаг 1. Серверная функция без контекста

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

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

Шаг 2. Вызов и вывод на клиенте

&НаКлиенте
Процедура Сформировать(Команда)
	
	Макет = МакетСчета();
	
	ТабДок = Новый ТабличныйДокумент;
	
	ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
	ОбластьШапка.Параметры.НомерДокумента = НомерСчета;
	ОбластьШапка.Параметры.ДатаДокумента  = Формат(ДатаСчета, "ДЛФ=D");
	ТабДок.Вывести(ОбластьШапка);
	
	ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
	Для Каждого СтрокаТЧ Из Объект.Товары Цикл
		ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаТЧ);
		ТабДок.Вывести(ОбластьСтрока);
	КонецЦикла;
	
	ТабДок.Показать("Счёт на оплату");
	
КонецПроцедуры

Имена Шапка, Строка и параметры — это имена областей и параметров в вашем макете. Откройте макет в конфигураторе и сверьте их через свойства ячеек и областей.

Шаг 3. Решить, где заполнять

Заполнять области можно и на сервере, и на клиенте. Правило простое:

  • 📦 нужны данные из базы (остатки, реквизиты контрагента, запрос) — заполняйте на сервере и возвращайте готовый документ;
  • 🖥 все данные уже в форме — можно заполнять на клиенте, сервер нужен только для самого макета.

Заполнение на сервере почти всегда быстрее: один вызов вместо цепочки «получить макет → вернуться на сервер за данными».

Двоичные данные, временное хранилище и выгрузка макета в файл

Макеты типа «Двоичные данные» обычно хранят шаблоны Word и Excel, картинки, XML-заготовки. Их тоже можно вернуть значением, но для файлов удобнее временное хранилище: клиент получает строку-адрес, а файл забирает, когда нужно.

Положить макет во временное хранилище

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

Второй параметр — УникальныйИдентификатор формы. Данные живут, пока открыта форма, и не копятся в памяти сеанса. Поэтому функция с контекстом (&НаСервере): уникальный идентификатор — свойство формы.

Забрать на клиенте

&НаКлиенте
Процедура ОткрытьШаблон(Команда)
	Адрес = АдресШаблонаДоговора();
	ДвДанные = ПолучитьИзВременногоХранилища(Адрес);
	// дальше — сохранить файл пользователю
КонецПроцедуры

Для сохранения на диск в современных конфигурациях на БСП есть ФайловаяСистемаКлиент.СохранитьФайл(): процедура принимает описание оповещения, адрес во временном хранилище и имя файла. Она сама выбирает асинхронный вариант для веб-клиента. Без БСП используйте асинхронные методы платформы для получения файлов с сервера.

Выгрузить макет в файл вручную

Иногда макет нужен не в коде, а у вас на диске: отправить коллеге, поправить в Excel, сравнить версии.

  1. Откройте конфигуратор, найдите объект в дереве метаданных, раскройте ветку Макеты.
  2. Откройте макет двойным щелчком.
  3. В меню Файл выберите сохранение в файл и укажите формат: для табличного документа — .mxl, для двоичных данных — исходное расширение.

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

Программно табличный документ выгружают на сервере методом ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.MXL). Затем его можно прочитать в ДвоичныеДанные и передать клиенту той же схемой через хранилище.

Макеты в управляемых формах и БСП: что учесть

Макеты, изменённые пользователем

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

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

Не храните тяжёлые макеты в реквизитах формы

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

Что помогает:

  • 🔹 вызовы без контекста везде, где не нужны реквизиты формы;
  • 🔹 сам макет — в клиентской переменной модуля формы, а не в реквизите;
  • 🔹 в реквизит кладите только результат, который пользователь видит.

Кэш макета на клиенте

&НаКлиенте
Перем КэшМакета;

&НаКлиенте
Функция МакетЭтикетки()
	Если КэшМакета = Неопределено Тогда
		КэшМакета = ПолучитьМакетЭтикеткиНаСервере();
	КонецЕсли;
	Возврат КэшМакета;
КонецФункции

&НаСервереБезКонтекста
Функция ПолучитьМакетЭтикеткиНаСервере()
	Возврат Обработки.ПечатьЭтикеток.ПолучитьМакет("Этикетка");
КонецФункции

Переменная живёт, пока открыта форма. Сто этикеток подряд — один вызов сервера вместо ста.

Получение макетов из внешних обработок и отчётов

У внешней обработки нет менеджера в дереве метаданных, поэтому Обработки.Имя.ПолучитьМакет() не подходит. Макет берут у объекта обработки.

Из формы самой внешней обработки

&НаСервере
Функция МакетОбработки()
	ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
	Возврат ОбработкаОбъект.ПолучитьМакет("ПечатнаяФорма");
КонецФункции

РеквизитФормыВЗначение() работает только с контекстом формы. С директивой &НаСервереБезКонтекста функция не скомпилируется.

Из модуля объекта обработки

Если печать вызывается из модуля объекта (так устроены внешние печатные формы для БСП), макет доступен прямо: ЭтотОбъект.ПолучитьМакет("ПечатнаяФорма") или просто ПолучитьМакет("ПечатнаяФорма"). Модуль объекта выполняется на сервере, ограничений клиента там нет.

Обработка из файла, которая не зарегистрирована в базе

  1. На клиенте пользователь выбирает файл .epf, файл помещается во временное хранилище.
  2. На сервере обработка подключается методом ВнешниеОбработки.Подключить(Адрес, , БезопасныйРежим), который возвращает её имя.
  3. Объект создаётся через ВнешниеОбработки.Создать(Имя), и у него вызывается ПолучитьМакет().
  4. Готовый макет или заполненный документ возвращается на клиент.

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

Для внешнего отчёта всё так же, только менеджер — ВнешниеОтчеты. Если макет — схема компоновки данных, её обычно не таскают на клиент: отчёт формируется на сервере, клиент получает результат.

Различия в толстом, тонком и веб-клиенте

КлиентПолучить макет на клиентеСохранить файл на дискЧто учесть
Толстый, обычное приложениеДа, ПолучитьМакет() из модуля объекта или формыСинхронные методы работаютКод непереносим в тонкий клиент
Толстый, управляемое приложениеТехнически возможно, но не опирайтесьДаПишите как для тонкого клиента
Тонкий клиентТолько через серверДа, лучше асинхронноСледите за объёмом передачи
Веб-клиентТолько через серверАсинхронные методы; доступ к файлам может требовать расширения работы с файламиСинхронные вызовы могут быть запрещены настройками конфигурации

В веб-клиенте чаще всего ломается не получение макета, а сохранение файла. Если конфигурация запрещает синхронные вызовы расширений платформы, старые ПолучитьФайл() и запись ДвоичныеДанные.Записать() на клиенте выдадут ошибку. Переходите на асинхронные методы или на ФайловаяСистемаКлиент из БСП.

Проверяйте код сразу в тонком клиенте. Режим запуска из конфигуратора задают в Сервис → Параметры → Запуск 1С:Предприятия. Ошибка с методом на клиенте всплывёт в первом же тесте, а не у пользователя.

Пример: динамическая модификация макета на клиенте

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

Макет Ценник содержит области:

  • Заголовок — наименование и артикул;
  • СтараяЦена — зачёркнутая цена;
  • Цена — актуальная цена;
  • Штрихкод — строка с кодом.

Макет получаем один раз (кэш из раздела выше), дальше собираем документ на клиенте:

&НаКлиенте
Процедура ОбновитьПредпросмотр()
	
	Макет = МакетЦенника();
	Результат = Новый ТабличныйДокумент;
	
	Для Каждого Строка Из Товары Цикл
		
		Область = Макет.ПолучитьОбласть("Заголовок");
		Область.Параметры.Наименование = Строка.Наименование;
		Область.Параметры.Артикул      = Строка.Артикул;
		Результат.Вывести(Область);
		
		Если ПоказыватьСтаруюЦену И Строка.СтараяЦена > Строка.Цена Тогда
			Область = Макет.ПолучитьОбласть("СтараяЦена");
			Область.Параметры.СтараяЦена = Формат(Строка.СтараяЦена, "ЧДЦ=2");
			Результат.Вывести(Область);
		КонецЕсли;
		
		Область = Макет.ПолучитьОбласть("Цена");
		Область.Параметры.Цена = Формат(Строка.Цена, "ЧДЦ=2");
		Результат.Вывести(Область);
		
		Если ПоказыватьШтрихкод Тогда
			Область = Макет.ПолучитьОбласть("Штрихкод");
			Область.Параметры.Штрихкод = Строка.Штрихкод;
			Результат.Вывести(Область);
		КонецЕсли;
		
	КонецЦикла;
	
	Предпросмотр = Результат;
	
КонецПроцедуры

&НаКлиенте
Процедура ПоказыватьШтрихкодПриИзменении(Элемент)
	ОбновитьПредпросмотр();
КонецПроцедуры

Здесь Товары — таблица значений формы, Предпросмотр — реквизит типа ТабличныйДокумент, связанный с полем на форме. Флажки ПоказыватьСтаруюЦену и ПоказыватьШтрихкод — булевы реквизиты.

Что даёт такой подход:

  1. Сервер вызывается один раз — при первом формировании.
  2. Переключение флажков перестраивает документ мгновенно, даже на медленном канале.
  3. Логика вывода остаётся в одном месте, её легко дополнить новой областью.

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

Типичные ошибки при получении макета

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

Частые вопросы

Можно ли вернуть с сервера на клиент любой макет?
Табличный документ, текстовый документ и двоичные данные передаются без проблем. Схему компоновки данных на клиент обычно не передают: отчёт формируют на сервере и возвращают результат.
Чем ПолучитьМакет отличается от ПолучитьОбщийМакет?
ПолучитьМакет() возвращает макет конкретного объекта: документа, обработки, отчёта. ПолучитьОбщийМакет() — макет из ветки Общие → Общие макеты. Оба работают на сервере.
Нужно ли удалять данные из временного хранилища?
Если при помещении указан уникальный идентификатор формы, данные удалятся при её закрытии. Если форма живёт долго, а файлов много, освобождайте память вручную методом УдалитьИзВременногоХранилища(Адрес).
Можно ли менять оформление ячеек на клиенте?
Да. Шрифт, цвет фона и рамки области меняются через её свойства и на клиенте. Это удобно для подсветки строк в предпросмотре без обращения к серверу.
Как получить макет внешней печатной формы, подключённой через БСП?
Такая форма печатает из модуля объекта обработки, который выполняется на сервере. Там макет берут вызовом ПолучитьМакет("ИмяМакета") без дополнительных серверных функций.