Как программно ограничить выбор пользователей в справочнике на основе данных из регистра сведений?

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

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

Способ 1. Использование события ОбработкаПолученияДанныхВыбора в модуле менеджера

Этот метод считается одним из самых «чистых» и правильных, так как он работает не только при открытии формы выбора, но и при вводе по строке (автоподборе). Если пользователь начнет печатать имя в поле ввода, система вызовет этот обработчик и предложит только разрешенные варианты.

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

Рассмотрим пример кода:


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

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

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

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

Если нам необходимо, чтобы при нажатии на кнопку выбора (три точки) открывалась стандартная форма справочника, но в ней отображались только нужные записи, мы воспользуемся динамическим списком и его настройками. Выясним, почему лучше использовать именно ФиксированныеНастройки.

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

Разберем пример установки отбора при создании формы на сервере:


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

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

Важно помнить, что если пользователей в регистре очень много, передача огромного массива в ВидСравнения.ВСписке может замедлить работу. В таких случаях лучше использовать соединение в самом запросе динамического списка.

Способ 3. Параметры выбора и связи параметров выбора

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

Однако, если условие сложное (как в нашем случае с регистром), ПараметрыВыбора напрямую из метаданных могут не подойти. Но мы можем программно заполнить их перед началом выбора. Разберем событие НачалоВыбора:


&НаКлиенте
Процедура ПользовательНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    МассивДоступных = ПолучитьСписокДоступныхПользователейНаСервере();
    
    ПараметрыФильтра = Новый Структура("Отбор", Новый Структура("Ссылка", МассивДоступных));
    Элемент.ПараметрыВыбора = Новый ФиксированныйМассив(Новый Массив); // Сброс старых
    
    // Установка новых параметров
    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(Новый ПараметрВыбора("Отбор.Ссылка", МассивДоступных));
    Элемент.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);

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

Способ 4. Режим выбора из списка (ChoiceList)

Если в вашем регистре сведений находится небольшое количество записей (например, до 20-30 пользователей), то открывать целую форму справочника — это избыточный расход ресурсов. В таком случае логичнее использовать выпадающий список.

Выясним, как это работает. Мы переключаем поле в режим «выбора из списка» и программно заполняем этот список значениями. Рассмотрим пошагово:

  1. Установите у элемента формы свойство РежимВыбораИзСписка в значение Истина.
  2. В событии ПриСозданииНаСервере заполните СписокВыбора этого элемента.

Пример программного заполнения:


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

Этот метод очень удобен для пользователя: вместо открытия нового окна он просто выбирает нужную фамилию из компактного выпадающего меню.

Важный нюанс: История выбора и очистка данных

Проанализируем одну распространенную проблему. Даже если вы установили все фильтры, пользователь может увидеть «старые» значения в выпадающем списке под полем ввода. Это происходит из-за механизма Истории выбора 1С. Система запоминает, кого пользователь выбирал вчера, и предлагает их снова, даже если сегодня этих людей нет в регистре сведений.

Чтобы исключить эту ситуацию, рекомендуется:

Способ 5. Ограничение на уровне прав (RLS)

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

В такой ситуации разберем использование Record Level Security (RLS). Это механизм, который настраивается в ролях. Вы прописываете запрос прямо в правах доступа к справочнику Пользователи. Система сама будет добавлять условие ГДЕ Ссылка В (ВЫБРАТЬ Пользователь ИЗ РегистрСведений.Доступные...) ко всем запросам в базе. Это гарантирует, что «лишние» пользователи исчезнут из всех отчетов, списков и форм выбора автоматически.

Подведем итоги

Мы проанализировали несколько подходов к ограничению выбора. Если вам нужен быстрый и визуально приятный способ для небольшого списка — выбирайте СписокВыбора. Если нужно комплексное решение, работающее и при поиске, и при открытии формы — комбинируйте ОбработкаПолученияДанныхВыбора и ФиксированныеНастройки динамического списка. А для обеспечения жесткой безопасности всегда используйте RLS.

← На главную