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