Data Template: Purchase to Pay - Purchase Order
Your Purchase to Pay - Purchase Order Data Template
- Recommended attributes to collect
- Key activities to track
- Extraction guidance for SAP ECC
Purchase to Pay - Purchase Order Attributes
| Name | Description | ||
|---|---|---|---|
Activity Activity | The name of the specific business event or step that occurred within the purchase order lifecycle. | ||
Description This attribute describes a single step in the process, such as 'Purchase Order Created', 'Purchase Order Approved', or 'Goods Receipt Posted'. The sequence of these activities forms the process flow for each purchase order. Analyzing the sequence, frequency, and duration between activities is the core of process mining. It helps identify bottlenecks, rework loops, and deviations from the standard process, enabling targeted improvements and standardization efforts. Why it matters Activities define the steps of the process. Analyzing their sequence and timing reveals the actual process flow, bottlenecks, and deviations. Where to get Derived from various SAP tables and transaction logs, such as CDHDR/CDPOS for changes, EKBE for GR/IR, and EBAN for requisitions. Often requires a custom logic or extraction program to generate. Examples Purchase Order CreatedPurchase Order ApprovedGoods Receipt Posted | |||
Event Time EventTime | The precise date and time when the activity occurred. | ||
Description This timestamp marks the exact moment an event took place, such as the time a PO was approved or when a goods receipt was posted. It provides the chronological order for all activities within a case. Timestamps are fundamental for process mining as they enable all time-based analysis. This includes calculating cycle times between activities, identifying delays, analyzing process throughput, and measuring performance against service level agreements (SLAs). Why it matters This timestamp is critical for calculating all duration-based metrics, such as cycle times and bottlenecks, and for ordering events chronologically. Where to get Derived from various date and time fields in SAP tables, such as EKKO-AEDAT (Change Date), CDHDR-UDATE/UTIME (Change Log Timestamp), or EKBE-BUDAT (Posting Date). Examples 2023-04-15T10:05:31Z2023-04-16T14:22:00Z2023-05-01T09:00:15Z | |||
Purchase Order PurchaseOrder | The unique identifier for the Purchase Order (PO) document, serving as the primary case for tracking the procurement process. | ||
Description The Purchase Order number is the central identifier that links all activities from its creation to final goods receipt and completion. Each unique PO number represents a single instance of the procurement process. In process mining, this attribute is essential for reconstructing the end-to-end journey of each purchase. It allows for detailed analysis of cycle times, process variations, and compliance checks for every individual order, forming the foundation of the entire process model. Why it matters This is the core identifier that connects all related events, making it possible to analyze the complete lifecycle of each individual purchase order. Where to get Table: EKKO, Field: EBELN Examples 450001762345000176244500017625 | |||
Company Code CompanyCode | The identifier for the legal entity or company initiating the purchase. | ||
Description The Company Code represents an independent legal entity in SAP. All transactions are posted at the company code level, making it a fundamental organizational unit. Analyzing the process by Company Code allows for comparison of procurement efficiency and compliance across different business units or countries. It helps identify best practices in one entity that could be replicated elsewhere, or pinpoint specific units that are struggling with the process. Why it matters Represents the legal entity, enabling process performance comparison and compliance checks across different parts of the organization. Where to get Table: EKKO, Field: BUKRS Examples 10002100US01 | |||
Document Type DocumentType | A code that classifies different types of purchase orders. | ||
Description The Document Type is a configuration in SAP that controls the number range, field selection, and overall process flow for a purchase order. For example, there might be different types for standard POs, service POs, or stock transport orders. This attribute is a powerful dimension for analysis, as different document types often follow intentionally different processes. Filtering by document type allows for a more accurate, apples-to-apples comparison of cycle times and process flows. Why it matters Distinguishes between different kinds of purchasing processes (e.g., standard, service, return), which often have distinct paths and performance expectations. Where to get Table: EKKO, Field: BSART Examples NBFOUB | |||
Material Group MaterialGroup | A classification for grouping materials or services with similar characteristics. | ||
Description The Material Group, or purchase category, is used to classify the type of goods or services being procured. Examples include 'IT Hardware', 'Office Supplies', or 'Professional Services'. This attribute is crucial for spend analysis and understanding procurement patterns. It allows for filtering the process to analyze how different categories are handled, who approves them, and which vendors supply them. It is a key dimension in the 'Purchase Order Value Analysis' dashboard. Why it matters Allows for segmenting the process by product or service category, revealing different behaviors, cycle times, or vendors for different types of spend. Where to get Table: EKPO, Field: MATKL Examples 00101IT_HWCONSULT | |||
Order Amount OrderAmount | The total monetary value of the purchase order line item. | ||
Description This attribute represents the total value of a specific line item on the purchase order, calculated as quantity multiplied by the net price. For a full PO value, item amounts need to be aggregated. Analyzing the process by order amount is critical for identifying high-value transactions that may require more stringent controls or different approval paths. It powers the 'Purchase Order Value Analysis' dashboard and helps prioritize process improvement efforts on the most financially significant orders. Why it matters Quantifies the financial impact of each purchase, enabling value-based analysis to prioritize high-value orders or identify cost-saving opportunities. Where to get Table: EKPO, Field: NETWR (Net Order Value). Examples 1500.00250.7512345.50 | |||
User Name UserName | The user ID of the person who executed the activity. | ||
Description This attribute captures the SAP username of the employee who created, changed, or approved a document. For automated steps, it may show a system or batch user ID. Analyzing by user helps identify training needs, high-performing individuals, or potential compliance issues. It is key for building dashboards related to workload distribution, approval matrix compliance, and understanding the performance of different teams or individuals. Why it matters Attributes user actions to specific individuals, enabling analysis of user performance, workload, and adherence to compliance protocols. Where to get Table: EKKO, Field: ERNAM (Created by); Table: CDHDR, Field: USERNAME (Changed by). Examples JSMITHMBROWNBATCH_USER | |||
Vendor Number VendorNumber | The unique identifier for the vendor or supplier. | ||
Description This is the code that uniquely identifies the supplier from whom the goods or services are being procured. It is a critical piece of master data in the procurement process. This attribute is essential for vendor-centric analysis. It allows for the evaluation of vendor delivery performance, comparison of lead times across different suppliers, and analysis of spending patterns. It is the primary dimension for the 'Vendor Delivery Performance' dashboard. Why it matters Enables vendor performance analysis, helping to identify reliable suppliers and those causing delays or quality issues. Where to get Table: EKKO, Field: LIFNR Examples 100345V-20598700112 | |||
Currency Currency | The currency code for the purchase order amount. | ||
Description This attribute specifies the currency in which the purchase order value is denominated, such as USD, EUR, or GBP. It provides essential context for any monetary values. For global organizations, currency is essential for correct financial analysis. It allows for proper aggregation and comparison of order values, and all monetary KPIs must be interpreted in the context of their currency. Why it matters Provides necessary context for all monetary values, ensuring accurate financial analysis, especially in multinational organizations. Where to get Table: EKKO, Field: WAERS Examples USDEURJPY | |||
End-To-End Cycle Time EndToEndCycleTime | The total time elapsed from the first activity to the last activity for a purchase order. | ||
Description This metric measures the total duration of the entire purchase order process, from the earliest recorded event (e.g., 'Purchase Requisition Created') to the final event (e.g., 'Purchase Order Completed'). This is a critical KPI for measuring overall process efficiency. It provides a high-level view of performance, and its analysis helps identify the longest running cases and general bottlenecks. It directly supports the 'End-to-End PO Cycle Time Analysis' dashboard and the 'Avg End-to-End PO Cycle Time' KPI. Why it matters Measures the overall speed and efficiency of the entire procurement process, providing a key health indicator. Where to get This is a calculated attribute, determined by subtracting the timestamp of the first event from the timestamp of the last event for each case. Examples 10 days 4 hours22 days 1 hour5 days 8 hours | |||
Is On-Time Delivery IsOnTimeDelivery | A flag indicating if the goods were received on or before the requested delivery date. | ||
Description This boolean attribute is true if the 'Goods Receipt Posted' activity's timestamp is on or before the 'Requested Delivery Date'. It provides a clear, binary outcome for delivery performance on each PO line item. This attribute is the foundation for the 'On-Time Goods Receipt Rate' KPI. It simplifies the analysis of vendor performance and internal receiving efficiency by allowing for easy aggregation and filtering of on-time versus late deliveries. Why it matters Provides a clear success or failure metric for delivery timeliness, directly supporting vendor performance KPIs and dashboards. Where to get This is a calculated attribute derived by comparing the goods receipt posting date (EKBE-BUDAT) with the requested delivery date (EKPO-EINDT). Examples truefalse | |||
Is Post-Approval Change IsPostApprovalChange | A flag indicating if a PO change occurred after the initial approval. | ||
Description This boolean attribute is true if a 'Purchase Order Changed' activity is detected after a 'Purchase Order Approved' activity for the same PO. It helps isolate problematic changes that occur late in the process. This calculated field directly supports the 'Post-Approval PO Change Rate' KPI and the 'Purchase Order Rework and Changes' dashboard. It helps quantify and highlight disruptive changes that can cause delays and require re-approval, pointing to issues in the initial specification or scoping process. Why it matters Directly measures rework after approval, a key KPI for process stability and efficiency. High rates indicate problems in the upstream requirements definition. Where to get This is a calculated attribute derived from the sequence of activities in the event log. Examples truefalse | |||
Last Data Update LastDataUpdate | The timestamp indicating when the data was last refreshed from the source system. | ||
Description This attribute records the date and time of the most recent data extraction or update. It provides context on the freshness of the data being analyzed. Displaying this information in dashboards is vital for users to understand if the insights are based on near real-time data or a historical snapshot. It manages user expectations and ensures decisions are made based on data of a known age. Why it matters Informs users about the timeliness of the data, ensuring they understand if the analysis reflects the most current state of operations. Where to get This timestamp is generated and added by the data extraction or ETL process at the time of execution. Examples 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
Plant Plant | The physical location or plant where the goods are to be delivered. | ||
Description The Plant is an organizational unit representing a production facility, warehouse, or other location where goods or services are received. Analyzing by Plant helps understand geographical variations in the procurement process. It can reveal differences in vendor delivery times to certain locations or highlight specific plants that have inefficient receiving processes, supporting analysis of goods receipt timeliness. Why it matters Specifies the delivery location, which is useful for analyzing regional process differences and logistics performance. Where to get Table: EKPO, Field: WERKS Examples 100011002000 | |||
Purchase Requisition PurchaseRequisition | The identifier of the purchase requisition that preceded the purchase order. | ||
Description This attribute links the purchase order back to its originating purchase requisition. Not all POs will have a preceding requisition. This link is vital for analyzing the 'Requisition to Order Conversion' dashboard and the 'PR to PO Conversion Rate' KPI. It allows for measuring the efficiency of the upstream process, from the initial request to the creation of a formal order, and for identifying non-compliant POs created without a requisition. Why it matters Links the PO to its source request, enabling analysis of the PR-to-PO conversion process and identifying POs created without a prior requisition. Where to get Table: EKPO, Field: BANFN Examples 1001589010015891 | |||
Purchasing Group PurchasingGroup | The specific buyer or group of buyers responsible for the procurement activity. | ||
Description The Purchasing Group represents the individual or team of buyers responsible for a certain purchasing activity. They are the main point of contact for vendors. This attribute provides a more granular level of analysis than the Purchasing Organization. It helps in understanding workload distribution among buyers and identifying performance differences at the buyer level, which can inform resource allocation and training initiatives. Why it matters Provides a granular view of who is responsible for a purchase, allowing for detailed workload and performance analysis at the buyer or team level. Where to get Table: EKKO, Field: EKGRP Examples 001002N01 | |||
Purchasing Organization PurchasingOrganization | The organizational unit responsible for negotiating prices and procuring materials or services. | ||
Description The Purchasing Organization is a key organizational unit in SAP responsible for procurement activities. It can be centralized for the entire company or decentralized by plant or region. Analyzing process performance by Purchasing Organization helps identify which procurement teams are most efficient. It allows for comparing metrics like cycle time, rework rates, and costs across different organizational units, highlighting best practices and areas needing support. Why it matters Identifies the procurement team responsible, enabling performance comparisons and analysis across different organizational units. Where to get Table: EKKO, Field: EKORG Examples 1000US01DE01 | |||
Rejection Reason RejectionReason | The reason code or text explaining why a purchase requisition or order was rejected. | ||
Description This attribute captures the specific reason provided when a purchase order is rejected during the approval workflow. This information is crucial for understanding the root causes of rework and delays. Analyzing rejection reasons helps identify common issues such as incorrect pricing, budget overruns, or non-compliant vendor selection. This insight allows the business to address the root causes, improve the quality of initial PO creation, and streamline the approval process. Why it matters Provides direct insight into why approvals fail, enabling targeted improvements to reduce rework and shorten approval cycle times. Where to get This information can be difficult to locate. It may be stored in long text fields or depend on custom workflow configuration. Often requires specific implementation knowledge. Examples Incorrect priceBudget exceededDuplicate request | |||
Requested Delivery Date RequestedDeliveryDate | The date on which the business requested the vendor to deliver the goods or services. | ||
Description This is the target delivery date specified in the purchase order. It serves as the baseline against which actual delivery performance is measured. This date is essential for calculating the 'On-Time Goods Receipt Rate' KPI. By comparing the actual goods receipt date to this requested date, organizations can quantitatively measure vendor reliability and internal receiving efficiency, which directly supports the 'Vendor Delivery Performance' dashboard. Why it matters This is the target date for delivery, essential for calculating on-time performance KPIs and evaluating vendor reliability. Where to get Table: EKPO, Field: EINDT Examples 2023-06-102023-07-222023-08-01 | |||
Source System SourceSystem | The system from which the data was extracted. | ||
Description This attribute identifies the origin of the data, which is typically an SAP ECC instance identifier (e.g., 'ECC_PROD_100'). In environments with multiple systems, it helps differentiate data sources. For governance and data lineage, knowing the source system is crucial. It ensures data integrity and helps in troubleshooting data extraction or quality issues, especially when data is merged from different ERP systems or modules. Why it matters Identifies the data's origin, which is crucial for data governance, validation, and managing analyses across multiple systems. Where to get This is typically a static value added during the data extraction process to label the dataset with its system of origin. Examples SAP_ECC_PRODECC_EU_100S4H_FIN | |||
Vendor Name VendorName | The legal name of the vendor or supplier. | ||
Description The descriptive name of the vendor, which is more user-friendly than the vendor number. This is typically sourced from the vendor master data. While the Vendor Number is used for joins and unique identification, the Vendor Name is crucial for user-facing dashboards and reports. It makes analyses more intuitive and accessible to business users who may not be familiar with the vendor codes. Why it matters Provides a human-readable name for the vendor, making dashboards and reports much easier for business users to understand. Where to get Table: LFA1, Field: NAME1. This requires a join from EKKO-LIFNR to LFA1-LIFNR. Examples Staples Inc.Global Tech SolutionsOffice Supply Co. | |||
Purchase to Pay - Purchase Order Activities
| Activity | Description | ||
|---|---|---|---|
Goods Receipt Posted | This activity signifies the physical receipt of goods from a vendor against a specific purchase order. Posting the goods receipt is an explicit action (e.g., via transaction MIGO) that creates a material document and updates inventory. | ||
Why it matters This is a critical milestone for tracking vendor delivery performance and the start of the invoice verification process. It is used to calculate on-time delivery rates and goods receipt timeliness. Where to get Recorded upon the creation of a material document. The event timestamp is the posting date (MKPF-BUDAT) or creation date (MKPF-CPUDT) from the material document header table (MKPF), linked to the PO via the item table (MSEG). Capture Use the posting/creation timestamp from the MKPF table for material documents referencing the PO. Event type explicit | |||
Purchase Order Approved | Represents the final approval of the purchase order, authorizing it to be sent to the vendor. This key milestone is typically inferred from a change in the PO's release status to a 'fully released' or 'approved' state. | ||
Why it matters This activity is critical for calculating the PO Approval Cycle Time KPI and identifying bottlenecks in the approval workflow. It is a prerequisite for most subsequent activities like sending the order to the vendor. Where to get Inferred by tracking the change logs (CDHDR/CDPOS) for the Purchase Order header table (EKKO) to find when the final release code is applied or when the overall release status indicator (EKKO-FRGKE) is set to 'released'. Capture Identify the timestamp when the PO's overall release status (EKKO-FRGKE) changes to the final approved state. Event type inferred | |||
Purchase Order Completed | Indicates that a purchase order item is considered fully delivered. This is an inferred event, typically derived from the 'Delivery Completed' indicator being automatically or manually set on the purchase order item. | ||
Why it matters This activity serves as a logical end point for the order fulfillment part of the process. It is essential for calculating the end-to-end PO cycle time from creation to completion. Where to get Inferred from the change documents (CDHDR/CDPOS) that record when the 'Delivery Completed' indicator (EKPO-ELIKZ) is set to 'X' for a PO item. The last item being marked as complete can signify the completion of the whole PO. Capture Identify the timestamp from change documents when the EKPO-ELIKZ flag is set. Event type inferred | |||
Purchase Order Created | This activity signifies the creation of a formal purchase order document, which is a binding contract with a vendor. This is an explicit event, logged when a user creates and saves a PO (e.g., via transaction ME21N), resulting in entries in the EKKO and EKPO tables. | ||
Why it matters Marks the official start of the purchase order lifecycle. It serves as a key milestone for measuring both the PR-to-PO conversion time and the end-to-end order fulfillment time. Where to get Captured from the creation date (EKKO-AEDAT) in the Purchase Order header table (EKKO) for the corresponding PO number (EKKO-EBELN). Capture Use the creation timestamp from the EKKO table for each new Purchase Order. Event type explicit | |||
Purchase Order Sent to Vendor | This activity marks the point at which the approved purchase order is officially transmitted to the vendor, for example, via EDI, email, or print. It is an explicit event captured in the message control tables when an output message is successfully processed. | ||
Why it matters This is a critical milestone that starts the clock on vendor lead time. Analyzing the time from this event to goods receipt is key for evaluating vendor performance and delivery timeliness. Where to get Recorded in the message status table (NAST). The timestamp can be taken from NAST-DATVR and NAST-UHRVR when the processing status (NAST-VSTAT) is '1' (successfully processed) for the relevant PO output type. Capture Use the processing timestamp from the NAST table for the PO's output message. Event type explicit | |||
Purchase Requisition Created | This activity marks the creation of a formal request for goods or services. It is an explicit event captured when a user saves a new purchase requisition document (using transactions like ME51N), which generates a unique record in the EBAN table. | ||
Why it matters This is the primary starting point for the procurement process. Analyzing the time from this event to purchase order creation helps measure the efficiency of converting internal demand into actionable orders. Where to get Recorded upon the creation of an entry in the Purchase Requisition header table (EBAN). The creation date (EBAN-BADAT) and time serve as the timestamp for this event. Capture Identify new entries in the EBAN table based on creation date. Event type explicit | |||
Goods Returned | Represents the return of previously received goods to the vendor, often due to quality issues or incorrect shipments. This is an explicit event captured by posting a material document with a return-specific movement type. | ||
Why it matters This activity highlights problems with vendor quality or order accuracy and is a key indicator of process rework. It is crucial for calculating the Goods Receipt Variance Rate KPI. Where to get Recorded in the material document tables (MKPF/MSEG) when a return movement type (e.g., '122' for Return Delivery to Vendor) is used. The posting date (MKPF-BUDAT) serves as the timestamp. Capture Identify material documents with a return movement type (e.g., 122) that reference the original PO. Event type explicit | |||
Purchase Order Approval Requested | Indicates that a created or changed purchase order has been submitted for approval according to its configured release strategy. This event is inferred when the release strategy is triggered and the PO enters a pending approval status. | ||
Why it matters Differentiating between PO creation and the start of the approval process helps to precisely measure the approval cycle time KPI. It highlights any lag before the approval workflow begins. Where to get Inferred from change documents (CDHDR/CDPOS) for the Purchase Order (object EINKBELEG) that show the initial setting of a release status, or when the overall release status (EKKO-FRGKE) is first set to a value indicating an approval process is active. Capture Identify the first change document entry that triggers the release strategy for the PO. Event type inferred | |||
Purchase Order Changed | Represents any modification made to a purchase order after its initial creation, such as changes to quantity, price, or delivery dates. These changes are explicitly logged in SAP's change document system. | ||
Why it matters Frequent changes, especially after approval, indicate process inefficiencies, poor initial planning, or scope creep. This activity is essential for the PO Rework and Changes dashboard and related KPIs. Where to get Explicitly logged in the change document header (CDHDR) and item (CDPOS) tables for the Purchase Order object (EINKBELEG). Each change creates a new entry with a timestamp. Capture Extract change events and timestamps from CDHDR and CDPOS tables linked to the Purchase Order number. Event type explicit | |||
Purchase Order Deleted | Represents the cancellation or logical deletion of a purchase order item, preventing further processing like goods receipts or invoicing. This is an inferred event, captured when the deletion indicator is set on the PO item. | ||
Why it matters This is a terminal activity that indicates an order was cancelled. Analyzing why and when orders are deleted can uncover issues in demand planning or vendor selection. Where to get Inferred from change documents (CDHDR/CDPOS) that show the deletion indicator (EKPO-LOEKZ) being set to 'L' for a purchase order item. Capture Identify the timestamp from change documents when the EKPO-LOEKZ flag is set. Event type inferred | |||
Purchase Order Rejected | This activity occurs when an approver rejects a purchase order during the approval workflow. It is an inferred event, derived from a status change in the PO's release strategy data, indicating a rejection has occurred. | ||
Why it matters Tracking rejections helps identify issues with PO data quality, policy non-compliance, or problems within the approval matrix. It often leads to rework and increases overall cycle time. Where to get Inferred from change documents (CDHDR/CDPOS) for the purchase order release status. A rejection is typically recorded when a release code is cancelled or a specific rejection status is set. Capture Monitor change logs for the cancellation of a release code or a status change indicating rejection. Event type inferred | |||
Purchase Requisition Approved | Represents the formal approval of a purchase requisition, authorizing it to be converted into a purchase order. This event is inferred from changes in the release status fields within the purchase requisition data, as tracked by SAP's release strategy workflow. | ||
Why it matters Tracking approvals is crucial for identifying bottlenecks in the pre-ordering phase and ensuring compliance with approval policies. Delays here directly impact the overall procurement cycle time. Where to get Inferred from the change logs for the Purchase Requisition table (EBAN), specifically monitoring changes to the release status fields (e.g., EBAN-FRGZU) or by analyzing change documents in CDHDR/CDPOS for the EBAN object. Capture Monitor change documents for EBAN release status fields to identify the timestamp of the final approval. Event type inferred | |||
Quality Inspection Performed | Indicates that received goods have undergone a quality inspection. This activity is typically inferred when an inspection lot, created at the time of goods receipt, has a usage decision made against it in the Quality Management module. | ||
Why it matters For industries where quality is critical, this activity helps analyze the duration and outcomes of the inspection process. Delays here can create bottlenecks between goods receipt and availability for use. Where to get Inferred from the Quality Management module. An inspection lot is created (QALS table) upon goods receipt, and the activity is marked by the creation of a usage decision (QAVE table), which includes a timestamp. Capture Identify the timestamp of the usage decision in table QAVE for the inspection lot linked to the material document. Event type inferred | |||
Services Confirmation Entered | For service-based purchase orders, this activity represents the confirmation that services have been rendered. It is an explicit event captured through the creation of a Service Entry Sheet (e.g., via transaction ML81N). | ||
Why it matters This is the equivalent of a goods receipt for services and is essential for tracking the fulfillment of service orders. It triggers the financial process for service payment. Where to get Captured from the creation date (ESSR-ERDAT) in the Service Entry Sheet header table (ESSR). The link to the purchase order is in the ESLL table. Capture Use the creation timestamp from the ESSR table for service entry sheets linked to the PO. Event type explicit | |||
Extraction Guides
Steps
- Create ABAP Program: Open the ABAP Editor using transaction code
SE38. Enter a name for your new program, for exampleZ_PM_PO_EXTRACT, and click 'Create'. Provide a title like 'Process Mining PO Data Extraction' and set the type to 'Executable Program'. - Define Selection Screen: In the program, define the selection screen parameters. This allows users to filter the data they want to extract. Key parameters include the Purchase Order creation date range, Company Code (
BUKRS), and Purchasing Document Type (BSART). - Define Data Structures: Declare an internal table structure that matches the final event log format. This structure should include all required and recommended attributes:
PurchaseOrder,Activity,EventTime,UserName,VendorNumber,OrderAmount,MaterialGroup,CompanyCode, andDocumentType. - Implement Data Selection Logic: Write the core ABAP logic to select data for each of the 14 required activities. This involves querying multiple SAP tables like
EKKO,EKPO,EKBE,EBAN,CDHDR,CDPOS, andNAST. Use a separate subroutine (PERFORM) for each activity to keep the code organized. - Select Purchase Requisition Data: Query the
EBANtable for 'Purchase Requisition Created' events, linking them to Purchase Orders via theEKPOtable. Use the change log tables (CDHDR,CDPOS) to identify 'Purchase Requisition Approved' events by tracking changes to the release status fields. - Select Purchase Order Core Events: Query the
EKKOandEKPOtables for the 'Purchase Order Created' event. Use the change log tables (CDHDR,CDPOS) on objectEINKBELEGto extract 'Purchase Order Changed', 'Purchase Order Approved', 'Purchase Order Rejected', 'Purchase Order Completed', and 'Purchase Order Deleted' events based on changes to specific fields like release indicators and deletion flags. - Select PO Communication Events: Query the
NASTtable to find records where the PO was successfully transmitted, capturing the 'Purchase Order Sent to Vendor' activity. - Select Goods and Services Events: Query the
EKBEtable for material document postings to identify 'Goods Receipt Posted' and 'Goods Returned' activities based on the movement type category. QueryESSRandESLLfor service entry sheets to capture 'Services Confirmation Entered'. - Select Quality Management Events: If the Quality Management module is in use, query tables
QALSandQAVEto identify when a usage decision was made for an inspection lot linked to a PO, representing the 'Quality Inspection Performed' activity. - Combine and Format Data: Consolidate the data from all individual selections into a single final internal table. Ensure the
EventTimefield is formatted consistently (e.g.,YYYY-MM-DDTHH:MI:SS). - Implement File Download: Add functionality to download the final internal table as a file. The recommended format is a tab-separated or CSV file, which can be achieved using the
GUI_DOWNLOADfunction module. - Execute and Save: Execute the program using transaction
SE38orSA38. Fill in the selection criteria and run the report. When prompted, save the output file to your local machine with a.csvextension, ready for upload.
Configuration
- Date Range: It is crucial to define a specific date range for the extraction, typically based on the Purchase Order creation date (
EKKO-AEDAT). A range of 3-6 months is often a good starting point to balance data volume and process insight. - Company Code (
BUKRS): Filter by one or more company codes to limit the extraction to relevant legal entities. This is a key parameter for performance and relevance. - Purchasing Document Type (
BSART): Filter by specific document types (e.g., 'NB' for Standard PO) to focus the analysis on standard processes and exclude special procurement types if necessary. - Data Granularity: The extraction is designed for the purchase order item level. The Case ID is the Purchase Order number (
EBELN). All events, including those at the item level like goods receipts, are linked back to this main case ID. - Performance Considerations: For large datasets, schedule the program to run as a background job (
SM36) to avoid timeout errors. Ensure database indexes exist on key fields used inWHEREclauses, especially for tables likeCDHDRandCDPOS. - Prerequisites: The user running the report needs authorization to access the ABAP workbench (
SE38) for development and execution rights for the program. They also require read access to all underlying tables, includingEKKO,EKPO,EKBE,CDHDR,CDPOS,EBAN,NAST,ESSR, and QM tables.
a Sample Query abap
REPORT Z_PM_PO_EXTRACT.
TABLES: ekko, ekpo, eban.
*&---------------------------------------------------------------------*
*& Data Structures for Event Log
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
purchaseorder TYPE ebeln,
activity TYPE string,
eventtime TYPE timestamp,
username TYPE ernam,
vendornumber TYPE lifnr,
orderamount TYPE netwr_ak,
materialgroup TYPE matkl,
companycode TYPE bukrs,
documenttype TYPE bsart,
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_aedat FOR ekko-aedat OBLIGATORY, " PO Creation Date
s_bukrs FOR ekko-bukrs, " Company Code
s_bsart FOR ekko-bsart, " PO Document Type
s_ebeln FOR ekko-ebeln. " PO Number
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM get_po_headers.
IF gt_event_log IS NOT INITIAL.
PERFORM get_pr_created.
PERFORM get_pr_approved.
PERFORM get_po_created.
PERFORM get_po_release_events. " Approved, Rejected, Approval Requested
PERFORM get_po_sent_to_vendor.
PERFORM get_po_changed.
PERFORM get_goods_receipt_posted.
PERFORM get_services_confirmed.
PERFORM get_quality_inspection.
PERFORM get_goods_returned.
PERFORM get_po_completed.
PERFORM get_po_deleted.
PERFORM download_to_csv.
ELSE.
MESSAGE 'No Purchase Orders found for the given criteria.' TYPE 'I'.
ENDIF.
*&---------------------------------------------------------------------*
*& Form GET_PO_HEADERS (Base data)
*&---------------------------------------------------------------------*
FORM get_po_headers.
SELECT h~ebeln, h~lifnr, h~bukrs, h~bsart, p~netwr, p~matkl
FROM ekko AS h
INNER JOIN ekpo AS p ON h~ebeln = p~ebeln
INTO TABLE @DATA(lt_po_base)
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
AND h~ebeln IN @s_ebeln.
SORT lt_po_base BY ebeln.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_CREATED
*&---------------------------------------------------------------------*
FORM get_pr_created.
DATA: lt_pr_events TYPE TABLE OF ty_event_log.
SELECT p~ebeln AS purchaseorder,
'Purchase Requisition Created' AS activity,
b~erdat AS event_date,
'000000' AS event_time,
b~ernam AS username,
h~lifnr AS vendornumber,
p~netwr AS orderamount,
p~matkl AS materialgroup,
h~bukrs AS companycode,
h~bsart AS documenttype
FROM ekpo AS p
JOIN eban AS b ON p~banfn = b~banfn AND p~bnfpo = b~bnfpo
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~ebeln IN @s_ebeln
AND p~banfn IS NOT NULL AND p~banfn <> ''
AND h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
INTO TABLE @DATA(lt_pr_created).
LOOP AT lt_pr_created ASSIGNING FIELD-SYMBOL(<fs_pr>).
DATA(ls_event) = CORRESPONDING ty_event_log(<fs_pr>).
CONCATENATE <fs_pr>-event_date <fs_pr>-event_time INTO DATA(lv_ts).
CONVERT DATE <fs_pr>-event_date TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_APPROVED
*&---------------------------------------------------------------------*
FORM get_pr_approved.
DATA: lt_pr_list TYPE TABLE OF eban-banfn.
SELECT DISTINCT p~banfn FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND p~banfn IS NOT NULL AND p~banfn <> ''
INTO TABLE @lt_pr_list.
IF lt_pr_list IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~fname, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
FOR ALL ENTRIES IN @lt_pr_list
WHERE h~objectclas = 'BANF'
AND h~objectid = @lt_pr_list-table_line
AND p~tabname = 'EBAN'
AND p~fname = 'FRGZU'
INTO TABLE @DATA(lt_cd_pr).
LOOP AT lt_cd_pr ASSIGNING FIELD-SYMBOL(<fs_cd>) WHERE <fs_cd>-value_new = 'X'.
SELECT SINGLE p~ebeln, p~netwr, p~matkl, h~lifnr, h~bukrs, h~bsart
FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~banfn = @<fs_cd>-objectid(10)
INTO @DATA(ls_po_info).
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = ls_po_info-ebeln
activity = 'Purchase Requisition Approved'
username = <fs_cd>-username
vendornumber = ls_po_info-lifnr
orderamount = ls_po_info-netwr
materialgroup = ls_po_info-matkl
companycode = ls_po_info-bukrs
documenttype = ls_po_info-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CREATED
*&---------------------------------------------------------------------*
FORM get_po_created.
LOOP AT lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>).
SELECT SINGLE aedat, ernam FROM ekko INTO @DATA(ls_ekko)
WHERE ebeln = @<fs_po>-ebeln.
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Created'
username = ls_ekko-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE ls_ekko-aedat TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_RELEASE_EVENTS
*&---------------------------------------------------------------------*
FORM get_po_release_events.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
WHERE h~objectclas = 'EINKBELEG'
AND h~objectid IN lt_ebeln
AND p~tabname = 'EKKO'
AND p~fname = 'FRGKE'
INTO TABLE @DATA(lt_cd_po).
LOOP AT lt_cd_po ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
CASE <fs_cd>-value_new.
WHEN '2' OR 'R'. " Final Release
ls_event-activity = 'Purchase Order Approved'.
WHEN '1'. " Blocked
ls_event-activity = 'Purchase Order Rejected'.
WHEN OTHERS. " Any other change implies a pending state
ls_event-activity = 'Purchase Order Approval Requested'.
ENDCASE.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_SENT_TO_VENDOR
*&---------------------------------------------------------------------*
FORM get_po_sent_to_vendor.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT objky, erdat, eruhr, ernam
FROM nast
WHERE kapol = 'EF' AND objky IN lt_ebeln AND vstat = '1'
INTO TABLE @DATA(lt_nast).
LOOP AT lt_nast ASSIGNING FIELD-SYMBOL(<fs_nast>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_nast>-objky.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Sent to Vendor'
username = <fs_nast>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_nast>-erdat TIME <fs_nast>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CHANGED
*&---------------------------------------------------------------------*
FORM get_po_changed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT DISTINCT objectid, username, udate, utime
FROM cdhdr
WHERE objectclas = 'EINKBELEG' AND objectid IN lt_ebeln AND tcode <> 'ME21N' AND tcode <> 'ME22'
INTO TABLE @DATA(lt_cdhdr_chg).
LOOP AT lt_cdhdr_chg ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Changed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RECEIPT_POSTED
*&---------------------------------------------------------------------*
FORM get_goods_receipt_posted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam, k~bewtp
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bewtp = 'E' AND k~shkzg = 'S'
INTO TABLE @DATA(lt_gr).
LOOP AT lt_gr ASSIGNING FIELD-SYMBOL(<fs_gr>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_gr>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Receipt Posted'
username = <fs_gr>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_gr>-cpudt TIME <fs_gr>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_SERVICES_CONFIRMED
*&---------------------------------------------------------------------*
FORM get_services_confirmed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT l~ebeln, h~erdat, h~eruhr, h~ernam
FROM essr AS h JOIN esll AS l ON h~lblni = l~lblni
WHERE l~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_ses).
LOOP AT lt_ses ASSIGNING FIELD-SYMBOL(<fs_ses>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ses>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Services Confirmation Entered'
username = <fs_ses>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ses>-erdat TIME <fs_ses>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_QUALITY_INSPECTION
*&---------------------------------------------------------------------*
FORM get_quality_inspection.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT q~ebeln, v~vdatum, v~vzeit, v~vname
FROM qals AS q JOIN qave AS v ON q~prueflos = v~prueflos
WHERE q~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_qm).
LOOP AT lt_qm ASSIGNING FIELD-SYMBOL(<fs_qm>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_qm>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Quality Inspection Performed'
username = <fs_qm>-vname
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_qm>-vdatum TIME <fs_qm>-vzeit INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RETURNED
*&---------------------------------------------------------------------*
FORM get_goods_returned.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bwart = '122'
INTO TABLE @DATA(lt_ret).
LOOP AT lt_ret ASSIGNING FIELD-SYMBOL(<fs_ret>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ret>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Returned'
username = <fs_ret>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ret>-cpudt TIME <fs_ret>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_COMPLETED
*&---------------------------------------------------------------------*
FORM get_po_completed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'ELIKZ' AND p~value_new = 'X'
INTO TABLE @DATA(lt_cd_comp).
LOOP AT lt_cd_comp ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Completed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_DELETED
*&---------------------------------------------------------------------*
FORM get_po_deleted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'LOEKZ' AND p~value_new = 'L'
INTO TABLE @DATA(lt_cd_del).
LOOP AT lt_cd_del ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Deleted'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form DOWNLOAD_TO_CSV
*&---------------------------------------------------------------------*
FORM download_to_csv.
DATA: lv_filename TYPE string.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'PurchaseOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'EventTime' TO lt_fieldnames.
APPEND 'UserName' TO lt_fieldnames.
APPEND 'VendorNumber' TO lt_fieldnames.
APPEND 'OrderAmount' TO lt_fieldnames.
APPEND 'MaterialGroup' TO lt_fieldnames.
APPEND 'CompanyCode' TO lt_fieldnames.
APPEND 'DocumentType' TO lt_fieldnames.
DATA(lv_header) = REDUCE string( INIT h = '' FOR f IN lt_fieldnames NEXT h = h && f && cl_abap_char_utilities=>horizontal_tab ).
REPLACE LAST OCCURRENCE OF cl_abap_char_utilities=>horizontal_tab IN lv_header WITH cl_abap_char_utilities=>cr_lf.
DATA(lv_file_content) = lv_header.
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_log>).
DATA lv_line TYPE string.
DATA lv_eventtime_str TYPE string.
lv_eventtime_str = |{ <fs_log>-eventtime TIMESTAMP = ISO }|.
lv_line = <fs_log>-purchaseorder && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-activity && cl_abap_char_utilities=>horizontal_tab &&
lv_eventtime_str && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-username && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-vendornumber && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-orderamount && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-materialgroup && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-companycode && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-documenttype && cl_abap_char_utilities=>cr_lf.
CONCATENATE lv_file_content lv_line INTO lv_file_content.
ENDLOOP.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = 'C:\temp\po_event_log.csv'
filetype = 'ASC'
CHANGING
data_tab = lv_file_content.Steps
- Establish Database Connection: Obtain read-only credentials and connection details (hostname, port, database name) for the underlying SAP ECC database. Ensure you have the necessary client tools, like DBeaver, SQL Developer, or SSMS, installed.
- Identify SAP Schema: Connect to the database and identify the primary SAP schema where the tables are located. This is often
SAPSR3,SAPHANADB, or a similar system-specific name. You will need to prefix all table names in the query with this schema if it's not the default for your user. - Review the SQL Query: Open the provided SQL script in your client tool. This comprehensive query is designed to extract 14 distinct activities from the Purchase-to-Pay process by joining multiple SAP tables.
- Customize Query Parameters: Locate the
PO_BASECommon Table Expression (CTE) at the beginning of the script. Modify the placeholder values to define the scope of your extraction:[START_DATE]and[END_DATE]: Set the date range for the analysis (e.g., '20230101' and '20230630'). Filtering on theAEDAT(Changed On) field is recommended.[COMPANY_CODE_1],[COMPANY_CODE_2]: Specify the SAP Company Codes to include.[DOC_TYPE_1],[DOC_TYPE_2]: Specify the PO Document Types to include.[Your SAP Schema]: Replace this placeholder with your actual SAP schema name throughout the script.
- Execute the Query: Run the customized SQL script against the SAP database. The execution time will vary depending on the date range, data volume, and database performance.
- Inspect the Results: Once the query completes, perform a quick review of the output. Check for a reasonable number of rows and ensure that key columns like
PurchaseOrder,Activity, andEventTimeare populated as expected. - Export Data to CSV: Export the entire result set from your SQL client to a CSV file. Use UTF-8 encoding to prevent character issues.
- Prepare for Upload: Ensure the column headers in your CSV file match the required attribute names exactly:
PurchaseOrder,Activity,EventTime,UserName,VendorNumber,OrderAmount,MaterialGroup,CompanyCode,DocumentType. - Upload to Process Mining Tool: Upload the final CSV file to your process mining application for analysis and visualization.
Configuration
- Prerequisites: Direct, read-only access to the underlying SAP ECC database is required. Users need sufficient authorization to query tables like
EKKO,EKPO,EKBE,EBAN,CDHDR,CDPOS, andNAST. - Date Range Filtering: It is critical to apply a date range filter to limit the data volume. Filtering on
EKKO.AEDAT(PO Change Date) for a period of 3-6 months is a common starting point. Large date ranges can lead to extremely long query execution times. - Key Data Filters: To ensure a focused analysis, always filter on
EKKO.BUKRS(Company Code) andEKKO.BSART(Document Type). This narrows the scope to relevant legal entities and business processes. - Performance Considerations: The query joins several large tables, including the change history tables (
CDHDR,CDPOS). This can be resource-intensive. It is strongly recommended to run this extraction during off-peak hours or against a replicated, non-production database to avoid impacting system performance. - Change Document Logging: The accuracy of activities like 'Approved', 'Rejected', 'Completed', and 'Changed' depends on change document logging being active for the relevant fields in SAP. Confirm with your SAP administrator that this logging is enabled (via transaction
SCDO).
a Sample Query sql
WITH PO_BASE AS (
SELECT
H.EBELN, -- Purchase Order Number
I.EBELP, -- Purchase Order Item
H.LIFNR, -- Vendor Number
H.BUKRS, -- Company Code
H.BSART, -- Document Type
I.NETWR, -- Order Amount (Item Level)
I.MATKL, -- Material Group
I.BANFN, -- Purchase Requisition Number
I.BNFPO -- Purchase Requisition Item
FROM [Your SAP Schema].EKKO AS H
JOIN [Your SAP Schema].EKPO AS I ON H.EBELN = I.EBELN
WHERE H.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' -- Filter on PO Change Date, e.g., '20230101' and '20231231'
AND H.BUKRS IN ('[COMPANY_CODE_1]', '[COMPANY_CODE_2]') -- Specify Company Codes
AND H.BSART IN ('[DOC_TYPE_1]', '[DOC_TYPE_2]') -- Specify PO Document Types
)
-- 1. Purchase Requisition Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Created' AS "Activity",
TO_TIMESTAMP(CONCAT(pr.ERDAT, '000000'), 'YYYYMMDDHH24MISS') AS "EventTime", -- Time is not available in EBAN
pr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EBAN pr ON po.BANFN = pr.BANFN AND po.BNFPO = pr.BNFPO
WHERE po.BANFN IS NOT NULL AND po.BANFN <> ''
UNION ALL
-- 2. Purchase Requisition Approved
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Approved' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'BANF' AND ch.OBJECTID = po.BANFN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EBAN' AND cp.FNAME = 'FRGZU' AND cp.VALUE_NEW = 'X' -- Release indicator set to 'released'
UNION ALL
-- 3. Purchase Order Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Created' AS "Activity",
TO_TIMESTAMP(CONCAT(ekko.ERDAT, ' ', ekko.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
ekko.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (from Change Docs)
SELECT
po.EBELN AS "PurchaseOrder",
CASE
WHEN cp.VALUE_NEW > cp.VALUE_OLD THEN 'Purchase Order Approval Requested'
WHEN cp.VALUE_NEW = ekko.FRGKE AND ekko.FRGKE = 'R' THEN 'Purchase Order Approved'
ELSE 'Purchase Order Rejected' -- Simplified logic, may need adjustment
END AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKKO' AND cp.FNAME = 'FRGZU' -- Release status
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Sent to Vendor' AS "Activity",
TO_TIMESTAMP(CONCAT(na.ERDAT, ' ', na.ERUHR), 'YYYYMMDD HH24MISS') AS "EventTime",
na.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].NAST na ON na.OBJKY = po.EBELN AND na.KSCHL = '[Your PO Output Type]' -- e.g., 'NEU'
WHERE na.VSTAT = '1' -- Successfully processed
UNION ALL
-- 8. Purchase Order Changed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Changed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
WHERE ch.TCODE IN ('ME22', 'ME22N') -- Filter for change transactions
UNION ALL
-- 9. Goods Receipt Posted
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Receipt Posted' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Receipt
AND ekbe.SHKZG = 'S' -- Debit/Credit Indicator: Goods Receipt
UNION ALL
-- 10. Services Confirmation Entered
SELECT
po.EBELN AS "PurchaseOrder",
'Services Confirmation Entered' AS "Activity",
TO_TIMESTAMP(CONCAT(essr.ERDAT, ' ', essr.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
essr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].ESSR essr ON ekbe.LBLNI = essr.LBLNI
WHERE ekbe.BEWTP = 'L' -- Service Entry Sheet
UNION ALL
-- 11. Quality Inspection Performed
SELECT
po.EBELN AS "PurchaseOrder",
'Quality Inspection Performed' AS "Activity",
TO_TIMESTAMP(CONCAT(qave.VDATUM, ' ', qave.VZEIT), 'YYYYMMDD HH24MISS') AS "EventTime",
qave.VNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].QALS qals ON qals.MBLNR = ekbe.BELNR AND qals.MJAHR = ekbe.GJAHR
JOIN [Your SAP Schema].QAVE qave ON qals.PRUEFLOS = qave.PRUEFLOS
WHERE ekbe.BEWTP = 'E' -- Linked to a Goods Receipt
UNION ALL
-- 12. Goods Returned
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Returned' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Movement
AND ekbe.SHKZG = 'H' -- Debit/Credit Indicator: Return
AND ekbe.BWART = '122' -- Movement type for return to vendor
UNION ALL
-- 13. Purchase Order Completed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Completed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'ELIKZ' AND cp.VALUE_NEW = 'X' -- Delivery completed indicator
UNION ALL
-- 14. Purchase Order Deleted
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Deleted' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'LOEKZ' AND cp.VALUE_NEW = 'L'; -- Deletion indicatorSteps
- Prerequisites and Connection: Ensure your third-party ETL tool has the SAP Certified Connector installed and licensed. In your ETL tool's administration console, configure a new connection to your SAP ECC system. You will need the application server host, system number, client ID, and a dedicated SAP user with appropriate RFC and table read authorizations.
- Identify Source Tables: Within your ETL job or data flow, define the required SAP tables as data sources. The primary tables include EKKO (PO Header), EKPO (PO Item), EBAN (Purchase Requisition), CDHDR (Change Document Header), CDPOS (Change Document Item), MSEG (Document Segment: Material), MKPF (Material Document Header), NAST (Message Status), ESSR (Service Entry Sheet Header), and QALS (Inspection Lot).
- Extract 'Purchase Order Created': Create a data flow sourcing from the EKKO table. Filter records based on your desired date range (e.g., using
AEDAT) and organizational scope (e.g.,BUKRSfor Company Code,BSARTfor Document Type). Map EKKO.EBELN toPurchaseOrder, 'Purchase Order Created' toActivity, and combineAEDATandERZETfor theEventTime. Map other required attributes. - Extract 'Goods Receipt Posted': Create a separate data flow sourcing from MSEG and joining with MKPF on
MBLNRandMJAHR. Filter for relevant movement types, such as '101'. Map MSEG.EBELN toPurchaseOrder, 'Goods Receipt Posted' toActivity, and use MKPF.CPUDT and MKPF.CPUTM for theEventTime. - Extract Change-Based Events (Approvals, Changes, Deletions): Create a data flow sourcing from CDHDR and CDPOS, joined on
CHANGENR. This single source can be used to derive multiple activities.- Filter
OBJECTCLAS = 'EINKBELEG'andTABNAME = 'EKPO'. - For 'Purchase Order Approved', filter for changes to the release status field (e.g.,
FNAME = 'FRGZU') where the new value (VALUE_NEW) signifies final approval. - For 'Purchase Order Deleted', filter for changes to the deletion indicator (
FNAME = 'LOEKZ') where the new value is 'L'. - For 'Purchase Order Changed', filter for other relevant field changes, excluding the specific status fields used for other activities.
- For all these events, use CDHDR.UDATE and CDHDR.UTIME for the
EventTime.
- Filter
- Extract 'Purchase Requisition' Events: Create a data flow from EBAN for 'Purchase Requisition Created'. To link this to a
PurchaseOrdercase, join EBAN to EKPO using the requisition number (BANFN) and item (BNFPO). For 'Purchase Requisition Approved', use CDHDR/CDPOS withOBJECTCLAS = 'BANF'. This requires careful mapping to ensure the event is associated with the eventual PO. - Extract 'PO Sent to Vendor': Create a data flow sourcing from the NAST table. Filter on
OBJECTKEY(which contains the PO number), the relevant output type (KSCHL), and a successful processing status (VSTAT = '1'). UseERDATandUHRforEventTime. - Combine Activity Streams: Use a 'Union' or 'Merge' transformation in your ETL tool to combine the outputs of all the individual data flows created in the previous steps. Ensure the column names and data types are consistent across all streams (
PurchaseOrder,Activity,EventTime, etc.). - Data Type and Format Conversion: Ensure the
EventTimecolumn is converted to a consistent timestamp format (e.g.,YYYY-MM-DD HH:MM:SS). ConvertOrderAmountto a standard decimal format. - Define Target Destination: Configure a target or 'sink' for your combined data stream. This is typically a flat file, such as a CSV or Parquet file. Configure the delimiter, text qualifiers, and header options.
- Execute and Validate: Run the complete ETL job. Perform validation checks on the output file to ensure all 14 activities are present, row counts are reasonable, and key attributes are populated correctly.
- Schedule and Export: Once validated, schedule the ETL job for periodic execution (e.g., nightly) to keep the data fresh. The generated file is now ready to be uploaded to your process mining tool.
Configuration
- Prerequisites: A commercial ETL tool (e.g., Informatica PowerCenter, Talend, SAP Data Services) with the corresponding SAP Certified Connector for ECC. An SAP dialog or system user with authorizations to S_RFC and S_TABU_DIS for the required tables.
- SAP Connection: The connector must be configured with the SAP application server, system number, client, user, and password. Using Secure Network Communications (SNC) is recommended.
- Date Range Filter: It is critical to apply a date range filter to limit the data volume. A common practice is to filter
EKKO.AEDAT(PO Creation Date) for the last 3 to 12 months. This filter should be applied at the source to prevent extracting excessive data from SAP. - Organizational Scope Filters: Always filter by
EKKO.BUKRS(Company Code) and consider filtering byEKPO.WERKS(Plant) orEKKO.EKORG(Purchasing Organization) to narrow the analysis to a specific business unit. - Document Type Filter: Use
EKKO.BSARTto include only relevant purchase order types and exclude stock transfers or other internal documents that are not part of the standard P2P process. - Performance Tuning: Extracting from change document tables (CDHDR, CDPOS) can be slow. Ensure filters on
OBJECTCLAS,OBJECTID, andUDATEare applied. Adjust the 'Packet Size' setting in the SAP connector to optimize data transfer rates. For very large systems, consider an initial historical load followed by scheduled delta loads.
a Sample Query config
/*
This is a logical representation of the transformations performed within the ETL tool.
The tool's graphical interface will be used to configure these separate data flows, which are then combined with a UNION transformation.
Placeholders like [Your ETL Tool Functions] and [Filter Values] must be configured in the tool.
*/
-- 1. Purchase Requisition Created
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Created' AS Activity,
[Your ETL Tool Functions].DateTime(eban.ERDAT, eban.ERZET) AS EventTime,
eban.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM EBAN AS eban
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 2. Purchase Requisition Approved (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Approved' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EBAN AS eban ON cdhdr.OBJECTID = eban.BANFN
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'BANF' AND cdpos.TABNAME = 'EBAN' AND cdpos.FNAME = 'FRGZU' AND cdpos.VALUE_NEW = '[Final Release Indicator for PR]'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 3. Purchase Order Created
SELECT
EBELN AS PurchaseOrder,
'Purchase Order Created' AS Activity,
[Your ETL Tool Functions].DateTime(AEDAT, ERZET) AS EventTime,
ERNAM AS UserName,
LIFNR AS VendorNumber,
NULL AS OrderAmount, -- Amount is at item level
NULL AS MaterialGroup, -- Attribute is at item level
BUKRS AS CompanyCode,
BSART AS DocumentType
FROM EKKO
WHERE AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
CASE
WHEN cdpos.VALUE_NEW = '[Final Release Code]' THEN 'Purchase Order Approved'
WHEN cdpos.VALUE_NEW = '[Rejection Release Code]' THEN 'Purchase Order Rejected'
ELSE 'Purchase Order Approval Requested'
END AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKKO' AND cdpos.FNAME = 'FRGKE'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Sent to Vendor' AS Activity,
[Your ETL Tool Functions].DateTime(nast.ERDAT, nast.UHR) AS EventTime,
nast.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM NAST AS nast
INNER JOIN EKKO AS ekko ON nast.OBJKY = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE nast.KAPPL = 'EF' AND nast.VSTAT = '1' AND nast.KSCHL IN ([Your PO Output Types])
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 8. Purchase Order Changed (inferred from change documents, simplified example)
SELECT DISTINCT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Changed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.FNAME NOT IN ('FRGKE', 'FRGZU', 'LOEKZ', 'ELIKZ')
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 9. Goods Receipt Posted
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Receipt Posted' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '101' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 10. Services Confirmation Entered
SELECT
essr.EBELN AS PurchaseOrder,
'Services Confirmation Entered' AS Activity,
[Your ETL Tool Functions].DateTime(essr.ERDAT, essr.ERZET) AS EventTime,
essr.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM ESSR AS essr
INNER JOIN EKKO AS ekko ON essr.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON essr.EBELN = ekpo.EBELN AND essr.EBELP = ekpo.EBELP
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 11. Quality Inspection Performed
SELECT
qals.EBELN AS PurchaseOrder,
'Quality Inspection Performed' AS Activity,
[Your ETL Tool Functions].DateTime(qals.PASTRTERM, '000000') AS EventTime, -- Time is often not available
qals.PRUEFER AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM QALS AS qals
INNER JOIN EKKO AS ekko ON qals.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON qals.EBELN = ekpo.EBELN AND qals.EBELP = ekpo.EBELP
WHERE qals.VCODE <> '' -- A usage decision code exists
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 12. Goods Returned
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Returned' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '122' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 13. Purchase Order Completed (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Completed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'ELIKZ' AND cdpos.VALUE_NEW = 'X'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 14. Purchase Order Deleted (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Deleted' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'LOEKZ' AND cdpos.VALUE_NEW = 'L'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);