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