Как сохранить причину отмены проведения документа при возникновении ошибки

Программист Управленческий учет Торговля и дистрибуция
← На главную

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

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

Метод 1. Изменение бизнес-логики: переход на систему статусов

Проанализируем ситуацию: часто жесткая отмена проведения — это не единственный выход. Вместо того чтобы полностью блокировать запись документа при ошибке, мы можем позволить документу «провестись» технически, но изменить его статус. Это наиболее надежный и архитектурно правильный подход для сложных систем автоматизации.

Рассмотрим алгоритм реализации этого метода:

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

Таким образом, документ остается в базе, а операторы видят его в списке по фильтру и могут оперативно исправить проблему. Это исключает потерю данных, так как транзакция завершается успешно.

Метод 2. Использование фоновых заданий для «выхода» из транзакции

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

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


ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ЭтотОбъект.Ссылка);
ПараметрыЗадания.Добавить("Ошибка: Расхождение цены при смене штрихкода");

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

В общем модуле процедура будет выглядеть следующим образом:


Процедура ЗаписатьПричинуОткатаВРегистр(ДокументСсылка, ТекстОшибки) Экспорт
    МенеджерЗаписи = РегистрыСведений.Логи ОшибокПроведения.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Период = ТекущаяДата();
    МенеджерЗаписи.Документ = ДокументСсылка;
    МенеджерЗаписи.ОписаниеОшибки = ТекстОшибки;
    МенеджерЗаписи.Записать();
КонецПроцедуры

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

Метод 3. Обработка исключений в вызывающем коде

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

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


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

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

Метод 4. Использование ДополнительныхСвойств для вывода в форму

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

В модуле объекта в процедуре ОбработкаПроведения мы можем заполнить это свойство:


Если НедостаточноОстатков Тогда
    ЭтотОбъект.ДополнительныеСвойства.Вставить("ТекстОшибкиДляПользователя", "Не хватает товара на складе!");
    Отказ = Истина;
КонецЕсли;

Затем в модуле формы документа, в обработчике ПослеЗаписиНаСервере, мы можем прочитать это свойство и вывести сообщение пользователю, используя ПоказатьОповещениеПользователя или установив значение программного реквизита формы. Это позволит оператору сразу увидеть «человеческое» описание причины, а не системное сообщение о нарушении транзакции.

Метод 5. HTTP-сервисы как независимый регистратор

Для высоконагруженных систем, где работа с фоновыми заданиями может создавать избыточную очередь, рассмотрим продвинутый вариант — использование внутреннего HTTP-сервиса.

При возникновении ошибки проведения код 1С выполняет HTTP-запрос (POST) к самой себе. HTTP-соединение устанавливается с новым сеансом, который мгновенно записывает лог в независимую таблицу или даже во внешнюю базу данных (например, ClickHouse или Elasticsearch для анализа логов). Поскольку HTTP-вызов — это внешнее по отношению к СУБД действие, откат транзакции в 1С никак не может повлиять на данные, уже отправленные по сети.

Резюме и рекомендации

Выяснив причину сложности — атомарность транзакций, мы определили несколько путей решения:

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

← На главную