Как разрешить редактирование одного реквизита в документе с ограниченными правами доступа?

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

В практике разработки на платформе 1С часто возникает ситуация, когда бизнес-процесс требует от пользователя внесения изменений в документ, который уже закрыт для редактирования (например, проведен или находится в периоде, запрещенном для редактирования). Типичный пример: менеджер должен иметь возможность изменить только «Комментарий» или «Состояние доставки», не имея при этом прав на изменение самого документа, его сумм или товарного состава. Рассмотрим подробнее, как реализовать этот механизм правильно и безопасно.

Почему стандартный подход с «УстановитьПривилегированныйРежим» в форме не работает?

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

Кроме того, важно понимать разницу между доступностью элементов формы и правами доступа к данным. Даже если вы программно установите ЭлементыФормы.ИмяРеквизита.Доступность = Истина, попытка записать объект (ЭтотОбъект.Записать()) под учетной записью пользователя без соответствующих ролей приведет к отказу в доступе на уровне сервера базы данных или сработает механизм RLS (Row Level Security).

Правильная архитектура решения через Общий модуль

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

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

Рассмотрим пример кода в таком модуле (назовем его РаботаСДокументамиСервер):


Процедура ИзменитьРеквизитДокументаПривилегированно(СсылкаНаДокумент, НовоеЗначение) Экспорт
    
    // Получаем объект из ссылки
    ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
    
    Если ОбъектДокумента = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Устанавливаем новое значение конкретного реквизита
    ОбъектДокумента.Реквизит1 = НовоеЗначение;
    
    // Отключаем проверки бизнес-логики, если это необходимо
    ОбъектДокумента.ОбменДанными.Загрузка = Истина;
    
    // Записываем документ без перепроведения (режим Запись)
    Попытка
        ОбъектДокумента.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        ЗаписьЖурналаРегистрации("Ошибка записи реквизита", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение "Не удалось сохранить изменения: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецПроцедуры

Нюансы использования «ОбменДанными.Загрузка = Истина»

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

Установка Загрузка = Истина позволяет обойти эти проверки, так как большинство типовых и самописных конфигураций содержат условие в начале процедур модуля документа: Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;. Однако будьте осторожны: это также отключает и полезные проверки (контроль заполнения, проверка остатков и т.д.). Используйте этот метод только тогда, когда уверены, что меняемый реквизит не влияет на целостность данных системы.

Реализация в Обычных формах

Поскольку в сообщении автора упоминаются обычные формы, процесс вызова серверного кода имеет свои особенности. В обычных формах (в отличие от управляемых) нет явных директив &НаСервере. Вызов будет выглядеть так:

Разберем код в модуле формы документа (например, при нажатии на специальную кнопку «Изменить статус»):


Процедура КнопкаИзменитьНажатие(Элемент)
    
    // 1. Вызываем нашу привилегированную процедуру из общего модуля
    РаботаСДокументамиСервер.ИзменитьРеквизитДокументаПривилегированно(Ссылка, ЭлементыФормы.ПолеВводаРеквизита.Значение);
    
    // 2. Важнейший шаг: обновление данных в открытой форме
    // Если этого не сделать, возникнет конфликт версий при попытке закрыть форму
    ЭтаФорма.Прочитать(); 
    
    Сообщить("Реквизит успешно изменен!");
    
КонецПроцедуры

Проблема конфликта версий (Объект изменен)

Посмотрим на ситуацию со стороны платформы: пользователь открыл форму документа. В памяти клиента создана копия объекта. В этот момент вы программно на сервере меняете этот документ в базе данных. Теперь версия объекта в памяти клиента (в форме) и версия объекта в базе данных различаются.

Если пользователь после вашего программного изменения нажмет «ОК» в форме, он получит ошибку: «Объект изменен или удален другим пользователем». Чтобы этого избежать, после выполнения серверного кода записи обязательно используйте метод Прочитать() (для обычных форм) или ОповеститьОбИзменении(Ссылка) вместе с перечитыванием данных (для управляемых форм). Это синхронизирует данные формы с актуальным состоянием в базе данных.

Безопасность и дополнительные проверки

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


Если НЕ РольДоступна("ПравоНаСпецИзменение") Тогда
    ВызватьИсключение "У вас недостаточно прав для выполнения этой операции!";
КонецЕсли;

Таким образом, мы объединяем мощь Привилегированного режима с гибкостью настройки прав через роли, обеспечивая корректное выполнение бизнес-задачи без нарушения логики работы системы.

← На главную