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