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