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