При обновлении типовых конфигураций (например, УТ 11.5, ERP 2.5 или КА 2.5) разработчики часто сталкиваются с ситуацией, когда стабильно работавшее расширение внезапно перестает функционировать. Типичный сценарий: вы обновили версию программы, и при попытке выполнить привычную операцию (например, проверку контрагента в заказе клиента) система выдает ошибку: "Процедура или функция с указанным именем не определена". При этом вы точно видите, что процедура в коде расширения есть, она помечена как Экспорт и находится в модуле формы.
В этой статье мы подробно разберем, почему так происходит, как на это повлияло изменение режима совместимости платформы до 8.3.21 и как правильно адаптировать ваш код под новые требования безопасности и производительности платформы 1С:Предприятие.
Проанализируем ситуацию, описанную в теме. При переходе с версии УТ 11.5.12.147 на 11.5.12.165 режим совместимости конфигурации изменился с 8.3.17 на 8.3.21. Это ключевой момент. Именно в версии 8.3.21 платформа ужесточила правила работы с контекстом управляемой формы.
Ранее в 1С существовала особенность: если метод модуля формы был помечен директивой &НаСервере и ключевым словом Экспорт, его можно было вызвать напрямую из клиентского контекста (например, из другого метода &НаКлиенте той же формы или даже извне). Платформа самостоятельно выполняла неявный серверный вызов. Однако, начиная с режима совместимости 8.3.21, такие методы больше не видны в клиентском программном интерфейсе формы. Компилятор теперь четко разделяет: клиент видит только клиентские экспортные методы, а сервер — серверные.
Рассмотрим подробнее, почему это ломает расширения. Когда вы добавляете свой код в расширение формы, платформа «склеивает» методы основной конфигурации и расширения. Если ваш код на клиенте пытается обратиться к ЭтаФорма.МойСерверныйМетод(), система ищет его в клиентском составе методов и, не находя (так как он теперь «спрятан» на сервере), выдает ошибку.
Самый быстрый и эффективный способ вернуть работоспособность коду — это создание промежуточного клиентского метода, который будет служить мостом между клиентом и сервером. Разберем этот процесс по шагам.
Предположим, у вас в расширении модуля формы был такой код, который перестал работать:
&НаСервере
Процедура Расш1_ПроверитьКонтрагентаНаСервере() Экспорт
// Здесь ваша логика проверки
Сообщить("Проверка выполнена на сервере");
КонецПроцедуры
&НаКлиенте
Процедура Расш1_КомандаВыполнитьПроверку(Команда)
// Раньше это работало, теперь — нет
ЭтаФорма.Расш1_ПроверитьКонтрагентаНаСервере();
КонецПроцедуры
Чтобы исправить ошибку, нам нужно добавить клиентскую экспортную процедуру, которая вызовет серверную. Посмотрим на правильный вариант реализации:
&НаСервере
Процедура Расш1_ПроверитьКонтрагентаНаСервере()
// Теперь Export здесь не обязателен, если вызов только из этой формы
// Логика проверки...
КонецПроцедуры
&НаКлиенте
Процедура Расш1_ПроверитьКонтрагентаНаКлиенте() Экспорт
// Это и есть наша "обертка"
Расш1_ПроверитьКонтрагентаНаСервере();
КонецПроцедуры
&НаКлиенте
Процедура Расш1_КомандаВыполнитьПроверку(Команда)
// Теперь вызываем КЛИЕНТСКИЙ экспортный метод
ЭтаФорма.Расш1_ПроверитьКонтрагентаНаКлиенте();
КонецПроцедуры
Важный нюанс: обратите внимание, что внутри одного модуля формы вызов Расш1_ПроверитьКонтрагентаНаСервере() без префикса ЭтаФорма сработает нормально, так как контекст сервера доступен. Проблема возникает именно при обращении через точку от объекта формы на клиенте.
Если ваша процедура (например, ПроверитьКонтрагентовФоновоеЗадание) выполняет тяжелые вычисления или запросы к базе данных, правильнее будет вынести её из модуля формы вовсе. Рассмотрим, почему это выгодно:
Вызов сервера не подвержены изменениям в поведении экспортных методов форм.Для реализации этого подхода выполните следующие действия:
Расш1_РаботаСКонтрагентамиСервер).Пример кода в общем модуле:
Процедура ПроверитьКонтрагента(СсылкаНаОбъект) Экспорт
// Логика, не привязанная к конкретным элементам формы
КонецПроцедуры
Вызов из формы будет выглядеть очень лаконично:
&НаКлиенте
Процедура Расш1_КомандаВыполнитьПроверку(Команда)
Расш1_РаботаСКонтрагентамиСервер.ПроверитьКонтрагента(Объект.Ссылка);
КонецПроцедуры
В процессе обсуждения часто возникает вопрос: почему в некоторых типовых документах (например, в «Реализации товаров и услуг») подобные вызовы продолжают работать? Проанализируем эту ситуацию. В типовых конфигурациях 1С часто используется механизм БСП (Библиотека стандартных подсистем).
Там вызовы могут быть реализованы через стандартные обработчики команд или подключаемые модули, где платформа сама управляет контекстом. Кроме того, в типовом коде вызов метода часто идет напрямую в модуле (без ЭтаФорма.), что не нарушает правил типизации даже в режиме 8.3.21. Как только мы начинаем работать в расширении и пытаемся «достучаться» до методов через программный интерфейс объекта формы, мы сразу попадаем под действие новых ограничений.
Если вы столкнулись с подобной проблемой, рекомендуем следующий алгоритм действий:
&НаСервере Экспорт с клиента.Подводя итог, можно сказать, что изменения в платформе направлены на повышение дисциплины разработки. Разделение клиентской и серверной логики через явные «обертки» или вынос кода в общие модули делает систему более предсказуемой и производительной, даже если на первых порах это требует дополнительного времени на адаптацию старых расширений. Для автоматического выявления подобных проблем в коде расширений можно использовать конфигурацию для анализа и проверки вызовов процедур и функций.