配置订单BOM因为要考虑历史ECN、特征语法、BOM语法,是最复杂的一个算法结果,为了摆脱这种被动的场景,博主开发了一个被动核对数据的程序来保障数据质量。
今天是APS系统上线的第三天,我们的核对程序在昨天上线,面对大量用户的基础数据查询,SAP和APS在核对无误的情况下,可以可靠的输出基础数据,两个系统用完全一致的数据相互验证了BOM的准确率。 博主也给自己找到一个工作岗位,每天跑一下一个自动核对程序,程序可以核对SAP和APS两个系统的订单BOM,当两个系统的数据完全一致,就表示我们的数据是正确的。
又过了2天,设变来了,我才发现SAP的销售订单BOM不会随设变更新,没有PP中的重读BOM功能,所以,在SAP中拿到订单BOM解析,只能走CU50一条路。SAP社区中有很多关于CU50的问答。终于,我完成了一个半自动的订单BOM核对程序,它工作后的输出很简洁:
20231006:B27F,CC12,PA74,P009-XX
APS:2897
SAP:2897
every item same
*&---------------------------------------------------------------------*
*& Report ZPPR0016B
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZPPR0016B.
TABLES:vbap,stko.
TYPES:BEGIN OF ty_vbap,
vbeln TYPE vbap-vbeln,
posnr TYPE vbap-posnr,
cuobj TYPE vbap-cuobj,
matnr TYPE vbap-matnr,
werks TYPE vbap-werks,
END OF ty_vbap.
DATA gs_vbap TYPE ty_vbap.
DATA gt_conf_out TYPE TABLE OF conf_out.
DATA gt_stpo TYPE TABLE OF stpox.
DATA:gs_layout TYPE lvc_s_layo, "#EC NEEDED
gs_glay TYPE lvc_s_glay, "#EC NEEDED
gt_fieldcat TYPE lvc_t_fcat. "#EC NEEDED
SELECTION-SCREEN BEGIN OF BLOCK a0 WITH FRAME TITLE TEXT-001.
PARAMETERS:s_vbeln TYPE vbap-vbeln . "销售凭证
PARAMETERS:s_posnr TYPE vbap-posnr . "项目
PARAMETERS:s_datuv TYPE stko-datuv DEFAULT sy-datum. "有效起始日期
SELECTION-SCREEN END OF BLOCK a0.
START-OF-SELECTION.
PERFORM frm_get_data.
FORM frm_get_data .
SELECT SINGLE vbeln,
posnr,
cuobj,
matnr,
werks
FROM vbap
WHERE vbeln = @s_vbeln
AND posnr = @s_posnr
INTO @gs_vbap.
IF gs_vbap IS INITIAL.
MESSAGE 'no data' TYPE 'E' DISPLAY LIKE 'S'.
ENDIF.
"--------取SAP系统销售订单的BOM--------------------------------
IF gs_vbap-cuobj IS INITIAL.
MESSAGE 'no data' TYPE 'E' DISPLAY LIKE 'S'.
ENDIF.
IF s_datuv = ''.
MESSAGE 'Please enter the expiration date' TYPE 'E' DISPLAY LIKE 'S'.
ELSE.
SELECT * FROM mast
WHERE matnr = @gs_vbap-matnr
AND werks = @gs_vbap-werks
INTO TABLE @DATA(lt_mast).
IF sy-subrc <> 0.
MESSAGE 'Please enter expiry date non-expandable BOM material number' TYPE 'E' DISPLAY LIKE 'S'.
ENDIF.
CALL FUNCTION 'CS_BOM_EXPL_KND_V1'
EXPORTING
vbeln = gs_vbap-vbeln
vbpos = gs_vbap-posnr
capid = 'PP01'
cuobj = gs_vbap-cuobj
datuv = s_datuv "界面输入,默认当天
mktls = 'X'
mehrs = '' "勾选则为X,不勾选则为空
mtnrv = gs_vbap-matnr "(物料)
werks = gs_vbap-werks "(工厂)
TABLES
stb = gt_stpo.
ENDIF.
"--------取销售订单的四大配置和APS的订单BOM-------------
IF gs_vbap-cuobj IS INITIAL.
MESSAGE 'no data' TYPE 'E' DISPLAY LIKE 'S'.
ELSE.
CALL FUNCTION 'VC_I_GET_CONFIGURATION'
EXPORTING
instance = gs_vbap-cuobj
TABLES
configuration = gt_conf_out.
ENDIF.
" F2_CC00 = CC12
" F2_PA00 = PA63
" F2_PM = B27FRF8JA4L01
" F2_PKG0 = P002-F2
" F2_PKG0 = P003-F2
DATA ls_write TYPE zspp_bominfo.
DATA ls_head TYPE zspp_bominfo.
DATA lt_head TYPE TABLE OF zspp_bominfo.
DATA lv_rfcdest TYPE rfcdest.
DATA lt_esb_com TYPE zsca_esb_com_tab.
DATA lt_bomlist TYPE TABLE OF zspp_bomlist.
LOOP AT gt_conf_out INTO DATA(gs_conf).
IF gs_conf-ATNAM = 'F2_PM'. ls_head-ATWRT1 = gs_conf-ATWRT. ENDIF.
IF gs_conf-ATNAM = 'F2_CC00'. ls_head-ATWRT2 = gs_conf-ATWRT. ENDIF.
IF gs_conf-ATNAM = 'F2_PA00'. ls_head-ATWRT3 = gs_conf-ATWRT. ENDIF.
IF gs_conf-ATNAM = 'F2_PKG0'.
IF ls_head-ATWRT4 is INITIAL.
ls_head-ATWRT4 = gs_conf-ATWRT.
ELSE.
ls_head-ATWRT4 = ls_head-ATWRT4 && ';' && gs_conf-ATWRT.
ENDIF.
ENDIF.
ENDLOOP.
ls_head-werks = '1003'.
ls_head-matnr = 'F2'.
ls_head-badat = s_datuv.
IF gs_vbap-MATNR EQ 'F2'. ls_head-z_st = 'V'. ENDIF.
IF gs_vbap-MATNR EQ 'F2PD'. ls_head-z_st = 'P'. ENDIF.
IF gs_vbap-MATNR EQ 'F2BD'. ls_head-z_st = 'A'. ENDIF.
APPEND ls_head TO lt_head .
ls_write = ls_head.
CLEAR ls_head.
lv_rfcdest = zcl_ca_tools=>get_rfcdest( ).
CALL FUNCTION 'ZSAP_PP_APS_BOMINFO_OUT' DESTINATION lv_rfcdest
TABLES
et_po_header = lt_head
tt_esb_com = lt_esb_com
tt_bomlist = lt_bomlist.
"-----去掉一个物料---------------
LOOP AT gt_stpo INTO DATA(gs_stpo).
IF gs_stpo-OJTXP = 'F2BD'. DELETE gt_stpo. ENDIF.
IF gs_stpo-OJTXP = 'F2PD'. DELETE gt_stpo. ENDIF.
ENDLOOP.
"----输出两个表的条数-----------
WRITE:/ gs_vbap-vbeln && ',' && gs_vbap-posnr && ',' && ls_write-atwrt1 && ',' && ls_write-atwrt2 && ',' && ls_write-atwrt3 && ',' && ls_write-atwrt4.
DATA lv_l1 TYPE i VALUE 0.
DATA lv_l2 TYPE i VALUE 0.
lv_l1 = lines( lt_bomlist ).
lv_l2 = lines( gt_stpo ).
WRITE:/ 'APS: ' && lv_l1.
WRITE:/ 'SAP: ' && lv_l2 .
"----两个内表比较-----------IDNRK
"定义结构体
TYPES: BEGIN OF ty_table,
matnr(40) TYPE C,
END OF ty_table.
"定义内表
DATA gt_SAP TYPE TABLE OF ty_table.
DATA gt_APS TYPE TABLE OF ty_table.
DATA gs_gsgs TYPE ty_table.
LOOP AT gt_stpo INTO DATA(gs_1).
gs_gsgs-MATNR = gs_1-IDNRK.
APPEND gs_gsgs to gt_SAP.
CLEAR gs_gsgs.
ENDLOOP.
LOOP AT lt_bomlist INTO DATA(gs_2).
gs_gsgs-MATNR = gs_2-MATNR.
APPEND gs_gsgs to gt_APS.
CLEAR gs_gsgs.
ENDLOOP.
SORT gt_SAP.
SORT gt_APS.
IF gt_SAP[] = gt_APS[].
WRITE:/ 'every item same'.
ELSE.
WRITE:/ 'some item different'.
ENDIF.
CLEAR:gt_SAP[],gt_APS[],lt_bomlist[],gt_stpo[],gs_vbap,gt_conf_out[].
ENDFORM.