Useful ABAP code example to demonstrate how to display an SAP ALV report which displays alist of PERNR details and then automatically allows the user to email ALV PDF as a document attchement. The code covers the following SAP ABAP report functionality:
- 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 background
- ABAP report submits itself in background to create spool
- Pass parameter and select option to report submit
- Delete SAP spool request
Click here for ABAP code and more info
ABAP code to send ALV report as PDF
*& TITLE: Display ABAP report of pernrs and email output as PDF *&-------------------------------* *& Report ZREP_EMAIL_ALV_SPOOL *&-------------------------------* *& *& SAP ABAP report functionality used *& ********************************** *& 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 background *& ABAP report submits itself in background to create spool *& Pass parameter and select option to report submit *& Delete SAP spool request *&-------------------------------* 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 'myemail@mydomain.com'. * Ensure you always declare your email parameters using AD_SMTPADR. On one occasion * when using somlreci1-receiver I found that the entered default resulted in a different * underlying hexedecimal value which SAP did not recognise as a valid email address. * For example during runtime take a look at the values contained in gd_email2 and * gd_email3. You may notice that the hex values are different from p_email. Just * somthing to think about if your email are not getting sent and SO_DOCUMENT_SEND_API1 * is returning an x_error. 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: 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 = '#myemail@mydomain.com'. gd_email3 = '#myemail@mydomain.com'. 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_email_rep. PERFORM delete_spool. 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. * set_optimize will set columns optimised based on data and will remove * any width specification setup within build_fieldcatalog column setup * it_columns->set_optimize( ). 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. *&-------------------------------* * The code below simply displays all available functions but you can * restrict this if you require *&-------------------------------* 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 *----------------------------------------------------------------------* * --> p1 text * <-- p2 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. * get Columns object lo_cols_tab = alv_table->get_columns( ). *Set column colour * TRY. * lo_col_tab ?= lo_cols_tab->get_column( 'PERNR' ). * ls_color-col = col_total. * lo_col_tab->set_color( ls_color ). * CATCH cx_salv_not_found. * ENDTRY. 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. * We will set this COLOR table field name of the internal table to * COLUMNS tab reference for the specific colors 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 = ' ' dst_device = 'LOCL' IMPORTING pdf_bytecount = gd_bytecount TABLES pdf = it_pdf_output 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. CHECK sy-subrc = 0. * Transfer the 132-long strings to 255-long strings LOOP AT it_pdf_output. TRANSLATE it_pdf_output USING ' ~'. CONCATENATE gd_buffer it_pdf_output INTO gd_buffer. ENDLOOP. TRANSLATE gd_buffer USING '~ '. DO. it_mess_att = gd_buffer. APPEND it_mess_att. SHIFT gd_buffer LEFT BY 255 PLACES. IF gd_buffer IS INITIAL. EXIT. ENDIF. ENDDO. ENDFORM. *---------------------------------------------------------------------* * FORM send_email * *---------------------------------------------------------------------* * --> p_email * *---------------------------------------------------------------------* FORM send_email_rep. data: ld_sender type somlreci1-receiver. DESCRIBE TABLE it_mess_att LINES gd_recsize. CHECK gd_recsize > 0. CHECK NOT ( gd_email IS INITIAL ). ld_sender = gd_email. REFRESH it_mess_bod. * Default subject matter gd_subject = 'Subject'. gd_attachment_desc = 'Attachname'. * CONCATENATE 'attach_name' ' ' INTO gd_attachment_name. it_mess_bod = 'Email Message Body text, line 1'. APPEND it_mess_bod. it_mess_bod = 'Email message Body text, line 2...'. APPEND it_mess_bod. * If no sender specified - default blank IF ld_sender EQ space. gd_sender_type = space. ELSE. gd_sender_type = 'INT'. ENDIF. * Send file by email as .pdf attachment PERFORM send_file_as_email_attachment TABLES IT_MESS_BOD it_mess_att using gd_email 'Example pdf document email attachment' 'PDF' gd_attachment_name gd_attachment_desc ld_sender gd_sender_type changing gd_error gd_reciever. ENDFORM. *&-------------------------------* *& Form SEND_FILE_AS_EMAIL_ATTACHMENT *&-------------------------------* * Send email *----------------------------------------------------------------------* FORM SEND_FILE_AS_EMAIL_ATTACHMENT TABLES IT_MESSAGE it_attach using p_email p_mtitle p_format p_filename p_attdescription p_sender_address p_sender_addres_type changing p_error p_reciever. DATA: ld_error TYPE sy-subrc, ld_reciever TYPE sy-subrc, ld_mtitle LIKE sodocchgi1-obj_descr, ld_email LIKE somlreci1-receiver, ld_format TYPE so_obj_tp, ld_attdescription TYPE so_obj_nam, ld_attfilename TYPE so_obj_des, ld_sender_address LIKE soextreci1-receiver, ld_sender_address_type LIKE soextreci1-adr_typ, ld_receiver LIKE sy-subrc. data: t_packing_list like sopcklsti1 occurs 0 with header line, t_contents like solisti1 occurs 0 with header line, t_receivers like somlreci1 occurs 0 with header line, t_attachment like solisti1 occurs 0 with header line, t_object_header like solisti1 occurs 0 with header line, w_cnt type i, w_sent_all(1) type c, w_doc_data like sodocchgi1. ld_email = p_email. ld_mtitle = p_mtitle. ld_format = p_format. ld_attdescription = p_attdescription. ld_attfilename = p_filename. ld_sender_address = p_sender_address. ld_sender_address_type = p_sender_addres_type. * Fill the document data. w_doc_data-doc_size = 1. * Populate the subject/generic message attributes w_doc_data-obj_langu = sy-langu. w_doc_data-obj_name = 'SAPRPT'. w_doc_data-obj_descr = ld_mtitle . w_doc_data-sensitivty = 'F'. * Fill the document data and get size of attachment CLEAR w_doc_data. READ TABLE it_attach INDEX w_cnt. w_doc_data-doc_size = ( w_cnt - 1 ) * 255 + STRLEN( it_attach ). w_doc_data-obj_langu = sy-langu. w_doc_data-obj_name = 'SAPRPT'. w_doc_data-obj_descr = ld_mtitle. w_doc_data-sensitivty = 'F'. CLEAR t_attachment. REFRESH t_attachment. t_attachment[] = it_attach[]. * Describe the body of the message CLEAR t_packing_list. REFRESH t_packing_list. t_packing_list-transf_bin = space. t_packing_list-head_start = 1. t_packing_list-head_num = 0. t_packing_list-body_start = 1. DESCRIBE TABLE it_message LINES t_packing_list-body_num. t_packing_list-doc_type = 'RAW'. APPEND t_packing_list. * Create attachment notification t_packing_list-transf_bin = 'X'. t_packing_list-head_start = 1. t_packing_list-head_num = 1. t_packing_list-body_start = 1. DESCRIBE TABLE t_attachment LINES t_packing_list-body_num. t_packing_list-doc_type = ld_format. t_packing_list-obj_descr = ld_attdescription. t_packing_list-obj_name = ld_attfilename. t_packing_list-doc_size = t_packing_list-body_num * 255. APPEND t_packing_list. * Add the recipients email address CLEAR t_receivers. REFRESH t_receivers. t_receivers-receiver = ld_email. t_receivers-rec_type = 'U'. t_receivers-com_type = 'INT'. t_receivers-notif_del = 'X'. t_receivers-notif_ndel = 'X'. APPEND t_receivers. CALL FUNCTION 'SO_DOCUMENT_SEND_API1' EXPORTING document_data = w_doc_data put_in_outbox = 'X' sender_address = ld_sender_address sender_address_type = ld_sender_address_type commit_work = 'X' IMPORTING sent_to_all = w_sent_all TABLES packing_list = t_packing_list contents_bin = t_attachment contents_txt = it_message receivers = t_receivers EXCEPTIONS too_many_receivers = 1 document_not_sent = 2 document_type_not_exist = 3 operation_no_authorization = 4 parameter_error = 5 x_error = 6 enqueue_error = 7 OTHERS = 8. * Populate zerror return code ld_error = sy-subrc. * Populate zreceiver return code LOOP AT t_receivers. ld_receiver = t_receivers-retrn_code. ENDLOOP. ENDFORM. *---------------------------------------------------------------------* * FORM delete_spool * *---------------------------------------------------------------------* FORM delete_spool. DATA: ld_spool_nr TYPE tsp01_sp0r-rqid_char. ld_spool_nr = gd_spool_nr. check not ld_spool_nr is initial. CALL FUNCTION 'RSPO_R_RDELETE_SPOOLREQ' EXPORTING spoolid = ld_spool_nr. 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
Selection Text: P_KEYDAT = Key date
Selection Text: SO_PERNR = Personnel Selection