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