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