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