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