При разработке учетных механизмов в 1С:Предприятии разработчики иногда сталкиваются со специфической задачей: если проведение документа завершилось неудачно (например, обнаружены расхождения в остатках или спецификациях), необходимо автоматически создать корректирующий или сигнальный документ. Разберем особенности транзакционной модели 1С, почему невозможно создать документ непосредственно внутри обработчика с флагом отмены, и рассмотрим правильные варианты реализации данной логики.
Проанализируем, как платформа 1С выполняет запись и проведение документов. Обработчик ОбработкаПроведения всегда выполняется внутри неявной транзакции базы данных. Если в коде устанавливается значение Отказ = Истина или возникает исключение, платформа инициирует автоматический откат (Rollback) транзакции.
Важно понимать:
ЗафиксироватьТранзакцию() внутри событий объекта приведет к синтаксической или критической ошибке выполнения, так как транзакцией записи управляет сама платформа.ЗаписьЖурналаРегистрации).Поэтому попытка вызвать НовыйДокумент.Записать() внутри процедуры ОбработкаПроведения при установке Отказ = Истина не приведет к созданию документа — его запись будет откатана вместе с проведением исходного документа.
Фоновое задание выполняется в отдельном сеансе на сервере со своим собственным независимым транзакционным пространством. Если перед установкой флага Отказ = Истина передать необходимые данные и запустить фоновое задание, откат транзакции в текущем сеансе никак не повлияет на работу фонового процесса.
Посмотрим на пример реализации передачи параметров и создания документа в фоновом задании:
// В модуле объекта документа
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Проверяем наличие расхождений
Если ЕстьРасхожденияСЗаказом() Тогда
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(Ссылка);
ПараметрыЗадания.Добавить(ПолучитьТаблицуРасхождений());
// Запуск создания корректировки в отдельном транзакционном контексте
ФоновыеЗадания.Выполнить("ОбщийМодульСервер.СоздатьКорректировкуФоново", ПараметрыЗадания);
Отказ = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Выявлены расхождения. Документ не проведен, создается корректировка.";
Сообщение.Сообщить();
Возврат;
КонецЕсли;
КонецПроцедуры
Разберем код фоновой процедуры в общем серверном модуле:
Процедура СоздатьКорректировкуФоново(ДокументОснование, ТаблицаРасхождений) Экспорт
ДокКорректировка = Документы.КорректировкаВнутреннегоЗаказа.СоздатьДокумент();
ДокКорректировка.Дата = ТекущаяДатаСеанса();
ДокКорректировка.ДокументОснование = ДокументОснование;
ДокКорректировка.Товары.Загрузить(ТаблицаРасхождений);
Попытка
ДокКорректировка.Записать(РежимЗаписиДокумента.Запись);
Исключение
ЗаписьЖурналаРегистрации("СозданиеКорректировки", УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Если операция всегда выполняется интерактивно пользователем, можно переопределить стандартную команду проведения на форме. В этом случае попытка проведения оборачивается в программный вызов, и в случае неудачи создается корректирующий документ вне транзакции проведения исходного объекта.
Рассмотрим пример кода команды формы:
&НаКлиенте
Процедура КомандаПровестиИОбработать(Команда)
ПараметрыЗаписи = Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение);
Если Не ЗаписатьВФорме(ПараметрыЗаписи) Тогда
// Транзакция проведения завершилась с ошибкой и полностью откатана
СоздатьДокументКорректировкиНаСервере();
Оповестить("ОбновленыДокументы");
КонецЕсли;
КонецПроцедуры
Обратите внимание: данный подход работает только при проведении из формы объекта. Если документ проводится групповой обработкой, регламентным заданием или через контекстное меню динамического списка, данный алгоритм не сработает.
Создание документов по факту ошибки бизнес-логики часто свидетельствует о неоптимальной архитектуре учета. В типовых конфигурациях 1С (ERP, КА, УТ) для подобных сценариев применяются более надежные паттерны: