IDocフラットファイルのパースと検証
目標
SAP IDocのフラットファイルを、制御レコードとデータレコードに分解し、セグメントのレイアウトどおりにSDATAをパースして検証し、内部標準のJSONに変換できるようになります。
なぜ重要なのか
韓国の大企業のプロジェクトで、ERP連携はほぼ必ず出会います。そして、会議で「IDocで受け取っていただければ大丈夫です」という言葉が出てきた瞬間、構造を知らなければ何も決められません。実際に、IDocのパースは、セグメント名でレイアウトを探して、1000文字のSDATAを位置で切り出す作業で、前のモジュールの固定長のパースと同じ作業です。そして、運用で最もよく見ることになるステータスコード51が、「送信の失敗」ではなく「SAPの中での業務処理の失敗」だと知っているだけでも、連携担当者間の平行線を一度断ち切れます。
ステップ
- 元データ:
/opt/lab/fixtures/eai/idoc/ORDERS05.txtレイアウト:/opt/lab/fixtures/eai/idoc/segments.md /root/idocを作成し、制御レコードだけを/root/idoc/control.txtに、データレコードだけを/root/idoc/data.txtに分離してください。2つのファイルの行数の合計が、元の行数と同じである必要があります。/root/idoc/ctrl.csvを作成してください。1行目はdocnum,idoctyp,mestyp,sndprn,rcvprn,credatです。制御レコード1件につき1行で、docnumの昇順です。/root/idoc/segstat.csvを作成してください。1行目はsegnam,countです。セグメント名ごとの件数を、件数の降順、同数なら名前の昇順で書いてください。E1EDK01セグメントをパースして、/root/idoc/header.csvを作成してください。1行目はdocnum,belnr,curcy,netwrです。netwrはヘッダーの総額です。E1EDP01セグメントをパースして、/root/idoc/items.csvを作成してください。1行目はdocnum,posex,matnr,menge,netpr,amountです。amountはmenge × netprです。/root/idoc/validate.shを作成してください。引数なしで実行し、ヘッダーのnetwrと、明細のamountの合計が異なるIDocのdocnumを、1行に1つずつ出力して、1つでもあれば0以外の終了コードで終了します。実行結果を/root/idoc/mismatch.txtに保存してください。(1件あります。)/root/idoc/status.csvを作成してください。1行目はcode,meaning,actionです。03、12、51、53、64、68の6つのコードをすべて入れ、actionは、정상、대기、조사、재전송(韓国語の値で、順に正常、待機、調査、再送を意味します)のいずれかです。/root/idoc/orders.jsonを作成してください。最上位は配列で、各要素は次の構造です。docnumの昇順です。
(山括弧の中の韓国語はプレースホルダーで、数値を意味します。){ "docnum": "...", "belnr": "...", "currency": "...", "netAmount": <숫자>, "items": [ { "posex": "...", "matnr": "...", "qty": <숫자>, "price": <숫자> }, ... ] }
参考
- 固定長の切り出しは、Pythonのスライシングが楽です:
line[10:30](定義書の位置は1始まりなので、インデックスは-1する必要があります) - jqで構造を確認:
jq '.[0].items | length' orders.json - よくあるミス1: 定義書の1始まりの位置を、0始まりのインデックスにそのまま使うことです。
- よくあるミス2: 数量・金額のフィールドの先頭の0と小数点の扱いを決めないことです。
- よくあるミス3: ステータスコード51を「送信の失敗」と解釈することです。データは届いていて、SAPの中で業務処理が失敗した状態です。
制御レコードとデータレコードの分離
/root/idocを作成し、制御レコードだけを/root/idoc/control.txtに、データレコードだけを/root/idoc/data.txtに分離してください。
2つのファイルの行数の合計が、元の行数と同じである必要があります。
レコードの種類は、各行の先頭部分に区分として示されています。まずファイルの構造を目で確認してから、分離の基準を決めてください。
制御レコードのパース
/root/idoc/ctrl.csvを作成してください。1行目はdocnum,idoctyp,mestyp,sndprn,rcvprn,credatです。
制御レコード1件につき1行で、docnumの昇順です。
制御レコードには、この文書が何で、誰から誰に送られるかが入っています。レイアウト定義書の位置どおりに切り出す必要があります。
セグメントの統計
/root/idoc/segstat.csvを作成してください。1行目はsegnam,countです。
セグメント名ごとの件数を、件数の降順、同数なら名前の昇順で書いてください。
セグメント名ごとに何件かを数えると、文書の構造が見えます。ヘッダー系のセグメントは1件、明細系のセグメントは複数件であれば正常です。
ヘッダーセグメントのパース
E1EDK01セグメントをパースして、/root/idoc/header.csvを作成してください。
1行目はdocnum,belnr,curcy,netwrです。netwrはヘッダーの総額です。
SDATAは固定長の文字列です。セグメントごとにレイアウトが違うので、定義書で該当のセグメントを探す必要があります。
明細セグメントのパース
E1EDP01セグメントをパースして、/root/idoc/items.csvを作成してください。
1行目はdocnum,posex,matnr,menge,netpr,amountです。
amountはmenge × netprです。
明細は複数件あります。各件の数量と単価を取り出して金額を計算しておくと、次のステップで使います。
ヘッダーと明細の金額の検証
/root/idoc/validate.shを作成してください。引数なしで実行し、ヘッダーのnetwrと、明細のamountの合計が異なるIDocのdocnumを、1行に1つずつ出力して、1つでもあれば0以外の終了コードで終了します。
実行結果を/root/idoc/mismatch.txtに保存してください。(1件あります。)
ヘッダーに書かれた総額と明細の合計が違えば、その文書は処理してはいけません。どのIDocが問題かを、番号で知らせてください。
ステータスコードのマッピング表
/root/idoc/status.csvを作成してください。1行目はcode,meaning,actionです。
03、12、51、53、64、68の6つのコードをすべて入れ、actionは、정상、대기、조사、재전송(韓国語の値で、順に正常、待機、調査、再送を意味します)のいずれかです。
「送信の失敗」と「SAPの中での業務処理の失敗」は違います。この区別ができないと、両側の担当者が平行線をたどります。
内部標準のJSONへの変換
/root/idoc/orders.jsonを作成してください。最上位は配列で、各要素は次の構造です。docnumの昇順です。
{ "docnum": "...", "belnr": "...", "currency": "...",
"netAmount": <숫자>,
"items": [ { "posex": "...", "matnr": "...",
"qty": <숫자>, "price": <숫자> }, ... ] }
(山括弧の中の韓国語はプレースホルダーで、数値を意味します。)
セグメントの階層レベルを生かして、明細をヘッダーの下の配列に入れます。jqで構造を検証できるように作ってください。