Как отследить отправку уведомлений при записи документа и смене статуса в 1С?

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

Рассмотрим распространенную задачу разработки в 1С: требуется отправлять email-уведомления определенным пользователям при создании нового документа, а также при изменении статуса этого документа (например, на статус "Закрыта"). При этом необходимо гарантированно фиксировать факт отправки, чтобы исключить повторную рассылку одних и тех же писем при перепроведении.

Многие начинающие разработчики пытаются решить эту задачу "в лоб": отправляют письмо прямо в модуле объекта и там же устанавливают булево значение (галочку) УведомлениеОтправлено = Истина. Проанализируем, почему этот подход приводит к ошибкам, потери данных и зависаниям базы, а также подробно разберем правильное архитектурное решение с использованием регистров сведений.

Разберем ошибки: почему реквизит не сохраняется в процедуре ПриЗаписи()

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

Запись документа в 1С происходит строго внутри транзакции базы данных. События распределяются следующим образом:

  1. Событие ПередЗаписью(): Выполняется до сохранения данных в СУБД. Именно здесь можно менять реквизиты текущего объекта, и они будут сохранены в базу автоматически вместе с документом.
  2. Физическая запись в базу: Платформа берет значения реквизитов из памяти и выполняет SQL-запрос INSERT или UPDATE к таблицам СУБД.
  3. Событие ПриЗаписи(): Выполняется, когда данные уже записаны в базу данных, но транзакция еще не зафиксирована.

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

Проанализируем риски отправки писем внутри транзакции записи

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

Посмотрим на проблемы, к которым это гарантированно приведет:

  1. Отсутствие номера: У нового документа в процедуре ПередЗаписью() еще может не быть номера. Если мы сформируем текст письма на этом этапе, в уведомлении будет пустое поле номера документа.
  2. Отказ при записи: Документ может не записаться из-за сбоя, нехватки прав, нарушения контроля остатков и срабатывания Отказ = Истина. Транзакция откатится, документа в базе не будет, но письмо уже уйдет получателю.
  3. Блокировки и зависания базы: Процедура ПриЗаписи() выполняется внутри открытой транзакции СУБД, удерживая эксклюзивные блокировки на таблицы. Если почтовый SMTP-сервер ответит с задержкой в 10-15 секунд (или вовсе зависнет), запись документа "повиснет" на это время. Все остальные пользователи, пытающиеся работать с этими таблицами, будут заблокированы, что может парализовать работу целого отдела.

Как правильно отследить изменение статуса документа

Для того чтобы понять, что статус поменялся именно сейчас на "Закрыта" (и нужно инициировать отправку), нам не нужны дополнительные галочки в самом документе. В 1С применяется механизм сравнения старых данных (из базы) и новых (введенных на форме пользователем).

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

Посмотрим на пример кода:


Процедура ПриЗаписи(Отказ)
    
    // Проверяем, что это новый документ
    Если ЭтоНовый() Тогда
        // Фиксируем необходимость отправить письмо о создании
        ЗафиксироватьЗадачуНаОтправку(ЭтотОбъект.Ссылка, "Создание");
    КонецЕсли;
    
    // Проверяем изменение статуса
    Если Ссылка.Статус <> Статус И Статус = Перечисления.СтатусыЗаявок.Закрыта Тогда
        // Фиксируем необходимость отправить письмо о закрытии
        ЗафиксироватьЗадачуНаОтправку(ЭтотОбъект.Ссылка, "Закрытие");
    КонецЕсли;

КонецПроцедуры

Лучшая практика: Создание очереди уведомлений через Регистр Сведений

Архитектурно верное решение задачи, принятое в качестве стандарта разработки 1С, — это паттерн "Очередь сообщений". Мы должны вынести долгий процесс (отправку email) за пределы транзакции записи документа.

Разберем по шагам, как это реализовать:

Шаг 1. Создание регистра сведений.
Создаем независимый непериодический Регистр Сведений, например, ОчередьОтправкиПисем. Добавляем измерения: Документ (тип ДокументСсылка) и ВидСобытия (Строка или Перечисление: "Создание", "Закрытие"). Добавляем ресурсы: Отправлено (Булево), КоличествоПопыток (Число), ТекстОшибки (Строка).

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

Шаг 3. Регламентное задание для рассылки.
Создаем Общий модуль (с галочкой "Сервер") и Регламентное задание, которое запускается по расписанию (например, каждые 2-3 минуты).
Внутри процедуры регламентного задания мы:

  1. Читаем из регистра записи, где Отправлено = Ложь и КоличествоПопыток < 3.
  2. В цикле формируем текст писем (тут нам уже доступен присвоенный номер документа из ссылки).
  3. Отправляем письма через интернет-почту.
  4. Если письмо отправлено успешно — устанавливаем в регистре Отправлено = Истина (или вообще удаляем запись из регистра).
  5. Если произошла ошибка — увеличиваем счетчик попыток и записываем текст ошибки для системного администратора.

Использование типовых подсистем (БСП)

Если мы ведем разработку в современных типовых конфигурациях 1С (УТ, ERP, БП, КА и др.), нам даже не придется писать регистр сведений с нуля. В них встроена Библиотека стандартных подсистем (БСП).

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

Применяя подход с асинхронной отправкой через регистры сведений и регламентные задания, мы обеспечиваем высокую стабильность системы, отказоустойчивость при сетевых сбоях и комфортную скорость работы пользователей в базе 1С.

← На главную