SAP KO22内部订单预算BAPI与BDC
KO22可以为内部订单预先维护预算,以便在后续成本实际产生时进行控制。
使用BAPI进行创建:KBPP_EXTERN_UPDATE_CO
SAP note 625613中对该BAPI的使用方式有详细介绍,使用时可进行参考。
年度预算:e_gjahr传值、e_ges置空;
总预算:e_gjahr置空、e_ges为'X'。
实际使用过程中,发现有一种情况用该BAPI更新不了,即在分配预算之前,该订单就已经产生成本,这种时候前台可以正常保存,但BAPI无法直接更新成功,debug无果后决定使用BDC来进行实现,如果有人知道通过BAPI怎么处理这种情况,可以评论分享下。
DATA:lt_bpak TYPE bpak_tab,ls_bpak TYPE bpak,lt_return TYPE bapiret2_t,ls_return TYPE bapiret2."年度预算
ls_bpak-e_objnr = us_item-objnr.
ls_bpak-e_gjahr = us_item-gjahr.
ls_bpak-wert = us_item-wtjhr.
ls_bpak-twaer = us_item-twaer.
ls_bpak-e_versn = ''.
APPEND ls_bpak TO lt_bpak.
CLEAR ls_bpak."总预算
ls_bpak-e_objnr = us_item-objnr.
ls_bpak-wert = us_item-wtges.
ls_bpak-twaer = us_item-twaer.
ls_bpak-e_ges = 'X'.
ls_bpak-e_versn = ''.
APPEND ls_bpak TO lt_bpak.
CLEAR ls_bpak.* 预算更新CALL FUNCTION 'KBPP_EXTERN_UPDATE_CO'EXPORTINGi_budget_activity = 'KBUD'
* I_BUDGET_ACTIV_SUP_RET = ' '
* I_BUDGET_DISTRIBUTION_ALLOWED = ' '
* I_COMMIT_DATA = ' '
* I_DELTA_AMOUNTS = 'X'
* I_ROLLUP_DATA = 'X'
* I_CHECK_PLAN_DATA = 'X'
* I_APPLICATION =i_commit_all = 'X'
* IMPORTING
* E_ERRORS_FOUND =TABLESit_bpak = lt_bpakit_return = lt_returnEXCEPTIONSno_update = 1OTHERS = 2.
使用BDC进行创建
使用SHDB进行录屏,BDC的使用方法网上太多帖子了,这里只分享下使用BDC过程中碰到的几个问题:
问题1:
在初次登陆系统时,进入该事务代码时,会出现这个弹窗,让用户选择控制范围,输入过之后,后续再次进入该事务代码,这个弹窗就不会出现了,这也是使用BDC时需要注意到的点,这个弹窗也需要录进去,但是程序应该根据什么逻辑来决定是否需要弹窗这段录屏代码呢?
理论上SAP大多数类似的标准功能都是相同的逻辑,都是点选了对应的值之后,使用SET PARAMER ID 'XXX' FIELD VALUE来将用户选择的值保存到SAP SESSION中,后面每次进入事务码时,使用GET PARAMER ID 'XXX' FIELD VALUE来进行获取,如果获取到就不会出现这个弹窗,所以我们在录屏的代码中,加上对应的判断即可。
在弹窗输入框中摁下F1,即可快速找到该字段对应的Parameter ID。
问题2:
使用BDC时,有时候一些前台的报错日志不会返回到messtab中,例如下图这种报错。
解决思路就是在前台点保存之后,/H进行debug,一步一步跟踪看标准代码是怎么进行处理的,以我这个前台报错为例,最终定位到程序在CHECK_ALL子例程中进行所有检查逻辑,在CHECK_LIST中将错误信息进行转换,并且收集到内表 (SAPLSMSG)XMESG[] 中,再以弹窗形式输出,但是前台执行和BDC执行时有些地方有不太一样。
在CHECK_ALL的子例程中,检查发生在函数KBPT_CHECK_BUDGET_PLAN中,前台执行后,如果有错误信息,不会执行446行的E类型消息,但BDC后台调用会执行该语句,E类型的消息会直接终止掉程序,所以后续的CHECK_LIST中收集错误的逻辑就没有办法去执行,程序中自然也无法获取到错误消息。
后来进一步调试,发现消息的收集和显示,是在CHECK_LIST里面的一个函数KBPT_ERROR_LOG中完成,参数MOVE_MESS决定了是否出现弹窗。
所以想要程序中捕获到这个错误信息,就需要在message E 类型语句之前把对应的错误消息收集到,并抛给程序,最终发现只有一个位置可以用来做这件事,就是在SET_ERROR_MARK中做隐式增强来进行数据抛出。
因为后续的message E语句会终止掉internal session,导致调用程序中无法获取到该session中的任何数据,所以只能通过EXPORT TO DATABASE的方式来共享数据。
以上,即可拿到跟前台一样的错误日志数据。
KO22的BDC参考代码:
*&---------------------------------------------------------------------*
*& Form FRM_BDC_CONTRACT_MAINTAIN
*&---------------------------------------------------------------------*
*& Using BDC to create contract
*&---------------------------------------------------------------------*
FORM frm_bdc_contract_maintain USING ut_item TYPE zprfitintordbudget_item_inCHANGING cs_resp TYPE zprbcsrest_out.DATA:lv_kokrs TYPE tka01-kokrs,lt_index TYPE STANDARD TABLE OF string,lv_tabix TYPE n LENGTH 2,lv_year TYPE n LENGTH 4,lv_bdc_field TYPE string,lv_bdc_value_i TYPE i,lv_bdc_value_c TYPE string,lv_errmsg TYPE string,lv_objnr TYPE bp_objekt.* BDC Error logDATA:lt_mesg TYPE STANDARD TABLE OF mesg,lt_xmesg TYPE STANDARD TABLE OF smesgx.CONSTANTS:lc_wert1 TYPE string VALUE 'BPDY-WERT1',lc_left_brackets TYPE char1 VALUE '(',lc_right_brackets TYPE char1 VALUE ')'.* SPA/GPA-Parameter prüfenGET PARAMETER ID 'CAC' FIELD lv_kokrs.lv_year = sy-datlo+0(4) - 1.APPEND 'TOTAL' TO lt_index.DO 5 TIMES.APPEND lv_year TO lt_index.ADD 1 TO lv_year.ENDDO.IF lv_kokrs IS INITIAL.
* Select Controller AreaPERFORM frm_bdc_dynpro USING 'SAPLSPO4' '0300'.PERFORM frm_bdc_field USING 'BDC_CURSOR''SVALD-VALUE(01)'.PERFORM frm_bdc_field USING 'BDC_OKCODE''=FURT'.PERFORM frm_bdc_field USING 'SVALD-VALUE(01)''ZDPS'.ENDIF.* Enter OrderREAD TABLE ut_item INTO DATA(us_item) INDEX 1.PERFORM frm_bdc_dynpro USING 'SAPMKBUD' '0300'.PERFORM frm_bdc_field USING 'BDC_CURSOR''CODIA-AUFNR'.PERFORM frm_bdc_field USING 'BDC_OKCODE''/00'.PERFORM frm_bdc_field USING 'CODIA-AUFNR'us_item-aufnr.PERFORM frm_bdc_dynpro USING 'SAPLKBPP' '0320'.PERFORM frm_bdc_field USING 'BDC_CURSOR''BPDY-WERT1(01)'.PERFORM frm_bdc_field USING 'BDC_OKCODE''=FULL'.* Full amountPERFORM frm_bdc_dynpro USING 'SAPLKBPP' '0220'.PERFORM frm_bdc_field USING 'BDC_CURSOR''BPDY-WERT1(03)'.PERFORM frm_bdc_field USING 'BDC_OKCODE''=POST'.LOOP AT ut_item INTO us_item.READ TABLE lt_index TRANSPORTING NO FIELDSWITH KEY table_line = us_item-gjahr.IF sy-subrc = 0.lv_tabix = sy-tabix.lv_bdc_field = lc_wert1 &&lc_left_brackets &&lv_tabix &&lc_right_brackets.lv_bdc_value_i = us_item-wtjhr.lv_bdc_value_c = lv_bdc_value_i.CONDENSE lv_bdc_value_c NO-GAPS.* Year valuePERFORM frm_bdc_field USING lv_bdc_fieldlv_bdc_value_c.ENDIF.IF us_item-wtges IS NOT INITIAL..lv_bdc_value_i = us_item-wtges.lv_bdc_value_c = lv_bdc_value_i.CONDENSE lv_bdc_value_c NO-GAPS.* Total valuePERFORM frm_bdc_field USING 'BPDY-WERT1(01)'lv_bdc_value_c.ENDIF.ENDLOOP.lv_objnr = us_item-objnr.CALL FUNCTION 'ENQUEUE_EBPTR_EX'EXPORTINGobjnr = lv_objnrEXCEPTIONSforeign_lock = 1system_failure = 2OTHERS = 3.IF sy-subrc <> 0.
* Implement suitable error handling herecs_resp-msgty = 'E'.MESSAGE ID sy-msgidTYPE sy-msgtyNUMBER sy-msgnoWITH sy-msgv1sy-msgv2sy-msgv3sy-msgv4INTO cs_resp-msgtx.RETURN.ELSE.CALL FUNCTION 'DEQUEUE_EBPTR_EX'EXPORTINGobjnr = lv_objnr.ENDIF.TRY.CALL TRANSACTION 'KO22' WITH AUTHORITY-CHECK USING bdcdataMODE 'N'UPDATE 'S'MESSAGES INTO messtab.LOOP AT messtab INTO DATA(ls_messtab) WHERE msgtyp CA 'EAX'.cs_resp-msgty = 'E'.EXIT.ENDLOOP.IF sy-subrc <> 0.cs_resp-msgty = 'S'.MESSAGE ID sy-msgidTYPE sy-msgtyNUMBER sy-msgnoWITH sy-msgv1sy-msgv2sy-msgv3sy-msgv4INTO cs_resp-msgtx.ELSE.IMPORT zprerrlog = lt_xmesg FROM DATABASE indx(pr) ID 'ZPRMEMORY_KO22'.DELETE FROM DATABASE indx(pr) ID 'ZPRMEMORY_KO22'.LOOP AT lt_xmesg INTO DATA(ls_xmesg).MESSAGE ID ls_xmesg-arbgbTYPE 'E'NUMBER ls_xmesg-txtnrWITH ls_xmesg-msgv1ls_xmesg-msgv2ls_xmesg-msgv3ls_xmesg-msgv4INTO lv_errmsg.CONCATENATE cs_resp-msgtx '|' lv_errmsg INTO cs_resp-msgtx.ENDLOOP.cs_resp-msgtx = shift_left( val = cs_resp-msgtx sub = '|' ).ENDIF.CATCH cx_sy_authorization_error INTO DATA(lx_auth_check).
* Authorization missing for user when executing transactionDATA(lv_auth_check_text) = lx_auth_check->get_text( ).cs_resp-msgty = 'E'.cs_resp-msgtx = lv_auth_check_text.ENDTRY.CLEAR:bdcdata,bdcdata[],messtab,messtab[],lt_mesg.FREE:bdcdata[],messtab[].
ENDFORM.