VOFM、Copy Control与合并开票

问题的提出:
很多企业在晚上运行后台作业来开具到期发票。问题是这些自动运行的到期清单,是以怎样的逻辑被拆分、合并的?本文档将解释标准系统的工作逻辑并提供事例来说明怎样对标准逻辑作自定义增强。
发票(Billing Documents)是用功能函数RV_INVOICE_CREATE来创建的,这个函数将被VF01/SAPMV60A、VF04/SDBILLDL等事务码调用。在此函数运行之前,会有一个内含一条或者多条数据的内表传入。这些数据将以客户、销售组织、开票类型等字段排序,排序的结果是这些数据被分成了几个小组。对每一个小组,系统逻辑试图合并他们从而开除一张发票。在发票创建的过程中,系统将从上述内表中提取出抬头和行项目数据,填充至带开票的内存数据中。
r3中包含了一种用于数据传输控制的可配置的函数逻辑(Routines),叫Data Transfer Routine,它可以更改数据从源凭证到目的凭证的传递方式。本例中将对发票凭证进行讨论。
一旦待开票的数据(内存数据)被填充,系统逻辑将循环对照次行数据与前行数据,如果基本字段一致,两者将被合并。如果不同,新的发票将被创建。发票里有几个特殊的字段,他们不能作为拆分依据。下一节将说明标准合并规则(Standard Combination Criteria),里面列举了这些不能作为拆分依局的字段。
标准合并规则(Standard Combination Criteria)
程序SAPMV60A/MV60ATOP中,有如下定义:
DATA: BEGIN OF AUSNAHME_TAB,
        FELD1(5)  VALUE 'VBELN',
        FELD2(5)  VALUE 'NETWR',
        FELD3(5)  VALUE 'KNUMV',
        FELD4(5)  VALUE 'VBELN',
        FELD5(5)  VALUE 'ERNAM',
        FELD6(5)  VALUE 'ERDAT',
        FELD7(5)  VALUE 'ERZET',
        FELD8(5)  VALUE 'AEDAT',
        FELD9(5)  VALUE 'BELNR',
        FELD10(5) VALUE 'RFBSK',
        FELD12(5) VALUE 'SFAKN',
        FELD13(5) VALUE 'MWSBK',
        FELD14(5) VALUE 'FKTYP',
      END OF AUSNAHME_TAB.
存在于AUSNAHME_TAB结构中的字段将不会作为拆分依据。具体判断逻辑在函数SPLIT_TREE_LIST_DISPLAY、子例程SPLIT_EXAMINE中:
        IF I_HEADER_EXCEPTION_FIELDS NS GT_HEADER_NAMETAB-FIELDNAME.
          GT_HEADER_FIELD_SPLIT-VBELN_F  = LS_VBRK_F-VBELN.
          GT_HEADER_FIELD_SPLIT-VBELN_S  = LS_VBRK_S-VBELN.
          GT_HEADER_FIELD_SPLIT-FIELD    = GT_HEADER_NAMETAB-FIELDTEXT.
          GT_HEADER_FIELD_SPLIT-VALUE_F  = .
          GT_HEADER_FIELD_SPLIT-VALUE_S  = .
          APPEND GT_HEADER_FIELD_SPLIT.
        ENDIF.
数据传输例程(Data Transfer Routine)
正确的控制合并和拆分的方法是采用数据传输例程(Data Transfer Routines)。数据传输例程的主要目的是将前导文件数据传到待创建的后续文件的内存结构中。我们可以在VOFM中找到系统标准的例程。
在VOFM里定义自己的逻辑后,再在发票拷贝关系(TCode:VTFL)中分配给相关的单据。
1 、强制拆分
在发票抬头中有一个用来强制拆分开票的特殊字段:VBRK-ZUKRI。如001例程中,SPART字段和VTWEG字段分别代表产品组合分销渠道。所以,001例程的含义就是,不同的产品组、不同的分销渠道,要出具不同的发票!
FORM DATEN_KOPIEREN_900.
  DATA: BEGIN OF ZUK,
          MODUL(3) VALUE '001',
          VTWEG LIKE VBAK-VTWEG,
          SPART LIKE VBAK-SPART,
          WERKS LIKE LIPS-WERKS,
        END OF ZUK.
  ZUK-SPART = VBAK-SPART.
  ZUK-VTWEG = VBAK-VTWEG.
  ZUK-WERKS = LIPS-WERKS. ‘新增工厂控制
  VBRK-ZUKRI = ZUK.
ENDFORM.
如果新增一行对工厂的限制(ZUK-WERKS = LIPS-WERKS),那么不同的工厂也要开出不同的发票。
2 、阻止拆分
为了阻止拆分,可以将影响拆分的字段设置成相同的内容。例如,两个含有不同装运条件的交货单将被拆分开票,因为装运条件被拷贝到了发票抬头(VBRK)中。如果这个字段被清空了,那么拆分将不再发生。示例例程如下:
FORM DATEN_KOPIEREN_900.
  DATA: BEGIN OF ZUK,
          MODUL(3) VALUE '001',
          VTWEG LIKE VBAK-VTWEG,
          SPART LIKE VBAK-SPART,
        END OF ZUK.
  ZUK-SPART = VBAK-SPART.
  ZUK-VTWEG = VBAK-VTWEG.
  VBRK-ZUKRI = ZUK.
  CLEAR VBRK-VSBED. ‘ 清空装运条件字段
ENDFORM.
新增一行:Clear VBRK-VSBED清空发票抬头(内存临时数据)的装运条件字段。激活后分配给到发票的复制控制,开票时,装运条件不再作为拆分依据了。
3 、用自定义字段合并、拆分
如果客户每天发生多笔业务,那么每天就会有很多发货过账和发票。有些客户希望同一天同一个工厂开具一张发票,另一些客户希望为每一笔到达货物出具发票。
为满足上述需求,我们将创建一个自定义的数据传输例程,此例程基于一个自定义的客户数据字段(例如KNA1-KATR7)来决定交货单是否应该被合并或拆分到发票。为了实现它,订单号码将被添加到VBRK-ZUKRI字段中。
(1)本例中将使用KNA1-KATR7,将其描述更改为“Consolidated Invoice”。
(2)在SM30中,定义KATR7只允许有2个值:“”代表拆分、“X”代表合并。
(3)使KATR7字段在数据传输例程中生效。将KATR7添加到结构KUAGV中的字结构KUAGVZ中,激活。
(4)在数据传输例程中添加如下代码:
FORM DATEN_KOPIEREN_900.
  DATA: BEGIN OF ZUK,
          MODUL(3) VALUE '001',
          VTWEG LIKE VBAK-VTWEG,
          SPART LIKE VBAK-SPART,
          WERKS LIKE LIPS-WERKS,
          VBELN LIKE VBAK-VBELN,
        END OF ZUK.
  ZUK-SPART = VBAK-SPART.
  ZUK-VTWEG = VBAK-VTWEG.
  ZUK-WERKS = LIPS-WERKS. ‘新增工厂控制
  IF VBAK-KATR7 IS INITIAL.
    ZUK-VBELN = VBAK-VBELN.
  ENDIF.
  VBRK-ZUKRI = ZUK.
ENDFORM.
如果在客户数据中维护了客户组7(KNA1-KATR7)为“X”,将集中出具发票。

延伸阅读、相关的OSS ID:
11162 Invoice Split Criteria in Billing Documents
36832 Invoice Split Fields from the Sales Order
308733 Billing Split Due to the Person Number
Symptom
The Chinese tax regulations require that any invoice issued by the Chinese companies complies with the following rules:
  • The invoice can not have more than N line items. The invoice has to be printed on a pre-printed paper and the area for describing the invoiced line items is limited by the paper template used for that. The limit for the number of line items in an invoice is varying for different provinces.
  • The invoice amount should not exceed a certain max. amount. This amount is different for different provinces too, but depends also on the type of the issuing company, as well as on the type of the issued document. Further information about the applicable limits for each case you can obtain at the local tax bureau.
Solution
DATA: BEGIN OF ZUK906,
          MODUL(3) VALUE '906',
          VTWEG  LIKE VBAK-VTWEG,
          SPART  LIKE VBAK-SPART,
          VGBEL  LIKE VBRP-VGBEL,
          BILLNO LIKE TVKO-MAXBI,
        END OF ZUK906.
  DATA: BEGIN OF SIZE_SPLIT OCCURS 0,
          KUNRG         LIKE VBRK-KUNRG,
          KUNAG         LIKE VBRK-KUNAG,
          ZTERM         LIKE VBRK-ZTERM.
          INCLUDE STRUCTURE ZUK906.
  DATA:   ITEMNO        LIKE TVKO-MAXBI,
          AMOUNT_LEFT   LIKE VBRK-NETWR.
  DATA: END OF SIZE_SPLIT.
  DATA: LAST_BILL_NO LIKE TVKO-MAXBI VALUE 0.
  FORM DATEN_KOPIEREN_906.
  DATA: MATCH_INDEX LIKE SY-TABIX value 0,
        lv_Split_Amount like vbrk-netwr value 0.
* Determine split amount - any specific determination should be
* entered here! Assign value 0 in case no split is necessary.
* IMPORTANT: Split amount value should be the net amount of the billing
* document!!! Please reserve the necessary amount for taxes!!! Example:
*   if VBRK-WAERK = 'CNY'.
*     case VBRK-BUKRS.
*       when 'CN10'. LV_SPLIT_AMOUNT = 10000000000.
*       when 'CN11'. LV_SPLIT_AMOUNT = 50000000.
*       when others. LV_SPLIT_AMOUNT = 0.
*     endcase.
*   else.
*     LV_SPLIT_AMOUNT = 0.
*   endif.
    LV_SPLIT_AMOUNT = 200000000.
* Check if appropriate split part already exists
    LOOP AT SIZE_SPLIT WHERE
         KUNRG = VBRK-KUNRG AND
         KUNAG = VBRK-KUNAG AND
         ZTERM = VBRK-ZTERM AND
         VGBEL = VBRP-VGBEL.
* Check for additional split criteria:
* max amount and max.no. of items in billing document
      IF ( lv_Split_Amount is initial or    "No split due to max.amount
           size_split-Amount_Left >= VBRP-NETWR ) "or limit not reached
         AND
         ( TVKO-MAXBI IS INITIAL OR         "No split due to max.numbe
            SIZE_SPLIT-ITEMNO < TVKO-MAXBI ). "or limit not reached
         MATCH_INDEX = SY-TABIX. EXIT.
      ENDIF.
    ENDLOOP.
* Appropriate entry not found - load values for a new SIZE_SPLIT recor
    IF MATCH_INDEX = 0.
      IF LV_SPLIT_AMOUNT > 0 and VBRP-NETWR > LV_SPLIT_AMOUNT.
         mes Sage E220(F5A).
      ENDIF.
      CLEAR SIZE_SPLIT.
      MOVE-CORRESPONDING VBRK TO SIZE_SPLIT.
      MOVE-CORRESPONDING VBRP TO SIZE_SPLIT.
      ADD 1 TO LAST_BILL_NO.
      SIZE_SPLIT-BILLNO      = LAST_BILL_NO.
      SIZE_SPLIT-AMOUNT_LEFT = LV_SPLIT_AMOUNT.
    ENDIF.
    IF NOT TVKO-MAXBI IS INITIAL.
      ADD 1 TO SIZE_SPLIT-ITEMNO.
    ENDIF.
    IF NOT lv_Split_Amount IS INITIAL.
      SUBTRACT VBRP-NETWR FROM SIZE_SPLIT-AMOUNT_LEFT.
    ENDIF.
*   Store actual billing document counter and item counter
    IF MATCH_INDEX = 0.
      APPEND SIZE_SPLIT.
    ELSE.
      MODIFY SIZE_SPLIT INDEX MATCH_INDEX.
    ENDIF.
    ZUK906-BILLNO = SIZE_SPLIT-BILLNO.
* End of billing document split by number of allowed items
    ZUK906-VTWEG = VBAK-VTWEG.
    ZUK906-SPART = VBRP-SPART.
    IF KURGV-PERFK = SPACE.
      ZUK906-VGBEL = VBRP-VGBEL.
    ENDIF.
    VBRK-ZUKRI = ZUK906.
ENDFORM.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值