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