Many a times third parties send their data in a file that will update for example a material master. For these scenarios we can use the standard IDoc to post data. IDoc gives us detailed messages as well a good logging feature and if something goes wrong we can reprocess them.
We will do this in the following steps:
- Read file
- Validate file
- Build IDoc
- Post IDoc
- Display log/IDoc status
Technically we will touch upon these things:
- Reading a file from PC
- Building an IDoc
- Posting an IDoc
- Building log messages
- Displaying log messages
- Tab strip
- Hotspot in an ALV
The file that comes in will be uploaded by the user from her local PC so we will give an option of F4 on file location. For this the code will be:
* F4AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.PERFORM open_file.
FORM open_file .DATA:l_t_file_table TYPE TABLE OF file_table,l_s_file_table TYPE file_table.CALL METHOD cl_gui_frontend_services=>file_open_dialogCHANGINGfile_table = l_t_file_tablerc = v_subrcEXCEPTIONSfile_open_dialog_failed = 1cntl_error = 2error_no_gui = 3not_supported_by_gui = 4OTHERS = 5.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.READ TABLE l_t_file_table INTO l_s_file_table INDEX 1.p_file = l_s_file_table-filename.
Before we start let’s open a log handle to a log so that any errors or success messages can be recorded.
FORM open_log .* create a logg_s_log-extnumber = 'Application Log in Subscreen'(001).CALL FUNCTION 'BAL_LOG_CREATE'EXPORTINGi_s_log = g_s_logIMPORTINGe_log_handle = g_log_handleEXCEPTIONSOTHERS = 1.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.INSERT g_log_handle INTO TABLE g_t_log_handle.ENDFORM. " open_log
We will have procedure that will add the messages in the log, before calling the procedure a MESSAGE statement will set the system message variables.
FORM msg_add USING value(i_log_handle) TYPE balloghndl.DATA:l_s_msg TYPE bal_s_msg.* define data of message for Application Logl_s_msg-msgty = sy-msgty.l_s_msg-msgid = sy-msgid.l_s_msg-msgno = sy-msgno.l_s_msg-msgv1 = sy-msgv1.l_s_msg-msgv2 = sy-msgv2.l_s_msg-msgv3 = sy-msgv3.l_s_msg-msgv4 = sy-msgv4.* add this message to log fileCALL FUNCTION 'BAL_LOG_MSG_ADD'EXPORTINGi_log_handle = i_log_handlei_s_msg = l_s_msgEXCEPTIONSOTHERS = 1.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.ENDFORM. " msg_add
Read the file from PC.
FORM read_pc CHANGING l_subrc.v_filename = p_file.CALL METHOD cl_gui_frontend_services=>gui_uploadEXPORTINGfilename = v_filenameCHANGINGdata_tab = it_recsEXCEPTIONSfile_open_error = 1file_read_error = 2no_batch = 3gui_refuse_filetransfer = 4invalid_type = 5no_authority = 6unknown_error = 7bad_data_format = 8header_not_allowed = 9separator_not_allowed = 10header_too_long = 11unknown_dp_error = 12access_denied = 13dp_out_of_memory = 14disk_full = 15dp_timeout = 16not_supported_by_gui = 17error_no_gui = 18OTHERS = 19.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO g_dummy.PERFORM msg_add USING g_log_handle.l_subrc = sy-subrc.ELSE.MESSAGE s100 INTO g_dummy. " File opened successfullyPERFORM msg_add USING g_log_handle.PERFORM delimited_file.ENDIF.ENDFORM. "read_pc
After reading you might have your own checks on the file contents. e.g. material type is incorrect or if the mandatory values are not coming, etc. Once the checks are done it is time to build the IDoc. For each material in our case we will send one IDoc. The IDoc consists of a control part and data part. The control part tells SAP what type of IDoc is (definition) and what to do with the IDoc. The data part stores the data in different segments. Let’s see first how the control is made. The IDoc types will obviously be different for different scenarios.
* Control is of type EDIDCedidc-mandt = sy-mandt. " Clientedidc-doctyp = 'MATMAS01'. " IDoc typeedidc-idoctp = 'MATMAS01'. " Basic Typeedidc-cimtyp = 'ZMATMAS01'. " Extensionedidc-direct = '2'. " Inboundedidc-mestyp = 'MATMAS'. " Message Typeedidc-sndpor = 'DUMMY'. " Sender Portedidc-sndprn = 'DUMMY'. " Sender partneredidc-sndprt = 'LS'. " Partner type
Now that control record is done let’s see how the data part is done. The data is stored in the EDIDD structure. First move the relevant data in the structure for the relevant segment and then the segment is moved to the EDIDD structure. So this is done in two steps. We will see this in example of filling segment E1MARAM. The code will be something like this.
PERFORM fill_e1maram CHANGING s_e1maram.PERFORM add_idoc_segment USING 'E1MARAM's_e1maram.
FORM fill_e1maram CHANGING ch_e1maram.ch_e1maram-xxxxx = yyyyyyy....ENDFORM.FORM add_idoc_segment USING i_segnam i_sdata.*CLEAR s_edidd.CHECK NOT i_sdata IS INITIAL.s_edidd-mandt = sy-mandt.s_edidd-segnam = i_segnam.s_edidd-docnum = edidd-docnum.s_edidd-sdata = i_sdata.APPEND s_edidd TO t_edidd.ENDFORM. "ADD_IDOC_SEGMENT
Once one material information is entered we should call the function module to create the IDoc. Along with posting we will also store the IDoc number and its status in out output structure S_OUTPUT.
FORM create_idoc.CALL FUNCTION 'IDOC_WRITE_AND_START_INBOUND'EXPORTINGi_edidc = edidcIMPORTINGdocnum = v_idoc_numTABLESi_edidd = t_ediddEXCEPTIONSidoc_not_saved = 1OTHERS = 2.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.PERFORM msg_add USING g_log_handle.ELSE.COMMIT WORK AND WAIT.s_output-docnum = v_idoc_num.* Check to see if IDOC posted successfullySELECT SINGLE teds2~status descrpINTO (s_output-status, s_output-descrp)FROM edidcJOIN teds2 ON teds2~status = edidc~statusWHERE docnum = v_idoc_numAND langua = sy-langu.* Put lights in the rowSELECT SINGLE stalight INTO s_output-traffic_lightFROM stacustJOIN stalight ON stalight~statva = stacust~statvaWHERE status = s_output-status.CASE s_output-traffic_light.WHEN '1'.* move icon_yellow_light to hugo.s_output-traffic_light = 2.WHEN '2'.* move icon_green_light to hugo.s_output-traffic_light = 3.WHEN '3'.* move icon_red_light to hugo.s_output-traffic_light = 1.ENDCASE.ENDIF.ENDFORM. "CREATE_IDOC
IDoc posting is done now lets show the user what happened. Over the course of opening the file and creating the IDoc we logging whatever happened so we want to show those messages as well as the IDoc posted. For this a tabbed screen appropriate so that user can have the details easy accessible. SAP has a very good demo of how to show logs in a tabbed subscreen in the program SBAL_DEMO_04_SUBSCREEN. That has been the basis of this program as well. So just looks at how the IDoc is displayed with a link to its application log. Our output structure is something like this:
The column CELL_TYPE can be used to define how a particular cell should behave in the ALV output. For IDoc number (DOCNUM) we want to be of type hotspot so the following will set it of that type.
* Make the IDoc of type linkl_s_salv_t_int4_column-columnname = 'DOCNUM'.l_s_salv_t_int4_column-value = if_salv_c_cell_type=>hotspot.APPEND l_s_salv_t_int4_column TO l_t_salv_t_int4_column.s_output-cell_type = l_t_salv_t_int4_column.MODIFY t_output FROM s_output TRANSPORTING cell_typeWHERE cell_type IS INITIAL.
Make the container and create the ALV table object.
* Create holder containerCREATE OBJECT l_r_cust_contEXPORTING =container_name = 'G_CUST_CONTROL'EXCEPTIONScntl_error = 1cntl_system_error = 2create_error = 3lifetime_error = 4lifetime_dynpro_dynpro_link = 5OTHERS = 6.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.*--------------------------------------------------------------------** Create AVL tableTRY.cl_salv_table=>factory(EXPORTINGr_container = l_r_cust_contIMPORTINGr_salv_table = l_r_tableCHANGINGt_table = t_output ).CATCH cx_salv_msg. "#EC NO_HANDLERENDTRY.
Set the column CELL_TYPE as a cell definition column and we also plan to show the status with some traffic lights.
* ColumnsDATA:lr_columns TYPE REF TO cl_salv_columns_table,lr_column TYPE REF TO cl_salv_column.lr_columns = l_r_table->get_columns( ).lr_columns->set_optimize( abap_true ).TRY.CALL METHOD lr_columns->set_exception_columnEXPORTINGvalue = 'TRAFFIC_LIGHT'group = '2'condensed = if_salv_c_bool_sap=>false.CATCH cx_salv_data_error .ENDTRY.TRY.CALL METHOD lr_columns->set_cell_type_columnEXPORTINGvalue = 'CELL_TYPE'.CATCH cx_salv_data_error .ENDTRY.
Define a event handler for the hotpot on IDoc number.
*--------------------------------------------------------------------** EventsDATA:l_r_event_handler TYPE REF TO l_cl_event_handler,l_r_events TYPE REF TO cl_salv_events_table.l_r_events = l_r_table->get_event( ).CREATE OBJECT l_r_event_handler.SET HANDLER l_r_event_handler->on_link_click FOR l_r_events.
The handler for on_link_click event will be a local class.
CLASS l_cl_event_handler DEFINITION.PUBLIC SECTION.METHODS:on_link_click FOR EVENT link_click OF cl_salv_events_tableIMPORTING row column.PRIVATE SECTION.METHODS:handle_idoc_click IMPORTING i_row TYPE salv_de_row.ENDCLASS. "l_cl_event_handler DEFINITION
In the method handle_idoc_click we will read the IDoc messages that are written in SAP’s application log. The demo SBAL_DEMO_05 has some good examples to save logs in the database and read from it. We will use the POPUP profile of log to show the message for given IDoc.
CLASS l_cl_event_handler IMPLEMENTATION.METHOD on_link_click.CASE column.WHEN 'DOCNUM'.handle_idoc_click( EXPORTING i_row = row ).WHEN OTHERS.ENDCASE.ENDMETHOD. "on_clickMETHOD handle_idoc_click.DATA:l_s_object TYPE bal_s_obj,l_s_extnumber TYPE bal_s_extn,l_s_log_filter TYPE bal_s_lfil,l_t_log_header TYPE balhdr_t,l_s_display_profile TYPE bal_s_prof,l_s_log TYPE bal_s_log,l_log_handle TYPE balloghndl,l_t_log_handle TYPE bal_t_logh,l_s_handle_filter TYPE bal_s_logh,l_t_handle_filter TYPE TABLE OF bal_s_logh.* Don't show programs own logl_s_handle_filter-sign = 'E'.l_s_handle_filter-option = 'EQ'.l_s_handle_filter-low = g_log_handle.APPEND l_s_handle_filter TO l_t_handle_filter.l_s_log_filter-log_handle = l_t_handle_filter.READ TABLE t_output INTO s_output INDEX i_row.* create a filter with all relevant criteria:l_s_object-sign = 'I'.l_s_object-option = 'EQ'.l_s_object-low = 'MATU'.APPEND l_s_object TO l_s_log_filter-object.l_s_extnumber-sign = 'I'.l_s_extnumber-option = 'EQ'.l_s_extnumber-low = s_output-docnum.APPEND l_s_extnumber TO l_s_log_filter-extnumber.* search on DB for these logsCALL FUNCTION 'BAL_DB_SEARCH'EXPORTINGi_s_log_filter = l_s_log_filterIMPORTINGe_t_log_header = l_t_log_headerEXCEPTIONSOTHERS = 0.* load logs from DBCALL FUNCTION 'BAL_DB_LOAD'EXPORTINGi_t_log_header = l_t_log_headerEXCEPTIONSOTHERS = 0.* get a prepared profileCALL FUNCTION 'BAL_DSP_PROFILE_POPUP_GET'IMPORTINGe_s_display_profile = l_s_display_profileEXCEPTIONSOTHERS = 1.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.l_s_display_profile-disvariant-handle = 'LOG'.CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'EXPORTINGi_s_display_profile = l_s_display_profilei_s_log_filter = l_s_log_filterEXCEPTIONSprofile_inconsistent = 1internal_error = 2no_data_available = 3no_authority = 4OTHERS = 5.IF sy-subrc <> 0.MESSAGE ID sy-msgid TYPE 'I' NUMBER sy-msgnoWITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.ENDIF.ENDMETHOD. "handle_link_clickENDCLASS. "l_cl_event_handler IMPLEMENTATION
The output will look something like this: