VA03 と値が合わない(数時間溶かしたやつ)
とあるアドオンプログラムで本番障害が・・・。納入済数量が標準伝票で表示される数量と異なるとのこと。
当該のプログラムでは以下から納入済数量をとっていました。前後のロジックにも問題なさそう。
VBEP-DLVQTY_SU/VBEP-DLVQTY_BU
ところが、VA03 の納入済数量と突き合わせると、合いません。ほとんどの伝票はテーブル値と一致するのに、ときどき一致しない伝票がある。これはハマるやつです。
結論だけ先に言いますと、VA03 は VBEP をメインに、納入日程行を画面表示する直前に再計算しています。DB の値そのままを出しているのではありません。なので VBEP-DLVQTY_SU が VA03 と一致しないことがあります。
ちなみにAIに聞いても、ズバッと答えは返ってこず・・・。 RV_SCHEDULE_CHECK_DELIVERIESが代替になるという回答もありましたが、S/4HANAでは使えませんでした(たぶんECC用です)
VA03 の中で何が起きているか
VA03 を起動して XVBEP-VSMNG の変更箇所を追っていくと、まずここで DB の VBEP-DLVQTY_SU から VSMNG を組み立てています。
Program : SAPFV45E
Include : FV45EFEP_XVBEP_AUFBAUEN
FORM : XVBEP_AUFBAUEN
ただこの後ろでさらに VSMNG と DLVQTY_SU が書き換わります。本命はこちらです。
Program : SAPFV45E
Include : FV45EF0V_VBEP_ODQ_DETERMINE
FORM : VBEP_ODQ_DETERMINE
中で呼ばれているのが CL_SDOC_PROCESS_UTIL=>GET_INSTANCE( )->SET_SLINE_DLVQTY。これが再計算している本体です。
DATA(lo_sdoc_process) = cl_sdoc_process_util=>get_instance( ).
lo_sdoc_process->set_sline_dlvqty(
EXPORTING
iv_vbeln = us_xvbap-vbeln
iv_posnr = us_xvbap-posnr
iv_lfgsa = xvbup-lfgsa
iv_kzfme = us_xvbap-kzfme
iv_umvkz = us_xvbap-umvkz
iv_umvkn = us_xvbap-umvkn
iv_fixmg = us_xvbap-fixmg
iv_netwr = us_xvbap-netwr
iv_kwmeng = us_xvbap-kwmeng
iv_kbmeng = us_xvbap-kbmeng
it_xvbfa = xvbfa[]
iv_set_update_indicator = abap_true
IMPORTING
ev_changed = lv_changed
CHANGING
ct_xvbep = lt_xvbep[] ).
戻ってきた値を XVBEP に書き戻しています。
xvbep-vsmng = <ls_xvbep>-vsmng.
xvbep-olfmng = <ls_xvbep>-olfmng.
xvbep-dlvqty_bu = <ls_xvbep>-dlvqty_bu.
xvbep-dlvqty_su = <ls_xvbep>-dlvqty_su.
xvbep-ocdqty_bu = <ls_xvbep>-ocdqty_bu.
xvbep-ocdqty_su = <ls_xvbep>-ocdqty_su.
xvbep-ordqty_bu = <ls_xvbep>-ordqty_bu.
xvbep-ordqty_su = <ls_xvbep>-ordqty_su.
MODIFY xvbep INDEX <ls_xvbep>-tabix.
つまり VA03 と同じ値を取りたければ、自分でも同じ SET_SLINE_DLVQTY を呼ぶしかありません。標準内部ロジックなのでリリース済み API としての保証はないのですが、現状この経路を通さないと VA03 と数量が揃いません。
自前で再計算する
以下に自前計算するために検証したプログラムを記載します。当方の環境ではこれで全伝票VA03と完全一致しました。
*&---------------------------------------------------------------------*
*& Report Z_TEST_SCHEDULELINE
*&---------------------------------------------------------------------*
REPORT Z_TEST_SCHEDULELINE.
DATA:
lt_vbfa TYPE STANDARD TABLE OF vbfavb,
lt_vbep TYPE STANDARD TABLE OF vbepvb,
lt_vbap TYPE STANDARD TABLE OF vbapvb.
DATA:
lt_xvbep TYPE STANDARD TABLE OF vbepvb,
ls_vbap TYPE vbapvb.
DATA:
lv_vbeln TYPE vbeln_va,
lv_posnr TYPE posnr_va,
lv_lfgsa TYPE lfgsa,
lv_changed TYPE abap_bool.
FIELD-SYMBOLS:
<ls_vbep> TYPE vbepvb.
lv_vbeln = '1000008980'. "ここに受注番号
lv_posnr = '000010'. "ここに受注明細番号
" Read document flow for the whole sales order
SELECT *
FROM vbfa
INTO CORRESPONDING FIELDS OF TABLE @lt_vbfa
WHERE vbelv = @lv_vbeln.
" Read schedule lines for the whole sales order
SELECT *
FROM vbep
INTO CORRESPONDING FIELDS OF TABLE @lt_vbep
WHERE vbeln = @lv_vbeln.
" Read sales order items for the whole sales order
SELECT *
FROM vbap
INTO CORRESPONDING FIELDS OF TABLE @lt_vbap
WHERE vbeln = @lv_vbeln.
" Get target item
READ TABLE lt_vbap INTO ls_vbap
WITH KEY vbeln = lv_vbeln
posnr = lv_posnr.
IF sy-subrc <> 0.
WRITE: / 'VBAP item not found.'.
RETURN.
ENDIF.
" In S/4HANA, item status is usually available in VBAP.
" VBUP may be empty for newly created sales documents.
lv_lfgsa = ls_vbap-lfgsa.
" Prepare schedule lines for the target item only
LOOP AT lt_vbep ASSIGNING <ls_vbep>
WHERE vbeln = lv_vbeln
AND posnr = lv_posnr.
APPEND <ls_vbep> TO lt_xvbep.
ENDLOOP.
IF lt_xvbep IS INITIAL.
WRITE: / 'VBEP schedule lines not found.'.
RETURN.
ENDIF.
WRITE: / 'Before SET_SLINE_DLVQTY'.
ULINE.
LOOP AT lt_xvbep INTO DATA(ls_before).
WRITE: / ls_before-vbeln,
ls_before-posnr,
ls_before-etenr,
'WMENG=', ls_before-wmeng,
'BMENG=', ls_before-bmeng,
'VSMNG=', ls_before-vsmng,
'DLVQTY_SU=', ls_before-dlvqty_su,
'DLVQTY_BU=', ls_before-dlvqty_bu,
'OCDQTY_SU=', ls_before-ocdqty_su,
'OCDQTY_BU=', ls_before-ocdqty_bu,
'ORDQTY_SU=', ls_before-ordqty_su,
'ORDQTY_BU=', ls_before-ordqty_bu.
ENDLOOP.
DATA(lo_sdoc_process) = cl_sdoc_process_util=>get_instance( ).
lo_sdoc_process->set_sline_dlvqty(
EXPORTING
iv_vbeln = lv_vbeln
iv_posnr = lv_posnr
iv_lfgsa = lv_lfgsa
iv_kzfme = ls_vbap-kzfme
iv_umvkz = ls_vbap-umvkz
iv_umvkn = ls_vbap-umvkn
iv_fixmg = ls_vbap-fixmg
iv_netwr = ls_vbap-netwr
iv_kwmeng = ls_vbap-kwmeng
iv_kbmeng = ls_vbap-kbmeng
it_xvbfa = lt_vbfa
iv_set_update_indicator = abap_false
IMPORTING
ev_changed = lv_changed
CHANGING
ct_xvbep = lt_xvbep ).
WRITE: /.
WRITE: / 'After SET_SLINE_DLVQTY'.
WRITE: / 'Changed =', lv_changed.
ULINE.
LOOP AT lt_xvbep INTO DATA(ls_after).
WRITE: / ls_after-vbeln,
ls_after-posnr,
ls_after-etenr,
'WMENG=', ls_after-wmeng,
'BMENG=', ls_after-bmeng,
'VSMNG=', ls_after-vsmng,
'DLVQTY_SU=', ls_after-dlvqty_su,
'DLVQTY_BU=', ls_after-dlvqty_bu,
'OCDQTY_SU=', ls_after-ocdqty_su,
'OCDQTY_BU=', ls_after-ocdqty_bu,
'ORDQTY_SU=', ls_after-ordqty_su,
'ORDQTY_BU=', ls_after-ordqty_bu.
ENDLOOP.
明らかに処理パフォーマンスは悪くなるので、例えばこの計算を一部出荷済の受注明細だけで動くようにするなどして、できるだけ計算範囲は減らしたほうがいいかと思います。