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