Вызов экспортных методов модуля объекта: из формы, общего модуля и обработки
Содержание
Чтобы обратиться к функции в модуле объекта 1С, объявите её с ключевым словом Экспорт, получите сам объект (не ссылку!) и вызовите метод через точку: ДокОбъект.РассчитатьИтог(). Внутри того же модуля функцию вызывают просто по имени, без Экспорт и без точки.
Способ получения объекта зависит от места вызова. В общем модуле на сервере это Ссылка.ПолучитьОбъект(), в управляемой форме — РеквизитФормыВЗначение("Объект") в серверной процедуре, для обработки — Обработки.Имя.Создать(). С клиента модуль объекта недоступен вообще, и большинство ошибок при вызове растёт именно отсюда.
Экспорт и область видимости методов модуля объекта
Модуль объекта есть у справочников, документов, обработок, отчётов, планов видов характеристик и других прикладных объектов. Открывается он в конфигураторе из контекстного меню объекта: Открыть модуль объекта. Код этого модуля исполняется в контексте конкретного экземпляра — того элемента или документа, который сейчас в памяти.
Что видно снаружи, решает одно слово:
- 🔒 Без
Экспорт— процедура или функция служебная. Её можно вызвать только из этого же модуля. - 🔓 С
Экспорт— метод становится методом объекта. Его видит любой код, у которого в руках экземпляр объекта. - 📦 Переменная модуля с
Экспорт—Перем КэшНастроек Экспорт;в начале модуля. Она тоже доступна через точку, как свойство:ДокОбъект.КэшНастроек.
// Модуль объекта документа «РеализацияТоваров»
Перем РежимПересчета Экспорт;
Функция РассчитатьИтог() Экспорт
Возврат Товары.Итог("Сумма") - СуммаСкидкиПоДокументу();
КонецФункции
Функция СуммаСкидкиПоДокументу()
// служебная: снаружи не видна
Возврат Товары.Итог("СуммаСкидки");
КонецФункции
Внутри модуля к реквизитам и табличным частям обращаются напрямую: Товары, Дата, Контрагент. Сам экземпляр доступен через ЭтотОбъект — это пригодится, когда объект нужно передать параметром в общий модуль.
Экспортируйте только то, что действительно нужно вызывать снаружи. Каждый экспортный метод — это обязательство: его могут вызывать из других модулей и расширений, и переименовать его потом сложнее.
В типовых конфигурациях текст модуля объекта обычно обёрнут в инструкцию препроцессора:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// процедуры и функции модуля
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
Директивы &НаКлиенте и &НаСервере в модуле объекта не используются — они нужны в модулях форм и команд. Место исполнения модуля объекта определяется контекстом, в котором создан экземпляр.
Как вызвать функцию внутри одного модуля объекта
Внутри модуля метод вызывают по имени. Префикс ЭтотОбъект. не нужен, хотя и не запрещён для экспортных методов.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
СуммаДокумента = РассчитатьИтог();
Если СуммаДокумента <= 0 Тогда
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Несколько правил, которые экономят время на отладке:
- Порядок объявления не важен. В 8.3 можно вызвать функцию, описанную ниже по тексту модуля. Предварительное объявление, как в 7.7, не требуется.
- Функцию можно вызвать как процедуру. Строка
РассчитатьИтог();без присваивания допустима — результат просто отбросится. - Процедуру нельзя вызвать как функцию.
Х = ЗаполнитьТовары();для процедуры даст ошибку компиляцииИспользование процедуры как функции. - Имена уникальны в пределах модуля. Перегрузки по числу параметров в языке 1С нет. Две функции с одним именем — ошибка компиляции.
Обработчики событий (ПередЗаписью, ОбработкаПроведения, ОбработкаЗаполнения) тоже живут в модуле объекта. Их вызывает платформа, вручную вызывать их не нужно. Если та же логика нужна и в обработчике, и снаружи, вынесите её в отдельную экспортную функцию и вызывайте её из обработчика.
Обращение к функции модуля объекта из другого модуля
Главное правило: методы модуля объекта есть у объекта, а не у ссылки. Тип ДокументСсылка.РеализацияТоваров их не знает. Сначала получите объект одним из способов ниже.
Существующий элемент или документ по ссылке
// общий модуль с флажком «Сервер» или серверная процедура
ДокОбъект = ДокументСсылка.ПолучитьОбъект();
Итог = ДокОбъект.РассчитатьИтог();
ПолучитьОбъект() читает из базы весь объект с табличными частями. Для одного-двух полей это дорого: если нужно только значение реквизита, прочитайте его запросом или через ДокументСсылка.ИмяРеквизита.
Новый объект
НовыйДок = Документы.РеализацияТоваров.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.ЗаполнитьПоУмолчанию(); // экспортная функция модуля объекта
НовыйДок.Записать();
Для справочника — Справочники.Номенклатура.СоздатьЭлемент(), для группы — СоздатьГруппу().
Обработка или отчёт из конфигурации
Обработка = Обработки.ЗагрузкаПрайса.Создать();
Обработка.ИмяФайла = "C:\Обмен\price.xlsx";
Результат = Обработка.ВыполнитьЗагрузку();
У обработки нет записи в базу, поэтому её модуль объекта часто служит «библиотекой» с экспортными функциями. Это самый частый на практике случай.
Внешняя обработка
Для внешней обработки объект создают методом ВнешниеОбработки.Создать() с путём к файлу .epf. Этот метод работает только при отключённом безопасном режиме и с правом на интерактивное открытие внешних обработок. В типовых конфигурациях внешние обработки подключают через справочник дополнительных отчётов и обработок, а экспортные функции вызывают у созданного объекта так же через точку.
Внешняя обработка выполняет любой код с правами текущего пользователя. Перед вызовом её функций в рабочей базе убедитесь, что файл получен из надёжного источника.
Из внешнего соединения
Через COM-соединение (V83.COMConnector) экспортные методы модуля объекта вызываются той же цепочкой: Соединение.Документы.РеализацияТоваров.НайтиПоНомеру(...).ПолучитьОбъект().РассчитатьИтог(). Условие — модуль скомпилирован для внешнего соединения. Если в препроцессорной обёртке нет ВнешнееСоединение, метод окажется недоступен.
Вызов из управляемой формы: где клиент, а где сервер
В управляемой форме реквизит Объект имеет тип ДанныеФормыСтруктура. Это копия данных для клиента, а не сам объект. Методов модуля объекта у неё нет, поэтому Объект.РассчитатьИтог() в клиентской процедуре упадёт с ошибкой Метод объекта не обнаружен.
Рабочая схема — серверная процедура формы, которая превращает данные формы в объект:
&НаКлиенте
Процедура Пересчитать(Команда)
ПересчитатьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
ДокОбъект.ПересчитатьСкидки(); // меняет табличную часть
ЗначениеВРеквизитФормы(ДокОбъект, "Объект"); // вернуть изменения в форму
КонецПроцедуры
Три момента, на которых ошибаются чаще всего:
- 🔁 Обратная запись. Если функция модуля объекта меняет реквизиты или табличные части, без
ЗначениеВРеквизитФормыпользователь изменений не увидит. Если функция только считает и возвращает значение, обратная запись не нужна. - 📝 Незаписанные данные.
РеквизитФормыВЗначениеберёт то, что сейчас на экране, включая несохранённые правки.Объект.Ссылка.ПолучитьОбъект()прочитает старую версию из базы. Выбирайте осознанно. - 🌐 Без контекста. В процедуре
&НаСервереБезКонтекстареквизитаОбъектнет. Туда передают ссылку и вызываютПолучитьОбъект()— но получат записанную версию.
В модуле объекта нельзя вызвать клиентский код: открыть форму, показать вопрос, вызвать ПоказатьПредупреждение. Если функции нужен ответ пользователя, спросите его на клиенте до вызова сервера и передайте ответ параметром.
В обычных формах толстого клиента модуль формы объекта видит экспортные методы модуля объекта напрямую, по имени. Код, перенесённый из обычной формы в управляемую, перестаёт работать именно поэтому — его нужно переписать через серверную процедуру.
Параметры функции и возвращаемое значение
Параметры в 1С по умолчанию передаются по ссылке: если функция присвоит параметру новое значение, оно вернётся в вызывающий код. Чтобы этого не было, используйте Знач.
Функция СуммаСНДС(Знач Сумма, СтавкаНДС = 20, ОкруглятьДоРубля = Ложь) Экспорт
Сумма = Сумма * (100 + СтавкаНДС) / 100;
Если ОкруглятьДоРубля Тогда
Возврат Окр(Сумма, 0);
КонецЕсли;
Возврат Окр(Сумма, 2);
КонецФункции
Варианты вызова этой функции:
| Вызов | Что получится |
|---|---|
ДокОбъект.СуммаСНДС(1000) | 1200 — ставка и округление по умолчанию |
ДокОбъект.СуммаСНДС(1000, 10) | 1100 |
ДокОбъект.СуммаСНДС(1000, , Истина) | 1200 — второй параметр пропущен запятой |
ДокОбъект.СуммаСНДС(1000, 20, Истина, 5) | ошибка: слишком много параметров |
Что помнить про параметры:
- ✅ Параметры со значением по умолчанию ставьте в конец списка. Пропущенный параметр без значения по умолчанию получит
Неопределено. - ✅ Изменяемые коллекции (
ТаблицаЗначений,Массив,Структура) передаются ссылкой на один и тот же экземпляр. Даже сЗначизменение содержимого коллекции — добавление строк, удаление элементов — будет видно снаружи.Значзащищает только от присваивания параметру другого значения. - ✅ При вызове с клиента на сервер параметры сериализуются. Передавать можно примитивы, ссылки, массивы, структуры, соответствия. Объект (
ДокументОбъект) с клиента на сервер не передаётся.
Возврат значения. Функция заканчивается оператором Возврат Значение;. Если до него дело не дошло, функция вернёт Неопределено. Когда нужно вернуть несколько значений, возвращайте структуру:
Функция ПроверитьОстатки() Экспорт
Результат = Новый Структура("Успех, Сообщение", Истина, "");
// ... проверка
Возврат Результат;
КонецФункции
Для передачи данных между обработчиками записи одного экземпляра есть свойство ДополнительныеСвойства. Его удобно заполнять перед Записать() и читать в ПередЗаписью — без лишних экспортных переменных.
Модуль объекта, менеджера или общий модуль: куда положить функцию
Часто функцию кладут в модуль объекта по привычке, хотя ей не нужен конкретный экземпляр. Тогда каждый вызов тянет ПолучитьОбъект() и лишнее чтение из базы.
| Где лежит функция | Как вызывают | Когда выбирать |
|---|---|---|
| Модуль объекта | ДокОбъект.Функция() | Работа с данными одного экземпляра до записи: заполнение, пересчёт, проверка |
| Модуль менеджера | Документы.Имя.Функция(Ссылка) | Не нужен объект в памяти: печать, запросы по ссылке, списки |
| Общий модуль | ИмяМодуля.Функция(...) | Логика для разных объектов и форм |
Модуль менеджера открывается там же, где модуль объекта: Открыть модуль менеджера. Его экспортные функции доступны через Справочники.Имя и Документы.Имя без создания экземпляра. Из формы такую функцию удобно вызывать в процедуре &НаСервереБезКонтекста — серверный вызов получается легче, потому что данные формы не передаются.
Хорошее правило: если функции для работы хватает ссылки и запроса — ей место в модуле менеджера. Если ей нужны несохранённые реквизиты экземпляра — в модуле объекта.
В расширении конфигурации метод модуля объекта можно дополнить, не меняя основную конфигурацию: в модуле объекта расширения используют аннотации &Перед, &После и &Вместо с именем исходного метода. Внутри &Вместо исходный код вызывают через ПродолжитьВызов(). Обращаются к такому методу снаружи по-прежнему по исходному имени.
Ошибки при вызове функции модуля объекта и их отладка
Как найти проблему быстро:
- Синтаксический контроль. В конфигураторе в модуле нажмите
Ctrl+F7. Опечатки в именах локальных функций всплывут сразу. Вызовы через точку синтаксический контроль не проверяет — они разрешаются только во время выполнения. - Точка останова. Поставьте её на строку вызова (
F9) и запустите отладку (F5). Наведите курсор на переменную или откройте табло: там видно, этоДокументОбъектилиДокументСсылка. - Шаг внутрь. Клавиша
F11заходит в вызываемую функцию модуля объекта. Если отладчик в неё не заходит, а вызов идёт с клиента, — значит, код исполняется не там, где вы ожидаете. - Отладка на сервере. В клиент-серверной базе для серверного кода должна быть включена отладка на сервере 1С. Иначе точки останова в модуле объекта не сработают.