受注伝票の納入日程行の納入済数量がテーブル値と合わない件

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

ただこの後ろでさらに VSMNGDLVQTY_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.

明らかに処理パフォーマンスは悪くなるので、例えばこの計算を一部出荷済の受注明細だけで動くようにするなどして、できるだけ計算範囲は減らしたほうがいいかと思います。

コメントする