SAP allows customer additions to their own tables, for many of the main documents. E.g. the purchase order can hold data on tables EKKO and EKPO, which can also be maintained via a BAPI call to BAPI_PO_CHANGE. The concept of a BAPI is allowing changes to a document via a programming interface (e.g. a function module). But how should SAP know which fields are added on the customer's site ? How should these fields be made changeable via function module parameters ? SAP's answer: the extension.

Extensions is a concept for allowing changes to non SAP-standard fields, used by several BAPI's. The example outlined here is for BAPI_PO_CHANGEbut also applies to many other BAPIs. The main components of extensions:

 

  • Function module BAPI_PO_CHANGE has a tables parameter field EXTENSIONIN STRUCTURE BAPIPAREX OPTIONAL. This table is used to hold the customer field changes for both the PO header (EKKO) and the PO item (EKPO).
  • Much like segments on an Idoc, the EXTENSIONIN structure holds a field called STRUCTURE¬†which is used to identify whether the entry is about the header fields (ekko), header field-update flags, item-fields (ekpo) or item fields update flags.
  • Again much like the Idoc segment concept, the actual data is set up on the VALUEPART1 through to VALUEPART4 fields (which act much like the SDATA field on table EDIDD. The Value-part fields act like a buffer field for the contents of the complete customer data extension (all fields concatenated together like held on EKKO or EKPO).
  • Like with standard SAP fields, the customer fields require an indicator to be checked, to enable the bapi to differentiate between clearing a field and leaving a field unchanged. Extensions work the same way, for the extension PO item fields, the actual field value (new value) must be maintained on EXTENSIONIN, and the field should be flagged for change on the EXTENSIONIN next entry.

An example should clarify how this all hangs together:

A simple example which updates a customer field in the header of the PO. Data declaration and BAPI call preparation. Make sure the variabele p_ebeln is filled with a valid PO number...

  DATA: p_ebeln like ekko-ebeln. 
  DATA: i_return type table of bapiret2 with header line,
        BAPI_TE_MEPOHEADER LIKE BAPI_TE_MEPOHEADER,
        BAPI_TE_MEPOHEADERX LIKE BAPI_TE_MEPOHEADERX.

  FIELD-SYMBOLS: <WA>   TYPE ANY.

  clear i_extensionin.
  clear BAPI_TE_MEPOHEADER.
  i_extensionin-STRUCTURE = 'BAPI_TE_MEPOHEADER'.
  BAPI_TE_MEPOHEADER-po_number = p_ebeln.
  BAPI_TE_MEPOHEADER-z_ownfield= 'MYVALUE'.
  ASSIGN i_extensionin-VALUEPART1 TO <WA> CASTING TYPE
                                        BAPI_TE_MEPOHEADER.
  <WA> = BAPI_TE_MEPOHEADER.
  APPEND i_extensionin.

  clear i_extensionin.
  clear BAPI_TE_MEPOHEADERX.
  i_extensionin-STRUCTURE = 'BAPI_TE_MEPOHEADERX'.
  BAPI_TE_MEPOHEADERX-po_number = p_ebeln.
  BAPI_TE_MEPOHEADERX-z_ownfield = 'X'.
  ASSIGN i_extensionin-VALUEPART1 TO <WA> CASTING TYPE
                                        BAPI_TE_MEPOHEADERX.
  <WA> = BAPI_TE_MEPOHEADERX.
  APPEND i_extensionin.

Above the extension fields are added, the first line from this table holds the actual field change, the second line indicates which field should be changed. Now call the BAPI and respond with the error (if there is one):

  CALL FUNCTION 'BAPI_PO_CHANGE'
    EXPORTING
      PURCHASEORDER = p_ebeln
    TABLES
      RETURN        = I_RETURN
*     POITEM        = p_poitem
*     POITEMX       = p_poitemX
      EXTENSIONIN   = i_extensionin.

  read table i_return with key type = 'E'.
  if sy-subrc ne 0.
    read table i_return with key type = 'A'.
  endif.
  if sy-subrc ne 0.
* Commit changes to database
    call function 'BAPI_TRANSACTION_COMMIT'.
    write: 'Call succesful'. 
  else.
    write: / i_return-message.
    exit.
  endif.

If the total size of the customer fields in an extension is bigger than the contents of the VALUEPART1 field, the second valuepart should be filled (as well). How ? Well, the same rules apply as described in the article above, except for the use of a field symbol to move field contents into the VALUEPART1 field. Check out the above example.