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