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