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