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

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

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

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

Постановка задачи и анализ контекста

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

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

Давайте разберемся, почему так делать нельзя:

  1. Отсутствие контекста. Общие модули в 1С — это, по сути, библиотеки процедур. Они не привязаны к конкретному экземпляру объекта базы данных. Когда выполняется код общего модуля, система не знает, что такое ЭтотОбъект, если вы находитесь не в модуле объекта или формы.
  2. Передача параметров. Чтобы определить, с каким документом работает процедура, необходимо смотреть на её параметры. Обычно процедуры проведения или обработки документов принимают ссылку на документ или сам объект документа в качестве первого аргумента.

Использование аннотации &Вместо (&Around)

Для решения задачи полной или частичной подмены логики в расширениях используется аннотация &Вместо (в английском синтаксисе &Around). Эта аннотация говорит платформе: "Не выполняй стандартный метод, выполняй мой метод".

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

Алгоритм действий будет следующим:

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

Реализация решения

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

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


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

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

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

Режим "Изменить и контролировать"

В обсуждении был предложен отличный способ добавления кода в расширение — использование режима "Изменить и контролировать". Давайте разберем, почему это рекомендуется.

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

При выборе варианта "Изменить и контролировать":

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

Зачем это нужно? Если в следующем обновлении поставщик конфигурации (например, фирма 1С) исправит ошибку в этой процедуре, то при запуске программы вы увидите предупреждение, что версия метода в расширении не соответствует версии в основной конфигурации. Это сигнал для программиста: "Внимание, типовой код изменился, нужно проверить, актуальны ли ваши доработки".

Альтернативный вариант: частичное вмешательство

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

Пример: для Авансового отчета нужно сначала выполнить типовой код, а потом что-то дописать.


&Вместо("ОбработатьДокумент")
Процедура Расш1_ОбработатьДокумент(ДокументСсылка, ПараметрыПечати)
    
    // Сначала даем отработать типовой логике для ВСЕХ документов
    ПродолжитьВызов(ДокументСсылка, ПараметрыПечати);
    
    // А теперь добавляем свою логику только для нужного типа
    Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.АвансовыйОтчет") Тогда
        // Дополнительные действия после отработки стандарта
        ЗаписьЖурналаРегистрации("Обработка Авансового отчета завершена");
    КонецЕсли;

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

Резюме по решению проблемы

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

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

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

← На главную