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