PDF отчеты как объекты ABAP в SAP R/3

При работе в системе SAP R3 в силу специфики любой учетной системы разработчику приходится делать большое количество отчетов. Существует встроенный инструмент SAP SMART FORMS, но предпочтительно использовать универсальный формат PDF, который, кроме всего прочего, позволяет реализовать внутренню логику на JavaScript. Но есть небольшое неудобство, которое заключается в том, что для работы с PDF не реализовано никакой ООП обвязки и разработчику, каждый раз приходится выполнять одни и те же действия. Хороший программист - ленивый программист, поэтому мы созданим свой инструмент.


Создадим класс zatm_cl_pdf_module_handler для инкапсуляции действий по работе с PDF. Если внимательней смотреть на реализацию класса, то можно обратить внимание на то, что часть методов можно объявить как PROTECTED, то есть возможно создание потомков класса и переопределение этих методов. В этих методах задаются свойства печати и оставлена возможность для их изменения. А вот реализация методов:
METHOD constructor.

  CALL METHOD me->init_components( ).

ENDMETHOD.

METHOD pdf_module_show.
  " module_name IMPORTING TYPE string
  " r_var       IMPORTING TYPE REF TO zif_pdf_module_handler
  " result      RETURNING TYPE zboolean_t
  
MOVE 1 TO result.

  IF r_var IS INITIAL.
    MOVE 0 TO result.
    zcl_sys_msgbox=>message( textline = mc_callback_error ).
    EXIT.
  ENDIF.

  IF module_name IS INITIAL.
    MOVE 0 TO result.
    zcl_sys_msgbox=>message( textline = mc_name_error ).
    EXIT.
  ENDIF.

  COMPUTE result = me->try_job_open( ).
  CHECK result EQ 1.

  COMPUTE result = me->try_module_name( module_name ).
  CHECK result EQ 1.

  CALL METHOD r_var->call_pdf_function( i_name = mv_name
                                        i_docparams = mv_docparams ).

  COMPUTE result = me->try_job_close( ).

ENDMETHOD.

METHOD suffix.
  " suffix_value IMPORTING TYPE string
  " result       RETURNING TYPE string

  IF suffix_value IS INITIAL.
    MOVE mv_suffix TO result.
  ELSE.
    MOVE suffix_value TO mv_suffix.
    CALL METHOD me->fill_itcpo( ).
  ENDIF.

ENDMETHOD.

METHOD init_components.

  CALL METHOD me->fill_usr01( ).
  CALL METHOD me->fill_itcpo( ).
  CALL METHOD me->fill_hdialog( ).
  CALL METHOD me->fill_htddevice( ).
  CALL METHOD me->fill_docparams( ).
  CALL METHOD me->fill_outputparams( ).

ENDMETHOD. 

METHOD fill_usr01.

  CLEAR mv_usr01.
  CALL FUNCTION 'GET_PRINT_PARAM'
    EXPORTING
      i_bname = sy-uname
    IMPORTING
      e_usr01 = mv_usr01.

ENDMETHOD.

METHOD fill_outputparams.

  CLEAR mv_outputparams-noprint.
  "mv_outputparams-NOPRIBUTT = mv_outputparams-NODIALOG.
  mv_outputparams-device     = mv_itcpo-tdprinter.
  mv_outputparams-preview    = mv_itcpo-tdpreview.
  mv_outputparams-dest       = mv_itcpo-tddest.
  mv_outputparams-reqnew     = mv_itcpo-tdnewid.
  mv_outputparams-reqimm     = mv_itcpo-tdimmed.
  mv_outputparams-reqdel     = mv_itcpo-tddelete.
  mv_outputparams-reqfinal   = mv_itcpo-tdfinal.
  mv_outputparams-senddate   = mv_itcpo-tdsenddate.
  mv_outputparams-sendtime   = mv_itcpo-tdsendtime.
  mv_outputparams-schedule   = mv_itcpo-tdschedule.
  mv_outputparams-copies     = mv_itcpo-tdcopies.
  mv_outputparams-dataset    = mv_itcpo-tddataset.
  mv_outputparams-suffix1    = mv_itcpo-tdsuffix1.
  mv_outputparams-suffix2    = mv_itcpo-tdsuffix2.
  mv_outputparams-covtitle   = mv_itcpo-tdcovtitle.
  mv_outputparams-cover      = mv_itcpo-tdcover.
  mv_outputparams-receiver   = mv_itcpo-tdreceiver.
  mv_outputparams-division   = mv_itcpo-tddivision.
  mv_outputparams-lifetime   = mv_itcpo-tdlifetime.
  mv_outputparams-authority  = mv_itcpo-tdautority.
  mv_outputparams-rqposname  = mv_itcpo-rqposname.
  mv_outputparams-arcmode    = mv_itcpo-tdarmod.
  mv_outputparams-noarmch    = mv_itcpo-tdnoarmch.
  mv_outputparams-title      = mv_itcpo-tdtitle.
  mv_outputparams-nopreview  = mv_itcpo-tdnoprev.

  " Sets output parameters and opens the spool job
  MOVE 'X' TO: mv_outputparams-pdftagged,
               mv_outputparams-nodialog,
               mv_outputparams-preview.

ENDMETHOD.

METHOD fill_itcpo.

  CLEAR mv_itcpo.
  MOVE: 'PDF1'    TO mv_itcpo-tddest,
        'X'       TO mv_itcpo-tdimmed,
        ' '       TO mv_itcpo-tddelete,
        'PDF1'    TO mv_itcpo-tdsuffix1,
        mv_suffix TO mv_itcpo-tdsuffix2,
        '3'       TO mv_itcpo-tdlifetime,
        ' '       TO mv_itcpo-tdpreview,
        1         TO mv_itcpo-tdcopies.

ENDMETHOD.

METHOD fill_htddevice.

  CLEAR mv_htddevice.
  MOVE 'PRINTER' TO mv_htddevice.

ENDMETHOD. 

METHOD fill_hdialog.

  CLEAR mv_hdialog.
  MOVE space TO mv_hdialog.

ENDMETHOD.

METHOD fill_docparams.

  " Call the generated functional module
  " set locale RU_ru
  CHECK sy-langu EQ 'R'.
  MOVE: 'R' TO mv_docparams-langu,
        'RU' TO mv_docparams-country.

ENDMETHOD.

METHOD try_module_name.
  " module_name IMPORTING TYPE string
  " result      RETURNING TYPE zboolean_t

  " Get the name of the generated function module
  DATA: lv_name TYPE fpname,
        oref TYPE REF TO cx_root,
        lv_errstr TYPE string,
        lv_textline TYPE string.

  MOVE 0 TO result.

  CHECK NOT module_name IS INITIAL.

  MOVE module_name TO lv_name.
  TRY.
      CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
        EXPORTING
          i_name     = lv_name
        IMPORTING
          e_funcname = mv_name.

      MOVE 1 TO result.
    CATCH cx_root INTO oref.
      MOVE oref->get_text( ) TO lv_errstr.
      MOVE lv_errstr TO lv_textline.
    CLEANUP.
      MOVE mc_others_error TO lv_textline.
      MOVE 0 TO result.
  ENDTRY.

  IF sy-subrc NE 0.
    MOVE 0 TO result.
  ENDIF.
  " Message
  IF NOT lv_textline IS INITIAL.
    zcl_sys_msgbox=>message( textline = lv_textline ).
  ENDIF.

ENDMETHOD.

METHOD try_job_open.
  " result RETURNING TYPE zboolean_t

  " Sets the output parameters and opens the spool job
  DATA: oref TYPE REF TO cx_root,
        lv_errstr TYPE string,
        lv_textline TYPE string.

  MOVE 0 TO result.

  TRY.
      CALL FUNCTION 'FP_JOB_OPEN'
        CHANGING
          ie_outputparams = mv_outputparams
        EXCEPTIONS
          cancel          = 1
          usage_error     = 2
          system_error    = 3
          internal_error  = 4
          OTHERS          = 5.

      MOVE 1 TO result.
    CATCH cx_root INTO oref.
      MOVE oref->get_text( ) TO lv_errstr.
      MOVE lv_errstr TO lv_textline.
    CLEANUP.
      MOVE 0 TO result.
  ENDTRY.

  IF sy-subrc NE 0.
    CASE sy-subrc.
      WHEN 1.
        MOVE mc_usage_error TO lv_textline.
      WHEN 2.
        MOVE mc_system_error TO lv_textline.
      WHEN 3.
        MOVE mc_internal_error TO lv_textline.
      WHEN OTHERS.
        MOVE mc_others_error TO lv_textline.
    ENDCASE.
    MOVE 0 TO result.
  ENDIF.
  " Message
  IF NOT lv_textline IS INITIAL.
    zcl_sys_msgbox=>message( textline = lv_textline ).
  ENDIF.

ENDMETHOD.

METHOD try_job_close.
  " result RETURNING TYPE zboolean_t

  " Close the spool job
  DATA: oref TYPE REF TO cx_root,
        lv_errstr TYPE string,
        lv_textline TYPE string.

  MOVE 0 TO result.

  TRY.
      CALL FUNCTION 'FP_JOB_CLOSE'
"        IMPORTING
"          e_result             =
        EXCEPTIONS
          usage_error           = 1
          system_error          = 2
          internal_error        = 3
          OTHERS                = 4.

      MOVE 1 TO result.
    CATCH cx_root INTO oref.
      MOVE oref->get_text( ) TO lv_errstr.
      MOVE lv_errstr TO lv_textline.
    CLEANUP.
      MOVE 0 TO result.
  ENDTRY.

  IF sy-subrc NE 0.
    CASE sy-subrc.
      WHEN 1.
        MOVE mc_usage_error TO lv_textline.
      WHEN 2.
        MOVE mc_system_error TO lv_textline.
      WHEN 3.
        MOVE mc_internal_error TO lv_textline.
      WHEN OTHERS.
        MOVE mc_others_error TO lv_textline.
    ENDCASE.
    MOVE 0 TO result.
  ENDIF.
  " Message
  IF NOT lv_textline IS INITIAL.
    zcl_sys_msgbox=>message( textline = lv_textline ).
  ENDIF.

ENDMETHOD.

А вот пример использования.

REPORT ztst.

PARAMETERS: p_test AS CHECKBOX.

START-OF-SELECTION.

*----------------------------------------------------------------------*
*       CLASS lcl_pdf_print DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_pdf_print DEFINITION.
  PUBLIC SECTION.
    INTERFACES zatm_if_pdf_module_handler.
    METHODS: show_pdf_form IMPORTING i_name TYPE fpname.
*    DATA: m_items  TYPE zmm_m15_items_tt,
*          m_header TYPE zmm_m15_header_wa.
ENDCLASS.                    "lcl_pdf_print DEFINITION
*----------------------------------------------------------------------*
*       CLASS lcl_pdf_print IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_pdf_print IMPLEMENTATION.
  METHOD show_pdf_form.
 " Наследник zcl_module_handler
    DATA: opdf TYPE REF TO zatm_cl_pdf_module_handler.
    CREATE OBJECT opdf
      TYPE zatm_cl_pdf_module_handler.
    CALL METHOD opdf->show_pdf
      EXPORTING
        i_fpname = i_name
        io_if    = me.
    FREE opdf.
  ENDMETHOD.                    "show_pdf_form
  METHOD zatm_if_pdf_module_handler~call_pdf_function.
    DATA:  ls_usr02 TYPE  usr02.
    CALL FUNCTION i_name
      EXPORTING
        /1bcdwb/docparams = i_docparams
        is_user             = ls_usr02
*        itemsm15          = m_items[]
*        headm15           = m_header
      EXCEPTIONS
        usage_error       = 1
        system_error      = 2
        internal_error    = 3
        OTHERS            = 4.
  ENDMETHOD.                    "zif_pdf_module_handler~call_pdf_function
ENDCLASS.                    "lcl_pdf_print IMPLEMENTATION

*&---------------------------------------------------------------------*
*&      Form  DATA_PRINT
*&---------------------------------------------------------------------*
*       Вывод в PDF
*----------------------------------------------------------------------*
FORM data_print.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
      percentage = 10
      text       = 'Выгрузка данных в PDF... '.

  " Вывод в формуляр
  DATA: l_pdf_print TYPE REF TO lcl_pdf_print.
  CREATE OBJECT l_pdf_print.
*  l_pdf_print->m_header  = gs_header.
*  l_pdf_print->m_items[] = gt_items[].
  CALL METHOD l_pdf_print->show_pdf_form( 'ZTEST' ).
  FREE l_pdf_print.

ENDFORM.                    " DATA_PRINT

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

Комментарии