В каком обработчике событий 1С лучше изменять значение реквизита документа?

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

Часто при разработке в 1С возникает задача: изменить или заполнить определенный реквизит документа непосредственно в момент его записи. Например, необходимо установить значение реквизита в зависимости от курса валюты на текущий день. Рассмотрим подробнее, какой обработчик событий выбрать для этой цели и почему некоторые интуитивно понятные варианты могут привести к ошибкам.

Почему не стоит использовать обработчик ПриЗаписи?

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

Выясним причину такого поведения. В событии ПриЗаписи платформы 1С физическая запись данных в таблицы базы данных уже выполнена, хотя общая транзакция записи еще не закрыта. Любые изменения реквизитов, которые мы производим в этом обработчике, применяются исключительно к экземпляру объекта в оперативной памяти (в кэше). База данных об этих изменениях ничего не знает.

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

Правильное решение: обработчик ПередЗаписью

Разберем по шагам правильный подход. Для модификации объекта перед его сохранением в базу данных необходимо использовать серверный обработчик ПередЗаписью в модуле объекта. В этот момент данные еще не отправлены в СУБД, и любые изменения реквизитов будут штатно сохранены в рамках текущей транзакции.

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

Альтернативные варианты и лучшие практики (UX/UI)

Посмотрим на другие способы реализации логики обновления реквизитов, которые могут быть более предпочтительными с точки зрения пользовательского опыта:

  1. События формы (ПриИзменении): Изменение зависимых от курса реквизитов лучше всего отрабатывать непосредственно в модуле управляемой формы. Если курс привязан к дате, логично использовать обработчики ПриИзменении для полей «Дата» и «Валюта». Это позволит пользователю увидеть новые значения на экране сразу, еще до нажатия кнопки записи.
  2. Событие ОбработкаЗаполнения: Если реквизит нужно инициализировать актуальным курсом при создании совершенно нового документа (на основании или копированием), получение курса следует вынести в обработчик модуля объекта ОбработкаЗаполнения.
  3. Событие ПередЗаписью на форме: Если перед изменением реквизита требуется интерактивное подтверждение (например, вопрос пользователю: "Пересчитать суммы по новому курсу?"), логику следует реализовывать в клиентском обработчике ПередЗаписью в модуле формы. Серверные модули объекта (включая подписки) не умеют взаимодействовать с пользователем и выводить окна сообщений.

Ограничения платформы и производительность

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

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

Использование механизма расширений

Если для решения задачи вы решили использовать расширение конфигурации (чтобы не усложнять дальнейшие обновления основной базы), для изменения реквизита перед записью следует использовать перехват метода с аннотацией &Перед. Это позволит выполнить ваш код до стандартного обработчика записи.

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

← На главную