Data Template: Order to Cash - Sales Order Processing
Your Order to Cash - Sales Order Processing Data Template
- Recommended attributes to collect
- Key activities to track
- Extraction guidance for SAP ECC
Order to Cash - Sales Order Processing Attributes
| Name | Description | ||
|---|---|---|---|
Sales Order SalesOrder | The unique identifier for a sales order document, which serves as the primary case for tracking the entire Order-to-Cash process. | ||
Description The Sales Order is the central document in the sales process, representing a customer's request for goods or services. It contains all the information needed to process the customer's request from start to finish. In process mining, this attribute is used as the Case ID. Each unique Sales Order number represents one end-to-end process instance. Analyzing processes by Sales Order allows for tracking the complete lifecycle, measuring cycle times, and identifying variations for each individual customer order. Why it matters It is the essential key to link all related activities and events, enabling a complete end-to-end analysis of each customer order's journey. Where to get Found in the Sales Document Header Data table (VBAK) as the field VBELN. Examples 900001234590000123469000012347 | |||
Activity Activity | The name of a specific business step or event that occurred within the sales order process. | ||
Description This attribute describes a single step in the Order-to-Cash process, such as 'Sales Order Created', 'Delivery Created', or 'Payment Received'. These activities are the building blocks used to reconstruct the process flow for each sales order. Analyzing the sequence and timing of these activities is the core of process mining. It helps to visualize the process map, identify bottlenecks, discover process variants, and check for compliance against a standard model. Activities are typically derived from a combination of document creation events, status changes, or specific transaction codes recorded in the system. Why it matters Activities form the backbone of the process map, allowing for visualization and analysis of the process flow, deviations, and bottlenecks. Where to get This is a derived attribute, typically generated during data extraction by mapping SAP transaction codes (T-Codes), document status changes (e.g., from tables VBUK, VBUP), or change document logs (tables CDHDR, CDPOS) to user-friendly activity names. Examples Sales Order CreatedDelivery CreatedGoods IssuedInvoice CreatedPayment Received | |||
Last Data Update LastDataUpdate | Timestamp indicating when the data for this record was last refreshed from the source system. | ||
Description This attribute records the date and time of the most recent data extraction or update for a given event or case. It provides transparency into the freshness of the data being analyzed. In dashboards and reports, this information is crucial for users to understand the timeliness of the insights. It helps confirm if the analysis reflects the most current state of operations or if it is based on older data, managing user expectations about the data's recency. Why it matters Ensures users are aware of the data's freshness, which is critical for making timely and informed decisions based on the process mining analysis. Where to get This is a metadata attribute populated by the data extraction tool or process at the time of data ingestion. It is not stored in the source SAP tables. Examples 2024-06-10T05:00:00Z2024-06-11T05:00:00Z2024-06-12T05:00:00Z | |||
Source System SourceSystem | Identifies the source system from which the data was extracted. | ||
Description This attribute specifies the originating system, for example, a specific SAP ECC instance name or client number. It provides context for the data, especially in environments with multiple production systems or data from legacy systems. In analysis, it's used to filter or segment data based on its origin. This is particularly useful for comparing processes across different systems or during system migration projects to ensure data integrity and consistency. Why it matters Provides essential context, especially in multi-system landscapes, allowing for process comparison and ensuring data lineage is clear. Where to get This value is typically added during the data extraction process and is often a static value representing the SAP System ID (SAPSID) or client (MANDT). Examples ECC_PROD_800SAP_ERP_EU1ECC_QAS_300 | |||
Start Time StartTime | The timestamp indicating when an activity or event began. | ||
Description The Start Time, also known as the event timestamp, records the precise date and time that a specific activity occurred. For example, it would capture when a sales order was created, when goods were issued, or when an invoice was posted. This timestamp is fundamental for all time-based analysis in process mining. It is used to calculate cycle times between activities, measure the total duration of a case, and identify delays or bottlenecks. Accurate timestamps are critical for performance analysis dashboards, such as those monitoring on-time delivery or fulfillment lead times. Why it matters This is a critical attribute for calculating all performance metrics, such as cycle times and durations, which are essential for identifying bottlenecks. Where to get This is a composite attribute, typically derived by combining a date field (e.g., ERDAT) and a time field (e.g., ERZET) from various SAP tables like VBAK (Sales Order), LIKP (Delivery), and VBRK (Invoice). Examples 2023-04-15T09:00:12Z2023-04-16T14:30:00Z2023-04-20T11:22:45Z | |||
Customer Number CustomerNumber | The unique identifier for the customer who placed the sales order. | ||
Description This attribute represents the 'Sold-to Party', the primary customer account associated with the sales order. It links the transaction to a specific customer in the master data. Analyzing by customer number allows for segmenting the process to understand customer-specific behaviors and performance. It helps answer questions like which customers have the longest cycle times, highest rework rates, or most frequent order changes. This is crucial for improving customer relationship management and service levels. Why it matters Enables customer-centric analysis, helping to identify process issues affecting specific customers and to measure customer-specific performance. Where to get Found in the Sales Document Header Data table (VBAK) as the field KUNNR. Examples 100234100567200112 | |||
Delivery Block DeliveryBlock | A code indicating if a sales order is blocked for delivery, preventing the creation of a delivery document. | ||
Description The Delivery Block is a status set on a sales order (at header or item level) to temporarily halt the process before the delivery step. Blocks can be set manually by a user or automatically by the system due to reasons like credit limit failure or incomplete data. This attribute is critical for the 'Sales Order Blockage and Rework Analysis' dashboard. Analyzing the frequency, duration, and reasons for delivery blocks helps identify major bottlenecks in the fulfillment process. Reducing these blocks is key to improving on-time delivery and overall cycle time. Why it matters Directly identifies bottlenecks in the fulfillment process. Analyzing why and how often orders are blocked is crucial for improving flow efficiency. Where to get Found in the Sales Document Header Data table (VBAK) as the field LIFSK. Examples 0102Z1 | |||
Material Number MaterialNumber | The unique identifier for a product or service being sold. | ||
Description The Material Number identifies the specific item on a sales order line. Since a single sales order can contain multiple materials, this attribute is typically analyzed at the item level. Analyzing the process by Material Number helps uncover product-specific issues. It can reveal if certain products are associated with longer fulfillment times, higher rates of delivery blocks, or more frequent invoice discrepancies. This is crucial for supply chain and product management to optimize the process for different product lines. Why it matters Allows for product-based process analysis, revealing which products are associated with process inefficiencies like delays, blocks, or rework. Where to get Found in the Sales Document Item Data table (VBAP) as the field MATNR. Examples FG-1001-ARAW-205BSERV-INSTALL | |||
Net Amount NetAmount | The total value of the sales order, excluding taxes and discounts at the header level. | ||
Description Net Amount represents the monetary value of the sales order. It is a key financial metric associated with each process instance. This attribute is essential for value-based process mining. It allows for prioritizing process improvement initiatives by focusing on high-value orders. Analysts can correlate process issues, such as delays or rework, with financial impact, helping to build a stronger business case for change. For example, it can be used to analyze if high-value orders are processed more or less efficiently than low-value ones. Why it matters Enables value-based analysis, helping to prioritize improvement efforts on orders that have the most significant financial impact on the company. Where to get Found in the Sales Document Header Data table (VBAK) as the field NETWR. Examples 1500.0012550.75850.50 | |||
Rejection Reason RejectionReason | A code indicating the reason why a sales order item was rejected or cancelled. | ||
Description The Rejection Reason provides context for why a sales order or a specific line item was not fulfilled. This could be due to customer cancellation, product unavailability, or other business reasons. This attribute is essential for the 'Sales Order Cancellation Trends' dashboard. By analyzing the most common rejection reasons, a business can identify root causes for lost sales. This insight can drive improvements in inventory management, pricing strategy, or customer communication to reduce the order cancellation rate. Why it matters Provides the 'why' behind order cancellations, enabling root cause analysis to reduce lost sales and improve forecast accuracy. Where to get Found in the Sales Document Item Data table (VBAP) as the field ABGRU. Examples 0215Z5 | |||
Sales Order Cycle Time SalesOrderCycleTime | The total duration from the creation of the sales order to its final closure or payment. | ||
Description This calculated metric measures the end-to-end processing time for a single sales order. It is typically calculated as the difference between the timestamp of the very first activity ('Sales Order Created') and the very last activity (e.g., 'Payment Received' or 'Order Item Closed'). This attribute is the primary measure for the 'Sales Order End-to-End Cycle Time' dashboard and the Sales Order Fulfillment Cycle Time KPI. It provides a high-level view of process efficiency and is a critical metric for identifying long-running orders and overall process health. Analyzing the distribution of this metric helps to set benchmarks and track the impact of improvement initiatives over time. Why it matters This is the primary KPI for measuring overall process velocity and efficiency, providing a critical baseline for improvement initiatives. Where to get This is a calculated metric derived from the event log by taking the difference between the maximum and minimum StartTime for a given SalesOrder. Examples 10 days 4 hours25 days 11 hours5 days 2 hours | |||
Sales Organization SalesOrganization | The organizational unit responsible for the sale of products or services. | ||
Description A Sales Organization is a key organizational entity in SAP that structures the company according to its sales requirements. It is responsible for negotiating sales conditions and distributing goods and services. In process mining, this attribute is a critical dimension for analysis. It allows for comparing process performance, efficiency, and compliance across different sales units, regions, or divisions. This helps identify best practices in high-performing organizations and areas for improvement in others. Why it matters Allows for organizational benchmarking, enabling comparison of process efficiency and compliance across different business units or regions. Where to get Found in the Sales Document Header Data table (VBAK) as the field VKORG. Examples 100025003100 | |||
User User | The user ID of the employee who created or last changed the document or performed the activity. | ||
Description This attribute captures the SAP user ID responsible for a particular event in the process. For example, it identifies the sales clerk who created the order or the warehouse staff who posted the goods issue. Analyzing the process by user helps to understand workload distribution, identify training needs, and detect variations in how different users perform the same task. It is essential for dashboards focusing on resource performance, compliance, and identifying manual interventions. Why it matters Provides visibility into resource performance and workload, helps identify user-specific process deviations, and is key for compliance and automation analysis. Where to get Found in many SAP header tables as the 'Created by' field (ERNAM) or 'Changed by' field (AENAM), such as in VBAK, LIKP, VBRK. Examples CBURKEJSMITHRWILLIAMS | |||
Confirmed Delivery Date ConfirmedDeliveryDate | The date on which the delivery of the goods or services has been confirmed to the customer. | ||
Description This is the committed delivery date given to the customer, based on material availability and scheduling. It serves as the baseline for measuring delivery performance. This attribute is the foundation for the 'On-Time Delivery Performance' dashboard and the On-Time Delivery Rate KPI. By comparing the Confirmed Delivery Date with the actual 'Goods Issued' date, the analysis can determine whether an order was delivered on time, early, or late. This is a primary measure of supply chain reliability and customer satisfaction. Why it matters This is the benchmark for measuring on-time delivery performance, a critical KPI for customer satisfaction and supply chain efficiency. Where to get Found in the Sales Document Schedule Line table (VBEP) as the field EDATU. Examples 2023-05-102023-06-202023-07-01 | |||
Credit Check Status CreditCheckStatus | Indicates the status of the credit check for the sales document. | ||
Description This attribute shows the outcome of the automated or manual credit check performed on a sales order. Common statuses include 'Approved', 'Rejected', or 'Blocked'. This is a key attribute for the 'Credit Check Processing Time Analysis' dashboard. Delays or blocks at the credit check stage can significantly impact the overall order fulfillment cycle time. Analyzing this status helps to understand the efficiency of the credit management process and its impact on sales velocity. Why it matters Directly impacts order processing speed. Analyzing this status helps identify bottlenecks in credit management that delay order fulfillment. Where to get Found in the Sales Document Header Status table (VBUK) or directly in VBAK as the credit status field (e.g., CMGST). Examples ABD | |||
Is On-Time Delivery IsOnTimeDelivery | A boolean flag that indicates whether the goods were shipped on or before the confirmed delivery date. | ||
Description This calculated attribute compares the actual goods issue date with the 'ConfirmedDeliveryDate' for a sales order. If the goods issue date is on or before the confirmed date, it is marked as true, otherwise false. This attribute simplifies the creation of the 'On-Time Delivery Performance' dashboard and the calculation of the On-Time Delivery Rate KPI. It allows for easy aggregation and visualization of performance without needing to perform date comparisons on the fly within every analysis or chart. This provides a clear, at-a-glance measure of delivery reliability. Why it matters Provides a clear and simple measure of delivery performance, making it easy to calculate the overall On-Time Delivery Rate KPI. Where to get This is a calculated attribute. The logic compares the timestamp of the 'Goods Issued' activity with the value from the 'ConfirmedDeliveryDate' attribute. Examples truefalse | |||
Is Rework IsRework | A boolean flag indicating if a sales order has undergone a significant change or rework activity after initial creation. | ||
Description This calculated attribute identifies process instances that have experienced rework, such as one or more 'Sales Order Changed' activities. The specific logic for what constitutes rework, for example, a change to price, quantity, or delivery date, is defined during the project setup. This attribute is vital for the 'Sales Order Rework and Change Frequency' dashboard and the Sales Order Rework Rate KPI. It simplifies the analysis by allowing for direct filtering and comparison between orders that followed a 'straight-through' path versus those that required manual changes. This helps quantify the impact of rework on cycle times and costs. Why it matters Directly quantifies the frequency of rework, allowing for analysis of its causes and its impact on overall process efficiency and cycle time. Where to get This is a calculated attribute derived from the event log. The logic checks for the presence of 'Sales Order Changed' activities or specific change events from tables CDHDR/CDPOS. Examples truefalse | |||
Shipping Conditions ShippingConditions | Defines the general shipping strategy for the delivery of goods to the customer. | ||
Description Shipping Conditions determine how an order will be shipped, for example, 'Standard', 'Express', or 'Pickup'. This is agreed with the customer and influences logistics planning. This attribute is used in the 'Shipping Method Efficiency & Cost' analysis. By segmenting the process by shipping conditions, companies can analyze if certain methods are more prone to delays or have longer cycle times. This data helps optimize logistics and manage customer expectations regarding delivery times. Why it matters Enables analysis of logistics performance, helping to determine if certain shipping methods correlate with delays or higher efficiency. Where to get Found in the Sales Document Header Data table (VBAK) as the field VSBED. Examples 011020 | |||
Order to Cash - Sales Order Processing Activities
| Activity | Description | ||
|---|---|---|---|
Goods Issued | A critical event where ownership of the goods transfers and they officially leave the warehouse. This is an explicit financial posting that creates a material document and updates inventory. | ||
Why it matters This is the 'shipping' event and a key milestone for measuring on-time delivery and fulfillment lead times. It triggers financial updates and is a point of no return in the physical fulfillment process. Where to get Creation of a material document (MKPF/MSEG) with a goods issue movement type (e.g., 601), which is linked to the delivery document. Capture Creation of a material document (MKPF/MSEG) with a goods issue movement type, linked to the delivery. Event type explicit | |||
Invoice Created | Marks the creation of the customer invoice or billing document. This is an explicit event that generates a new document in the system, initiating the payment part of the process. | ||
Why it matters This is a crucial milestone that starts the clock on the 'Invoice to Payment Cycle Time'. Delays in invoicing directly impact cash flow. Where to get Recorded in the VBRK table (Billing Document: Header Data) based on its creation date (ERDAT). The link to the sales order or delivery is in the VBFA table. Capture Event based on creation timestamp (ERDAT) in VBRK table. Event type explicit | |||
Order Confirmed | This activity signifies that the sales order has passed all initial checks and is confirmed for fulfillment. It is typically inferred when the order is no longer blocked and has confirmed quantities in its schedule lines. | ||
Why it matters This is a major milestone that separates order entry from fulfillment. It is the starting point for measuring fulfillment lead times and on-time delivery performance. Where to get Can be inferred when schedule lines in VBEP have a confirmed quantity (BMENG > 0) and the order is not blocked for delivery (e.g., VBUK-LIFSK is empty). Capture Inferred from schedule line confirmation (VBEP-BMENG > 0) and removal of header-level blocks. Event type inferred | |||
Order Item Closed | This activity marks the final closure of a sales order item, indicating it is fully delivered, invoiced, and considered complete. This is inferred from the item's overall status. | ||
Why it matters Serves as the successful end event for the process. Analyzing when items close helps understand the end-to-end process duration and identify orders that remain open unnecessarily. Where to get Inferred from the overall status field in the VBUP table (Sales Document: Item Status) for the item. When VBUP-GBSTA is 'C' (Completely processed), the item is closed. Capture Inferred from item status (VBUP-GBSTA) changing to 'C' (Completely processed). Event type inferred | |||
Payment Received | This event signifies that the customer's payment has been received and applied to the invoice, clearing the open accounts receivable item. This is an accounting event, inferred from the clearing of a financial document. | ||
Why it matters This is the final step in realizing cash from the sale. It is the end point for measuring the 'Invoice to Payment Cycle Time' and overall 'Sales Order Fulfillment Cycle Time'. Where to get Inferred from the clearing document information in the BSEG table for the customer line item. When BSEG-AUGBL (Clearing Document) and BSEG-AUGDT (Clearing Date) are populated, payment is received. Capture Inferred from clearing date (AUGDT) population in the BSEG table for the AR line item. Event type inferred | |||
Sales Order Created | Marks the creation of a new sales order document. This is an explicit event captured when a user saves a new order, typically via transaction VA01 in SAP. | ||
Why it matters This is the primary start event for the Order-to-Cash process. Analyzing its timing is crucial for measuring overall cycle time and order intake rates. Where to get Recorded in the VBAK table (Sales Document Header Data) using the creation date (ERDAT) and time (ERZET). The transaction code is stored in VBAK-TCODE. Capture Event based on creation timestamp (ERDAT, ERZET) in VBAK table. Event type explicit | |||
Credit Check Performed | Indicates the completion of the automatic or manual credit check for the customer on the sales order. This is typically inferred from a change in the overall credit status of the document. | ||
Why it matters The credit check is often a critical bottleneck. Measuring the time taken for this step is essential for the 'Credit Check Processing Time Analysis' and for accelerating order processing. Where to get Inferred from the credit status fields in the VBUK table (Sales Document: Header Status). A change in VBUK-CMGST from blocked to released marks this activity. Capture Inferred from changes to the overall credit status field (VBUK-CMGST). Event type inferred | |||
Delivery Block Set | Represents an action where a delivery block is applied to the sales order, preventing the creation of a delivery document. This can be captured explicitly from change logs or inferred from status tables. | ||
Why it matters This activity directly relates to the 'Sales Order Blockage Rate' KPI. Identifying why and how often blocks are set helps uncover reasons for fulfillment delays. Where to get Can be found in change logs (CDHDR/CDPOS) for field VBAK-LIFSK. Alternatively, it's inferred by observing when the VBAK-LIFSK field is populated. Capture Event from change documents for field VBAK-LIFSK or VBAP-LIFSP. Event type explicit | |||
Delivery Created | This event marks the creation of the outbound delivery document, which is the instruction to the warehouse to begin picking and shipping activities. This is an explicit event captured from the document flow. | ||
Why it matters This is the first step in the physical fulfillment process. The time between order confirmation and delivery creation indicates how quickly the logistics process is initiated. Where to get The creation of a record in the LIKP table (SD Document: Delivery Header Data). The link to the sales order is maintained in the document flow table VBFA. Capture Event based on creation timestamp in LIKP table, linked via VBFA table. Event type explicit | |||
Invoice Cancelled | Represents the reversal of a previously created billing document. This is an explicit transaction that creates a new cancellation document to offset the original. | ||
Why it matters Tracking invoice cancellations helps identify issues with pricing, shipping discrepancies, or data errors. This supports the 'Invoice Discrepancy Rate' KPI. Where to get An explicit event captured by the creation of a cancellation billing document (VBRK-VBTYP = 'N' or 'O'). The original invoice is referenced in VBRK-SFAKN. Capture Creation of a cancellation document in VBRK, referencing the original invoice. Event type explicit | |||
Order Cancelled | Indicates that a sales order has been cancelled before fulfillment. This is typically captured by applying a 'reason for rejection' to all relevant items on the order. | ||
Why it matters This is a critical failure endpoint that directly supports the 'Order Cancellation Rate' KPI. Understanding when and why orders are cancelled provides insights into sales process issues. Where to get Inferred from the VBAP-ABGRU (Reason for rejection) field being populated for all active items on a sales order. The date of the change can be found in CDHDR/CDPOS. Capture Inferred by population of the 'Reason for Rejection' field (VBAP-ABGRU) on all items. Event type inferred | |||
Picking Completed | Signifies that all items for the delivery have been physically picked from the warehouse. If Warehouse Management (WM) is used, this can be inferred from the status of the Transfer Order. | ||
Why it matters Analyzing picking time helps optimize warehouse operations. Delays here directly impact the overall shipping timeline and fulfillment cycle. Where to get Inferred from the picking status of the delivery item in table LIPS-KOSTA changing to 'C' (fully picked). If WM is active, it can be inferred from Transfer Order confirmation (LTAK/LTAP tables). Capture Inferred from change in picking status (LIPS-KOSTA) or WM Transfer Order confirmation. Event type inferred | |||
Proof Of Delivery Confirmed | This activity represents the confirmation that the customer has received the goods. It is captured when the proof of delivery is recorded in the system, often updating the delivery document status. | ||
Why it matters This event provides the actual delivery date, which is essential for accurately measuring the 'On-Time Delivery Rate' against the promised date. Where to get Inferred from the proof of delivery status (VBUK-PODAT) being set to 'C' (Confirmed). The confirmation date is stored in VLPOD-PODAT. This is not always implemented. Capture Inferred from POD status update on the delivery (VBUK-PODAT) or VLPOD table entry. Event type inferred | |||
Sales Order Changed | Represents a modification made to an existing sales order after its initial creation. These changes are captured in dedicated change log tables (CDHDR, CDPOS) when fields like quantity, price, or dates are altered. | ||
Why it matters Tracking changes helps identify rework, process instability, and data quality issues. A high frequency of changes can indicate problems in the initial order entry process, leading to delays. Where to get Retrieved from change document tables CDHDR (header) and CDPOS (item) for OBJECTCLAS = 'VERKBELEG'. The timestamp and changed field can be identified. Capture Event from change document tables (CDHDR, CDPOS) for sales document objects. Event type explicit | |||
Extraction Guides
Steps
- Program Development: Using transaction
SE38orSE80, create a new executable ABAP program. This program will house the entire extraction logic. - Define Selection Screen: In your program, create a selection screen to filter the data. Include parameters for Sales Document Creation Date (
VBAK-ERDAT), Sales Organization (VBAK-VKORG), and Sales Document Type (VBAK-AUART). This makes the extraction reusable and manageable. - Data Declarations: Define the internal tables and structures needed to hold the data from various SAP tables (e.g.,
VBAK,VBAP,VBFA,CDHDR,CDPOS,VBRK,BSAD). Also, define the final output structure for the event log that matches the required attributes. - Select Base Sales Orders: Write the initial
SELECTstatement to retrieve sales order headers (VBAK) and items (VBAP) based on the user's selection screen inputs. This forms the core dataset of cases to be analyzed. - Extract 'Creation' Event: Loop through the selected
VBAKrecords. For each record, populate the event log structure with the 'Sales Order Created' activity, usingVBAK-ERDATandVBAK-ERZETfor theStartTime. - Extract Change Log Events: Select records from
CDHDRandCDPOSwhere theOBJECTCLASis 'VERKBELEG' for the selected sales orders. Loop through the results to identify specific field changes. For example, a change toVBAK-LIFSKindicates a 'Delivery Block Set', and a change toVBUK-CMGSTindicates a 'Credit Check Performed'. Any other relevant change can be logged as 'Sales Order Changed'. - Extract Document Flow Data: For the selected sales orders, query the document flow table (
VBFA). This table links sales orders to subsequent documents like deliveries, goods movements, and invoices. Select all related documents for further processing. - Extract Delivery and Fulfillment Events: Using the delivery document numbers from
VBFA, queryLIKPandLIPSfor 'Delivery Created' events. QueryMKPFandMSEGfor goods issue documents (movement type '601') to capture the 'Goods Issued' event. If Warehouse Management is active, queryLTAKandLTAPto find the confirmation time for the last transfer order item to determine 'Picking Completed'. Check delivery header statusVBUK-PODATfor 'Proof of Delivery Confirmed'. - Extract Invoicing and Payment Events: Using the billing document numbers from
VBFA, queryVBRKandVBRPto capture 'Invoice Created' and 'Invoice Cancelled' (whereVBRK-FKSTO= 'X') events. To find 'Payment Received', link the invoice fromVBRKto the accounting document inBKPF, then find the clearing document and clearing date inBSAD. - Extract Status-Based Events: Use the status tables
VBUP(Item Status) andVBUK(Header Status) to infer business events. For example, an item is considered 'Order Item Closed' whenVBUP-GBSTAequals 'C'. An order is 'Order Cancelled' when a 'Reason for Rejection' (VBAP-ABGRU) is set for all relevant items. - Consolidate and Format: Combine all captured events into a single final internal table. Ensure all attributes (
SalesOrder,Activity,StartTime,User, etc.) are correctly populated for each event record. Add theSourceSystemandLastDataUpdatetimestamps. - Generate Output File: Use the
GUI_DOWNLOADfunction module orcl_gui_frontend_services=>gui_downloadmethod to export the final internal table to a CSV file on the user's local machine. Ensure the file is saved with UTF-8 encoding.
Configuration
- Prerequisites: ABAP developer authorizations (e.g., access to transaction
SE38), and read permissions for all required SAP tables includingVBAK,VBAP,CDHDR,CDPOS,VBFA,LIKP,LIPS,VBRK,VBRP,MKPF,MSEG, andBSAD. - Selection Parameters: The program must include a selection screen with parameters for filtering. Key parameters are:
- Date Range: A mandatory date range for sales order creation (
VBAK-ERDAT). Start with a recent period of 3-6 months to keep the dataset manageable. - Sales Organization: Filter by
VBAK-VKORGto focus the analysis on specific business units. - Sales Document Type: Filter by
VBAK-AUARTto include only relevant order types (e.g., standard orders) and exclude others (e.g., quotes, returns).
- Date Range: A mandatory date range for sales order creation (
- Performance Considerations: Extracting from change log tables (
CDHDR,CDPOS) and document flow (VBFA) can be very slow for large data volumes. The program should be optimized to use index fields inWHEREclauses. For very large extractions, schedule the program to run as a background job during off-peak hours using transactionSM36. - Change Log Activation: This method relies on SAP's change document functionality. Verify that change logging is enabled for key data elements (e.g.,
LIFSK,CMGST,ABGRU). This can be checked via transactionSCDOfor objectVERKBELEG.
a Sample Query abap
REPORT Z_O2C_PM_EXTRACTOR.
*&---------------------------------------------------------------------*
*& Data Declarations
*&---------------------------------------------------------------------*
TABLES: vbak.
TYPES: BEGIN OF ty_event_log,
salesorder TYPE vbeln_va,
activity TYPE string,
starttime TYPE string,
sourcesystem TYPE logsys,
lastdataupdate TYPE string,
user TYPE ernam,
customernumber TYPE kunnr,
salesorganization TYPE vkorg,
netamount TYPE netwr,
materialnumber TYPE matnr,
deliveryblock TYPE lifsk,
rejectionreason TYPE abgru,
salesordercycletime TYPE string, " Placeholder for calculation
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
DATA: gs_event_log TYPE ty_event_log.
DATA: gv_sysid TYPE logsys.
DATA: gv_last_update TYPE string.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_erdat FOR vbak-erdat OBLIGATORY,
s_vkorg FOR vbak-vkorg,
s_auart FOR vbak-auart.
PARAMETERS: p_file TYPE rlgrap-filename OBLIGATORY DEFAULT 'C:\temp\o2c_event_log.csv'.
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
own_logical_system = gv_sysid.
CONCATENATE sy-datum sy-uzeit INTO gv_last_update.
PERFORM get_base_data.
PERFORM write_output_file.
*&---------------------------------------------------------------------*
*& Form get_base_data
*&---------------------------------------------------------------------*
FORM get_base_data.
TYPES: BEGIN OF ty_order_item,
vbeln TYPE vbeln_va,
posnr TYPE posnr_va,
erdat TYPE erdat,
erzet TYPE erzet,
ernam TYPE ernam,
kunnr TYPE kunnr,
vkorg TYPE vkorg,
netwr TYPE netwr_ak,
matnr TYPE matnr,
lifsk TYPE lifsk,
abgru TYPE abgru,
END OF ty_order_item.
DATA: lt_order_items TYPE TABLE OF ty_order_item.
SELECT h~vbeln i~posnr h~erdat h~erzet h~ernam h~kunnr h~vkorg h~netwr i~matnr h~lifsk i~abgru
INTO TABLE lt_order_items
FROM vbak AS h
INNER JOIN vbap AS i ON h~vbeln = i~vbeln
WHERE h~erdat IN s_erdat
AND h~vkorg IN s_vkorg
AND h~auart IN s_auart.
CHECK sy-subrc = 0.
DATA(lt_vbeln_range) = VALUE rsdsselopt_t(
FOR <fs_item> IN lt_order_items WHERE ( vbeln = <fs_item>-vbeln )
( sign = 'I' option = 'EQ' low = <fs_item>-vbeln ) ).
SORT lt_vbeln_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_vbeln_range COMPARING low.
PERFORM extract_order_created USING lt_order_items.
PERFORM extract_changes USING lt_vbeln_range lt_order_items.
PERFORM extract_doc_flow_events USING lt_vbeln_range lt_order_items.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_order_created
*&---------------------------------------------------------------------*
FORM extract_order_created USING it_order_items TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_item> TYPE any.
DATA: lt_unique_orders TYPE HASHED TABLE OF vbeln_va WITH UNIQUE KEY table_line.
lt_unique_orders = VALUE #( FOR <order> IN it_order_items ( CONV vbeln_va( <order>-vbeln ) ) ).
LOOP AT it_order_items ASSIGNING <fs_item> WHERE table_line IN lt_unique_orders.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Sales Order Created'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
gs_event_log-salesorganization = <fs_item>-vkorg.
gs_event_log-netamount = <fs_item>-netwr.
APPEND gs_event_log TO gt_event_log.
DELETE lt_unique_orders WHERE table_line = <fs_item>-vbeln.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_changes
*&---------------------------------------------------------------------*
FORM extract_changes USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_cdhdr TYPE TABLE OF cdhdr,
lt_cdpos TYPE TABLE OF cdpos.
SELECT * INTO TABLE lt_cdhdr FROM cdhdr
WHERE objectclas = 'VERKBELEG'
AND objectid IN it_vbeln_range
AND tcode = 'VA02'.
IF sy-subrc = 0.
SELECT * INTO TABLE lt_cdpos FROM cdpos
FOR ALL ENTRIES IN lt_cdhdr
WHERE objectclas = lt_cdhdr-objectclas
AND objectid = lt_cdhdr-objectid
AND changenr = lt_cdhdr-changenr.
ENDIF.
LOOP AT lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_cdhdr>-objectid ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_cdhdr>-objectid.
gs_event_log-user = <fs_cdhdr>-username.
CONCATENATE <fs_cdhdr>-udate <fs_cdhdr>-utime INTO gs_event_log-starttime.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
" Generic Change Event
gs_event_log-activity = 'Sales Order Changed'.
APPEND gs_event_log TO gt_event_log.
LOOP AT lt_cdpos ASSIGNING FIELD-SYMBOL(<fs_cdpos>)
WHERE objectclas = <fs_cdhdr>-objectclas
AND objectid = <fs_cdhdr>-objectid
AND changenr = <fs_cdhdr>-changenr.
CASE <fs_cdpos>-fname.
WHEN 'LIFSK'. " Delivery Block
gs_event_log-activity = 'Delivery Block Set'.
gs_event_log-deliveryblock = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
WHEN 'CMGST'. " Credit Status
IF <fs_cdpos>-value_new = 'B'. " B = Credit Check OK
gs_event_log-activity = 'Credit Check Performed'.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'ABGRU'. " Rejection Reason
IF <fs_cdpos>-value_new IS NOT INITIAL.
gs_event_log-activity = 'Order Cancelled'.
gs_event_log-rejectionreason = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_doc_flow_events
*&---------------------------------------------------------------------*
FORM extract_doc_flow_events USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_vbfa TYPE TABLE OF vbfa,
lt_vbrk TYPE TABLE OF vbrk,
lt_likp TYPE TABLE OF likp,
lt_mseg TYPE TABLE OF mseg,
lt_bsad TYPE TABLE OF bsad,
lt_vbup TYPE TABLE OF vbup.
SELECT * INTO TABLE lt_vbfa FROM vbfa
WHERE vbelv IN it_vbeln_range
AND ( vbtyp_n = 'J' " Delivery
OR vbtyp_n = 'M' " Invoice
OR vbtyp_n = 'N' " Invoice Cancellation
OR vbtyp_n = 'R' ). " Goods Movement
IF lt_vbfa IS INITIAL. RETURN. ENDIF.
SELECT vbeln, erdat, erzet, ernam, fksto, belnr FROM vbrk INTO TABLE lt_vbrk
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln
AND ( lt_vbfa-vbtyp_n = 'M' OR lt_vbfa-vbtyp_n = 'N' ).
SELECT vbeln, erdat, erzet, ernam, podat FROM likp INTO TABLE lt_likp
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln AND lt_vbfa-vbtyp_n = 'J'.
SELECT mblnr, mjahr, zeile, bwart, budat, cpuzt, usnam FROM mseg INTO TABLE lt_mseg
FOR ALL ENTRIES IN lt_vbfa
WHERE mblnr = lt_vbfa-vbeln AND mjahr = lt_vbfa-mjahr AND zeile = lt_vbfa-posnn AND lt_vbfa-vbtyp_n = 'R' AND bwart = '601'.
SELECT augdt, belnr, gjahr, kunnr FROM bsad INTO TABLE lt_bsad
FOR ALL ENTRIES IN lt_vbrk
WHERE belnr = lt_vbrk-belnr AND gjahr = SUBSTRING( val = lt_vbrk-erdat len = 4 ).
SELECT vbeln, posnr, gbsta FROM vbup INTO TABLE lt_vbup
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbelv AND posnr = lt_vbfa-posnv.
LOOP AT lt_vbfa ASSIGNING FIELD-SYMBOL(<fs_vbfa>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_vbfa>-vbelv ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_vbfa>-vbelv.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
gs_event_log-materialnumber = lv_order_info->matnr.
CASE <fs_vbfa>-vbtyp_n.
WHEN 'J'. " Delivery
READ TABLE lt_likp ASSIGNING FIELD-SYMBOL(<fs_likp>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Delivery Created'.
CONCATENATE <fs_likp>-erdat <fs_likp>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_likp>-ernam.
APPEND gs_event_log TO gt_event_log.
" Picking Completed - simplified logic, check status
gs_event_log-activity = 'Picking Completed'. APPEND gs_event_log TO gt_event_log.
" POD Confirmed
IF <fs_likp>-podat IS NOT INITIAL.
gs_event_log-activity = 'Proof Of Delivery Confirmed'.
gs_event_log-starttime = <fs_likp>-podat.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'R'. " Goods Issue
READ TABLE lt_mseg ASSIGNING FIELD-SYMBOL(<fs_mseg>) WITH KEY mblnr = <fs_vbfa>-vbeln mjahr = <fs_vbfa>-mjahr zeile = <fs_vbfa>-posnn.
IF sy-subrc = 0.
gs_event_log-activity = 'Goods Issued'.
CONCATENATE <fs_mseg>-budat <fs_mseg>-cpuzt INTO gs_event_log-starttime.
gs_event_log-user = <fs_mseg>-usnam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'M'. " Invoice
READ TABLE lt_vbrk ASSIGNING FIELD-SYMBOL(<fs_vbrk>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Invoice Created'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
" Payment Received
READ TABLE lt_bsad ASSIGNING FIELD-SYMBOL(<fs_bsad>) WITH KEY belnr = <fs_vbrk>-belnr.
IF sy-subrc = 0 AND <fs_bsad>-augdt IS NOT INITIAL.
gs_event_log-activity = 'Payment Received'.
gs_event_log-starttime = <fs_bsad>-augdt.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'N'. " Invoice Cancellation
READ TABLE lt_vbrk ASSIGNING <fs_vbrk> WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0 AND <fs_vbrk>-fksto = 'X'.
gs_event_log-activity = 'Invoice Cancelled'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
" Infer other events from status
LOOP AT lt_vbup ASSIGNING FIELD-SYMBOL(<fs_vbup>).
IF <fs_vbup>-gbsta = 'C'.
DATA(lv_order_info_stat) = REF #( it_order_items[ vbeln = <fs_vbup>-vbeln ] ).
IF lv_order_info_stat IS NOT BOUND. CONTINUE. ENDIF.
gs_event_log-salesorder = <fs_vbup>-vbeln.
gs_event_log-activity = 'Order Item Closed'.
" Timestamp for closed is harder, using current time as placeholder
CONCATENATE sy-datum sy-uzeit INTO gs_event_log-starttime.
gs_event_log-user = sy-uname.
gs_event_log-customernumber = lv_order_info_stat->kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
" Order Confirmed (Simplified - assumes if not blocked it's confirmed)
LOOP AT it_order_items ASSIGNING FIELD-SYMBOL(<fs_item>).
IF <fs_item>-lifsk IS INITIAL.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Order Confirmed'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form write_output_file
*&---------------------------------------------------------------------*
FORM write_output_file.
DATA: lt_final_output TYPE TABLE OF ty_event_log.
" Add common fields
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_event>).
<fs_event>-sourcesystem = gv_sysid.
<fs_event>-lastdataupdate = gv_last_update.
ENDLOOP.
SORT gt_event_log BY salesorder starttime.
DELETE ADJACENT DUPLICATES FROM gt_event_log COMPARING ALL FIELDS.
lt_final_output = gt_event_log.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'SalesOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'StartTime' TO lt_fieldnames.
APPEND 'SourceSystem' TO lt_fieldnames.
APPEND 'LastDataUpdate' TO lt_fieldnames.
APPEND 'User' TO lt_fieldnames.
APPEND 'CustomerNumber' TO lt_fieldnames.
APPEND 'SalesOrganization' TO lt_fieldnames.
APPEND 'NetAmount' TO lt_fieldnames.
APPEND 'MaterialNumber' TO lt_fieldnames.
APPEND 'DeliveryBlock' TO lt_fieldnames.
APPEND 'RejectionReason' TO lt_fieldnames.
APPEND 'SalesOrderCycleTime' TO lt_fieldnames.
DATA(lv_header) = REDUCE string(
INIT s = ''
FOR field IN lt_fieldnames
NEXT s = s && COND #( WHEN s = '' THEN field ELSE |,{ field }| ) ).
DATA: lt_file_content TYPE TABLE OF string.
APPEND lv_header TO lt_file_content.
LOOP AT lt_final_output INTO DATA(ls_output).
DATA(lv_line) = |"{ ls_output-salesorder }","{ ls_output-activity }","{ ls_output-starttime }","{ ls_output-sourcesystem }","{ ls_output-lastdataupdate }","{ ls_output-user }","{ ls_output-customernumber }","{ ls_output-salesorganization }",{ ls_output-netamount },"{ ls_output-materialnumber }","{ ls_output-deliveryblock }","{ ls_output-rejectionreason }","{ ls_output-salesordercycletime }"|.
APPEND lv_line TO lt_file_content.
ENDLOOP.
cl_gui_frontend_services=>gui_download(
EXPORTING
filename = p_file
filetype = 'ASC'
CHANGING
data_tab = lt_file_content ).
ENDFORM.Steps
- Prerequisites: Ensure you have direct, read-only access to the underlying SAP ECC database. You will need a database client tool such as DBeaver, SQL Server Management Studio, or Oracle SQL Developer to connect and execute queries.
- Obtain the SQL Script: Copy the complete SQL query provided in the 'query' section of this document.
- Connect to the Database: Open your database client and establish a connection to the SAP ECC database instance. You will need the server address, port, database name, and appropriate login credentials.
- Configure the Query: Paste the SQL script into a new query editor window. Locate the configuration section within the main Common Table Expression (CTE) named
SalesOrders. Replace the placeholder values for the start date ('{StartDate}'), end date ('{EndDate}'), sales organizations ('{SalesOrgs}'), and document types ('{DocTypes}') with the actual values for your analysis. - Execute the Query: Run the configured SQL script. Depending on the date range and the size of your SAP database, this query may take several minutes to complete.
- Review the Results: Once the query finishes, a result set will be displayed. Briefly scan the data to ensure it contains the expected columns (
SalesOrder,Activity,StartTime, etc.) and that rows are being returned for various activities. - Export the Data: Use your database client's export functionality to save the result set as a CSV file. Name the file something descriptive, like
SAP_O2C_Event_Log.csv. - Format for ProcessMind: Open the CSV file in a spreadsheet editor. Verify that the column headers match the required attributes exactly (e.g.,
SalesOrder,Activity,StartTime). Ensure the date and time format forStartTimeandLastDataUpdateis consistent and supported by ProcessMind, such asYYYY-MM-DD HH:MI:SS. - Upload to ProcessMind: Upload the final, formatted CSV file to your ProcessMind project for analysis.
Configuration
- Date Range: The query uses placeholders (
'{StartDate}'and'{EndDate}') to filter sales orders based on their creation date (VBAK.ERDAT). A typical analysis period is 3 to 6 months of data to ensure a representative sample without causing excessive database load. - Sales Organization Filter: Use the
'{SalesOrgs}'placeholder to limit the extraction to specific sales organizations (e.g.,'1000', '2000'). This is crucial for focusing the analysis and improving query performance. - Document Type Filter: Use the
'{DocTypes}'placeholder to select specific sales order types (e.g.,'OR'for Standard Order). This helps exclude irrelevant documents like free-of-charge deliveries or returns from the main process flow. - Source System Identifier: A hardcoded placeholder
'{SourceSystemName}'is used to tag every record with its system of origin. This should be set to a meaningful name for your SAP ECC instance (e.g.,SAP_ECC_PRD). - Database Compatibility: The function used for combining date and time fields,
[Your DB-specific timestamp function], is a placeholder. You must replace it with the correct function for your specific database (e.g.,TO_TIMESTAMP(CONCAT(CDHDR.UDATE, CDHDR.UZEIT), 'YYYYMMDDHH24MISS')for SAP HANA orCAST(CDHDR.UDATE AS DATETIME) + CAST(CDHDR.UZEIT AS DATETIME)for SQL Server). - Prerequisites: This method requires direct, read-only database credentials. The database user must have authorization to access all tables referenced in the query, including
VBAK,VBAP,VBFA,CDHDR,CDPOS,LIKP,VBRK, andBSAD.
a Sample Query sql
WITH SalesOrders AS (
SELECT VBELN
FROM VBAK
WHERE ERDAT BETWEEN '{StartDate}' AND '{EndDate}' -- Filter by creation date
AND VKORG IN ('{SalesOrgs}') -- Filter by Sales Organization(s)
AND AUART IN ('{DocTypes}') -- Filter by Sales Document Type(s)
)
-- 1. Sales Order Created
SELECT
vbak.VBELN AS "SalesOrder",
'Sales Order Created' AS "Activity",
[Your DB-specific timestamp function](vbak.ERDAT, vbak.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbak.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBAK vbak
JOIN SalesOrders so ON vbak.VBELN = so.VBELN
UNION ALL
-- 2. Sales Order Changed
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Sales Order Changed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG' AND cdhdr.TCODE IN ('VA02')
UNION ALL
-- 3. Credit Check Performed (Release)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Credit Check Performed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'CMGST'
AND cdpos.VALUE_NEW = 'B' -- Credit status 'Released'
UNION ALL
-- 4. Order Confirmed (Overall status not blocked)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Order Confirmed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'GBSTK'
AND cdpos.VALUE_OLD <> 'A' AND cdpos.VALUE_NEW = 'A' -- Status changes to 'Not yet processed'
UNION ALL
-- 5. Delivery Block Set
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Delivery Block Set' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
cdpos.VALUE_NEW AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAK'
AND cdpos.FNAME = 'LIFSK'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> ''
UNION ALL
-- 6. Delivery Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Delivery Created' AS "Activity",
[Your DB-specific timestamp function](likp.ERDAT, likp.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
UNION ALL
-- 7. Picking Completed
SELECT
vbfa.VBELV AS "SalesOrder",
'Picking Completed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN CDHDR cdhdr ON vbfa.VBELN = cdhdr.OBJECTID
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
AND cdhdr.OBJECTCLASS = 'LIEFERUNG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'PKSTK'
AND cdpos.VALUE_NEW = 'C'
UNION ALL
-- 8. Goods Issued
SELECT
vbfa_gi.VBELV AS "SalesOrder",
'Goods Issued' AS "Activity",
[Your DB-specific timestamp function](mkpf.BUDAT, mkpf.CPUTM) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
mkpf.USNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa_gi
JOIN SalesOrders so ON vbfa_gi.VBELV = so.VBELN
JOIN MKPF mkpf ON vbfa_gi.VBELN = mkpf.XBLNR -- XBLNR is Reference Document Number
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa_gi.VBTYP_V = 'J' AND vbfa_gi.VBTYP_N = 'R'
UNION ALL
-- 9. Proof Of Delivery Confirmed
SELECT
vbfa.VBELV AS "SalesOrder",
'Proof Of Delivery Confirmed' AS "Activity",
[Your DB-specific timestamp function](likp.PODAT, '000000') AS "StartTime", -- PODAT is only a date
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.AENAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J' AND likp.PODAT IS NOT NULL AND likp.PODAT <> '00000000'
UNION ALL
-- 10. Invoice Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Created' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
UNION ALL
-- 11. Invoice Cancelled
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Cancelled' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'M' AND vbfa.VBTYP_N = 'N'
UNION ALL
-- 12. Payment Received
SELECT
vbfa.VBELV AS "SalesOrder",
'Payment Received' AS "Activity",
[Your DB-specific timestamp function](bsad.AUGDT, '000000') AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
NULL AS "User", -- Clearing user not readily available here
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN BSAD bsad ON vbrk.VBELN = bsad.VBLNR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
AND bsad.AUGDT IS NOT NULL AND bsad.AUGDT <> '00000000'
UNION ALL
-- 13. Order Item Closed
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Item Closed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
vbap.ABGRU AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUP'
AND cdpos.FNAME = 'GBSTA'
AND cdpos.VALUE_NEW = 'C' -- Item is completely processed
UNION ALL
-- 14. Order Cancelled
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Cancelled' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
cdpos.VALUE_NEW AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAP'
AND cdpos.FNAME = 'ABGRU'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> '';