Как программно определить отказ в проведении документа и прервать выполнение кода?

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

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

Анализ проблемы: почему стандартный вызов не всегда очевиден

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

Способ 1. Использование конструкции Попытка...Исключение

Это наиболее надежный и распространенный метод в среде 1С. Проведение документа — это операция, которая в случае неудачи (установки Отказ = Истина) инициирует исключительную ситуацию с точки зрения платформы, если транзакция не может быть завершена. Проанализируем пример кода:


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

Важный нюанс: использование Попытки позволяет не только остановить выполнение, но и корректно обработать системные ошибки (например, блокировки базы данных или ошибки конфигурации), которые не связаны напрямую с бизнес-логикой остатков.

Способ 2. Проверка свойства Проведен

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


ПеремещениеТМЦ.Заполнить(Объект.Ссылка);
ПеремещениеТМЦ.Записать(РежимЗаписиДокумента.Проведение);

Если НЕ ПеремещениеТМЦ.Проведен Тогда
    Сообщить("Внимание: документ не был проведен. Операция прервана.");
    Возврат;
Конецесли;

Здесь мы анализируем свойство Проведен самого объекта. Если транзакция записи была прервана из-за установки флага Отказ в модуле документа, свойство Проведен останется равным Ложь. Однако стоит учитывать, что если документ уже был проведен ранее и вы пытаетесь его перепровести, этот метод может потребовать более тщательной проверки (сравнения версии данных или использования дополнительных флагов).

Способ 3. Рефакторинг: Переход от процедур к функциям

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


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

// Вызывающая процедура
Процедура ВыполнитьВсякуюЕрунду()
    
    Если НЕ СоздатьИПровестиПеремещение(МоиПараметры) Тогда
        // Если функция вернула Ложь, прекращаем работу
        Возврат;
    КонецЕсли;
    
    // Продолжаем работу...
    
КонецПроцедуры

Способ 4. Передача флага ошибки через параметры (структура)

Если вам необходимо возвращать не просто «Да/Нет», а подробную информацию об ошибке или ссылку на созданный документ (даже если он не провелся), удобно использовать структуру в качестве параметра процедуры. Это позволяет обойти ограничения процедур, которые не возвращают значения напрямую.


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

// Использование
Контейнер = Новый Структура("Успех, Ссылка, ТекстОшибки", Ложь, Неопределено, "");
СоздатьДокументПеремещениеТМЦ(Контейнер);

Если НЕ Контейнер.Успех Тогда
    Сообщить("Проблема: " + Контейнер.ТекстОшибки);
    Возврат;
КонецЕсли;

Различие между Отказом и Исключением

В процессе обсуждения возник важный методологический спор: чем отличается Отказ от Исключения? Разберем по шагам:

  1. Отказ: Это переменная логического типа, доступная в обработчиках событий (ПередЗаписью, ОбработкаПроведения). Установка Отказ = Истина сигнализирует платформе о необходимости отмены транзакции.
  2. Исключение: Это программное прерывание потока выполнения. Метод Записать() при неудаче проведения генерирует именно исключение, которое «пробрасывается» в вызывающий код.

Следовательно, если вы вызываете Записать(РежимЗаписиДокумента.Проведение) и в модуле документа сработал Отказ, то выполнение кода сразу перейдет в блок Исключение (если он есть) или остановится с системной ошибкой. Именно поэтому блок Попытка...Исключение считается наиболее «чистым» способом решения задачи.

Дополнительные рекомендации

Для повышения качества кода проанализируем еще несколько приемов:

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

← На главную