Вызов экспортной процедуры модуля объекта: синтаксис, контекст, примеры

· 9 мин

Содержание

Чтобы обратиться к процедуре в модуле объекта 1С из другого места конфигурации, объявите её со словом Экспорт, получите сам объект (не ссылку) и вызовите метод через точку: ДокументОбъект.ЗаполнитьТовары(). Объект получают через Ссылка.ПолучитьОбъект(), Документы.Имя.СоздатьДокумент() или, в форме, через РеквизитФормыВЗначение("Объект") на сервере.

Внутри того же модуля объекта процедуру вызывают просто по имени, без префикса. Остальное — частности: где выполняется код, как передать параметры и почему платформа пишет Метод объекта не обнаружен. Всё это ниже, с рабочими примерами для платформы 8.3 и управляемых форм.

Что такое модуль объекта и кто видит его процедуры

Модуль объекта есть у справочников, документов, обработок, отчётов, планов видов характеристик, бизнес-процессов и задач. У регистров его роль играет модуль набора записей. Открыть модуль можно в Конфигураторе: правый клик по объекту в дереве метаданных → Открыть модуль объекта.

Код модуля объекта работает в контексте конкретного экземпляра. Каждый раз, когда вы получаете объект документа, у него свой набор значений реквизитов, и процедуры модуля работают именно с ними.

Кто и что видит:

  • 🔒 Процедура без Экспорт — доступна только внутри этого модуля. Её вызывают обработчики событий и другие процедуры того же модуля.
  • 🔓 Процедура с Экспорт — становится методом объекта. Её можно вызвать из любого кода, где есть сам объект: из общего модуля, модуля формы, другой обработки.
  • 📦 Переменная с Экспорт (Перем РежимЗагрузки Экспорт;) — становится свойством объекта и доступна как Объект.РежимЗагрузки. Живёт, пока жив экземпляр, и в базу не записывается.

Чем модуль объекта отличается от соседних модулей:

МодульКак вызвать экспортную процедуруНужен экземпляр
Модуль объектаДокументОбъект.ИмяПроцедуры()Да
Модуль менеджераДокументы.ПриходТовара.ИмяПроцедуры()Нет
Общий модульИмяОбщегоМодуля.ИмяПроцедуры()Нет
Модуль формыТолько внутри формы или через ПолучитьФорму()Форма

Если процедуре не нужны данные конкретного документа (например, она строит запрос по всем документам вида), ей место в модуле менеджера. В модуль объекта кладут то, что работает с ЭтотОбъект: заполнение, проверки, расчёт табличных частей.

Синтаксис обращения к процедуре модуля объекта

Объявление экспортной процедуры в модуле документа ПриходТовара:

Процедура ПересчитатьСуммы() Экспорт

	Для Каждого Строка Из Товары Цикл
		Строка.Сумма = Строка.Количество * Строка.Цена;
	КонецЦикла;

КонецПроцедуры

Вызов из общего модуля или любого серверного кода:

ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокОбъект.ПересчитатьСуммы();
ДокОбъект.Записать();

Новый документ создают через менеджер, и у него сразу доступны те же методы:

НовыйДок = Документы.ПриходТовара.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.ПересчитатьСуммы();
НовыйДок.Записать();

Внутри самого модуля пишут просто ПересчитатьСуммы(); или ЭтотОбъект.ПересчитатьСуммы();. Обе записи работают одинаково, вторая удобна, когда хочется явно показать, что вызывается метод объекта.

Процедура, функция и встроенный метод — в чём разница

  • ⚙️ Процедура выполняет действие и ничего не возвращает. Её вызывают отдельной строкой.
  • 🔢 Функция возвращает значение через Возврат. Её можно использовать в выражении: Итог = ДокОбъект.СуммаПоТоварам();.
  • 🧩 Встроенные методы (Записать(), Заполнить(), ПроверитьЗаполнение(), Скопировать()) даёт платформа. Пользовательские экспортные процедуры вызываются тем же синтаксисом, поэтому их имена не должны совпадать со встроенными.

Если попытаться получить значение из процедуры (Х = ДокОбъект.ПересчитатьСуммы();), платформа выдаст ошибку Обращение к процедуре объекта как к функции. Функцию отдельной строкой вызвать можно: результат просто отбрасывается.

Вызов из подписки на событие

Подписка на событие указывает на процедуру общего модуля, а объект приходит в неё параметром Источник. Это и есть экземпляр, поэтому его экспортные методы доступны сразу:

Процедура ПриходТовараПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	Если ТипЗнч(Источник) = Тип("ДокументОбъект.ПриходТовара") Тогда
		Источник.ПересчитатьСуммы();
	КонецЕсли;

КонецПроцедуры

Проверка типа нужна, если подписка назначена на несколько видов документов: у остальных такого метода может не быть. Записывать Источник внутри ПередЗаписью не нужно — платформа сама запишет его после обработчика.

Параметры: как передать данные в процедуру модуля

Параметры описывают в скобках через запятую. По умолчанию они передаются по ссылке: если процедура изменит параметр, изменится и переменная в вызывающем коде. Чтобы этого не было, перед параметром ставят Знач.

Процедура УстановитьСклад(НовыйСклад, Знач ПерезаписатьЗаполненные = Ложь) Экспорт

	Для Каждого Строка Из Товары Цикл
		Если ПерезаписатьЗаполненные Или Не ЗначениеЗаполнено(Строка.Склад) Тогда
			Строка.Склад = НовыйСклад;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Варианты вызова:

ДокОбъект.УстановитьСклад(ОсновнойСклад);        // второй параметр = Ложь
ДокОбъект.УстановитьСклад(ОсновнойСклад, Истина); // перезаписать все строки

Что полезно помнить про параметры:

  • 📌 Необязательный параметр получает значение по умолчанию после знака =. Он должен стоять после обязательных.
  • 📌 Пропустить параметр в середине можно запятой: Метод(А, , В).
  • 📌 Если параметров много и они меняются, передавайте одну Структура — сигнатура не будет ломаться при доработках.
  • 📌 Для передачи данных между обработчиками одного объекта есть свойство ДополнительныеСвойства. Например, перед Записать() кладут ДокОбъект.ДополнительныеСвойства.Вставить("БезПроверкиОстатков", Истина) и читают его в ПередЗаписью.

Передача по ссылке — частый источник скрытых ошибок. Процедура «случайно» обнулила переданную таблицу, и вызывающий код дальше работает с пустыми данными. Если параметр нужен только для чтения, ставьте Знач.

Где выполняется код: клиент, сервер и контекст вызова

Модуль объекта в управляемом приложении выполняется на сервере (а также в толстом клиенте и во внешнем соединении). На тонком клиенте и в веб-клиенте объекта прикладного типа просто нет. Поэтому из клиентского кода формы напрямую вызвать процедуру модуля объекта нельзя.

Директивы &НаСервере и &НаКлиенте в модуле объекта не пишут. В типовых конфигурациях код модуля обёрнут инструкцией препроцессора, которая честно говорит, где он доступен:

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

Процедура ПересчитатьСуммы() Экспорт
	// ...
КонецПроцедуры

#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли

Схема правильного вызова с клиента:

  1. На клиенте обработчик команды вызывает серверную процедуру формы.
  2. Серверная процедура получает объект: из реквизита формы или по ссылке.
  3. Вызывается экспортный метод объекта.
  4. Результат возвращается на клиент или переносится обратно в данные формы.

Параметры, которые идут с клиента на сервер и обратно, должны быть сериализуемыми: ссылки, примитивы, Структура, Массив, ДанныеФормыСтруктура. Сам ДокументОбъект через границу клиент-сервер не передаётся.

Каждый серверный вызов — это обращение по сети. Если на клиенте в цикле дергать сервер для каждой строки, форма станет заметно тормозить. Собирайте данные в массив и делайте один вызов.

Вызов процедуры модуля объекта из формы

Из формы самого объекта

В форме документа основной реквизит Объект имеет тип ДанныеФормыСтруктура. Это не объект документа, а его «слепок» для формы, и методов модуля объекта у него нет. Поэтому на сервере форму превращают в объект, вызывают метод и возвращают изменения обратно:

&НаКлиенте
Процедура ПересчитатьСуммыКоманда(Команда)
	ПересчитатьСуммыНаСервере();
КонецПроцедуры

&НаСервере
Процедура ПересчитатьСуммыНаСервере()

	ДокОбъект = РеквизитФормыВЗначение("Объект");
	ДокОбъект.ПересчитатьСуммы();
	ЗначениеВРеквизитФормы(ДокОбъект, "Объект");

КонецПроцедуры

Не забывайте ЗначениеВРеквизитФормы: без этой строки метод отработает на копии, а пользователь в форме ничего не увидит. Документ при этом не записывается — пользователь сохранит его сам.

Вместо пары РеквизитФормыВЗначение / ЗначениеВРеквизитФормы можно использовать методы формы ДанныеФормыВЗначение и ЗначениеВДанныеФормы. Результат тот же, разница только в записи.

Из формы списка или другой формы

Здесь в форме нет данных объекта, есть только ссылка. Удобнее всего серверная процедура без контекста — она не гоняет данные формы на сервер:

&НаСервереБезКонтекста
Процедура ПересчитатьИЗаписать(Ссылка)

	ДокОбъект = Ссылка.ПолучитьОбъект();
	ДокОбъект.ПересчитатьСуммы();
	ДокОбъект.Записать();

КонецПроцедуры

Если документ проведён и вы меняете его табличные части, записывайте с нужным режимом: ДокОбъект.Записать(РежимЗаписиДокумента.Проведение). Иначе движения останутся от старых данных.

Из формы обработки или отчёта

Принцип тот же, только основной реквизит обработки называется Объект, а у отчёта — Отчет:

&НаСервере
Процедура СформироватьНаСервере()

	ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
	ОбработкаОбъект.ЗаполнитьСписок();
	ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");

КонецПроцедуры

Для отчёта — РеквизитФормыВЗначение("Отчет").

Обращение к процедурам внешней обработки

Внешняя обработка (.epf) — тот же объект, только хранится вне конфигурации. Её модуль объекта вызывают после создания экземпляра.

Если файл лежит на сервере и безопасный режим не мешает:

Обработка = ВнешниеОбработки.Создать("C:\Обработки\Загрузка.epf", Ложь);
Обработка.ЗагрузитьДанные(ПараметрыЗагрузки);

Второй параметр — безопасный режим. Отключать его стоит только для проверенных файлов.

В клиент-серверном варианте и в управляемом приложении правильнее схема через временное хранилище:

  1. На клиенте пользователь выбирает файл, и его данные помещаются во временное хранилище — вы получаете адрес.
  2. На сервере вызывают ВнешниеОбработки.Подключить(Адрес). Метод возвращает имя подключённой обработки.
  3. Экземпляр создают по этому имени: ВнешниеОбработки.Создать(ИмяОбработки).
  4. У экземпляра вызывают экспортные процедуры модуля объекта.
&НаСервере
Функция ВыполнитьВнешнююОбработку(АдресФайла)

	ИмяОбработки = ВнешниеОбработки.Подключить(АдресФайла);
	Обработка = ВнешниеОбработки.Создать(ИмяОбработки);
	Возврат Обработка.ПолучитьРезультат();

КонецФункции

Если обработка зарегистрирована в справочнике дополнительных отчётов и обработок, типовые конфигурации на БСП сами подключают её и вызывают процедуру ВыполнитьКоманду. Тогда в модуле объекта нужно описать регистрационные данные (СведенияОВнешнейОбработке) и эту процедуру с Экспорт.

Внешняя обработка, запущенная без безопасного режима, получает полный доступ к базе. Подключайте только файлы, которые вы написали сами или проверили по коду.

Вызов по имени, которое известно только во время работы

Иногда имя процедуры приходит из настроек. Конструкция Выполнить("Объект." + ИмяМетода + "()") работает, но опасна: в строку можно подставить любой код. В конфигурациях на БСП есть безопасная обёртка ОбщегоНазначения.ВыполнитьМетодОбъекта(Объект, ИмяМетода, Параметры) — она проверяет имя метода перед вызовом. Пользуйтесь ею, если библиотека есть в вашей конфигурации.

Ошибки при вызове процедуры модуля объекта и как их найти

Диагностика: выберите симптом

Как отладить вызов

  1. В Конфигураторе поставьте точку останова на строке вызова: клавиша F9.
  2. Запустите отладку F5 или подключитесь к уже открытому сеансу через меню Отладка → Подключение.
  3. Когда выполнение остановится, нажмите F11 — отладчик зайдёт внутрь процедуры модуля объекта.
  4. Наведите курсор на переменную или откройте Табло (Ctrl+Alt+W) и проверьте её тип. Если там ДокументСсылка или ДанныеФормыСтруктура, причина ошибки найдена.

Для клиент-серверной базы отладка серверного кода должна быть включена на сервере 1С: служба агента запускается с ключом -debug. Если точка останова в модуле объекта не срабатывает, а на клиенте срабатывает — дело почти всегда в этом. Включать ключ на рабочем сервере стоит по согласованию с администратором: для этого перезапускают службу агента, и все сеансы пользователей оборвутся.

В файловой базе серверный код выполняется в том же процессе, что и клиент, поэтому точки останова в модуле объекта работают без настроек сервера.

Частые вопросы

Можно ли вызвать процедуру модуля объекта без записи объекта?
Да. Метод меняет данные в памяти. Пока вы не вызовете Записать(), в базе ничего не изменится.
Вызываются ли при вызове метода обработчики ПередЗаписью и ПриЗаписи?
Нет. Они срабатывают только при Записать(). Ваша экспортная процедура вызывается сама по себе.
Как вызвать процедуру модуля объекта из модуля менеджера того же документа?
Получите экземпляр: Ссылка.ПолучитьОбъект() или СоздатьДокумент(), и вызовите метод через точку. Напрямую по имени из менеджера процедура объекта не видна.
Можно ли вызвать экспортную процедуру модуля объекта в расширении?
Да. Экспортные методы объекта конфигурации доступны коду расширения так же, как и коду основной конфигурации. Новые экспортные процедуры можно добавить в модуль объекта в самом расширении.
Чем ЭтотОбъект отличается от Ссылка внутри модуля?
ЭтотОбъект — сам экземпляр с текущими, ещё не записанными данными. Ссылка — указатель на запись в базе; у нового объекта до первой записи она пустая.