Как правильно изменять код функций общих модулей в расширениях 1С?

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

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

Метод 1. Использование аннотации &Вместо и метода ПродолжитьВызов()

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

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

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


&Вместо("РассчитатьСуммуДокумента")
Функция Мой_РассчитатьСуммуДокумента(Параметры)
    
    // Выполняем действия ДО основного кода
    Параметры.Вставить("ДополнительныйКоэффициент", 1.1);
    
    // Вызываем стандартную логику
    Результат = ПродолжитьВызов(Параметры);
    
    // Выполняем действия ПОСЛЕ основного кода
    Результат = Результат * 0.95; 
    
    Возврат Результат;
КонецФункции

Этот метод идеален, если нужно подготовить параметры перед выполнением или скорректировать возвращаемый результат. Главное преимущество — вы сохраняете связь с типовым кодом. Если фирма «1С» изменит алгоритм расчета внутри функции, ваше расширение автоматически подхватит эти изменения.

Метод 2. Инструкции препроцессора #Вставить, #Удалить и #Изменить

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

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

Пример использования инструкции #Вставить:


&Вместо("СформироватьТекстЗапроса")
Процедура Расш_СформироватьТекстЗапроса()
    #Вставить
    // Этот код будет вставлен в начало метода, 
    // но инструкции позволяют работать и внутри блоков
    Если МоеУсловие Тогда
        Возврат;
    КонецЕсли;
    #КонецВставки
    
    ПродолжитьВызов();
КонецПроцедуры

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

Метод 3. Программная модификация текста запроса

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

Разберем пример, где мы перехватываем формирование запроса через &После:


&После("ПолучитьТекстЗапросаДляОтчета")
Функция Расш_ПолучитьТекстЗапросаДляОтчета(Параметры)
    Текст = Результат; // Результат — это то, что вернула типовая функция
    
    // Модифицируем строку запроса
    Текст = СтрЗаменить(Текст, "ИЗ Документ.Реализация КАК Реализация", 
        "ИЗ Документ.Реализация КАК Реализация 
        | ГДЕ Реализация.Проведен = ИСТИНА");
    
    Возврат Текст;
КонецФункции

Этот подход позволяет не копировать сотни строк кода типовой функции только ради одного условия ГДЕ.

Метод 4. Использование переопределяемых модулей БСП

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

Фирма «1С» специально оставляет эти модули пустыми, чтобы разработчики могли вклиниться в процесс без использования расширений или с минимальным риском. Посмотрим на алгоритм поиска такой точки:

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

Метод 5. Работа через ДополнительныеСвойства

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

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

  1. В аннотации &Перед для объекта документа устанавливаем свойство: ЭтотОбъект.ДополнительныеСвойства.Вставить("МойФлаг", Истина);.
  2. В нужном общем модуле через расширение проверяем этот флаг и выполняем действие.

Пример проверки:


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

Метод 6. Полное замещение (Copy-Paste) — крайняя мера

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

Внимание! Это самый опасный метод. Вы полностью копируете код типовой функции в расширение. Риски:

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

Заключение

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

← На главную