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