一、业务背景
在实际业务上,同一笔销售订单可能分多次发货,多次开票,因此再销售订单状态报表上就要体现该过程:对于同一张销售订单,分多次开票时,按照发票和订单行项目,显示开票数量与为开票数量
即实现:
二、开发逻辑
1、基于交货单开票与销售订单订单开票
在实际业务中,ZQC\ZFW\ZJR\ZDR四种单据类型是基于销售订单开票,而ZOR\ZPT等设备、配件是基于交货单开票,因此在取数时需要区分订单类型取数。
2、涉及的主要数据库表
vbak:销售凭证的抬头数据;vbkd:销售凭证的业务数据;vbap:销售凭证的项目数据
likp:销售凭证,交货抬头数据,取交货数据;lips:销售凭证,交货项目数据
vbrk:出具发票抬头数据,根据销售订单或者交货单取开票数据;vbrp:出具发票项数据
3、取开票数量和未开票数量的思路
首先在VBAK、VBAP中分别取出基于销售订单开票、基于交货单开票的销售数据
销售订单开票:vbak~auart IN ('ZQC', 'ZCR', 'ZDR', 'ZFW')
取数方法:现将所有数据都取出SELECT.......
最后循环,使用READ TABLE 读入
LOOP AT gt_alv1 ASSIGNING FIELD-SYMBOL (<fs_alv1>),
READ TABLE lt_dtvakt INTO DATA(ls_dtvakt) WITH KEY auart = <fs_alv1>-auart BINARY SEARCH.
IF sy-subrc EQ 0.
<fs_alv1>-bezei = ls_dtvakt-bezei.
ENDIF.
注意:基于销售订单开票的订单类型是没有交货单,因此对于vbrp和vbrk的取数要分情况讨论
3.1基于交货单开票的销售数据
内表Lt_dvbrk中存储着开票信息
可以看到,VBAP中只存储这销售订单上的两条行项目的数据,而VBRP、LIPS中存储有三条开票的数据,因此要想将三条开票数据均体现在报表上,对于有交货单的销售数据,需要循环lt_dlips表,而对于销售订单开票的数据,就需要对lt_dvbrp表进行循环,这样就能取出三条开票数据。
IF lt_dlips[] IS NOT INITIAL . -----取基于交货单开票的开票数据
SELECT vbrp~vbeln,
vbrp~posnr,
vbrp~fkimg。。。。。。
INTO TABLE @DATA(lt_dvbrk)
FROM vbrk
INNER JOIN vbrp
ON vbrk~vbeln = vbrp~vbeln
FOR ALL ENTRIES IN @lt_dlips
*交货数据
LOOP AT gt_alv1 ASSIGNING FIELD-SYMBOL(<fs_alv1>) .
LOOP AT lt_dlips INTO DATA(ls_dlips) WHERE vgbel = <fs_alv1>-vbeln AND vgpos = <fs_alv1>-posnr.
<fs_alv1>-jvbeln = ls_dlips-vbeln. "交货单
<fs_alv1>-vstel = ls_dlips-vstel. "装运点
<fs_alv1>-lfart = ls_dlips-lfart. "交货单类型
。。。。
gs_alv = <fs_alv1>."EDIT by DXY 2023.09.25
APPEND gs_alv TO gt_out.
CLEAR:gs_alv.
ENDLOOP.
ENDLOOP.
*开票数据
LOOP AT gt_out ASSIGNING FIELD-SYMBOL(<fs_out>).
LOOP AT lt_dvbrk ASSIGNING FIELD-SYMBOL(<fs_dvbrk01>) WHERE vgbel = <fs_out>-jvbeln
AND vgpos = <fs_out>-jposnr
<fs_out>-lfimg2 = <fs_out>-fkimg. "交货已开票数量
<fs_out>-lfimg3 = <fs_out>-lfimg - <fs_out>-lfimg2. "交货未开票数量
ENDLOOP.
IF <fs_out>-fkimg IS INITIAL. "开票数量为0,取订单数量
<fs_out>-lfimg3 = abs( <fs_out>-kwmeng ). "交货未开票数量
ENDIF.
gs_alv = <fs_out>.
ENDLOOP.
为什么在开票数据和未开票数据这里要循环两次:
首先:在报表上体现开票数和未开始票数的最终数值,那么仅仅从数据库表中取数,是不能满足的,数据库中存储的是某一次开票的静态的值,比如下列的行项目2,它实际的开票数量分别为2,2,最终的未开票数量为0,那么多次循环就能满足最后在报表中体现的是最终的数值
3.2基于销售订单开票的销售数据
IF lt_vbak[] IS NOT INITIAL. -----取基于销售单开票的销售数据
SELECT vbrp~vbeln,
vbrp~posnr,
vbrp~fkimg,
INTO TABLE @DATA(lt_dvbrk01)
FROM vbrk
INNER JOIN vbrp
ON vbrk~vbeln = vbrp~vbeln
FOR ALL ENTRIES IN @lt_vbak
*取开票数据
LOOP AT gt_alv1 ASSIGNING FIELD-SYMBOL(<fs_alv1>) .
IF <fs_alv1>-auart = 'ZCR' OR <fs_alv1>-auart = 'ZDR' OR <fs_alv1>-auart = 'ZFW' OR <fs_alv1>-auart = 'ZQC'.
LOOP AT lt_dvbrk01 INTO DATA(ls_dvbrk01) WHERE vgbel = <fs_alv1>-vbeln AND posnr = <fs_alv1>-posnr .
gs_alv = <fs_alv1>."EDIT by DXY 2023.09.25
APPEND gs_alv TO gt_out.
CLEAR:gs_alv.
ENDLOOP.
ELSE.
ENDLOOP.
*开票数据
LOOP AT gt_out ASSIGNING FIELD-SYMBOL(<fs_out>).
IF <fs_out>-auart = 'ZQC' OR <fs_out>-auart = 'ZCR' OR <fs_out>-auart = 'ZDR' OR <fs_out>-auart = 'ZFW' .
*add start of增加判断条件无交货单,销售订单开票取值*********——W34074_20240108
LOOP AT lt_dvbrk ASSIGNING FIELD-SYMBOL(<fs_dvbrk>) WHERE vgbel = <fs_out>-vbeln
AND vgpos = <fs_out>-posnr
<fs_out>-lfimg2 = <fs_out>-lfimg2 + <fs_out>-fkimg. "销售单已开票数量
<fs_out>-lfimg3 = <fs_out>-kwmeng - <fs_out>-lfimg2. "销售单未开票数量
ENDLOOP.
3.2开票凭证
因为有些类型的销售订单是基于交货单开票,那么在取开票凭证时,可以依据交货单进行匹配取出
但对于另一部分基于销售单据开票,由于销售订单号和行项目号相同的同一物料,分两次开票时,会有两个不同的开票凭证,因此在匹配时,就无法按照某一独特的字段来进行匹配
故采取以下方式:
基于交货单开票
SELECT vbrk~vbeln,
vbrk~belnr,
vgbel,
vgpos
FROM vbrk
INNER JOIN vbrp ON vbrk~vbeln = vbrp~vbeln
FOR ALL ENTRIES IN @gt_out1
WHERE vgbel = @gt_out1-fvbeln
AND vgpos = @gt_out1-fposnr
AND vbrk~fkart = 'ZF2'
AND vbrk~fksto NE 'X'
INTO TABLE @DATA(lt_vbrkt01)
.
LOOP AT gt_out1 INTO gs_alv.
READ TABLE lt_vbrkt01 ASSIGNING FIELD-SYMBOL(<fs_vbrkt>) WITH KEY vgbel = gs_alv-jvbeln vgpos = gs_alv-jposnr.
IF sy-subrc = 0.
gs_alv-fvbeln = <fs_vbrkt>-vbeln. "销售发票号
gs_alv-belnr = <fs_vbrkt>-belnr. "会计凭证编号
ENDIF.
"----ADD BY W34074 AT 06.09.2024 14:08:21
gs_alv-kzwi1 = gs_alv-lfimg * gs_alv-hsdj. "含税金额=交货数量*含税金额
"----ADD BY W34074 AT 06.09.2024 14:08:25
MODIFY gt_out1 FROM gs_alv.
ENDLOOP.
基于销售订单开票--采取排序后删除的方式匹配
IF <fs_out>-auart = 'ZQC' OR <fs_out>-auart = 'ZCR' OR <fs_out>-auart = 'ZDR' OR <fs_out>-auart = 'ZFW' .
SELECT vbrk~vbeln,
vbrk~belnr,
posnr,
vgbel,
vgpos
FROM vbrk
INNER JOIN vbrp ON vbrk~vbeln = vbrp~vbeln
FOR ALL ENTRIES IN @gt_out1
WHERE vgbel = @gt_out1-vbeln
AND vgpos = @gt_out1-posnr
AND vbrk~fkart IN ( 'ZL2','ZG2' )
AND vbrk~fksto NE 'X'
INTO TABLE @DATA(lt_vbrkt) .
SORT lt_vbrkt BY vbeln posnr.
LOOP AT gt_out1 INTO gs_alv.
READ TABLE lt_vbrkt ASSIGNING FIELD-SYMBOL(<fs_vbrkt01>) WITH KEY vgbel = gs_alv-vbeln vgpos = gs_alv-posnr.
IF sy-subrc = 0.
gs_alv-fvbeln = <fs_vbrkt01>-vbeln. "销售发票号
gs_alv-belnr = <fs_vbrkt01>-belnr. "会计凭证编号
ENDIF.
gs_alv-kzwi1 = gs_alv-lfimg * gs_alv-hsdj. "含税金额=交货数量*含税金额
MODIFY gt_out1 FROM gs_alv.
DELETE lt_vbrkt INDEX sy-tabix. " sy-tabix是当前循环的索引
ENDLOOP.