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