Как ограничить установку определенного статуса перечисления для конкретных пользователей?

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

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

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

Анализ логической ошибки в условии

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

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


&НаСервере
Процедура СтатусПриИзмененииНаСервере()
    // Проверяем, что установлен именно целевой статус
    Если Объект.Статус = Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно Тогда
        
        ТекущийПользователь = ПользователиКлиентСервер.ТекущийПользователь();
        Пользователь1 = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван", Истина);
        Пользователь2 = Справочники.Пользователи.НайтиПоНаименованию("Петров Петр", Истина);
        
        // Условие: если текущий пользователь это НЕ Иванов И это НЕ Петров
        Если ТекущийПользователь <> Пользователь1 И ТекущийПользователь <> Пользователь2 Тогда
             Объект.Статус = ПредопределенноеЗначение("Перечисление.ХХХ_ВидыВнутреннихПеремещений.ПустаяСсылка");
             Сообщить("У вас недостаточно прав для установки статуса 'Согласовано'!");
        КонецЕсли;
        
    КонецЕсли;
КонецПроцедуры

Использование события ОбработкаВыбора

Метод с очисткой значения в ПриИзменении не совсем удобен для пользователя: он сначала выбирает значение, а программа его тут же «стирает». Это создает плохой пользовательский опыт (UX). Разберем, как перехватить выбор еще до того, как значение попадет в реквизит, используя событие ОбработкаВыбора.

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


&НаКлиенте
Процедура СтатусОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    Если ВыбранноеЗначение = ПредопределенноеЗначение("Перечисление.ХХХ_ВидыВнутреннихПеремещений.Согласованно") Тогда
        Если Не ПроверитьПравоСогласованияНаСервере() Тогда
            СтандартнаяОбработка = Ложь; // Отменяем выбор
            ПоказатьПредупреждение(, "Вам запрещено устанавливать статус 'Согласовано'");
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Управление списком выбора (самый правильный UX)

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

Посмотрим, как это реализовать в процедуре ПриСозданииНаСервере:

  1. Установим у поля формы Статус свойство РежимВыбораИзСписка в значение Истина.
  2. Заполним список выбора только теми значениями, которые разрешены текущему пользователю.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Очищаем стандартный список
    Элементы.Статус.СписокВыбора.Очистить();
    
    // Добавляем общие для всех статусы
    Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.Проект);
    Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.НаУтверждении);
    
    // Проверяем права на специальный статус
    Если ПравоУстановкиСтатусаСогласовано() Тогда
        Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно);
    КонецЕсли;
    
КонецПроцедуры

Почему нельзя искать по наименованию?

Важно обратить внимание на критическую ошибку в коде автора — использование НайтиПоНаименованию("Пользователь 1"). Выясним, почему это плохо: во-первых, администратор может изменить имя пользователя в справочнике, и код перестанет работать. Во-вторых, в базе могут оказаться два полных тезки. В-третьих, если список согласующих расширится до 10 человек, ваш код превратится в огромную нечитаемую простыню из условий И.

Рекомендуемые альтернативы хардкоду:

Комплексная защита: проверка в модуле объекта

Помните, что все проверки на форме — это лишь интерфейсные ограничения. Пользователь может изменить статус документа через «Групповое изменение реквизитов» или с помощью внешней обработки. Чтобы обеспечить 100% надежность, необходимо продублировать проверку на уровне сервера в модуле объекта (или в подписке на событие ПередЗаписью).


// В модуле объекта документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Сравниваем старое значение из базы с новым
    Если Статус = Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно 
       И Ссылка.Статус <> Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно Тогда
        
        Если Не ПользовательИмеетПравоСогласования() Тогда
            Отказ = Истина;
            Сообщить("Недостаточно прав для перевода документа в статус 'Согласовано'!");
        КонецЕсли;
        
    КонецЕсли;
КонецПроцедуры

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

← На главную