Как обойти проверку РольДоступна() при программной записи регистра сведений?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При доработке типовых конфигураций разработчики нередко сталкиваются с ситуацией, когда в расширении или основной конфигурации в модуле набора записей регистра сведений установлена жесткая блокировка на изменение данных. Например, в процедуре-обработчике события ПередЗаписью прописан явный запрет на запись для пользователей без роли ПолныеПрава. Если перед нами стоит задача выполнить запись в этот регистр из внешней обработки под обычным пользователем, стандартный вызов завершится ошибкой и отказом в транзакции. Разберем практические способы решения этой задачи, выясним ограничения различных объектов платформы и рассмотрим правильные шаблоны записи данных.

Ограничения объекта РегистрСведенийМенеджерЗаписи

Первое, на что стоит обратить внимание: почему не удается передать произвольные флаги при использовании объекта РегистрСведенийМенеджерЗаписи. Дело в том, что у менеджера записи отсутствует стандартная коллекция ДополнительныеСвойства, которая есть у наборов записей или документов. При попытке передать параметр напрямую через менеджер записи платформа вызовет исключение об отсутствии свойства.

Для реализации гибкого механизма управления проверками необходимо перейти от использования СоздатьМенеджерЗаписи() к работе с объектом СоздатьНаборЗаписей(). Это открывает доступ к свойству ДополнительныеСвойства, существующему на протяжении жизненного цикла объекта набора до момента фиксации транзакции.

Решение 1. Передача управляющего флага через ДополнительныеСвойства

Проанализируем базовый способ: передачу специального параметра из вызывающего кода во встроенную проверку в модуле набора записей. Мы модифицируем расширение так, чтобы оно пропускало проверку роли, если в наборе установлен специальный флаг, и заполняем этот флаг во внешней обработке.

Рассмотрим код обработчика в расширении конфигурации (событие ПередЗаписью модуля набора записей):


&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, Замещение)
	
	// Если передан флаг обхода проверки, выходим из процедуры до проверки прав
	Если ДополнительныеСвойства.Свойство("НеПроводитьПроверкуНаПрава") Тогда
		Возврат;
	КонецЕсли;

	// Стандартная жесткая проверка заказчика
	Если Не РольДоступна("ПолныеПрава") Тогда
		Отказ = Истина;
	КонецЕсли;	
	
КонецПроцедуры

Теперь посмотрим на реализацию серверного кода внешней обработки. Мы формируем набор записей, устанавливаем отбор, добавляем данные и перед вызовом метода Записать() инициализируем свойство в коллекции ДополнительныеСвойства:


Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	Таблица.Номенклатура КАК Номенклатура,
	|	Таблица.Серия КАК Серия
	|ИЗ
	|	ВременнаяТаблица КАК Таблица";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
	
	НовыйШтрихкод = РегистрыСведений.ШтрихкодыНоменклатуры.СформироватьШтрихкодEAN13();
	
	НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
	
	// Обязательно устанавливаем отбор по ключевому измерению
	НаборЗаписей.Отбор.Штрихкод.Установить(НовыйШтрихкод);
	
	// Передаем флаг для обхода проверки в модуле набора
	НаборЗаписей.ДополнительныеСвойства.Вставить("НеПроводитьПроверкуНаПрава", Истина);
	
	НоваяЗапись = НаборЗаписей.Добавить();
	НоваяЗапись.Штрихкод = НовыйШтрихкод;
	НоваяЗапись.Номенклатура = Выборка.Номенклатура;
	НоваяЗапись.УТР_Серия = Выборка.Серия;
	
	Попытка
		НаборЗаписей.Записать(Истина);
	Исключение
		Сообщить("Ошибка при записи набора: " + ОписаниеОшибки());
	КонецПопытки;

КонецЦикла;

Критически важные нюансы работы с набором записей и отборами

Разберем типичную ошибку при использовании вызова НаборЗаписей.Записать(Ложь) без установки отборов. Параметр Ложь указывает платформе, что замещение существующих данных выполнять не требуется. Однако отсутствие установленного отбора приводит к следующим системным проблемам:

  1. Блокировка всей таблицы: транзакция накладывает исключительную блокировку на все пространство записей регистра, что при многопользовательской работе немедленно вызовет эскалацию блокировок и взаимные блокировки (Deadlocks).
  2. Конфликты уникальности: если при вызове без отборов в базу попытаться записать ключ, который уже присутствует, возникнет неустранимая ошибка нарушения уникальности.
  3. Правильный шаблон: всегда устанавливайте отбор по ключевым измерениям (в данном случае по штрихкоду) и выполняйте стандартную запись с замещением НаборЗаписей.Записать(Истина) или НаборЗаписей.Записать().

Решение 2. Использование ПривилегированныйРежим()

Проанализируем альтернативный и более универсальный подход. Проверка РольДоступна("ПолныеПрава") возвращает ложь даже при выполнении кода в привилегированном режиме, если текущему интерактивному пользователю эта роль не назначена в конфигураторе. Однако мы можем скорректировать логику в расширении так, чтобы она учитывала состояние привилегированного режима платформы:


&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, Замещение)
	
	// Если включен привилегированный режим, пропускаем системную запись
	Если Не РольДоступна("ПолныеПрава") И Не ПривилегированныйРежим() Тогда
		Отказ = Истина;
	КонецЕсли;	
	
КонецПроцедуры

В вызывающем коде обработки в таком случае достаточно включить привилегии перед записью:


УстановитьПривилегированныйРежим(Истина);

// Формирование и запись набора записей регистра сведений
НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Штрихкод.Установить(НовыйШтрихкод);
// ... заполнение данных ...
НаборЗаписей.Записать();

УстановитьПривилегированныйРежим(Ложь);

Внимание: ограничение безопасного режима БСП! Если внешняя обработка подключена через подсистему «Дополнительные отчеты и обработки» БСП, по умолчанию она выполняется в безопасном режиме (БезопасныйРежим() = Истина). В этом состоянии платформа 1С полностью блокирует метод УстановитьПривилегированныйРежим() — он отрабатывает вхолостую без генерации исключения, но привилегии не повышаются. Чтобы привилегированный режим сработал во внешней обработке, в карточке дополнительной обработки необходимо отключить признак безопасного режима или предоставить соответствующие разрешения.

Решение 3. Архитектурная альтернатива — ограничение на уровне интерфейса

Выясним причину архитектурных сложностей: проверка прав через РольДоступна() в обработчике ПередЗаписью модуля набора является антипаттерном. Она непреднамеренно «ломает» фоновые задания, регламентные процедуры и любые внешние инструменты обмена данными.

Если цель разработчика — не допустить ручного редактирования данных пользователями, эту задачу следует решать следующими методами:

  1. Отзыв права интерактивного изменения: в профиле групп доступа или роли снимается галочка «Интерактивное добавление» для нужного регистра. При этом право на программную запись (права «Чтение» и «Изменение») у пользователя сохраняется.
  2. Проверка в событиях формы: запрет на полные права выносится в модуль формы записи регистра (в обработчики ПриОткрытии или ПередЗаписьюНаСервере формы). В этом случае интерактивный ввод через окно формы будет заблокирован, а любая программная запись через код продолжит штатно работать без использования костылей.
← На главную