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

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

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

Разберем подробнее причины такого поведения платформы и проанализируем доступные способы решения этой задачи.

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

Выясним, почему платформа 1С отменяет записи в справочнике. Операции записи и проведения объекта выполняются в рамках единой неявной транзакции СУБД. В эту транзакцию последовательно входят события модуля объекта:

  1. ПередЗаписью
  2. ПриЗаписи
  3. ОбработкаПроведения

Если на любом из этапов устанавливается Отказ = Истина или возникает необработанная ошибка, платформа автоматически вызывает отмену транзакции. Все изменения в базе данных, сделанные с момента начала проведения, аннулируются. Чтобы данные справочника сохранились, необходимо выполнить их запись за пределами транзакции проведения документа.

Способ 1. Использование события формы «ПередЗаписьюНаСервере»

Если документ проводится пользователем интерактивно из управляемой формы, мы можем применить событие формы ПередЗаписьюНаСервере. Это событие вызывается до открытия транзакции записи документа в СУБД.

Запись справочника, выполненная в этом событии, фиксируется в базе данных отдельной самостоятельной транзакцией. Если в дальнейшем проведение документа завершится отказом, созданный или измененный элемент справочника останется в базе.

Посмотрим на пример кода в модуле формы документа:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        
        // Записываем данные в справочник до начала транзакции проведения
        ОбъектСправочника = Справочники.СобытияПроведения.СоздатьЭлемент();
        ОбъектСправочника.Наименование = "Попытка проведения: " + ТекущийОбъект.Ссылка;
        ОбъектСправочника.ДатаСобытия = ТекущаяДата();
        ОбъектСправочника.Записать();
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 2. Использование события «ОбработкаПроверкиЗаполнения»

Рассмотрим еще одно событие, которое выполняется вне основной транзакции записи — ОбработкаПроверкиЗаполнения в модуле объекта или форме. Платформа вызыват проверку заполнения перед стартом записи и проведения.

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

Способ 3. Выполнение через фоновое задание

Фоновое задание исполняется в отдельном сеансе на сервере со своей независимой транзакцией. Если из процедуры ПередЗаписью или ОбработкаПроведения запустить фоновое задание, передав ему нужные параметры, отмена транзакции документа не повлияет на работу фонового задания.

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


ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(Ссылка);
ПараметрыЗадания.Добавить("Результат анализа условий");

ФоновыеЗадания.Выполнить("ОбщийМодульСервер.ФиксацияРезультатаВСправочник", ПараметрыЗадания);

Особенности работы фонового задания:

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

Способ 4. Программный перехват в блоке «Попытка ... Исключение»

Если документ проводится программно (например, из обработки или другого документа), записать данные в справочник после отказа можно с помощью обработки исключений.

Разберем пример кода:


Попытка
    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
    // Транзакция проведения отменена, мы находимся за ее пределами
    ОбъектСправочника = Справочники.ЛогОшибок.СоздатьЭлемент();
    ОбъектСправочника.Наименование = "Отказ проведения " + ДокументОбъект.Ссылка;
    ОбъектСправочника.Записать();
КонецПопытки;

После возникновения ошибки или отката проведение прерывается, и управление передается в блок Исключение, где транзакция проведения уже закрыта, что позволяет свободно производить запись любых объектов.

Способ 5. Вызов HTTP-сервиса

Для гарантированного сохранения данных при любом виде проведения (как интерактивном, так и программном) прямо из модуля документа можно применить вызов собственного HTTP-сервиса базы. Обращение к HTTP-сервису создает новое соединение на сервере вне текущей транзакции, гарантируя независимую запись данных.

Пересмотр логики и архитектурного подхода

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

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

  1. Журнал регистрации: запись через функцию ЗаписатьСобытиеЖурналаРегистрации() выполняется вне транзакций СУБД и сохраняется всегда.
  2. Независимый регистр сведений: для хранения структурированных технических данных.
← На главную