Как программно установить отбор в динамическом списке по нескольким складам текущего пользователя?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ проблемы: почему список оказывается пустым?

Рассмотрим ситуацию, когда программист пытается добавить два отдельных элемента отбора для одного и того же поля (например, Склад) в коллекцию отборов динамического списка. По умолчанию платформа объединяет все элементы отбора по правилу Группа И. В результате формируется запрос, условие которого выглядит следующим образом: ГДЕ Склад = &Склад1 И Склад = &Склад2. С точки зрения логики базы данных, одна запись не может одновременно содержать два разных значения в одном поле. Именно поэтому динамический список отображается пустым.

Для решения этой задачи мы можем пойти двумя путями: использовать логическое объединение Группа ИЛИ или применить вид сравнения В списке. Второй вариант является более предпочтительным с точки зрения чистоты кода и производительности.

Способ 1: Использование вида сравнения "В списке"

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


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

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

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

Способ 2: Использование Фиксированных настроек

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

Выясним, как это реализовать:


&НаСервере
Процедура УстановитьФиксированныйОтбор()
    
    ГруппаОтбора = Список.ФиксированныеНастройки.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
    ГруппаОтбора.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;
    
    // Добавляем первый склад
    Элемент1 = ГруппаОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    Элемент1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
    Элемент1.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    Элемент1.ПравоеЗначение = Склад1;
    
    // Добавляем второй склад
    Элемент2 = ГруппаОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    Элемент2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
    Элемент2.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    Элемент2.ПравоеЗначение = Склад2;
    
КонецПроцедуры

Преимущество Фиксированных настроек заключается в том, что они суммируются с пользовательскими настройками. Если пользователь решит дополнительно отфильтровать список по контрагенту, система применит условие: (Склад1 ИЛИ Склад2) И Контрагент.

Важные рекомендации и нюансы

При работе с динамическими списками и отборами важно учитывать несколько критических моментов:

  1. Проверка заполнения параметров: Всегда проверяйте, получены ли значения из настроек пользователя. Если передать в ПравоеЗначение пустой СписокЗначений или Неопределено, список либо отобразит все записи, либо не отобразит ничего (зависит от настроек платформы).
  2. Использование RLS (Row Level Security): Программный отбор в форме защищает только "глаза" пользователя. Если пользователь продвинутый, он может увидеть данные через консоль запросов или другие отчеты. Если задача стоит в обеспечении безопасности данных, используйте механизм Ограничения доступа на уровне записей. В УТ 11 это настраивается через Группы доступа, где можно ограничить доступ к конкретным складам для определенных профилей.
  3. Производительность: Если в динамическом списке используется сложный произвольный запрос, отбор по индексированным полям (каким обычно является Склад) выполняется крайне быстро. Однако, если складов в списке сотни, лучше использовать параметры запроса.

Использование функций БСП

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), рекомендуется использовать готовые инструменты, чтобы не "изобретать велосипед". Проанализируем использование общего модуля ОбщегоНазначенияКлиентСервер:


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

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

Подведем итог: для корректной фильтрации динамического списка по нескольким значениям необходимо использовать либо ГруппаИЛИ, либо вид сравнения ВСписке. Использование ФиксированныхНастроек позволит сделать этот отбор скрытым и защищенным от изменений пользователем в процессе работы с формой.

← На главную