Вызов экспортной процедуры модуля объекта: синтаксис, контекст, примеры
Содержание
Чтобы обратиться к процедуре в модуле объекта 1С из другого места конфигурации, объявите её со словом Экспорт, получите сам объект (не ссылку) и вызовите метод через точку: ДокументОбъект.ЗаполнитьТовары(). Объект получают через Ссылка.ПолучитьОбъект(), Документы.Имя.СоздатьДокумент() или, в форме, через РеквизитФормыВЗначение("Объект") на сервере.
Внутри того же модуля объекта процедуру вызывают просто по имени, без префикса. Остальное — частности: где выполняется код, как передать параметры и почему платформа пишет Метод объекта не обнаружен. Всё это ниже, с рабочими примерами для платформы 8.3 и управляемых форм.
Что такое модуль объекта и кто видит его процедуры
Модуль объекта есть у справочников, документов, обработок, отчётов, планов видов характеристик, бизнес-процессов и задач. У регистров его роль играет модуль набора записей. Открыть модуль
можно в Конфигураторе: правый клик по объекту в дереве метаданных → Открыть модуль объекта.
Код модуля объекта работает в контексте конкретного экземпляра. Каждый раз, когда вы получаете объект документа, у него свой набор значений реквизитов, и процедуры модуля работают именно с ними.
Кто и что видит:
- 🔒 Процедура без
Экспорт— доступна только внутри этого модуля. Её вызывают обработчики событий и другие процедуры того же модуля. - 🔓 Процедура с
Экспорт— становится методом объекта. Её можно вызвать из любого кода, где есть сам объект: из общего модуля, модуля формы, другой обработки. - 📦 Переменная с
Экспорт(Перем РежимЗагрузки Экспорт;) — становится свойством объекта и доступна какОбъект.РежимЗагрузки. Живёт, пока жив экземпляр, и в базу не записывается.
Чем модуль объекта отличается от соседних модулей:
| Модуль | Как вызвать экспортную процедуру | Нужен экземпляр |
|---|---|---|
| Модуль объекта | ДокументОбъект.ИмяПроцедуры() | Да |
| Модуль менеджера | Документы.ПриходТовара.ИмяПроцедуры() | Нет |
| Общий модуль | ИмяОбщегоМодуля.ИмяПроцедуры() | Нет |
| Модуль формы | Только внутри формы или через ПолучитьФорму() | Форма |
Если процедуре не нужны данные конкретного документа (например, она строит запрос по всем документам вида), ей место в модуле менеджера. В модуль объекта кладут то, что работает с ЭтотОбъект: заполнение, проверки, расчёт табличных частей.
Синтаксис обращения к процедуре модуля объекта
Объявление экспортной процедуры в модуле документа ПриходТовара:
Процедура ПересчитатьСуммы() Экспорт
Для Каждого Строка Из Товары Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
КонецПроцедуры
Вызов из общего модуля или любого серверного кода:
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокОбъект.ПересчитатьСуммы();
ДокОбъект.Записать();
Новый документ создают через менеджер, и у него сразу доступны те же методы:
НовыйДок = Документы.ПриходТовара.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.ПересчитатьСуммы();
НовыйДок.Записать();
Внутри самого модуля пишут просто ПересчитатьСуммы(); или ЭтотОбъект.ПересчитатьСуммы();. Обе записи работают одинаково, вторая удобна, когда хочется явно показать, что вызывается метод объекта.
Процедура, функция и встроенный метод — в чём разница
- ⚙️ Процедура выполняет действие и ничего не возвращает. Её вызывают отдельной строкой.
- 🔢 Функция возвращает значение через
Возврат. Её можно использовать в выражении:Итог = ДокОбъект.СуммаПоТоварам();. - 🧩 Встроенные методы (
Записать(),Заполнить(),ПроверитьЗаполнение(),Скопировать()) даёт платформа. Пользовательские экспортные процедуры вызываются тем же синтаксисом, поэтому их имена не должны совпадать со встроенными.
Если попытаться получить значение из процедуры (Х = ДокОбъект.ПересчитатьСуммы();), платформа выдаст ошибку Обращение к процедуре объекта как к функции. Функцию отдельной строкой вызвать можно: результат просто отбрасывается.
Вызов из подписки на событие
Подписка на событие указывает на процедуру общего модуля, а объект приходит в неё параметром Источник. Это и есть экземпляр, поэтому его экспортные методы доступны сразу:
Процедура ПриходТовараПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если ТипЗнч(Источник) = Тип("ДокументОбъект.ПриходТовара") Тогда
Источник.ПересчитатьСуммы();
КонецЕсли;
КонецПроцедуры
Проверка типа нужна, если подписка назначена на несколько видов документов: у остальных такого метода может не быть. Записывать Источник внутри ПередЗаписью не нужно — платформа сама запишет его после обработчика.
Параметры: как передать данные в процедуру модуля
Параметры описывают в скобках через запятую. По умолчанию они передаются по ссылке: если процедура изменит параметр, изменится и переменная в вызывающем коде. Чтобы этого не было, перед параметром ставят Знач.
Процедура УстановитьСклад(НовыйСклад, Знач ПерезаписатьЗаполненные = Ложь) Экспорт
Для Каждого Строка Из Товары Цикл
Если ПерезаписатьЗаполненные Или Не ЗначениеЗаполнено(Строка.Склад) Тогда
Строка.Склад = НовыйСклад;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Варианты вызова:
ДокОбъект.УстановитьСклад(ОсновнойСклад); // второй параметр = Ложь
ДокОбъект.УстановитьСклад(ОсновнойСклад, Истина); // перезаписать все строки
Что полезно помнить про параметры:
- 📌 Необязательный параметр получает значение по умолчанию после знака
=. Он должен стоять после обязательных. - 📌 Пропустить параметр в середине можно запятой:
Метод(А, , В). - 📌 Если параметров много и они меняются, передавайте одну
Структура— сигнатура не будет ломаться при доработках. - 📌 Для передачи данных между обработчиками одного объекта есть свойство
ДополнительныеСвойства. Например, передЗаписать()кладутДокОбъект.ДополнительныеСвойства.Вставить("БезПроверкиОстатков", Истина)и читают его вПередЗаписью.
Передача по ссылке — частый источник скрытых ошибок. Процедура «случайно» обнулила переданную таблицу, и вызывающий код дальше работает с пустыми данными. Если параметр нужен только для чтения, ставьте Знач.
Где выполняется код: клиент, сервер и контекст вызова
Модуль объекта в управляемом приложении выполняется на сервере (а также в толстом клиенте и во внешнем соединении). На тонком клиенте и в веб-клиенте объекта прикладного типа просто нет. Поэтому из клиентского кода формы напрямую вызвать процедуру модуля объекта нельзя.
Директивы &НаСервере и &НаКлиенте в модуле объекта не пишут. В типовых конфигурациях код модуля обёрнут инструкцией препроцессора, которая честно говорит, где он доступен:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ПересчитатьСуммы() Экспорт
// ...
КонецПроцедуры
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
Схема правильного вызова с клиента:
- На клиенте обработчик команды вызывает серверную процедуру формы.
- Серверная процедура получает объект: из реквизита формы или по ссылке.
- Вызывается экспортный метод объекта.
- Результат возвращается на клиент или переносится обратно в данные формы.
Параметры, которые идут с клиента на сервер и обратно, должны быть сериализуемыми: ссылки, примитивы, Структура, Массив, ДанныеФормыСтруктура. Сам ДокументОбъект через границу клиент-сервер не передаётся.
Каждый серверный вызов — это обращение по сети. Если на клиенте в цикле дергать сервер для каждой строки, форма станет заметно тормозить. Собирайте данные в массив и делайте один вызов.
Вызов процедуры модуля объекта из формы
Из формы самого объекта
В форме документа основной реквизит Объект имеет тип ДанныеФормыСтруктура. Это не объект документа, а его «слепок» для формы, и методов модуля объекта у него нет. Поэтому на сервере форму превращают в объект, вызывают метод и возвращают изменения обратно:
&НаКлиенте
Процедура ПересчитатьСуммыКоманда(Команда)
ПересчитатьСуммыНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьСуммыНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
ДокОбъект.ПересчитатьСуммы();
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры
Не забывайте ЗначениеВРеквизитФормы: без этой строки метод отработает на копии, а пользователь в форме ничего не увидит. Документ при этом не записывается — пользователь сохранит его сам.
Вместо пары РеквизитФормыВЗначение / ЗначениеВРеквизитФормы можно использовать методы формы ДанныеФормыВЗначение и ЗначениеВДанныеФормы. Результат тот же, разница только в записи.
Из формы списка или другой формы
Здесь в форме нет данных объекта, есть только ссылка. Удобнее всего серверная процедура без контекста — она не гоняет данные формы на сервер:
&НаСервереБезКонтекста
Процедура ПересчитатьИЗаписать(Ссылка)
ДокОбъект = Ссылка.ПолучитьОбъект();
ДокОбъект.ПересчитатьСуммы();
ДокОбъект.Записать();
КонецПроцедуры
Если документ проведён и вы меняете его табличные части, записывайте с нужным режимом: ДокОбъект.Записать(РежимЗаписиДокумента.Проведение). Иначе движения останутся от старых данных.
Из формы обработки или отчёта
Принцип тот же, только основной реквизит обработки называется Объект, а у отчёта — Отчет:
&НаСервере
Процедура СформироватьНаСервере()
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
ОбработкаОбъект.ЗаполнитьСписок();
ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");
КонецПроцедуры
Для отчёта — РеквизитФормыВЗначение("Отчет").
Обращение к процедурам внешней обработки
Внешняя обработка (.epf) — тот же объект, только хранится вне конфигурации. Её модуль объекта вызывают после создания экземпляра.
Если файл лежит на сервере и безопасный режим не мешает:
Обработка = ВнешниеОбработки.Создать("C:\Обработки\Загрузка.epf", Ложь);
Обработка.ЗагрузитьДанные(ПараметрыЗагрузки);
Второй параметр — безопасный режим. Отключать его стоит только для проверенных файлов.
В клиент-серверном варианте и в управляемом приложении правильнее схема через временное хранилище:
- На клиенте пользователь выбирает файл, и его данные помещаются во временное хранилище — вы получаете адрес.
- На сервере вызывают
ВнешниеОбработки.Подключить(Адрес). Метод возвращает имя подключённой обработки. - Экземпляр создают по этому имени:
ВнешниеОбработки.Создать(ИмяОбработки). - У экземпляра вызывают экспортные процедуры модуля объекта.
&НаСервере
Функция ВыполнитьВнешнююОбработку(АдресФайла)
ИмяОбработки = ВнешниеОбработки.Подключить(АдресФайла);
Обработка = ВнешниеОбработки.Создать(ИмяОбработки);
Возврат Обработка.ПолучитьРезультат();
КонецФункции
Если обработка зарегистрирована в справочнике дополнительных отчётов и обработок, типовые конфигурации на БСП сами подключают её и вызывают процедуру ВыполнитьКоманду. Тогда в модуле объекта нужно описать регистрационные данные (СведенияОВнешнейОбработке) и эту процедуру с Экспорт.
Внешняя обработка, запущенная без безопасного режима, получает полный доступ к базе. Подключайте только файлы, которые вы написали сами или проверили по коду.
Вызов по имени, которое известно только во время работы
Иногда имя процедуры приходит из настроек. Конструкция Выполнить("Объект." + ИмяМетода + "()") работает, но опасна: в строку можно подставить любой код. В конфигурациях на БСП есть безопасная обёртка ОбщегоНазначения.ВыполнитьМетодОбъекта(Объект, ИмяМетода, Параметры) — она проверяет имя метода перед вызовом. Пользуйтесь ею, если библиотека есть в вашей конфигурации.
Ошибки при вызове процедуры модуля объекта и как их найти
Как отладить вызов
- В Конфигураторе поставьте точку останова на строке вызова: клавиша
F9. - Запустите отладку
F5или подключитесь к уже открытому сеансу через менюОтладка → Подключение. - Когда выполнение остановится, нажмите
F11— отладчик зайдёт внутрь процедуры модуля объекта. - Наведите курсор на переменную или откройте
Табло(Ctrl+Alt+W) и проверьте её тип. Если тамДокументСсылкаилиДанныеФормыСтруктура, причина ошибки найдена.
Для клиент-серверной базы отладка серверного кода должна быть включена на сервере 1С: служба агента запускается с ключом -debug. Если точка останова в модуле объекта не срабатывает, а на клиенте срабатывает — дело почти всегда в этом. Включать ключ на рабочем сервере стоит по согласованию с администратором: для этого перезапускают службу агента, и все сеансы пользователей оборвутся.
В файловой базе серверный код выполняется в том же процессе, что и клиент, поэтому точки останова в модуле объекта работают без настроек сервера.
Частые вопросы
Можно ли вызвать процедуру модуля объекта без записи объекта?
Записать(), в базе ничего не изменится.Вызываются ли при вызове метода обработчики ПередЗаписью и ПриЗаписи?
Записать(). Ваша экспортная процедура вызывается сама по себе.Как вызвать процедуру модуля объекта из модуля менеджера того же документа?
Ссылка.ПолучитьОбъект() или СоздатьДокумент(), и вызовите метод через точку. Напрямую по имени из менеджера процедура объекта не видна.Можно ли вызвать экспортную процедуру модуля объекта в расширении?
Чем ЭтотОбъект отличается от Ссылка внутри модуля?
ЭтотОбъект — сам экземпляр с текущими, ещё не записанными данными. Ссылка — указатель на запись в базе; у нового объекта до первой записи она пустая.