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