In this code snippet I’ll demonstrate how to create or modify a source list (TCode ME01). I did’t find a suitable “standard way” how to do it, but after digging in the function module which processes inboud IDOC for source list (IDOC_INPUT_SRCLST) I managed to replicate the functionality in my own code.
I tried several ways how to do it:
Source list via BDC – batch input
One possible solution is a batch input. But this one is not very practical when you need to modify source list’s line items (especially when there are more line items), because it’s quite difficult to adress line items apeearing on later pages of the list. So you can’t easily access them via index… but anyway, if anyone is interested, you can use the following code:
DATA:
gt_bdcdata TYPE TABLE OF bdcdata,
gt_return TYPE TABLE OF bdcmsgcoll,
gv_message TYPE string.
START-OF-SELECTION.
PERFORM bdc_dynpro USING 'SAPLMEOR' '0200'.
PERFORM bdc_field USING 'BDC_CURSOR' 'EORD-MATNR'.
PERFORM bdc_field USING 'BDC_OKCODE' '/00'.
PERFORM bdc_field USING 'EORD-MATNR' '1000001974'.
PERFORM bdc_field USING 'EORD-WERKS' '0040'.
* Modify validity dates of the 5th line of source list
PERFORM bdc_dynpro USING 'SAPLMEOR' '0205'.
PERFORM bdc_field USING 'BDC_CURSOR' 'EORD-BDATU(01)'.
PERFORM bdc_field USING 'BDC_OKCODE' '=NS'.
PERFORM bdc_field USING 'EORD-VDATU(05)' '01.04.2016'.
PERFORM bdc_field USING 'EORD-BDATU(05)' '02.04.2016'.
* Add new line item in the source list
PERFORM bdc_dynpro USING 'SAPLMEOR' '0205'.
PERFORM bdc_field USING 'BDC_CURSOR' 'EORD-VDATU(02)'.
PERFORM bdc_field USING 'BDC_OKCODE' '=BU'.
PERFORM bdc_field USING 'EORD-VDATU(02)' '10.04.2016'.
PERFORM bdc_field USING 'EORD-BDATU(02)' '10.04.2016'.
PERFORM bdc_field USING 'EORD-LIFNR(02)' '510769'.
PERFORM bdc_field USING 'EORD-EKORG(02)' '0040'.
PERFORM bdc_field USING 'EORD-MEINS(02)' 'PC'.
PERFORM bdc_field USING 'EORD-EBELN(02)' '5500000667'.
PERFORM bdc_field USING 'EORD-EBELP(02)' '0010'.
PERFORM bdc_field USING 'EORD-AUTET(02)' '2'.
CALL TRANSACTION 'ME01' USING gt_bdcdata
MODE 'N'
UPDATE 'S'
MESSAGES INTO gt_return.
LOOP AT gt_return ASSIGNING FIELD-SYMBOL(<ls_return>).
MESSAGE ID <ls_return>-msgid
TYPE <ls_return>-msgtyp
NUMBER <ls_return>-msgnr
WITH <ls_return>-msgv1
<ls_return>-msgv2
<ls_return>-msgv3
<ls_return>-msgv4
INTO gv_message.
WRITE:/ gv_message.
ENDLOOP.
FORM bdc_field USING fnam fval.
DATA: ls_bdcdata TYPE bdcdata.
ls_bdcdata-fnam = fnam.
ls_bdcdata-fval = fval.
APPEND ls_bdcdata TO gt_bdcdata.
ENDFORM.
FORM bdc_dynpro USING prog scr.
DATA: ls_bdcdata TYPE bdcdata.
ls_bdcdata-program = prog.
ls_bdcdata-dynpro = scr.
ls_bdcdata-dynbegin = 'X'.
APPEND ls_bdcdata TO gt_bdcdata.
ENDFORM.
Source list via IDOC
I also tried to use inbound IDOC method, because I don’t have to care about adressing the item row numbers and everything is done by SAP standard. The problem is that the IDOC completely IGNORES the MSGFN field. Therefore you are not able to neither modify nor delete line items of a source list. The only action you can do this way is to INSERT new items.
CLASS lcl_idoc DEFINITION.
PUBLIC SECTION.
METHODS:
send_idoc.
PRIVATE SECTION.
CONSTANTS:
co_idoc_header_segment TYPE edilsegtyp VALUE 'E1EORDH',
co_idoc_item_segment TYPE edilsegtyp VALUE 'E1EORDM',
co_idoc_message_type TYPE edi_mestyp VALUE 'SRCLST',
co_idoc_basic_type TYPE edi_idoctp VALUE 'SRCLST01'.
DATA:
ms_control_rec TYPE edidc,
mt_idoc_data TYPE TABLE OF edidd,
ms_process_data TYPE tede2.
METHODS:
create_control_record,
create_header_segment,
create_item_segments,
create_idoc_db,
post_idoc_inbound.
ENDCLASS.
CLASS lcl_idoc IMPLEMENTATION.
METHOD send_idoc.
ir_idoc->create_control_record( ).
ir_idoc->create_header_segment( ).
ir_idoc->create_item_segments( ).
ir_idoc->create_idoc_db( ).
ir_idoc->post_idoc_inbound( ).
ENDMETHOD.
METHOD create_control_record.
DATA:
lv_logsys type LOGSYS.
ms_control_rec-mestyp = co_idoc_message_type.
ms_control_rec-idoctp = co_idoc_basic_type.
ms_control_rec-direct = 2. " 1 = outbound, 2 = inbound
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
OWN_LOGICAL_SYSTEM = lv_logsys.
ms_control_rec-rcvprt = 'LS'.
ms_control_rec-rcvprn = lv_logsys.
ms_control_rec-sndprt = 'LS'.
ms_control_rec-sndprn = lv_logsys.
ms_control_rec-sndpor = 'DUMMY'.
ENDMETHOD.
METHOD create_header_segment.
DATA:
ls_header TYPE e1eordh.
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
OWN_LOGICAL_SYSTEM = ls_header-logsy.
ls_header-msgfn = '005'. "This is ignored!!!
ls_header-matnr = '1000001974'.
ls_header-werks = '0040'.
APPEND INITIAL LINE TO mt_idoc_data
ASSIGNING FIELD-SYMBOL(<ls_header>).
<ls_header>-segnam = co_idoc_header_segment.
<ls_header>-sdata = ls_header.
ENDMETHOD.
METHOD create_item_segments.
DATA:
ls_item TYPE e1eordm,
lv_isocode type ISOCD_UNIT.
* IDOC accepts ISO codes ONLY!!! (e.g. 'PC' => 'PCE')
SELECT SINGLE isocode
FROM t006 INTO lv_isocode
WHERE msehi = 'PC'.
* INSERT new line item
ls_item-erdat = sy-datum.
ls_item-ernam = sy-uname.
ls_item-vdatu = '20160401'.
ls_item-bdatu = '20160401'.
ls_item-lifnr = '0000510769'.
ls_item-ebeln = '5500000667'.
ls_item-ebelp = '00010'.
ls_item-ekorg = '0040'.
* L = scheduling agreement
ls_item-vrtyp = 'L'. " L = scheduling agreement"
* '0' = Standard
* '2' = Consignment
ls_item-eortp = '0'. " category of source list record
* ' ' = Source list record not relevant to MRP
* '1' = Record relevant to MRP
* '2' = Recored relevant to MRP, sch.lines generated automatically
ls_item-autet = '2'.
ls_item-meins = lv_isocode.
APPEND INITIAL LINE TO mt_idoc_data
ASSIGNING FIELD-SYMBOL(<ls_item>).
<ls_item>-segnam = 'E1EORDM'.
<ls_item>-sdata = ls_item.
ENDMETHOD.
METHOD create_idoc_db.
CALL FUNCTION 'IDOC_INBOUND_WRITE_TO_DB'
IMPORTING
pe_idoc_number = ms_control_rec-docnum
pe_inbound_process_data = ms_process_data
TABLES
t_data_records = mt_idoc_data
CHANGING
pc_control_record = ms_control_rec
EXCEPTIONS
idoc_not_saved = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ELSE.
COMMIT WORK AND WAIT.
ENDIF.
ENDMETHOD.
METHOD post_idoc_inbound.
DATA:
lt_control_recs TYPE TABLE OF edidc.
APPEND ms_control_rec TO lt_control_recs.
CALL FUNCTION 'IDOC_START_INBOUND'
EXPORTING
pi_inbound_process_data = ms_process_data
pi_called_online = 'X'
succ_show_flag = 'X'
TABLES
t_control_records = lt_control_recs
EXCEPTIONS
invalid_document_number = 1
error_before_call_application = 2
inbound_process_not_possible = 3
old_wf_start_failed = 4
wf_task_error = 5
serious_inbound_error = 6
OTHERS = 7.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
CREATE OBJECT gr_idoc.
gr_idoc->send_idoc( ).
The reason why it’s not possible to modify or delete data is hidden in SAP standard FM ‘IDOC_INPUT_SRCLST’. If you dig in and check it’s form FILL_APPL_STRUCTURES_SRCLST you will find this:
- In the called form READ_SEG_E1EORDM you won’t find a row, where ZEORD is read.
- Even if the ZEAORD was read, on line #127 it is cleared.
This means the even if you try to address line items from EORD by their positions (ZEORD), it will be cleared (by standard!!!) and everything will be treated as new line items.
Next bad thing is hidden later in FM IDOC_INPUT_SRCLST, where it’s hardcoded, that all lines will be treated as NEW entries.
Therefore you can’t use the IDOC method for updating or deleting entries unless you want to modify SAP standard.
Source list via ME_DIRECT_INPUT_SOURCE_LIST
Finally I’ve discovered a fully functional way how to
- CREATE
- UPDATE
- DELETE
entries from the source list.
I managed to do it by more or less replicating code from the IDOC_INPUT_SCRLST, where I re-used some function modules called there in the following order:
- ME_INITIALIZE_SOURCE_LIST
- ME_DIRECT_INPUT_SOURCE_LIST
- ME_POST_SOURCE_LIST_NEW
- ME_WRITE_DISP_RECORD_SOS
- COMMIT WORK AND WAIT
The following code takes two input parameters (validity of the new line in source list) on the selection screen, invalidates all existing lines in source list which validity time frame overlap with the new line’s validity and creates the new line with given validity dates.
Here you can see source list status BEFORE the program execution
On the program’s selection screen I enter validity of the new line item in the source list
And here is the status of the source list AFTER the program was executed
DATA:
gv_new_sag TYPE ebeln,
gv_new_lifnr TYPE lifnr,
gv_matnr TYPE matnr,
gv_werks TYPE werks_d.
SELECTION-SCREEN BEGIN OF BLOCK bl01.
PARAMETERS:
p_vdatu LIKE eord-vdatu,
p_bdatu LIKE eord-bdatu.
SELECTION-SCREEN END OF BLOCK bl01.
FORM update_source_list USING uv_new_sag TYPE ebeln
uv_new_lifnr TYPE lifnr
uv_matnr TYPE matnr
uv_werks TYPE werks_d.
DATA:
lt_eordu TYPE TABLE OF eordu,
lt_eord TYPE TABLE OF eord,
lt_tupel TYPE TABLE OF metup,
lv_lifnr TYPE lifnr.
* Get all existing source list's line items for given MATNR, WERKS, LIFNR
SELECT *
INTO CORRESPONDING FIELDS OF TABLE lt_eordu
FROM eord
WHERE matnr = uv_matnr
AND werks = uv_werks
AND (
( vdatu <= p_vdatu AND bdatu >= p_vdatu )
OR ( vdatu <= p_bdatu AND bdatu >= p_bdatu )
OR ( vdatu >= p_vdatu AND bdatu <= p_bdatu )
).
* Make sure there's at least one source list's line item
CHECK lt_eordu IS NOT INITIAL.
SORT lt_eordu BY vdatu bdatu.
LOOP AT lt_eordu ASSIGNING FIELD-SYMBOL(<ls_eordu>).
APPEND INITIAL LINE TO lt_eord
ASSIGNING FIELD-SYMBOL(<ls_eord>).
MOVE-CORRESPONDING <ls_eordu> TO <ls_eord>.
* Item which is valid at beginning of the new source list entry will be updated
* It can be only one line
IF <ls_eordu>-vdatu < p_vdatu AND
<ls_eordu>-bdatu >= p_vdatu.
* Update the item so it's validity ends before validity of the new entry
<ls_eordu>-bdatu = p_vdatu - 1.
<ls_eordu>-kz = 'U'.
ELSE.
* Source list's items which are NOT valid at beginning of the new source list's entry will be deleted
<ls_eordu>-kz = 'D'.
ENDIF.
ENDLOOP.
READ TABLE lt_eordu ASSIGNING <ls_eordu> INDEX 1.
* We use this line as a template for the new source list's entry
APPEND INITIAL LINE TO lt_eordu
ASSIGNING FIELD-SYMBOL(<ls_eordu_new>).
<ls_eordu_new> = <ls_eordu>.
* Set correct data for the new source list's entry
CLEAR <ls_eordu_new>-zeord.
<ls_eordu_new>-kz = 'I'.
<ls_eordu_new>-vdatu = p_vdatu.
<ls_eordu_new>-bdatu = p_bdatu.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = uv_new_lifnr
IMPORTING
output = <ls_eordu_new>-lifnr.
<ls_eordu_new>-ebeln = uv_new_sag.
CALL FUNCTION 'ME_INITIALIZE_SOURCE_LIST'.
CALL FUNCTION 'ME_DIRECT_INPUT_SOURCE_LIST'
EXPORTING
i_matnr = uv_matnr
i_werks = uv_werks
i_vorga = 'B'
TABLES
t_eord = lt_eordu
EXCEPTIONS
plant_missing = 1
material_missing = 2
OTHERS = 3.
IF sy-subrc = 0.
APPEND INITIAL LINE TO lt_tupel
ASSIGNING FIELD-SYMBOL(<ls_tupel>).
<ls_tupel>-matnr = uv_matnr.
<ls_tupel>-werks = uv_werks.
CALL FUNCTION 'ME_POST_SOURCE_LIST_NEW'.
CALL FUNCTION 'ME_WRITE_DISP_RECORD_SOS' IN UPDATE TASK
TABLES
eord_alt = lt_eord
eord_neu = lt_eordu
tupel = lt_tupel.
COMMIT WORK AND WAIT.
ENDIF.
ENDFORM.
INITIALIZATION.
p_vdatu = sy-datum + 1.
p_bdatu = '99991231'.
START-OF-SELECTION.
gv_new_sag = '5500000667'.
gv_new_lifnr = '510769'.
gv_matnr = '1000001974'.
gv_werks = '0040'.
PERFORM update_source_list USING gv_new_sag
gv_new_lifnr
gv_matnr
gv_werks.
FOR THE CODE IT IS TRIGGERING A SYNTAX ERROR LIKE THIS -{Field “FIELD-SYMBOLS” is unknown. It is neither in one of the
specified tables nor defined by a “DATA” statement. “DATA” statement}.
Hello, this is a feature called “inline declaration” enabled in ABAP language since release 7.40 (see details at e.g. http://scn.sap.com/community/abap/blog/2013/07/22/abap-news-for-release-740)
If it’s not working in your environment, you can easily rewrite such command as:
.
FIELD-SYMBOLS:
… ASSIGNING …
Good job!
Hi
Can i get the rest of the code in last ABAP Option. Currently its only till start of selection.
Thanks
GSP
Thank you. Your analysis and solution proved invaluable!
Thanks!
Hi,
How do we activate change log to view change history after successful Source List update via this method?
Thanks…
Hi Leonard, sadly I don’t have access to the system anymore so I’m not able to check it.
Thanks Buddy, I had no option but to do it the hard way, BDC 🙂