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