События объектов
События — это точки, в которых платформа «спрашивает» ваш код: всё ли в порядке, прежде чем записать, провести или удалить объект.
Обработчик события — процедура с зарезервированным именем в модуле объекта, которую платформа вызывает автоматически в определённый момент жизни объекта. Вы не вызываете её сами — её вызывает система, а вы лишь описываете, что должно произойти.
В прошлом уроке мы выяснили, что бизнес-правила объекта живут в модуле объекта. События — это и есть механизм, через который эти правила подключаются. Идея проста и мощная: платформа сама, в нужный момент, заглядывает в модуль объекта, и если находит там процедуру с определённым именем — выполняет её. Хотите вмешаться в запись документа? Опишите процедуру ПередЗаписью. Хотите проверить перед удалением? — ПередУдалением. Разберём главные события и, что критично, порядок их вызова.
Зачем перехватывать события
Без событий объект вёл бы себя одинаково для всех: записался — и записался. Но реальная учётная логика полна условий. Нельзя провести отгрузку, если товара нет на складе. Нельзя удалить контрагента, по которому есть долги. При записи заказа нужно автоматически посчитать сумму. Всё это — вмешательство в стандартное поведение, и события дают для него аккуратные, предсказуемые точки входа. Вы не переписываете платформу — вы вешаете свои проверки на её «крючки».
ПередЗаписью — последний рубеж проверки
Событие ПередЗаписью срабатывает, когда объект уже готов записаться, но в базу ещё ничего не попало. Это идеальное место для валидации. У обработчика есть параметр Отказ: присвоив ему Истина, вы отменяете всю запись целиком.
Процедура ПередЗаписью(Отказ)
Если Сумма <= 0 Тогда
Сообщить("Сумма документа должна быть больше нуля");
Отказ = Истина;
Возврат; // дальше проверять нет смысла
КонецЕсли;
Если Дата > ТекущаяДата() Тогда
Сообщить("Нельзя проводить документ будущей датой");
Отказ = Истина;
КонецЕсли;
КонецПроцедурыОбратите внимание на экранированные операторы сравнения: <= и >. В коде 1С это обычные «меньше-равно» и «больше», просто в HTML урока они записаны безопасно.
ПриЗаписи — данные уже в транзакции
Событие ПриЗаписи наступает после того, как объект записался, но пока ещё внутри той же транзакции. Здесь тоже есть Отказ, и если его выставить, транзакция откатится — запись как будто и не было. Разница с ПередЗаписью в том, что тут объект уже существует в базе, и можно, например, обновить связанные данные, зная его ссылку.
Процедура ПриЗаписи(Отказ)
// логируем факт записи в регистр сведений
Запись = РегистрыСведений.ЖурналИзменений.СоздатьМенеджерЗаписи();
Запись.Документ = Ссылка;
Запись.Дата = ТекущаяДата();
Запись.Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
Запись.Записать();
КонецПроцедурыОбработкаПроведения — сердце документа
Для документов главное событие — ОбработкаПроведения. Проведение — это отражение документа в учёте: списание товара со склада, движение денег, начисление. В этом обработчике формируются движения по регистрам. Параметр Режим подсказывает, проводится документ оперативно или нет, а Отказ позволяет запретить проведение.
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.ОстаткиТоваров.Записывать = Истина;
Для Каждого СтрокаТовары Из Товары Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = СтрокаТовары.Номенклатура;
Движение.Количество = СтрокаТовары.Количество;
КонецЦикла;
КонецПроцедурыИменно здесь документ перестаёт быть «просто записью» и начинает влиять на остатки, обороты, балансы. Если ОбработкаПроведения пуста — документ проводится, но в учёте ничего не меняется.
ПередУдалением — защита от потери данных
Событие ПередУдалением срабатывает при непосредственном удалении объекта. Здесь уместно запретить удаление, если объект где-то используется.
Процедура ПередУдалением(Отказ)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка
|ИЗ Документ.РасходнаяНакладная
|ГДЕ Контрагент = &Контрагент";
Запрос.УстановитьПараметр("Контрагент", Ссылка);
Если Не Запрос.Выполнить().Пустой() Тогда
Сообщить("Нельзя удалить: по контрагенту есть накладные");
Отказ = Истина;
КонецЕсли;
КонецПроцедурыКак это работает: порядок вызова
Порядок событий — не абстракция, а то, от чего зависит корректность программы. При записи проведённого документа платформа выполняет их строго последовательно:
| № | Событие | Момент |
| 1 | ПередЗаписью | объект готов, в базе ещё ничего нет |
| 2 | ПриЗаписи | объект записан, транзакция открыта |
| 3 | ОбработкаПроведения | формируются движения по регистрам |
Всё это — внутри одной транзакции. Если на любом шаге выставить Отказ = Истина, транзакция откатывается целиком: ни запись, ни движения не сохранятся. Это свойство транзакционности бесценно — оно гарантирует, что в базе не окажется «полузаписанного» документа с движениями, но без шапки, или наоборот. Либо всё, либо ничего.
Отмена проведения устроена зеркально: платформа удаляет ранее сделанные движения, а вы можете подключиться к событию ОбработкаУдаленияПроведения, если нужно откатить что-то ещё.
Частые ошибки
- Забывают
ВозвратпослеОтказ = Истина. Код продолжает выполняться, обращается к незаполненным данным и падает с новой ошибкой, маскируя настоящую причину. Выставили отказ — прервите обработчик. - Путают
ПередЗаписьюиОбработкаПроведения. Движения по регистрам формируют только вОбработкаПроведения. Попытка писать движения вПередЗаписьюлибо не сработает, либо приведёт к дублям. - Тяжёлые запросы в обработчике записи. Каждое событие выполняется внутри транзакции и держит блокировки. Долгий запрос в
ПередЗаписьютормозит всех, кто ждёт эти же данные. - Проверяют пользовательский ввод в
ПередЗаписью, а не в форме. Технически работает, но пользователь узнаёт об ошибке слишком поздно — при попытке записи. Мелкие подсказки лучше давать сразу в форме, а в модуле объекта оставлять жёсткие бизнес-правила.
Итоги
- Обработчик события — процедура с зарезервированным именем в модуле объекта; вызывает её платформа, а не вы.
ПередЗаписью— валидация до записи;ПриЗаписи— действия после записи в той же транзакции.ОбработкаПроведения— формирование движений по регистрам, «отражение в учёте».ПередУдалением— защита от удаления используемых объектов.- Параметр
Отказ = Истинаотменяет операцию и откатывает транзакцию целиком. - Порядок при проведении:
ПередЗаписью→ПриЗаписи→ОбработкаПроведения, всё в одной транзакции.