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