Как ограничить редактирование полей проведенного документа для конкретной роли в 1С?

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

В практике разработки на платформе 1С:Предприятие нередко возникает задача: предоставить пользователю с ограниченными правами возможность однократно изменить лишь один реквизит в проведенном документе (например, уточнить значение поля Контрагент, если изначально был указан временный или неопределенный партнер), оставив все остальные реквизиты заблокированными.

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

Анализ проблемы и логических условий

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

Часто в коде возникает путаница из-за сложных составных условий с конструкциями НЕ, И, ИначеЕсли. Если условия составлены несимметрично, документ может либо полностью блокироваться, либо, наоборот, открываться для полного редактирования всех полей.

Проанализируем базовый вариант логики, предложенный в обсуждении:


Если НЕ РольДоступна("ПолныеПрава") Тогда 
    Если Проведен И РольДоступна("ИзменениеКонтрагентаОплаты") Тогда
        Если НЕ Контрагент = Константы.НеизвестныйКонтрагент.Получить() Тогда
            ЭтаФорма.ТолькоПросмотр = Истина;
        КонецЕсли;
    ИначеЕсли Контрагент = Константы.НеизвестныйКонтрагент.Получить() Тогда
        Для Каждого Элф Из ЭтаФорма.ЭлементыФормы Цикл
            Если Элф.Имя = "Док_Основание" Или Элф.Имя = "Закрыть" Или Элф.Имя = "КНДолги" Тогда
                Продолжить;
            КонецЕсли;    
            Если (Элф.Имя = "Контрагент" Или Элф.Имя = "ОК") И НЕ Правка Тогда
                Продолжить;
            КонецЕсли;
            Попытка
                Элф.ТолькоПросмотр = Истина;
            Исключение
                Элф.Доступность = Ложь;
            КонецПопытки;    
        КонецЦикла;    
    КонецЕсли;
КонецЕсли;

Пошаговое построение корректной логики формы

Разберем по шагам, как выстроить ветвление условий прозрачно и без скрытых логических ошибок:

  1. Проверка административных прав: Если у пользователя есть роль ПолныеПрава, алгоритм не накладывает никаких дополнительных ограничений.
  2. Проверка статуса документа: Если документ не проведен, действуют стандартные правила редактирования. Если документ проведен, переходим к проверке прав и реквизитов.
  3. Проверка роли и значения реквизита: Если у пользователя есть целевая роль (например, ИзменениеКонтрагентаОплаты) и реквизит еще не заполнен (равен значению Константы.НеизвестныйКонтрагент.Получить()), разрешаем редактирование только нужного поля, блокируя остальные. Во всех остальных случаях для проведенного документа включаем ЭтаФорма.ТолькоПросмотр = Истина.

Посмотрим на пример структурированного кода для процедуры ПриОткрытии:


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

Тонкости работы с элементами управления в обычных формах

При реализации блокировки интерфейса в обычных формах важно учитывать следующие технические особенности платформы:

  1. Приоритет общего свойства формы: Если для всей формы установлено ЭтаФорма.ТолькоПросмотр = Истина, дочерние элементы управления нельзя сделать доступными для редактирования. Сначала форма должна оставаться доступной (ТолькоПросмотр = Ложь), после чего выборочно блокируются отдельные элементы.
  2. Вложенные элементы на панелях: Простой обход коллекции ЭтаФорма.ЭлементыФормы верхнего уровня не изменяет свойства элементов, расположенных на страницах элементов управления типа Панель. Для полной блокировки сложного интерфейса требуется рекурсивный обход элементов.

Риски управления правами исключительно на уровне формы

Выясним причину, почему ограничений на уровне формы недостаточно для надежной защиты данных:

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

Рекомендуемые способы реализации (Best Practice)

Рассмотрим два надежных подхода к решению задачи:

Вариант 1. Контроль изменений в модуле объекта (ПередЗаписью)

Если редактирование выполняется непосредственно в форме документа, обязателен программный контроль целостности данных в модуле объекта:

  1. В процедуре-обработчике ПередЗаписью модуля документа сравниваем текущие данные объекта (ЭтотОбъект) с данными, сохраненными в базе данных (Ссылка).
  2. Проверяем, что изменен исключительно реквизит Контрагент, а остальные реквизиты и табличные части остались неизменными.
  3. Проверяем условие однократности: если значение Ссылка.Контрагент уже отличается от значения константы, устанавливаем Отказ = Истина и выводим предупреждение пользователю.

Вариант 2. Использование команды в привилегированном режиме

Наиболее безопасным подходом является отказ от предоставления пользователю права «Интерактивное изменение проведенных»:

  1. Документ остается полностью недоступным для интерактивного редактирования пользователем.
  2. Создается специальная команда или обработка «Указать контрагента».
  3. Запись и корректировка движений документа выполняются программно в процедуре с вызовом УстановитьПривилегированныйРежим(Истина), что полностью исключает несанкционированное изменение остальных реквизитов проведенного документа.
← На главную