Как программно создать и настроить отбор в списке регистра сведений в 1С

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

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

В этой статье мы подробно разберем, почему возникает популярная ошибка «Метод не доступен для данного объекта» при работе с отборами, как правильно программировать фильтрацию данных для обычных и управляемых форм, а также рассмотрим лучшие практики разделения системных и пользовательских настроек.

Выясняем причину ошибки «Метод не доступен для данного объекта»

Давайте проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики. Пытаясь программно создать «новый» отбор в списке регистра сведений, они пишут следующий код:

РегистрСведенийСписок.Отбор.Добавить("ТипДоступныхЦен"); // Вызывает ошибку!

В этот момент система генерирует исключение. Почему это происходит? Дело в том, что объект Отбор в списках 1С жестко связан с метаданными самого регистра сведений. В коллекцию отборов невозможно «на лету» добавить произвольное несуществующее поле с вымышленным именем (например, ТипДоступныхЦен). Доступными для фильтрации являются только измерения регистра, а также те реквизиты и ресурсы, для которых в конфигураторе включено индексирование или прямо разрешено использование в отборах.

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

Рассмотрим по шагам варианты решения этой задачи для различных поколений форм платформы 1С.

---

Вариант 1. Реализация для обычных форм (Толстый клиент)

Если вы работаете в обычной форме, где табличное поле связано с типом РегистрСведенийСписок, нам необходимо установить программный отбор в обработчике события ПриОткрытии и заблокировать его изменение со стороны пользователя.

Разберем по шагам, как выглядит эта процедура:

  1. Получаем массив или список значений, по которым будет выполняться фильтрация (например, список разрешенных типов цен).
  2. Заполняем стандартное свойство отбора регистра, устанавливая вид сравнения ВСписке.
  3. Отключаем доступность этого поля в интерактивной форме настройки отбора, чтобы пользователь не мог его переопределить или отключить.

Посмотрим на пример программного кода, который реализует эту логику:


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

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

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

---

Вариант 2. Реализация для управляемых форм (Динамический список с произвольным запросом)

В управляемом интерфейсе (Тонкий клиент, Веб-клиент) для вывода списков используется объект ДинамическийСписок. Здесь задача разделения «жесткого системного ограничения» и «гибкого пользовательского фильтра» решается гораздо более красиво и надежно с помощью механизма параметров запроса. Это лучшая практика разработки.

Выясним, как это сделать. Мы можем внедрить ограничение непосредственно в текст запроса динамического списка. В этом случае пользовательские отборы по полю ТипЦен вообще не будут пересекаться с нашим программным ограничением.

Выполним следующие шаги:

  1. Откроем свойства динамического списка на форме и установим флаг «Произвольный запрос».
  2. В тексте запроса пропишем условие фильтрации в секции ГДЕ с использованием параметра:

ВЫБРАТЬ
    РегистрЦен.Период КАК Период,
    РегистрЦен.Номенклатура КАК Номенклатура,
    РегистрЦен.ТипЦен КАК ТипЦен,
    РегистрЦен.Цена КАК Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК РегистрЦен
ГДЕ
    РегистрЦен.ТипЦен В (&ДоступныеТипыЦен)
  1. В модуле формы в обработчике события ПриСозданииНаСервере передадим в параметры динамического списка массив разрешенных значений:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Получаем массив доступных типов цен для текущего контекста/пользователя
    МассивРазрешенныхТипов = ПолучитьДоступныеТипыЦен(); // Ваша экспортная функция
    
    // Устанавливаем значение параметра запроса динамического списка
    Список.Параметры.УстановитьЗначениеПараметра("ДоступныеТипыЦен", МассивРазрешенныхТипов);
    
КонецПроцедуры

Преимущества этого метода очевидны: ограничение накладывается на уровне базы данных (СУБД). Пользователь даже не подозревает о его существовании и видит только разрешенные данные. При этом он может открывать стандартные настройки списка, накладывать любые интерактивные отборы на поле ТипЦен (например, отобрать конкретно «Оптовую» цену из разрешенного ему списка), и система никогда не выдаст ошибку о конфликте настроек.

---

Вариант 3. Использование пользовательских настроек в управляемых формах

Иногда требуется установить программный отбор при открытии так, чтобы пользователь не просто был ограничен, а явно видел этот отбор на форме и при желании мог самостоятельно его отключить или изменить.

Если мы попытаемся записать такой отбор в Список.КомпоновщикНастроек.ФиксированныеНастройки, а пользователь потом попробует установить отбор по этому же полю через интерфейс, платформа выдаст ошибку: «Невозможно применить фиксированные настройки. Пересекаются элементы отбора».

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

Рассмотрим пример кода, реализующий эту схему в процедуре ПриСозданииНаСервере:


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

Используя этот метод, мы программно задаем начальное состояние формы. Отбор красиво отображается в шапке списка (или в панели быстрых настроек), и пользователь может управлять им интерактивно.

---

Вариант 4. Быстрая установка отбора с использованием функций БСП

Если вы ведете разработку в типовой конфигурации, созданной на основе Библиотеки стандартных подсистем (БСП), вам не нужно писать громоздкий код обхода коллекций компоновщика настроек. Разработчики БСП уже позаботились об этом и предоставили удобные общие модули.

Для быстрой установки отбора в динамическом списке воспользуемся процедурой из общего модуля ОбщегоНазначенияКлиентСервер. Посмотрим, как лаконично выглядит это решение:


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

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

---

Резюме и рекомендации

Мы проанализировали различные варианты решения проблемы и выяснили, как правильно управлять фильтрацией списков. Подведем итоги:

← На главную