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