Как в динамическом списке скрыть строки регистра сведений с недоступными документами («Объект не найден»)?

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

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

Когда пользователь, обладающий правами только на Док1 и регистр сведений, открывает форму со стандартным динамическим списком, он видит все строки регистра. При этом поля документов типа Док2 отображаются как <Объект не найден> (или в виде внутреннего идентификатора GUID). Выясним причину такого поведения платформы 1С и подробно рассмотрим практические способы решения этой проблемы.

Почему возникает «Объект не найден» и почему не работают временные таблицы

Проанализируем механику работы ограничений на уровне записей (RLS) платформы «1С:Предприятие». Когда выполняется запрос к регистру (в том числе неявно с ключевым словом ВЫБРАТЬ РАЗРЕШЕННЫЕ), права проверяются только на сам опрашиваемый регистр сведений. Если у пользователя есть Роль3 с полным доступом к чтению регистра, платформа извлекает все его записи. Ссылочное поле содержит реальный идентификатор документа, однако платформа при попытке получить строковое представление запрещенного объекта упирается в ограничение прав на чтение целевой таблицы и выводит заглушку.

Попытка обойти ограничение путем помещения разрешенных документов во временные таблицы (ПОМЕСТИТЬ) с последующим соединением с регистром не срабатывает, так как динамический список категорически не поддерживает пакетные запросы и работу с временными таблицами. Механизм RLS также не умеет «подсматривать» в другие роли: каждая роль самодостаточна, а итоговые права пользователя объединяются по правилу логического «ИЛИ».

Способ 1. Использование условий по типу ссылки и параметров сеанса в RLS

Посмотрим на классический подход с настройкой ограничения доступа на уровне записей для самого регистра сведений. В языке ограничений доступа 1С штатно поддерживается проверка типа с помощью оператора ССЫЛКА или функции ТИПЗНАЧЕНИЯ.

Чтобы не перегружать СУБД тяжелыми подзапросами, в конфигурацию добавляют булевы параметры сеанса (например, Роль1Доступна и Роль2Доступна), которые инициализируются при старте сеанса пользователя:


// В модуле сеанса или общем модуле инициализации параметров сеанса:
ПараметрыСеанса.Роль1Доступна = РольДоступна("Роль1");
ПараметрыСеанса.Роль2Доступна = РольДоступна("Роль2");

После этого для чтения регистра сведений задается условие RLS, связывающее тип ссылки в поле документа и доступность соответствующей роли:


ГДЕ
    (ПолеДокумент ССЫЛКА Документ.Док1 И &Роль1Доступна)
    ИЛИ
    (ПолеДокумент ССЫЛКА Документ.Док2 И &Роль2Доступна)

Разберем нюансы этого метода: оператор ССЫЛКА проверяет только внутренний код типа метаданных и не выполняет разыменования полей документа. Поэтому платформа не выдаст ошибку о нехватке прав на сам документ, а строки с запрещенными типами просто отфильтруются на уровне СУБД.

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

Если разграничение прав выполняется только на уровне типов метаданных (то есть у пользователя либо есть доступ ко всем документам определенного вида, либо нет вовсе, без RLS по организациям или подразделениям), оптимальнее отказаться от RLS на регистр в пользу серверного кода формы. Это полностью исключит лишние накладные расходы на стороне СУБД.

Посмотрим, как настроить фильтрацию в обработчике формы списка:

  1. Открываем модуль формы, содержащей динамический список.
  2. В процедуре ПриСозданииНаСервере выполняем проверку прав текущего пользователя с помощью метода ПравоДоступа.
  3. Программно устанавливаем отбор по типу документов в фиксированные настройки списка.

Рассмотрим пример реализации на встроенном языке:


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

Способ 3. Переход на стандартный объект «Журнал документов»

Проанализируем архитектурное решение задачи. Если цель регистра сведений сводится исключительно к выводу единого реестра документов разного вида с общими полями, наиболее правильным является использование встроенного объекта конфигурации Журнал документов.

У журналов документов есть важное платформенное преимущество: ядро 1С автоматически исключает из журнала документы тех типов, на которые у текущей роли нет прав на чтение. Никаких записей <Объект не найден> при этом не возникает. Сопутствующую информацию (например, статус или флаги) можно получать в запросе формы журнала через левое соединение с регистром сведений по полю Ссылка.

Способ 4. Шаблоны доступа БСП (наследование прав)

Если разработка ведется в типовой или дорабатываемой конфигурации на базе Библиотеки стандартных подсистем (БСП) с включенным производительным режимом RLS, разберем решение через подсистему управления доступом:

  1. Включаем регистр сведений в определяемый тип ВладелецЗначенийКлючейДоступа (или ВладелецЗначенийКлючейДоступаНаборЗаписей).
  2. В модуле менеджера регистра описываем процедуру ПриЗаполненииОграниченияДоступа, где настраиваем наследование прав от поля с ведущим документом:
    
    Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
        Ограничение.Текст =
            "РазрешитьЧтение
            |ГДЕ
            |   ЧтениеОбъектаРазрешено(Документ)";
    КонецПроцедуры
    

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

← На главную