В процессе разработки бизнес-логики часто возникает задача: ограничить возможность установки определенного значения реквизита (например, статуса «Согласовано») так, чтобы это могли делать только ответственные лица. Рассмотрим ситуацию, когда начинающий разработчик пытается реализовать это через проверку условия в процедуре ПриИзменении, но сталкивается с тем, что условие срабатывает неправильно или код получается слишком «хрупким».
Разберем подробно, как правильно организовать такую проверку, исправим логические ошибки и изучим более профессиональные подходы к решению этой задачи в среде 1С:Предприятие.
Проанализируем ситуацию автора: он хотел, чтобы только два пользователя могли устанавливать статус. Первоначальный код содержал логическую ошибку в блоке ИЛИ. Выясним причину: если мы пишем Если НЕ Пользователь1 ИЛИ НЕ Пользователь2, то это условие будет истинным всегда. Почему? Потому что текущий пользователь в любой момент времени не может быть одновременно и Первым, и Вторым. Если зашел Пользователь 2, он «не равен» Пользователю 1, и условие выполняется. Если зашел Пользователь 1, он «не равен» Пользователю 2, и условие снова выполняется.
Чтобы ограничение работало корректно, необходимо использовать логическое И. Рассмотрим исправленный вариант условия:
&НаСервере
Процедура СтатусПриИзмененииНаСервере()
// Проверяем, что установлен именно целевой статус
Если Объект.Статус = Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно Тогда
ТекущийПользователь = ПользователиКлиентСервер.ТекущийПользователь();
Пользователь1 = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван", Истина);
Пользователь2 = Справочники.Пользователи.НайтиПоНаименованию("Петров Петр", Истина);
// Условие: если текущий пользователь это НЕ Иванов И это НЕ Петров
Если ТекущийПользователь <> Пользователь1 И ТекущийПользователь <> Пользователь2 Тогда
Объект.Статус = ПредопределенноеЗначение("Перечисление.ХХХ_ВидыВнутреннихПеремещений.ПустаяСсылка");
Сообщить("У вас недостаточно прав для установки статуса 'Согласовано'!");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Метод с очисткой значения в ПриИзменении не совсем удобен для пользователя: он сначала выбирает значение, а программа его тут же «стирает». Это создает плохой пользовательский опыт (UX). Разберем, как перехватить выбор еще до того, как значение попадет в реквизит, используя событие ОбработкаВыбора.
Этот способ позволяет отменить стандартную обработку, если пользователю запрещено выбирать данное значение:
&НаКлиенте
Процедура СтатусОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Если ВыбранноеЗначение = ПредопределенноеЗначение("Перечисление.ХХХ_ВидыВнутреннихПеремещений.Согласованно") Тогда
Если Не ПроверитьПравоСогласованияНаСервере() Тогда
СтандартнаяОбработка = Ложь; // Отменяем выбор
ПоказатьПредупреждение(, "Вам запрещено устанавливать статус 'Согласовано'");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Проанализируем еще более изящный метод: зачем показывать пользователю статус в выпадающем списке, если он все равно не может его выбрать? Мы можем программно сформировать список доступных значений при открытии формы.
Посмотрим, как это реализовать в процедуре ПриСозданииНаСервере:
Статус свойство РежимВыбораИзСписка в значение Истина.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Очищаем стандартный список
Элементы.Статус.СписокВыбора.Очистить();
// Добавляем общие для всех статусы
Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.Проект);
Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.НаУтверждении);
// Проверяем права на специальный статус
Если ПравоУстановкиСтатусаСогласовано() Тогда
Элементы.Статус.СписокВыбора.Добавить(Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно);
КонецЕсли;
КонецПроцедуры
Важно обратить внимание на критическую ошибку в коде автора — использование НайтиПоНаименованию("Пользователь 1"). Выясним, почему это плохо: во-первых, администратор может изменить имя пользователя в справочнике, и код перестанет работать. Во-вторых, в базе могут оказаться два полных тезки. В-третьих, если список согласующих расширится до 10 человек, ваш код превратится в огромную нечитаемую простыню из условий И.
Рекомендуемые альтернативы хардкоду:
ПравоУстановкиСтатусаСогласовано. В коде проверяйте право функцией РольДоступна("..."). Это позволит управлять доступом через стандартные профили групп доступа без изменения кода.ПараметрыСеанса.ТекущийПользователь, это работает быстрее и надежнее.Помните, что все проверки на форме — это лишь интерфейсные ограничения. Пользователь может изменить статус документа через «Групповое изменение реквизитов» или с помощью внешней обработки. Чтобы обеспечить 100% надежность, необходимо продублировать проверку на уровне сервера в модуле объекта (или в подписке на событие ПередЗаписью).
// В модуле объекта документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Сравниваем старое значение из базы с новым
Если Статус = Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно
И Ссылка.Статус <> Перечисления.ХХХ_ВидыВнутреннихПеремещений.Согласованно Тогда
Если Не ПользовательИмеетПравоСогласования() Тогда
Отказ = Истина;
Сообщить("Недостаточно прав для перевода документа в статус 'Согласовано'!");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Подводя итог, наиболее профессиональным подходом будет сочетание ограничения списка выбора на форме (для удобства пользователя) и жесткой проверки в модуле объекта (для безопасности данных), основываясь при этом на ролевой модели, а не на именах конкретных сотрудников.