При разработке отчетов на платформе 1С:Предприятие 8.3 часто возникает задача динамической подмены схемы компоновки данных (СКД) в зависимости от выбранного пользователем режима работы или параметров формы. Попытка сделать это «в лоб» через свойство СхемаКомпоновкиДанных объекта отчета в событии формы ПриСозданииНаСервере обычно приводит к ошибке «Не установлена схема компоновки данных» при первой же попытке сформировать отчет.
В этой статье мы подробно разберем причины этой ошибки, выясним, как устроена работа со схемами компоновки на управляемых формах, и рассмотрим три надежных практических решения этой задачи.
Рассмотрим, что происходит в коде, когда мы пытаемся присвоить схему напрямую в модуле формы:
ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
СхемаКомпоновкиДанных = ОтчетОбъект.ПолучитьМакет("ГрафикВыставленияАктов");
ОтчетОбъект.СхемаКомпоновкиДанных = СхемаКомпоновкиДанных;
ЗначениеВРеквизитФормы(ОтчетОбъект, "Отчет");
Этот код успешно выполнится в рамках процедуры ПриСозданииНаСервере, но при нажатии кнопки «Сформировать» произойдет аварийное завершение работы отчета. Дело в том, что реквизит формы Отчет (имеющий тип ОтчетОбъект) хранит настройки, структуру и параметры компоновщика, но не хранит саму схему компоновки данных на клиенте из-за её потенциально большого объема. Схема компоновки — это тяжелый объект метаданных.
При каждом новом серверном вызове платформа заново создает экземпляр ОтчетОбъект на основе данных формы и дефолтных метаданных конфигурации. Так как в метаданных отчета наша динамическая схема не назначена основной, программно установленная ранее схема просто стирается и заменяется на Неопределено.
Для решения этой проблемы мы можем использовать один из трех подходов, описанных ниже.
---
Если нам необходимо переопределить настройки схемы непосредственно при создании формы, чтобы пользователь сразу увидел актуальные доступные поля, отборы и группировки, мы должны использовать Временное Хранилище (ВХ).
Критически важный нюанс: в конструктор объекта ИсточникДоступныхНастроекКомпоновкиДанных нельзя передавать саму схему как объект. Ему необходимо передавать строковый адрес временного хранилища, в котором эта схема находится. В противном случае на клиенте список доступных настроек окажется пустым.
Разберем по шагам правильную реализацию в модуле управляемой формы отчета:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// 1. Получаем нужный макет схемы компоновки из объекта
ТекущийОтчетОбъект = РеквизитФормыВЗначение("Отчет");
СхемаКД = ТекущийОтчетОбъект.ПолучитьМакет("ГрафикВыставленияАктов");
// 2. Помещаем схему во временное хранилище с привязкой к УникальномуИдентификатору формы
АдресСхемыВоВХ = ПоместитьВоВременноеХранилище(СхемаКД, УникальныйИдентификатор);
// 3. Инициализируем источник настроек строго по СТРОКОВОМУ АДРЕСУ в ВХ
ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемыВоВХ);
// 4. Инициализируем компоновщик настроек формы новым источником
Отчет.КомпоновщикНастроек.Инициализировать(ИсточникНастроек);
// 5. Загружаем настройки по умолчанию из новой схемы
Отчет.КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКД.НастройкиПоУмолчанию);
КонецПроцедуры
Этот способ решает проблему интерфейса формы, однако при самом формировании отчета платформа все равно обратится к основной схеме из метаданных. Поэтому данный способ рекомендуется комбинировать со вторым решением.
---
Самый надежный и независимый от используемой конфигурации способ — переопределить стандартный вывод отчета в модуле его объекта. Платформа предоставляет для этого предопределенное событие ПриКомпоновкеРезультата.
Для реализации этого метода создадим в реквизитах нашего отчета строковый реквизит ИмяТекущейСхемы. Будем заполнять его на форме при открытии, а в модуле объекта анализировать это значение.
Проанализируем пример кода в Модуле объекта отчета:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартный механизм формирования отчета платформой
СтандартнаяОбработка = Ложь;
// Выбираем схему в зависимости от заполненного реквизита объекта
Если ИмяТекущейСхемы = "ГрафикВыставленияАктов" Тогда
СхемаКД = ПолучитьМакет("GraphicVystavleniyaAktov");
Иначе
СхемаКД = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
КонецЕсли;
// Выполняем ручную компоновку макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКД, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
// Инициализируем процессор компоновки данных
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
// Очищаем результирующий табличный документ и выводим в него данные
ДокументРезультат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Этот подход гарантирует стабильный результат на любых конфигурациях, так как мы полностью берем управление процессом построения отчета в свои руки.
---
Если вы работаете в типовой конфигурации, построенной на базе Библиотеки Стандартных Подсистем (БСП), ручное переопределение процедуры ПриКомпоновкеРезультата может нарушить работу стандартных механизмов: сохранение пользовательских вариантов отчетов, рассылку отчетов, печать и отправку по почте.
Для корректного решения нашей задачи в БСП предусмотрен специальный программный интерфейс. Мы можем использовать предопределенную процедуру ПередЗагрузкойНастроекВКомпоновщик в модуле объекта отчета и встроенную функцию БСП ОтчетыСервер.ПодключитьСхему.
Рассмотрим пример правильной интеграции в Модуле объекта отчета:
#Область ПрограммныйИнтерфейсБСП
// Вызывается подсистемой "Варианты отчетов" БСП перед загрузкой настроек в компоновщик.
Процедура ПередЗагрузкойНастроекВКомпоновщик(Контекст, КлючСхемы, КлючВарианта, НовыеНастройкиКД, НовыеПользовательскиеНастройкиКД) Экспорт
// Проверяем, что выбран интересующий нас вариант отчета, и схема еще не подменена
Если КлючВарианта = "ВариантГрафикАктов" И КлючСхемы <> "ГрафикВыставленияАктов" Тогда
КлючСхемы = "ГрафикВыставленияАктов";
НоваяСхема = ПолучитьМакет("ГрафикВыставленияАктов");
// Метод БСП автоматически зарегистрирует схему в контексте выполнения,
// обновит компоновщик и синхронизирует его с формой отчета.
ОтчетыСервер.ПодключитьСхему(ЭтотОбъект, Контекст, НоваяСхема, КлючСхемы);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
При использовании этого метода БСП самостоятельно берет на себя все заботы по передаче схемы через временные хранилища и обеспечивает корректную работу всех сервисных функций отчетов в типовых конфигурациях.