Почему при установке Отказ = Истина в обработке проведения документа в управляемой форме 1С 8.2 вылетает ошибка вместо сообщения о непроведении?

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

При разработке и сопровождении конфигураций на платформе 1С 8.2 с использованием управляемых форм программисты часто сталкиваются с неожиданным поведением системы при попытке отменить проведение документа. В стандартной ситуации, если в процедуре ОбработкаПроведения мы устанавливаем параметр Отказ = Истина, ожидается, что система просто сообщит пользователю о том, что документ не проведен, и вернет управление без каких-либо ошибок. Однако, как показывает практика, при работе с управляемыми формами в версиях платформы 1С 8.2 (например, 8.2.17.169, 8.2.15 и других), вместо штатного сообщения о непроведении документа, мы можем получить сообщение об ошибке типа "Не удалось провести: "НазваниеДокумента"!" с кнопками "ОК" и "Подробно". При нажатии на "Подробно" выводится скупое "по причине: не удалось провести". Рассмотрим подробнее эту ситуацию, выясним ее причины и предложим возможные решения и обходные пути.

Анализ ситуации: ожидаемое и фактическое поведение

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // Предположим, у нас есть некоторая проверка
    Если Не ПроверитьУсловияПроведения() Тогда
        Отказ = Истина;
        // Оператор Возврат; часто используется для немедленного завершения процедуры,
        // но сам по себе он не является причиной ошибки, как мы выясним далее.
        Возврат;
    КонецЕсли;

    // ... далее идет код формирования движений, если Отказ = Ложь
КонецПроцедуры

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

Важно отметить, что эта проблема не связана с ошибками в коде самой процедуры ОбработкаПроведения. Мы можем воспроизвести ее, создав абсолютно новый, пустой документ без реквизитов, подписок и регистров, и просто поместив две строки Отказ = Истина; Возврат; в его процедуру ОбработкаПроведения. Проведение такого документа из его управляемой формы вызовет описанную ошибку, тогда как из формы списка или обычной формы – штатное сообщение.

Выясняем причину: особенности управляемых форм в 1С 8.2

Подобное поведение, когда установка Отказ = Истина приводит к исключению вместо стандартного сообщения, скорее всего, является особенностью реализации платформы 1С 8.2 для управляемых форм. Некоторые пользователи и статьи подтверждают, что такое поведение является "стандартным" для управляемых форм в толстом клиенте. Это может быть связано с тем, как платформа обрабатывает отмену проведения в различных режимах (обычные формы против управляемых) и с тем, что в управляемом приложении система может рассматривать отказ от проведения как исключение, если явно не предоставлено информативное сообщение пользователю.

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

Отличие поведения при проведении из разных форм

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

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

Это наблюдение подтверждает, что причина кроется именно в специфике взаимодействия между управляемой формой документа и механизмом проведения. Очевидно, что контекст вызова процедуры проведения (из какой формы был инициирован процесс) имеет значение для платформы 1С 8.2 при обработке параметра Отказ.

Рекомендации 1С по работе с параметром Отказ

Согласно стандартам и методикам разработки 1С, устанавливать параметр Отказ = Истина без информирования пользователя о причинах является неприемлемым. В таких случаях сообщение об ошибке (например, "Не удалось записать "Заказ покупателя"!") становится неинформативным и затрудняет расследование проблемы. Рекомендуется корректно уведомить пользователя о причинах отказа с помощью сообщения или вызова исключения с подробным описанием. Это не только улучшает пользовательский опыт, но и, как мы увидим далее, может помочь платформе корректнее обработать ситуацию.

Возможные обходные пути и решения

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

  1. Предоставление информативного сообщения

    Вместо простого Отказ = Истина, рекомендуется использовать функции Сообщить() или ПоказатьПредупреждение() для информирования пользователя о причине непроведения. Это соответствует стандартам разработки 1С и может помочь платформе корректнее обработать ситуацию, даже если исключение все равно возникает, пользователь будет знать причину.

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

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

  2. Перехват исключений на клиентской стороне

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

    Разберем по шагам, как это можно реализовать:

    1. На клиентской стороне формы документа, в обработчике команды проведения (например, кнопки "Провести"), мы вызываем серверную процедуру, которая фактически выполняет запись и проведение.
    2. Этот вызов оборачиваем в блок Попытка...Исключение.
    3. В блоке Исключение мы можем вывести пользователю понятное сообщение, а также, при необходимости, зарегистрировать подробности ошибки для анализа программистом.

    Посмотрим на пример:

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

    Такой подход дает нам полный контроль над тем, как ошибка будет представлена пользователю, скрывая от него технические детали и предлагая понятные инструкции.

  3. Изменение режима совместимости интерфейса (обходной путь для UI)

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

    Последовательность действий следующая:

    1. Установите режим совместимости интерфейса на "Такси. Разрешить Версия 8.2" (или аналогичный, позволяющий переключаться между интерфейсами).
    2. Запустите 1С со старым интерфейсом управляемых форм (НЕ "Такси").
    3. Зайдите в документ и попробуйте его провести. В этот момент вы должны получить ошибку проведения, но уже с окном без кнопки "Подробно" (только "ОК").
    4. Переключите интерфейс обратно на "Такси".

    По словам автора, после этих манипуляций при проведении документа с Отказ = Истина в интерфейсе "Такси" вы будете получать окно ошибки без кнопки "Подробно". Это скорее обходной путь для визуального представления ошибки, а не системное решение самой причины ее возникновения. Его эффективность может зависеть от версии платформы и конфигурации.

  4. Перенос проверок в ПередЗаписью формы

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

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

    Рассмотрим пример:

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

    Важно понимать, что ПередЗаписью на клиенте отменяет запись формы. Если же нам требуется выполнить проверки на сервере перед записью/проведением, мы можем вызвать серверную процедуру из ПередЗаписьюНаСервере или из клиентской ПередЗаписью, если она требует доступа к контексту объекта.

    
    &НаСервере
    Процедура ПередЗаписьюНаСервере(Отказ, СтандартнаяОбработка)
        // Здесь можно выполнить дополнительные серверные проверки,
        // используя доступ к полям объекта и базам данных.
        Если ЭтотОбъект.СуммаДокумента < 0 Тогда
            Отказ = Истина;
            Сообщить("Сумма документа не может быть отрицательной!", СтатусСообщения.Важное);
        КонецЕсли;
    КонецПроцедуры
    

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

Заключение

Проблема с выводом сообщения об ошибке вместо штатного уведомления при установке Отказ = Истина в процедуре ОбработкаПроведения для документов, открытых через управляемые формы в 1С 8.2, является известной особенностью платформы. Хотя это может показаться "багом", это, скорее, следствие специфической обработки событий в управляемом приложении.

Мы выяснили, что причина кроется не в ошибке нашего кода, а в поведении платформы, и что она проявляется только при проведении из управляемой формы объекта документа. Чтобы сделать работу с программой более комфортной для пользователя и избежать неинформативных сообщений об ошибках, мы рекомендуем:

Понимание этих особенностей платформы 1С 8.2 и применение предложенных подходов помогут вам создавать более надежные и удобные для пользователя решения.

← На главную