实时发送SAP会计凭证到外部系统

实时发送SAP会计凭证到外部系统

原创 ABAP老白 ABAP老白 2023-01-29 19:17 发表于上海

最近几年做的接口类型的开发比较多,有一类接口是把SAP的凭证类型数据或者主数据发送到外部系统。在对实时性要求不高的时候,通常会通过筛选创建日期、时间等使用JOB程序推送到外部,但是如果对实时性要求比较高这个方法就不再适合了。这个时候可以使用Message以IDOC的方式发出去,或者在增强里面使用自开发程序直接推出去。

本例使用BTE的方式,实时的把SAP会计凭证推送到外部的Oracle数据库。

和物料凭证的POST不同,并没有一个出口/BADI能够包含会计凭证的所有创建/更改,如果使用BTE的话,需要下面三个:

1、事件00001030    直接生成的会计凭证,比如F-02 2、事件00001050    VF01 MIRO等间接生成的凭证数据 3、事件00001110    FB02 更改凭证数据

详细过程: 1、配置BTE,事务码FIBF

2、程序

FUNCTION zbte_send_bseg_to_gb.

*"----------------------------------------------------------------------

*"*"更新函数模块:

*"

*"*"局部接口:

*" IMPORTING

*" VALUE(UPDKZ) TYPE UPDKZ_D OPTIONAL

*" VALUE(I_XBKPF) TYPE BKPF OPTIONAL

*" VALUE(I_YBKPF) TYPE BKPF OPTIONAL

*" TABLES

*" T_BKPF STRUCTURE BKPF OPTIONAL

*" T_BSEG STRUCTURE BSEG OPTIONAL

*" XBSEG STRUCTURE FBSEG OPTIONAL

*"----------------------------------------------------------------------

DATA: lt_bseg TYPE TABLE OF bseg WITH HEADER LINE.

DATA: lt_gb TYPE TABLE OF zbte_send_bseg_to_gb_s1 WITH HEADER LINE.

CHECK s_hkont[] IS NOT INITIAL.

IF updkz = 'I'.

LOOP AT t_bseg WHERE hkont IN s_hkont.

READ TABLE t_bkpf WITH KEY bukrs = t_bseg-bukrs

belnr = t_bseg-belnr

gjahr = t_bseg-gjahr.

MOVE-CORRESPONDING t_bseg TO lt_gb.

MOVE-CORRESPONDING t_bkpf TO lt_gb.

APPEND lt_gb.CLEAR lt_gb.

ENDLOOP.

ELSEIF updkz = 'U'.

IF i_xbkpf-bktxt <> i_ybkpf-bktxt OR

i_xbkpf-xblnr <> i_ybkpf-xblnr OR

i_xbkpf-xref1_hd <> i_ybkpf-xref1_hd OR

i_xbkpf-xref2_hd <> i_ybkpf-xref2_hd OR

xbseg[] IS INITIAL.

SELECT * INTO CORRESPONDING FIELDS OF TABLE lt_bseg

FROM bseg

WHERE bukrs = i_xbkpf-bukrs AND

belnr = i_xbkpf-belnr AND

gjahr = i_xbkpf-gjahr AND

hkont IN s_hkont.

CHECK sy-subrc = 0.

LOOP AT lt_bseg.

READ TABLE xbseg WITH KEY buzei = lt_bseg-buzei.

IF sy-subrc = 0.

MOVE-CORRESPONDING xbseg TO lt_bseg.

ENDIF.

MOVE-CORRESPONDING lt_bseg TO lt_gb.

MOVE-CORRESPONDING i_xbkpf TO lt_gb.

APPEND lt_gb.CLEAR lt_gb.

ENDLOOP.

ELSE.

LOOP AT xbseg WHERE hkont IN s_hkont.

MOVE-CORRESPONDING xbseg TO lt_gb.

MOVE-CORRESPONDING i_xbkpf TO lt_gb.

APPEND lt_gb.CLEAR lt_gb.

ENDLOOP.

ENDIF.

ENDIF.

CHECK lt_gb[] IS NOT INITIAL.

CALL FUNCTION 'ZBTE_PUSH_BSEG_TO_GB' "IN BACKGROUND TASK

EXPORTING

updkz = updkz

commit = ''

TABLES

gbtab = lt_gb.

ENDFUNCTION.

FUNCTION zbte_push_bseg_to_gb.

*"----------------------------------------------------------------------

*"*"Local interface:

*" IMPORTING

*" VALUE(UPDKZ) TYPE UPDKZ_D OPTIONAL

*" VALUE(COMMIT) TYPE CHAR1 OPTIONAL

*" TABLES

*" GBTAB STRUCTURE ZBTE_SEND_BSEG_TO_GB_S1

*"----------------------------------------------------------------------

DATA: connam TYPE dbcon-con_name VALUE 'EDWP'.

DATA: lt_log TYPE TABLE OF zgbt2 WITH HEADER LINE.

DATA: cxserr TYPE REF TO cx_sy_native_sql_error,

excmsg TYPE string,

rtmsg TYPE bapi_msg.

DATA: BEGIN OF lt_error OCCURS 0,

bukrs TYPE zgbt2-bukrs,

belnr TYPE zgbt2-belnr,

gjahr TYPE zgbt2-gjahr,

buzei TYPE zgbt2-buzei,

exmsg TYPE zgbt2-exmsg,

END OF lt_error.

LOOP AT gbtab.

lt_log-bukrs = gbtab-bukrs.

lt_log-belnr = gbtab-belnr.

lt_log-gjahr = gbtab-gjahr.

lt_log-buzei = gbtab-buzei.

lt_log-hkont = gbtab-hkont.

lt_log-aedat = sy-datum.

lt_log-aezet = sy-uzeit.

lt_log-aenam = sy-uname.

APPEND lt_log.

ENDLOOP.

MODIFY zgbt2 FROM TABLE lt_log.

IF commit = 'X'.

COMMIT WORK.

ENDIF.

TRY .

EXEC SQL.

connect to :connam

ENDEXEC.

CATCH cx_sy_native_sql_error INTO cxserr.

excmsg = cxserr->sqlmsg.

CONCATENATE '连接' connam '失败:' excmsg INTO excmsg.

LOOP AT lt_log.

UPDATE zgbt2 SET exmsg = excmsg

WHERE bukrs = lt_log-bukrs AND

belnr = lt_log-belnr AND

gjahr = lt_log-gjahr AND

buzei = lt_log-buzei.

MOVE-CORRESPONDING lt_log TO lt_error.

lt_error-exmsg = excmsg.

APPEND lt_error.

ENDLOOP.

ENDTRY.

IF lt_error[] IS INITIAL.

LOOP AT gbtab.

CLEAR excmsg.

TRY.

IF updkz = 'U'.

EXEC SQL.

delete from zodss700_bseg

where mandt = :gbtab-mandt and

bukrs = :gbtab-bukrs and

belnr = :gbtab-belnr and

gjahr = :gbtab-gjahr and

buzei = :gbtab-buzei

ENDEXEC.

ENDIF.

CLEAR sy-subrc.

EXEC SQL.

insert into zodss700_bseg

( mandt ,bukrs ,belnr ,gjahr ,buzei ,blart ,bldat ,budat ,monat ,cpudt ,

cputm ,aedat ,upddt ,usnam ,tcode ,bvorg ,xblnr ,stjah ,bktxt ,waers ,

kursf ,hwaer ,awsys ,stgrd ,ppnam ,numpg ,bstat ,glvor ,awtyp ,awkey ,

augdt ,augbl ,bschl ,koart ,umskz ,umsks ,shkzg ,gsber ,mwskz ,dmbtr ,

wrbtr ,pswbt ,pswsl ,valut ,zuonr ,sgtxt ,kokrs ,kostl ,aufnr ,vbeln ,

vbel2 ,posn2 ,anln1 ,bzdat ,xkres ,xpanz ,xzahl ,saknr ,hkont ,kunnr ,

lifnr ,zfbdt ,zterm ,matnr ,werks ,menge ,meins ,ebeln ,bwkey ,bwtar ,

rstgr ,prctr ,kstrg ,projk ,lokkt ,xref1 ,xref2 ,fkber ,xnegp ,kkber ,

xref3 ,zzcfi,anln2 ,anbwa ,load_dt )

values

( :gbtab-mandt ,

:gbtab-bukrs ,

:gbtab-belnr ,

:gbtab-gjahr ,

:gbtab-buzei ,

:gbtab-blart ,

:gbtab-bldat ,

:gbtab-budat ,

trim( :gbtab-monat ) ,

:gbtab-cpudt,

:gbtab-cputm ,

:gbtab-aedat ,

:gbtab-upddt ,

trim( :gbtab-usnam ) ,

trim( :gbtab-tcode ) ,

trim( :gbtab-bvorg ) ,

trim( :gbtab-xblnr ) ,

trim( :gbtab-stjah ) ,

trim( :gbtab-bktxt ) ,

trim( :gbtab-waers ) ,

trim( :gbtab-kursf ) ,

trim( :gbtab-hwaer ) ,

trim( :gbtab-awsys ) ,

trim( :gbtab-stgrd ) ,

trim( :gbtab-ppnam ) ,

trim( :gbtab-numpg ) ,

trim( :gbtab-bstat ) ,

trim( :gbtab-glvor ) ,

trim( :gbtab-awtyp ) ,

trim( :gbtab-awkey ) ,

:gbtab-augdt ,

trim( :gbtab-augbl ),

trim( :gbtab-bschl ),

trim( :gbtab-koart ),

trim( :gbtab-umskz ),

trim( :gbtab-umsks ),

trim( :gbtab-shkzg ),

trim( :gbtab-gsber ),

trim( :gbtab-mwskz ),

trim( :gbtab-dmbtr ),

trim( :gbtab-wrbtr ),

trim( :gbtab-pswbt ),

trim( :gbtab-pswsl ),

:gbtab-valut,

trim( :gbtab-zuonr ) ,

trim( :gbtab-sgtxt ) ,

trim( :gbtab-kokrs ) ,

trim( :gbtab-kostl ) ,

trim( :gbtab-aufnr ) ,

trim( :gbtab-vbeln ) ,

trim( :gbtab-vbel2 ) ,

trim( :gbtab-posn2 ) ,

trim( :gbtab-anln1 ) ,

:gbtab-bzdat ,

trim( :gbtab-xkres ) ,

trim( :gbtab-xpanz ) ,

trim( :gbtab-xzahl ) ,

trim( :gbtab-saknr ) ,

trim( :gbtab-hkont ) ,

trim( :gbtab-kunnr ) ,

trim( :gbtab-lifnr ) ,

:gbtab-zfbdt ,

trim( :gbtab-zterm ) ,

trim( :gbtab-matnr ) ,

trim( :gbtab-werks ) ,

trim( :gbtab-menge ) ,

trim( :gbtab-meins ) ,

trim( :gbtab-ebeln ) ,

trim( :gbtab-bwkey ) ,

trim( :gbtab-bwtar ) ,

trim( :gbtab-rstgr ) ,

trim( :gbtab-prctr ) ,

trim( :gbtab-kstrg ) ,

trim( :gbtab-projk ) ,

trim( :gbtab-lokkt ) ,

trim( :gbtab-xref1 ) ,

trim( :gbtab-xref2 ) ,

trim( :gbtab-fkber ) ,

trim( :gbtab-xnegp ) ,

trim( :gbtab-kkber ) ,

trim( :gbtab-xref3 ) ,

trim( :gbtab-zzcfi ) ,

trim( :gbtab-anln2 ) ,

trim( :gbtab-anbwa ) ,

sysdate

)

ENDEXEC.

IF sy-subrc <> 0.

WRITE sy-subrc TO rtmsg LEFT-JUSTIFIED.

UPDATE zgbt2 SET exmsg = rtmsg

WHERE bukrs = gbtab-bukrs AND

belnr = gbtab-belnr AND

gjahr = gbtab-gjahr AND

buzei = gbtab-buzei.

CONTINUE.

ENDIF.

EXEC SQL.

commit

ENDEXEC.

CATCH cx_sy_native_sql_error INTO cxserr.

excmsg = cxserr->sqlmsg.

UPDATE zgbt2 SET exmsg = excmsg

WHERE bukrs = gbtab-bukrs AND

belnr = gbtab-belnr AND

gjahr = gbtab-gjahr AND

buzei = gbtab-buzei.

MOVE-CORRESPONDING gbtab TO lt_error.

lt_error-exmsg = excmsg.

APPEND lt_error.

ENDTRY.

ENDLOOP.

ENDIF.

ENDFUNCTION.

说明: ZBTE_SEND_BSEG_TO_GB为UPDATE Module, ZBTE_SEND_BSEG_TO_GB为RFC

重发程序: 因为网络或者Oracle的原因,发送失败是在所难免的,所以还需要一个重发程序,此程序既能够看到发送日志,也可以进行重发。

*&---------------------------------------------------------------------*

*& Report ZGB_ZGBT2_RESEND

*&

*&---------------------------------------------------------------------*

*&

*& 重新发送管报凭证数据

*&---------------------------------------------------------------------*

REPORT zgb_resend_docs NO STANDARD PAGE HEADING.

TYPE-POOLS: sscr,slis.

DATA: fldct TYPE lvc_t_fcat WITH HEADER LINE,

slayt TYPE lvc_s_layo,

varnt TYPE disvariant,

repid TYPE sy-repid.

DATA: BEGIN OF it_out OCCURS 0,

bukrs TYPE zgbt2-bukrs,

belnr TYPE zgbt2-belnr,

gjahr TYPE zgbt2-gjahr,

buzei TYPE zgbt2-buzei,

hkont TYPE zgbt2-hkont,

aedat TYPE zgbt2-aedat,

aezet TYPE zgbt2-aezet,

aenam TYPE zgbt2-aenam,

exmsg TYPE zgbt2-exmsg,

seled,

END OF it_out.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE t01.

SELECT-OPTIONS s_bukrs FOR it_out-bukrs.

SELECT-OPTIONS s_belnr FOR it_out-belnr.

SELECT-OPTIONS s_gjahr FOR it_out-gjahr.

SELECT-OPTIONS s_aedat FOR it_out-aedat.

SELECT-OPTIONS s_aenam FOR it_out-aenam.

SELECT-OPTIONS s_exmsg FOR it_out-exmsg.

SELECTION-SCREEN END OF BLOCK b1.

AT SELECTION-SCREEN OUTPUT.

t01 = '选择条件'.

%_s_bukrs_%_app_%-text = '公司代码'.

%_s_belnr_%_app_%-text = '凭证号'.

%_s_gjahr_%_app_%-text = '年度'.

%_s_aedat_%_app_%-text = '发送日期'.

%_s_aenam_%_app_%-text = '发送账号'.

%_s_exmsg_%_app_%-text = '错误文本'.

START-OF-SELECTION.

PERFORM getdata.

PERFORM outdata.

*&---------------------------------------------------------------------*

*& Form getdata

*&---------------------------------------------------------------------*

FORM getdata.

CLEAR it_out[].

SELECT * INTO CORRESPONDING FIELDS OF TABLE it_out

FROM zgbt2

WHERE bukrs IN s_bukrs AND

belnr IN s_belnr AND

gjahr IN s_gjahr AND

aedat IN s_aedat AND

aenam IN s_aenam AND

exmsg IN s_exmsg

ORDER BY PRIMARY KEY .

MESSAGE s000(oo) WITH '数据条数:' sy-dbcnt.

ENDFORM. "getdata

*&---------------------------------------------------------------------*

*& Form outdata

*&---------------------------------------------------------------------*

FORM outdata.

repid = sy-repid.

slayt-zebra = 'X'.

slayt-no_toolbar = 'X'.

slayt-detailinit = 'X'.

slayt-box_fname = 'SELED'.

varnt-report = sy-repid.

varnt-handle = 1.

PERFORM catset TABLES fldct

USING: 'BUKRS' '' '' '公司代码',

'BELNR' '' '' '凭证号',

'GJAHR' '' '' '年度',

'BUZEI' '' '' '项目号',

'HKONT' '' '' '科目',

'AEDAT' '' '' '发送日期',

'AEZET' '' '' '时间',

'AENAM' '' '' '账号',

'EXMSG' '' '' '错误消息'.

CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'

EXPORTING

it_fieldcat_lvc = fldct[]

i_save = 'A'

is_variant = varnt

is_layout_lvc = slayt

i_callback_program = repid

i_callback_user_command = 'USER_COMMAND'

i_callback_pf_status_set = 'SET_STATUS'

TABLES

t_outtab = it_out.

ENDFORM. " outdata

*&---------------------------------------------------------------------*

*& Form SET_STATUS

*&---------------------------------------------------------------------*

FORM set_status USING rt_extab TYPE slis_t_extab.

SET PF-STATUS 'STD_FULL' EXCLUDING rt_extab .

ENDFORM. "SET_STATUS

*---------------------------------------------------------------------*

* FORM catset *

*---------------------------------------------------------------------*

FORM catset TABLES fldcat USING p_field p_reftab p_reffld p_text.

DATA: ls_fldcat TYPE lvc_s_fcat.

ls_fldcat-fieldname = p_field.

ls_fldcat-scrtext_l = p_text.

ls_fldcat-coltext = p_text.

ls_fldcat-ref_table = p_reftab.

ls_fldcat-ref_field = p_reffld.

ls_fldcat-col_opt = 'A'.

CASE ls_fldcat-fieldname.

WHEN 'BELNR'.

ls_fldcat-edit_mask = '==ALPHA'.

WHEN OTHERS.

ENDCASE.

APPEND ls_fldcat TO fldcat .

CLEAR ls_fldcat .

ENDFORM. "catset

*&--------------------------------------------------------------------*

*& Form user_command

*&--------------------------------------------------------------------*

FORM user_command USING r_ucomm TYPE sy-ucomm

r_field TYPE slis_selfield.

DATA: lt_retn TYPE TABLE OF bapiret2.

READ TABLE it_out INDEX r_field-tabindex.

CASE r_ucomm.

WHEN '&IC1'.

SET PARAMETER ID 'BLN' FIELD it_out-belnr .

SET PARAMETER ID 'BUK' FIELD it_out-bukrs.

SET PARAMETER ID 'GJR' FIELD it_out-gjahr.

CALL TRANSACTION 'FB03' AND SKIP FIRST SCREEN .

RETURN.

WHEN 'RESEND'.

PERFORM resend.

RETURN.

WHEN 'REFRESH'.

PERFORM getdata.

WHEN 'TOCLIP'.

PERFORM itabtoclip_alv(zpublicform) TABLES it_out USING 'X'.

RETURN.

ENDCASE.

r_field-row_stable = 'X'.

r_field-col_stable = 'X'.

r_field-refresh = 'X'.

ENDFORM. "user_command

*&---------------------------------------------------------------------*

*& Form re_send

*&---------------------------------------------------------------------*

FORM resend.

DATA: BEGIN OF lt_key OCCURS 0,

bukrs TYPE bseg-bukrs,

belnr TYPE bseg-belnr,

gjahr TYPE bseg-gjahr,

buzei TYPE bseg-buzei,

END OF lt_key.

DATA: lt_gbtab TYPE TABLE OF zbte_send_bseg_to_gb_s1 WITH HEADER LINE.

LOOP AT it_out WHERE seled = 'X'.

MOVE-CORRESPONDING it_out TO lt_key.

APPEND lt_key.

ENDLOOP.

IF sy-subrc <> 0.

MESSAGE e000(oo) WITH '请至少选择一行'.

ENDIF.

SELECT * INTO CORRESPONDING FIELDS OF TABLE lt_gbtab

FROM bseg

FOR ALL ENTRIES IN lt_key

WHERE bukrs = lt_key-bukrs AND

belnr = lt_key-belnr AND

gjahr = lt_key-gjahr AND

buzei = lt_key-buzei.

LOOP AT lt_gbtab.

SELECT SINGLE * INTO CORRESPONDING FIELDS OF lt_gbtab

FROM bkpf

WHERE bukrs = lt_gbtab-bukrs AND

belnr = lt_gbtab-belnr AND

gjahr = lt_gbtab-gjahr.

MODIFY lt_gbtab.

ENDLOOP.

CALL FUNCTION 'ZBTE_PUSH_BSEG_TO_GB' IN BACKGROUND TASK

EXPORTING

updkz = 'U'

commit = 'X'

TABLES

gbtab = lt_gbtab.

COMMIT WORK.

MESSAGE s000(oo) WITH '已在后台重新发送,请稍后刷新查看最新状态'.

ENDFORM. "resend

如果是讲究一点的开发人员,还会再做一个初始化的程序,用来推送历史凭证,以及一个检查程序,用来检查外部Oracle数据库的凭证是不是缺少。

注:在外部Oracle数据库取数的时候,可以不使用NativeSQL,如下:

总结:这个凭证推送的方法代表了一大类SAP数据推送的解决方案,方案简短来说就是在保存的出口/BADI里面调用一个Update Module,然后Update Module里面调用tRFC(最好是bgRFC),然后保存日志。调用外部的方式可以是RFC、Webservice、DB、FTP等等。

返回FICO参考资料列表