Better formatting on stackoverflow: https://stackoverflow.com/questions/58626204/proper-way-to-create-documentary-batches-programatically-how-to-use-bapi-goodsm
Solution at the bottom
My employer wishes to perform automatic documentary batch handling on some products from external vendors, and I'm trying to figure out how to set this up through Customizing and ABAP. It seems to me that Documentary Batches are only meant to be used through MIGO - in any case I'm unable to find a proper solution to assign them programatically, and any hacked-together solution I can come up with, seems insufficient and unstable. What avenues do I have to solve this issue?
Can I somehow do it through stuff like BAPI_GOODSMVT_CREATE?
I also specifically need it to work for consumption messaging through PPPI, and I thought to build on top of the standard Message Destination 'PI04', FM 'COCI_CONFIRM_MATERIAL_CONS'. This FM creates a Material Document but does not go through the 'BAPI_GOODSMVT_CREATE' FM. It does however use 'MB_CREATE_GOODS_MOVEMENT'.
I made hack-solution for one area, where I watched which table-updates MIGO performed and with which data (through FM's 'VB_INSERT_BATCH' and 'VB_BATCH_WHERE_USED_LIST'), and then filled out these structures manually. However, providing all the needed info is not feasible for other implementation areas, as they do not have all the necessary values available, and it doesn't cover unforeseen situations where other parameters might be required.
I've tried spying on whether BAPI_GOODSMVT_CREATE performs the same FM's but only found it accessing 'VB_BATCH_WHERE_USED_LIST'. It seems to be possible to activate this functionality by controlling Memory ID 'Documentary Batch #1', 'Documentary Batch #2', 'Documentary Batch #3' and 'Documentary Batch #5' (see FM 'VBDBDM_DATA_POST_IM'), but this requires filling out a lot data, including the structure name 'DOCUBATCH_SCREEN_FIELDS', which again makes it seem like this might not be the correct avenue of approach.
Regardless, this still doesn't allow me to maintain batch through tables MCHA and MCH1.
Here is how my hacked solution looks. Again, this is not a feasible way to go about the problem, as other implementation areas does not have the resulting Material Document immediately available:
FUNCTION zproxy_mdr_goodsreceipt. *"---------------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" VALUE(IS_GOODSRECEIPT_HEAD) TYPE ZPROXY_GOODSREC_HEAD *" VALUE(IT_GOODSRECEIPT_ITEM) TYPE ZPROXY_GOODSREC_ITEM_T *" REFERENCE(I_CREATE_TO_FROM_REQUIREMENTS) TYPE FLAG DEFAULT '-' *" EXPORTING *" REFERENCE(E_GOODSMVT_MSG_IDNO) TYPE CHAR23 *" REFERENCE(E_MBLNR) TYPE MBLNR *" REFERENCE(E_TO_CREATION_SUBRC) TYPE SY-SUBRC *" REFERENCE(E_LGNUM_ERROR) TYPE LGNUM *" REFERENCE(E_TBNUM_ERROR) TYPE TBNUM *" REFERENCE(E_DOCBATCH_SUBRC) TYPE SY-SUBRC *" REFERENCE(E_DOCBATCH_MSG_IDNO) TYPE CHAR23 *" REFERENCE(E_CLASSNUM) TYPE BAPI1003_KEY-CLASSNUM *" REFERENCE(E_OBJKEY) TYPE BAPI1003_KEY-OBJECT *" EXCEPTIONS *" GOODSMVT_FAILED *" NO_TRANSFER_REQUIREMENTS *" TRANSFER_ORDER_CREATION_ERROR *"---------------------------------------------------------------------- FIELD-SYMBOLS: <return> TYPE bapiret2, <goods_rec_item> TYPE zproxy_goodsrec_item, <mseg> TYPE mseg, <char_char> TYPE bapi1003_alloc_values_char, <ltap_creat> TYPE LTAP_CREAT. DATA: ls_header TYPE bapi2017_gm_head_01, ls_code TYPE bapi2017_gm_code, ls_item TYPE bapi2017_gm_item_create, lt_item TYPE STANDARD TABLE OF bapi2017_gm_item_create, lt_return TYPE STANDARD TABLE OF bapiret2, ls_headret TYPE bapi2017_gm_head_ret, l_mblnr LIKE bapi2017_gm_head_ret-mat_doc, l_docubatch TYPE charg_d, l_subrc TYPE sy-subrc, lt_mseg TYPE STANDARD TABLE OF mseg. CLEAR l_subrc. * ############################## Create goods movement ############################## * Build structures MOVE-CORRESPONDING is_goodsreceipt_head TO ls_header. ls_code-gm_code = '01'. LOOP AT it_goodsreceipt_item ASSIGNING <goods_rec_item>. MOVE-CORRESPONDING <goods_rec_item> TO ls_item. APPEND ls_item TO lt_item. ENDLOOP. * BAPI call CALL FUNCTION 'BAPI_GOODSMVT_CREATE' EXPORTING goodsmvt_header = ls_header goodsmvt_code = ls_code IMPORTING goodsmvt_headret = ls_headret materialdocument = l_mblnr TABLES goodsmvt_item = lt_item return = lt_return. * Check errors READ TABLE lt_return ASSIGNING <return> WITH KEY type = 'E'. IF sy-subrc = 0. e_goodsmvt_msg_idno = <return>-id && <return>-number. ROLLBACK WORK. RAISE goodsmvt_failed. ELSE. e_mblnr = l_mblnr. COMMIT WORK AND WAIT. "Wait for TO requirements to be created ENDIF. * Only proceede if Material Document has been successfully posted CHECK l_subrc = 0 AND l_mblnr IS NOT INITIAL. * ############################## Update with Documentary Batch ################################### DATA: lt_chvw TYPE STANDARD TABLE OF chvw, ls_chvw TYPE chvw, lt_mch1 TYPE STANDARD TABLE OF mch1, ls_mch1 TYPE mch1, lt_mcha TYPE STANDARD TABLE OF mcha, ls_mcha TYPE mcha, lt_mchb TYPE STANDARD TABLE OF mchb, lt_mska TYPE STANDARD TABLE OF mska, lt_mspr TYPE STANDARD TABLE OF mspr, lt_char_num TYPE STANDARD TABLE OF bapi1003_alloc_values_num, lt_char_char TYPE STANDARD TABLE OF bapi1003_alloc_values_char, lt_char_curr TYPE STANDARD TABLE OF bapi1003_alloc_values_curr, l_objkey TYPE bapi1003_key-object, l_classnum TYPE bapi1003_key-classnum, l_atnam TYPE atnam. REFRESH lt_chvw. * Get material document items SELECT * FROM mseg INTO TABLE lt_mseg WHERE mblnr = l_mblnr. * Perpare docubatch registration data LOOP AT it_goodsreceipt_item ASSIGNING <goods_rec_item>. * Generate class num and atnam from plant CONCATENATE 'PI_' <goods_rec_item>-plant INTO l_classnum. CONCATENATE 'Z_DOC_BATCH_' <goods_rec_item>-plant INTO l_atnam. * Get material docubatch usage characteristic REFRESH: lt_return, lt_char_num, lt_char_char, lt_char_curr. l_objkey(18) = <goods_rec_item>-material. CALL FUNCTION 'BAPI_OBJCL_GETDETAIL' EXPORTING objectkey = l_objkey objecttable = 'MARA' classnum = l_classnum classtype = '001' TABLES allocvaluesnum = lt_char_num allocvalueschar = lt_char_char allocvaluescurr = lt_char_curr return = lt_return. LOOP AT lt_return ASSIGNING <return> WHERE type = 'E'. "Check for errors * Couldn't read characteristic, assume no docubatch handling e_docbatch_subrc = '1'. e_docbatch_msg_idno = <return>-id && <return>-number. e_classnum = l_classnum. e_objkey = l_objkey. CONTINUE. ENDLOOP. READ TABLE lt_char_char ASSIGNING <char_char> WITH KEY charact = l_atnam. IF sy-subrc <> 0 OR <char_char>-value_neutral = 0. * No docubatch value CONTINUE. ENDIF. * Get associated material document item READ TABLE lt_mseg ASSIGNING <mseg> WITH KEY mblnr = ls_headret-mat_doc mjahr = ls_headret-doc_year bwart = <goods_rec_item>-move_type matnr = <goods_rec_item>-material werks = <goods_rec_item>-plant menge = <goods_rec_item>-entry_qnt meins = <goods_rec_item>-entry_uom hsdat = <goods_rec_item>-prod_date kzbew = <goods_rec_item>-mvt_ind lgort = <goods_rec_item>-stge_loc. IF sy-subrc <> 0. * No associated material document item CONTINUE. ENDIF. * Check docubatch type IF <char_char>-value_neutral <> 0. * Perform basic docubatch actions (MCHA and MCH1) * Verify that docubatch nr is assigned IF <goods_rec_item>-vendrbatch IS INITIAL. * !!!!!!!!!!!!! Venderbatch not filled even though material is docubatch managed, what to do? !!!!!!!!!!!!!!! CONTINUE. ENDIF. * Prepare data for docubatch registration CLEAR: ls_mch1, ls_mcha. ls_mch1-matnr = <goods_rec_item>-material. ls_mch1-charg = <goods_rec_item>-vendrbatch. ls_mch1-ersda = sy-datum. ls_mch1-ernam = sy-uname. ls_mch1-ersda_tmstp = sy-datum && sy-uzeit. ls_mch1-ersda_tz_sys = sy-tzone. ls_mch1-ersda_tz_usr = sy-zonlo. MOVE-CORRESPONDING ls_mch1 TO ls_mcha. "Same fields from MCH1 are included in MCHA ls_mcha-werks = <goods_rec_item>-plant. APPEND: ls_mch1 TO lt_mch1, ls_mcha TO lt_mcha. ENDIF. IF <char_char>-value_neutral = 2. "Also include batch where-used * Perpare data for batch where-used registration CLEAR ls_chvw. ls_chvw-matnr = <goods_rec_item>-material. ls_chvw-werks = <goods_rec_item>-plant. ls_chvw-charg = <goods_rec_item>-vendrbatch. ls_chvw-ebeln = <goods_rec_item>-po_number. ls_chvw-ebelp = <goods_rec_item>-po_item. ls_chvw-mblnr = ls_headret-mat_doc. ls_chvw-mjahr = ls_headret-doc_year. ls_chvw-zeile = <mseg>-zeile. ls_chvw-budat = is_goodsreceipt_head-pstng_date. ls_chvw-shkzg = 'S'. "??? VALUE ??? ls_chvw-bwart = <goods_rec_item>-move_type. ls_chvw-kzbew = <goods_rec_item>-mvt_ind. "Goods Movement for Purchase Order ls_chvw-menge = <goods_rec_item>-entry_qnt. ls_chvw-meins = <goods_rec_item>-entry_uom. APPEND ls_chvw TO lt_chvw. ENDIF. ENDLOOP. * Perform batch registration CALL FUNCTION 'VB_INSERT_BATCH' TABLES zmch1 = lt_mch1 zmcha = lt_mcha zmchb = lt_mchb zmska = lt_mska zmspr = lt_mspr . * Perform batch where-used registration CALL FUNCTION 'VB_BATCH_WHERE_USED_LIST' TABLES xchvw = lt_chvw. ENDFUNCTION.
Summary of why this isn't good enough, and what I need
This performs as a snapshot of MIGO configured with documentary batch handling, but doesn't necessarily cover all cases. It only works in the context of a Purchase Document, and doesn't cover other cases such as Orders and Sales Orders. Additionally I only have the necessary date because of the material document being created immediately above, which is not possible for all implementation cases.
I would like to know if there is an intended way to perform Documentary Batch handling from custom code.
Example call for Purchase Order Goods Receipt
LOOP AT it_goodsreceipt_item ASSIGNING <goods_rec_item>. CALL FUNCTION 'VBDBDM_DATA_MAINTAIN_RFC' EXPORTING i_matnr = <goods_rec_item>-material i_werks = <goods_rec_item>-plant i_quantity = <goods_rec_item>-entry_qnt i_uom = <goods_rec_item>-entry_uom i_docubatch_charg = <goods_rec_item>-vendrbatch * IT_DOCUBATCHES = i_process_id = '01' "Goods Receipt for External Procurement * I_REPLACE_EXISTING_DATA = i_ebeln = <goods_rec_item>-po_number i_ebelp = <goods_rec_item>-po_item * I_AUFNR = * I_AUFPS = * I_RSNUM = * I_RSPOS = * I_RSART = * I_VBELN = * I_POSNR = * IS_DOCUBATCH_COM = * I_LINE_ID = * I_LGNUM = * I_TANUM = * I_TAPOS = EXCEPTIONS parameter_error = 1 process_not_active = 2. ENDLOOP. * Follow up by creating Material Document, for example through BAPI_GOODSMVT_CREATE