Вызов экспортных методов модуля менеджера: из формы, с сервера и по имени объекта
Содержание
Функцию из модуля менеджера вызывают через менеджер объекта: Справочники.Номенклатура.ИмяФункции(Параметры) или Документы.ПоступлениеТоваровУслуг.ИмяФункции(Параметры). Работает это при двух условиях: функция объявлена с ключевым словом Экспорт, а вызов идёт в серверном контексте. С тонкого клиента
и из клиентских процедур формы менеджер напрямую недоступен — нужен промежуточный серверный метод.
Самая частая ошибка — писать такой вызов прямо в обработчике кнопки с директивой &НаКлиенте. Конфигуратор при проверке модуля ругается Переменная не определена (Справочники), хотя функция в модуле менеджера есть и объявлена правильно. Дело не в функции, а в том, откуда её зовут. Всё ниже относится к платформе 8.3 и управляемым формам, от конфигурации не зависит.
Где модуль менеджера выполняется и почему клиент его не видит
Модуль менеджера есть у справочников, документов, регистров, обработок, отчётов, планов видов характеристик и других прикладных объектов. Открывается он в Конфигураторе: правой кнопкой по объекту в дереве → Открыть модуль менеджера. Или на закладке «Прочее» в окне свойств объекта.
Код модуля менеджера компилируется в таких контекстах:
- 🖥️ сервер (основной сценарий в клиент-серверной и файловой базе);
- 🧱 толстый клиент в режиме обычного приложения;
- 🔌 внешнее соединение (COM-подключение к базе).
В тонком клиенте и веб-клиенте его нет. Глобальные свойства Справочники, Документы, РегистрыСведений и подобные на клиенте управляемого приложения просто не определены. Поэтому любой путь вызова сводится к одному: сначала попасть на сервер, а уже там обратиться к менеджеру.
В типовых конфигурациях на базе БСП весь модуль менеджера обычно обёрнут в инструкцию препроцессора:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
Функция ОстатокПоСкладу(Номенклатура, Склад) Экспорт
// ...
Возврат 0;
КонецФункции
#КонецОбласти
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
Обёртка не даёт случайно скомпилировать модуль там, где он работать не должен. Свои функции добавляйте внутрь блока #Если, иначе они не скомпилируются вовсе или поведут себя непредсказуемо.
Как объявить функцию, чтобы её можно было вызвать снаружи
Без Экспорт функция видна только внутри своего модуля менеджера. Снаружи вызов даст ошибку Метод объекта не обнаружен (ИмяФункции).
Минимальный рабочий пример для справочника «Номенклатура»:
// Модуль менеджера справочника Номенклатура
Функция АртикулПоСсылке(Ссылка) Экспорт
Если Не ЗначениеЗаполнено(Ссылка) Тогда
Возврат "";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Артикул;
КонецЕсли;
Возврат "";
КонецФункции
Правила оформления, которые стоит соблюдать сразу:
- Экспортные методы держите в области
ПрограммныйИнтерфейс, служебные — вСлужебныеПроцедурыИФункции. Так другой разработчик сразу видит, что можно вызывать. - Функция возвращает значение через
Возврат. Процедура не возвращает ничего, и попытка присвоить её результат переменной — ошибка. - Имя метода не должно совпадать со стандартными методами менеджера:
НайтиПоКоду,Выбрать,СоздатьЭлемент,ПолучитьФормуи т. п. - В модуле менеджера нет
ЭтотОбъекти нет данных конкретного элемента. Всё нужное передавайте параметрами — обычно ссылку.
В модуль менеджера кладут логику «про тип в целом»: печать, заполнение, проверки по ссылке, запросы по всем элементам. Логику конкретного записываемого объекта — в модуль объекта.
Вызов функции модуля менеджера из серверного кода
На сервере вызов прямой. Это верно для модуля объекта, модуля набора записей, другого модуля менеджера, общего модуля с флажком «Сервер» и процедур формы с директивами &НаСервере или &НаСервереБезКонтекста.
// Модуль объекта документа РеализацияТоваровУслуг
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Для Каждого Строка Из Товары Цикл
Артикул = Справочники.Номенклатура.АртикулПоСсылке(Строка.Номенклатура);
Если ПустаяСтрока(Артикул) Тогда
// сообщить пользователю и установить Отказ = Истина
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Пример иллюстрирует синтаксис. В реальном коде запрос в цикле по строкам лучше заменить одним запросом по всей табличной части: при 500 строках это 500 обращений к базе против одного.
Для других видов объектов синтаксис тот же, меняется только коллекция менеджеров:
| Вид объекта | Как обратиться к менеджеру |
|---|---|
| Справочник | Справочники.Имя.Функция() |
| Документ | Документы.Имя.Функция() |
| Регистр сведений | РегистрыСведений.Имя.Функция() |
| Регистр накопления | РегистрыНакопления.Имя.Функция() |
| Обработка | Обработки.Имя.Функция() |
| Отчёт | Отчеты.Имя.Функция() |
| План видов характеристик | ПланыВидовХарактеристик.Имя.Функция() |
| Перечисление | Перечисления.Имя.Функция() |
Вызов из формы: клиент → сервер → менеджер
Кнопка формы обрабатывается на клиенте. Чтобы получить результат функции модуля менеджера, добавьте в модуль формы серверную функцию-посредника.
&НаКлиенте
Процедура ПоказатьАртикул(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Артикул = АртикулНаСервере(ТекущиеДанные.Номенклатура);
ПоказатьПредупреждение(, "Артикул: " + Артикул);
КонецПроцедуры
&НаСервереБезКонтекста
Функция АртикулНаСервере(Номенклатура)
Возврат Справочники.Номенклатура.АртикулПоСсылке(Номенклатура);
КонецФункции
Почему именно &НаСервереБезКонтекста, а не &НаСервере:
- ⚡ при
&НаСерверена сервер уходят все данные формы, включая табличные части; при большом документе это заметная задержка на каждом клике; - 📦 при
&НаСервереБезКонтекстапередаются только параметры функции; - 🧩
&НаСерверенужен, если внутри посредника вы читаете или меняете реквизиты формы (Объект, реквизиты на форме).
Через общий модуль с вызовом сервера
Если одна и та же функция нужна из многих форм, посредника выносят в общий модуль. В свойствах модуля включают флажки «Сервер» и «Вызов сервера», клиентские флажки оставляют выключенными.
// Общий модуль РаботаСНоменклатуройВызовСервера (Сервер + Вызов сервера)
Функция АртикулНоменклатуры(Номенклатура) Экспорт
Возврат Справочники.Номенклатура.АртикулПоСсылке(Номенклатура);
КонецФункции
С клиента вызов выглядит так: Артикул = РаботаСНоменклатуройВызовСервера.АртикулНоменклатуры(Ссылка);. Суффикс ВызовСервера в имени — соглашение типовых конфигураций, по нему видно, что каждое обращение к модулю стоит одного серверного вызова.
| Способ | Когда подходит | Минус |
|---|---|---|
&НаСервереБезКонтекста в форме | Нужен в одной форме | Код дублируется, если форм много |
&НаСервере в форме | Нужны данные формы | Тяжёлая передача контекста |
| Общий модуль «Вызов сервера» | Нужен во многих местах | Ещё один модуль в конфигурации |
Обращение к менеджеру по имени объекта
Иногда тип объекта известен только во время выполнения: универсальная обработка, подписка на событие на несколько документов, код в расширении. Тогда к менеджеру обращаются по имени через квадратные скобки:
ИмяСправочника = "Номенклатура";
Менеджер = Справочники[ИмяСправочника];
Результат = Менеджер.АртикулПоСсылке(Ссылка);
Если известна только ссылка, имя берут из метаданных: Ссылка.Метаданные().Имя. Для документа менеджер будет Документы[Ссылка.Метаданные().Имя].
В конфигурациях на БСП для этого есть готовые функции общего модуля ОбщегоНазначения:
ОбщегоНазначения.МенеджерОбъектаПоСсылке(Ссылка)— менеджер по ссылке любого ссылочного типа;ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени("Справочник.Номенклатура")— менеджер по полному имени объекта метаданных;ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяМетода, Параметры)— вызов экспортного метода по строковому имени с проверкой этого имени.
Перед вызовом метода по имени проверьте, что у объекта такой метод вообще есть. Иначе при добавлении нового документа в подписку код упадёт с Метод объекта не обнаружен.
Не собирайте вызов через Выполнить или Вычислить из строки, которую может изменить пользователь или внешний файл. Это прямой путь к выполнению чужого кода на сервере. Если имя метода приходит извне, используйте ВыполнитьМетодКонфигурации из БСП или сверяйте имя с белым списком.
Директивы компиляции, права и привилегированный режим
В самом модуле менеджера директивы &НаКлиенте и &НаСервере не пишут — они для модулей форм и команд. Контекст модуля менеджера управляется только инструкциями препроцессора #Если ... Тогда, как в примере выше.
С правами всё проще, чем кажется. Код модуля менеджера выполняется с правами текущего пользователя. Если в функции есть запрос к регистру, на который у пользователя нет права «Чтение», вызов завершится ошибкой о недостаточных правах.
Варианты решения:
- Дать роли пользователя нужное право — если это действительно его данные.
- Вынести запрос в общий серверный модуль с флажком «Привилегированный» и вызывать его из модуля менеджера.
- Включить привилегированный режим точечно, внутри функции:
УстановитьПривилегированныйРежим(Истина);
// запрос к защищённым данным
УстановитьПривилегированныйРежим(Ложь);
Привилегированный режим отключает проверку прав и RLS для всего кода внутри. Возвращайте на клиент только тот результат, который пользователь вправе видеть. Не отдавайте наружу целиком таблицы, прочитанные в привилегированном режиме.
Отдельный случай — безопасный режим. Если ваш код выполняется через Выполнить в безопасном режиме (так типовые конфигурации запускают часть внешних обработок), часть операций с файлами, COM и внешними компонентами будет запрещена. Сама функция модуля менеджера при этом вызывается, но упадёт на запрещённой операции внутри.
Параметры и возвращаемые значения между клиентом и сервером
Пока вызов идёт сервер → менеджер, передавать можно что угодно: объекты, таблицы значений, менеджеры временных таблиц. Ограничения появляются на границе клиент ↔ сервер.
Что передаётся без проблем:
- ✅ примитивы: строка, число, дата, булево;
- ✅ ссылки на объекты базы;
- ✅
Структура,Массив,Соответствиеиз таких значений; - ✅
ФиксированнаяСтруктура,ФиксированныйМассив.
Что вызовет ошибку при возврате на клиент:
- ❌
ТаблицаЗначений,ДеревоЗначений— на тонком клиенте этих типов нет; - ❌
СправочникОбъект,ДокументОбъект— объекты живут только на сервере; - ❌
Запрос,РезультатЗапроса,МенеджерВременныхТаблиц.
Таблицу значений для клиента превращают в массив структур или кладут во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор). На форме по адресу её потом забирают серверным вызовом.
Ещё одна тонкость — передача по ссылке. Параметр без Знач при серверном вызове возвращается на клиент вместе с изменениями. Если функция меняет полученную структуру, клиент увидит новые значения. Если изменения не нужны, объявляйте параметр как Знач — меньше данных гоняется обратно.
Функция ЦенаНаДату(Знач Номенклатура, Знач Дата, Знач ВидЦены) Экспорт
// ...
КонецФункции
Вернуть несколько значений удобнее всего структурой: Возврат Новый Структура("Цена, Валюта", Цена, Валюта);. На клиенте поля читаются как Результат.Цена и Результат.Валюта.
Ошибки при вызове и как их разобрать
Ещё две ситуации, которые не дают текста ошибки, но ломают логику:
- 🔄 Правка модуля «не применилась». Вы изменили функцию, а база работает по-старому. Конфигурацию сохранили, но не обновили конфигурацию базы данных (
F7), либо у пользователя открыт старый сеанс — ему нужно перезапустить 1С. - 🧩 В расширении функция не видна. Новый экспортный метод в модуле менеджера расширения вызывается так же, через
Справочники.Имя. Если объект не заимствован в расширение, модуля менеджера у него в расширении нет — сначала заимствуйте объект.
Частые вопросы
Можно ли вызвать функцию модуля менеджера внешней обработки?
Обработки. Её методы вызывают у объекта: создайте его через ВнешниеОбработки.Создать(ИмяФайла) и вызывайте экспортные методы модуля объекта.Чем модуль менеджера отличается от общего модуля для хранения функций?
Можно ли закешировать результат функции модуля менеджера?
Работает ли вызов функции модуля менеджера через COM-соединение?
Соединение.Справочники.Номенклатура.ИмяФункции(...), функция должна быть экспортной.