При разработке расширений для типовых конфигураций 1С перед программистом часто встает дилемма: как внести изменения в логику общего модуля, не снимая его с поддержки и сохраняя возможность легкого обновления. Ситуация усложняется, когда правки требуются не в начале или конце процедуры, а в самой середине алгоритма, например, в тексте сложного запроса. В этой статье мы подробно разберем существующие механизмы расширения функций, проанализируем их плюсы и минусы, а также выясним, как действовать в сложных случаях.
Это основной и наиболее корректный с точки зрения архитектуры способ, если вам нужно дополнить логику стандартного метода. Рассмотрим, как это работает. Мы перехватываем выполнение функции в расширении и вызываем основной код через специальную команду. Разберем по шагам реализацию этого механизма:
&Вместо("ИмяМетода").ПродолжитьВызов().Рассмотрим пример кода:
&Вместо("РассчитатьСуммуДокумента")
Функция Мой_РассчитатьСуммуДокумента(Параметры)
// Выполняем действия ДО основного кода
Параметры.Вставить("ДополнительныйКоэффициент", 1.1);
// Вызываем стандартную логику
Результат = ПродолжитьВызов(Параметры);
// Выполняем действия ПОСЛЕ основного кода
Результат = Результат * 0.95;
Возврат Результат;
КонецФункции
Этот метод идеален, если нужно подготовить параметры перед выполнением или скорректировать возвращаемый результат. Главное преимущество — вы сохраняете связь с типовым кодом. Если фирма «1С» изменит алгоритм расчета внутри функции, ваше расширение автоматически подхватит эти изменения.
Если нам нужно поменять код в середине функции (например, добавить условие или изменить одну строку в запросе), использование &Вместо с полным копированием кода становится опасным. Для решения этой проблемы в платформу (начиная с версии 8.3.15) были введены специальные инструкции. Они позволяют «точечно» воздействовать на исходный текст.
Проанализируем ситуацию: если режим совместимости вашей конфигурации (например, старой версии «Бухгалтерия предприятия 3.0») ниже 8.3.15, эти инструкции работать не будут. Однако в современных релизах это лучший способ.
Пример использования инструкции #Вставить:
&Вместо("СформироватьТекстЗапроса")
Процедура Расш_СформироватьТекстЗапроса()
#Вставить
// Этот код будет вставлен в начало метода,
// но инструкции позволяют работать и внутри блоков
Если МоеУсловие Тогда
Возврат;
КонецЕсли;
#КонецВставки
ПродолжитьВызов();
КонецПроцедуры
Важный момент: использование этих инструкций позволяет платформе при обновлении «склеивать» ваш код с новым типовым кодом более интеллектуально, чем при полном замещении метода.
Выясним причину, по которой часто не удается использовать ПродолжитьВызов(): внутри метода формируется текст запроса, и вам нужно добавить в него поле или условие. Если функция возвращает текст запроса или принимает объект Запрос как параметр, мы можем применить строковые функции.
Разберем пример, где мы перехватываем формирование запроса через &После:
&После("ПолучитьТекстЗапросаДляОтчета")
Функция Расш_ПолучитьТекстЗапросаДляОтчета(Параметры)
Текст = Результат; // Результат — это то, что вернула типовая функция
// Модифицируем строку запроса
Текст = СтрЗаменить(Текст, "ИЗ Документ.Реализация КАК Реализация",
"ИЗ Документ.Реализация КАК Реализация
| ГДЕ Реализация.Проведен = ИСТИНА");
Возврат Текст;
КонецФункции
Этот подход позволяет не копировать сотни строк кода типовой функции только ради одного условия ГДЕ.
Прежде чем «костылить» в основном модуле, проанализируем структуру конфигурации. В библиотеке стандартных подсистем (БСП) многие функции имеют вызовы в модули с постфиксом Переопределяемый. Например, ОбщегоНазначенияПереопределяемый или ПриЗаписиПереопределяемый.
Фирма «1С» специально оставляет эти модули пустыми, чтобы разработчики могли вклиниться в процесс без использования расширений или с минимальным риском. Посмотрим на алгоритм поиска такой точки:
При... или содержащих слово Переопределяемый.&После. Это гарантирует, что основная логика системы не будет нарушена.Если вам нужно передать какую-то информацию вглубь сложного алгоритма проведения, который вы не хотите переписывать целиком, используйте ДополнительныеСвойства. Это коллекция (структура), которая есть почти у всех объектных типов (ДокументОбъект, СправочникОбъект).
Разберем ситуацию: вам нужно, чтобы в середине глубокого вызова общего модуля сработал ваш алгоритм, но менять параметры всех функций в цепочке нельзя.
&Перед для объекта документа устанавливаем свойство: ЭтотОбъект.ДополнительныеСвойства.Вставить("МойФлаг", Истина);.Пример проверки:
&Вместо("ОбработатьДанные")
Процедура Расш_ОбработатьДанные(Объект)
Если Объект.ДополнительныеСвойства.Свойство("МойФлаг") Тогда
// Наша кастомная логика в середине процесса
КонецЕсли;
ПродолжитьВызов(Объект);
КонецПроцедуры
Рассмотрим ситуацию, когда ни один из вышеперечисленных способов не подходит (старая платформа, отсутствие переопределяемых методов, закрытый код). В этом случае используется &Вместо без ПродолжитьВызов().
Внимание! Это самый опасный метод. Вы полностью копируете код типовой функции в расширение. Риски:
Если вы вынуждены пойти на этот шаг, обязательно оставляйте комментарии с датой и причиной копирования, чтобы при следующем обновлении программист знал, что этот кусок кода нужно пересмотреть и актуализировать.
Мы проанализировали различные подходы к модификации общих модулей. Помните, что приоритет всегда должен отдаваться методам, сохраняющим вызов оригинального кода (ПродолжитьВызов()) или использующим штатные механизмы (инструкции #Вставить и переопределяемые модули). Это залог стабильной работы системы и легкого сопровождения в будущем.