Как программно изменить схему компоновки данных (СКД) в отчете 1С с обновлением настроек?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Создание отдельных отчетов для каждой схемы — путь наименьшего сопротивления, но он приводит к лавинообразному увеличению количества объектов в конфигурации и усложняет дальнейшую поддержку. Гораздо изящнее реализовать динамическую смену схем внутри одного отчета. Разберем, с какими трудностями сталкиваются разработчики при решении этой задачи, почему «ломаются» настройки интерфейса и как правильно реализовать переключение схем для обычных и управляемых форм, а также в рамках интеграции с Библиотекой стандартных подсистем (БСП).

В чем суть проблемы и почему «ломается» компоновщик?

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

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

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

Проанализируем детально правильный порядок действий для решения этой задачи в различных окружениях.

---

Решение для обычных форм (толстый клиент)

В обычных формах схема компоновки данных доступна непосредственно в клиентском контексте. Это значительно упрощает работу, так как мы можем напрямую инициализировать компоновщик новым источником доступных настроек, созданным на основании полученного макета.

Рассмотрим по шагам правильный алгоритм программной смены схемы:

  1. Запрашиваем у пользователя выбор нужного макета схемы из списка.
  2. Получаем объект выбранного макета схемы.
  3. Создаем новый объект ИсточникДоступныхНастроекКомпоновкиДанных, передавая в него нашу новую схему.
  4. Инициализируем КомпоновщикНастроек формы этим источником.
  5. Загружаем настройки по умолчанию новой схемы в компоновщик настроек.
  6. Выполняем стандартный вывод отчета в табличный документ, используя актуальные настройки из обновленного компоновщика.

Посмотрим на пример реализации данного алгоритма на встроенном языке:


Процедура СменаСхемыНажатие(Элемент)
    // Шаг 1. Формируем список доступных схем для выбора
    СписокСхем = Новый СписокЗначений;
    СписокСхем.Добавить("ОсновнаяСхемаКомпоновкиДанных", "Основная схема (Продажи)");
    СписокСхем.Добавить("ОсновнаяСхемаКомпоновкиДанных1", "Альтернативная схема (Остатки)");
    
    ВыбранныйЭлемент = СписокСхем.ВыбратьЭлемент("Выберите вариант отчета");
    Если ВыбранныйЭлемент = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 2. Получаем новую схему из макетов отчета
    НоваяСхема = ПолучитьМакет(ВыбранныйЭлемент.Значение);
    СхемаКомпоновкиДанных = НоваяСхема; // Переопределяем основную схему отчета
    
    // Шаг 3. Инициализируем компоновщик настроек новым источником доступных настроек.
    // Это ключевое действие, которое обновляет состав доступных полей, группировок и отборов на форме!
    НовыйИсточник = Новый ИсточникДоступныхНастроекКомпоновкиДанных(НоваяСхема);
    КомпоновщикНастроек.Инициализировать(НовыйИсточник);
    
    // Шаг 4. Загружаем настройки по умолчанию для вновь выбранной схемы
    КомпоновщикНастроек.ЗагрузитьНастройки(НоваяСхема.НастройкиПоУмолчанию);
    
    // Шаг 5. Получаем настройки для компоновки макета
    ТекущиеНастройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Шаг 6. Стандартный вывод отчета в результирующий табличный документ
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(НоваяСхема, ТекущиеНастройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    Результат = ЭлементыФормы.Результат;
    Результат.Очистить();
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры

---

Решение для управляемых форм (тонкий / веб-клиент)

В управляемом приложении архитектура взаимодействия клиента и сервера накладывает свои ограничения. Объект СхемаКомпоновкиДанных не существует на стороне клиента — он доступен только на сервере. Соответственно, мы не можем просто так передать саму схему в конструктор источника доступных настроек на клиенте.

Для управляемых форм единственным надежным и правильным механизмом является использование Временного хранилища. Источник доступных настроек компоновки данных на управляемой форме может инициализироваться не только объектом схемы, но и текстовым адресом во временном хранилище, где эта схема временно размещена на сервере.

Разберем по шагам, как выглядит этот процесс на управляемой форме:

  1. Пользователь инициирует смену схемы на клиенте (например, выбирая вариант из выпадающего списка или нажимая кнопку).
  2. Вызывается серверная процедура, в которой извлекается нужный макет схемы СКД из объекта отчета.
  3. Макет схемы помещается во временное хранилище. При этом важно связать адрес хранилища с уникальным идентификатором текущей формы, чтобы платформа автоматически очистила память после закрытия окна.
  4. Компоновщик настроек отчета инициализируется новым источником, в качестве параметра которого передается полученный адрес временного хранилища.
  5. Загружаются дефолтные настройки новой схемы.

Посмотрим, как выглядит пример кода для реализации этой схемы на управляемой форме:


&НаКлиенте
Процедура СменитьСхему(Команда)
    // Для примера жестко пропишем имя макета. В реальном отчете это может быть выбор пользователя.
    ИмяВыбраннойСхемы = "ОсновнаяСхемаКомпоновкиДанных1";
    УстановитьНовуюСхемуНаСервере(ИмяВыбраннойСхемы);
КонецПроцедуры

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

---

Особенности работы в типовых конфигурациях (БСП)

Если ваша разработка ведется внутри типовой конфигурации 1С (например, 1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей, 1С:Бухгалтерия предприятия), то ручная инициализация компоновщика настроек в обход стандартных механизмов может нарушить работу подсистемы «Варианты отчетов» Библиотеки стандартных подсистем (БСП).

В современных версиях БСП предусмотрен штатный механизм динамического переключения и подмены схем компоновки. Чтобы воспользоваться им, разработчику не нужно вручную помещать схемы во временное хранилище и переинициализировать компоновщик. Достаточно переопределить настройки формы в модуле объекта отчета.

Разберем, как это сделать программно в модуле объекта отчета:

  1. В модуле объекта отчета находим или создаем экспортную процедуру ОпределитьНастройкиФормы. В ней мы сообщаем системе, что хотим перехватить событие перед загрузкой настроек.
  2. Создаем экспортную процедуру-обработчик ПередЗагрузкойНастроекВКомпоновщик.
  3. Внутри обработчика, в зависимости от выбранного ключа варианта, получаем нужный макет схемы и подключаем его с помощью специализированного метода БСП ОтчетыСервер.ПодключитьСхему.

Проанализируем пример кода для модуля объекта отчета в БСП:


// Процедура определяет индивидуальные настройки формы отчета для БСП
Процедура ОпределитьНастройкиФормы(Форма, КлючВарианта, Настройки) Экспорт
    // Включаем признак перехвата события перед загрузкой настроек в компоновщик
    Настройки.События.ПередЗагрузкойНастроекВКомпоновщик = Истина;
КонецПроцедуры

// Обработчик события, выполняющийся на сервере перед загрузкой настроек в СКД
Процедура ПередЗагрузкойНастроекВКомпоновщик(Контекст, КлючСхемы, КлючВарианта, НовыеНастройкиКД, НовыеПользовательскиеНастройкиКД) Экспорт
    // Если пользователь выбрал вариант, соответствующий альтернативной схеме
    Если КлючВарианта = "ВариантОстаткиМатериалов" Тогда
        АльтернативнаяСхема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных1");
        
        // Используем штатный метод БСП для бесшовной подмены схемы.
        // БСП сама позаботится о временном хранилище и корректной переинициализации формы!
        ОтчетыСервер.ПодключитьСхему(ЭтотОбъект, Контекст, АльтернативнаяСхема, КлючСхемы);
        КлючСхемы = КлючВарианта;
    КонецЕсли;
КонецПроцедуры

---

Важный нюанс: Сохранение заполненных параметров пользователем

При использовании метода ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию) все ранее заполненные пользователем значения (например, выбранный период, организация, склад) полностью сбрасываются, заменяясь на дефолтные значения из новой схемы. Это крайне неудобно: пользователю приходится заново указывать параметры при каждом переключении схем.

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

Рассмотрим пример вспомогательного кода, который решает эту проблему:


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

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

← На главную