Программная генерация PDF форм на ABAP или как избавиться от проблем со SPOOL

в 18:39, , рубрики: abap, ERP-системы, PDF, sap, Программирование, метки: , ,

С чего все началось

Специфика компании, в которой я работаю, подразумевает тесный контакт и сотрудничество с нашими клиентами. Одним из таких бизнес-процессов является рассылка различной документации как по почте, так и на бумажных носителях по наше не любимой почте в конвертах. Стандартный функционал, который позволяет генерировать печатные формы PDF и выводить их на печать или публиковать куда-либо в бинарном виде использует фоновые задачи и SPOOL данных печати.
Поначалу все было прекрасно, данные формировались, клиенты были довольны. Но в один момент все накрылось «медным тазом», объемы генерируемых печатных форм значительно выросли, SPOOL стал сильно «засераться», что приводило к жутким тормозам всей серверной части. Об одном из способов решения этой проблемы я и хочу рассказать в данной статье.

Поехали

Как это обычно бывает, первым делом все бегут с подобными проблемами к базистам, которые отвечают за работу серверной части и оптимизацию кучи различных настроек в конфигурационных файлах. Что в результате: прочитана куча SAP Notes, проштудированы форумы, потом начались изменения параметров, что-то дало небольшой прирост производительности, где-то наоборот. Но в конечном результате нужного эффекта так и не получили. Само собой давление руководства и недовольных клиентов возрастало, так как формирование документов занимало все больше и больше времени и о какой либо клиентоориентированность не могло быть и речи, что пагубно влияло на престиж компании. В результате было принято решение попробовать разобраться с проблемой на программной уровне.
Хватит уже прелюдий, перейдем к технической стороне вопроса.

Анализ базисного кода

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

  1. Создать XFT файл формуляра;
  2. Сгенерировать XFD файл, содержащий данные;
  3. Получить бинарный файл и PDL файл, который понимает принтер;

Создать XFT файл формуляра

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

DATA:
        l_xdp       TYPE fpwbformname VALUE 'ZTEST', " Имя формуляра
        l_xft       TYPE string, " Путь к формуляру на сервере приложений
        l_except TYPE REF TO cx_fp_api_repository. " Для обработки данных

TRY.
      cl_fp_wb_helper=>form_layout_exists( i_name = l_xdp ).
    CATCH cx_fp_api_usage.                              "#EC NO_HANDLER
    CATCH cx_fp_api_repository INTO l_except.
      IF l_except->textid = cx_fp_api_repository=>object_already_exists.
        l_xft = cl_fp_wb_helper=>form_layout_url( i_name      = l_xdp
                                                  i_dest_path = 'X' ).
      ELSE.
         MESSAGE ID 'FPRUNX' TYPE 'E' NUMBER '050' WITH sy-langu.
      ENDIF.
  ENDTRY.

Здесь мы проверяем существует ли формуляр в системе с заданным именем и если получаем положительный ответ, то считываем путь к этому формуляру.

Генерируем XFD файл, содержащий данные

Сформировать PDF файл — это еще пол дела. Нам необходимо наполнить его данными, чтобы это сделать нужно сгенерировать файл с данными XFD, который представляет из себя обычный xml файла. Лучшее для меня решения было — это использовать трансформации. Итак приступим.
Как нам узнать как должен выглядеть файл после трансформации, чтобы он успешно применился к нашему формуляру? Сделать это очень просто, заходим в транзакцию SFP, открываем нужный нам формуляр и включаем отладку, как показано на рисунках ниже:

Режим отладки формуляра

Выбираем в формуляре Параметры настройки
Программная генерация PDF форм на ABAP или как избавиться от проблем со SPOOL

Далее ставим режим отладки, это позволит нам после вывода печатной формы получить файлы во вложении
Программная генерация PDF форм на ABAP или как избавиться от проблем со SPOOL

Запускаем печатную форму на тест и получаем необходимые файлы во вложении PDF, нас интересует XFD.xml
Программная генерация PDF форм на ABAP или как избавиться от проблем со SPOOL

Итак, мы получили файл представления данных для печатной формы, теперь нам не составит труда создать трансформацию и вызывать ее в дальнейшем:

CALL  TRANSFORMATION ztest_trans
            SOURCE
                   is_data     = it_data
                RESULT XML xstr.

Получить бинарный файл и PDL файл, который понимает принтер

Итак, у нас есть все необходимое для того, чтобы сформировать печатную форму. Правда тут есть один нюанс. В природе как выяснилось существует различные типы принтеров, одни цветные, другие нет. Для определенной группы принтеров применяются так называемые шаблоны XSD, применяемые для генерации PDF файлов. Более подробно о их типах и классификации написано тут.
Мы будем использовать hppcl5c.xdc, так как он идеально подходит для нашей задачи, в том числе позволяет распечатывать на цветном принтере. Что мы получили:

Немного кода

DATA: l_fp        TYPE REF TO if_fp,
            l_pdfobj    TYPE REF TO if_fp_pdf_object,
            pdfresult   TYPE xstring,
            pdlresult   TYPE xstring.

* получаем ADS-соединение
 MOVE cl_fp=>get_ads_connection( ) TO l_dest.
* получаем FP reference
  l_fp = cl_fp=>get_reference( ).
TRY.
*   создаем объект PDF
    l_pdfobj = l_fp->create_pdf_object( connection = l_dest ).
*   указываем наш шаблон, который мы нашли ранее
    l_pdfobj->set_template( xftfile = l_xft ).
*   задам данные для шаблона
    l_pdfobj->set_data( formdata = l_xfd ).

*   говорим объекту PDF создать PDF
*   так же в классе есть другие задачи, которые можно глянуть в описании класса
    l_pdfobj->set_task_renderpdf( ).

* говорим объекту PDF создать PDL файл
    CALL METHOD l_pdfobj->set_task_renderpdl
      EXPORTING
        pdltype = 'pcl'
        pdlfile = ''
        xdcname = 'hppcl5c.xdc'.

    DATA: form TYPE string.
    form = i_fpwbformname.
    l_pdfobj->set_application_form_identity( application = 'SAFP'
                                             form        = form ).
*   запускаем наши задачи, вызвав ADS
    TRY.
        l_pdfobj->execute( ).

      CATCH cx_fp_runtime_internal
            cx_fp_runtime_system
            cx_fp_runtime_usage.                        "#EC NO_HANDLER

    ENDTRY.

*   получаем результат в формате XSTRING
    l_pdfobj->get_pdf( IMPORTING pdfdata = pdfresult ).
    CALL METHOD l_pdfobj->get_pdl
      IMPORTING
        pdldata = pdlresult.

  ENDTRY.

Итоги

В результате после применения данного подхода, удалось вообще исключить SPOOL как таковой в цепочке. Это позволило нам создавать довольно крупные объемы печатных форм в фоновом режиме не загружая сервер, на текущий момент порядка 5000 документов за 3 часа. Стоит обратить внимание, что такой подход позволяет так же совершать другие операции с PDF, например цифровую подпись со стороны сервера. Более детально можно изучить примеры в пакете, о котором я говорил выше в статье SAFP.

Автор: KaaPex

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js