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