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