Email ABAP report PDF

The below code to demonstrates how to email ABAP report PDF. It generates an ALV output of personal numbers (PERNRS) and then converts this to a PDF document. Its then sends an external email with the PDF as an attachment

SAP ABAP report functionality used by this report

  • Email address input selection screen fields
  • Display ALV report using Objects cl_salv_table
  • Add custom ALV column header
  • Change colour of ALV rows based on user start year
  • Get ALV Spool from background execution
  • Convert Spool to PDF and send as Email
  • Submit an ABAP report in the background
  • ABAP report submits itself in the background to create spool
  • Pass parameter and select options to report submit ABAP statement

*&-------------------------------*
REPORT zrep_email_alv_spool.

TABLES:  pa0001, pa0000.

SELECTION-SCREEN BEGIN OF BLOCK block1 WITH FRAME TITLE text-001.
SELECT-OPTIONS:   so_pernr FOR pa0001-pernr.
PARAMETERS:       p_keydat TYPE datum DEFAULT sy-datum.
PARAMETERS:       p_email  TYPE ad_smtpadr DEFAULT '[email protected]'.

SELECTION-SCREEN END OF BLOCK block1.

*Data Declaration
*----------------
DATA: r_objid TYPE RANGE OF hrp1001-objid.
DATA: wa_objid LIKE LINE OF r_objid.

TYPES: BEGIN OF t_report,
         pernr       TYPE p0000-pernr,
         vorna       TYPE p0002-vorna,
         nachn       TYPE p0002-nachn,
         ename       TYPE p0001-ename,
         begda       TYPE p0000-begda,
         orgeh       TYPE p0001-orgeh,
         details(20) TYPE c,
         color       TYPE lvc_t_scol, "table for cell colouring
       END OF t_report.
DATA: it_report TYPE STANDARD TABLE OF t_report INITIAL SIZE 0,
      wa_report TYPE                   t_report.

DATA alv_table TYPE REF TO cl_salv_table.
DATA alv_columns TYPE REF TO cl_salv_columns_table.
DATA single_column TYPE REF TO cl_salv_column.

DATA: objec_tab TYPE STANDARD TABLE OF objec,
      it_dept   TYPE STANDARD TABLE OF objec,
      wa_objtab LIKE LINE OF           objec_tab,
      struc_tab TYPE STANDARD TABLE OF struc,
      wa_struc  LIKE LINE OF           struc_tab,
      ld_orgeh  TYPE                   orgeh.

DATA: gd_recsize TYPE i.

DATA: gd_eventid                 LIKE tbtcm-eventid,
      gd_eventparm               LIKE tbtcm-eventparm,
      gd_external_program_active LIKE tbtcm-xpgactive,
      gd_jobcount                LIKE tbtcm-jobcount,
      gd_jobname                 LIKE tbtcm-jobname,
      gd_stepcount               LIKE tbtcm-stepcount,
      gd_error                   TYPE sy-subrc,
      gd_reciever                TYPE sy-subrc.

DATA send_request TYPE REF TO cl_bcs.
DATA document TYPE REF TO cl_document_bcs.
DATA recipient TYPE REF TO if_recipient_bcs.
DATA bcs_exception TYPE REF TO cx_bcs.
DATA sent_to_all TYPE os_boolean.
DATA: pdf_content TYPE solix_tab.
DATA: pdf_xstring TYPE xstring.
DATA: bin_size TYPE i.
DATA pdf_size TYPE so_obj_len.


DATA:  w_recsize TYPE i.

DATA: gd_subject         LIKE sodocchgi1-obj_descr,
      it_mess_bod        LIKE solisti1 OCCURS 0 WITH HEADER LINE,
      it_mess_att        LIKE solisti1 OCCURS 0 WITH HEADER LINE,
      gd_sender_type     LIKE soextreci1-adr_typ,
      gd_attachment_desc TYPE so_obj_nam,
      gd_attachment_name TYPE so_obj_des.

* Spool to PDF conversions
DATA: gd_spool_nr    LIKE tsp01-rqident,
      gd_destination LIKE rlgrap-filename,
      gd_bytecount   LIKE tst01-dsize,
      gd_buffer      TYPE string.

* Spool IDs
TYPES: BEGIN OF t_tbtcp.
        INCLUDE STRUCTURE tbtcp.
TYPES: END OF t_tbtcp.
DATA: it_tbtcp TYPE STANDARD TABLE OF t_tbtcp INITIAL SIZE 0,
      wa_tbtcp TYPE                   t_tbtcp.

* Binary store for PDF
DATA: BEGIN OF it_pdf_output OCCURS 0.
        INCLUDE STRUCTURE tline.
DATA: END OF it_pdf_output.

DATA: seltab    TYPE TABLE OF rsparams,
      seltab_wa LIKE LINE OF  seltab.

DATA: gd_email  TYPE somlreci1-receiver,
      gd_email2 TYPE somlreci1-receiver,  "just for test/demo
      gd_email3 TYPE ad_smtpadr.          "just for test/demo

DATA: wa_addreess TYPE sx_address.

************************************************************************
* START-OF-SELECTION
START-OF-SELECTION.
  gd_email = p_email.
  gd_email2 = '#[email protected]'.
  gd_email3 = '#[email protected]'.

  PERFORM data_retrieval.
  PERFORM display_settings.
  PERFORM set_row_colors.

************************************************************************
* END-OF-SELECTION
END-OF-SELECTION.
  PERFORM display_alv_report.

  IF sy-batch EQ 'X'.
    PERFORM get_job_details.
    PERFORM obtain_spool_id.
    PERFORM convert_spool_to_pdf.
    PERFORM send.

  ELSE.
    PERFORM submit_report_in_background.
  ENDIF.


*&-------------------------------*
*& FORM data_retrieval.
*&-------------------------------*
FORM data_retrieval.
  DATA: ld_deptlines TYPE i.

  SELECT a~pernr a~begda b~vorna b~nachn c~ename  c~orgeh
    FROM pa0000 AS a INNER JOIN pa0002 AS b
      ON b~pernr EQ a~pernr
     INNER JOIN pa0001 AS c
    ON c~pernr EQ b~pernr
    INTO CORRESPONDING FIELDS OF TABLE it_report
   "for ALL ENTRIES IN it_emps
   WHERE "a~pernr eq it_emps-pernr
       a~pernr IN so_pernr
     AND a~begda LE p_keydat
     AND a~endda GE p_keydat
     AND b~begda LE p_keydat
     AND b~endda GE p_keydat
     AND c~begda LE p_keydat
     AND c~endda GE p_keydat.
ENDFORM.                    " DATA_RETRIEVAL

*&-------------------------------*
*& FORM display_settings.
*&-------------------------------*
FORM display_settings.
  DATA: err_message TYPE REF TO cx_salv_msg.

  TRY.
      cl_salv_table=>factory(
      IMPORTING
        r_salv_table = alv_table
      CHANGING
        t_table      = it_report ).

      alv_columns = alv_table->get_columns( ).

      PERFORM build_layout.
      PERFORM build_fieldcatalog.
      PERFORM build_toolbar.
      PERFORM hide_columns.
      PERFORM report_settings.

    CATCH cx_salv_msg INTO err_message.
*   Add error processing
  ENDTRY.
ENDFORM.

*&-------------------------------*
*& FORM display_alv_report.
*&-------------------------------*
FORM display_alv_report.
  alv_table->display( ).
ENDFORM.

*&-------------------------------*
*& FORM build_layout.
*&-------------------------------*
FORM build_layout.
  DATA: layout TYPE REF TO cl_salv_layout.
  DATA: layout_key TYPE salv_s_layout_key.

  layout = alv_table->get_layout( ).

  layout_key-report = sy-repid.
  layout->set_key( layout_key ).

  layout->set_save_restriction( if_salv_c_layout=>restrict_none ).
ENDFORM.                    "BUILD_LAYOUT

*&-------------------------------*
*& FORM hide_columns.
*&-------------------------------*
FORM hide_columns.
  DATA: err_notfound TYPE REF TO cx_salv_not_found.

  TRY.
      single_column = alv_columns->get_column( 'VORNA' ).
      single_column->set_visible( if_salv_c_bool_sap=>false ).
      single_column = alv_columns->get_column( 'NACHN' ).
      single_column->set_visible( if_salv_c_bool_sap=>false ).

    CATCH cx_salv_not_found INTO err_notfound.
*   Add error processing
  ENDTRY.
ENDFORM.

*&-------------------------------*
*& FORM build_fieldcatalog.
*&-------------------------------*
*  Your ALV report should get texts from the internal table used but you
*  overwrite them here if you require
*&-------------------------------*
FORM build_fieldcatalog.
  DATA: err_notfound TYPE REF TO cx_salv_not_found.

  TRY.
      single_column = alv_columns->get_column( 'BEGDA' ).
      single_column->set_short_text( 'Start Date' ).  "Will cause syntax error if text is too long
      single_column->set_medium_text( 'Start Date' ).
      single_column->set_long_text( 'Employee Start Date' ).
      single_column->set_output_length( '10' ). "Force column to be wider to accomodate heading

    CATCH cx_salv_not_found INTO err_notfound.
*   Add error processing
  ENDTRY.
ENDFORM.

*&-------------------------------*
*& FORM build_toolbar.
*&-------------------------------*
FORM build_toolbar.
  DATA: toolbar_functions TYPE REF TO cl_salv_functions_list.

  toolbar_functions = alv_table->get_functions( ).
  toolbar_functions->set_all( ).
ENDFORM.

*&-------------------------------*
*& FORM report_settings.
*&-------------------------------*
FORM report_settings.
  DATA: report_settings TYPE REF TO cl_salv_display_settings.

  report_settings = alv_table->get_display_settings( ).
  report_settings->set_striped_pattern( if_salv_c_bool_sap=>true ).
  report_settings->set_list_header( 'Demo SAP ALV Report and PDF email' ).
ENDFORM.

*&-------------------------------*
*&      Form  SET_ROW_COLORS
*&-------------------------------*
*       text
*----------------------------------------------------------------------*
FORM set_row_colors .
  DATA: lo_cols_tab TYPE REF TO cl_salv_columns_table,
        lo_col_tab  TYPE REF TO cl_salv_column_table.
  DATA: ls_color TYPE lvc_s_colo.    " Colors strucutre

  DATA: lt_s_color TYPE lvc_t_scol,
        ls_s_color TYPE lvc_s_scol,
        ld_tabix   TYPE sy-tabix.

  lo_cols_tab = alv_table->get_columns( ).


  LOOP AT it_report INTO wa_report.
    ld_tabix = sy-tabix.

    IF wa_report-begda(4) EQ sy-datum(4). "this year.
      ls_s_color-color-col = col_negative.
      ls_s_color-color-int = 1.
      ls_s_color-color-inv = 0.
      APPEND ls_s_color TO lt_s_color.
      CLEAR  ls_s_color.
    ELSE." eq other year
      ls_s_color-color-col =  7.
      ls_s_color-color-int = 1.
      ls_s_color-color-inv = 0.
      APPEND ls_s_color TO lt_s_color.
      CLEAR  ls_s_color.
    ENDIF.

    wa_report-color = lt_s_color.
    MODIFY it_report FROM wa_report INDEX ld_tabix.

    CLEAR  lt_s_color.
  ENDLOOP.

  TRY.
      lo_cols_tab->set_color_column( 'COLOR' ).
    CATCH cx_salv_data_error.                           "#EC NO_HANDLER
  ENDTRY.
ENDFORM.                    " SET_ROW_COLORS

*---------------------------------------------------------------------*
*       FORM get_job_details                                          *
*---------------------------------------------------------------------*
FORM get_job_details.
* Get current job details
  CALL FUNCTION 'GET_JOB_RUNTIME_INFO'
    IMPORTING
      eventid                 = gd_eventid
      eventparm               = gd_eventparm
      external_program_active = gd_external_program_active
      jobcount                = gd_jobcount
      jobname                 = gd_jobname
      stepcount               = gd_stepcount
    EXCEPTIONS
      no_runtime_info         = 1
      OTHERS                  = 2.
ENDFORM.

*---------------------------------------------------------------------*
*       FORM obtain_spool_id                                          *
*---------------------------------------------------------------------*
FORM obtain_spool_id.
  CHECK NOT ( gd_jobname IS INITIAL ).
  CHECK NOT ( gd_jobcount IS INITIAL ).

  SELECT * FROM  tbtcp
                 INTO TABLE it_tbtcp
                 WHERE      jobname     = gd_jobname
                 AND        jobcount    = gd_jobcount
                 AND        stepcount   = gd_stepcount
                 AND        listident  = '0000000000'
                 ORDER BY   jobname
                            jobcount
                            stepcount.

  READ TABLE it_tbtcp INTO wa_tbtcp INDEX 1.
  IF sy-subrc = 0.
    gd_spool_nr = wa_tbtcp-listident.
    MESSAGE s004(zdd) WITH gd_spool_nr.
  ELSE.
    MESSAGE s005(zdd).
  ENDIF.
ENDFORM.


*---------------------------------------------------------------------*
*       FORM convert_spool_to_pdf                                     *
*---------------------------------------------------------------------*
FORM convert_spool_to_pdf.

  CALL FUNCTION 'CONVERT_ABAPSPOOLJOB_2_PDF'
    EXPORTING
      src_spoolid              = gd_spool_nr
      no_dialog                = 'X'
      pdf_destination          = 'X'
      no_background            = 'X'
    IMPORTING
      pdf_bytecount            = bin_size
      bin_file                 = pdf_xstring
    EXCEPTIONS
      err_no_abap_spooljob     = 1
      err_no_spooljob          = 2
      err_no_permission        = 3
      err_conv_not_possible    = 4
      err_bad_destdevice       = 5
      user_cancelled           = 6
      err_spoolerror           = 7
      err_temseerror           = 8
      err_btcjob_open_failed   = 9
      err_btcjob_submit_failed = 10
      err_btcjob_close_failed  = 11
      OTHERS                   = 12.

  pdf_size = bin_size.

ENDFORM.

*---------------------------------------------------------------------*
*       FORM send_email                                               *
*---------------------------------------------------------------------*
*  -->  p_email                                                       *
*---------------------------------------------------------------------*
FORM send.
  DATA: it_contents TYPE STANDARD TABLE OF soli,
        wa_contents TYPE                   soli,
        ld_subject  TYPE                   so_obj_des.

  TRY.
      CONCATENATE 'Please fine attached the output report' ''
                       INTO wa_contents-line.
      APPEND wa_contents TO it_contents.

      ld_subject  = |Output report |.

*     -------- create persistent send request ------------------------
      send_request = cl_bcs=>create_persistent( ).

*     -------- create and set document -------------------------------
      pdf_content = cl_document_bcs=>xstring_to_solix( pdf_xstring ).

      document = cl_document_bcs=>create_document(
            i_type    = 'PDF'
            i_hex     = pdf_content
            i_length  = pdf_size
            i_subject = ld_subject
            i_text    = it_contents ).                      "#EC NOTEXT

*     add document object to send request
      send_request->set_document( document ).

*     --------- add recipient (e-mail address) -----------------------
*     create recipient object
      recipient = cl_cam_address_bcs=>create_internet_address( p_email ).

*     add recipient object to send request
      send_request->add_recipient( recipient ).

*     ---------- send document ---------------------------------------
      sent_to_all = send_request->send( i_with_error_screen = 'X' ).

      COMMIT WORK.

      IF sent_to_all IS INITIAL.
        MESSAGE i500(sbcoms) WITH p_email.
      ELSE.
        MESSAGE s022(so).
      ENDIF.

*   ------------ exception handling ----------------------------------
*   replace this rudimentary exception handling with your own one !!!
    CATCH cx_bcs INTO bcs_exception.
      MESSAGE i865(so) WITH bcs_exception->error_type.
  ENDTRY.

ENDFORM.



*&-------------------------------*
*&      Form  SUBMIT_REPORT_IN_BACKGROUND
*&-------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM submit_report_in_background .
  DATA: jobname LIKE tbtcjob-jobname VALUE
                             'TRANSFER DATA'.
  DATA: jobcount LIKE tbtcjob-jobcount,
        host     LIKE msxxlist-host.
  DATA: BEGIN OF starttime.
          INCLUDE STRUCTURE tbtcstrt.
  DATA: END OF starttime.
  DATA: starttimeimmediate LIKE btch0000-char1 VALUE 'X'.

  DATA: wa_pernr LIKE LINE OF so_pernr.

  REFRESH: seltab.

  seltab_wa-selname = 'SO_PERNR'.

  LOOP AT so_pernr INTO wa_pernr.
    seltab_wa-sign    = wa_pernr-sign.
    seltab_wa-option  = wa_pernr-option.
    seltab_wa-low    = wa_pernr-low.
    seltab_wa-high    = wa_pernr-high.
    APPEND seltab_wa TO seltab.
  ENDLOOP.

* Job open
  CALL FUNCTION 'JOB_OPEN'
    EXPORTING
      delanfrep        = ' '
      jobgroup         = ' '
      jobname          = jobname
      sdlstrtdt        = sy-datum
      sdlstrttm        = sy-uzeit
    IMPORTING
      jobcount         = jobcount
    EXCEPTIONS
      cant_create_job  = 01
      invalid_job_data = 02
      jobname_missing  = 03.
  IF sy-subrc NE 0.
    "error processing
  ENDIF.

  SUBMIT (sy-cprog) AND RETURN   "
    WITH SELECTION-TABLE seltab
    WITH p_keydat = p_keydat
    WITH p_sendto = gd_email
    USER sy-uname
    VIA JOB jobname
    NUMBER jobcount.

*    SKIP.
*    WRITE:/ 'Program must be executed in background in-order for spool',
*            'request to be created.'.

* Close job
  starttime-sdlstrtdt = sy-datum + 1.
  starttime-sdlstrttm = '220000'.
  CALL FUNCTION 'JOB_CLOSE'
    EXPORTING
      "            event_id             = starttime-eventid
      "            event_param          = starttime-eventparm
      "            event_periodic       = starttime-periodic
      jobcount             = jobcount
      jobname              = jobname
"     laststrtdt           = starttime-laststrtdt
"     laststrttm           = starttime-laststrttm
"     prddays              = 1
"     prdhours             = 0
"     prdmins              = 0
"     prdmonths            = 0
"     prdweeks             = 0
"     sdlstrtdt            = starttime-sdlstrtdt
"     sdlstrttm            = starttime-sdlstrttm
      strtimmed            = starttimeimmediate
"     targetsystem         = host
    EXCEPTIONS
      cant_start_immediate = 01
      invalid_startdate    = 02
      jobname_missing      = 03
      job_close_failed     = 04
      job_nosteps          = 05
      job_notex            = 06
      lock_failed          = 07
      OTHERS               = 99.
  IF sy-subrc EQ 0.
    "error processing
  ENDIF.

ENDFORM.                    " SUBMIT_REPORT_IN_BACKGROUND

Text pool values

Selection Text: P_ADMAIL = Admin Email
Selection Text: P_KEYDAT = Key date
Selection Text: SO_PERNR = Personnel Selection