Как правильно запретить сохранение или проведение документа через расширение в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке расширений для конфигураций на платформе «1С:Предприятие 8.3» программисты часто сталкиваются с необходимостью ограничить права пользователей на запись или проведение конкретных документов. Казалось бы, задача простая: нужно перехватить процедуру записи и установить флаг Отказ = Истина. Однако на практике это часто приводит к появлению системных ошибок типа «ОшибкаХранимыхДанных», которые пугают пользователей и не дают информативного описания проблемы. В этой статье мы подробно разберем, почему так происходит, и как реализовать запрет «научно» и корректно.

Разберем причину ошибки «ОшибкаХранимыхДанных»

Когда мы устанавливаем Отказ = Истина в процедуре ПередЗаписью модуля объекта (даже через расширение), мы фактически приказываем платформе отменить уже начатую транзакцию записи в базу данных. Для платформы 1С (особенно в версиях 8.3.15 и выше) любая отмена транзакции в модуле объекта — это исключительная ситуация. Платформа интерпретирует это как невозможность сохранения данных и выводит техническое сообщение «ОшибкаХранимыхДанных».

Проанализируем ситуацию: пользователь нажимает кнопку «Провести и закрыть», срабатывает ваш код в расширении, транзакция прерывается, и вместо вашего лаконичного сообщения «Вам запрещено!» система выдает громоздкое окно с кодом ошибки. Чтобы этого избежать, нам нужно изменить подход к тому, где и как выполнять проверку.

Выбор между модулем формы и модулем объекта

Первое правило качественной разработки в 1С: интерактивные проверки должны выполняться в форме, а проверки целостности данных — в объекте.

  1. Модуль формы: Если нам нужно запретить конкретному пользователю нажимать кнопку в интерфейсе, лучше всего делать это в обработчике ПередЗаписьюНаСервере модуля формы. В этом случае транзакция базы данных еще не начата, и установка флага Отказ = Истина приведет к спокойной остановке процесса без системных алертов.
  2. Модуль объекта: Здесь проверку стоит оставлять только как «последний рубеж» для защиты от программной записи (например, через загрузку данных или внешние обработки).

Рассмотрим, как правильно реализовать проверку в расширении формы документа. Мы будем использовать аннотацию &Перед, чтобы не затирать типовую логику конфигурации.


&НаСервере
&Перед("ПередЗаписьюНаСервере")
Процедура Р1_ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверяем наличие настройки запрета у пользователя
    Запрет = УправлениеСвойствами.ЗначениеСвойства(ПользователиКлиентСервер.ТекущийПользователь(), "ЗапретНаКнопкуСохранитьВРеализации");
    
    Если Запрет Тогда
        Отказ = Истина;
        // Используем стандартный метод сообщения пользователю
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Вам запрещено сохранять данный документ согласно корпоративной политике.");
    КонецЕсли;
    
КонецПроцедуры

Почему аннотация &Перед лучше, чем &Вместо?

Использование &Вместо — это радикальный метод. Проанализируем риски: если вы полностью замещаете типовую процедуру ПередЗаписью, вы берете на себя ответственность за выполнение всех системных механизмов, которые были там прописаны (проверки заполнения, подписки на события, расчеты). Если фирма «1С» обновит типовой код в этом месте, ваше расширение продолжит выполнять старый код, что может привести к непредсказуемым ошибкам в учете.

Используя &Перед, мы встраиваемся в цепочку вызовов. Если наш код установит Отказ = Истина, выполнение основной (типовой) процедуры даже не начнется, что безопасно и эффективно.

Работа с модулем объекта через расширение

Если вы все же решили делать проверку в модуле объекта (например, чтобы запретить и программное создание документов), используйте следующий шаблон в расширении модуля документа:


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

Чтобы избежать некрасивой системной ошибки при работе в модуле объекта, некоторые разработчики применяют метод ВызватьИсключение. Рассмотрим этот пример:


Если Запрет Тогда
    ВызватьИсключение "Действие заблокировано системой безопасности: недостаточно прав для сохранения реализации.";
КонецЕсли;

В этом случае платформа покажет окно с вашим текстом, но это всё равно будет выглядеть как «авария» приложения. Поэтому метод с формой остается приоритетным для UX (пользовательского опыта).

Как запретить пометку удаления в списке

Часто задача звучит шире: запретить не только запись, но и удаление документа. Если пользователь попытается пометить документ на удаление из списка, процедура формы документа не сработает. Посмотрим, как решить эту задачу.

Для этого в расширении модуля объекта необходимо анализировать изменение свойства ПометкаУдаления. Мы сравниваем текущее состояние объекта с тем, что записано в базе данных.


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

«Научный» подход: Роли и RLS

Самый правильный и надежный способ — это использование механизма ролей. В расширении вы можете создать свою роль и настроить права доступа к объекту. Если у пользователя нет права «Интерактивное проведение» или «Интерактивная пометка удаления», платформа сама заблокирует соответствующие кнопки в интерфейсе.

Преимущества работы через роли:

Подводя итог, можно сказать: если ваша цель — быстрое решение «здесь и сейчас», используйте &Перед("ПередЗаписьюНаСервере") в модуле формы. Если вы строите серьезную систему разграничения прав — используйте роли в расширении.

← На главную