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

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

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

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

Для начала проанализируем, в какой именно момент должна происходить проверка статуса. У нас есть два основных варианта в модуле объекта: процедура ОбработкаПроведения и процедура ПередЗаписью. На форуме в сообщении №4 справедливо замечено, что проверка «после» (например, в процедуре ПриЗаписи) уже не имеет смысла, так как транзакция может быть близка к завершению или данные уже зафиксированы.

Рассмотрим вариант с процедурой ОбработкаПроведения. Этот метод вызывается непосредственно в момент формирования движений документа по регистрам. Если мы установим здесь запрет, документ не будет проведен. Однако более правильным с точки зрения производительности и экономии ресурсов системы является использование события ПередЗаписью. Почему? Потому что ОбработкаПроведения вызывается уже после того, как система выполнила часть работы по записи объекта и очистке старых движений. Прерывание процесса в ПередЗаписью происходит раньше, что минимизирует нагрузку на базу данных.

Реализация логики в модуле объекта (метод ПередЗаписью)

Разберем по шагам, как написать код в процедуре ПередЗаписью. Нам необходимо убедиться, что документ записывается именно в режиме проведения, и проверить значение реквизита Статус. Посмотрим на пример кода:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем, что пользователь нажал именно "Провести"
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        
        // Сравниваем статус документа с необходимым значением из перечисления
        Если Статус <> Перечисления.СтатусыДокументов.Согласована Тогда
            
            // Устанавливаем флаг Отказ, чтобы прервать запись и проведение
            Отказ = Истина;
            
            // Информируем пользователя о причине ошибки
            Сообщить("Документ не может быть проведен, так как он не согласован!");
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание на использование параметра Отказ = Истина. Это критически важный момент. Просто использовать Возврат, как предлагалось в некоторых сообщениях на форуме, недостаточно, так как система не получит сигнал о необходимости отмены транзакции. Только установка Отказ в значение Истина гарантирует, что документ останется в прежнем состоянии.

Использование подписок на события для типовых конфигураций

Если вы работаете с типовой конфигурацией (например, 1С:Управление торговлей или ERP) и не хотите снимать документ с поддержки, проанализируем ситуацию с использованием Подписок на события. Это более профессиональный подход, который позволяет внедрить логику, не меняя код самого объекта.

Для этого создадим новый объект метаданных «Подписка на событие». В качестве источника выберем ваш документ (или несколько типов документов), а в качестве события — ПередЗаписью. Далее создадим общий модуль, в котором опишем процедуру проверки.


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

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

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

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если документ уже проведен и мы пытаемся его просто записать или перепровести
    Если Проведен Тогда
        
        // Получаем старое значение статуса из базы данных
        СтатусВБазе = Ссылка.Статус;
        
        // Если в базе был статус "Согласована", а теперь он изменился
        Если СтатусВБазе = Перечисления.СтатусыДокументов.Согласована 
            И Статус <> Перечисления.СтатусыДокументов.Согласована Тогда
            
            Отказ = Истина;
            Сообщить("Нельзя отменить согласование у проведенного документа! Сначала отмените проведение.");
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Улучшение пользовательского интерфейса (UX)

Проанализируем ситуацию с точки зрения удобства пользователя. Всегда лучше предотвратить ошибку, чем выдавать сообщение о ней после совершения действия. Если статус документа не позволяет его проводить, логично сделать кнопку Провести недоступной на форме.

В модуле формы документа, в процедуре ПриЧтенииНаСервере или в обработчике изменения статуса, мы можем управлять доступностью кнопок. Рассмотрим пример кода для формы:


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

Такой подход делает интерфейс более «отзывчивым» и понятным для бухгалтера или менеджера, так как система сразу визуально ограничивает недопустимые действия.

Заключение

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

← На главную