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

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

В процессе разработки часто возникает задача ограничить создание новых документов по определенным бизнес-правилам, которые не связаны напрямую с системой прав доступа. Например, можно запретить создание заказов после 18:00 или разрешить ввод только одного документа определенного вида на основании другого. При этом важно не просто запретить действие, но и понятно объяснить пользователю причину отказа, так как это напрямую влияет на пользовательский опыт при работе с программными ограничениями.

Разберем несколько способов реализации такого запрета, их преимущества, недостатки и особенности применения, в том числе используя расширения для блокировки записи объекта по условию.

Решение 1: Использование обработчика `ПриСозданииНаСервере` (Рекомендуемый способ)

Это наиболее подходящий и логичный метод для блокировки интерактивного создания документа. Этот обработчик события формы срабатывает в самый первый момент ее серверной инициализации, еще до того, как форма будет передана на клиент. Для реализации сложной логики изменения интерфейса "на лету" также может быть полезен специальный модификатор управляемых форм.

Ключевые моменты:

  1. Параметр `Отказ`: У обработчика `ПриСозданииНаСервере` есть стандартный параметр `Отказ`. Если присвоить ему значение `Истина`, платформа не будет создавать и открывать форму.
  2. Проверка на новый документ: Чтобы наш код срабатывал только при создании нового документа, а не при открытии существующего, необходимо добавить проверку. Самый надежный способ — проверить, что параметр формы `Ключ` не заполнен: Параметры.Ключ.Пустая().
  3. Информирование пользователя: Просто установить `Отказ = Истина;` — плохая практика, так как для пользователя ничего не произойдет, форма просто не откроется. Чтобы вывести сообщение, можно использовать метод ВызватьИсключение(), который прервет выполнение кода и покажет пользователю модальное окно с текстом ошибки.

Особенность при работе с расширениями:

При добавлении логики через расширение конфигурации важно использовать обработчик с суффиксом `Перед` (например, `МоеРасширение_ПриСозданииНаСервереПеред`). В обработчиках с суффиксом `После` платформа может запретить изменение стандартных параметров, таких как `Отказ`, и вы получите ошибку "Запрещено изменение параметра, отменяющего действие".

Посмотрим на итоговый пример кода, который решает задачу автора темы:


&НаСервере
// Используем обработчик "Перед", чтобы иметь возможность изменить параметр "Отказ" в расширении
Процедура МоеРасширение_ПриСозданииНаСервереПеред(Отказ, СтандартнаяОбработка)

    // Условие 1: Это новый документ?
    // Проверяем, что в параметрах формы не передан ключ существующего объекта
    Если Параметры.Ключ.Пустая() 
        // Условие 2: Выполняется ли наше бизнес-правило?
        // Например, проверяем роль пользователя и текущее время
        И РольДоступна("KMS_Склад") 
        И Час(ТекущаяДата()) >= 18 Тогда
        
        // Устанавливаем флаг отказа, чтобы форма не открылась
        Отказ = Истина;
        
        // Формируем понятный текст для пользователя
        ТекстСообщения = "Создание заказов работникам склада после 18:00 запрещено.";
        
        // Вызываем исключение, чтобы показать модальное окно с сообщением
        ВызватьИсключение(ТекстСообщения);
        
    КонецЕсли;

КонецПроцедуры

Решение 2: Использование обработчика `ОбработкаЗаполнения`

Этот обработчик события объекта, а не формы. Он срабатывает еще раньше, чем `ПриСозданииНаСервере`, в момент, когда платформа создает новый объект документа в памяти. Он тоже подходит для нашей задачи, но имеет свои нюансы и относится к альтернативным способам запрета создания объектов.

Ключевые моменты:

  1. Отсутствие параметра `Отказ`: В этом обработчике нет стандартный параметра для отмены действия.
  2. Единственный способ отмены — исключение: Чтобы прервать создание объекта и, соответственно, открытие его формы, необходимо использовать ВызватьИсключение().

В некоторых типовых конфигурациях существуют специализированные решения, позволяющие реализовать блокировку и отслеживание изменений объектов 1С непосредственно с формы. Также могут существовать процедуры вида `УправлениеДиалогомСервер.ЗапретитьОткрытиеФормыОбъекта`, которые "под капотом" реализуют сложную логику с передачей параметров и вызовом исключений.

Пример кода:


// В модуле объекта документа
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)

    // Проверяем наше условие
    Если ВыполняетсяУсловиеЗапрета() Тогда
        
        ТекстСообщения = "Создание документа запрещено по таким-то причинам.";
        // Прерываем выполнение и показываем ошибку
        ВызватьИсключение(ТекстСообщения);
        
    КонецЕсли;

КонецПроцедуры

Этот метод так же эффективен, как и первый, но размещение логики в обработчике формы (`ПриСозданииНаСервере`) часто считается более правильным с точки зрения архитектуры, так как мы управляем именно поведением интерфейса.

Другие возможные подходы

Рассмотрим еще несколько методов, которые могут быть полезны в других ситуациях.

`ПередЗаписью`

Этот обработчик позволяет отменить запись документа (`Отказ = Истина`). Однако для задачи запрета создания он не подходит, так как сработает только тогда, когда пользователь уже заполнил весь документ и нажал кнопку "Записать". Это приведет к потере времени и негативному пользовательскому опыту.

Подписка на событие `ОбработкаПолученияФормы`

Это более продвинутый и гибкий механизм. Он позволяет создать централизованную проверку для разных видов документов, не внося изменения в каждый из них. В обработчике подписки можно проанализировать тип создаваемого объекта и условия, а затем либо отменить открытие формы, либо подменить ее на свою "форму-заглушку" с сообщением.

Важное замечание: Почему не стоит использовать `РольДоступна()` для бизнес-логики

В обсуждении был поднят важный архитектурный вопрос: использование функции РольДоступна("ИмяРоли") для управления бизнес-логикой является антипаттерном. Давайте разберемся, почему.

Какие есть альтернативы?

  1. Дополнительные реквизиты пользователей/физлиц: Создайте в справочнике "Пользователи" реквизит, например, "Подразделение" или "Должность". Ваша проверка будет выглядеть так: Если ПараметрыСеанса.ТекущийПользователь.Подразделение = &Склад Тогда.... Это гораздо гибче и проще в администрировании.
  2. Параметры сеанса: При старте сеанса пользователя можно определять его принадлежность к той или иной группе и записывать это в параметр сеанса. Проверка будет быстрой и не потребует лишних запросов к базе данных.
  3. Функциональные опции: Если нужно полностью скрыть возможность создания документа для определенной группы пользователей, можно использовать функциональные опции. Вы можете настроить доступность элементов формы у пользователей, привязав видимость команды "Создать" в интерфейсе к значению опции. Это лучший вариант с точки зрения UX — пользователь даже не увидит кнопку, которую ему нельзя нажимать.
← На главную