1. 举个我们这次系统中的一个业务场景
前面讲到我们需要把一个Oracle应付发票的凭证导入到SAP中,但是导入的字段比较多,就会出现如下的问题: SAP系统中把凭证中的[分支号]作为不同系统的来源,例如凭证来源于Oracle,金蝶,用友,那么分支号分别是'001','002','003'。 我们这里使用BAPI_ACC_DOCUMENT_POST来导入凭证, 大家可以看一下在BKPF表中存在[分支号]字段 但是在BAPIACHE09(操作代码SE37)结构中却没有[分支号]这个字段,BAPIACHE09是BAPI_ACC_DOCUMENT_POST导入凭证头的入口结构 那么标准API没有[分支号],SAP采用何种方法才能将[分支号]导入系统哪? 很高兴看到SAP提供了增强BAdi(客户化创建BAdi)来导入标准API没有的字段 一般情况下,不需要对BAdi作增强,但是当需要将某个不常用的字段导入到SAP,但是标准的BAPI又不能够支持这个字段,则需要对BAdi作增强,那么如何对BAdi作增强那? 下面简单做个讲解: 1)首先需要我们对标准的BAdi(操作代码SE19)做个实例化,本场景中,我们对ACC_DOCUMENT这个标准的BAdi实例化 关键是上图中的CHANGE部分,双击就可以进入BAdi的ABAP程序源代码,是不是感觉很爽,不过别高兴太早,因为进入源代码的编辑器之后,是空的,当然,源代码是需要自己添加的,请看下图: 上面的代码看不懂没关系,我来解释一下: DATA部分是定义变量,liw_accit TYPE accit就是定义一个accit的结构类型的变量liw_accit; LOOP部分就是对BAPI中的extension2的数据作循环 Liw_accit-bschl就是对bschl这个字段根据实际传入的数据作赋值,当然,bschl就是类似[分支号]的字段; MODIFY就是将bashl等字段写入到c_accit结构中,相当于更新accit表中的数据 大家看到这里,可能已经明白了BAdi是怎么回事。但是大家可能会问,BAPI怎么会去调用BAdi来做这个事情哪?这个问题可能比较复杂,但是我把他简化了说: 在下图中,BAPI一般会有 [Import]传入参数 [Export]传出参数 [Tabellen]这个是table类型的,用来传入和传出数组类型或table类型的数据,在table类型的数据中有个参数是extension2,作为扩展导入的字段,只要在extension2中作了定义,那么就会执行所有实例化的BAdi,所以这也算是SAP的一个缺点,因为假设你定义了2个相同类型的BAdi,它们都会被执行,假设这两个BAdi逻辑相悖,则会导致所无的数据,所以要在SAP的开发中避免
1. SAP导入多个凭证
不过讲到这里,我们也只是一个凭证,但是在我们实际的业务场景中,我们大部分都需要导入多个凭证,那么如果想要导入多个凭证,使用SAP的API如何来实现那? 既然可以使用BAPI_ACC_DOCUMENT_POST可以导入单个凭证,只要对它循环操作就可以实现多个凭证的导入了,大家看了下面的代码就会理解,红色的部分就是循环调用BAPI_ACC_DOCUMENT_POST就可以批量导入凭证
主要关于BAPI_ACC_DOCUMENT_POST的用法,懂ABAP的人都知道这是用于过账的,而BAPI_ACC_DOCUMENT_CHECK是用于做过账前的Check处理的。我程序里明明设置好了参数,但是Debug测试时只看到Post Successfully的消息,却看不到我要的会计凭证号,当时很奇怪。百翻思考,网上查资料,后来问题终于得到解决。原来是因为我在 documentheader里多传进去了三个参数:OBJ_TYPE, OBJ_KEY,OBJ_SYS。如果删除这三个参数的话就能在返回的内部table里抓去我想要的凭证号码了。呵呵!问题搞定,当时真的很兴奋!
如果谁对BAPI_ACC_DOCUMENT_POST和BAPI_ACC_DOCUMENT_CHECK这两个BAPI不太熟悉的话,那麽在 SAP ECC6.0以上的版本上有一本系统程序ACC_BAPI_TEST_DOCUMENT,可供参考。里面有关于他们的用法以及参数设置。。。
实例代码:
* 当前行过账-header信息设定 PERFORM FRM_HEADER_DOCUMENT USING LV_INDEX CHANGING LW_HEADER_DOCU. * 当前行过账-明细信息设定 PERFORM FRM_EDIT_BAPIITEMS USING LV_INDEX LW_ALVDATA. * 登录会计凭证 PERFORM FRM_CALL_BAPI USING LW_HEADER_DOCU.
*&---------------------------------------------------------------------* *& Form FRM_HEADER_DOCUMENT *&---------------------------------------------------------------------* * header信息设定 *----------------------------------------------------------------------* * -->P_IN_FLG 处理FLG * <--PW_OUT_HEADER 表头 *----------------------------------------------------------------------* FORM FRM_HEADER_DOCUMENT USING P_IN_FLG TYPE CHAR01 CHANGING PW_OUT_HEADER TYPE BAPIACHE09. DATA: LV_TEXT TYPE BKTXT. CLEAR PW_OUT_HEADER. * YYYY年MM月总额法坏账准备计提 CONCATENATE P_YEMON+0(4) TEXT-005 P_YEMON+4(2) TEXT-006 INTO LV_TEXT. PW_OUT_HEADER-USERNAME = SY-UNAME. "用户名 PW_OUT_HEADER-HEADER_TXT = LV_TEXT. "凭证抬头文本 PW_OUT_HEADER-COMP_CODE = P_BUKRS. "公司代码 PW_OUT_HEADER-DOC_DATE = GV_EDATE. "凭证中的凭证日期 PW_OUT_HEADER-DOC_TYPE = 'ZG'. "凭证类型 * 处理FLG CASE P_IN_FLG. * 当月的坏账会计凭证 WHEN '1'. PW_OUT_HEADER-PSTNG_DATE = GV_EDATE. "凭证过帐日期 PW_OUT_HEADER-FISC_YEAR = P_YEMON+0(4)."会计年度 PW_OUT_HEADER-FIS_PERIOD = P_YEMON+4(2)."会计期间 * 下月的冲销会计凭证 WHEN '2'. * 下个会计期间的设定 PERFORM FRM_GET_NEXTMONTH CHANGING PW_OUT_HEADER-PSTNG_DATE "凭证过帐日期 PW_OUT_HEADER-FISC_YEAR "会计年度 PW_OUT_HEADER-FIS_PERIOD."会计期间 WHEN OTHERS. ENDCASE. ENDFORM. " FRM_HEADER_DOCUMENT
*&---------------------------------------------------------------------* *& Form FRM_EDIT_BAPIITEMS *&---------------------------------------------------------------------* * 当前行过账-明细信息设定 *----------------------------------------------------------------------* * -->P_IN_FLG 当月凭证与下一个月凭证标志 * -->P_IN_ALVDATA alv数据 *----------------------------------------------------------------------* FORM FRM_EDIT_BAPIITEMS USING P_IN_FLG TYPE CHAR01 P_IN_ALVDATA TYPE TYP_ALVDATA. REFRESH: GT_ACCOUNTGL, GT_CURRAMOUNT, GT_ACCOUNTAR, GT_EXTENSION2. ****第一个分录 * 各明细项目的作成 PERFORM FRM_APPEND_ITEMS USING P_IN_FLG '1' P_IN_ALVDATA. ****第二个分录 * 各明细项目的作成 PERFORM FRM_APPEND_ITEMS USING P_IN_FLG '2' P_IN_ALVDATA. ENDFORM. " FRM_EDIT_BAPIITEMS
*&---------------------------------------------------------------------* *& Form FRM_APPEND_ITEMS *&---------------------------------------------------------------------* * 各明细项目的作成 *----------------------------------------------------------------------* * -->P_IN_CLFLG 当月凭证标志与下一个月凭证标志 * -->P_IN_INDEX 第一分录与第二分录标志 * -->P_IN_DATA alv数据 *----------------------------------------------------------------------* FORM FRM_APPEND_ITEMS USING P_IN_CLFLG TYPE CHAR01 P_IN_INDEX TYPE CHAR01 P_IN_DATA TYPE TYP_ALVDATA. DATA: LW_ACCOUNTGL TYPE BAPIACGL09, LW_CURRAMOUNT TYPE BAPIACCR09, LW_ACCOUNTAR TYPE BAPIACAR09, LW_EXTENSION2 TYPE BAPIPAREX, LW_ZEXTEN TYPE ZEXTEN. * 第一分录的时候 IF P_IN_INDEX = '1'. * 会计凭证行项目编号 LW_ACCOUNTGL-ITEMNO_ACC = 1. * 利润中心 LW_ACCOUNTGL-PROFIT_CTR = P_IN_DATA-PRCTR. * 总账科目 LW_ACCOUNTGL-GL_ACCOUNT = '0670100100'. APPEND LW_ACCOUNTGL TO GT_ACCOUNTGL. ELSEIF P_IN_INDEX = '2'. * 会计凭证行项目编号 LW_ACCOUNTAR-ITEMNO_ACC = 2. * 客户编号 LW_ACCOUNTAR-CUSTOMER = P_IN_DATA-KUNNR. * 到期日计算的基限日期 LW_ACCOUNTAR-BLINE_DATE = GV_EDATE. * 利润中心 LW_ACCOUNTAR-PROFIT_CTR = P_IN_DATA-PRCTR. APPEND LW_ACCOUNTAR TO GT_ACCOUNTAR. ENDIF. * 会计凭证行项目编号 LW_CURRAMOUNT-ITEMNO_ACC = LINES( GT_CURRAMOUNT ) + 1. * 货币码 LW_CURRAMOUNT-CURRENCY = P_IN_DATA-WAERS. * 货币类型 LW_CURRAMOUNT-CURR_TYPE = '00'. * 第一分录的时候 IF P_IN_INDEX = '1'. CASE P_IN_CLFLG. * 当月的坏账会计凭证 WHEN '1'. * 凭证货币金额(正值) --- 40 --- LW_CURRAMOUNT-AMT_DOCCUR = ABS( P_IN_DATA-DMBTRP_SUM ). * 下月的冲销会计凭证 WHEN '2'. * 凭证货币金额(负值) --- 50 --- LW_CURRAMOUNT-AMT_DOCCUR = ABS( P_IN_DATA-DMBTRP_SUM ) * -1. WHEN OTHERS. ENDCASE. * 第二分录的时候 ELSEIF P_IN_INDEX = '2'. CASE P_IN_CLFLG. * 当月的坏账会计凭证 --- 19 --- WHEN '1'. * 凭证货币金额(负值) LW_CURRAMOUNT-AMT_DOCCUR = ABS( P_IN_DATA-DMBTRP_SUM ) * -1. * 下月的冲销会计凭证 WHEN '2'. * 凭证货币金额(负值) --- 09 --- LW_CURRAMOUNT-AMT_DOCCUR = ABS( P_IN_DATA-DMBTRP_SUM ). WHEN OTHERS. ENDCASE. ENDIF. APPEND LW_CURRAMOUNT TO GT_CURRAMOUNT. CLEAR LW_ZEXTEN. * 第一分录的时候 IF P_IN_INDEX = '1'. CASE P_IN_CLFLG. * 当月的坏账会计凭证 WHEN '1'. * 记帐代码 LW_ZEXTEN-BSCHL = '40'. * 下月的冲销会计凭证 WHEN '2'. * 记帐代码 LW_ZEXTEN-BSCHL = '50'. WHEN OTHERS. ENDCASE. * 第二分录的时候 ELSEIF P_IN_INDEX = '2'. CASE P_IN_CLFLG. * 当月的坏账会计凭证 WHEN '1'. * 记帐代码 LW_ZEXTEN-BSCHL = '19'. * 下月的冲销会计凭证 WHEN '2'. * 记帐代码 LW_ZEXTEN-BSCHL = '09'. WHEN OTHERS. ENDCASE. * 特殊总帐标识 LW_ZEXTEN-UMSKZ = 'H'. ENDIF. * 会计凭证行项目编号 LW_ZEXTEN-POSNR = LINES( GT_EXTENSION2 ) + 1. * 到期日 LW_ZEXTEN-ZFBDT = GV_EDATE. * BAPI 表扩展的结构名称 LW_EXTENSION2-STRUCTURE = 'ZEXTEN'. * BAPI 扩展参数的数据部分 LW_EXTENSION2-VALUEPART1 = LW_ZEXTEN. APPEND LW_EXTENSION2 TO GT_EXTENSION2. ENDFORM. " FRM_APPEND_ITEMS
*&---------------------------------------------------------------------* *& Form FRM_CALL_BAPI *&---------------------------------------------------------------------* * 登录会计凭证 *----------------------------------------------------------------------* * -->P_IN_HEADER header信息 *----------------------------------------------------------------------* FORM FRM_CALL_BAPI USING P_IN_HEADER TYPE BAPIACHE09. DATA: LW_RETURN TYPE BAPIRET2, LT_RETURN TYPE STANDARD TABLE OF BAPIRET2. CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST' EXPORTING DOCUMENTHEADER = P_IN_HEADER TABLES ACCOUNTGL = GT_ACCOUNTGL ACCOUNTRECEIVABLE = GT_ACCOUNTAR CURRENCYAMOUNT = GT_CURRAMOUNT RETURN = LT_RETURN EXTENSION2 = GT_EXTENSION2. * S 成功,E 错误,W 警告,I 信息,A 中断 LOOP AT LT_RETURN INTO LW_RETURN WHERE TYPE = 'E' OR TYPE = 'A'. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. MESSAGE ID LW_RETURN-ID TYPE 'E' NUMBER LW_RETURN-NUMBER WITH LW_RETURN-MESSAGE_V1 LW_RETURN-MESSAGE_V2 LW_RETURN-MESSAGE_V3 LW_RETURN-MESSAGE_V4. ENDLOOP. * 创建成功 IF SY-SUBRC <> 0. CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING WAIT = 'X'. * 凭证过账运行结束! MESSAGE S067(ZFI01). ENDIF. ENDFORM. " FRM_CALL_BAPI