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