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