第一次接触SAP BADI增强时,我完全被这个"面向对象"的概念搞懵了。作为一个习惯了传统ABAP编程的开发者,突然要面对接口、实现类这些新名词,确实需要一些适应时间。但当我真正理解BADI的工作原理后,才发现它其实比传统的用户出口(User Exit)和客户出口(Customer Exit)要优雅得多。
BADI(Business Add-In)是SAP第三代增强技术,它完全基于面向对象的设计理念。简单来说,SAP预先定义好了一组接口(Interface),我们只需要实现这些接口中定义的方法,就能在不修改标准代码的情况下扩展SAP的功能。这就像是在标准的SAP程序上"插"入我们自己的业务逻辑。
举个例子,在物料移动(MIGO)事务中,SAP提供了一个名为MB_DOCUMENT_BADI的增强点。当我们需要在物料凭证保存前进行额外的校验时,不需要去修改SAP的标准代码,只需要实现这个BADI接口中的CHECK方法即可。这种解耦的设计让我们的增强代码更加独立,也更容易维护。
找对增强点是成功实施BADI的第一步。我常用的方法是利用SE24事务码对CL_EXITHANDLER类进行调试。具体操作如下:
abap复制" 这是CL_EXITHANDLER类中GET_INSTANCE方法的关键代码
DATA: lv_exit_name TYPE exit_def.
CALL METHOD cl_exithandler=>get_class_name_by_interface
EXPORTING
exit_name = lv_exit_name.
在调试模式下,重点关注EXIT_NAME参数的值,这就是我们要找的BADI名称。比如在航班管理事务(BC425)中,可能会看到BC425_00FLIGHT2这样的BADI名称。
找到疑似BADI名称后,我习惯用SE18事务码进行验证。在SE18中输入BADI名称,如果能查到定义,说明我们找对了。这里有个小技巧:SAP的标准BADI通常都有详细的文档说明,包括每个方法的调用时机和参数含义,这些信息对我们后续实现非常重要。
找到正确的BADI后,就可以开始实现了。以MB_DOCUMENT_BADI为例,我们通过SE19创建实现:
abap复制CLASS zcl_mb_document_impl DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_ex_mb_document_badi.
ENDCLASS.
CLASS zcl_mb_document_impl IMPLEMENTATION.
METHOD if_ex_mb_document_badi~check.
" 在这里实现物料凭证的校验逻辑
ENDMETHOD.
ENDCLASS.
不同的BADI有不同的方法需要实现。以MB_DOCUMENT_BADI为例,最重要的三个方法是:
我曾经在一个项目中需要阻止特定工厂的物料移动,就是在CHECK方法中实现的:
abap复制METHOD if_ex_mb_document_badi~check.
LOOP AT imt_mseg ASSIGNING FIELD-SYMBOL(<fs_mseg>)
WHERE werks = '1000'. " 限制1000工厂的移动
MESSAGE e001(zmm) WITH '该工厂物料移动已被限制'.
ENDLOOP.
ENDMETHOD.
BADI的屏幕增强允许我们在标准事务的界面上添加自定义的屏幕区域。以BC425航班管理为例,假设我们需要在航班详情界面添加一个"特殊要求"字段:
使用SE80创建子屏幕:
abap复制" 屏幕0500的PBO模块
MODULE status_0500 OUTPUT.
IF zcl_flight_badi_impl=>gv_special_req IS INITIAL.
zcl_flight_badi_impl=>gv_special_req = '无'.
ENDIF.
ENDMODULE.
回到BADI实现(SE19),在屏幕增强相关的参数中填写:
然后在GET_DATA和PUT_DATA方法中实现数据传递:
abap复制METHOD if_ex_bc425_00flight2~get_data.
" 从标准界面获取数据到自定义字段
cs_flight-special_req = zcl_flight_badi_impl=>gv_special_req.
ENDMETHOD.
METHOD if_ex_bc425_00flight2~put_data.
" 将自定义字段数据保存到内存
zcl_flight_badi_impl=>gv_special_req = is_flight-special_req.
ENDMETHOD.
在实施BADI增强时,我遇到过不少"坑"。最常见的问题包括:
当增强导致程序DUMP时,ST22是最有用的工具。我通常会:
对于高频调用的BADI方法,我有几个优化心得:
abap复制" 不推荐的写法(每次循环都创建新工作区)
LOOP AT it_mseg INTO DATA(ls_mseg).
" 处理逻辑
ENDLOOP.
" 推荐的写法(使用FIELD-SYMBOL)
LOOP AT it_mseg ASSIGNING FIELD-SYMBOL(<fs_mseg>).
" 处理逻辑
ENDLOOP.
SAP允许一个BADI有多个实现,这在多子公司场景下特别有用。比如:
在SE19创建实现时,可以指定过滤字段。例如按公司代码过滤:
abap复制METHOD if_ex_mb_document_badi~check.
CASE iv_bukrs. " 公司代码过滤
WHEN '1000'.
" 北京公司特殊逻辑
WHEN '2000'.
" 上海公司特殊逻辑
ENDCASE.
ENDMETHOD.
在某些特殊场景下,我们可能需要动态调用BADI。这时可以直接使用CL_EXITHANDLER:
abap复制DATA: lo_badi TYPE REF TO if_ex_mb_document_badi.
TRY.
CALL METHOD cl_exithandler=>get_instance
EXPORTING
exit_name = 'MB_DOCUMENT_BADI'
CHANGING
instance = lo_badi.
lo_badi->check(...).
CATCH cx_badi_not_implemented.
" 处理未实现情况
ENDTRY.
在最近一个物流项目中,我们使用BADI增强了VL02N(外向交货单)事务。需求是在保存交货单时,根据运输路线自动计算预计到达时间。实现过程如下:
abap复制METHOD if_ex_outbound_delivery~change.
" 获取运输路线数据
SELECT SINGLE transit_time
FROM ztransit_time
INTO @DATA(lv_transit_time)
WHERE route = @cs_likp-route.
" 计算预计到达时间
cs_likp-zeta = cs_likp-lfdat + lv_transit_time.
ENDMETHOD.
这个增强上线后,仓库人员不再需要手动计算到达时间,错误率降低了80%。整个实施过程只用了2天,充分体现了BADI增强的高效性。