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