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