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