Как ограничить доступ к документу в расширении и исправить ошибку «Запрещено изменение параметра, отменяющего действие»?

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

В процессе разработки расширений для типовых конфигураций 1С часто возникает задача ограничить доступ к определенным документам на основании значений их реквизитов, предварительно выполнив просмотр ролей для объекта. Например, если в документе "Счет на оплату" установлен флаг "Счет закрыт", рядовые пользователи не должны иметь возможности редактировать или даже открывать этот документ, в то время как менеджеры с особыми правами должны сохранять полный доступ.

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

Суть задачи

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

  1. Проверить, установлена ли галочка СчетЗакрыт.
  2. Если галочка стоит, проверить, есть ли у текущего пользователя роль ДоступМенеджер.
  3. Если роли нет, запретить открытие формы или сделать её доступной только для просмотра.

Анализ ошибки: почему нельзя менять «Отказ» в событии «После»

Рассмотрим код, который часто пытаются использовать разработчики и который приводит к ошибке. В расширении создается обработчик события ПриОткрытии с аннотацией &После.


&НаКлиенте
Процедура Расш1_ПриОткрытииПосле(Отказ)
    Если Объект.СчетЗакрыт И НЕ ЕстьПраво() Тогда
        Отказ = Истина; // ОШИБКА ЗДЕСЬ
    КонецЕсли;
КонецПроцедуры

При попытке открыть документ система выдаст ошибку: "Запрещено изменение параметра, отменяющего действие (параметр номер 1 в процедуре)".

Давайте разберемся в причинах. Жизненный цикл событий в расширениях 1С имеет строгий порядок:

  1. Сначала выполняются обработчики с аннотацией &Перед.
  2. Затем выполняется основной код конфигурации.
  3. В конце выполняются обработчики с аннотацией &После.

Параметр Отказ предназначен для того, чтобы прервать действие (в данном случае — открытие формы). Если событие уже свершилось (то есть мы находимся в обработчике &После), отменять его поздно. Форма фактически уже создана и открывается. Платформа блокирует изменение параметра Отказ в пост-обработчиках, чтобы избежать логических противоречий.

Правильное решение: использование аннотации «Перед»

Чтобы иметь возможность запретить открытие формы, мы должны перехватить управление до того, как форма окончательно откроется. Для этого необходимо использовать аннотацию &Перед.

Давайте исправим код. Нам понадобится серверная функция для проверки прав и клиентская процедура для управления открытием.


&НаСервере
Функция ЕстьПравоНаРедактирование()
    // Проверяем наличие специальной роли
    Возврат РольДоступна("ДоступМенеджер");
КонецФункции

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

КонецПроцедуры

В этом случае мы вмешиваемся в процесс до его завершения, и изменение параметра Отказ отработает корректно.

Альтернативный вариант: режим «Только просмотр»

Часто полный запрет на открытие документа является слишком жесткой мерой. Пользователю может потребоваться посмотреть содержимое счета, даже если он не может его менять. В этом случае вместо блокировки открытия (Отказ = Истина) лучше перевести форму в режим "Только просмотр".

Важно отметить: свойство ЭтаФорма.Доступность = Ложь делает форму полностью "мертвой" — нельзя даже скопировать текст или прокрутить список. Правильнее использовать свойство ТолькоПросмотр.

Посмотрим, как это реализовать. В данном случае лучше использовать событие ПриСозданииНаСервере, так как оно выполняется один раз при инициализации формы и не требует лишних серверных вызовов с клиента.


&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Проверяем условие блокировки
    СчетЗакрыт = Объект.СчетЗакрыт; // Получаем значение реквизита
    ЕстьПрава = РольДоступна("ДоступМенеджер");
    
    Если СчетЗакрыт И НЕ ЕстьПрава Тогда
        // Устанавливаем режим "Только чтение" для всей формы
        ЭтаФорма.ТолькоПросмотр = Истина;
    КонецЕсли;
    
    // Дополнительная логика для блокировки самой галочки "СчетЗакрыт"
    // Чтобы даже менеджер не мог случайно снять её, или наоборот - разрешить только ему.
    // Если у пользователя нет прав менеджера, он вообще не должен менять этот статус.
    Элементы.СчетЗакрыт.ТолькоПросмотр = НЕ ЕстьПрава;

КонецПроцедуры

Разберем нюансы управления доступностью элементов

В обсуждении проблемы автор столкнулся с ситуацией, когда элемент формы оставался недоступным даже для пользователя с полными правами. Это часто происходит из-за логических ошибок в условиях.

Рассмотрим пример управления конкретным элементом формы СчетЗакрыт. Допустим, мы хотим, чтобы ставить и снимать эту галочку могли только менеджеры, независимо от текущего состояния документа.


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

Правильный подход — устанавливать свойство безусловно, опираясь только на права:


// Правильный пример
// Элемент доступен только если есть право, значение самой галочки не важно
Элементы.СчетЗакрыт.Доступность = ЕстьПравоНаРедактирование();

Механизм RLS: профессиональный подход

Хотя управление формой (видимость, доступность, отказ при открытии) решает задачу визуально, это не обеспечивает 100% защиты данных. Продвинутый пользователь может открыть список документов, воспользоваться групповой обработкой или отчетом и увидеть/изменить данные.

Для надежного ограничения доступа в 1С используется механизм RLS (Record Level Security) — ограничение доступа на уровне записей.

Если задача стоит именно в жесткой безопасности (никто кроме менеджера не должен видеть суммы закрытых счетов), следует настроить RLS в роли пользователя:

  1. Открываем роль пользователя в конфигураторе (или создаем новую в расширении).
  2. Переходим к правам на документ "Счет на оплату".
  3. В правой части (Ограничение доступа к данным) для прав "Чтение" и "Изменение" прописываем шаблон запроса.

Примерная логика шаблона ограничения:


ГДЕ (СчетЗакрыт = ЛОЖЬ) ИЛИ (СчетЗакрыт = ИСТИНА И &ТекущийПользователь В (ВЫБРАТЬ ... ИЗ Менеджеры ...))

Однако настройка RLS требует хорошего знания языка запросов и понимания производительности системы. Для простых задач, таких как «защита от случайного редактирования», метод с ТолькоПросмотр в форме является вполне приемлемым и простым в реализации.

Резюме

Для решения задачи автора необходимо выполнить следующие действия:

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