Как в 1С 7.7 получить причину ошибки при проведении документа и правильно обработать результат?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

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

Понимаем механику метода Провести()

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

Синтаксис выглядит следующим образом:

Результат = ДокОбъект.Провести(Режим, Формула);

Где Результат может принимать два значения:

  1. 1 — Документ успешно проведен.
  2. 0 — Документ не проведен (отказ в проведении).

Самая распространенная ошибка начинающих разработчиков в 1С 7.7 — это попытка проверить статус документа через метод Проведен() сразу после вызова команды проведения. Давайте разберем, почему так делать категорически нельзя.

Ловушка перепроведения: почему нельзя верить методу Проведен()

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

Рассмотрим ошибочный код, который часто встречается:


// ОШИБОЧНЫЙ ПОДХОД
ДокОбъект.Провести(); 
Если ДокОбъект.Проведен() = 0 Тогда
    Сообщить("Ошибка проведения!");
КонецЕсли;

Почему этот код неверен? Дело в том, как платформа 7.7 обрабатывает транзакции:

  1. Система начинает транзакцию проведения.
  2. Если возникает ошибка (например, СтатусВозврата(0)), транзакция откатывается (Rollback).
  3. Документ возвращается в то состояние, в котором он был до начала транзакции.
  4. Если документ был проведен до нашей попытки, он останется проведенным (со старыми движениями).

Следовательно, метод ДокОбъект.Проведен() вернет 1 (Истина), хотя наша попытка перепроведения провалилась. Программа посчитает, что все прошло успешно, но на самом деле изменения не вступили в силу.

Правильное решение: всегда ориентируйтесь только на возвращаемое значение самого метода.


// ПРАВИЛЬНЫЙ ПОДХОД
Если ДокОбъект.Провести() = 0 Тогда
    Сообщить("Не удалось провести документ: " + ДокОбъект.ТекущийДокумент());
    // Здесь обрабатываем ошибку
Иначе
    Сообщить("Успешно!");
КонецЕсли;

Почему не работает Попытка / Исключение?

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

Давайте разберем код, который не даст желаемого результата:


Попытка
    Статус = ДокОбъект.Провести();
Исключение
    Сообщить(ОписаниеОшибки()); // Сюда мы почти никогда не попадем при логических ошибках
КонецПопытки;

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

  1. Логические отказы: Это штатное поведение, запрограммированное разработчиком конфигурации. Например, проверка остатков, незаполненные реквизиты, нарушение бизнес-логики. В коде модуля проведения это реализуется через СтатусВозврата(0). Для платформы это не является "аварийной" ситуацией (Exception), это просто результат выполнения функции. Поэтому блок Исключение не сработает.
  2. Системные ошибки: Деление на ноль в модуле, синтаксические ошибки (в этом поможет технологическая проверка кода), потеря связи с SQL-сервером или критические ошибки файловой системы. Только такие ошибки могут быть пойманы через Исключение.

Таким образом, если документ не провелся из-за нехватки товара, Попытка это проигнорирует, и код пойдет дальше. Единственный способ узнать об этом — проверить возвращаемое значение метода Провести().

Как получить текст ошибки?

Это самый сложный вопрос в рамках штатного функционала 1С 7.7. Когда документ не проводится, модуль проведения обычно выводит сообщение пользователю через процедуру Сообщить(). Например: "На складе недостаточно товара Х".

Проблема в том, что этот текст уходит в окно сообщений (Message Window) и программно "достать" его из объекта ДокОбъект невозможно. Метод Провести() возвращает только 0 или 1.

Давайте рассмотрим варианты решения этой задачи.

Вариант 1. Использование внешних компонент (Рекомендуемый)

Если вам необходимо во внешней обработке получить текст причины, по которой документ не провелся, лучше всего использовать проверенные временем внешние компоненты, такие как FormEx или 1C++. Эти библиотеки расширяют возможности "семерки" и позволяют перехватывать вывод в окно сообщений.

Пример логики с использованием FormEx (псевдокод):


// Включаем перехват сообщений
Сервис = СоздатьОбъект("Сервис"); // Объект FormEx
Сервис.ПерехватСообщений(1); 

Если ДокОбъект.Провести() = 0 Тогда
    ТекстОшибки = Сервис.ПолучитьСообщения(); // Получаем то, что платформа вывела в окно
    ЗаписатьЛог("Ошибка: " + ТекстОшибки);
КонецЕсли;

Сервис.ПерехватСообщений(0); // Выключаем перехват

Вариант 2. Логирование в глобальную переменную (Без ВК)

Если использование внешних компонент невозможно, придется дорабатывать конфигурацию. Идея заключается в том, чтобы модуль проведения не просто сообщал ошибку пользователю, но и сохранял её текст куда-то, откуда его может прочитать вызывающая обработка.

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

Технические причины отказа (возврат 0 без СтатусВозврата)

Иногда возникает вопрос: может ли метод Провести() вернуть 0, если в модуле проведения нет явного СтатусВозврата(0)? Да, такие ситуации возможны, и мы должны их учитывать:

  1. Блокировки (Locking): Если таблица документа заблокирована другим пользователем или процессом (для диагностики используйте просмотр блокировок 1С 7.7 SQL), и истекло время ожидания блокировки (TimeOut), платформа прекратит попытку проведения и вернет 0.
  2. Ошибки времени выполнения: Критические ошибки кода внутри транзакции (например, деление на ноль или ошибка обращения к базе данных) прервут выполнение.
  3. Пометка на удаление: Если документ помечен на удаление (для управления этим статусом подойдет помощник удаления/распроведения документов), метод Провести() сразу вернет 0, даже не запуская модуль проведения.
  4. Нарушение уникальности: Если при проведении должен присвоиться новый номер, но он неуникален, платформа может отказать в записи и проведении.

Итоговый алгоритм безопасного проведения

Подводя итог, сформулируем универсальный алгоритм для проведения документов в 1С 7.7 во внешних обработках:


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

    // 3. Анализируем результат
    Если Результат = 0 Тогда
        Сообщить("Документ НЕ проведен! " + Док.ТекущийДокумент());
        // Здесь мы знаем, что произошел отказ. 
        // Причину ищем визуально в окне сообщений или используем FormEx для перехвата.
    Иначе
        Сообщить("Документ успешно проведен.");
    КонецЕсли;

КонецЕсли;

Используя этот подход, вы избежите ложных срабатываний при перепроведении и сможете корректно обрабатывать ситуации, когда документ не удается провести по бизнес-логике или техническим причинам.

← На главную