Как в СКД сделать фильтр-переключатель с вариантами "Заполнено", "Не заполнено", "Все"?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов на Системе компоновки данных (СКД) часто возникает задача создать для пользователя удобный фильтр с несколькими предопределенными состояниями. Классический пример — фильтрация по наличию или отсутствию каких-либо данных, например, электронной почты у контрагента. Пользователю нужны три опции: показать только тех, у кого почта заполнена, только тех, у кого не заполнена, и показать всех. Давайте разберем, как реализовать такой переключатель в отчете на СКД, и проанализируем типичную ошибку, которая возникает при попытке решить эту задачу "в лоб".

Основная проблема, с которой сталкиваются разработчики, заключается в правильном формировании условия в секции ГДЕ текста запроса. Попытка использовать конструкцию ВЫБОР ... КОНЕЦ может привести к ошибке несоответствия типов, если не учесть, что все ветви этого оператора в данном контексте должны возвращать логическое значение (Истина/Ложь).

Рассмотрим два надежных способа реализации такого фильтра.

Способ 1. Корректное использование конструкции ВЫБОР в запросе СКД

Это самый простой и декларативный способ, который не требует написания кода в форме отчета. Вся логика реализуется непосредственно в тексте запроса набора данных СКД.

Шаг 1. Создание параметра

Сначала в настройках отчета на вкладке "Параметры" создадим новый параметр, например, с именем ОтборПоПочте.

  1. Зададим ему тип Строка.
  2. В свойстве "Доступные значения" укажем список строк, которые будут отображаться пользователю: "Все", "Заполнено", "Не заполнено". Можно также указать представление, если нужно, чтобы в коде использовались одни значения, а пользователь видел другие.
  3. В свойстве "Выражение" для списка доступных значений можно указать первое значение по умолчанию, например, "Все".
  4. Важно установить флажок "Включать в пользовательские настройки", чтобы параметр отображался на форме отчета. Для удобства можно задать вид элемента формы "Переключатель".

Шаг 2. Написание запроса с ошибкой (для понимания)

Проанализируем типичную ошибку. Разработчик пытается построить условие так:


ГДЕ
    ВЫБОР
        КОГДА &ОтборПоПочте = "Не заполнено"
            ТОГДА КонтактнаяИнформация.Представление ЕСТЬ NULL
        КОГДА &ОтборПоПочте = "Заполнено"
            ТОГДА КонтактнаяИнформация.Представление ЕСТЬ НЕ NULL
        ИНАЧЕ КонтактнаяИнформация.Представление // Вот здесь ошибка!
    КОНЕЦ

Почему этот код не работает? Секция ГДЕ ожидает на выходе логическое значение. Первые две ветки КОГДА его и возвращают: результат операции ЕСТЬ NULL — это Истина или Ложь. А вот ветка ИНАЧЕ пытается вернуть само значение поля КонтактнаяИнформация.Представление, которое является строкой. Система не может сравнить логическое значение с текстовой строкой, что и приводит к ошибке "Несоответствие типов".

Шаг 3. Правильная реализация запроса

Чтобы исправить ситуацию, нам нужно, чтобы ветка ИНАЧЕ (которая соответствует значению параметра "Все") также возвращала логическое значение. Для этого достаточно вернуть ИСТИНА. Это будет означать, что если пользователь выбрал "Все", то для любой записи условие фильтрации считается выполненным, и запись попадает в отчет.

Корректный код запроса будет выглядеть так:


ВЫБРАТЬ
    Контрагенты.Ссылка,
    КонтактнаяИнформация.Представление КАК АдресЭП
ИЗ
    Справочник.Контрагенты КАК Контрагенты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
        ПО Контрагенты.Ссылка = КонтактнаяИнформация.Объект
            И (КонтактнаяИнформация.Вид = &ВидКИЭлектроннаяПочта)
ГДЕ
    ВЫБОР
        КОГДА &ОтборПоПочте = "Не заполнено"
            ТОГДА КонтактнаяИнформация.Представление ЕСТЬ NULL
        КОГДА &ОтборПоПочте = "Заполнено"
            ТОГДА КонтактнаяИнформация.Представление ЕСТЬ НЕ NULL
        ИНАЧЕ ИСТИНА
    КОНЕЦ

В этом варианте все ветви конструкции ВЫБОР возвращают булево значение, и СКД корректно обрабатывает запрос. Этот метод является предпочтительным для простых случаев, так как он нагляден и не требует дополнительного программирования.

Способ 2. Программное управление отбором в модуле формы отчета

Этот способ более гибкий и подходит для сложных отчетов, где логика фильтрации может зависеть от нескольких параметров. Суть заключается в том, чтобы не "зашивать" условие в запрос, а динамически управлять коллекцией отборов компоновщика настроек. Для реализации удобного интерфейса связки элементов формы с СКД можно использовать методику стыковки элементов управляемой формы и пользовательских настроек СКД.

Шаг 1. Настройка формы отчета

  1. Откройте основную форму отчета. Если используется типовая форма, может потребоваться ее скопировать и назначить отчету.
  2. Добавьте на форму новый реквизит, например, РежимОтбораПоПочте с типом Строка.
  3. В свойствах реквизита задайте список выбора со значениями "Все", "Заполнено", "Не заполнено".
  4. Разместите этот реквизит на форме как элемент управления, например, "Поле с переключателем".
  5. Для созданного элемента формы создайте обработчик события ПриИзменении.

Шаг 2. Написание кода в модуле формы

Вся работа будет происходить в обработчике события, который мы создали. Логика следующая: при каждом изменении значения переключателя мы будем очищать старые отборы по полю с адресом почты и, при необходимости, добавлять новый.


&НаКлиенте
Процедура РежимОтбораПоПочтеПриИзменении(Элемент)
    УстановитьОтборПоПочтеНаСервере(РежимОтбораПоПочте);
КонецПроцедуры

&НаСервере
Процедура УстановитьОтборПоПочтеНаСервере(ВыбранныйРежим)

    // Получаем компоновщик настроек отчета
    // Имя "Отчет" может отличаться в вашей конфигурации
    КомпоновщикНастроек = Отчет.КомпоновщикНастроек;

    // Сначала удалим все предыдущие отборы, установленные по этому полю,
    // чтобы избежать их дублирования.
    // Итерируем с конца, так как удаляем элементы из коллекции.
    Для i = КомпоновщикНастроек.Настройки.Отбор.Элементы.Количество() - 1 По 0 Цикл
        ЭлементОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы[i];

        // Проверяем, что это элемент отбора и что он установлен на наше поле
        Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных")
           И ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("АдресЭП") Тогда
            КомпоновщикНастроек.Настройки.Отбор.Элементы.Удалить(ЭлементОтбора);
        КонецЕсли;
    КонецЦикла;

    // Если выбран режим "Все", то ничего добавлять не нужно.
    // Если "Заполнено" или "Не заполнено", создаем и настраиваем новый элемент отбора.
    Если ВыбранныйРежим = "Заполнено" ИЛИ ВыбранныйРежим = "Не заполнено" Тогда
        НовыйОтбор = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        
        // Указываем поле, по которому будем фильтровать.
        // Имя поля должно совпадать с псевдонимом в запросе СКД.
        НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("АдресЭП");
        
        // Включаем использование отбора
        НовыйОтбор.Использование = Истина;
        
        // Правое значение не указываем, так как виды сравнения "Заполнено" и "НеЗаполнено"
        // не требуют второго операнда.
        
        // Устанавливаем вид сравнения в зависимости от выбора пользователя
        Если ВыбранныйРежим = "Заполнено" Тогда
            НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Заполнено;
        ИначеЕсли ВыбранныйРежим = "Не заполнено" Тогда
            НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.НеЗаполнено;
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

Важный момент: при использовании этого способа поле АдресЭП должно быть доступно для отбора в настройках СКД на вкладке "Настройки". Также убедитесь, что в тексте запроса нет жестко прописанного условия, которое мы разбирали в первом способе, иначе фильтры будут конфликтовать.

Таким образом, мы рассмотрели два эффективных подхода. Первый способ (через запрос) идеален для простых и быстрых реализаций. Второй (программный) предоставляет полный контроль над настройками отчета и незаменим в сложных сценариях, где фильтры зависят друг от друга или требуют нетривиальной логики.

← На главную