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