一般销售业务中存在多次交货及多次开票的可能.这种情况在SAP中标准功能是实现不了的,所以需要进行增强。POD的抬头状态栏有三个:总体状态,POD状态,开票状态,用来确定交货单目前所处的状态。POD确认之后必须完成销售开票才能再次POD,所以允许再次POD确认的逻辑写在了开票的增强里。
1.先对POD进行增强
1.1创建自建表用于保存TVPOD的数据
POD确认的数据会保存在TVPOD表里,同时做POD确认以及销售开票的时候会同步修改LIKP、LIPS两张表。需要再次POD确认需要清除标准表TVPOD的数据,所以将需要使用的数据保存到自建表中,用于后续开票以及POD确认操作使用。
1.2POD确认增强逻辑
因为修改的是标准表的数据,所以要在数据保存到标准表之后才可以进行操作。添加判断如果交货数量和POD数量不一致的时候,并且POD确定总数量小于交货单数量,将TVPOD的数据保存到自建表ZTVPOD以统计累计确定数量并清除标准表tvpod的数据.在自建表ZTVPOD根据交货单取数判断当前是否为第一次POD,不是第一次则需要修改POD状态使得允许再次开票.
1.3代码示例
等待0.5S,防止数据还没保存到标准表,也可以通过SELECT去判断。
增强程序:FV50XF0B_BELEG_SICHERN
增强点: fv50xf0b_beleg_sichern_06
WAIT UP TO '0.5' SECONDS.
IF sy-tcode = 'VLPOD'.
DATA:gt_tvpod LIKE TABLE OF tvpod WITH HEADER LINE.
DATA:l_count TYPE lfimg.
DATA:gt_ztvpod LIKE TABLE OF ztvpod WITH HEADER LINE.
DATA:gt_ztvpod1 LIKE TABLE OF ztvpod WITH HEADER LINE.
DATA:gt_lips LIKE TABLE OF lips WITH HEADER LINE.
DATA:gt_likp LIKE TABLE OF likp WITH HEADER LINE.
DATA:i_code.
DATA:i_code2.
LOOP AT xlips.
REFRESH gt_tvpod.
REFRESH gt_ztvpod.
REFRESH gt_ztvpod1.
REFRESH gt_likp.
REFRESH gt_lips.
CLEAR:i_code , l_count.
SELECT * INTO TABLE gt_tvpod FROM tvpod WHERE vbeln = xlips-vbeln AND posnr = xlips-posnr.
MOVE-CORRESPONDING gt_tvpod[] TO gt_ztvpod[].
LOOP AT gt_ztvpod.
IF xlips-lfimg > gt_ztvpod-podmg.
i_code = 'X'.
gt_ztvpod-datum = sy-datum.
gt_ztvpod-uzeit = sy-uzeit.
gt_ztvpod-uname = sy-uname.
DATA:g_message_id TYPE guid_32. "定义消息id
CALL FUNCTION 'GUID_CREATE' "调用方法创建信息id
IMPORTING
ev_guid_32 = g_message_id. "需要保存的信息id
gt_ztvpod-guid = g_message_id.
MODIFY gt_ztvpod.
ENDIF.
ENDLOOP.
DELETE gt_ztvpod WHERE podmg = 0.
SELECT COUNT(*) FROM ztvpod WHERE vbeln = xlips-vbeln.
IF SY-subrc NE 0.
CLEAR i_code.
ENDIF.
MODIFY ztvpod FROM TABLE gt_ztvpod.
IF i_code = 'X'.
IF i_code = 'X'.
SELECT * INTO TABLE gt_lips FROM lips WHERE vbeln = xlips-vbeln AND posnr = xlips-posnr.
SELECT SINGLE * INTO gt_likp FROM likp WHERE vbeln = xlips-vbeln.
LOOP AT gt_lips.
IF gt_likp-fkstk = 'C' AND gt_lips-fksta = 'C'.
i_code2 = 'A'.
gt_lips-fksta = 'B'. "交货相关开票状态
gt_lips-gbsta = 'B'. "总体状态
* gt_lips-pdsta = 'B'. "交付证明状态
gt_lips-fkivp = 'B'. "公司间开票状态
MODIFY lips FROM gt_lips.
ENDIF.
IF gt_likp-fkstk <> 'C' AND gt_lips-fksta <> 'C'.
IF gt_likp-fkstk <> '' AND gt_lips-fksta <> ''.
i_code2 = 'B'.
gt_lips-fksta = 'B'. "交货相关开票状态
gt_lips-gbsta = 'B'. "总体状态
* gt_lips-PDSTA = 'B'. "交付证明状态
gt_lips-fkivp = 'B'. "公司间开票状态
MODIFY lips FROM gt_lips.
ENDIF.
ENDIF.
ENDLOOP.
CASE i_code2.
WHEN 'A'.
gt_likp-fkstk = 'B'. "交货相关开票状态
gt_likp-gbstk = 'B'. "总体状态
* gt_likp-pdstk = 'B'. "交付证明状态
gt_likp-fkivk = 'B'. "公司间开票状态
MODIFY likp FROM gt_likp.
WHEN 'B'.
gt_likp-fkstk = 'B'. "交货相关的开票状态
gt_likp-gbstk = 'B'. "总体状态
* gt_likp-PDSTK = 'B'. "交货证明状态
gt_likp-fkivk = 'B'. "公司间开票状态
MODIFY likp FROM gt_likp.
WHEN OTHERS.
ENDCASE.
ENDIF.
ENDIF.
ENDLOOP.
ENDIF.
2.销售开票的增强
2.1开票增强逻辑
修改标准表需要在数据保存完之后再做修改,运行标准程序发现在调用完函数’RV_INVOICE_REFRESH’之后数据会保存到标准表,而这个函数会清空内存里的数据,所以要在调用函数之前保存需要使用的数据在函数之后进行操作。这个函数本身就在一个增强点里,所以直接创建这个增强实现,增强点自带调用函数模块’RV_INVOICE_REFRESH’的代码。所以在调用前保存XVBRK、XVBRP的数据作为后续使用。在自建表ZTVPOD获取累计POD确定数量用来判断是否允许下一次POD。如果自建表获取的累计POD数量小于交货单交货数量则修改POD状态以允许下次POD操作。
2.2代码示例
函数模块:RV_INVOICE_DOCUMENT_ADD
增强点: ES_SAPLV60A / rv_invoice_document_add_02
DATA(lt_vbrk) = xvbrk[].
DATA(lt_vbrp) = xvbrp[].
DATA l_xvbrp TYPE vbrpvb.
DATA:l_count TYPE lfimg.
DATA:l_lfimg TYPE lfimg.
DATA lv_used TYPE char1.
CALL FUNCTION 'RV_INVOICE_REFRESH'
EXPORTING
with_posting = kom-posting
TABLES
xkomfk = xkomfk
xkomv = xkomv
xthead = xthead
xvbfs = xvbfs
xvbss = xvbss
xvbpa = xvbpa
xvbrk = xvbrk
xvbrp = xvbrp.
IF sy-tcode = 'VF01'.
WAIT UP TO '0.5' SECONDS.
LOOP AT lt_vbrk INTO DATA(ls_vbrk).
IF ls_vbrk-fkart EQ 'ZF01' OR ls_vbrk-fkart EQ 'ZF02' OR ls_vbrk-fkart EQ 'ZF03' OR ls_vbrk-fkart EQ 'ZF04' OR ls_vbrk-fkart EQ 'ZF10' OR ls_vbrk-fkart EQ 'ZIV'.
LOOP AT lt_vbrp INTO l_xvbrp.
SELECT SINGLE * FROM likp INTO @DATA(ls_likp) WHERE vbeln = @l_xvbrp-vgbel.
SELECT * FROM ztvpod INTO TABLE @DATA(lt_pod) WHERE vbeln = @l_xvbrp-vgbel AND posnr = @l_xvbrp-vgpos.
IF lt_pod[] IS NOT INITIAL.
LOOP AT lt_pod INTO DATA(ls_pod).
l_count = l_count + ls_pod-podmg.
l_lfimg = ls_pod-lfimg.
ENDLOOP.
ENDIF.
SELECT SINGLE * FROM lips INTO @DATA(ls_lips) WHERE vbeln = @l_xvbrp-vgbel AND posnr = @l_xvbrp-vgpos.
IF l_count <> l_lfimg.
IF ls_likp-fkivk = '' AND ls_lips-fkivp = ''.
I_CODE = 'A'.
ls_lips-fksta = 'B'. "交货相关开票状态
ls_lips-gbsta = 'B'. "总体状态
ls_lips-pdsta = 'B'. "交付证明状态
MODIFY lips FROM ls_lips.
SELECT * FROM tvpod INTO TABLE @DATA(lt_tvpod) WHERE vbeln = @ls_lips-vbeln.
IF lt_tvpod[] IS NOT INITIAL.
DELETE tvpod FROM TABLE lt_tvpod.
ENDIF.
ENDIF.
IF ls_likp-fkivk = 'C' AND ls_lips-fkivp = 'C' .
IF ls_vbrk-fkart NE 'ZIV'.
I_CODE = 'B'.
* ls_lips-fksta = 'B'. "交货相关开票状态
ls_lips-gbsta = 'B'. "总体状态
* ls_lips-pdsta = 'B'. "交付证明状态
ls_lips-fkivp = 'B'. "公司间开票状态
MODIFY lips FROM ls_lips.
ELSE.
I_CODE = 'C'.
ls_lips-fksta = 'B'. "交货相关开票状态
ls_lips-gbsta = 'B'. "总体状态
ls_lips-pdsta = 'B'. "交付证明状态
ls_lips-fkivp = 'B'. "公司间开票状态
MODIFY lips FROM ls_lips.
SELECT * FROM tvpod INTO TABLE @lt_tvpod WHERE vbeln = @ls_lips-vbeln.
IF lt_tvpod[] IS NOT INITIAL.
DELETE tvpod FROM TABLE lt_tvpod.
ENDIF.
ENDIF.
ENDIF.
ELSE.
IF ls_vbrk-fkart NE 'ZIV' AND ls_likp-fkivk <> '' AND ls_lips-fkivp <> ''.
I_CODE = 'D'.
* ls_lips-fksta = 'B'. "交货相关开票状态
ls_lips-gbsta = 'B'. "总体状态
* ls_lips-pdsta = 'B'. "交付证明状态
ls_lips-fkivp = 'B'. "公司间开票状态
MODIFY lips FROM ls_lips.
ENDIF.
ENDIF.
ENDLOOP.
CASE I_CODE.
WHEN 'A'.
ls_likp-fkstk = 'B'."交货相关的开票状态
ls_likp-gbstk = 'B'."总体状态
ls_likp-pdstk = 'B'."交货证明状态
WHEN 'B'.
* ls_likp-fkstk = 'B'."交货相关的开票状态
ls_likp-gbstk = 'B'."总体状态
* ls_likp-pdstk = 'B'."交货证明状态
ls_likp-fkivk = 'B'."公司间开票状态
MODIFY likp FROM ls_likp.
WHEN 'C'.
ls_likp-fkstk = 'B'."交货相关的开票状态
ls_likp-gbstk = 'B'."总体状态
ls_likp-pdstk = 'B'."交货证明状态
ls_likp-fkivk = 'B'."公司间开票状态
WHEN 'D'.
* ls_likp-fkstk = 'B'."交货相关的开票状态
ls_likp-gbstk = 'B'."总体状态
* ls_likp-pdstk = 'B'."交货证明状态
ls_likp-fkivk = 'B'."公司间开票状态
ENDCASE.
IF I_CODE <> ''.
MODIFY likp FROM ls_likp.
CLEAR:I_CODE.
ENDIF.
ENDIF.
ENDLOOP.
ENDIF.
REFRESH: lt_vbrk[],lt_vbrp[].
FREE:ls_vbrk,ls_vbrp.