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'
    EXPORTING
      i_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    =
    TABLES
      it_bpak           = lt_bpak
      it_return         = lt_return
    EXCEPTIONS
      no_update         = 1
      OTHERS            = 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_in
                             CHANGING 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 log
  DATA:
    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üfen
  GET 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 Area
    PERFORM 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 Order

  READ 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 amount
  PERFORM 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 FIELDS
      WITH 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 value
      PERFORM frm_bdc_field USING lv_bdc_field
                                  lv_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 value
      PERFORM frm_bdc_field USING 'BPDY-WERT1(01)'
                                  lv_bdc_value_c.
    ENDIF.
  ENDLOOP.

  lv_objnr = us_item-objnr.

  CALL FUNCTION 'ENQUEUE_EBPTR_EX'
    EXPORTING
      objnr          = lv_objnr
    EXCEPTIONS
      foreign_lock   = 1
      system_failure = 2
      OTHERS         = 3.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
    cs_resp-msgty = 'E'.

    MESSAGE ID sy-msgid
          TYPE sy-msgty
        NUMBER sy-msgno
          WITH sy-msgv1
               sy-msgv2
               sy-msgv3
               sy-msgv4
          INTO cs_resp-msgtx.
    RETURN.
  ELSE.
    CALL FUNCTION 'DEQUEUE_EBPTR_EX'
      EXPORTING
        objnr = lv_objnr.
  ENDIF.

  TRY.
      CALL TRANSACTION 'KO22' WITH AUTHORITY-CHECK USING bdcdata
                       MODE   '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-msgid
              TYPE sy-msgty
            NUMBER sy-msgno
              WITH sy-msgv1
                   sy-msgv2
                   sy-msgv3
                   sy-msgv4
              INTO 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-arbgb
                TYPE 'E'
              NUMBER ls_xmesg-txtnr
                WITH ls_xmesg-msgv1
                     ls_xmesg-msgv2
                     ls_xmesg-msgv3
                     ls_xmesg-msgv4
                INTO 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 transaction
      DATA(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.

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeveloperMrMeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值