調達から支払いまで:請求書処理のデータテンプレート
調達から支払いまで:請求書処理のデータテンプレート
- 収集を推奨する属性
- 追跡すべき主要なアクティビティ
- SAP S/4HANAからの抽出ガイダンス
調達から支払いまで:請求書処理の属性
| 名前 | 説明 | ||
|---|---|---|---|
| 請求書番号 InvoiceNumber | 仕入先請求書伝票を一意に識別する番号であり、プロセスにおける主要なケース識別子です。 | ||
| 説明 請求書番号は、SAP S/4HANA内の各仕入先請求書に割り当てられる一意の識別子です。作成、保留、承認、支払いなど、関連するすべてのアクティビティを1つの一貫したプロセスインスタンスに結び付けます。 プロセスマイニングでは、この属性が各請求書のエンドツーエンドの経過を追跡する基盤になります。受領から最終支払いまでのプロセスフロー全体を再構成できるため、請求書単位でサイクル時間、ボトルネック、プロセスのばらつきを分析できます。 重要な理由 関連するすべてのイベントを結び付け、システム上で請求書のライフサイクルを完全に追跡するために欠かせないキーです。 入手先 BKPFテーブルのBELNRフィールドにある会計伝票番号です。 例 190000000119000000451900000132 | |||
| アクティビティ名 ActivityName | 請求書について、特定の時点で発生した業務アクティビティまたはイベントの名称です。 | ||
| 説明 アクティビティ名は、請求書処理のライフサイクルにおける特定のステップまたはステータス変更を表します。例として、「請求書伝票作成」、「請求書承認依頼送付」、「支払ブロック設定」、「支払実行」などがあります。 この属性は、アクティビティの流れを視覚的に表すプロセスマップの作成に欠かせません。アクティビティの順序、頻度、間隔を分析することで、ボトルネック、手戻りループ、コンプライアンスに反するプロセスのばらつきを特定できます。あらゆるプロセスマイニング分析の基盤となる属性です。 重要な理由 プロセスの各ステップを定義し、プロセスマップの可視化とプロセスフローおよびばらつきの分析を可能にします。 入手先 SAPトランザクションコード(SY-TCODE)、変更文書オブジェクトのステータス(CDHDR/CDPOS)、およびステータス変更を示す特定のフィールド値を組み合わせて算出します。 例 請求書の仮保存請求書の承認支払実行 | |||
| イベント時刻 EventTime | アクティビティが発生した正確な日付と時刻です。 | ||
| 説明 イベント時刻は、特定のアクティビティが発生した正確な時点を記録するタイムスタンプです。このデータは、プロセス内の各ステップ間の期間、サイクル時間、待機時間を算出するために欠かせません。 プロセスマイニング分析では、正確なタイムスタンプを使って「平均請求書サイクル時間」や「請求書承認サイクル時間」などのパフォーマンスKPIを測定します。アクティビティ間の経過時間を分析することで、請求書が滞留するボトルネックを特定し、プロセスを迅速化する機会を見つけられます。 重要な理由 このタイムスタンプは、パフォーマンス監視、ボトルネックの特定、SLAの追跡など、時間に基づくすべての分析の基盤です。 入手先 通常は、変更文書テーブルCDHDR(ヘッダー)とCDPOS(明細)のUDATEフィールドおよびUTIMEフィールドから取得します。一部のイベントでは、BKPFテーブルなどの作成日または入力日(CPUDT、CPUTM)を使用する場合があります。 例 2023-04-15T10:30:00Z2023-04-18T14:05:21Z2023-05-02T09:00:00Z | |||
| ユーザー名 UserName | アクティビティを実行した担当者またはシステムのSAPユーザーIDです。 | ||
| 説明 特定のトランザクションを実行したユーザー、または伝票を作成したユーザーを識別する属性です。個人のユーザーIDの場合も、自動バッチ処理用のシステムIDの場合もあります。 ユーザー単位で分析すると、業務量の分布、トレーニングの必要性、通常とは異なるユーザーの行動を把握できます。たとえば、例外処理を頻繁に担当するユーザーや、自動処理された請求書(例:「BATCHUSER」ユーザー)を特定できます。これは「請求書自動化率」KPIの算出にも役立ちます。 重要な理由 プロセスのアクティビティを特定のユーザーまたはシステムアカウントに紐付け、業務量の分析、パフォーマンス比較、自動化の検出を可能にします。 入手先 BKPF-USNAM(入力者)やCDHDR-USERNAME(変更者)などのフィールドから取得します。 例 SMITHJMUELLERTWF-BATCH | |||
| 仕入先番号 VendorNumber | 請求書を提出した仕入先を一意に識別する番号です。 | ||
| 説明 仕入先番号は、請求書に関連付けられた仕入先または債権者を識別します。請求書取引を仕入先マスターデータに結び付けます。 この属性は、「仕入先支払パフォーマンス」の評価や、例外または支払ブロックにつながる問題のある請求書を頻繁に提出する仕入先の特定など、仕入先中心の分析に欠かせません。仕入先との関係を管理し、サプライヤーの信頼性を評価するのに役立ちます。 重要な理由 仕入先ごとのプロセスパフォーマンスを分析し、傾向の特定、関係の管理、仕入先に起因する問題の評価に役立ちます。 入手先 通常は、会計伝票セグメントテーブルBSEGのLIFNRフィールドにあります。 例 100345700012V9832 | |||
| 会社コード CompanyCode | 財務諸表を作成する、法的に独立した会社を表す組織単位です。 | ||
| 説明 会社コードは、SAP財務会計における基本的な組織単位です。各請求書には特定の会社コードが割り当てられ、取引を担当する法人が決まります。 プロセスマイニングでは、会社コードでフィルタリングまたは比較することが、異なる事業部門、法人、国のプロセスパフォーマンスを分析するうえで欠かせません。地域ごとの効率、コンプライアンス、自動化レベルの違いを特定し、対象を絞った改善施策を支援できます。 重要な理由 組織内の異なる法人または地域間で、請求書処理のパフォーマンスを分類して比較できます。 入手先 伝票ヘッダーテーブルBKPFの標準フィールドであるBUKRSです。 例 1000US01DE01 | |||
| 伝票タイプ DocumentType | 仕入先請求書や貸方メモなど、会計伝票の種類を分類するコードです。 | ||
| 説明 伝票タイプは、SAPで異なる業務取引を区別するために使用します。たとえば、「KR」は通常の仕入先請求書を、「KG」は仕入先貸方メモを表す場合があります。 伝票タイプ別に分析すると、取引の種類ごとにプロセスを分類し、処理方法を把握できます。たとえば、貸方メモのプロセスは通常の請求書とは大きく異なる場合があります。この分類により、より正確で関連性の高いプロセス分析が可能になります。 重要な理由 通常の請求書や貸方メモなど、異なる経理取引を区別できます。これらは異なるプロセス経路をたどることがよくあります。 入手先 伝票ヘッダーテーブルBKPFのBLARTフィールドにあります。 例 KRREKG | |||
| 支払ブロック理由 PaymentBlockReason | 請求書が支払対象からブロックされた理由を示すコードです。 | ||
| 説明 請求書が支払ブロックされた場合に、数量差異や価格不一致など、具体的な理由を示す属性です。これらの理由は、例外処理を標準化するためにSAPで設定します。 この属性は、「支払ブロックの発生状況と期間」ダッシュボードに欠かせません。ブロック理由ごとの頻度を分析すると、特定の仕入先、品目、社内プロセスに起因する支払遅延の根本原因を特定し、対象を絞った是正措置を講じられます。 重要な理由 支払ブロックの具体的な根本原因を示し、遅延の削減と初回正解率の向上に向けた分析を可能にします。 入手先 BSEGテーブルの仕入先明細にあるZLSPRフィールド(支払ブロックキー)にあります。 例 RIA | |||
| 支払期日 PaymentDueDate | 延滞を避けるために請求書を支払う必要がある日付です。 | ||
| 説明 支払期日は、請求書日付と合意した支払条件に基づいて算出される、仕入先への支払期限です。プロセスにおける重要な締切日となります。 この属性は、「期限内支払率」KPIや「仕入先支払パフォーマンス」ダッシュボードに欠かせません。実際の支払日と支払期日を比較することで、支払義務を果たす能力を測定できます。これは仕入先との関係や財務上の信用にも影響します。 重要な理由 期限内支払の実績を測定する主要な基準です。良好な仕入先関係を維持し、延滞料金を避けるうえで重要です。 入手先 通常は、BSEGテーブルの仕入先明細にあるZFBDTフィールド(支払期日計算の基準日)から直接取得できます。正味支払期日は、この基準日と支払条件から算出します。 例 2023-05-302023-06-152023-07-01 | |||
| 請求書金額 AmountInCompanyCodeCurrency | 会社コードの現地通貨で表した請求書の税込み総額です。 | ||
| 説明 請求書の合計金額を表す属性です。請求書処理業務の財務的な影響と規模を把握するための重要な指標です。 請求書金額を分析すると、高額請求書を優先的に迅速処理したり、支出の傾向を把握したり、プロセス上の問題と金額を関連付けたりできます。たとえば、高額請求書ほどブロックされやすいか、承認に時間がかかるかを調査できます。 重要な理由 プロセスに財務面の情報を加え、金額に基づく分析を可能にします。たとえば、高額請求書が異なる方法で処理されているかを確認できます。 入手先 通常は、BSEGテーブルの関連する明細項目にあるWRBTRフィールド(現地通貨金額)の合計から算出します。 例 1500.75125000.00850.20 | |||
| 購買発注 PurchasingDocument | 請求書に関連する購買発注番号です。 | ||
| 説明 購買伝票番号は、仕入先請求書を元の購買発注(PO)に結び付けます。このリンクは、請求書、購買発注、入庫を照合する3点照合プロセスの基盤です。 この属性で分析すると、購買発注に基づく請求書と、購買発注のない請求書に関する問題を把握できます。照合差異の調査や、調達プロセスの効率を理解するうえでも重要です。 重要な理由 請求書を調達プロセスに結び付け、照合差異と購買発注のコンプライアンスを分析できます。 入手先 通常は、伝票セグメントテーブルBSEGのEBELNフィールド(購買伝票番号)にあります。 例 450000123445000056784500009012 | |||
| ソースシステムID SourceSystemId | データの抽出元であるSAP S/4HANAシステムの識別子です。 | ||
| 説明 元となるシステムを指定する属性です。たとえば、「S4H_PROD」や「ERP_EU」などです。複数のERPインスタンスや、レガシーシステムと最新システムが混在する環境では特に重要です。 分析では、異なるシステムや地域間でプロセスのパフォーマンスを比較できます。データの出所を明確にし、複数のソースからのデータを中央のプロセスマイニングプラットフォームに統合する際のデータガバナンスとトラブルシューティングにも欠かせません。 重要な理由 データの出所に関する情報を提供します。データガバナンスや、異なるシステムまたは拠点間でプロセスを比較するうえで欠かせません。 入手先 通常は、データ抽出時のSAPシステムID(sy-sysid)から取得するか、ETLパイプラインで静的な値として設定します。 例 S4PS4H_PROD_100ECC_EU | |||
| 取消理由 ReversalReason | 請求書伝票を取り消した理由を示すコードです。 | ||
| 説明 請求書が誤って転記された場合、取り消されることがあります。取消理由コードは、「誤った転記日」や「データ入力エラー」など、取消の理由を示します。 取消理由を分析すると、請求書転記プロセスにおけるエラーの傾向を特定できます。この情報を使って、トレーニングの改善、システム統制の強化、財務上の手戻りや管理負荷につながる再発問題への対策を進められます。 重要な理由 請求書がキャンセルされた理由を説明し、転記プロセスにおけるエラーと手戻りの発生源を直接把握できます。 入手先 元の伝票のヘッダーにあるBKPFテーブルのSTGRDフィールド(取消理由)にあります。 例 010205 | |||
| 手戻りかどうか IsRework | 承認却下や支払ブロック解除など、請求書が手戻りのアクティビティを経たかどうかを示すフラグです。 | ||
| 説明 1回以上の手戻りループが発生した請求書を示す属性です。たとえば、「請求書却下」の後に「請求書承認」が続く場合や、「支払ブロック設定」の後に「支払ブロック解除」が続く場合に、手戻りとして識別します。 この属性により、「請求書手戻り率」KPIを簡単に算出できます。手戻りが発生したケースを絞り込み、非効率や繰り返しの手作業の根本原因を調査できます。 重要な理由 作業のやり直しが必要な非効率なプロセスフローを特定し、無駄の定量化とプロセス上の例外の根本原因の特定に役立ちます。 入手先 イベントログ内のアクティビティの順序に基づいて算出します。たとえば、請求書のトレースに「請求書却下」が含まれる場合、このフラグはtrueになります。 例 truefalse | |||
| 承認サイクル数 ApprovalCycleCount | 請求書が承認に回された回数です。 | ||
| 説明 1つの請求書について、「請求書承認依頼送付」アクティビティの発生回数を数える指標です。回数が1回を超える場合、請求書が少なくとも1回却下または差し戻され、新たな承認サイクルが必要になったことを示します。 この属性は、「初回承認率」KPIを直接支えます。承認サイクル数が多い請求書を分析することで、情報不足やコードの誤りなど、承認に失敗した理由を特定し、プロセスを改善できます。 重要な理由 承認サブプロセス内の手戻りを定量化し、初回正解率の測定と承認却下の理由の特定に役立ちます。 入手先 一意のInvoiceNumberごとに「請求書承認依頼送付」アクティビティの発生回数を数えて算出します。 例 123 | |||
| 抽出タイムスタンプ ExtractionTimestamp | ソースシステムからデータを抽出した日付と時刻です。 | ||
| 説明 データ抽出イベントのタイムスタンプを記録する属性です。プロセスマイニングツールで分析するデータの鮮度を示します。 分析では、生成された情報がどの程度新しいかを把握するために使用します。運用監視用ダッシュボードでは、最新の情報に基づいて意思決定できるようにし、データ更新サイクルを適切に管理するために欠かせません。 重要な理由 データの鮮度を示し、分析とレポートが利用可能な最新情報に基づいていることを確認できます。 入手先 SAPのフィールドではありません。データ抽出ツールまたはETLプロセスが、データ取得時に生成して追加します。 例 2023-10-27T02:00:00Z2023-10-28T02:00:00Z2023-10-29T02:00:00Z | |||
| 支払条件 PaymentTerms | 支払期日や割引期間など、仕入先と合意した支払条件を定義するコードです。 | ||
| 説明 支払条件は、早期支払時に利用できる割引を含め、請求書の支払ルールを定義します。たとえば、「Z030」は「30日以内の正味支払」を意味する場合があります。 この属性は、財務計画と運転資本の最適化に欠かせません。プロセスマイニングでは、「支払期日」の算出や早期支払割引の適用可否の判定に使用し、「早期支払割引取得率」KPIを直接支えます。 重要な理由 支払期日と割引に関するルールを定義し、期限内支払KPIと運転資本管理に直接影響します。 入手先 BSEGテーブルの仕入先明細にあるZTERMフィールド(支払条件キー)にあります。 例 0001Z030NT60 | |||
| 期限内支払かどうか IsPaidOnTime | 請求書が支払期日当日またはそれ以前に支払われた場合にtrueとなるフラグです。 | ||
| 説明 このブール型属性は、実際の支払日(「支払実行」アクティビティのタイムスタンプ)と「支払期日」を比較した結果です。各請求書の支払状況を明確に二値で示します。 「期限内支払率」KPIの中核となる計算です。遅延した支払いに共通する仕入先、会社コード、請求書金額などの特徴を簡単に絞り込み、分析できます。 重要な理由 支払条件の遵守状況を直接測定します。仕入先関係の管理と財務業務における重要なKPIです。 入手先 「支払実行」アクティビティのEventTimeとPaymentDueDate属性を比較して算出します。(Payment Date <= PaymentDueDate) 例 truefalse | |||
| 消込伝票番号 ClearingDocumentNumber | 請求書を消し込む伝票の番号で、通常は支払伝票を表します。 | ||
| 説明 消込伝票番号は、未消込の請求書明細を消し込む取引に結び付けます。通常は支払伝票であり、請求書が支払済みであることを確認できます。 この属性は、請求書と支払いを結び付ける決定的な情報です。「支払実行」アクティビティと対応するタイムスタンプの特定に使用し、エンドツーエンドのサイクル時間と期限内支払率の算出に役立ちます。 重要な理由 請求書が支払済みであることを確認し、特定の支払取引に結び付けます。サイクル時間と支払パフォーマンスの分析に欠かせません。 入手先 伝票セグメントテーブルBSEGのAUGBLフィールド(消込伝票番号)にあります。 例 150000000115000000231500000088 | |||
| 自動処理かどうか IsAutomated | アクティビティが自動システムユーザーによって実行されたかどうかを示すフラグです。 | ||
| 説明 このブール型属性は、アクティビティに関連付けられたユーザーが「WF-BATCH」や「SAP_SYSTEM」など、既知のシステムアカウントまたはバッチアカウントの場合にtrueになります。手動のプロセスステップと自動化されたステップを区別できます。 この属性は、「請求書自動化率」KPIの算出に欠かせません。プロセスのどの部分が自動化されているかを分析することで、自動化施策の成果を測定し、手作業の削減と効率向上に向けた追加の機会を特定できます。 重要な理由 手動アクティビティとシステム主導のアクティビティを区別します。自動化率の測定や、さらなる自動化の機会を特定するための基盤となります。 入手先 UserName属性から算出します。特定のユーザーIDを「自動処理」として分類するマッピングまたはルールを作成します。 例 truefalse | |||
| 請求書日付 InvoiceDate | 仕入先が請求書伝票を発行した日付です。 | ||
| 説明 請求書日付は伝票日付とも呼ばれ、仕入先が請求書に記載する日付です。合意した支払条件に基づいて支払期日を算出する際の起点になります。 分析では、請求書の経過日数や早期支払割引の適用可否など、財務計算の基礎となります。「早期支払割引取得率」KPIの主要な入力値です。 重要な理由 支払条件と支払期日を算出する基準となり、運転資本の管理と割引の取得に欠かせません。 入手先 伝票ヘッダーテーブルBKPFのBLDATフィールド(伝票日付)にあります。 例 2023-04-122023-05-152023-06-20 | |||
調達から支払いまで:請求書処理のアクティビティ
| アクティビティ | 説明 | ||
|---|---|---|---|
| 支払実行 | これは標準プロセスにおける最後のアクティビティで、支払いが実行され、請求書が消込されます。仕入先への資金の支払いが完了したことを示します。 | ||
| 重要な理由 これはP2P請求書ライフサイクルの終了を示します。エンドツーエンドの総サイクル時間を算出し、支払期日に対する期限内支払の実績を測定するために欠かせません。 入手先 このイベントは、仕入先明細の消込伝票情報から取得します。消込日(BSEG-AUGDT)と消込伝票(BSEG-AUGBL)によって、支払いが実行されたことを確認できます。 取得 消込済みの仕入先明細から、消込日(BSEG-AUGDT)を使用します。 イベントタイプ explicit | |||
| 請求書の承認 | 指定された権限者が請求書を承認したことを示すアクティビティです。承認ワークフローが正常に完了した時点や、リリースインジケーターが設定された時点で取得します。 | ||
| 重要な理由 支払いに進めるための重要な節目です。承認の遅れは一般的なボトルネックであり、このアクティビティを追跡することで、承認に時間がかかっている担当者やプロセス手順を特定できます。 入手先 SAPワークフローの最終リリース手順や、請求書または関連する購買伝票のテーブルにあるリリースステータス項目の変更から推定できます。 取得 ワークフロー完了イベント、または伝票のリリースステータス項目の変更から推定します。 イベントタイプ inferred | |||
| 請求書伝票の作成 | SAPで請求書伝票が作成されたことを示す、最初のイベントです。ユーザーが新しい請求書伝票を保存した時点で取得できます。伝票は未転記または仮転記前の状態の場合があります。 | ||
| 重要な理由 このアクティビティは、請求書処理ライフサイクルの開始を示します。このイベントから他のイベントまでの時間を分析することは、処理全体のリードタイムを測定するうえで重要です。 入手先 このイベントは、伝票ヘッダーのテーブル(通常はBKPF、ロジスティクス請求書の場合はRBKP)にある作成日と作成時刻(CPUDT、CPUTM)から取得します。FB60、MIRO、MIR7などのトランザクションコード(BKPF-TCODE)により、作成方法を確認できます。 取得 請求書伝票には、BKPF-CPUDTとBKPF-CPUTMの作成タイムスタンプを使用します。 イベントタイプ explicit | |||
| 請求書取消 | 以前に転記された請求書伝票の取消を表すアクティビティです。誤った請求書に対する終端イベントであり、その後、正しい内容で再入力されることがよくあります。 | ||
| 重要な理由 取消は、プロセスの早い段階で検出されなかった重大なエラーを示します。発生頻度と根本原因を追跡することは、プロセス改善と財務上の誤りの削減に欠かせません。 入手先 取消は、取消伝票が作成された時点で特定します。元の伝票ヘッダー(BKPF)には取消伝票番号(BKPF-STBLG)が記録され、その逆も同様です。取消伝票の転記日がイベント時刻になります。 取得 BKPF-STBLGフィールドに値がある伝票を特定し、取消伝票の転記日を使用します。 イベントタイプ explicit | |||
| 請求書転記完了 | これは、保留中または承認済みの請求書が総勘定元帳に正式に転記される重要な財務イベントです。この処理により、仕入先に対する債務が認識されます。 | ||
| 重要な理由 転記は、データ入力と承認の段階と、財務決済の段階を分ける重要な節目です。請求書の作成から転記までの時間は、社内処理の効率を測る重要な指標です。 入手先 このイベントは、伝票ヘッダーの転記日(BKPF-BUDAT)によって特定します。最初に保留された伝票では、転記済みステータスへの移行時点がイベントのタイムスタンプになります。 取得 転記日(BKPF-BUDAT)をイベントのタイムスタンプとして使用します。 イベントタイプ explicit | |||
| 支払ブロックの解除 | 以前に設定された支払ブロックが解除され、問題が解消されたことを示します。これにより、請求書は再び支払いの対象になります。 | ||
| 重要な理由 支払ブロックが設定されてから解除されるまでの時間は、プロセス上の例外を解消するまでの時間を表します。この期間を短縮することは、業務効率と仕入先との関係を改善するうえで重要です。 入手先 Payment Block Keyフィールド(BSEG-ZLSPR)がクリアされた時点で、このイベントが記録されます。この変更はCDHDRテーブルとCDPOSテーブルに記録され、ブロック解除のタイムスタンプを確認できます。 取得 変更文書(CDHDR/CDPOS)を通じて、BSEG-ZLSPRフィールドがクリアされた時点を特定します。 イベントタイプ explicit | |||
| 支払ブロックの設定 | 請求書が支払われないよう、意図的にブロックを設定するアクティビティです。価格や数量の不一致、クレジットメモの処理待ちなどが原因になることがあります。 | ||
| 重要な理由 支払ブロックは、支払い遅延や仕入先との紛争の主な原因です。ブロックの頻度、期間、理由を分析することは、期日どおりの支払い率を改善するうえで重要です。 入手先 請求書明細のPayment Block Key項目(BSEG-ZLSPR)の変更を追跡して取得します。CDHDRとCDPOSの変更ログから、ブロックが設定された日時とユーザーを確認できます。 取得 変更文書(CDHDR/CDPOS)を通じて、BSEG-ZLSPR項目に値が設定された時点を特定します。 イベントタイプ explicit | |||
| 支払提案作成 | 支払処理の一環として、請求書が選択され、支払提案に含まれます。これは自動支払プロセスの最初のステップです。 | ||
| 重要な理由 このアクティビティは、支払う意思が示されたことを表します。このステップから最終的な支払実行までの遅延を分析すると、支払処理、承認、銀行との通信に関する問題を把握できます。 入手先 支払処理のテーブル、特に支払提案に含まれる明細を保持するREGUPで確認できます。対応するREGUHテーブルの実行日がタイムスタンプになります。 取得 支払提案の実行により、請求書がREGUPテーブルに登録された時点を特定します。 イベントタイプ explicit | |||
| 支払遅延後の支払実行 | これは、請求書の支払いが算出された支払期日を過ぎて実行された場合に発生する計算イベントです。2つの日付フィールドを比較して算出します。 | ||
| 重要な理由 このアクティビティは、期限内支払KPIを直接支えます。また、支払遅延が頻繁に発生する仕入先や事業部門を特定するのに役立ちます。支払遅延は、仕入先との関係悪化や違約金につながる可能性があります。 入手先 消込日(BSEG-AUGDT)と正味支払期日を比較して算出します。支払期日は、基準日(BSEG-ZFBDT)と支払条件(BSEG-ZTERM)から算出されます。 取得 BSEG-AUGDT >(BSEG-ZFBDT + 支払条件の日数)を比較して算出します。 イベントタイプ calculated | |||
| 請求書データの更新 | 初回作成後に請求書伝票へ変更が加えられたことを示すアクティビティです。却下後の手戻りサイクルやエラー修正でよく発生します。 | ||
| 重要な理由 更新が頻繁に発生している場合、手戻りや入力時点でのデータ品質の問題が考えられます。変更を追跡することで、修正にかかった作業量を定量化し、よくあるエラーを特定できます。 入手先 主要項目への変更は、SAPの変更文書テーブルであるCDHDR(ヘッダー)とCDPOS(明細)に記録されます。対象の請求書オブジェクトに関する変更を抽出することで、イベントを生成できます。 取得 請求書オブジェクトについて、CDHDRとCDPOSから変更イベントを抽出します。 イベントタイプ explicit | |||
| 請求書の仮保存 | システムに入力済みですが、まだ総勘定元帳に転記されていない請求書を示します。仮保存は、未完成の請求書を保存したり、転記前に後で確認したりするために使用します。 | ||
| 重要な理由 仮保存は、プロセスが意図的に一時停止していることを示します。仮保存された請求書の期間と頻度を追跡すると、正式な転記・承認サイクルが始まる前の遅延理由を特定できます。 入手先 MIR7やFV60などの仮保存用トランザクションで作成された伝票を特定するか、BKPFテーブルの特定のステータス項目、またはVBKPFなどの仮保存伝票専用テーブルを確認します。 取得 仮保存用トランザクションで作成された伝票を特定するか、仮保存伝票のステータスを確認します。 イベントタイプ explicit | |||
| 請求書の却下 | 承認プロセス中に請求書が却下されたことを示します。このイベントにより手戻りが発生し、修正と再申請が必要になります。 | ||
| 重要な理由 請求書の却下は、プロセスの非効率やデータ品質の問題を示す重要な指標です。却下の頻度と理由を分析することで、改善やトレーニングの機会を特定できます。 入手先 SAPワークフローの「却下」ステータスなど、特定のステータス更新から推定します。または、現在の承認ワークフローを取り消し、処理担当者に差し戻すイベントから推定できます。 取得 却下を示すワークフローステータスの変更から推定します。 イベントタイプ inferred | |||
| 請求書を承認に回付 | 請求書の正式な承認ワークフローが開始されたことを示すアクティビティです。請求書のステータスが「承認待ち」に変わった時点や、ワークフロー項目が生成された時点から推定することが一般的です。 | ||
| 重要な理由 承認サイクルタイムの測定開始点です。承認がいつ始まったかを把握することは、承認ワークフロー自体のボトルネックを特定するうえで欠かせません。 入手先 通常は、請求書オブジェクト(例:BUS2081)に関連付けられたSAP Business Workflowの開始(SWW_WI2OBJテーブル)や、伝票ヘッダーのカスタムステータス項目の変更から推定します。 取得 請求書伝票に関連するワークフロー項目の作成から推定します。 イベントタイプ inferred | |||
抽出ガイド
ステップ
- 前提条件と権限:抽出を実行するユーザーに、必要なCore Data Services(CDS)ビューへアクセスするためのSAP S/4HANA権限があることを確認します。主なビューには、
I_InvoiceDocument、I_OperationalAcctgDocItem、I_ChangeDocument、I_ChangeDocumentItem、I_PaymentProposalItemがあります。また、ODataサービスや直接SQL接続など、選択したインターフェース経由でクエリを実行する権限も必要です。 - 接続方法の特定:SQLクエリを実行するために、SAP S/4HANAシステムへ接続する方法を決めます。一般的な方法には、SAP Data Services、SAP Data Intelligence、SAPコネクタを備えたサードパーティ製ETLツール、または組織のセキュリティポリシーで許可されている場合のSAP HANAデータベースへの直接SQL接続があります。
- 抽出パラメータの定義:クエリを実行する前に、主要なパラメータを定義します。たとえば、
CreationDateが'YYYY-MM-DD'から'YYYY-MM-DD'の範囲に入るよう、抽出期間を指定します。また、データ抽出の範囲を限定するため、含めるCompanyCodeの値を特定します。 - SQLクエリのカスタマイズ:提供されたSQLクエリを、選択したSQLクライアントまたはデータ抽出ツールにコピーします。
'{StartDate}'、'{EndDate}'、('{CompanyCode1}', '{CompanyCode2}')などのプレースホルダーを確認し、前の手順で定義した実際の値に置き換えます。SAPの構成に応じて、ワークフローステータスのフィールド名も調整が必要になる場合があります。 - クエリの実行:完成したSQLクエリをSAP S/4HANAデータベースに対して、または適切なサービスレイヤー経由で実行します。このクエリは詳細なデータを取得するため、データ量や選択した期間によっては実行に時間がかかる場合があります。エラーやタイムアウトが発生していないか監視します。
- 初期結果の確認:クエリが完了したら、出力を簡単に確認します。
InvoiceNumber、ActivityName、EventTimeの各列に値が入っていることを確認します。また、ActivityName列に「Invoice Document Created」だけでなく、さまざまなアクティビティが含まれていることを確認します。 - データ変換の確認:クエリは整ったイベントログ形式で出力されるよう構成されています。ただし、
EventTime列がYYYY-MM-DDTHH:MM:SSなどの一貫したタイムスタンプ形式になっていることを確認します。提供されたクエリでは、必要に応じて日付フィールドと時刻フィールドを1つのタイムスタンプに結合します。 - データのエクスポート:ツールから最終結果セットをCSV(Comma-Separated Values)ファイルとしてエクスポートします。この形式は、ProcessMindを含むプロセスマイニングツールと幅広く互換性があります。
- アップロードの準備:アップロード前に、文字化けを防ぐためCSVファイルがUTF-8エンコーディングで保存されていることを確認します。ファイルの列見出しが、必要な属性である
InvoiceNumber、ActivityName、EventTime、UserName、CompanyCodeなどと完全に一致していることを確認します。 - ProcessMindへのアップロード:準備したCSVファイルをプロセスマイニングプロジェクトにアップロードします。ファイルの列を、ツールのデータモデル設定における対応するケースID、アクティビティ名、タイムスタンプの各フィールドにマッピングします。
設定
- CDS Viewの使用:主なデータソースは標準SAP CDSビューです。主要なビューは、ヘッダーデータ用の
I_InvoiceDocument、財務転記と消込の詳細用のI_OperationalAcctgDocItem、支払ブロックやワークフローステータスなど請求書属性の履歴変更を追跡するI_ChangeDocumentおよびI_ChangeDocumentItemです。 - 期間による絞り込み:パフォーマンスを管理するため、特定の期間でデータを絞り込むことが重要です。提供されたクエリでは、
I_InvoiceDocumentビューのCreationDateにプレースホルダーを使用しています。最初は3~6か月分のデータから始めることを推奨します。 - 会社コードによる絞り込み:抽出対象を適切な範囲に収めるため、必ず1つ以上の
CompanyCodeで絞り込みます。クエリには、この目的のためにWHERE inv.CompanyCode IN ('{CompanyCode1}', '{CompanyCode2}')というプレースホルダーが含まれています。 - 伝票タイプによる絞り込み:
InvoiceDocumentTypeで絞り込むことで、抽出対象をさらに限定できます。たとえば、標準仕入先請求書(RE)を含め、クレジットメモを除外できます。これは初期CTEのWHERE句に追加できます。 - 前提条件:クエリを実行するユーザーには、指定した会社コードの財務伝票および購買伝票を表示する適切な権限が必要です。SQLクライアント経由で基盤のHANAデータベースへアクセスするには、通常とは別の特別な権限が必要です。
- パフォーマンスに関する考慮事項:変更伝票テーブル(
I_ChangeDocument、I_ChangeDocumentItem)からの抽出は、処理負荷が高くなる場合があります。実行時間が長くなるのを防ぐには、日付、会社コード、オブジェクトクラス(INCOMINGINVOICE)で厳密に絞り込むことが不可欠です。
a サンプルクエリ sql
WITH InvoiceBase AS (
SELECT
inv.InvoiceDocument,
inv.FiscalYear,
inv.CompanyCode,
inv.Supplier AS VendorNumber,
inv.DocumentType,
inv.GrossInvoiceAmountInCoCoCrcy AS AmountInCompanyCodeCurrency,
inv.NetDueDate AS PaymentDueDate,
inv.PurchasingDocument,
inv.CreationDateTime,
inv.CreatedByUser,
accdoc.AccountingDocument,
accdoc.ClearingDate,
accdoc.ClearingJournalEntry,
accdoc.PaymentBlockReason,
accdoc.IsReversed
FROM I_InvoiceDocument AS inv
LEFT JOIN I_OperationalAcctgDocItem AS accdoc
ON inv.AccountingDocument = accdoc.AccountingDocument
AND inv.FiscalYear = accdoc.FiscalYear
AND inv.CompanyCode = accdoc.CompanyCode
WHERE
inv.CreationDate BETWEEN '{StartDate}' AND '{EndDate}'
AND inv.CompanyCode IN ('{CompanyCode1}', '{CompanyCode2}')
)
-- 1. Invoice Document Created
SELECT
InvoiceDocument AS "InvoiceNumber",
'Invoice Document Created' AS "ActivityName",
CreationDateTime AS "EventTime",
CreatedByUser AS "UserName",
CompanyCode AS "CompanyCode",
VendorNumber AS "VendorNumber",
AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
PaymentDueDate AS "PaymentDueDate",
DocumentType AS "DocumentType",
CAST(NULL AS VARCHAR(1)) AS "PaymentBlockReason",
PurchasingDocument AS "PurchasingDocument"
FROM InvoiceBase
UNION ALL
-- 2. Invoice Parked
SELECT
i.InvoiceDocument AS "InvoiceNumber",
'Invoice Parked' AS "ActivityName",
i.CreationDateTime AS "EventTime",
i.CreatedByUser AS "UserName",
i.CompanyCode AS "CompanyCode",
i.Supplier AS "VendorNumber",
i.GrossInvoiceAmountInCoCoCrcy AS "AmountInCompanyCodeCurrency",
i.NetDueDate AS "PaymentDueDate",
i.DocumentType AS "DocumentType",
CAST(NULL AS VARCHAR(1)) AS "PaymentBlockReason",
i.PurchasingDocument AS "PurchasingDocument"
FROM I_InvoiceDocument AS i
WHERE
i.InvoiceDocumentIsParked = 'X'
AND i.CreationDate BETWEEN '{StartDate}' AND '{EndDate}'
AND i.CompanyCode IN ('{CompanyCode1}', '{CompanyCode2}')
UNION ALL
-- 3, 4, 5. Workflow activities (Sent for Approval, Approved, Rejected) from Change Docs
SELECT
cdpos.ObjectValue AS "InvoiceNumber",
CASE
WHEN cdpos.ValueNew = '[StatusSentForApproval]' THEN 'Invoice Sent For Approval'
WHEN cdpos.ValueNew = '[StatusApproved]' THEN 'Invoice Approved'
WHEN cdpos.ValueNew = '[StatusRejected]' THEN 'Invoice Rejected'
END AS "ActivityName",
CAST(cdhdr.ChangeDate AS TIMESTAMP) + CAST(cdhdr.ChangeTime AS TIME) AS "EventTime",
cdhdr.UserName AS "UserName",
inv.CompanyCode AS "CompanyCode",
inv.VendorNumber AS "VendorNumber",
inv.AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
inv.PaymentDueDate AS "PaymentDueDate",
inv.DocumentType AS "DocumentType",
CAST(NULL AS VARCHAR(1)) AS "PaymentBlockReason",
inv.PurchasingDocument AS "PurchasingDocument"
FROM I_ChangeDocument AS cdhdr
JOIN I_ChangeDocumentItem AS cdpos ON cdhdr.ChangeDocument = cdpos.ChangeDocument
JOIN InvoiceBase AS inv ON cdpos.ObjectValue = inv.InvoiceDocument
WHERE
cdhdr.ObjectClassName = 'INCOMINGINVOICE'
AND cdpos.FieldName = '[WorkflowStatusFieldName]'
AND cdpos.ValueNew IN ('[StatusSentForApproval]', '[StatusApproved]', '[StatusRejected]')
UNION ALL
-- 6. Invoice Data Updated
SELECT
cdpos.ObjectValue AS "InvoiceNumber",
'Invoice Data Updated' AS "ActivityName",
CAST(cdhdr.ChangeDate AS TIMESTAMP) + CAST(cdhdr.ChangeTime AS TIME) AS "EventTime",
cdhdr.UserName AS "UserName",
inv.CompanyCode AS "CompanyCode",
inv.VendorNumber AS "VendorNumber",
inv.AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
inv.PaymentDueDate AS "PaymentDueDate",
inv.DocumentType AS "DocumentType",
CAST(NULL AS VARCHAR(1)) AS "PaymentBlockReason",
inv.PurchasingDocument AS "PurchasingDocument"
FROM I_ChangeDocument AS cdhdr
JOIN I_ChangeDocumentItem AS cdpos ON cdhdr.ChangeDocument = cdpos.ChangeDocument
JOIN InvoiceBase AS inv ON cdpos.ObjectValue = inv.InvoiceDocument
WHERE
cdhdr.ObjectClassName = 'INCOMINGINVOICE'
AND cdpos.FieldName IN ('GrossInvoiceAmount', 'DocumentDate', 'PaymentTerms')
AND cdhdr.ChangeDate BETWEEN '{StartDate}' AND '{EndDate}'
UNION ALL
-- 7 & 8. Payment Block Set/Removed
SELECT
inv.InvoiceDocument AS "InvoiceNumber",
CASE
WHEN cdpos.ValueNew <> '' AND cdpos.ValueOld = '' THEN 'Payment Block Set'
WHEN cdpos.ValueNew = '' AND cdpos.ValueOld <> '' THEN 'Payment Block Removed'
END AS "ActivityName",
CAST(cdhdr.ChangeDate AS TIMESTAMP) + CAST(cdhdr.ChangeTime AS TIME) AS "EventTime",
cdhdr.UserName AS "UserName",
inv.CompanyCode AS "CompanyCode",
inv.VendorNumber AS "VendorNumber",
inv.AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
inv.PaymentDueDate AS "PaymentDueDate",
inv.DocumentType AS "DocumentType",
cdpos.ValueNew AS "PaymentBlockReason",
inv.PurchasingDocument AS "PurchasingDocument"
FROM I_ChangeDocument AS cdhdr
JOIN I_ChangeDocumentItem AS cdpos ON cdhdr.ChangeDocument = cdpos.ChangeDocument
JOIN InvoiceBase AS inv ON cdpos.ObjectValue = inv.AccountingDocument
WHERE
cdhdr.ObjectClassName = 'BELEG'
AND cdpos.TableName = 'BSEG'
AND cdpos.FieldName = 'ZLSPR'
AND ( (cdpos.ValueNew <> '' AND cdpos.ValueOld = '') OR (cdpos.ValueNew = '' AND cdpos.ValueOld <> '') )
UNION ALL
-- 9. Invoice Posted
SELECT
inv.InvoiceDocument AS "InvoiceNumber",
'Invoice Posted' AS "ActivityName",
CAST(accdoc.PostingDate AS TIMESTAMP) AS "EventTime",
accdoc.CreatedByUser AS "UserName",
inv.CompanyCode AS "CompanyCode",
inv.VendorNumber AS "VendorNumber",
inv.AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
inv.PaymentDueDate AS "PaymentDueDate",
inv.DocumentType AS "DocumentType",
accdoc.PaymentBlockReason AS "PaymentBlockReason",
inv.PurchasingDocument AS "PurchasingDocument"
FROM InvoiceBase AS inv
JOIN I_OperationalAcctgDocItem AS accdoc ON inv.AccountingDocument = accdoc.AccountingDocument
WHERE inv.AccountingDocument IS NOT NULL AND inv.IsReversed = FALSE
UNION ALL
-- 10. Payment Proposal Created
SELECT
item.InvoiceReference AS "InvoiceNumber",
'Payment Proposal Created' AS "ActivityName",
CAST(prun.PaymentRunDate AS TIMESTAMP) AS "EventTime",
prun.CreatedByUser AS "UserName",
item.CompanyCode AS "CompanyCode",
item.Supplier AS "VendorNumber",
item.AmountInTransactionCurrency AS "AmountInCompanyCodeCurrency",
item.NetDueDate AS "PaymentDueDate",
item.AccountingDocumentType AS "DocumentType",
item.PaymentBlockReason AS "PaymentBlockReason",
item.PurchasingDocument AS "PurchasingDocument"
FROM I_PaymentProposalItem as item
JOIN I_PaymentRun as prun ON item.PaymentRunName = prun.PaymentRunName
JOIN InvoiceBase AS inv ON item.InvoiceReference = inv.InvoiceDocument
UNION ALL
-- 11 & 12. Payment Executed / Late Payment Executed
SELECT
InvoiceDocument AS "InvoiceNumber",
CASE
WHEN ClearingDate > PaymentDueDate THEN 'Late Payment Executed'
ELSE 'Payment Executed'
END AS "ActivityName",
CAST(ClearingDate AS TIMESTAMP) AS "EventTime",
CAST(NULL AS VARCHAR(12)) AS "UserName", -- User for clearing is not always straightforward
CompanyCode AS "CompanyCode",
VendorNumber AS "VendorNumber",
AmountInCompanyCodeCurrency AS "AmountInCompanyCodeCurrency",
PaymentDueDate AS "PaymentDueDate",
DocumentType AS "DocumentType",
'' AS "PaymentBlockReason",
PurchasingDocument AS "PurchasingDocument"
FROM InvoiceBase
WHERE ClearingDate IS NOT NULL AND IsReversed = FALSE
UNION ALL
-- 13. Invoice Reversed
SELECT
rev.OriginalInvoiceDocument AS "InvoiceNumber",
'Invoice Reversed' AS "ActivityName",
rev.CreationDateTime AS "EventTime",
rev.CreatedByUser AS "UserName",
rev.CompanyCode AS "CompanyCode",
rev.Supplier AS "VendorNumber",
rev.GrossInvoiceAmountInCoCoCrcy AS "AmountInCompanyCodeCurrency",
CAST(NULL AS DATE) AS "PaymentDueDate",
rev.DocumentType AS "DocumentType",
CAST(NULL AS VARCHAR(1)) AS "PaymentBlockReason",
rev.PurchasingDocument AS "PurchasingDocument"
FROM I_InvoiceDocument AS rev
WHERE rev.OriginalInvoiceDocument IN (SELECT InvoiceDocument FROM InvoiceBase) AND rev.IsReversal = 'X' ステップ
- SAP HANAテナントまたはデータベーススキーマへの直接読み取りアクセスが承認済みであることを確認し、必要なSAPテーブルと、承認済みの変更履歴またはワークフローテーブルに対する読み取り専用権限を持つデータベースユーザーを取得します。SAP HANA Database Explorer、SAP HANA Studio、または承認済みのSQLクライアントを使用します。本番環境への書き込みアクセスは使用しないでください。
- 対象のS/4HANAシステムで、物理テーブル名と列名を確認します。ACDOCA、BKPF、RBKPは標準的な出発点ですが、ワークフロー、保留、支払提案、支払実行、変更履歴、支払ブロック履歴には、リリースや顧客ごとに異なるオブジェクトが使われる場合があります。クエリ内の角括弧で示された各プレースホルダーを、システムカタログで確認したオブジェクトと、関連する業務上の意味に置き換えます。
- [Start timestamp]と[End timestamp]を使って抽出期間を定義します。通常は3~6か月分など、伝票とイベントを十分に含む期間を抽出します。支払期日や支払遅延が請求書作成期間の後に発生する可能性がある場合は、期間を広げます。
- 設定済みの請求書キーを使って請求書ケースを特定します。クエリでは
InvoiceNumberをケース識別子として使用し、必要に応じて会社コードと会計年度を内部で組み合わせ、重複を避けます。業務上の定義で、ProcessMindのケース識別子に会計年度または会社コードを追加する必要があるか確認します。 - RBKP、BKPF、ACDOCAから転記済み請求書データをマッピングします。請求書ヘッダー情報にはRBKP、会計伝票のタイムスタンプとユーザーにはBKPF、仕入先、金額、購買伝票、消込、支払いに関する会計情報には、利用可能な場合にACDOCAを使用します。すべての転記シナリオで、すべてのフィールドに値が入るとは限りません。
- 確認済みのシステム固有のデータソースから、保留、承認、却下、更新、支払ブロック、取消、支払提案、支払実行のイベントをマッピングします。イベントのタイムスタンプ、請求書参照、ユーザー、ステータス、変更前後の値を公開する承認済みのビューまたはテーブルに、プレースホルダーのソースビューを置き換えます。ProcessMindはイベントを推測しないため、各アクティビティを明示的なイベント行として出力する必要があります。
- 完成したSQLクエリを非本番環境または読み取り専用セッションで実行します。実行計画を確認し、必要に応じて会社コード、伝票タイプ、会計年度、イベントタイムスタンプでクエリを制限します。大規模な仕訳テーブルと履歴テーブルを無制限に結合しないでください。
- 以下の確認項目に従って結果を検証します。必要な列がすべて存在すること、すべてのイベントでEventTimeに値が入っていること、すべてのケースでInvoiceNumberに値が入っていること、対応するソースデータが存在する場合に13種類すべてのアクティビティ名が出現することを確認します。
- 結果をProcessMindがサポートする区切り形式のファイルとしてエクスポートします。UTF-8 CSVを推奨します。1行を1イベントとし、InvoiceNumber、ActivityName、EventTime、UserName、CompanyCode、VendorNumber、AmountInCompanyCodeCurrency、PaymentDueDate、DocumentType、PaymentBlockReason、PurchasingDocumentの各列を含めます。タイムスタンプは一貫したタイムゾーンで保持し、識別子の先頭ゼロを維持します。
- イベントログをProcessMindにアップロードし、InvoiceNumberをケース識別子、ActivityNameをアクティビティ列、EventTimeをタイムスタンプ列として設定します。ProcessMindの設定で追加のケースキーがサポートされている場合は、抽出時に適用したものと同じ複合キーの方針を使用します。
設定
- 期間:最初の抽出では、直近3~6か月のローリング期間を使用します。承認、支払い、消込、取消、支払遅延のイベントが請求書作成期間の後に発生する可能性がある場合は、追加の履歴を含めます。
- 会社範囲:[Company code filter]で絞り込み、選択した会社コードに抽出権限があることを確認します。
- 伝票範囲:[Document type filter]で絞り込み、対象プロセスにおける仕入先請求書、クレジットメモ、保留中の請求書、取消を表す伝票タイプを含めます。
- ケース識別子:プロセス定義で指定されているとおり、InvoiceNumberを使用します。請求書番号がグローバルに一意でない場合は、ソース結果に会社コードと会計年度を保持するか、ProcessMindのモデルに従って複合ケースキーを設定します。
- イベントソース:ワークフローステータスの変更、承認判断、保留、変更履歴、支払ブロック、支払提案、支払実行の物理的なデータソースを確認します。これらのソースは、S/4HANAのリリース、有効化された範囲、ワークフロー設計、顧客拡張によって異なります。
- タイムスタンプ方針:抽出時刻ではなく、業務イベントのタイムスタンプを選択します。タイムゾーンを文書化し、アップロード前にすべてのイベントタイムスタンプを一貫した形式へ変換します。
- 金額方針:会社コード通貨額を使用し、選択したソースで借方と貸方の符号が一貫して保存されているか確認します。請求書ケースに対する集計ルールを検証せずに、仕訳明細を合計しないでください。
- 支払方針:Payment Executedが消込、支払伝票の転記、銀行での実行、その他の業務上のマイルストーンのどれを意味するか定義します。合意したプロセス定義に一致するソースを使用します。
- 支払遅延:Payment ExecutedがPaymentDueDateの後に発生した場合にのみ、Late Payment Executedを出力します。クエリはこのイベントを明示的に計算し、ProcessMindによる推測には依存しません。
- パフォーマンス:日付、会社コード、伝票タイプ、関連する会計年度でソースの読み取りを制限します。必要な列だけを選択し、クエリ計画を確認します。ソースの履歴が大きい場合は、承認済みの中間ビューをマテリアライズします。
- 前提条件:SAP HANAへの直接接続、選択したすべてのオブジェクトに対する読み取り権限、メタデータを確認する権限、買掛金、総勘定元帳、購買、ワークフロー、支払いに関するデータへのアクセスが必要です。必要なSAPライセンス、データベースアクセス方針、データ保護の承認が整っていることを確認します。
- セキュリティ:読み取り専用の技術ユーザーを使用し、仕入先データと支払データを保護します。組織の移送、監査、マスキング、認証情報管理の方針に従ってください。
a サンプルクエリ sql
WITH
invoice_base AS (
SELECT
r.INV_DOC_NO AS InvoiceNumber,
r.COMPANY_CODE AS CompanyCode,
r.FISCAL_YEAR AS FiscalYear,
r.DOCUMENT_TYPE AS DocumentType,
r.VENDOR_NO AS VendorNumber,
r.GROSS_AMOUNT_CC AS AmountInCompanyCodeCurrency,
r.PAYMENT_DUE_DATE AS PaymentDueDate,
r.PURCHASING_DOCUMENT AS PurchasingDocument,
r.CREATED_AT AS InvoiceCreatedAt,
r.CREATED_BY AS InvoiceCreatedBy
FROM [Your RBKP invoice header source] r
WHERE r.CREATED_AT >= '[Start timestamp]'
AND r.CREATED_AT < '[End timestamp]'
AND r.COMPANY_CODE IN ([Company code filter])
AND r.DOCUMENT_TYPE IN ([Document type filter])
),
posted_accounting AS (
SELECT
b.INV_DOC_NO AS InvoiceNumber,
b.COMPANY_CODE AS CompanyCode,
b.FISCAL_YEAR AS FiscalYear,
b.ACCOUNTING_DOCUMENT AS AccountingDocument,
b.POSTING_DATE AS PostingDate,
b.CREATED_AT AS PostedAt,
b.CREATED_BY AS PostedBy,
b.REVERSAL_DOCUMENT AS ReversalDocument,
b.REVERSED_DOCUMENT AS ReversedDocument
FROM [Your BKPF accounting document source] b
WHERE b.CREATED_AT >= '[Start timestamp]'
AND b.CREATED_AT < '[End timestamp]'
AND b.COMPANY_CODE IN ([Company code filter])
),
journal_attributes AS (
SELECT
a.COMPANY_CODE AS CompanyCode,
a.FISCAL_YEAR AS FiscalYear,
a.ACCOUNTING_DOCUMENT AS AccountingDocument,
MAX(a.VENDOR_NO) AS VendorNumber,
SUM(a.AMOUNT_IN_COMPANY_CODE_CURRENCY) AS AmountInCompanyCodeCurrency,
MAX(a.PURCHASING_DOCUMENT) AS PurchasingDocument,
MAX(a.CLEARING_DATE) AS ClearingDate,
MAX(a.CLEARING_DOCUMENT) AS ClearingDocument
FROM [Your ACDOCA universal journal source] a
WHERE a.COMPANY_CODE IN ([Company code filter])
AND a.POSTING_DATE >= '[Start date]'
AND a.POSTING_DATE < '[End date]'
GROUP BY
a.COMPANY_CODE,
a.FISCAL_YEAR,
a.ACCOUNTING_DOCUMENT
),
source_events AS (
SELECT
e.INV_DOC_NO AS InvoiceNumber,
e.COMPANY_CODE AS CompanyCode,
e.FISCAL_YEAR AS FiscalYear,
e.EVENT_TIMESTAMP AS EventTime,
e.EVENT_USER AS UserName,
e.PAYMENT_BLOCK_REASON AS PaymentBlockReason,
e.PURCHASING_DOCUMENT AS PurchasingDocument,
e.VENDOR_NO AS VendorNumber,
e.AMOUNT_IN_COMPANY_CODE_CURRENCY AS AmountInCompanyCodeCurrency,
e.PAYMENT_DUE_DATE AS PaymentDueDate,
e.DOCUMENT_TYPE AS DocumentType,
e.EVENT_TYPE AS SourceEventType
FROM [Your verified invoice event and workflow source] e
WHERE e.EVENT_TIMESTAMP >= '[Start timestamp]'
AND e.EVENT_TIMESTAMP < '[End timestamp]'
AND e.COMPANY_CODE IN ([Company code filter])
),
base_events AS (
SELECT
i.InvoiceNumber,
'Invoice Document Created' AS ActivityName,
i.InvoiceCreatedAt AS EventTime,
i.InvoiceCreatedBy AS UserName,
i.CompanyCode,
COALESCE(i.VendorNumber, j.VendorNumber) AS VendorNumber,
COALESCE(i.AmountInCompanyCodeCurrency, j.AmountInCompanyCodeCurrency) AS AmountInCompanyCodeCurrency,
i.PaymentDueDate,
i.DocumentType,
CAST(NULL AS NVARCHAR(20)) AS PaymentBlockReason,
COALESCE(i.PurchasingDocument, j.PurchasingDocument) AS PurchasingDocument
FROM invoice_base i
LEFT JOIN posted_accounting p
ON p.InvoiceNumber = i.InvoiceNumber
AND p.CompanyCode = i.CompanyCode
AND p.FiscalYear = i.FiscalYear
LEFT JOIN journal_attributes j
ON j.CompanyCode = p.CompanyCode
AND j.FiscalYear = p.FiscalYear
AND j.AccountingDocument = p.AccountingDocument
WHERE i.InvoiceCreatedAt IS NOT NULL
UNION ALL
SELECT
s.InvoiceNumber,
'Invoice Parked' AS ActivityName,
s.EventTime,
s.UserName,
s.CompanyCode,
COALESCE(s.VendorNumber, i.VendorNumber) AS VendorNumber,
COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency) AS AmountInCompanyCodeCurrency,
COALESCE(s.PaymentDueDate, i.PaymentDueDate) AS PaymentDueDate,
COALESCE(s.DocumentType, i.DocumentType) AS DocumentType,
s.PaymentBlockReason,
COALESCE(s.PurchasingDocument, i.PurchasingDocument) AS PurchasingDocument
FROM source_events s
LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PARKED'
UNION ALL
SELECT s.InvoiceNumber, 'Invoice Sent For Approval', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'SENT_FOR_APPROVAL'
UNION ALL
SELECT s.InvoiceNumber, 'Invoice Approved', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'APPROVED'
UNION ALL
SELECT s.InvoiceNumber, 'Invoice Rejected', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'REJECTED'
UNION ALL
SELECT s.InvoiceNumber, 'Invoice Data Updated', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'DATA_UPDATED'
UNION ALL
SELECT s.InvoiceNumber, 'Payment Block Set', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PAYMENT_BLOCK_SET'
UNION ALL
SELECT s.InvoiceNumber, 'Payment Block Removed', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PAYMENT_BLOCK_REMOVED'
UNION ALL
SELECT
i.InvoiceNumber,
'Invoice Posted',
p.PostedAt,
p.PostedBy,
i.CompanyCode,
COALESCE(i.VendorNumber, j.VendorNumber),
COALESCE(i.AmountInCompanyCodeCurrency, j.AmountInCompanyCodeCurrency),
i.PaymentDueDate,
i.DocumentType,
CAST(NULL AS NVARCHAR(20)),
COALESCE(i.PurchasingDocument, j.PurchasingDocument)
FROM invoice_base i
INNER JOIN posted_accounting p ON p.InvoiceNumber = i.InvoiceNumber AND p.CompanyCode = i.CompanyCode AND p.FiscalYear = i.FiscalYear
LEFT JOIN journal_attributes j ON j.CompanyCode = p.CompanyCode AND j.FiscalYear = p.FiscalYear AND j.AccountingDocument = p.AccountingDocument
WHERE p.PostedAt IS NOT NULL
UNION ALL
SELECT s.InvoiceNumber, 'Payment Proposal Created', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PAYMENT_PROPOSAL_CREATED'
UNION ALL
SELECT s.InvoiceNumber, 'Payment Executed', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PAYMENT_EXECUTED'
UNION ALL
SELECT s.InvoiceNumber, 'Late Payment Executed', s.EventTime, s.UserName, s.CompanyCode, COALESCE(s.VendorNumber, i.VendorNumber), COALESCE(s.AmountInCompanyCodeCurrency, i.AmountInCompanyCodeCurrency), COALESCE(s.PaymentDueDate, i.PaymentDueDate), COALESCE(s.DocumentType, i.DocumentType), s.PaymentBlockReason, COALESCE(s.PurchasingDocument, i.PurchasingDocument)
FROM source_events s LEFT JOIN invoice_base i ON i.InvoiceNumber = s.InvoiceNumber AND i.CompanyCode = s.CompanyCode AND i.FiscalYear = s.FiscalYear
WHERE s.SourceEventType = 'PAYMENT_EXECUTED'
AND s.EventTime > CAST(COALESCE(s.PaymentDueDate, i.PaymentDueDate) AS TIMESTAMP)
UNION ALL
SELECT
i.InvoiceNumber,
'Invoice Reversed',
p.ReversalEventAt,
p.ReversalUser,
i.CompanyCode,
COALESCE(i.VendorNumber, j.VendorNumber),
COALESCE(i.AmountInCompanyCodeCurrency, j.AmountInCompanyCodeCurrency),
i.PaymentDueDate,
i.DocumentType,
CAST(NULL AS NVARCHAR(20)),
COALESCE(i.PurchasingDocument, j.PurchasingDocument)
FROM invoice_base i
INNER JOIN [Your verified reversal event source] p ON p.INV_DOC_NO = i.InvoiceNumber AND p.COMPANY_CODE = i.CompanyCode AND p.FISCAL_YEAR = i.FiscalYear
LEFT JOIN journal_attributes j ON j.CompanyCode = p.COMPANY_CODE AND j.FiscalYear = p.FISCAL_YEAR AND j.AccountingDocument = p.ACCOUNTING_DOCUMENT
WHERE p.ReversalEventAt IS NOT NULL
)
SELECT
InvoiceNumber,
ActivityName,
EventTime,
UserName,
CompanyCode,
VendorNumber,
AmountInCompanyCodeCurrency,
PaymentDueDate,
DocumentType,
PaymentBlockReason,
PurchasingDocument
FROM base_events
WHERE InvoiceNumber IS NOT NULL
AND EventTime IS NOT NULL
ORDER BY InvoiceNumber, EventTime, ActivityName; ステップ
- ABAPエディタへのアクセス:SAP S/4HANAシステムにログインし、トランザクション
SE38(ABAPエディタ)を開きます。 - プログラムの作成:プログラム項目に新しいプログラム名を入力します。例:
Z_PM_INVOICE_EXTRACT。「作成」ボタンをクリックし、タイトルを入力して、タイプを「実行可能プログラム」に設定します。適切なパッケージに保存します。 - プログラム構造と選択画面の定義:エディタで、最終的なイベントログ出力用のデータ構造を定義します。次に、請求書入力日、会社コード、伝票タイプなどの期間をユーザーが入力できる選択画面を作成します。これにより、プログラムを再利用しやすく、柔軟に運用できます。
- データ選択ロジックの実装:各種SAPテーブルからデータを選択するABAP SQL文を記述します。プログラムは、必要な13種類のアクティビティごとに順番にクエリを実行します。
- ヘッダーデータと明細データの抽出:「Invoice Document Created」や「Invoice Posted」などの基本イベントについては、
RBKP(ロジスティクス請求書ヘッダー)やBKPF(会計伝票ヘッダー)などの主要テーブルからデータを選択します。 - 変更伝票データの抽出:「Payment Block Set」や「Payment Block Removed」などのアクティビティについては、変更伝票テーブル
CDHDR(変更伝票ヘッダー)とCDPOS(変更伝票明細)を検索します。たとえば、BSEGテーブルのZLSPRなど、特定フィールドへの変更を特定する必要があります。 - 支払データの抽出:支払い関連のアクティビティを取得するには、支払提案については
REGUP(支払プログラムの処理済み明細)、支払実行についてはBSAK(消込済み仕入先明細)などのテーブルを検索します。消込日(AUGDT)と正味支払期日(ZFBDT)を比較して、「Late Payment Executed」を区別します。 - ワークフローデータの抽出:承認アクティビティについては、
SWW_WI2OBJなどのSAP Business Workflowテーブルを検索し、ワークフローアイテムを請求書オブジェクトに関連付けます。この部分はワークフロー構成に大きく依存するため、大幅な調整が必要になる場合があります。 - データのイベントログ形式への統合:選択した各アクティビティのデータを、共通の内部テーブル構造に整形します。このテーブルの各行は1つのイベントを表し、ケース識別子(
InvoiceNumber)、ActivityName、EventTimeと、その他の推奨属性を含める必要があります。 - 出力ファイルの生成:ABAP文
OPEN DATASET、TRANSFER、CLOSE DATASETを使い、最終内部テーブルの内容をSAPアプリケーションサーバー上のフラットファイルに書き込みます。CSV形式を推奨します。 - スケジュールと実行:テストではフォアグラウンドで(
F8を使って)プログラムを実行します。本番実行では、トランザクションSM36を使ってオフピーク時間帯にバックグラウンドジョブとしてスケジュールし、システム性能への影響を避けます。 - 取得とアップロード:トランザクション
AL11を使って、ファイルを保存したアプリケーションサーバーのディレクトリへ移動します。ファイルをローカルシステムにダウンロードし、プロセスマイニングツールへアップロードする前に、UTF-8でエンコードされ、正しい形式になっていることを確認します。
設定
- 期間:請求書入力日(
RBKP-CPUDT)または転記日(BKPF-BUDAT)に基づき、抽出対象の期間を定義します。最初の分析では、データ量を管理しやすくするため、3~6か月の期間を推奨します。 - 会社コード(BUKRS):1つ以上の会社コードで絞り込むことが重要です。大規模な組織ですべての会社コードを抽出すると、実行時間が非常に長くなり、ファイルサイズも大きくなる可能性があります。
- 伝票タイプ(BLART):関連する伝票タイプで絞り込み、仕入先請求書を分離します。一般的なタイプには「RE」(請求書:総額)や「KR」(仕入先請求書)があります。これにより、分析に不要な伝票を除外できます。
- 仕入先勘定(LIFNR):特定の仕入先番号を対象とする任意のフィルターをプログラムに追加できます。対象を絞った分析やテストに便利です。
- 出力ファイル設定:アプリケーションサーバー上の出力ファイルパスと、カンマやセミコロンなどのフィールド区切り文字を定義するパラメータをプログラムに用意します。
- 前提条件:このプログラムを実行するユーザーまたはシステムアカウントには、ABAPプログラムを作成・実行するための開発者権限(
SE38経由)と、BKPF、BSEG、RBKP、RSEG、CDHDR、CDPOS、ワークフローテーブルなど、FI、MM、Basisテーブルに対する広範な読み取り権限が必要です。
a サンプルクエリ abap
REPORT Z_PM_INVOICE_EXTRACT.
* --- Internal table structure for the final event log
TYPES: BEGIN OF ty_s_event_log,
invoicenumber TYPE char25,
activityname TYPE char50,
eventtime TYPE char19, "YYYY-MM-DD HH:MM:SS
username TYPE sy-uname,
companycode TYPE bukrs,
vendornumber TYPE lifnr,
amountincompanycodecurrency TYPE wrbtr,
paymentduedate TYPE char10, "YYYY-MM-DD
documenttype TYPE blart,
paymentblockreason TYPE char1,
purchasingdocument TYPE ebeln,
END OF ty_s_event_log.
DATA: lt_event_log TYPE STANDARD TABLE OF ty_s_event_log.
DATA: ls_event_log TYPE ty_s_event_log.
* --- Selection Screen for user inputs
PARAMETERS: p_path TYPE string DEFAULT '/usr/sap/tmp/invoice_events.csv'.
SELECT-OPTIONS: s_erdat FOR sy-datum OBLIGATORY, " Entry Date
s_bukrs FOR bkpf-bukrs OBLIGATORY, " Company Code
s_blart FOR bkpf-blart. " Document Type
START-OF-SELECTION.
* --- 1. Invoice Document Created (from Logistics Invoice Verification)
SELECT CONCAT( rbkp~belnr, rbkp~gjahr ) AS invoicenumber,
'Invoice Document Created' AS activityname,
CONCAT( rbkp~cpudt, rbkp~cputm ) AS eventtime,
rbkp~usnam AS username,
rbkp~bukrs AS companycode,
rbkp~lifnr AS vendornumber,
rbkp~rmwwr AS amountincompanycodecurrency,
'' AS paymentduedate,
rbkp~blart AS documenttype,
rbkp~zuonr AS paymentblockreason,
'' AS purchasingdocument
FROM rbkp
INTO TABLE @DATA(lt_created)
WHERE rbkp~cpudt IN @s_erdat
AND rbkp~bukrs IN @s_bukrs
AND rbkp~blart IN @s_blart.
LOOP AT lt_created INTO DATA(ls_created).
ls_event_log-invoicenumber = ls_created-invoicenumber.
ls_event_log-activityname = ls_created-activityname.
ls_event_log-eventtime = |{ ls_created-eventtime(8) } { ls_created-eventtime+8(2) }:{ ls_created-eventtime+10(2) }:{ ls_created-eventtime+12(2) }|.
ls_event_log-username = ls_created-username.
ls_event_log-companycode = ls_created-companycode.
ls_event_log-vendornumber = ls_created-vendornumber.
ls_event_log-amountincompanycodecurrency = ls_created-amountincompanycodecurrency.
ls_event_log-paymentduedate = ''.
ls_event_log-documenttype = ls_created-documenttype.
ls_event_log-paymentblockreason = ''.
ls_event_log-purchasingdocument = ls_created-purchasingdocument.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
* --- 2. Invoice Parked (assuming status 'A' or 'B' in RBKP)
SELECT CONCAT( belnr, gjahr ) AS invoicenumber,
'Invoice Parked' AS activityname,
CONCAT( cpudt, cputm ) AS eventtime,
usnam AS username,
bukrs AS companycode,
lifnr AS vendornumber,
rmwwr AS amountincompanycodecurrency,
'' AS paymentduedate,
blart AS documenttype,
'' AS paymentblockreason,
'' AS purchasingdocument
FROM rbkp
INTO TABLE @DATA(lt_parked)
WHERE rbstat IN ('A', 'B')
AND cpudt IN @s_erdat
AND bukrs IN @s_bukrs
AND blart IN @s_blart.
LOOP AT lt_parked INTO DATA(ls_parked).
ls_event_log-invoicenumber = ls_parked-invoicenumber.
ls_event_log-activityname = ls_parked-activityname.
ls_event_log-eventtime = |{ ls_parked-eventtime(8) } { ls_parked-eventtime+8(2) }:{ ls_parked-eventtime+10(2) }:{ ls_parked-eventtime+12(2) }|.
ls_event_log-username = ls_parked-username.
ls_event_log-companycode = ls_parked-companycode.
ls_event_log-vendornumber = ls_parked-vendornumber.
ls_event_log-amountincompanycodecurrency = ls_parked-amountincompanycodecurrency.
ls_event_log-paymentduedate = ''.
ls_event_log-documenttype = ls_parked-documenttype.
ls_event_log-paymentblockreason = ''.
ls_event_log-purchasingdocument = ''.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
* --- 3, 4, 5. Sent For Approval, Approved, Rejected (Placeholder logic, needs adaptation)
* --- This logic is a generic template for SAP Business Workflow.
* --- Your implementation will vary. You must identify the correct workflow tasks.
SELECT obj.instid, wi.wi_cd, wi.wi_ct, wi.wi_stat, wi.wi_aagent
FROM sww_wi2obj AS obj
JOIN swwlog AS wi ON obj~instid = wi~wi_id
INTO TABLE @DATA(lt_workflow)
WHERE obj~typeid = 'BUS2081' " Business Object for Incoming Invoice
AND obj~catid = 'BO'
AND wi~wi_cd IN s_erdat.
LOOP AT lt_workflow INTO DATA(ls_workflow).
* --- This is a placeholder, adapt task IDs and logic
CASE ls_workflow-wi_stat.
WHEN 'STARTED'.
ls_event_log-activityname = 'Invoice Sent For Approval'.
WHEN 'COMPLETED'.
ls_event_log-activityname = 'Invoice Approved'.
WHEN 'CANCELLED'.
ls_event_log-activityname = 'Invoice Rejected'.
WHEN OTHERS.
CONTINUE.
ENDCASE.
* --- Code to get invoice details based on ls_workflow-instid needed here
* --- ... appending to lt_event_log ...
ENDLOOP.
* --- 6, 7, 8. Payment Block Set/Removed, Data Updated (from Change Docs)
SELECT h~objectid, h~username, h~udate, h~utime, p~fname, p~value_new, p~value_old
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectclas = p~objectclas AND h~objectid = p~objectid AND h~changenr = p~changenr
INTO TABLE @DATA(lt_changes)
WHERE h~objectclas = 'BELEGV'
AND h~udate IN s_erdat.
LOOP AT lt_changes INTO DATA(ls_change).
ls_event_log-invoicenumber = |{ ls_change-objectid+10(10) }{ ls_change-objectid(4) }|.
ls_event_log-username = ls_change-username.
ls_event_log-eventtime = |{ ls_change-udate } { ls_change-utime(2) }:{ ls_change-utime+2(2) }:{ ls_change-utime+4(2) }|.
IF ls_change-fname = 'ZLSPR'. " Payment Block
IF ls_change-value_old IS INITIAL AND ls_change-value_new IS NOT INITIAL.
ls_event_log-activityname = 'Payment Block Set'.
ls_event_log-paymentblockreason = ls_change-value_new.
ELSEIF ls_change-value_old IS NOT INITIAL AND ls_change-value_new IS INITIAL.
ls_event_log-activityname = 'Payment Block Removed'.
ls_event_log-paymentblockreason = ''.
ELSE.
CONTINUE.
ENDIF.
ELSE.
ls_event_log-activityname = 'Invoice Data Updated'.
ENDIF.
* --- Need to select other attributes based on invoice number
* --- ... appending to lt_event_log ...
ENDLOOP.
* --- 9. Invoice Posted
SELECT CONCAT( bkpf~belnr, bkpf~gjahr ) AS invoicenumber,
'Invoice Posted' AS activityname,
CONCAT( bkpf~cpudt, bkpf~cputm ) AS eventtime,
bkpf~usnam AS username,
bkpf~bukrs AS companycode,
bseg~lifnr AS vendornumber,
bseg~wrbtr AS amountincompanycodecurrency,
bseg~zfBDT AS paymentduedate,
bkpf~blart AS documenttype,
bseg~zlspr AS paymentblockreason,
bseg~ebeln AS purchasingdocument
FROM bkpf
JOIN bseg ON bkpf~bukrs = bseg~bukrs AND bkpf~belnr = bseg~belnr AND bkpf~gjahr = bseg~gjahr
INTO TABLE @DATA(lt_posted)
WHERE bkpf~cpudt IN @s_erdat
AND bkpf~bukrs IN @s_bukrs
AND bkpf~blart IN @s_blart
AND bseg~koart = 'K'. " Vendor line
LOOP AT lt_posted INTO DATA(ls_posted).
ls_event_log-invoicenumber = ls_posted-invoicenumber.
ls_event_log-activityname = ls_posted-activityname.
ls_event_log-eventtime = |{ ls_posted-eventtime(8) } { ls_posted-eventtime+8(2) }:{ ls_posted-eventtime+10(2) }:{ ls_posted-eventtime+12(2) }|.
ls_event_log-username = ls_posted-username.
ls_event_log-companycode = ls_posted-companycode.
ls_event_log-vendornumber = ls_posted-vendornumber.
ls_event_log-amountincompanycodecurrency = ls_posted-amountincompanycodecurrency.
ls_event_log-paymentduedate = ls_posted-paymentduedate.
ls_event_log-documenttype = ls_posted-documenttype.
ls_event_log-paymentblockreason = ls_posted-paymentblockreason.
ls_event_log-purchasingdocument = ls_posted-purchasingdocument.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
* --- 10. Payment Proposal Created
SELECT CONCAT( regup~belnr, regup~gjahr ) AS invoicenumber,
'Payment Proposal Created' AS activityname,
CONCAT( reguh~erfdt, reguh~erfzt ) AS eventtime,
reguh~erfbu AS username,
regup~bukrs AS companycode,
regup~lifnr AS vendornumber,
regup~wrbtr AS amountincompanycodecurrency,
'' AS paymentduedate,
regup~blart AS documenttype,
'' AS paymentblockreason,
'' AS purchasingdocument
FROM regup
JOIN reguh ON regup~laufd = reguh~laufd AND regup~laufi = reguh~laufi
INTO TABLE @DATA(lt_proposal)
WHERE reguh~erfdt IN @s_erdat
AND regup~bukrs IN @s_bukrs.
LOOP AT lt_proposal INTO DATA(ls_proposal).
ls_event_log-invoicenumber = ls_proposal-invoicenumber.
ls_event_log-activityname = ls_proposal-activityname.
ls_event_log-eventtime = |{ ls_proposal-eventtime(8) } { ls_proposal-eventtime+8(2) }:{ ls_proposal-eventtime+10(2) }:{ ls_proposal-eventtime+12(2) }|.
ls_event_log-username = ls_proposal-username.
ls_event_log-companycode = ls_proposal-companycode.
ls_event_log-vendornumber = ls_proposal-vendornumber.
ls_event_log-amountincompanycodecurrency = ls_proposal-amountincompanycodecurrency.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
* --- 11, 12. Payment Executed / Late Payment Executed
SELECT CONCAT( belnr, gjahr ) AS invoicenumber,
augdt,
zfBDT
FROM bsak
INTO TABLE @DATA(lt_cleared)
WHERE augdt IN @s_erdat
AND bukrs IN @s_bukrs.
LOOP AT lt_cleared INTO DATA(ls_cleared).
IF ls_cleared-augdt > ls_cleared-zfbdt.
ls_event_log-activityname = 'Late Payment Executed'.
ELSE.
ls_event_log-activityname = 'Payment Executed'.
ENDIF.
ls_event_log-invoicenumber = ls_cleared-invoicenumber.
ls_event_log-eventtime = |{ ls_cleared-augdt } 00:00:00|.
* --- Need to select other attributes based on invoice number
* --- ... appending to lt_event_log ...
ENDLOOP.
* --- 13. Invoice Reversed
SELECT CONCAT( stblg, stjah ) AS invoicenumber,
'Invoice Reversed' AS activityname,
CONCAT( cpudt, cputm ) AS eventtime,
usnam AS username,
bukrs AS companycode,
'' AS vendornumber,
'' AS amountincompanycodecurrency,
'' AS paymentduedate,
blart AS documenttype,
'' AS paymentblockreason,
'' AS purchasingdocument
FROM bkpf
INTO TABLE @DATA(lt_reversed)
WHERE stblg IS NOT NULL
AND cpudt IN @s_erdat
AND bukrs IN @s_bukrs.
LOOP AT lt_reversed INTO DATA(ls_reversed).
ls_event_log-invoicenumber = ls_reversed-invoicenumber.
ls_event_log-activityname = ls_reversed-activityname.
ls_event_log-eventtime = |{ ls_reversed-eventtime(8) } { ls_reversed-eventtime+8(2) }:{ ls_reversed-eventtime+10(2) }:{ ls_reversed-eventtime+12(2) }|.
ls_event_log-username = ls_reversed-username.
ls_event_log-companycode = ls_reversed-companycode.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
* --- Write internal table to CSV file
OPEN DATASET p_path FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc <> 0.
MESSAGE 'Error opening file.' TYPE 'E'.
ENDIF.
DATA: lv_line TYPE string.
FIELD-SYMBOLS: <fs_any> TYPE any.
* --- Header row
lv_line = 'InvoiceNumber,ActivityName,EventTime,UserName,CompanyCode,VendorNumber,AmountInCompanyCodeCurrency,PaymentDueDate,DocumentType,PaymentBlockReason,PurchasingDocument'.
TRANSFER lv_line TO p_path.
LOOP AT lt_event_log INTO ls_event_log.
CLEAR lv_line.
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE ls_event_log TO <fs_any>.
IF sy-subrc <> 0.
EXIT.
ENDIF.
IF sy-index = 1.
lv_line = <fs_any>.
ELSE.
CONCATENATE lv_line <fs_any> INTO lv_line SEPARATED BY ','.
ENDIF.
ENDDO.
TRANSFER lv_line TO p_path.
ENDLOOP.
CLOSE DATASET p_path.
WRITE: / 'Extraction complete. File saved to:', p_path. 始める準備はできましたか?
請求書処理の改善を今すぐ始めましょう。このテンプレートを、業務を大きく改善し、効率を高めるための第一歩としてご利用ください。
SAP S/4HANAの調達から支払いまでの請求書処理を今すぐ最適化
ボトルネックを特定し、請求書処理のサイクルタイムを30%以上短縮します。
クレジットカードは不要です。数分で設定できます。