Search code examples
abapbapi

Creating documentary batches programmatically with BAPI_GOODSMVT_CREATE?


Summary of the problem

Automatic Documentary Batch handling through custom ABAP code

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?

Enhancing BAPI_GOODSMVT_CREATE?

Can I somehow do it through stuff like BAPI_GOODSMVT_CREATE?

Enhancing PPPI Message Destinations?

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.

What I've already tried

MIGO Snapshot based Single Use hack solution

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.

Reading through BAPI_GOODSMVT_CREATE code

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 named 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.

Hacked together solution based on MIGO snapshot

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.

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.


Solution

  • Quoting from the documentation:

    If you work with RFID or TRM functions, or call IDocs/BAPIs, you can only book in documentary batches by calling up the RFC-capable function module VBDBDM_DATA_MAINTAIN_RFC beforehand or incorporating it into the process.

    So maybe this function module is the key? However, it seems you may not be the first to experience this pain. A comment on that documentation reads:

    Documentary Batch has a lot of constraints and it seems to be a semifinished product of SAP, since is missing a lot of features of real batches.

    Be prepared to make a lot of custom enhancements...

    ADDENDUM from community: below is the solution taken from the Original Poster two days after this answer, moved away from his question.

    Solution

    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