Skip to Content
Author's profile photo Jan Rauscher

CREMAS IDOC structure function module

Challenge

Quite often it’s requested to enhance given IDOC structures, e.g. the vendor master data IDOC of message type CREMAS. The SAP standard offers a row of customer exits within the standard master data IDOC creation function module MASTERIDOC_CREATE_CREMAS.

The exits are called segment per segment and because the vendor structure changes from vendor to vendor (different number of purchase organizations, address, company codes, etc.), it is not predictable how often the exit resp. BAdI is called. This fact makes it difficult when additional segments shall be added to the IDOC, e.g. with the NO_DATA sign (“/”) for deletion tasks in the target system (e.g. see note 1580326).

A second challenge is the fact that all segments in the IDOCs must adhere to a prescribed sequence incl. dependencies among segments, e.g. contact persons (segment E1WYT3M) must be assigned to a purchase organization (segment E1FLM1M).

 

 

When segments are added by custom code, it could easily happen that this destroys the mandated sequence. The result will be that the IDOC is not sent out because the outbound cannot transmit IDOCs with incorrect structures.

A further very valuable feature is making it possible that deleted supplier assigned data like contact persons, bank data and withholding tax data are deleted in the target system, too. This is only possible when IDOC segments are added that contain the NO_DATA sign “/”. The pure standard does not send over the “deletion information” to the target system, so the effect would be that e.g. the bank data remains assigned to the supplier in the target while it was removed completely from supplier in the source system.

 

Solution approach

The best way to range up the IDOC structure after segments have been added or changed would be an exit after the complete IDOC contents is ready and finished (but not yet in the correct sequence). For the sake of performance, it would be good to call this exit only once and not – like directly in the MASTERIDOC_CREATE_CREMAS – segment per segment.

In combination of this range up feature, it is easy to implement the second requirement: the handling of bank data, contact person and withholding tax deletions.

The most direct way to reach this goal is an implicit enhancement on top of function module MASTER_IDOC_DISTRIBUTE. An implicit enhancement has some disadvantages, especially when standard source code is changed – however the probability for changes is quite low.

 

 

The advantage of this location (beginning of FM MASTER_IDOC_DISTRIBUTION) is that the standard code has now finished building up the IDOC structure and content-wise all segments are now completely in the table MASTER_IDOC_DATA.

Independently how the IDOC segments are now sequenced in this table MASTER_IDOC_DATA, this implementation brings them into the correct order and additionally it adds deletion segments for contact person, bank and withholding tax data.

The code for ranging up the IDOC is encapsulated in an FM. Here in this environment it is called “Y1M_MDGS_IDOC_ADAPT”. This FM analyzes the incoming IDOC data (segments in a table format) in the following sequence:

  1. It checks whether there are company code segments
  2. If yes, it checks whether this cc segment contains tax data (LFBW), if no, a deletion segment for tax data is added to the IDOC structure
  3. If cc data is existing, it further checks whether this cc segment contains dunning data (LFB5), if no, a deletion segment for dunning data is added to the IDOC structure
  4. The FM makes sure that only on E1LFA1M segment is in the IDOC and it’s always the first segment
  5. It analyzes the incoming segments whether they are of 2nd level (E1LFA1B, E1LFA1A, E1LFA1H, E1LFB1M, E1LFM1M, E1LFBKM, E1LFASM, E1KNVKM and E1WYt1M). If yes, they will marked in a special way, they key field is extracted and the segments are located below the highest level E1LFA1M. The segments E1LFB1M, E1LFM1M and E1WYT1M play a special role because they may have dependent segments (children) that are not text segments.
  6. Now the FM checks the incoming data whether it contains segments for third level (E1LFBWM, E1LFB5M, E1LFM2M, E1LFB1H, E1LFM1H or E1WYTTM. These segments are analyzed to which upper segment they belong to, e.g. E1LFBWM, E1LFB5M and E1LFB1H belong always to a company code. Having found out the company code, the segments are located below the correct upper level segment, here company code segment E1LFB1M. Same is done for purchase org (E1LFM1M) and vendor sub range level (E1WYT1M).
  7. Having brought the dependent segments below they parent segments, the order of the IDOC is to be determined. A global counter is applied so that later a SORT command is sufficient to bring the segments into the correct order. According to the picture above, it’s clear that E1LFA1M is always the first segment. If there is E1LFA1B segment available, it will get order number 2, etc. If there is text segment (E1LFA1H) for the highest level, it may have at least one long text lines (E1LFA1L), those must be taken into account. Each segment will increase the global counter. Finally add segments for the vendor sub ranges (E1WYT1M) and dependent segments (E1WYTTM), if there are.
  8. Continue with the company code segment and their dependent segments E1LFBWM, E1LFB5M, E1LFB1H (and below E1LFB1L). Same is done on PO level. Before applying the same concept for contact person level, bank data (E1LFBKM), tax number (E1LFASM) and contact person data (E1KNVKM) segments are joined.

 

An example code is added. Please be aware that this code must be adapted to your individual use case, i.e. FM name changes, etc.

 

FUNCTION y1m_mdgs_idoc_adapt.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  TABLES
*"      T_IDOC_DATA STRUCTURE  EDIDD
*"----------------------------------------------------------------------

* this FM is for:
*
* 1) Deletion segments addition
* adding deletion segments for contact person, withholding tax, bank data,
* and texts for all levels (A, B, M)
*
* 2) bring all the IDOC segments in the required order which is
*  E1LFA1M
*    E1LFA1B
*    E1LFA1A
*    E1LFA1H
*      E1LFA1L
*    E1LFB1M
*      E1LFBWM
*      E1LFB5M
*      E1LFB1H
*        E1LFB1L
*    E1LFM1M
*      E1LFM2M
*      E1WYT3M
*      E1LFM1H
*        E1LFM1L
*    E1LFBKM
*    E1LFASM
*    E1KNVKM
*    E1WYT1M
*      E1WYTTM





  TYPES: BEGIN OF edidd_ext,  " IDOC data extended
           id          TYPE i,
           value       TYPE c LENGTH 50, " identification value, e.g. value of BUKRS
           type        TYPE c LENGTH 2,  " type of related object, e.g. PO or CC
           rel_to      TYPE i,
           order       TYPE i,
           s_idoc_data TYPE edidd,
         END OF edidd_ext.

  TYPES: BEGIN OF lfbw_type,
           bukrs TYPE bukrs,
           witht TYPE witht,
         END OF lfbw_type.

  TYPES: BEGIN OF lfb5_type,
           bukrs TYPE bukrs,
           maber TYPE maber,
         END OF lfb5_type.

  TYPES: BEGIN OF lfb1_type,
           bukrs TYPE bukrs,
         END OF lfb1_type.




  CONSTANTS: lc_e1lfa1m TYPE edilsegtyp VALUE 'E1LFA1M',
             lc_e1lfa1b TYPE edilsegtyp VALUE 'E1LFA1B',
             lc_e1lfa1a TYPE edilsegtyp VALUE 'E1LFA1A',
             lc_e1lfa1h TYPE edilsegtyp VALUE 'E1LFA1H',
             lc_e1lfa1l TYPE edilsegtyp VALUE 'E1LFA1L',
             lc_e1lfb1m TYPE edilsegtyp VALUE 'E1LFB1M',
             lc_e1lfb1h TYPE edilsegtyp VALUE 'E1LFB1H',
             lc_e1lfb1l TYPE edilsegtyp VALUE 'E1LFB1L',
             lc_e1lfbwm TYPE edilsegtyp VALUE 'E1LFBWM',
             lc_e1lfb5m TYPE edilsegtyp VALUE 'E1LFB5M',
             lc_e1lfm1m TYPE edilsegtyp VALUE 'E1LFM1M',
             lc_e1lfm1h TYPE edilsegtyp VALUE 'E1LFM1H',
             lc_e1lfm1l TYPE edilsegtyp VALUE 'E1LFM1L',
             lc_e1lfm2m TYPE edilsegtyp VALUE 'E1LFM2M',
             lc_e1lfbkm TYPE edilsegtyp VALUE 'E1LFBKM',
             lc_e1lfasm TYPE edilsegtyp VALUE 'E1LFASM',
             lc_e1knvkm TYPE edilsegtyp VALUE 'E1KNVKM',
             lc_e1wyt1m TYPE edilsegtyp VALUE 'E1WYT1M',
             lc_e1wyttm TYPE edilsegtyp VALUE 'E1WYTTM',
             lc_e1wyt3m TYPE edilsegtyp VALUE 'E1WYT3M',
             lc_cc      TYPE c length 2 value 'CC',
             lc_po      type c length 2 value 'PO',
             lc_wy      type c length 2 value 'WY' .



  DATA: lt_idoc_data_ext           TYPE TABLE OF edidd_ext,
        ls_idoc_data_ext           TYPE edidd_ext,
        lt_idoc_data_ext2          TYPE TABLE OF edidd_ext,
        ls_idoc_data_ext2          TYPE edidd_ext,
        lt_idoc_data               TYPE TABLE OF edidd,
        lt_idoc_data1              TYPE TABLE OF edidd,
        lv_cc1                     TYPE bukrs,
        lv_po1                     TYPE ekorg,
        lv_wy1                     TYPE ltsnr,
        lv_counter                 TYPE i,
        lv_id_e1lfa1m              TYPE i,
        ls_idoc_data               TYPE edidd,
        lv_sdata                   TYPE edi_sdata,
        lv_id_e1lfa1h              TYPE i,
        lv_tabix                   TYPE i,
        lv_order_counter           TYPE i,
        lv_loop                    TYPE i,
        lt_lfb1                    TYPE TABLE OF lfb1_type,
        ls_lfb1                    TYPE bukrs,
        lt_t001                    TYPE TABLE OF lfb1_type,
        ls_t001                    TYPE bukrs,
        lt_lfbw                    TYPE TABLE OF lfbw_type,
        ls_lfbw                    TYPE lfbw_type,
        lt_lfb5                    TYPE TABLE OF lfb5_type,
        ls_lfb5                    TYPE lfb5_type,
        lv_lifnr                   TYPE lifnr,
        lv_lfb1_num                TYPE i,
        lv_lfbw_num                TYPE i,
        lv_lfb5_num                TYPE i,
        lv_lfbk_num                TYPE i,
        lv_knvk_num                TYPE i,
        lo_y1m_mdgs_cl_idoc_cremas TYPE REF TO y1m_mdgs_cl_idoc_cremas_del_el,
        lv_objectid                TYPE cdhdr-objectid,
        lt_cdhdr                   TYPE TABLE OF cdhdr,
        ls_cdhdr                   TYPE cdhdr,
        lv_new                     TYPE char1 .  " flag whether supplier was newly created or just changed




*data: lv_i type i.
*
*while lv_i < 5.
*  lv_i = lv_i + 1.
*  lv_i = lv_i - 1.
*endwhile.


  READ TABLE t_idoc_data INTO ls_idoc_data
    WITH KEY segnam = lc_e1lfa1m .
  IF sy-subrc <> 0.
    RETURN.
  ENDIF.


  lv_sdata = ls_idoc_data-sdata.
  SHIFT lv_sdata BY 3 PLACES LEFT .
  lv_lifnr = lv_sdata(10) . " get vendor number value



* get the information whether this vendor was newly created or just changed
* (if it was newly created, do not enhance the IDOC with deletion segments)

  lv_objectid = lv_lifnr.
  lv_new = abap_true.

  CALL FUNCTION 'CHANGEDOCUMENT_READ_HEADERS'
    EXPORTING
      objectclass                = 'KRED'
      objectid                   = lv_objectid
    TABLES
      i_cdhdr                    = lt_cdhdr
    EXCEPTIONS
      no_position_found          = 1
      wrong_access_to_archive    = 2
      time_zone_conversion_error = 3
      OTHERS                     = 4.



  DATA: lt_cdhdr_l TYPE STANDARD TABLE OF cdhdr,
        lt_cdpos_l TYPE STANDARD TABLE OF cdpos,
        lw_cdhdr_l TYPE cdhdr,
        lw_cdpos_l TYPE cdpos.
  DATA: lv_new_lfb5 TYPE C VALUE 'X'.
  DATA: lv_string TYPE char100.
  lv_new = abap_true.
  SELECT * INTO TABLE lt_cdhdr_l
    FROM cdhdr
    WHERE objectclas = 'KRED'
    AND   objectid = lv_objectid.
  IF sy-subrc EQ 0.
    SORT lt_cdhdr_l BY changenr DESCENDING.
    delete ADJACENT DUPLICATES FROM lt_cdhdr_l COMPARING objectid.
    SELECT * INTO TABLE lt_cdpos_l
      FROM cdpos
      FOR ALL ENTRIES IN lt_cdhdr_l
      WHERE changenr = lt_cdhdr_l-changenr
      AND  tabname = 'LFBW'
      AND  chngind IN ('E','D').
    IF sy-subrc EQ 0.
      LOOP AT lt_cdpos_l INTO lw_cdpos_l.
        CONCATENATE lv_string lw_cdpos_l-fname INTO lv_string.
      ENDLOOP.
      IF lv_string CS 'WT_EXDFWT_EXDTWT_EXNRWT_EXRTWT_SUBJCTWT_WITHCDWT_WTEXRSWT_WTSTCD'.
        lv_new = 'D'.
      ENDIF.
    ENDIF.
  ENDIF.

  CLEAR: lt_cdhdr_l,lw_cdhdr_l,lw_cdpos_l,lt_cdpos_l,lv_string.
    SELECT * INTO TABLE lt_cdhdr_l
    FROM cdhdr
    WHERE objectclas = 'KRED'
    AND   objectid = lv_objectid.
  IF sy-subrc EQ 0.
    SORT lt_cdhdr_l BY changenr DESCENDING.
    delete ADJACENT DUPLICATES FROM lt_cdhdr_l COMPARING objectid.
    SELECT * INTO TABLE lt_cdpos_l
      FROM cdpos
      FOR ALL ENTRIES IN lt_cdhdr_l
      WHERE changenr = lt_cdhdr_l-changenr
      AND  tabname = 'LFB5'
      AND  chngind IN ('E','D').
    IF sy-subrc EQ 0.
      LOOP AT lt_cdpos_l INTO lw_cdpos_l.
        CONCATENATE lv_string lw_cdpos_l-fname INTO lv_string.
      ENDLOOP.
      IF lv_string CS 'BUSABGMVDTLFRMAMADATMAHNAMAHNSMANSP'.
        lv_new_lfb5 = 'D'.
      ENDIF.
    ENDIF.
  ENDIF.


*  IF sy-subrc EQ 1.
*    lv_new = abap_true.
*  ENDIF.
*
*  IF sy-subrc EQ 0.
*
*    READ TABLE lt_cdhdr INTO ls_cdhdr WITH KEY change_ind = 'U'.
*    IF sy-subrc EQ 0.
*      lv_new = abap_false.
*    ENDIF.
*
*    READ TABLE lt_cdhdr INTO ls_cdhdr WITH KEY change_ind = 'D'.
*    IF sy-subrc EQ 0.
*      lv_new = abap_false.
*    ENDIF.
*
*    READ TABLE lt_cdhdr INTO ls_cdhdr WITH KEY change_ind = 'E'.
*    IF sy-subrc EQ 0.
*      lv_new = abap_false.
*    ENDIF.
*
*  ENDIF.





  CREATE OBJECT lo_y1m_mdgs_cl_idoc_cremas .

  "***********************************
  "ADDING OF DUMMY SEGMENTS (START)
  "***********************************

* get company code data
  SELECT bukrs FROM lfb1 INTO CORRESPONDING FIELDS OF TABLE lt_lfb1 WHERE lifnr = lv_lifnr.
  SELECT bukrs FROM t001 INTO CORRESPONDING FIELDS OF TABLE lt_t001 WHERE wt_newwt = 'X' .

* only CCs with wt_newwt are relevant, remove the others
  LOOP AT lt_lfb1 INTO ls_lfb1 .
    lv_tabix = sy-tabix.
    READ TABLE lt_t001 INTO ls_t001 WITH KEY bukrs = ls_lfb1 .
    IF sy-subrc NE 0.
      DELETE lt_lfb1 INDEX lv_tabix.
    ENDIF.
  ENDLOOP.
  DESCRIBE TABLE lt_lfb1 LINES lv_lfb1_num .


* get withholding tax data
  SELECT bukrs witht FROM lfbw INTO CORRESPONDING FIELDS OF TABLE lt_lfbw WHERE lifnr = lv_lifnr .
  DESCRIBE TABLE lt_lfbw LINES lv_lfbw_num .

* get dunning data
  SELECT bukrs maber FROM lfb5 INTO CORRESPONDING FIELDS OF TABLE lt_lfb5 WHERE lifnr = lv_lifnr .
  DESCRIBE TABLE lt_lfb5 LINES lv_lfb5_num .

  SELECT COUNT(*) FROM lfbk INTO lv_lfbk_num
      WHERE lifnr = lv_lifnr.
  SELECT COUNT(*) FROM knvk INTO lv_knvk_num
      WHERE lifnr = lv_lifnr.

* ADD DELETION SEGMENTS FOR LFBK AND KNVK
* "BANK DATA (LFBK)
  IF lv_lfbk_num = 0.
    "add deletion segment for LFBK

    lt_idoc_data[] = t_idoc_data[] .
    CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_lfbk_segment_for_deletion
      EXPORTING
        iv_lifnr    = lv_lifnr
      CHANGING
        t_idoc_data = lt_idoc_data.

    t_idoc_data[] = lt_idoc_data[].

  ENDIF.

  "CONTACT PERSON (KNVK)
  IF lv_knvk_num = 0.
    "add deletion segment for KNVK

    lt_idoc_data[] = t_idoc_data[].
    CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_knvk_segment_for_deletion
      EXPORTING
        iv_lifnr    = lv_lifnr
      CHANGING
        t_idoc_data = lt_idoc_data.

    t_idoc_data[] = lt_idoc_data[].

  ENDIF.

*     lt_idoc_data[] = t_idoc_data[].
*     CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_empty_txthdr_a_seg_for_del
*        EXPORTING
*          iv_lifnr    = lv_lifnr
*        CHANGING
*          t_idoc_data = lt_idoc_data .
*
*     CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_empty_txthdr_b_seg_for_del
*        EXPORTING
*          iv_lifnr    = lv_lifnr
*        CHANGING
*          t_idoc_data = lt_idoc_data .
*
*     CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_empty_txthdr_m_seg_for_del
*        EXPORTING
*          iv_lifnr    = lv_lifnr
*        CHANGING
*          t_idoc_data = lt_idoc_data .
*
*       t_idoc_data[] = lt_idoc_data[].



* find out whether and which CC segments are in the idoc
  lt_idoc_data[] = t_idoc_data[].
  LOOP AT lt_idoc_data INTO ls_idoc_data WHERE segnam EQ lc_e1lfb1m .

    lv_sdata = ls_idoc_data-sdata.
    SHIFT lv_sdata BY 13 PLACES LEFT .
    lv_cc1 = lv_sdata(4) . " get cc value

    " add empty segments only for CCs with wt_newwt = 'X' !!
    READ TABLE lt_lfb1 INTO ls_lfb1 WITH KEY bukrs = lv_cc1.
    CHECK sy-subrc EQ 0.


    " check whether this CC contains tax data, if no, add a deletion segment
*    READ TABLE lt_lfbw INTO ls_lfbw WITH KEY bukrs = lv_cc1 .
    IF lv_new EQ 'D'.  " add a deletion segment only when change
      lv_tabix = sy-tabix.

      lt_idoc_data1[] = t_idoc_data[].
      CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_lfbw_segment_for_deletion
        EXPORTING
          iv_lifnr    = lv_lifnr
          iv_bukrs    = lv_cc1
          iv_tabix    = lv_tabix
        CHANGING
          t_idoc_data = lt_idoc_data1.

      t_idoc_data[] = lt_idoc_data1[].

    ENDIF.

    " check whether this CC contains dunning data, if no, add a deletion segment
*    READ TABLE lt_lfb5 INTO ls_lfb5 WITH KEY bukrs = lv_cc1 .
    IF lv_new_lfb5 EQ 'D'.  " add a deletion segment only when change
      lv_tabix = sy-tabix.

      lt_idoc_data1[] = t_idoc_data[].
      CALL METHOD lo_y1m_mdgs_cl_idoc_cremas->add_lfb5_segment_for_deletion
        EXPORTING
          iv_lifnr    = lv_lifnr
          iv_bukrs    = lv_cc1
          iv_tabix    = lv_tabix
        CHANGING
          t_idoc_data = lt_idoc_data1.

      t_idoc_data[] = lt_idoc_data1[].

    ENDIF.

  ENDLOOP.



  LOOP AT t_idoc_data INTO ls_idoc_data .

    lv_counter = lv_counter + 1.
    ls_idoc_data_ext-id = lv_counter.

* E1LFA1M is always on top level
* may occur only one time
    IF ls_idoc_data-segnam EQ lc_e1lfa1m.
*       lv_no_of_e1lfa1m = lv_no_of_e1lfa1m + 1.
*       ls_idoc_data_ext-level = 1.
      ls_idoc_data_ext-order = 1. "E1LFA1M is always first in IDOC structure

      lv_id_e1lfa1m = lv_counter.  " remember this id temporary

* set value for segment E1LFA1M to LIFNR value
      lv_sdata = ls_idoc_data-sdata.
      SHIFT lv_sdata BY 3 PLACES LEFT .
      ls_idoc_data_ext-value = lv_sdata(10) . " get lifnr value

    ENDIF.

* following segments are always on 2nd level
    IF ls_idoc_data-segnam EQ lc_e1lfa1b OR
       ls_idoc_data-segnam EQ lc_e1lfa1a OR
       ls_idoc_data-segnam EQ lc_e1lfa1h OR
       ls_idoc_data-segnam EQ lc_e1lfb1m OR
       ls_idoc_data-segnam EQ lc_e1lfm1m OR
       ls_idoc_data-segnam EQ lc_e1lfbkm OR
       ls_idoc_data-segnam EQ lc_e1lfasm OR
       ls_idoc_data-segnam EQ lc_e1knvkm OR
       ls_idoc_data-segnam EQ lc_e1wyt1m .

      ls_idoc_data_ext-rel_to = lv_id_e1lfa1m . "all level 2 segments relate to top level

* set value for segment E1LFB1M to CC value
      IF ls_idoc_data-segnam EQ lc_e1lfb1m .

        lv_sdata = ls_idoc_data-sdata.
        SHIFT lv_sdata BY 13 PLACES LEFT .
        ls_idoc_data_ext-value = lv_sdata(4) . " get CC value
        ls_idoc_data_ext-type  = lc_cc .

      ENDIF.

* set value for segment E1LFM1M to PO value
      IF ls_idoc_data-segnam EQ lc_e1lfm1m .

        lv_sdata = ls_idoc_data-sdata.
        SHIFT lv_sdata BY 13 PLACES LEFT .
        ls_idoc_data_ext-value = lv_sdata(4) . " get CC value
        ls_idoc_data_ext-type  = lc_po .

      ENDIF.

* set value for segment E1WYT1M to WY value
      IF ls_idoc_data-segnam EQ lc_e1wyt1m .

        lv_sdata = ls_idoc_data-sdata.
        SHIFT lv_sdata BY 13 PLACES LEFT .
        ls_idoc_data_ext-value = lv_sdata(4) . " get CC value
        ls_idoc_data_ext-type  = lc_wy .

      ENDIF.


    ENDIF.

    MOVE-CORRESPONDING ls_idoc_data TO ls_idoc_data_ext-s_idoc_data .
    APPEND ls_idoc_data_ext TO lt_idoc_data_ext .
    CLEAR ls_idoc_data_ext .
  ENDLOOP.




* check for dependency between segments

  lt_idoc_data_ext2[] = lt_idoc_data_ext[] . " copy to temporary table

  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext    " check relevant dependent segments
        WHERE s_idoc_data-segnam EQ lc_e1lfbwm OR
              s_idoc_data-segnam EQ lc_e1lfb5m OR
              s_idoc_data-segnam EQ lc_e1lfm2m OR
              s_idoc_data-segnam EQ lc_e1wyt3m OR
              s_idoc_data-segnam EQ lc_e1lfb1h OR
              s_idoc_data-segnam EQ lc_e1lfm1h OR
              s_idoc_data-segnam EQ lc_e1wyttm .

    lv_tabix = sy-tabix.
* CC segments
* look for matching parent segment E1LFB1M for child segments E1LFBWM and E1LFB5M
* and set the rel_to parameter of child segments to parent ID
    IF ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfbwm OR
       ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfb5m OR
       ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfb1h .

      lv_sdata = ls_idoc_data_ext-s_idoc_data-sdata.
      IF ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfb1h.
        SHIFT lv_sdata BY 23 PLACES LEFT.
      ELSE.
        SHIFT lv_sdata BY 13 PLACES LEFT.
      ENDIF.
      lv_cc1 = lv_sdata(4). " get CC value of E1LFBWM segment

      IF lv_cc1 IS NOT INITIAL.
        READ TABLE lt_idoc_data_ext2 INTO ls_idoc_data_ext2 WITH KEY value = lv_cc1 type = lc_cc .
        IF sy-subrc EQ 0.
          ls_idoc_data_ext-rel_to = ls_idoc_data_ext2-id.
          MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext .
        ENDIF.
      ENDIF.
    ENDIF.

* PO segments
* look for matching parent segment E1LFM1M for child segments E1LFM2M and E1WYT3M
* and set the rel_to parameter of child segments to parent ID
    IF ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfm2m OR
       ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1wyt3m OR
       ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfm1h .

      lv_sdata = ls_idoc_data_ext-s_idoc_data-sdata.
      IF ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1lfm1h.
        SHIFT lv_sdata BY 23 PLACES LEFT.
      ELSE.
        SHIFT lv_sdata BY 13 PLACES LEFT.
      ENDIF.
      lv_po1 = lv_sdata(4). " get PO value of E1LFM1M segment

      IF lv_po1 IS NOT INITIAL.
        READ TABLE lt_idoc_data_ext2 INTO ls_idoc_data_ext2 WITH KEY value = lv_po1 type = lc_po .
        IF sy-subrc EQ 0.
          ls_idoc_data_ext-rel_to = ls_idoc_data_ext2-id.
          MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext .
        ENDIF.

      ENDIF.
    ENDIF.


* WYT1M segments
* look for matching parent segment E1WYT1M for child segments E1WYTTM
* and set the rel_to parameter of child segments to parent ID
    IF ls_idoc_data_ext-s_idoc_data-segnam EQ lc_e1wyttm .
      lv_sdata = ls_idoc_data_ext-s_idoc_data-sdata.
      SHIFT lv_sdata BY 13 PLACES LEFT.
      lv_wy1 = lv_sdata(6). " get WY value of E1WYT1M segment

      IF lv_wy1 IS NOT INITIAL.
        READ TABLE lt_idoc_data_ext2 INTO ls_idoc_data_ext2 WITH KEY value = lv_wy1 type = lc_wy .
        IF sy-subrc EQ 0.
          ls_idoc_data_ext-rel_to = ls_idoc_data_ext2-id.
          MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext .
        ENDIF.
      ENDIF.
    ENDIF.
  ENDLOOP.


* determine the order of the segments
* see docu for prescribed IDOC structure

* check the E1LFA1M level (on very top)
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfa1m .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.

* check the E1LFA1B level (on 2nd position)
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfa1b .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.

* check the E1LFA1A level (on 3rd order)
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfa1a .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.

* check E1LFA1H text header segment, on 4th + 5th (E1LFA1L, text body) position
* an E1LFA1H element has always a following E1LFA1L element
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfa1h .
    lv_tabix = sy-tabix.

    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.

* check whether there are more following E1LFA1L segments (several text lines in long text)
    lv_loop = 1.   " there is at least one following E1LFA1L segment
    WHILE lv_loop > 0 .
      READ TABLE lt_idoc_data_ext INTO ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
      IF sy-subrc EQ 0 AND ls_idoc_data_ext2-s_idoc_data-segnam EQ lc_e1lfa1l.
        lv_order_counter = lv_order_counter + 1.
        ls_idoc_data_ext2-order = lv_order_counter.
        MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
        lv_loop = lv_loop + 1.
      ELSE.
        lv_loop = 0.  " no more text lines, stop loop
      ENDIF.
    ENDWHILE.

  ENDLOOP.


* check the E1LFB1M level, i.e. cc level
* on 6th position in the IDOC structure
  lt_idoc_data_ext2[] = lt_idoc_data_ext[].
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfb1m .
    lv_tabix = sy-tabix.

    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.

* find these E1LFBWM segments that belong to the E1LFB1M (cc) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
          WHERE s_idoc_data-segnam EQ lc_e1lfbwm AND
                rel_to EQ ls_idoc_data_ext-id.
      lv_tabix = sy-tabix.
      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter.
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.

    ENDLOOP.

* find these E1LFB5M segments that belong to the E1LFB1M (cc) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
          WHERE s_idoc_data-segnam EQ lc_e1lfb5m AND
                rel_to EQ ls_idoc_data_ext-id.
      lv_tabix = sy-tabix.
      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter.
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.
    ENDLOOP.


* find these E1LFB1H segments that belong to the E1LFB1M (cc) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
       WHERE s_idoc_data-segnam EQ lc_e1lfb1h AND
             rel_to EQ ls_idoc_data_ext-id.

      lv_tabix = sy-tabix.

      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter .
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.

* check whether there are more following E1LFB1L segments (several text lines in long text)
      lv_loop = 1.   " there is at least one following E1LFB1L segment
      WHILE lv_loop > 0 .
        READ TABLE lt_idoc_data_ext INTO ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
        IF sy-subrc EQ 0 AND ls_idoc_data_ext2-s_idoc_data-segnam EQ lc_e1lfb1l.
          lv_order_counter = lv_order_counter + 1.
          ls_idoc_data_ext2-order = lv_order_counter.
          MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
          lv_loop = lv_loop + 1.
        ELSE.
          lv_loop = 0.  " no more text lines, stop loop
        ENDIF.
      ENDWHILE.


    ENDLOOP.

  ENDLOOP.


* check the E1LFM1M level, i.e. po level
* on 11th position in the IDOC structure
  lt_idoc_data_ext2[] = lt_idoc_data_ext[].
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfm1m .
    lv_tabix = sy-tabix.

    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.

* find these E1LFM2M segments that belong to the E1LFM1M (po) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
          WHERE s_idoc_data-segnam EQ lc_e1lfm2m AND
                rel_to EQ ls_idoc_data_ext-id.
      lv_tabix = sy-tabix.
      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter.
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.

    ENDLOOP.

* find these E1WYT3M segments that belong to the E1LFM1M (po) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
          WHERE s_idoc_data-segnam EQ lc_e1wyt3m AND
                rel_to EQ ls_idoc_data_ext-id.
      lv_tabix = sy-tabix.
      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter.
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.
    ENDLOOP.


* find these E1LFM1H segments that belong to the E1LFM1M (po) segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
       WHERE s_idoc_data-segnam EQ lc_e1lfm1h AND
             rel_to EQ ls_idoc_data_ext-id.

      lv_tabix = sy-tabix.

      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter .
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.

* check whether there are more following E1LFM1L segments (several text lines in long text)
      lv_loop = 1.   " there is at least one following E1LFM1L segment
      WHILE lv_loop > 0 .
        READ TABLE lt_idoc_data_ext INTO ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
        IF sy-subrc EQ 0 AND ls_idoc_data_ext2-s_idoc_data-segnam EQ lc_e1lfm1l.
          lv_order_counter = lv_order_counter + 1.
          ls_idoc_data_ext2-order = lv_order_counter.
          MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix + lv_loop.
          lv_loop = lv_loop + 1.
        ELSE.
          lv_loop = 0.  " no more text lines, stop loop
        ENDIF.
      ENDWHILE.

    ENDLOOP.


  ENDLOOP.




* check the E1LFBKM level
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfbkm .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.


* check the E1LFASM level
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1lfasm .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.


* check the E1KNVKM level
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1knvkm .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.
  ENDLOOP.


* check the E1WYT1M level
  lt_idoc_data_ext2[] = lt_idoc_data_ext[].
  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext WHERE s_idoc_data-segnam EQ lc_e1wyt1m .
    lv_order_counter = lv_order_counter + 1.
    ls_idoc_data_ext-order = lv_order_counter .
    MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext.

* find these E1WYTTM segments that belong to the E1WYT1M segment
    LOOP AT lt_idoc_data_ext2 INTO ls_idoc_data_ext2
          WHERE s_idoc_data-segnam EQ lc_e1wyttm AND
                rel_to EQ ls_idoc_data_ext-id.
      lv_tabix = sy-tabix.
      lv_order_counter = lv_order_counter + 1.
      ls_idoc_data_ext2-order = lv_order_counter.
      MODIFY lt_idoc_data_ext FROM ls_idoc_data_ext2 INDEX lv_tabix.
    ENDLOOP.

  ENDLOOP.


  SORT lt_idoc_data_ext BY order.


  LOOP AT lt_idoc_data_ext INTO ls_idoc_data_ext.
    ls_idoc_data = ls_idoc_data_ext-s_idoc_data.
    MODIFY t_idoc_data FROM ls_idoc_data INDEX sy-tabix.
  ENDLOOP.





ENDFUNCTION.

 

 

 

And the code for the deletion methods:

  method ADD_LFBK_SEGMENT_FOR_DELETION.
    DATA: ls_idoc_data TYPE EDIDD,
          ls_lfa1_segment TYPE EDIDD,
          ls_e1lfbkm TYPE E1LFBKM.

    READ TABLE t_idoc_data INTO ls_lfa1_segment
      WITH KEY SEGNAM = 'E1LFA1M'.
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    ls_e1lfbkm-MSGFN = '003'.
    ls_e1lfbkm-LIFNR = iv_lifnr.
    ls_e1lfbkm-banks = '/'.
    ls_e1lfbkm-bankl = '/'.
    ls_e1lfbkm-bankn = '/'.

    "ls_lfa1_segment contains main data elements (MANDT, DOCNUM)
    ls_idoc_data-MANDT = ls_lfa1_segment-MANDT.
    ls_idoc_data-DOCNUM = ls_lfa1_segment-DOCNUM.
    ls_idoc_data-SEGNUM = 0.
    ls_idoc_data-SEGNAM = 'E1LFBKM'.
    ls_idoc_data-PSGNUM = 0.
    ls_idoc_data-HLEVEL = 0.
    ls_idoc_data-DTINT2 = 0.
    ls_idoc_data-SDATA = ls_e1lfbkm.

    APPEND ls_idoc_data TO t_idoc_data.
  endmethod.




  method ADD_LFB5_SEGMENT_FOR_DELETION.


    DATA: ls_idoc_data TYPE edidd,
          ls_lfa1_segment TYPE edidd,
          lt_lfb1 TYPE STANDARD TABLE OF lfb1,
          ls_lfb1 TYPE lfb1,
          lv_bukrs TYPE bukrs,
          lv_sdata type EDI_SDATA,
          lv_maber type maber,
          ls_e1lfb5m TYPE e1lfb5m.

    READ TABLE t_idoc_data INTO ls_lfa1_segment
      WITH KEY segnam = 'E1LFA1M'.
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.


* check whether a deletion segment for dunning data is already in IDOC
    LOOP AT t_idoc_data INTO ls_idoc_data
      WHERE segnam = 'E1LFB5M' .

      lv_sdata = ls_idoc_data-sdata.
      SHIFT lv_sdata BY 13 PLACES LEFT .
      lv_bukrs = lv_sdata(4) . " get cc value

      IF lv_bukrs EQ iv_bukrs.  " check for current cc whether a deletion segment is already in the IDOC

        SHIFT lv_sdata BY 6 PLACES LEFT .
        lv_maber = lv_sdata(1) . " get tdline value

        IF lv_maber EQ gc_no_data.  " do not add a new deletion segment, it's already there
          RETURN.
        ENDIF.

      ENDIF.


    ENDLOOP.


    ls_e1lfb5m-msgfn = '003'.
    ls_e1lfb5m-lifnr = iv_lifnr.
    ls_e1lfb5m-bukrs = iv_bukrs.
    ls_e1lfb5m-maber = '/'.

    "ls_lfa1_segment contains main data elements (MANDT, DOCNUM)
    ls_idoc_data-mandt = ls_lfa1_segment-mandt.
    ls_idoc_data-docnum = ls_lfa1_segment-docnum.
    ls_idoc_data-segnum = 0.
    ls_idoc_data-segnam = 'E1LFB5M'.
    ls_idoc_data-psgnum = 0.
    ls_idoc_data-hlevel = 0.
    ls_idoc_data-dtint2 = 0.
    ls_idoc_data-sdata = ls_e1lfb5m.


* add the deletion tax IDOC segment (E1LFBW) right after the CC segment (E1LFB1M)
    INSERT ls_idoc_data INTO t_idoc_data INDEX iv_tabix + 1 .


  endmethod.






  METHOD add_lfbw_segment_for_deletion.


    DATA: ls_idoc_data TYPE edidd,
          ls_lfa1_segment TYPE edidd,
          lt_lfb1 TYPE STANDARD TABLE OF lfb1,
          ls_lfb1 TYPE lfb1,
          lv_bukrs TYPE bukrs,
          lv_sdata type EDI_SDATA,
          lv_witht type char2,
          ls_e1lfbwm TYPE e1lfbwm.

    READ TABLE t_idoc_data INTO ls_lfa1_segment
      WITH KEY segnam = 'E1LFA1M'.
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.


* check whether a deletion segment for tax data is already in IDOC
* this check is necessary because the BAdI incl. this method is called
* not only once but several times by the standard FM MASTERIDOC_CREATE_CREMAS

    LOOP AT t_idoc_data INTO ls_idoc_data
      WHERE segnam = 'E1LFBWM' .

      lv_sdata = ls_idoc_data-sdata.
      SHIFT lv_sdata BY 13 PLACES LEFT .
      lv_bukrs = lv_sdata(4) . " get cc value

      IF lv_bukrs EQ iv_bukrs.  " check for current cc whether a deletion segment is already in the IDOC

        SHIFT lv_sdata BY 4 PLACES LEFT .
        lv_witht = lv_sdata(1) . " get tdline value


        IF lv_witht EQ gc_no_data.  " do not add a new deletion segment, it's already there
          RETURN.
        ENDIF.

      ENDIF.


    ENDLOOP.



*    SELECT * FROM LFB1 INTO TABLE lt_lfb1
*        WHERE LIFNR = iv_lifnr.
*    IF sy-subrc <> 0.
*      RETURN.
*    ENDIF.
*    READ TABLE lt_lfb1 INTO ls_lfb1 INDEX 1.
*    lv_bukrs = ls_lfb1-bukrs.

*    CONCATENATE 'AL' iv_bukrs INTO lv_bukrs_gl.

    "MSGFN = '003'
    "BUKRS and BUKRS_GL = the corresponding company code
    "WITHT = '/' (NO_DATA)
    ls_e1lfbwm-msgfn = '003'.
    ls_e1lfbwm-lifnr = iv_lifnr.
    ls_e1lfbwm-bukrs = iv_bukrs.
    ls_e1lfbwm-witht = '/'.
    ls_e1lfbwm-wt_withcd = '/' .

    "ls_e1lfbwm-WT_SUBJCT = ''. "FIX 07.03.2017 (MORFA)
    "ls_e1lfbwm-QSREC = ''.
    "ls_e1lfbwm-WT_WTSTCD = ''.
    "ls_e1lfbwm-WT_WITHCD = '00'.
    "ls_e1lfbwm-WT_EXNR = ''.
    "ls_e1lfbwm-WT_EXRT = '0'.
    "ls_e1lfbwm-WT_EXDF = '00000000'.
    "ls_e1lfbwm-WT_EXDT = '00000000'.
    "ls_e1lfbwm-WT_WTEXRS = ''.
    ls_e1lfbwm-bukrs_gl = iv_bukrs.

    "ls_lfa1_segment contains main data elements (MANDT, DOCNUM)
    ls_idoc_data-mandt = ls_lfa1_segment-mandt.
    ls_idoc_data-docnum = ls_lfa1_segment-docnum.
    ls_idoc_data-segnum = 0.
    ls_idoc_data-segnam = 'E1LFBWM'.
    ls_idoc_data-psgnum = 0.
    ls_idoc_data-hlevel = 0.
    ls_idoc_data-dtint2 = 0.
    ls_idoc_data-sdata = ls_e1lfbwm.

*    APPEND ls_idoc_data TO t_idoc_data.

* add the deletion tax IDOC segment (E1LFBW) right after the CC segment (E1LFB1M)
    INSERT ls_idoc_data INTO t_idoc_data INDEX iv_tabix + 1 .

  ENDMETHOD.






  METHOD add_knvk_segment_for_deletion.


TYPES BEGIN OF:  ty_cdhdr.
    TYPES objectclas TYPE cdobjectcl .
    TYPES objectid   TYPE cdobjectv .
    TYPES changenr   TYPE cdchangenr .
TYPES END OF ty_cdhdr .


    DATA: ls_idoc_data               TYPE edidd,
          ls_lfa1_segment            TYPE edidd,
          ls_e1knvkm                 TYPE e1knvkm,
          lv_objectid                TYPE cdhdr-objectid ,
          lt_cdhdr                   TYPE STANDARD TABLE OF ty_cdhdr .




* check whether KNVK was ever added, if not, no deletion segment is needed


  lv_objectid = iv_lifnr.

  SELECT objectclas objectid changenr INTO TABLE lt_cdhdr
    FROM cdhdr
    WHERE objectclas = 'KRED'
    AND   objectid = lv_objectid.

  CHECK sy-subrc EQ 0.
  SORT lt_cdhdr BY changenr DESCENDING.
  SELECT COUNT(*) UP TO 1 ROWS
    FROM cdpos
    FOR ALL ENTRIES IN lt_cdhdr
    WHERE changenr = lt_cdhdr-changenr
    AND  tabname = 'KNVK'
    AND  chngind IN ('E','D').

  CHECK sy-subrc EQ 0. " not zero, no changes on KNVK, do not add an empty KNVK element


    READ TABLE t_idoc_data INTO ls_lfa1_segment
      WITH KEY segnam = 'E1LFA1M'.
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    ls_e1knvkm-msgfn = '003'.
    ls_e1knvkm-parnr = iv_lifnr.
    ls_e1knvkm-namev = '/'.
    ls_e1knvkm-name1 = '/'.
    ls_e1knvkm-abtnr = '/'.
    ls_e1knvkm-uepar = '0000000000'.
    ls_e1knvkm-pafkt = '/'.
    ls_e1knvkm-gbdat = '000000000'.
    ls_e1knvkm-vrtnr = '00000000000'.
    ls_e1knvkm-moab1 = '0000000'.
    ls_e1knvkm-mobi1 = '0000000'.
    ls_e1knvkm-moab2 = '0000000'.
    ls_e1knvkm-mobi2 = '0000000'.
    ls_e1knvkm-diab1 = '0000000'.
    ls_e1knvkm-dibi1 = '0000000'.
    ls_e1knvkm-diab2 = '0000000'.
    ls_e1knvkm-dibi2 = '0000000'.
    ls_e1knvkm-miab1 = '0000000'.
    ls_e1knvkm-mibi1 = '0000000'.
    ls_e1knvkm-miab2 = '0000000'.
    ls_e1knvkm-mibi2 = '0000000'.
    ls_e1knvkm-doab1 = '0000000'.
    ls_e1knvkm-dobi1 = '0000000'.
    ls_e1knvkm-doab2 = '0000000'.
    ls_e1knvkm-dobi2 = '0000000'.
    ls_e1knvkm-frab1 = '0000000'.
    ls_e1knvkm-frbi1 = '0000000'.
    ls_e1knvkm-frab2 = '0000000'.
    ls_e1knvkm-frbi2 = '0000000'.
    ls_e1knvkm-saab1 = '0000000'.
    ls_e1knvkm-sabi1 = '0000000'.
    ls_e1knvkm-saab2 = '0000000'.
    ls_e1knvkm-sabi2 = '0000000'.
    ls_e1knvkm-soab1 = '0000000'.
    ls_e1knvkm-sobi1 = '0000000'.
    ls_e1knvkm-soab2 = '0000000'.
    ls_e1knvkm-sobi2 = '0000000'.

    "ls_lfa1_segment contains main data elements (MANDT, DOCNUM)
    ls_idoc_data-mandt = ls_lfa1_segment-mandt.
    ls_idoc_data-docnum = ls_lfa1_segment-docnum.
    ls_idoc_data-segnum = 0.
    ls_idoc_data-segnam = 'E1KNVKM'.
    ls_idoc_data-psgnum = 0.
    ls_idoc_data-hlevel = 0.
    ls_idoc_data-dtint2 = 0.
    ls_idoc_data-sdata = ls_e1knvkm.

    APPEND ls_idoc_data TO t_idoc_data.
  ENDMETHOD.


 

 

 

 

 

 

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Michelle Crapo
      Michelle Crapo

      Code too? I really like that. I haven't had to extend an IDOC for a long time.  Why? Because I avoid them like the plague.  It's because they are just so darn hard to work with when you have to make a lot of changes.

      I'll have to keep this bookmarked for myself.  IDOCs are so solid to work with. Because they have been a part of SAP for a long time.

      What do I use instead? Proxy, XML, and good old flat files.

      Thank you,

      Michelle

      Author's profile photo Peranandam Chinnathambi
      Peranandam Chinnathambi

      Hi,

      I would like to add some points to bring more generic solutions.

      Business Problems:

      • Send additional data dynamically to the different target systems
      • Out of box solution not supporting to transfer deletion

       

      I would shift logic as part of below subroutine(using implicit enhancement in beginning of subroutine)  in order to have more control on transformations, filter, changing/additional idoc structures with respect to the target system level instead of writing logic in on top of FM'MASTER_IDOC_DISTRIBUTE'

      I would use MDG or ERP change pointer in order to identify deleted records instead of using CDHDR & CDPOS to have good performance and not to trigger deletion for every replication.

      • Activate required change pointer only for required segment (Consider segments which would have deletion scenarios) (TC BD66)
      • Implement BADI ‘BDCP_BEFORE_WRITE’ and generate change pointer only for deletion
      • Implement implicit enhancement option in subroutine mentioned above to read deletion change pointer which is not yet processed status and send deletion.
      • User table IDOCSYN in-order to identity correct hierarchy instead and to insert additional or deleted segment in correct position.
      • Set change pointer status processed (this way we will avoid of sending deletion repeatedly).
      • Delete processed change pointer once in a month to minimize load in change pointer table. Program RBDMIDOC has to be scheduled.

       

       

       

      Author's profile photo Jan Rauscher
      Jan Rauscher
      Blog Post Author

      Hello Michelle,

      thanks for your comment. Sometimes the project resp. customer prescribes the technology, so very often there is no way around IDOCs.

      Hello Perandaman, thanks for this helpful hints, very useful. Will take this into consideration when i face similar challenges in the future.

      Best

       

      Author's profile photo SRIKANTH GURURAJA
      SRIKANTH GURURAJA

      Hi Jan,

      Thanks for a good explanation of the issue and providing a solution. I came across the same issue for replication of Vendors from MDG to ECC using CREMAS IDOC.

      I discovered the below approach also works:

      • In the DRF class of Vendor 'CL_MDG_BS_VEND_ALE_DRF', we have a method SEND_CREMAS_IDOC, which in turn calls the form 'fill_keys_ext' of program SAPLKD01.
      • In the above perform, we can find a local class "lcl_cremas_keys=>fill" (Include LKD01P01) being called.
      • Enhance(Implicit) this method 'fill' as shown below, to add a dummy entry into the table of the segment of interest (In my case, I want to delete LFBK records in the target) - Here set the value of MSGFN = 003 (Deletion) in the exporting table et_lfbkkey.
      • By adding the above entry into table ET_LFBKKEY, the outbound IDOC automatically processes LFBK and adds a blank segment of LFBK with MSGFN = 003 which results in deletion of LFBK records in the target system.
      • This can be applied to other segments of the CREMAS Idoc which needs to be deleted in the target system in a hub method using DRF.
      • A similar approach can also be used for DEBMAS IDOC as well. In which case the class would CL_BS_CUST_ALE_DRF.

      Hope this helps!