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