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

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

Работа с расширениями в системе «1С:Предприятие 8.3» — это стандарт де-факто для доработки типовых конфигураций. Однако начинающие (и даже опытные) разработчики часто сталкиваются с ситуацией, когда ожидаемое поведение расширенной команды формы не совпадает с реальностью. Типичный сценарий: вы заимствуете форму, добавляете команду в расширение, указываете тип вызова Вместо, но код основной конфигурации всё равно выполняется или срабатывает не в том порядке. Рассмотрим подробнее, почему это происходит и как реализовать надежную проверку перед выполнением типового кода.

Проблема: Почему свойство «Действие» в расширении может подвести

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

  1. Программное назначение обработчиков: В современных конфигурациях (особенно на базе БСП) обработчики команд часто назначаются динамически в коде ПриСозданииНаСервере. Программная установка свойства Действие имеет приоритет над тем, что вы указали визуально в редакторе формы.
  2. Кэширование метаданных: Формы в расширениях крайне чувствительны к локальному кэшу. Изменения в визуальном редакторе могут не «подхватиться» сразу.
  3. Стандартные команды: Если команда является стандартной (например, Записать или Провести), платформа жестко связывает её с внутренними механизмами, и простая замена обработчика через свойства может игнорироваться.

Решение: Использование аннотации &Вместо для метода-обработчика

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

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


&НаКлиенте
&Вместо("ИмяПроцедурыТиповогоОбработчика")
Процедура РМЦДП_Чек(Команда)

    // Наша проверка перед выполнением основного кода
    Если Объект.ПолученоНаличными + ОплаченоБезналичным = 0 Тогда
        ПоказатьПредупреждение(, НСтр("ru = 'Не указана сумма оплаты!'"));
        Возврат; // Прерываем выполнение, типовой код не вызовется
    КонецЕсли;

    // Если проверка пройдена, вызываем оригинальный код основной конфигурации
    ПродолжитьВызов(Команда);

КонецПроцедуры

В данном примере ИмяПроцедурыТиповогоОбработчика — это название процедуры, которая указана в свойстве Действие у команды в основной конфигурации. Мы не меняем само свойство Действие в расширении, мы просто перехватываем выполнение этой процедуры.

Разберем по шагам алгоритм реализации

Чтобы гарантированно добиться нужного результата, выполним следующие действия:

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

Важность использования ПродолжитьВызов()

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

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

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

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

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

← На главную