ABAP 订单多次开票,显示多张开票凭证

一、业务背景

在实际业务上,同一笔销售订单可能分多次发货,多次开票,因此再销售订单状态报表上就要体现该过程:对于同一张销售订单,分多次开票时,按照发票和订单行项目,显示开票数量与为开票数量

即实现:

二、开发逻辑

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值