Почему не проводится и не записывается документ 1С при программном создании

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

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

Анализ исходного кода и типичные ошибки

Рассмотрим фрагмент кода, в котором возникает описанное поведение:


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

Проанализируем ключевые недочеты в приведенном фрагменте, которые приводят к сбоям:

  1. Подавление исключений без логирования. Конструкция Попытка ... Исключение с пустым блоком обработки скрывает реальную ошибку среды исполнения. Когда в процессе присвоения значений или записи объекта происходит сбой, управление мгновенно передается в ветку Исключение. Цикл может завершиться или прерваться, а программист не видит первопричину, считая, что запись не происходит без видимых причин.
  2. Дублирование вызова метода записи. Вызов НовыйДокумент.Записать() непосредственно перед НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение) является избыточным. Второй вызов инициирует повторный цикл событий объекта (ПередЗаписью, ПриЗаписи, ОбработкаПроведения). Это создает двойную нагрузку на СУБД и может приводить к коллизиям блокировок.
  3. Избыточное разыменование ссылок. Передача параметра в запрос вида ЭтотОбъект.Проект.Ссылка избыточна, так как реквизит Проект уже содержит ссылку на справочник или документ. Достаточно передавать ЭтотОбъект.Проект.

Выясним скрытые причины падения при записи и проведении

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

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

Правильная диагностика и перехват ошибок

Для того чтобы увидеть реальную причину остановки выполнения, необходимо отказаться от пустого блока исключения. Разберем, как правильно организовать диагностику:

  1. Включение остановки по ошибке в конфигураторе. В меню конфигуратора открываем пункт Отладка и выбираем Останавливаться по ошибке. Это заставит платформу прервать выполнение именно на той строке, где возникает исключение, даже если она обернута в блок перехвата.
  2. Логирование ошибки в Журнал регистрации. Если необходимо продолжить обработку других строк выборки при сбое на одном документе, текст исключения обязательно записывается в журнал регистрации или выводится в консоль сообщений.

Посмотрим на пример правильной обработки исключения:


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

Оптимальный алгоритм программного создания и проведения документов

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТаблицаДанных.Контроллер КАК Контроллер
    |ИЗ
    |   Справочник.Проекты КАК ТаблицаДанных
    |ГДЕ
    |   ТаблицаДанных.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Проект);

Выборка = Запрос.Выполнить().Выбрать();

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

Запись без проведения при первичной загрузке данных

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


НовыйДокумент = Документы.рм_обзвон_задача.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Контроллер = Выборка.Контроллер;

НовыйДокумент.ОбменДанными.Загрузка = Истина;
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

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

← На главную