最近在项目上遇到一个需求,需要在BAPI中更新PO明细上的EAN11字段,由于标准BAPI中并不支持更新该字段,所以考虑在标准预留增强结构(CI_EKPODB)中加入该字段,通过BAPI的EXTENSIONIN传入后,在BADI(ME_PROCESS_PO_CUST)的IF_EX_ME_PROCESS_PO_CUST~PROCESS_ITEM方法中通过SET_DATA方法进行更新,但经过实际尝试,发现依然无法更新该字段,于是开始查阅各种资料,经过调查,官方note中给的建议是前台去更改这个字段:
但是还是想再找找有没有别的解决方案,调试完标准代码,发现是如下逻辑决定了无法更新该字段:
首先在标准BAPI(创建和更新BAPI中结构mapping逻辑相同)中该子例程是将传入参数mapping到标准结构,其中包括增强字段的mapping
在做完数据mapping后,开始实例化后续BADI中用到的OO对象
在此例程中,lt_item和lt_itemx为mapping之后包含EKPO中所有字段的内表,会在此form中通过set_data,set_datax的方式将数据写入OO对象,关键点在于这两个方法中的处理逻辑决定了哪些字段会被传入OO对象
在这段循环中,是具体实现将BAPI传入字段传入到最终更改对象列表中的逻辑,而具体匹配的方法在下面这两个方法中
在merge方法中,将传入参数传递到最终更改使用结构中
我们通过实际数据来debug看一下具体是怎么运行的:
以这条数据为例:
然后在BAPI中将对应的值改为新值,在进入到断点时可以看到如下参数
然而标准逻辑中使用的更新结构MEPOITEM_DATA中并不包括EAN11字段,所以执行后无法将传入的EAN11的值更新至目标结构中,所以在后面set_data的时候,使用的ls_item_new中并不会包含EAN11的最新值,依然是原有的值
而在标准BADI的IF_EX_ME_PROCESS_PO_CUST~PROCESS_ITEM使用的SET_DATA方法中也是同样的处理逻辑,
所以解决思路就是在set_data以及set_datax时将ls_item_new中的值更新为BAPI传入的值,完整解决方式如下:
1.在标准BAPI预留的扩张中添加要更新的字段
Tips:这里需要注意的是,增强字段最好加在CI_EKPODB以及CI_EKPODBX中,这样在BAPI_TE_MEPOITEM和BAPI_TE_MEPOITEMX中会默认包含进去,而且会有标准form去处理映射,在BAPI中的标准form move_data_in 中会看到具体的映射方法,里面写死了check的结构名是CI_EKPODB以及其他等标准结构,如果是增强在CI_EKPODB以及CI_EKPODBX中,下面这段增强可以跳过,本例由于增强字段是通过CLOUD平台添加的,所以增强字段不在CI_EKPODB中,那么需要额外做一个增强才可以将字段正确映射,否则无法更新增强字段,增强实现如下:
1.实施BADI ME_BAPI_PO_CUST
2.创建实施类ZCL_ME_BAPI_PO_CUST
3.实施方法IF_EX_ME_BAPI_PO_CREATE_02~EXTENSIONIN
这里参照标准逻辑,创建一个私有方法MOVE_CONTAINER_IN来将BAPIPAREX中的VALUE部分解析到对应的结构中
IF_EX_ME_BAPI_PO_CREATE_02~EXTENSIONIN中完整代码如下:
METHOD IF_EX_ME_BAPI_PO_CREATE_02~EXTENSIONIN.
* BREAK SHIN063.
* 将VBAK/VBAP增强字段转入POHEADER,POHEADERX,POITEM,POITEMX
CHECK EXTENSIONIN IS NOT INITIAL.
DATA:
WA_BAPI_TE_MEPOHEADER TYPE BAPI_TE_MEPOHEADER,
WA_BAPI_TE_MEPOHEADERX TYPE BAPI_TE_MEPOHEADERX,
WA_BAPI_TE_MEPOITEM TYPE BAPI_TE_MEPOITEM,
WA_BAPI_TE_MEPOITEMX TYPE BAPI_TE_MEPOITEMX,
WA_BAPI_TE_MEPOACCOUNT TYPE BAPI_TE_MEPOACCOUNTING,
WA_BAPI_TE_MEPOACCOUNTX TYPE BAPI_TE_MEPOACCOUNTINGX,
L_CONTAINER TYPE ME_MAX_CONTAINER,
LR_PAREX TYPE REF TO CL_NLS_STRUC_CONTAINER.
LR_PAREX = CL_MMPUR_BAPI_PO=>GET_CODEPAGE_HANDLER( ).
LOOP AT EXTENSIONIN INTO DATA(LS_EXTENSIONIN).
L_CONTAINER = LS_EXTENSIONIN+30.
CASE LS_EXTENSIONIN-STRUCTURE.
WHEN 'BAPI_TE_MEPOHEADER'.
* 将增强字段转换为可读结构
CALL METHOD ME->MOVE_CONTAINER_IN
EXPORTING
I_CONTAINER = L_CONTAINER
I_NLS = LR_PAREX
CHANGING
E_STRUC = WA_BAPI_TE_MEPOHEADER.
MOVE-CORRESPONDING WA_BAPI_TE_MEPOHEADER TO POHEADER.
WHEN 'BAPI_TE_MEPOHEADERX'.
* 将增强字段转换为可读结构
CALL METHOD ME->MOVE_CONTAINER_IN
EXPORTING
I_CONTAINER = L_CONTAINER
I_NLS = LR_PAREX
CHANGING
E_STRUC = WA_BAPI_TE_MEPOHEADERX.
MOVE-CORRESPONDING WA_BAPI_TE_MEPOHEADER TO POHEADERX.
WHEN 'BAPI_TE_MEPOITEM'.
* 将增强字段转换为可读结构
CALL METHOD ME->MOVE_CONTAINER_IN
EXPORTING
I_CONTAINER = L_CONTAINER
I_NLS = LR_PAREX
CHANGING
E_STRUC = WA_BAPI_TE_MEPOITEM.
IF WA_BAPI_TE_MEPOITEM-PO_ITEM = POITEM-EBELP.
ASSIGN POITEM TO FIELD-SYMBOL(<FS_POITEM>).
MOVE-CORRESPONDING WA_BAPI_TE_MEPOITEM TO <FS_POITEM>.
ENDIF.
WHEN 'BAPI_TE_MEPOITEMX'.
* 将增强字段转换为可读结构
CALL METHOD ME->MOVE_CONTAINER_IN
EXPORTING
I_CONTAINER = L_CONTAINER
I_NLS = LR_PAREX
CHANGING
E_STRUC = WA_BAPI_TE_MEPOITEMX.
IF WA_BAPI_TE_MEPOITEMX-PO_ITEM = POITEMX-EBELP_KEY.
ASSIGN POITEMX TO FIELD-SYMBOL(<FS_POITEMX>).
MOVE-CORRESPONDING WA_BAPI_TE_MEPOITEMX TO <FS_POITEMX>.
ENDIF.
WHEN OTHERS.
ENDCASE.
ENDLOOP.
ENDMETHOD.
MOVE_CONTAINER_IN中完整代码如下:
METHOD MOVE_CONTAINER_IN.
TRY.
ASSIGN E_STRUC TO FIELD-SYMBOL(<FS_STRUC>).
* convert container data to target structure
I_NLS->CONT_TO_STRUC( EXPORTING CONT = I_CONTAINER
LANGU = SY-LANGU
IMPORTING STRUC = <FS_STRUC> ).
CATCH CX_ROOT. "#EC *
ENDTRY.
ENDMETHOD.
第一个增强结束,继续后续操作
2.在include L2012F25的set_object_attributes子例程中进行如下增强,系统预留了标准的增强点
3.在BAPI调用时将EAN11放在EXTENSIONIN中
至此,所有增强完成,可以使用BAPI来进行EAN11的更新,验证一下:
更新前
BAPI赋值测试(项目封装函数,里面调用BAPI_PO_CREATE1/BAPI_PO_CHANGE)
更新后
以上。
2021/07/19日追加,由于这种四代增强在以后升级中会有丢失的风险,考虑到这个影响,所以后来采用实现方式为,将标准BAPI复制一份出来,修改其中子例程,配合EXTENSIONIN实现,具体如下:
将copy出来的标准form替换为自定义form
在自定义form中添加如下逻辑:
将扩张字段更改为ZZEAN11,避免以后升级后系统支持更新EAN11的更新造成冲突 ,在BADI增强中添加如下逻辑进行字段映射
以上。