Create an IDoc programmatically – Easy solution
I was new to IDocs. A recent assignment forced me to learn it. I realized that certain portions of Idoc creation could be easily programmed. So, explored a bit and wrote the code to auto-generate them. It worked like a charm. The code (or report: zzz_create_idoc_wizard) is pasted below. Enjoy 🙂
The below report has 5 mandatory parameters. Refer the comments against each of the parameters. Key in valid inputs and execute the report. (Based on your logged on SAP GUI security settings, you may get a security popup to take your confirmation to create/update a file in your local system. Just confirm by clicking ‘Allow’ or ‘OK’ button). The output of this report is a text file that gets saved in the path mentioned under parameter m_path. Copy the entire content of this text file. This is it. You can directly paste this ‘ready-to-use code’ either into a new report or a function module or a subroutine or a class-method. (Isn’t it cool? 🙂 )
In the auto generated text file, refer the comments mentioned. (By default, I have set the value to ‘X’. You can either use this defaulted value for testing purposes. For productive use, replace the defaulted values with your own custom SELECT SQLs or custom logic to populate the segments’ internal tables of your IDoc). Save and activate this new code. You are ready. 🙂 The possible limits (max and min limit for each segment is also mentioned as comments in the code). This will be handy while preparing the internal tables for each segment of the IDoc.
Both ‘basic’ and extended’ IDoc types are supported. This saves tons of coding time of developers who intend to write, test and rewrite iDocs.
The developer only needs to add the relevant functional/business logic under the specific commented sections of the code in reference to the productive usage of the IDoc (which of course cannot be automated. Are you crazy? 😛 )
REPORT zzz_create_idoc_wizard.
PARAMETERS: m_obj TYPE edi_idcobj OBLIGATORY. "Existing IDoc Object Name
PARAMETERS: m_mestyp TYPE edidc-mestyp OBLIGATORY. "Message Type
PARAMETERS: m_rcvprt TYPE edidc-rcvprt OBLIGATORY. "Partner Type of Receiver
PARAMETERS: m_rcvprn TYPE edidc-rcvprn OBLIGATORY. "Partner Number of Receiver
PARAMETERS: m_path TYPE rlgrap-filename OBLIGATORY DEFAULT 'C:\temp\idoc.txt'. "Local folder path to save the result or output file
AT SELECTION-SCREEN ON VALUE-REQUEST FOR m_path.
DATA: lv_path TYPE string.
CALL METHOD cl_gui_frontend_services=>directory_browse
EXPORTING
window_title = 'Select Directory'
CHANGING
selected_folder = lv_path
EXCEPTIONS
cntl_error = 1.
CALL METHOD cl_gui_cfw=>flush
EXCEPTIONS
cntl_system_error = 1
cntl_error = 2.
m_path = lv_path && '\idoc.txt'.
START-OF-SELECTION.
* validate input
DATA l_attributes TYPE edi_iapi01.
CALL FUNCTION 'IDOCTYPE_EXISTENCE_CHECK'
EXPORTING
pi_idoctyp = m_obj
IMPORTING
pe_attributes = l_attributes
EXCEPTIONS
OTHERS = 1.
IF l_attributes IS INITIAL.
MESSAGE 'Invalid object' TYPE 'S' DISPLAY LIKE 'E'. EXIT.
ENDIF.
* process
DATA: lt_code TYPE TABLE OF string.
DATA: ls_code LIKE LINE OF lt_code.
ls_code = `**** Wizard generated code to create IDoc ` && m_obj && ` ****`.
APPEND ls_code TO lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND 'DATA: control_record LIKE edidc.' TO lt_code.
APPEND 'DATA: i_communication LIKE edidc OCCURS 0 WITH HEADER LINE,' TO lt_code.
APPEND ' lt_data LIKE edidd OCCURS 0 WITH HEADER LINE,' TO lt_code.
APPEND ' ls_data LIKE LINE OF lt_data.' TO lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND '**** Set the control record details' TO lt_code.
ls_code = 'control_record-idoctp = ''' && m_obj && '''.'. APPEND ls_code TO lt_code.
ls_code = 'control_record-mestyp = ''' && m_mestyp && '''.'. APPEND ls_code TO lt_code.
ls_code = 'control_record-rcvprt = ''' && m_rcvprt && '''.'. APPEND ls_code TO lt_code.
ls_code = 'control_record-rcvprn = ''' && m_rcvprn && '''.'. APPEND ls_code TO lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND '**** Logic to populate internal table LT_DATA[] ****' TO lt_code.
PERFORM custom_logic USING m_obj CHANGING lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND '**** End of logic to populate internal table LT_DATA[] ****' TO lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND 'CHECK LT_DATA[] IS NOT INITIAL.' TO lt_code.
APPEND INITIAL LINE TO lt_code.
APPEND '**** IDoc creation' TO lt_code.
APPEND ' CALL FUNCTION ''MASTER_IDOC_DISTRIBUTE''' TO lt_code.
APPEND ' EXPORTING' TO lt_code.
APPEND ' master_idoc_control = control_record' TO lt_code.
APPEND ' TABLES' TO lt_code.
APPEND ' communication_idoc_control = i_communication' TO lt_code.
APPEND ' master_idoc_data = LT_DATA' TO lt_code.
APPEND ' EXCEPTIONS' TO lt_code.
APPEND ' error_in_idoc_control = 1' TO lt_code.
APPEND ' error_writing_idoc_status = 2' TO lt_code.
APPEND ' error_in_idoc_data = 3' TO lt_code.
APPEND ' sending_logical_system_unknown = 4' TO lt_code.
APPEND ' OTHERS = 5.' TO lt_code.
APPEND ' IF sy-subrc <> 0.' TO lt_code.
APPEND ' MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno' TO lt_code.
APPEND ' WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.' TO lt_code.
APPEND ' ELSE.' TO lt_code.
APPEND ' LOOP AT i_communication.' TO lt_code.
APPEND ' WRITE: ''IDOC GENERATED'', i_communication-docnum. "check in tcode: WE05' TO lt_code.
APPEND ' ENDLOOP.' TO lt_code.
APPEND ' COMMIT WORK.' TO lt_code.
APPEND ' ENDIF.' TO lt_code.
DATA lv_path TYPE string.
lv_path = m_path.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = lv_path
filetype = 'DAT'
CHANGING
data_tab = lt_code[].
CALL METHOD cl_gui_frontend_services=>execute
EXPORTING
document = lv_path " m_path+Name to Document
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
bad_parameter = 3
file_not_found = 4
path_not_found = 5
file_extension_unknown = 6
error_execute_failed = 7
synchronous_failed = 8
not_supported_by_gui = 9
OTHERS = 10.
IF sy-subrc <> 0.
" do nothing
ENDIF.
*&---------------------------------------------------------------------*
*& Form GENERATE_LINES
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_OBJ text
* <--P_LT_CODE text
*----------------------------------------------------------------------*
FORM custom_logic USING p_obj LIKE m_obj
CHANGING p_lt_code LIKE lt_code.
DATA l_idoctyp TYPE edi_idoctp.
DATA g_idoctyp_attr TYPE edi_iapi01.
DATA :
gt_idocsyn LIKE edi_iapi02 OCCURS 20 WITH HEADER LINE,
gt_prev_idocsyn LIKE edi_iapi02 OCCURS 20 WITH HEADER LINE,
gs_prev_idocsyn LIKE LINE OF gt_prev_idocsyn.
DATA: gt_tnode LIKE snodetext OCCURS 20 WITH HEADER LINE,
gt_attr LIKE sed5attr OCCURS 20 WITH HEADER LINE,
gs_attr LIKE LINE OF gt_attr.
* read basis type
l_idoctyp = p_obj.
CALL FUNCTION 'IDOCTYPE_READ'
EXPORTING
pi_idoctyp = l_idoctyp
IMPORTING
pe_attributes = g_idoctyp_attr
TABLES
pt_syntax = gt_idocsyn
pt_pre_syntax = gt_prev_idocsyn.
DATA lv_variable TYPE string VALUE 'DATA : LT_& TYPE TABLE OF &, LS_& LIKE LINE OF LT_&.'.
DATA lv_variable_temp TYPE string.
LOOP AT gt_idocsyn INTO gs_prev_idocsyn.
lv_variable_temp = lv_variable.
REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_prev_idocsyn-segtyp.
APPEND lv_variable_temp TO p_lt_code.
ENDLOOP.
CALL FUNCTION 'CONVERT_IDOC_SYNTAX_TO_TREE'
EXPORTING
pi_idoctyp = l_idoctyp
pi_descrp = ''" g_idoctyp_attr-descrp
pi_e2display = ''
pi_e2segrel = ''
TABLES
lt_idocsyn = gt_idocsyn
lt_prev_idocsyn = gt_prev_idocsyn
lt_tree = gt_tnode
lt_attr = gt_attr.
LOOP AT gt_attr INTO gs_attr.
APPEND INITIAL LINE TO lt_code.
lv_variable_temp = `**** Process segment: ` && gs_attr-segtyp.
APPEND lv_variable_temp TO lt_code.
lv_variable_temp = 'REFRESH LT_&. CLEAR LT_&[]. CLEAR LS_&.'.
REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.
APPEND lv_variable_temp TO lt_code.
DATA lt_ddic_info TYPE ddfields.
DATA ls_ddic_info LIKE LINE OF lt_ddic_info.
*get ddic fields
CALL FUNCTION 'CATSXT_GET_DDIC_FIELDINFO'
EXPORTING
im_structure_name = gs_attr-segtyp
IMPORTING
ex_ddic_info = lt_ddic_info
EXCEPTIONS
failed = 1
OTHERS = 2.
IF sy-subrc <> 0.
" do nothing
ENDIF.
APPEND INITIAL LINE TO lt_code.
SHIFT gs_attr-occmax LEFT DELETING LEADING '0'.
lv_variable_temp = `**** Write your custom logic here. Note that the maximum limit for segment ` && gs_attr-segtyp && ` = ` && gs_attr-occmax.
APPEND lv_variable_temp TO lt_code.
IF gs_attr-occmax > 1.
lv_variable_temp = '**** You may cutom code your logic (or copy by referring below statements) for a maximum limit of #' && gs_attr-occmax && ' times'.
APPEND lv_variable_temp TO lt_code.
ENDIF.
LOOP AT lt_ddic_info INTO ls_ddic_info.
CASE ls_ddic_info-datatype.
WHEN 'CHAR'. lv_variable_temp = 'X'.
WHEN ''. "enhance for other types: I, P, date, time, etc
WHEN OTHERS. lv_variable_temp = 'X'. "default 'X' should work for most random cases
ENDCASE.
lv_variable_temp = 'LS_' && gs_attr-segtyp && '-' && ls_ddic_info-fieldname && ' = ''' && lv_variable_temp && '''.'.
APPEND lv_variable_temp TO lt_code.
ENDLOOP.
IF lt_ddic_info IS NOT INITIAL.
lv_variable_temp = 'APPEND LS_& TO LT_&.'.
REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.
APPEND lv_variable_temp TO lt_code.
APPEND INITIAL LINE TO lt_code.
ENDIF.
lv_variable_temp = 'LOOP AT LT_& INTO LS_&.'.
REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.
APPEND lv_variable_temp TO lt_code.
lv_variable_temp = ` LS_DATA-segnam = '&'. LS_DATA-sdata = LS_&. APPEND LS_DATA TO LT_DATA.`.
REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.
APPEND lv_variable_temp TO lt_code.
APPEND 'ENDLOOP.' TO lt_code.
ENDLOOP.
ENDFORM. " GENERATE_LINES