Как прервать выполнение типовой процедуры в расширении конфигурации 1С?

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

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

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

Проблема использования аннотации &Перед

Рассмотрим типичную ситуацию. Программист пытается использовать аннотацию &Перед для выполнения проверки перед основной процедурой. Логика кажется простой: если условие не выполнено, мы вызываем Возврат и ожидаем, что выполнение прекратится. Проанализируем пример такого кода:


&НаКлиенте
&Перед("Подключаемый_НачисленияПересчитатьСотрудника")
Процедура ЗП_Подключаемый_НачисленияПересчитатьСотрудника(Команда)
    Если Объект.Проведен Тогда
        Сообщить("Требуется отменить проведение");
        Возврат; // Попытка прервать выполнение
    КонецЕсли;
КонецПроцедуры

Почему это не работает? Механизм расширений в 1С спроектирован так, что аннотации &Перед и &После лишь «пристраиваются» к основной процедуре. Оператор Возврат внутри процедуры с аннотацией &Перед завершает работу только текущей процедуры расширения, после чего платформа неизбежно перейдет к выполнению кода основной конфигурации. Таким образом, типовой код все равно отработает, несмотря на ваши проверки.

Ошибка вызова метода УстановитьВыполнениеОбработчиковСобытия

Другой популярный подход — использование метода УстановитьВыполнениеОбработчиковСобытия(Ложь). Однако при попытке вызвать его в произвольной процедуре-команде (как в нашем примере с пересчетом начислений) платформа выдает ошибку: «Вызов метода разрешен только в обработчике расширяющей формы».

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

  1. ПриОткрытии
  2. ПередЗаписью
  3. ПриЧтенииНаСервере
  4. ПослеЗаписи

Метод УстановитьВыполнениеОбработчиковСобытия нельзя использовать в обработчиках команд, кнопках или программно созданных процедурах. Он управляет очередью выполнения именно системных событий в цепочке «Расширение 1 -> Расширение 2 -> Основная конфигурация».

Радикальное решение: Использование исключений

Один из способов гарантированно прервать выполнение всей цепочки вызовов — вызвать исключение. Проанализируем ситуацию, когда это может быть оправдано:


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

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

Оптимальное решение: Аннотация &Вместо и метод ПродолжитьВызов

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

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


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

Разберем по шагам, что происходит в этом коде:

  1. Программа заходит в нашу процедуру в расширении вместо типовой.
  2. Мы выполняем проверку Объект.Проведен.
  3. Если документ проведен, мы выводим сообщение пользователю и завершаем работу процедуры оператором Возврат. Типовой код при этом не выполняется.
  4. Если документ не проведен, мы вызываем метод ПродолжитьВызов(). Этот метод передает управление либо следующему расширению (если их несколько), либо непосредственно в процедуру основной конфигурации.

Как сохранить обновляемость конфигурации?

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

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

2. Проверка параметра Отказ. Перед тем как использовать &Вместо, посмотрите на сигнатуру типовой процедуры. Если среди параметров есть Отказ (типа Булево), вы можете использовать &Перед, просто установив Отказ = Истина. Типовой код часто проверяет этот параметр перед выполнением основной логики.

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

Итоги

Подведем итог нашему анализу. Для прерывания типового кода в расширениях 1С:

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

← На главную