Как правильно вызвать процедуру из внешнего отчета при замене стандартного механизма заполнения

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

При разработке внешних отчетов и обработок в среде 1С:Предприятие 8.3 (особенно в типовых конфигурациях вроде «Бухгалтерия предприятия 3.0») часто возникает задача подменить стандартную логику заполнения документа. Например, в документе Акт сверки взаиморасчетов используется типовой механизм формирования данных, который запускается в фоновом задании. Попытка просто скопировать вызов функции ДлительныеОперации.ВыполнитьВФоне во внешний отчет приводит к ошибкам, так как система не может найти процедуру внешнего файла по строковому пути.

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

Почему нельзя просто использовать «ДлительныеОперации.ВыполнитьВФоне» для внешнего отчета?

Разберем ситуацию: в типовом решении вы видите код, который обращается к процедуре по ее полному имени в конфигурации, например: "Документы.АктСверкиВзаиморасчетов.ПодготовитьДанныеДляЗаполнения". Когда вы создаете внешний отчет (файл .erf), этот объект не является частью метаданных основной конфигурации. Метод ВыполнитьВФоне создает новый сеанс на сервере, в котором «область видимости» ограничена только тем, что прописано в дереве метаданных.

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

Решение 1: Синхронный вызов через преобразование реквизита формы в значение

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

Для начала нам необходимо получить объект нашего отчета из данных формы. На управляемых формах мы работаем с данными формы (тип ОтчетОбъект.ИмяВашегоОтчета), а методы модуля объекта доступны только у «настоящего» объекта. Для этого используем метод РеквизитФормыВЗначение.

Проанализируем пример кода, который необходимо разместить в модуле формы вашего внешнего отчета:


&НаСервере
Процедура ВыполнитьЗаполнениеНаСервере()
    
    // 1. Преобразуем данные формы в объект внешнего отчета
    // Это позволяет нам обращаться к экспортным процедурам модуля объекта
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
    
    // 2. Подготавливаем структуру параметров (аналогично типовому акту сверки)
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("Организация", Отчет.Организация);
    СтруктураПараметров.Вставить("Контрагент",  Отчет.Контрагент);
    СтруктураПараметров.Вставить("НачалоПериода", Отчет.НачалоПериода);
    СтруктураПараметров.Вставить("КонецПериода",  Отчет.КонецПериода);
    
    // 3. Вызываем вашу процедуру из модуля объекта
    // Убедитесь, что в модуле объекта процедура объявлена с ключевым словом Экспорт
    РезультатЗаполнения = ОтчетОбъект.ПодготовитьДанныеДляЗаполнения(СтруктураПараметров);
    
    // 4. Обрабатываем полученный результат
    // Если нужно вернуть данные в форму, используем ЗначениеВРеквизитФормы
    ЗначениеВРеквизитФормы(ОтчетОбъект, "Отчет");
    
КонецПроцедуры

Обратите внимание: в модуле объекта ваша процедура должна выглядеть следующим образом:


// В модуле ОБЪЕКТА внешнего отчета
Процедура ПодготовитьДанныеДляЗаполнения(Параметры) Экспорт
    // Здесь ваш кастомный запрос
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ..."; // Ваш измененный текст запроса
    
    // Логика обработки данных
КонецПроцедуры

Решение 2: Перенос логики в модуль формы (упрощенный вариант)

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

Рассмотрим этот вариант:

  1. Скопируйте текст типовой процедуры в модуль формы вашего отчета.
  2. Добавьте префикс &НаСервере перед процедурой.
  3. В обработчике команды (нажатие кнопки) вызывайте ее напрямую.

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


&НаСервере
Функция ВыполнитьПодготовкуДанных()
    
    // Имитируем структуру, которую возвращает ДлительныеОперации.ВыполнитьВФоне
    Результат = Новый Структура;
    Результат.Вставить("Статус", "Выполнено");
    Результат.Вставить("ИдентификаторЗадания", Неопределено);
    
    // Вызываем нашу локальную процедуру подготовки
    ПодготовитьДанныеДляЗаполненияЛокально();
    
    Возврат Результат;
КонецФункции

Решение 3: Использование механизмов БСП для фонового выполнения

Если вы все же хотите сохранить возможность фонового выполнения (например, если запрос очень тяжелый и вы не хотите «вешать» интерфейс пользователя), правильным путем в рамках БСП (Библиотеки стандартных подсистем) будет регистрация вашего отчета в справочнике Дополнительные отчеты и обработки.

Рассмотрим, как это работает программно:

Критически важные моменты при работе с параметрами

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

  1. Потеря контекста формы: В типовом акте сверки процедура может обращаться к реквизитам документа через ЭтотОбъект. Во внешнем отчете у вас нет этого документа в базе. Все данные, которые нужны для запроса (организация, контрагент), должны передаваться через структуру Параметры.
  2. Типы данных: Убедитесь, что типы передаваемых параметров совпадают с теми, что ожидает запрос. Например, если в типовой процедуре ожидается массив контрагентов, а вы передаете одиночную ссылку, запрос может отработать некорректно.
  3. Экспортные методы: Если вы решили оставить процедуру в модуле объекта, никогда не забывайте про ключевое слово Экспорт. Без него метод будет невидим для контекста формы, даже после применения РеквизитФормыВЗначение.

Подводя итог, можно сказать следующее: для внешнего отчета в 90% случаев оптимальным решением является синхронный вызов через ОтчетОбъект = РеквизитФормыВЗначение("Отчет"). Это дает полный контроль над логикой запроса и позволяет избежать сложностей с инициализацией внешних файлов в сеансах фоновых заданий.

← На главную