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