При разработке интерфейсов на управляемых формах часто возникает задача ограничить видимость элементов и групп справочника для разных пользователей. Например, в справочнике Номенклатура необходимо показывать каждой группе пользователей только «свои» папки и позицию товара, исключив доступ к чужой иерархии. Если при этом заказчик просит обойтись без применения механизмов ограничения прав на уровне записей (RLS), разработчик сталкивается со специфическим поведением платформы «1С:Предприятие».
Разберем подробно, с какими сложностями мы сталкиваемся при такой постановке задачи и какими способами можно реализовать гибкий отбор в динамическом списке.
Проанализируем поведение системы при стандартной настройке отборов. Когда таблица формы отображает динамический список в режиме «Иерархический список» или «Дерево», платформа специально сохраняет в структуре вышестоящие родительские узлы. Даже если вышестоящая папка не соответствует условиям установленного отбора, система отобразит её, чтобы не нарушать целостность древовидного дерева.
Поле Родитель обрабатывается платформой особым образом для обеспечения навигации. Поэтому стандартные отборы системы компоновки данных (СКД), а также произвольные условия в запросе динамического списка по дополнительным реквизитам или флагам доступа не приводят к скрытию «пустых» узлов-предков. В результате пользователь видит развернутую цепочку пустых папок, внутри которых отображаются только разрешенные узлы.
Рассмотрим наименее трудоемкое с точки зрения программирования решение. Если бизнес-процессы компании допускают изменение структуры данных, оптимизируем иерархию справочника до двух уровней:
В этом случае мы можем добавить в группу справочника реквизит ГруппаДоступаНоменклатуры со ссылкой на соответствующий справочник прав или перечисление. Установив обычный отбор по реквизиту Родитель.ГруппаДоступаНоменклатуры или ГруппаДоступаНоменклатуры, мы избавимся от проблемы глубоких пустых узлов, так как иерархия станет строго фиксированной.
Посмотрим на вариант, когда структуры данных менять нельзя, но можно изменить форму отображения. Если пользователям не обязательно видеть данные в виде дерева, переключим свойство таблицы формы в обычный плоский режим.
Программно или через палитру свойств изменим режим отображения:
Элементы.Список.РежимОтображения = РежимОтображенияТаблицы.Список;
В плоском списке механизмы отбора СКД работают напрямую без учета древовидных связей. Все элементы и папки, не подпадающие под условия отбора, скрываются полностью, не оставляя никаких пустых узлов.
Проанализируем архитектурный подход, позволяющий сохранить навигацию по группам без использования сложной иерархии в одном динамическом списке. Разделим форму на два независимых динамических списка:
Связь реализуется через свойство ОтображениеРодителя или программно при активизации строки первой таблицы с помощью установки параметра отбора Родитель во втором динамическом списке:
&НаКлиенте
Процедура СписокГруппПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
ОтборРодитель = СписокЭлементов.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборРодитель.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Родитель");
ОтборРодитель.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборРодитель.ПравоеЗначение = ТекущиеДанные.Ссылка;
ОтборРодитель.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Рассмотрим вариант, когда необходимо скрыть элементы ещё на уровне запроса динамического списка. Для этого создадим регистр сведений ПраваДоступаКНоменклатуре с измерениями Пользователь (или ГруппаПользователей) и Номенклатура.
При изменении прав или регламентным заданием регистр заполняется развернутым списком всех доступных объектов (включая все вложенные элементы и папки). В произвольном запросе динамического списка настраиваем соединение:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Наименование КАК Наименование,
СправочникНоменклатура.Код КАК Код
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПраваДоступаКНоменклатуре КАК Права
ПО Права.Номенклатура = СправочникНоменклатура.Ссылка
ГДЕ
Права.Пользователь = &ТекущийПользователь
Данный подход гарантирует отсечение недоступных записей на уровне СУБД без использования RLS, однако требует поддержания актуальности данных в регистре сведений.
Проанализируем программный отбор с использованием вида сравнения ВИерархии. Если пользователю разрешен доступ к определенным корневым группам, мы можем передать массив этих групп в элемент отбора СКД:
МассивРазрешенныхГрупп = ПолучитьДоступныеГруппыДляПользователя();
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;
ЭлементОтбора.ПравоеЗначение = МассивРазрешенныхГрупп;
ЭлементОтбора.Использование = Истина;
При таком подходе ветки, не входящие в указанные группы, скрываются полностью. Однако следует учитывать: если доступная группа расположена глубоко в иерархии, её вышестоящие папки отображаться не будут, и группа станет корневым узлом в отображаемом дереве.
Подведем итоги и сравним рассмотренные методы с механизмом RLS (Record Level Security):
Список), либо использовать двухтабличный интерфейс, либо поддерживать вспомогательные регистры сведений.