Как программно получить печатную форму из внешней обработки в 1С?

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

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

Давайте разберем эту ситуацию подробнее. Мы пытаемся использовать конструкцию вида ИмяМенеджераПечати = "ВнешняяПечатнаяФорма.ПФ_УПД_Бренд2";, но она не срабатывает. Это происходит потому, что метод УправлениеПечатью.СформироватьПечатныеФормы() предназначен для вызова встроенных механизмов печати, определенных в конфигурации (например, для документов, отчетов, обработок), а внешние печатные формы представляют собой отдельные файлы, которые подключаются к системе через справочник «Дополнительные отчеты и обработки» и имеют свой уникальный механизм вызова. Для программного обращения к таким объектам можно использовать универсальный код вызова дополнительной обработки средствами БСП.

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

Решение 1: Прямой вызов экспортной функции внешней обработки

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

  1. Находим и получаем двоичные данные внешней обработки. Прежде всего, нам нужно найти запись о нашей внешней печатной форме в справочнике ДополнительныеОтчетыИОбработки. Мы ищем ее по имени объекта, которое обычно соответствует имени файла обработки без расширения или специфическому идентификатору, который указывается при регистрации ВПФ.

    Получив ссылку на элемент справочника, мы можем извлечь двоичные данные самой обработки, которые хранятся в реквизите ХранилищеОбработки.

    
    ВнешняяОбработкаЭлементСправочника = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоРеквизиту("ИмяОбъекта", "ПФ_УПД_Бренд2");
    Если ВнешняяОбработкаЭлементСправочника Тогда
        ДвоичныеДанные = ВнешняяОбработкаЭлементСправочника.ХранилищеОбработки.Получить();
    Иначе
        Сообщить("Внешняя печатная форма с указанным именем не найдена.");
        Возврат Неопределено;
    КонецЕсли;
    

    Здесь "ПФ_УПД_Бренд2" — это имя объекта внешней обработки, которое вы указывали при ее регистрации.

  2. Сохраняем двоичные данные во временный файл. Чтобы 1С могла работать с внешней обработкой как с программным объектом, нам необходимо записать ее двоичные данные во временный файл на диске. Это позволит платформе загрузить обработку для выполнения.

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

    ОбъектВнешнейОбработки = ВнешниеОбработки.Создать(ИмяВременногоФайла, Ложь);
  4. Вызываем экспортную функцию для формирования печатной формы. Самый важный шаг – это вызов функции внутри самой внешней обработки, которая сформирует и вернет нам табличный документ. Критически важно, чтобы во внешней обработке существовала экспортная функция, которая принимает необходимые для печати параметры (например, ссылку на объект документа) и возвращает объект типа ТабличныйДокумент.

    
    Если ОбъектВнешнейОбработки <> Неопределено Тогда
        // Проверяем наличие экспортной функции, например, "СформироватьПечатнуюФорму"
        Если ОбъектВнешнейОбработки.Метаданные().ЭкспортныеФункции.Содержит("СформироватьПечатнуюФорму") Тогда
            // Вызываем экспортную функцию, передавая ей необходимые данные
            // Например, ссылку на объект документа, для которого нужна печатная форма
            ТабДок = ОбъектВнешнейОбработки.СформироватьПечатнуюФорму(Выборка.Объект);
            
            // Далее работаем с полученным ТабДок: сохраняем, помещаем во временное хранилище и т.д.
        Иначе
            Сообщить("Внешняя печатная форма не содержит экспортную функцию 'СформироватьПечатнуюФорму'.");
            ТабДок = Неопределено;
        КонецЕсли;
    Иначе
        ТабДок = Неопределено;
    КонецЕсли;
    
    УдалитьФайлы(ИмяВременногоФайла); // Обязательно удаляем временный файл после использования
    

    Здесь Выборка.Объект – это пример ссылки на документ (например, РеализацияТоваровУслугСсылка), для которого мы хотим получить печатную форму.

Таким образом, во внешней печатной форме должна быть следующая экспортная функция:


// В модуле объекта внешней печатной формы (.epf)
Функция СформироватьПечатнуюФорму(СсылкаНаОбъект) Экспорт
    ТабличныйДокумент = Новый ТабличныйДокумент;
    // ... здесь располагается весь код по формированию макета и заполнению ТабличныйДокумент ...
    
    // Пример заполнения:
    // Макет = ПолучитьМакет("МойМакет");
    // ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    // ОбластьЗаголовок.Параметры.НазваниеДокумента = СсылкаНаОбъект.Представление;
    // ТабличныйДокумент.Вывести(ОбластьЗаголовок);
    
    Возврат ТабличныйДокумент;
КонецФункции

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

Решение 2: Модификация внешней печатной формы для возврата результата через реквизит (в случаях, когда процедура "Печать" не возвращает значение)

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

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

  1. Добавляем реквизит в модуль объекта внешней обработки. В модуле объекта внешней печатной формы (файл .epf) мы объявляем новую переменную (или реквизит обработки), которая будет хранить сформированный табличный документ. Назовем ее, например, ДляПередачи и установим тип ТабличныйДокумент.

    
    // В модуле объекта внешней печатной формы (.epf)
    Перем ДляПередачи Экспорт; // Объявляем переменную как Экспорт, чтобы к ней можно было обратиться
    // Или, если это реквизит обработки, достаточно объявить его в списке реквизитов
    // и затем использовать "ЭтотОбъект.ДляПередачи"
    
  2. Изменяем процедуру "Печать" для заполнения реквизита. Мы модифицируем существующую экспортную процедуру Печать так, чтобы она не только формировала табличный документ (как обычно), но и присваивала его нашему новому реквизиту ДляПередачи. Это не изменит ее стандартное поведение, но сделает результат доступным для других функций.

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

    
    // В модуле объекта внешней печатной формы (.epf)
    Функция ПолучитьПечатнуюФормуДляВложения(Объект) Экспорт
        МассивОбъектов = Новый Массив;
        МассивОбъектов.Добавить(Объект);
        
        // Создаем необходимые параметры, которые процедура Печать может ожидать
        ПараметрыПечати = Новый Структура;
        КоллекцияПечатныхФорм = Новый КоллекцияПечатныхФорм;
        ОбъектыПечати = Новый Структура;
        
        // Вызываем процедуру Печать. Она сформирует табличный документ
        // и присвоит его значение нашему реквизиту "ДляПередачи"
        Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати);
        
        // Возвращаем сформированный и сохраненный в реквизите табличный документ
        Возврат ДляПередачи;
    КонецФункции
    

    После этих изменений мы можем использовать этот подход в нашем основном коде:

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

Дальнейшая работа с полученным табличным документом

Независимо от того, какой из двух подходов мы выбрали, в результате мы получаем объект типа ТабличныйДокумент. С этим объектом мы можем выполнить различные действия, например, сохранить его в файл определенного формата (XLSX, PDF и т.д.) или поместить во временное хранилище для дальнейшей передачи (например, в качестве вложения к электронному письму). Если же требуется отобразить результат пользователю в типовом интерфейсе, можно использовать обработку для печати табличного документа через общую форму БСП.

Рассмотрим, как мы можем сохранить его в формате XLSX и поместить во временное хранилище, как это требовалось в исходной задаче:


// Предположим, что ТабДок уже содержит сформированный табличный документ
// полученный одним из описанных выше способов.
Если ТабДок <> Неопределено Тогда
    ВременныйФайл = ПолучитьИмяВременногоФайла("XLSX"); // Создаем имя временного файла с расширением XLSX
    ТабДок.Записать(ВременныйФайл, ТипФайлаТабличногоДокумента.XLSX); // Сохраняем табличный документ в файл
    
    ДвоичныеДанные = Новый ДвоичныеДанные(ВременныйФайл); // Получаем двоичные данные из сохраненного файла
    
    // Помещаем двоичные данные во временное хранилище и получаем ссылку на них
    СсылкаНаВложение = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
    
    УдалитьФайлы(ВременныйФайл); // Удаляем временный файл с диска для очистки
    
    Возврат СсылкаНаВложение; // Возвращаем ссылку на данные во временном хранилище
Иначе
    Возврат Неопределено;
КонецЕсли;

Метод ПоместитьВоВременноеХранилище() позволяет получить уникальный идентификатор, который можно использовать для дальнейшей работы с этими данными в рамках сеанса 1С или для их передачи между различными частями системы (например, из серверного модуля в клиентский).

Важные замечания

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

← На главную