Your Record to Report - Journal Entry Data Template
Your Record to Report - Journal Entry Data Template
- Recommended attributes for comprehensive analysis
- Key journal entry activities to track
- Practical data extraction guidance for SAP ECC
Record to Report - Journal Entry Attributes
| Name | Description | ||
|---|---|---|---|
| Activity Name ActivityName | The name of the business activity or event that occurred at a specific point in the journal entry process. | ||
| Description The Activity Name describes a specific step in the journal entry lifecycle, such as 'Journal Entry Created', 'Journal Entry Approved', or 'Journal Entry Posted'. This attribute is typically derived from multiple sources in SAP, including transaction codes (TCODE), change document logs (tables CDHDR and CDPOS), and document status fields. Analyzing activities is the core of process mining. It allows for the visualization of process maps, calculation of transition times between steps, and identification of rework loops (e.g., 'Journal Entry Rejected' followed by 'Journal Entry Corrected'). This data is fundamental for dashboards related to cycle times, rework rates, and process variants. Why it matters It defines the steps in the process map, making it possible to visualize, analyze, and optimize the journal entry workflow. Where to get Derived from various sources, including transaction codes in BKPF (TCODE), document status, and workflow logs in tables like SWW_WI2OBJ, or change documents in CDHDR and CDPOS. Examples Journal Entry CreatedJournal Entry ApprovedJournal Entry RejectedJournal Entry Posted | |||
| Event Time EventTime | The timestamp indicating when a specific activity or event occurred for the journal entry. | ||
| Description Event Time provides the exact date and time for each activity in the journal entry process. This data is critical for calculating all time-based metrics, such as cycle times, processing durations, and delays between steps. The source of this timestamp varies depending on the activity; it can be the document creation date/time (CPUDT/CPUTM) or change timestamps from logs (CDHDR-UDATE/UTIME). In analysis, Event Time is used to order events chronologically, forming the basis of the process map. It is essential for calculating all KPIs related to time, such as Average Journal Entry Cycle Time, Average Approval Time, and Time from Approval to Posting. Why it matters This timestamp is the foundation for all time-related analysis, enabling the calculation of cycle times, durations, and bottlenecks. Where to get Sourced from various fields depending on the activity, primarily creation timestamp (CPUDT, CPUTM) from BKPF or change document timestamps (UDATE, UTIME) from CDHDR. Examples 2023-10-26T09:00:00Z2023-10-26T14:30:15Z2023-10-27T11:05:00Z | |||
| Journal Entry ID JournalEntryId | The unique identifier for a financial accounting document, combining company code, document number, and fiscal year. | ||
| Description The Journal Entry ID is the primary case identifier for tracking the lifecycle of a journal entry. It is a composite key, typically formed by concatenating the Company Code (BUKRS), Document Number (BELNR), and Fiscal Year (GJAHR) to ensure uniqueness across the entire SAP system. In process analysis, this ID links all related activities, such as creation, parking, submission, approval, rejection, and posting. By tracing this identifier, we can construct the end-to-end journey of each journal entry, measure cycle times, and identify process deviations or bottlenecks for specific entries. Why it matters This is the essential key for tracking a journal entry from its creation to its final posting, enabling end-to-end process analysis and variant comparison. Where to get This is a derived attribute, typically a concatenation of fields from the BKPF table: Company Code (BUKRS), Document Number (BELNR), and Fiscal Year (GJAHR). Examples 1000-1000000123-20232000-1900000456-20231000-1800000789-2024 | |||
| Last Data Update LastDataUpdate | The timestamp indicating when the data was last extracted or refreshed from the source system. | ||
| Description This attribute records the date and time of the most recent data pull from SAP ECC. It is a metadata field that is critical for understanding the freshness and currency of the data being analyzed. In any process mining dashboard or analysis, knowing the last update time is crucial for users to trust the data and make informed decisions. It helps answer the question, 'How up-to-date is this information?'. Why it matters Informs users about the freshness of the data, ensuring they understand the time frame of the analysis and can trust the results. Where to get This is a metadata field generated and stored by the data extraction tool or ETL process at the time of data refresh. Examples 2024-05-20T04:00:00Z2024-05-21T04:00:00Z2024-05-22T04:00:00Z | |||
| Source System SourceSystem | The system from which the process data was extracted. | ||
| Description This attribute identifies the origin of the data, which in this case is the specific SAP ECC instance. It is typically a static value added during the data extraction process. While simple, this attribute is important in environments with multiple ERPs or data sources. It ensures data lineage is clear and allows for filtering or segmenting analysis by the system of origin. Why it matters Provides clear data lineage and is essential for tracking data quality, especially in environments with multiple source systems. Where to get This is typically a static value added during the data transformation process, identifying the specific SAP ECC instance (e.g., 'ECC_PROD_100'). Examples SAP ECC EHP8ECC_FIN_PRODSAP_ERP_60 | |||
| Company Code CompanyCode | The organizational unit representing an independent legal entity for which financial statements are prepared. | ||
| Description The Company Code is a fundamental organizational unit in SAP Financials. It represents a legally independent company and is a key field in the journal entry document header. This attribute is essential for segmenting process analysis by legal entity. It allows for comparing process performance, compliance rates, and KPI results across different parts of the business. For example, it can help identify if approval delays or high reversal rates are specific to certain company codes. Why it matters Allows for filtering and comparing process performance across different legal entities or business units within the organization. Where to get Located in the document header table BKPF, field BUKRS. Examples 10002000US01DE01 | |||
| Document Type DocumentType | A classification for accounting documents that controls how they are processed and stored. | ||
| Description The Document Type distinguishes different kinds of business transactions, such as a general ledger entry (SA), vendor invoice (KR), or asset posting (AA). It is defined during system configuration and assigned to every journal entry. This is a critical attribute for analysis as it allows for segmenting the process by the nature of the transaction. The 'Journal Entry Throughput by Type' dashboard and 'Average Cycle Time by Journal Entry Type' KPI depend directly on this field. It helps uncover if certain types of entries are more prone to delays, rework, or reversals. Why it matters Enables segmentation of analysis by transaction type, helping to identify if process issues are specific to certain types of journal entries. Where to get Located in the document header table BKPF, field BLART. Examples SAKRREAA | |||
| Is Reversed IsReversed | A boolean flag indicating whether the journal entry has been reversed. | ||
| Description This flag identifies journal entries that have been subsequently reversed by another accounting document. In SAP, a reversed document is linked to the reversal document, providing a clear audit trail. This attribute is fundamental for the 'Journal Entry Reversal Analysis' dashboard and the 'Journal Entry Reversal Rate' KPI. It allows for isolating reversed entries to investigate the root causes, such as data entry errors or incorrect accounting treatments, with the goal of reducing the frequency of reversals. Why it matters Directly supports reversal analysis by flagging entries that were later undone, helping to identify root causes of errors and improve data integrity. Where to get Derived from the Reversal Document number field (STBLG) in the BKPF table. If STBLG is not empty, the flag is true. Examples truefalse | |||
| Posting Date PostingDate | The date on which the transaction is recorded in the general ledger, affecting the financial period. | ||
| Description The Posting Date determines the fiscal period in which the journal entry is accounted for. It is a critical date field from a financial and compliance perspective, as it must align with accounting period close schedules and regulations. In process mining, this date is used to monitor compliance. The 'Compliance Adherence Monitoring' dashboard and 'Compliance Conformance Rate' KPI use this attribute to check if entries are posted within the correct period. It can also be used to analyze trends in journal entry volumes over time. Why it matters Crucial for financial reporting and compliance analysis, ensuring entries are posted in the correct accounting period. Where to get Located in the document header table BKPF, field BUDAT. Examples 2023-10-312023-11-302024-01-15 | |||
| Transaction Code TransactionCode | The SAP transaction code used to create or process the journal entry. | ||
| Description The Transaction Code (T-Code) is a unique identifier for a specific function or program in SAP. For journal entries, it indicates how the entry was created, for example, manually (FB01, F-02), via parking (FV50), or through an automated interface. This attribute is invaluable for the 'Manual Activity Optimization' dashboard. By analyzing the T-Code, we can distinguish between manual and automated activities, identify which manual processes are most time-consuming, and pinpoint opportunities for automation to reduce manual effort and improve efficiency. Why it matters Helps differentiate between manual and automated processes, identifying opportunities for automation and process standardization. Where to get Located in the document header table BKPF, field TCODE. Examples FB01F-02FV50FBD1 | |||
| User User | The SAP user ID of the person who created or changed the journal entry. | ||
| Description This attribute captures the SAP username responsible for a given activity, such as creating, parking, or posting a document. It is sourced directly from the document header or change log tables. Analyzing the User attribute is key to understanding team and individual performance. It supports the User Productivity dashboard by tracking activity volumes and processing times per user. It also helps identify who is involved in rework loops, reversals, or compliance deviations, enabling targeted training or process improvements. Why it matters Identifies the user responsible for each activity, enabling analysis of user performance, workload distribution, and rework patterns. Where to get Typically from the BKPF table (USNAM field for creator) or the CDHDR table (USERNAME field for changer). Examples ABROWNCJONESDSMITH | |||
| Approval Time ApprovalTime | The time elapsed from when a journal entry is submitted for approval until it is either approved or rejected. | ||
| Description This metric measures the duration of the approval sub-process, which is often a significant contributor to overall cycle time. It is calculated as the time difference between the 'Journal Entry Submitted' activity and the corresponding 'Journal Entry Approved' or 'Journal Entry Rejected' activity. Approval Time is the core metric for the 'Journal Entry Approval Performance' dashboard and the 'Average Journal Entry Approval Time' KPI. Analyzing this duration helps identify bottlenecks in the approval workflow, measure the performance of approvers, and justify process changes like adjusting approval thresholds. Why it matters Quantifies the duration of the approval stage, helping to pinpoint and address delays in the review and approval workflow. Where to get Calculated by subtracting the timestamp of the 'Journal Entry Submitted' event from the 'Journal Entry Approved' or 'Journal Entry Rejected' event. Examples P1DT2HPT4H15MP3D | |||
| Cost Center CostCenter | An organizational unit within a controlling area that represents a location where costs are incurred. | ||
| Description The Cost Center is a key master data element from the Controlling (CO) module, often assigned at the journal entry line item level. It is used to track costs for a specific department, function, or location. Including Cost Center allows for a more granular analysis of the journal entry process. It can help determine if certain departments generate more rework, have longer cycle times, or are responsible for a higher volume of manual entries. This enables a departmental view of process efficiency. Why it matters Enables analysis of process performance by department or functional area, helping to pinpoint localized inefficiencies. Where to get Located in the document line item table BSEG, field KOSTL. Examples 4100CC_FINANCE_US10010101 | |||
| Currency Key CurrencyKey | The currency code for the amounts recorded in the journal entry. | ||
| Description This attribute specifies the currency of the journal entry, such as USD, EUR, or JPY. It provides context for any financial amounts associated with the document. While not always a primary analysis dimension, it is crucial for interpreting monetary values correctly. It can also be used to segment analysis in global organizations to see if processes differ for entries in foreign vs. local currencies. Why it matters Provides necessary context for all monetary values, ensuring accurate financial analysis and interpretation. Where to get Located in the document header table BKPF, field WAERS. Examples USDEURGBPJPY | |||
| Cycle Time CycleTime | The total time elapsed from the creation of the first journal entry activity to the final posting activity. | ||
| Description Cycle Time is a key performance indicator that measures the end-to-end duration of the journal entry process. It is calculated by taking the difference between the timestamp of the final posting event and the initial creation event for a single journal entry. This calculated metric is the primary measure on the 'Journal Entry End-to-End Cycle Time' dashboard and the 'Average Journal Entry Cycle Time' KPI. It provides a high-level view of overall process efficiency and is used to track the impact of improvement initiatives over time. Why it matters Measures the overall end-to-end efficiency of the process, providing a key metric for identifying bottlenecks and tracking improvements. Where to get Calculated by subtracting the timestamp of the first event from the timestamp of the last event for each case (JournalEntryId). Examples P2DT3H15MPT8H30MP5D | |||
| Is Parked IsParked | A boolean flag indicating if the journal entry was saved as a parked document before being posted. | ||
| Description Parking a document allows a user to save an incomplete journal entry without it affecting financial balances. It can then be completed or reviewed by another user before posting. This flag identifies entries that have gone through a parking step. Analyzing this attribute helps understand the usage of the parking feature. It can reveal if parking is used as an informal review step, potentially causing delays. It supports analysis of the end-to-end cycle time, distinguishing between entries that are posted directly versus those that are parked first. Why it matters Identifies entries that use the parking feature, which can be a source of delay or an indicator of an informal review process. Where to get Derived from the document status field (BSTAT) in table BKPF. A 'V' indicates a parked document. Examples truefalse | |||
| Is Rework IsRework | A boolean flag indicating if a journal entry has undergone a rework loop, such as being rejected and then corrected. | ||
| Description This flag identifies cases that have deviated from the 'happy path' and required corrective action. It is typically set to true if a sequence of activities like 'Journal Entry Rejected' followed by 'Journal Entry Corrected' is observed for a given journal entry. This attribute is essential for calculating the 'Journal Entry Rework Rate' KPI and for analysis on the 'Rework and Rejection Rate' dashboard. It helps quantify the extent of inefficiency in the process and provides a basis for investigating the root causes of rework, such as unclear requirements or insufficient documentation. Why it matters Flags entries that required correction, enabling the quantification of rework and analysis of its root causes to improve first-time-right rates. Where to get This is a calculated attribute, derived by analyzing the sequence of activities for a case. A rework loop is identified if a rejection or correction activity occurs. Examples truefalse | |||
| Reversal Reason ReversalReason | A code indicating the reason why a journal entry was reversed. | ||
| Description When a document is reversed, SAP allows the user to specify a reason code. This code provides structured information about why the reversal was necessary, for example, incorrect posting date or data entry error. This attribute is a key input for the 'Journal Entry Reversal Analysis' dashboard. By analyzing the most common reversal reasons, organizations can identify systemic issues in their processes or training gaps, and take targeted actions to prevent future errors and reduce the reversal rate. Why it matters Provides direct insight into why reversals happen, enabling targeted root cause analysis to reduce future errors. Where to get Located in the document header table BKPF, field STGRD. Examples 010205 | |||
| Total Document Amount TotalDocumentAmount | The total value of the journal entry in the document currency. | ||
| Description This attribute represents the total financial value of the journal entry. It is typically calculated by summing the absolute values of all debit or credit line items associated with the document. Analyzing the process by financial value can reveal important patterns. For instance, high-value entries may follow a different, more stringent approval path. This attribute can be used to filter or segment analysis to see if cycle times, rejection rates, or approval delays correlate with the entry's amount. Why it matters Allows for financial impact analysis, such as correlating processing times or rejection rates with the monetary value of journal entries. Where to get This is a calculated field, derived by aggregating the amount field (WRBTR or DMBTR) from all line items in the BSEG table for a given journal entry. Examples 1500.0025000.75125.50 | |||
Record to Report - Journal Entry Activities
| Activity | Description | ||
|---|---|---|---|
| Journal Entry Approved | This activity marks the final approval of a journal entry within a workflow, making it eligible for posting. This event is captured from the workflow log when the final 'release' or 'approve' step is completed. | ||
| Why it matters This is a key milestone that concludes the approval process. The duration leading up to this activity is a critical KPI for approval efficiency, and the time from this event to posting measures post-approval lag. Where to get Inferred from the completion timestamp of the final approval step in the SAP Business Workflow log. This is the last approval action before the document is posted or made ready for posting. Capture Identify final 'release' or 'approve' step completion in workflow logs. Event type inferred | |||
| Journal Entry Parked | This activity marks the initial creation of a journal entry in a preliminary state, before it is officially posted to the general ledger. This is captured explicitly in SAP when a user saves a document using a parking transaction, setting the document status to 'parked'. | ||
| Why it matters This is a critical start event for processes involving review and approval. Analyzing the time between parking and posting helps identify delays in the pre-posting and approval phases. Where to get This event is identified from the document header table BKPF. A document is considered parked when it is created with a status BKPF-BSTAT = 'V'. The event timestamp is the creation date and time, BKPF-CPUDT and BKPF-CPUTM. Capture Identify document creation in BKPF where BKPF-BSTAT is 'V'. Event type explicit | |||
| Journal Entry Posted | This is the central activity where the journal entry is officially recorded in the general ledger, impacting financial statements. This event is captured explicitly when the document status is set to 'posted' and a posting date is assigned. | ||
| Why it matters This is the most important milestone, signifying the successful processing of a journal entry. The end-to-end cycle time is often measured up to this point, and it is a key event for financial closing analysis. Where to get Identified when a document in the BKPF table has a posting date (BKPF-BUDAT). For parked documents, this corresponds to the moment the status BKPF-BSTAT changes from 'V' to blank. The timestamp of the posting is the entry date BKPF-CPUDT. Capture Identify when BKPF-BSTAT changes from 'V' to blank, or for direct postings, the creation event. Event type explicit | |||
| Journal Entry Reversal Processed | This activity marks the reversal of a previously posted journal entry. A reversal is a new accounting document that cancels out the original entry. | ||
| Why it matters This is a critical event for measuring data quality and process accuracy. A high rate of reversals points to systemic issues in the initial data entry or approval stages, and each reversal represents rework. Where to get This event is identified in the original document's header (BKPF table). When a document is reversed, SAP populates the reversal document number (BKPF-STBLG) and reversal reason (BKPF-STGRD). The event timestamp is the posting date of the new reversal document. Capture Identify when BKPF-STBLG is populated on the original document; timestamp is the posting date of the reversal document. Event type explicit | |||
| Journal Entry Submitted | This activity signifies that a parked journal entry has been finalized by its creator and is now ready for review and approval. It is typically captured by the initiation of an SAP Business Workflow task associated with the parked document. | ||
| Why it matters This marks the handoff from the creator to the approver, starting the clock for approval cycle time KPIs. It is a key milestone for measuring the efficiency of the approval workflow. Where to get Inferred from the start time of the approval workflow instance linked to the financial document object. This requires analyzing workflow log tables like SWW_WI2OBJ to find the workflow started for the specific company code, document number, and fiscal year. Capture Identify workflow start event for the parked document object. Event type inferred | |||
| Cross-Company Posting Identified | A calculated activity that flags a journal entry affecting more than one company code. This is determined by analyzing the line items of a single financial document. | ||
| Why it matters Cross-company transactions can have more complex processing and approval requirements. Identifying them allows for separate analysis of their cycle times and process paths to find unique bottlenecks. Where to get Calculated by examining the line item table BSEG for a given document number (BELNR). If the line items contain more than one distinct company code (BSEG-BUKRS), the entry is a cross-company posting. Capture Check if multiple unique values of BSEG-BUKRS exist for a single BKPF-BELNR. Event type calculated | |||
| Documentation Attached | This activity represents a user attaching supporting documents, such as invoices or spreadsheets, to the journal entry. This event is not explicitly logged as a standard accounting event and is typically inferred by checking for the creation of attachments linked to the accounting document object. | ||
| Why it matters Tracking this activity helps verify compliance with policies requiring documentation. Delays in attaching documents can be a root cause for prolonged approval cycles. Where to get This is difficult to capture reliably as a timestamped event. It can potentially be inferred by analyzing the Generic Object Services (GOS) attachment tables, such as SOOD, and linking the attachment creation timestamp to the journal entry object key. Capture Infer from creation timestamp of linked objects in GOS tables (e.g., SOOD). Event type inferred | |||
| Journal Entry Changes Requested | Represents a point in the workflow where an approver has reviewed the journal entry and sent it back to the creator for correction. This event is captured from workflow logs indicating a 'rejection' or 'send back' user decision. | ||
| Why it matters This activity is essential for identifying rework loops, which are a primary source of inefficiency and process deviation. High frequency of this event indicates issues with entry quality or unclear requirements. Where to get This event is inferred from the timestamp of a specific user decision step in the SAP Business Workflow log that corresponds to a 'reject' or 'send for correction' action. Capture Identify 'rejection' or 'rework' decision timestamp in workflow logs. Event type inferred | |||
| Journal Entry Corrected | This activity indicates that the original creator has modified a parked journal entry after it was sent back for changes. It is inferred by detecting changes to the document after a 'Changes Requested' event. | ||
| Why it matters Tracking corrections helps quantify the effort spent on rework. The time between a change request and the correction highlights delays in resolving issues with submitted entries. Where to get Inferred by analyzing change document logs (tables CDHDR and CDPOS) for the parked document. A change recorded after a rejection event in the workflow signifies a correction has been made. The timestamp is from the CDHDR table. Capture Identify change log entry in CDHDR/CDPOS after a rejection event. Event type inferred | |||
| Journal Entry Created | Represents the creation of a journal entry that is posted directly, without a preceding parking step. This is captured when a document is created in SAP using a direct posting transaction. | ||
| Why it matters This activity serves as an alternative starting point for simpler journal entry processes that do not require an approval workflow. It helps differentiate between simple, direct postings and more complex, parked entries. Where to get This event corresponds to document creation in the BKPF table where the document status BKPF-BSTAT is blank (posted). The event timestamp is the creation date, BKPF-CPUDT. For these documents, 'Created' and 'Posted' events occur simultaneously. Capture Identify document creation in BKPF where BKPF-BSTAT is blank. Event type explicit | |||
| Journal Entry Line Item Cleared | This activity represents the reconciliation of an open-item managed G/L account line item, such as a bank clearing account. It occurs when a line item is matched against another, closing it out. | ||
| Why it matters For processes like bank reconciliation, the time to clear items is a crucial KPI. This activity helps analyze the efficiency of reconciliation and month-end closing procedures. Where to get This event is captured from the line item table BSEG. When a line item is cleared, the clearing date (BSEG-AUGDT) and clearing document (BSEG-AUGBL) fields are populated. The timestamp of the event is the clearing date. Capture Identify when the clearing date (BSEG-AUGDT) is populated for a line item. Event type explicit | |||
| Journal Entry Rejected | This activity signifies the final rejection of a journal entry, after which it will not be posted. This is typically a terminal status in an approval workflow, leading to the eventual deletion of the parked document. | ||
| Why it matters Tracking rejections is crucial for quality management. Analyzing the reasons and frequency of rejections helps improve the first-time-right rate of journal entries. Where to get This is an outcome captured from the SAP Business Workflow log, representing a final 'reject' user decision that terminates the process. The parked document may subsequently be deleted. Capture Identify terminal 'reject' status in the workflow log for the document. Event type inferred | |||
| Manual Entry Identified | This activity identifies if a journal entry was created through a manual online transaction versus an automated interface or batch process. This is not a user action but a calculated attribute of the entry, derived from system data. | ||
| Why it matters Distinguishing between manual and automated entries is key to targeted process improvement. Manual processes are often the focus for standardization and automation initiatives. Where to get This is calculated by analyzing fields in the document header table BKPF. Transaction codes (BKPF-TCODE) like 'FB01', 'FB50', or 'FV50' indicate manual entry, whereas other T-codes or specific batch input names (BKPF-AWKEY) suggest automation. Capture Derive from BKPF-TCODE or other source system indicators in the document header. Event type calculated | |||
| Parked Journal Entry Deleted | Represents the deletion of a parked journal entry that was never posted. This can occur after a rejection or if the entry was created in error. | ||
| Why it matters This activity marks an unsuccessful end to the process. Analyzing why parked documents are deleted can reveal issues such as duplicate entries or process misunderstandings. Where to get This event is captured when the status of a parked document in the BKPF table is changed. The status field BKPF-BSTAT is updated to 'Z' (Parked document deleted). The change timestamp can be found in the document change logs (CDHDR). Capture Identify when BKPF-BSTAT is updated to 'Z'. Event type explicit | |||
Extraction Guides
Steps
- Create the ABAP Program: In the SAP system, go to transaction code SE38 (ABAP Editor). Enter a name for the new program, for example, Z_PM_JE_EXTRACTION, and click Create. Provide a suitable title and set the program type to 'Executable Program'.
- Define Selection Screen: In the program source code, define the selection screen. This allows users to specify parameters like a date range for document creation, company codes, and document types to limit the data volume for the extraction.
- Declare Data Structures: Define an internal table structure that will hold the final event log data. This structure must include all required fields: JournalEntryId, ActivityName, EventTime, SourceSystem, LastDataUpdate, and any recommended attributes like User, CompanyCode, and PostingDate.
- Implement Data Selection Logic: Write the core ABAP SQL queries to extract data for each of the 14 required activities. This involves selecting data from primary tables like BKPF (Header) and BSEG (Line Item), change log tables CDHDR and CDPOS, workflow tables like SWWLOGHIST, and clearing tables like BSAS and BSAK.
- Extract Parked and Posted Documents: For 'Journal Entry Parked' events, select from BKPF where the document status (BSTAT) is 'V'. For 'Journal Entry Created' and 'Journal Entry Posted' events, select from BKPF where the status is blank, indicating a normal, posted document.
- Extract Change and Deletion Events: Query the change document tables, CDHDR and CDPOS, for object class 'BELEG'. Filter on the document key to find changes that correspond to 'Journal Entry Corrected' or 'Parked Journal Entry Deleted' activities.
- Extract Workflow Events: To capture activities like 'Journal Entry Submitted', 'Approved', 'Rejected', and 'Changes Requested', query the workflow tables. Use table SWW_WI2OBJ to link the accounting document to a workflow instance, then read SWWLOGHIST for specific user decisions or status changes.
- Identify Calculated Events: For 'Manual Entry Identified', check the transaction code (BKPF-TCODE) against a list of known manual entry t-codes. For 'Cross-Company Posting Identified', analyze the BSEG line items for a given document to see if multiple company codes are involved.
- Consolidate and Transform Data: As each activity's data is selected, transform it into the final event log structure. Concatenate Company Code, Document Number, and Fiscal Year to create the JournalEntryId. Convert SAP dates and times into a single EventTime timestamp. Append the results from each query into the final internal table.
- Implement File Export: Use ABAP file handling statements, such as OPEN DATASET, LOOP AT, TRANSFER, and CLOSE DATASET, to write the consolidated internal table to a CSV or flat file on the SAP application server directory (viewable via transaction AL11).
- Schedule as Background Job: Go to transaction SM36 (Define Background Job). Create a new job, define a step that executes your ABAP program, and set a schedule, for example, nightly or weekly during off-peak hours, to automate the extraction process.
- Retrieve and Format File: Use transaction CG3Y or work with your system administrator to download the generated file from the application server to your local machine. Ensure the file encoding and format are suitable for upload into your process mining tool.
Configuration
- Date Range: It is critical to define a date range to manage performance. Use the document creation date (BKPF-CPUDT) as the primary filter. For an initial analysis, a period of 3 to 6 months is recommended. For testing, use a range of a few days that is known to contain data.
- Company Code Filter: Always filter by company code (BKPF-BUKRS). Extracting data for all company codes at once can be extremely resource intensive. Start with one or a small group of relevant company codes.
- Document Type Filter: Use the document type filter (BKPF-BLART) to narrow the scope to specific types of journal entries, such as 'SA' for G/L documents, if you do not need to analyze all document types.
- Workflow Task IDs: The logic for extracting workflow events depends on specific task IDs used in your system for approval, rejection, and submission. These IDs must be configured in the program's source code based on your company's workflow definitions.
- Performance Considerations: The program joins several large tables, especially CDPOS and the workflow history tables. Running it during peak business hours can impact system performance. Always schedule it as a background job to run during off-peak times. Consider creating secondary database indexes if performance is a recurring issue.
- Prerequisites: This method requires a user with ABAP development authorizations (for SE38) and permissions to create and manage background jobs (for SM36). The user or job also needs read access to all relevant financial, workflow, and system tables (BKPF, BSEG, CDHDR, CDPOS, SWWLOGHIST, etc.).
a Sample Query abap
REPORT Z_PM_JE_EXTRACTION.
*&---------------------------------------------------------------------*
*& Data Structures for Final Event Log
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
journalentryid TYPE string,
activityname TYPE string,
eventtime TYPE timestamp,
sourcesystem TYPE string,
lastdataupdate TYPE timestamp,
username TYPE uname,
companycode TYPE bukrs,
documenttype TYPE blart,
postingdate TYPE budat,
transactioncode TYPE tcode,
isreversed TYPE abap_bool,
END OF ty_event_log.
DATA: lt_final_log TYPE STANDARD TABLE OF ty_event_log.
DATA: ls_event TYPE ty_event_log.
*&---------------------------------------------------------------------*
*& Selection Screen Parameters
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_bukrs FOR bkpf-bukrs OBLIGATORY,
s_blart FOR bkpf-blart,
s_cpudt FOR bkpf-cpudt OBLIGATORY.
PARAMETERS: p_sysid TYPE sy-sysid DEFAULT sy-sysid.
*&---------------------------------------------------------------------*
*& Main Logic
*&---------------------------------------------------------------------*
START-OF-SELECTION.
DATA(lv_last_update) = cl_abap_context_info=>get_system_timestamp( ).
" 1. Journal Entry Parked
SELECT CONCAT( a~bukrs, a~belnr, a~gjahr ) AS journalentryid,
'Journal Entry Parked' AS activityname,
a~cpudt, a~cputm,
a~usnam AS username,
a~bukrs AS companycode,
a~blart AS documenttype,
a~bldat AS postingdate,
a~tcode AS transactioncode
FROM bkpf AS a
WHERE a~bukrs IN s_bukrs
AND a~blart IN s_blart
AND a~cpudt IN s_cpudt
AND a~bstat = 'V' " Parked Document
INTO TABLE @DATA(lt_parked).
IF sy-subrc = 0.
LOOP AT lt_parked ASSIGNING FIELD-SYMBOL(<fs_parked>).
ls_event-journalentryid = <fs_parked>-journalentryid.
ls_event-activityname = <fs_parked>-activityname.
CONVERT DATE <fs_parked>-cpudt TIME <fs_parked>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
ls_event-sourcesystem = p_sysid.
ls_event-lastdataupdate = lv_last_update.
ls_event-username = <fs_parked>-username.
ls_event-companycode = <fs_parked>-companycode.
ls_event-documenttype = <fs_parked>-documenttype.
ls_event-postingdate = <fs_parked>-postingdate.
ls_event-transactioncode = <fs_parked>-transactioncode.
APPEND ls_event TO lt_final_log.
ENDLOOP.
ENDIF.
" 2. Journal Entry Created (directly posted, not parked first)
" 9. Journal Entry Posted
" These two events happen at the same time for a direct posting.
SELECT CONCAT( bukrs, belnr, gjahr ) AS journalentryid,
cpudt, cputm, usnam, bukrs, blart, budat, tcode, stblg
FROM bkpf
WHERE bukrs IN s_bukrs
AND blart IN s_blart
AND cpudt IN s_cpudt
AND bstat = '' " Normal, posted document
INTO TABLE @DATA(lt_posted).
IF sy-subrc = 0.
LOOP AT lt_posted ASSIGNING FIELD-SYMBOL(<fs_posted>).
" Activity: Journal Entry Created
ls_event-journalentryid = <fs_posted>-journalentryid.
ls_event-activityname = 'Journal Entry Created'.
CONVERT DATE <fs_posted>-cpudt TIME <fs_posted>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
ls_event-sourcesystem = p_sysid.
ls_event-lastdataupdate = lv_last_update.
ls_event-username = <fs_posted>-usnam.
ls_event-companycode = <fs_posted>-bukrs.
ls_event-documenttype = <fs_posted>-blart.
ls_event-postingdate = <fs_posted>-budat.
ls_event-transactioncode = <fs_posted>-tcode.
ls_event-isreversed = COND #( WHEN <fs_posted>-stblg IS NOT INITIAL THEN abap_true ELSE abap_false ).
APPEND ls_event TO lt_final_log.
" Activity: Journal Entry Posted
ls_event-activityname = 'Journal Entry Posted'.
APPEND ls_event TO lt_final_log.
ENDLOOP.
ENDIF.
" 3. Documentation Attached (via GOS)
SELECT a~instid_a, c~cr_timestamp
FROM srgbtbrel AS a
INNER JOIN sood AS b ON a~instid_b = b~objid
INNER JOIN socf AS c ON b~filid = c~filid
WHERE a~typeid_a = 'BKPF'
AND a~bukrs IN s_bukrs
INTO TABLE @DATA(lt_attachments).
IF sy-subrc = 0.
LOOP AT lt_attachments ASSIGNING FIELD-SYMBOL(<fs_attach>).
ls_event-journalentryid = |{ <fs_attach>-instid_a(4) }{ <fs_attach>-instid_a+4(10) }{ <fs_attach>-instid_a+14(4) }|.
ls_event-activityname = 'Documentation Attached'.
ls_event-eventtime = <fs_attach>-cr_timestamp.
" Other attributes may need to be looked up from BKPF if needed.
APPEND ls_event TO lt_final_log.
ENDLOOP.
ENDIF.
" 4, 5, 6, 7, 8: Workflow events (Submitted, Changes Requested, Corrected, Approved, Rejected)
" This is a simplified example. Real logic depends on specific workflow templates.
SELECT a~instid, b~wi_cd, b~wi_ct, b~wi_aagent, b~wi_text
FROM sww_wi2obj AS a
INNER JOIN swwloghist AS b ON a~wi_id = b~wi_id
WHERE a~typeid = 'BKPF'
AND a~catid = 'BO'
AND a~bukrs IN s_bukrs
AND b~wi_cd BETWEEN s_cpudt-low AND s_cpudt-high
INTO TABLE @DATA(lt_workflow).
IF sy-subrc = 0.
LOOP AT lt_workflow ASSIGNING FIELD-SYMBOL(<fs_wf>).
ls_event-journalentryid = |{ <fs_wf>-instid(4) }{ <fs_wf>-instid+4(10) }{ <fs_wf>-instid+14(4) }|.
ls_event-activityname = CASE <fs_wf>-wi_text. " Simplified logic based on work item text
WHEN '[Placeholder for Submit Text]' THEN 'Journal Entry Submitted'
WHEN '[Placeholder for Approve Text]' THEN 'Journal Entry Approved'
WHEN '[Placeholder for Reject Text]' THEN 'Journal Entry Rejected'
WHEN '[Placeholder for Rework Text]' THEN 'Journal Entry Changes Requested'
ELSE ''
ENDCASE.
IF ls_event-activityname IS NOT INITIAL.
CONVERT DATE <fs_wf>-wi_cd TIME <fs_wf>-wi_ct INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
ls_event-username = <fs_wf>-wi_aagent.
APPEND ls_event TO lt_final_log.
ENDIF.
ENDLOOP.
ENDIF.
" 10. Manual Entry Identified & 11. Cross-Company Posting Identified
SELECT bukrs, belnr, gjahr, tcode FROM bkpf
WHERE bukrs IN s_bukrs AND blart IN s_blart AND cpudt IN s_cpudt
INTO TABLE @DATA(lt_calc_base).
LOOP AT lt_calc_base ASSIGNING FIELD-SYMBOL(<fs_calc>).
ls_event-journalentryid = |{ <fs_calc>-bukrs }{ <fs_calc>-belnr }{ <fs_calc>-gjahr }|.
" Check for manual entry T-Codes
IF <fs_calc>-tcode = 'FB01' OR <fs_calc>-tcode = 'F-02' OR <fs_calc>-tcode = 'FB50'.
ls_event-activityname = 'Manual Entry Identified'.
APPEND ls_event TO lt_final_log.
ENDIF.
" Check for cross-company posting
SELECT SINGLE bukrs FROM bseg WHERE belnr = <fs_calc>-belnr AND gjahr = <fs_calc>-gjahr AND bukrs <> <fs_calc>-bukrs INTO @DATA(lv_cross_bukrs).
IF sy-subrc = 0.
ls_event-activityname = 'Cross-Company Posting Identified'.
APPEND ls_event TO lt_final_log.
ENDIF.
ENDLOOP.
" 12. Journal Entry Line Item Cleared
SELECT a~bukrs, a~belnr, a~gjahr, a~augdt, a~augbl
FROM bsas AS a " G/L Cleared Items
WHERE a~bukrs IN s_bukrs
AND a~budat IN s_cpudt
INTO TABLE @DATA(lt_cleared_gl).
IF sy-subrc = 0.
LOOP AT lt_cleared_gl ASSIGNING FIELD-SYMBOL(<fs_clr>).
ls_event-journalentryid = |{ <fs_clr>-bukrs }{ <fs_clr>-belnr }{ <fs_clr>-gjahr }|.
ls_event-activityname = 'Journal Entry Line Item Cleared'.
CONVERT DATE <fs_clr>-augdt INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
" User is often not directly available for clearing events
APPEND ls_event TO lt_final_log.
ENDLOOP.
ENDIF.
" 13. Parked Journal Entry Deleted & 6. Journal Entry Corrected
SELECT objectid, changenr, username, udate, utime FROM cdhdr
WHERE objectclas = 'BELEG'
AND udate IN s_cpudt
INTO TABLE @DATA(lt_cdhdr).
LOOP AT lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>).
SELECT SINGLE tcode FROM cdpos WHERE changenr = <fs_cdhdr>-changenr AND fname = 'BSTAT' AND value_new = 'Z' INTO @DATA(lv_deleted_tcode).
ls_event-journalentryid = |{ <fs_cdhdr>-objectid(4) }{ <fs_cdhdr>-objectid+4(10) }{ <fs_cdhdr>-objectid+14(4) }|.
CONVERT DATE <fs_cdhdr>-udate TIME <fs_cdhdr>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
ls_event-username = <fs_cdhdr>-username.
IF sy-subrc = 0.
ls_event-activityname = 'Parked Journal Entry Deleted'.
APPEND ls_event TO lt_final_log.
ELSE.
ls_event-activityname = 'Journal Entry Corrected'.
APPEND ls_event TO lt_final_log.
ENDIF.
ENDLOOP.
" 14. Journal Entry Reversal Processed
SELECT CONCAT( a~bukrs, a~belnr, a~gjahr ) AS journalentryid,
a~cpudt, a~cputm, a~usnam
FROM bkpf AS a
WHERE a~bukrs IN s_bukrs
AND a~blart IN s_blart
AND a~cpudt IN s_cpudt
AND a~stblg IS NOT NULL " Document is a reversal
INTO TABLE @DATA(lt_reversals).
IF sy-subrc = 0.
LOOP AT lt_reversals ASSIGNING FIELD-SYMBOL(<fs_rev>).
ls_event-journalentryid = <fs_rev>-journalentryid.
ls_event-activityname = 'Journal Entry Reversal Processed'.
CONVERT DATE <fs_rev>-cpudt TIME <fs_rev>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
ls_event-username = <fs_rev>-usnam.
APPEND ls_event TO lt_final_log.
ENDLOOP.
ENDIF.
" Final step: Output to file
DATA(lv_filename) = |/tmp/je_extraction_{ sy-datum }_{ sy-uzeit }.csv|.
OPEN DATASET lv_filename FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
IF sy-subrc = 0.
" Write header
DATA(lv_header) = 'JournalEntryId,ActivityName,EventTime,SourceSystem,LastDataUpdate,User,CompanyCode,DocumentType,PostingDate,TransactionCode,IsReversed'.
TRANSFER lv_header TO lv_filename.
LOOP AT lt_final_log INTO ls_event.
DATA(lv_line) = |"{ ls_event-journalentryid }","|
|{ ls_event-activityname }","|
|{ ls_event-eventtime }","|
|{ ls_event-sourcesystem }","|
|{ ls_event-lastdataupdate }","|
|{ ls_event-username }","|
|{ ls_event-companycode }","|
|{ ls_event-documenttype }","|
|{ ls_event-postingdate }","|
|{ ls_event-transactioncode }","|
|{ ls_event-isreversed }"|.
TRANSFER lv_line TO lv_filename.
ENDLOOP.
CLOSE DATASET lv_filename.
ENDIF. Steps
- Establish Database Connection: Obtain read-only credentials for the SAP ECC database. Use a standard SQL client, such as DBeaver, SAP HANA Studio, or SQL Server Management Studio, to connect to the database.
- Prepare the SQL Query: Copy the complete SQL query provided in the 'query' section of this document into your SQL client.
- Set Extraction Parameters: Before executing, you must configure the placeholders within the query. Replace
'[START_DATE]'and'[END_DATE]'with the desired date range in 'YYYYMMDD' format. Replace'[COMPANY_CODE_1]', '[COMPANY_CODE_2]'with the specific SAP company codes you wish to analyze. - Define Source System: In the main
SELECTstatement, replace the placeholder'[Your SAP System ID]'with the actual SAP System ID (SID) to correctly identify the data source. - Execute the Query: Run the configured SQL query against the SAP database. The execution time will vary depending on the date range and the size of your database tables.
- Review Initial Results: Once the query completes, briefly scan the returned rows to ensure data is being populated as expected. Check for a variety of activities and that key fields like
JournalEntryIdandEventTimeare not empty. - Handle Timestamps: The query concatenates date and time fields into a
YYYYMMDDHHMMSSstring. Ensure your post-processing or target system can parse this format, or adjust the SQLCONCATfunction to an ISO 8601 format likeYYYY-MM-DDTHH:MI:SSif your database supports it. - Export the Data: Export the full result set from your SQL client to a CSV file. Ensure you use UTF-8 encoding to prevent issues with special characters.
- Prepare for Upload: Before uploading to a process mining tool, confirm the column headers match the required data schema.
JournalEntryId,ActivityName, andEventTimeare critical. Add theLastDataUpdatecolumn, populating it with the timestamp of when the extraction was performed. - Final Validation: Perform the steps outlined in the 'validationSteps' section to ensure the extracted data is complete and accurate before beginning your analysis.
Configuration
- Database Authorizations: The database user requires read access to the following SAP tables: BKPF, BSEG, CDHDR, CDPOS, T001, and V_USERNAME. For workflow-related activities, access to SWW_WI2OBJ and SWWLOGHIST is also necessary. This level of access is typically granted only to specialized technical teams.
- Date Range Filtering: It is critical to filter the data by a specific date range to ensure query performance. The provided query uses placeholders for a start and end date, which are applied to the document creation date (
BKPF.CPUDT). A range of 3 to 6 months is recommended for an initial analysis. - Entity Filtering: To manage data volume and focus the analysis, always filter by Company Code (
BKPF.BUKRS). You may also consider filtering by Document Type (BKPF.BLART) to include only relevant journal entry types, for example, 'SA' for G/L documents, and exclude operational documents like invoices or payments if they are not in scope. - Performance Considerations: Direct queries against core tables like BSEG and CDPOS can be resource-intensive. Executing this extraction during off-peak business hours is strongly recommended to avoid impacting system performance for end-users. Avoid extracting data for more than one year in a single execution.
- Workflow Task IDs: The query contains placeholders like
'[WF_TASK_ID_SUBMIT]'and'[WF_TASK_ID_APPROVE]'. These must be replaced with the actual task IDs from your system's specific journal entry workflow configuration. These can be identified by working with an SAP Workflow specialist or by analyzing the technical workflow definition in transaction PFTC.
a Sample Query sql
WITH DOC_HEADERS AS (
SELECT
BUKRS,
BELNR,
GJAHR,
BLART,
BLDAT,
BUDAT,
CPUDT,
CPUTM,
USNAM,
TCODE,
BSTAT,
STBLG,
XRECH
FROM BKPF
WHERE CPUDT BETWEEN '[START_DATE]' AND '[END_DATE]'
AND BUKRS IN ('[COMPANY_CODE_1]', '[COMPANY_CODE_2]')
)
-- Event 1: Journal Entry Created (Directly Posted)
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Journal Entry Created' AS "ActivityName",
TO_TIMESTAMP(CONCAT(H.CPUDT, H.CPUTM), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
CASE WHEN H.STBLG IS NOT NULL AND H.STBLG <> '' THEN TRUE ELSE FALSE END AS "IsReversed"
FROM DOC_HEADERS H
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE H.BSTAT = '' OR H.BSTAT = 'U'
UNION ALL
-- Event 2: Journal Entry Parked
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Journal Entry Parked' AS "ActivityName",
TO_TIMESTAMP(CONCAT(H.CPUDT, H.CPUTM), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
FALSE AS "IsReversed"
FROM DOC_HEADERS H
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE H.BSTAT = 'V'
UNION ALL
-- Event 3: Journal Entry Posted (from Parked state)
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Journal Entry Posted' AS "ActivityName",
TO_TIMESTAMP(CONCAT(C.UDATE, C.UTIME), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
C.TCODE AS "TransactionCode",
CASE WHEN H.STBLG IS NOT NULL AND H.STBLG <> '' THEN TRUE ELSE FALSE END AS "IsReversed"
FROM DOC_HEADERS H
JOIN CDHDR C ON C.OBJECTCLAS = 'BELEG' AND C.OBJECTID = CONCAT(H.BUKRS, H.BELNR, H.GJAHR)
JOIN CDPOS P ON C.CHANGENR = P.CHANGENR AND P.OBJECTCLAS = 'BELEG' AND P.OBJECTID = C.OBJECTID
LEFT JOIN V_USERNAME U ON C.USERNAME = U.BNAME
WHERE H.BSTAT <> 'V'
AND P.TABNAME = 'BKPF'
AND P.FNAME = 'BSTAT'
AND P.VALUE_OLD = 'V'
AND P.VALUE_NEW <> 'V'
UNION ALL
-- Event 4: Parked Journal Entry Deleted
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Parked Journal Entry Deleted' AS "ActivityName",
TO_TIMESTAMP(CONCAT(C.UDATE, C.UTIME), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
C.TCODE AS "TransactionCode",
FALSE AS "IsReversed"
FROM DOC_HEADERS H
JOIN CDHDR C ON C.OBJECTCLAS = 'BELEG' AND C.OBJECTID = CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AND C.TCODE = 'FBV0'
JOIN CDPOS P ON C.CHANGENR = P.CHANGENR AND P.OBJECTCLAS = 'BELEG' AND P.OBJECTID = C.OBJECTID
LEFT JOIN V_USERNAME U ON C.USERNAME = U.BNAME
WHERE P.TABNAME = 'BKPF'
AND P.FNAME = 'BSTAT'
AND P.VALUE_OLD = 'V'
AND P.VALUE_NEW = 'Z'
UNION ALL
-- Event 5: Journal Entry Reversal Processed
SELECT
CONCAT(H.BUKRS, H.STBLG, H.GJAHR) AS "JournalEntryId", -- Linking to the original document
'Journal Entry Reversal Processed' AS "ActivityName",
TO_TIMESTAMP(CONCAT(H.CPUDT, H.CPUTM), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
TRUE AS "IsReversed"
FROM DOC_HEADERS H
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE H.STBLG IS NOT NULL AND H.STBLG <> ''
UNION ALL
-- Event 6: Journal Entry Line Item Cleared
SELECT
CONCAT(B.BUKRS, B.BELNR, B.GJAHR) AS "JournalEntryId",
'Journal Entry Line Item Cleared' AS "ActivityName",
TO_TIMESTAMP(B.AUGDT, 'YYYYMMDD') AS "EventTime", -- Clearing date used as event time
U.NAME_TEXT AS "User",
B.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
NULL AS "TransactionCode", -- Clearing transaction is in the clearing document header, complex to retrieve here
CASE WHEN H.STBLG IS NOT NULL AND H.STBLG <> '' THEN TRUE ELSE FALSE END AS "IsReversed"
FROM BSEG B
JOIN DOC_HEADERS H ON B.BUKRS = H.BUKRS AND B.BELNR = H.BELNR AND B.GJAHR = H.GJAHR
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE B.AUGBL IS NOT NULL AND B.AUGBL <> '' AND B.AUGDT <> '00000000'
UNION ALL
-- Event 7: Journal Entry Corrected (changes to a parked document)
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Journal Entry Corrected' AS "ActivityName",
TO_TIMESTAMP(CONCAT(C.UDATE, C.UTIME), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
C.TCODE AS "TransactionCode",
FALSE AS "IsReversed"
FROM DOC_HEADERS H
JOIN CDHDR C ON C.OBJECTCLAS = 'BELEG' AND C.OBJECTID = CONCAT(H.BUKRS, H.BELNR, H.GJAHR)
LEFT JOIN V_USERNAME U ON C.USERNAME = U.BNAME
WHERE H.BSTAT = 'V' AND C.TCODE IN ('FBV2', 'FBV4') -- FBV2 is change parked doc, FBV4 is change parked doc header
UNION ALL
-- Event 8: Documentation Attached (inferred from GOS attachment creation, requires configuration)
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Documentation Attached' AS "ActivityName",
TO_TIMESTAMP(CONCAT(REL.RECDATE, '000000'), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
FALSE AS "IsReversed"
FROM DOC_HEADERS H
JOIN SRGBTBREL REL ON REL.INSTID_A = CONCAT('BUS2081', H.BUKRS, H.BELNR, H.GJAHR) -- BUS2081 is object type for BKPF
LEFT JOIN V_USERNAME U ON REL.RECUNAM = U.BNAME
WHERE REL.TYPEID_A = 'BUS2081' AND REL.RELTYPE = 'ATTA'
UNION ALL
-- Events 9-13 from Workflow (Submitted, Changes Requested, Approved, Rejected) requires specific workflow config
-- This is a generic template. The WI_RH_TASK must be adapted to your system.
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
CASE
WHEN LOG.WI_RH_TASK = '[WF_TASK_ID_SUBMIT]' THEN 'Journal Entry Submitted'
WHEN LOG.WI_RH_TASK = '[WF_TASK_ID_APPROVE]' AND LOG.METHOD = 'DECISION' AND LOG.EVT_ID = 'COMPLETED' THEN 'Journal Entry Approved'
WHEN LOG.WI_RH_TASK = '[WF_TASK_ID_REJECT]' AND LOG.METHOD = 'DECISION' AND LOG.EVT_ID = 'COMPLETED' THEN 'Journal Entry Rejected'
WHEN LOG.WI_RH_TASK = '[WF_TASK_ID_CHANGES_REQ]' AND LOG.METHOD = 'DECISION' AND LOG.EVT_ID = 'COMPLETED' THEN 'Journal Entry Changes Requested'
ELSE NULL
END AS "ActivityName",
TO_TIMESTAMP(CONCAT(LOG.EVT_DATE, LOG.EVT_TIME), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
NULL AS "TransactionCode",
FALSE AS "IsReversed"
FROM DOC_HEADERS H
JOIN SWW_WI2OBJ WIOBJ ON WIOBJ.INSTID = CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AND WIOBJ.TYPEID = 'BKPF'
JOIN SWWLOGHIST LOG ON WIOBJ.WI_ID = LOG.WI_ID
LEFT JOIN V_USERNAME U ON LOG.EXEC_USER = U.BNAME
WHERE LOG.WI_RH_TASK IN ('[WF_TASK_ID_SUBMIT]', '[WF_TASK_ID_APPROVE]', '[WF_TASK_ID_REJECT]', '[WF_TASK_ID_CHANGES_REQ]')
UNION ALL
-- Event 14: Manual Entry Identified
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Manual Entry Identified' AS "ActivityName",
TO_TIMESTAMP(CONCAT(H.CPUDT, H.CPUTM), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
CASE WHEN H.STBLG IS NOT NULL AND H.STBLG <> '' THEN TRUE ELSE FALSE END AS "IsReversed"
FROM DOC_HEADERS H
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE H.TCODE IN ('FB01', 'F-02', 'FB50', 'F-04', 'F-22', 'F-43', 'FB60', 'FB70', 'FV50', 'FV60', 'FV70')
UNION ALL
-- Event 15: Cross-Company Posting Identified
SELECT
CONCAT(H.BUKRS, H.BELNR, H.GJAHR) AS "JournalEntryId",
'Cross-Company Posting Identified' AS "ActivityName",
TO_TIMESTAMP(CONCAT(H.CPUDT, H.CPUTM), 'YYYYMMDDHH24MISS') AS "EventTime",
U.NAME_TEXT AS "User",
H.BUKRS AS "CompanyCode",
H.BLART AS "DocumentType",
H.BUDAT AS "PostingDate",
H.TCODE AS "TransactionCode",
CASE WHEN H.STBLG IS NOT NULL AND H.STBLG <> '' THEN TRUE ELSE FALSE END AS "IsReversed"
FROM DOC_HEADERS H
LEFT JOIN V_USERNAME U ON H.USNAM = U.BNAME
WHERE H.XRECH = 'X' Steps
- Establish SAP Connection: In your third-party ETL tool, configure a new source connection to your SAP ECC system. This typically requires the application server details, client, system number, and a dedicated SAP user with the necessary RFC authorizations.
- Define Data Sources: Within your extraction project, add the required SAP tables as data sources. The primary tables include BKPF (Accounting Document Header), BSEG (Accounting Document Segment), VBSEGK (Parked Document Header), CDHDR (Change Document Header), CDPOS (Change Document Items), SWW_WI2OBJ (Workflow to Object Links), SWWLOGHIST (Workflow Log), and SRGBTBREL (Relationships for GOS Attachments).
- Extract Base Events (Created & Parked): Create the first data flow to extract initial events. For 'Journal Entry Parked', use VBSEGK as the source. For 'Journal Entry Created', use BKPF, ensuring you filter for documents that are not reversals and were not initially parked. This can be done by anti-joining with VBSEGK.
- Extract Workflow Events: Create a data flow joining BKPF to SWW_WI2OBJ using the object key (company code + document number + fiscal year) to find the workflow instance ID. Join this result with SWWLOGHIST to extract events like 'Submitted', 'Approved', 'Rejected', and 'Changes Requested' based on the workflow task outcomes and user decisions recorded in the log.
- Extract Change and Deletion Events: Use tables CDHDR and CDPOS to identify changes. For 'Journal Entry Corrected', filter for changes made to parked documents (Object Class 'FIPP'). For 'Parked Journal Entry Deleted', look for deletion markers in the change logs for parked documents.
- Extract Attachment Events: To capture 'Documentation Attached', join BKPF to SRGBTBREL where the object type is 'BKPF' and the relationship is '[Your attachment relationship type]'. The creation date of the link serves as the event time.
- Extract Clearing and Reversal Events: For 'Journal Entry Line Item Cleared', query the BSEG table where the clearing document field (AUGBL) is populated. The event time is the posting date of the clearing document (AUGDT). For 'Journal Entry Reversal Processed', query BKPF for documents that are reversals, identified by having a value in the reversed document field (STBLG).
- Derive Calculated Events: Create separate logic blocks for calculated events. For 'Manual Entry Identified', filter BKPF based on a list of manual transaction codes (e.g., FB01, FB50, F-02). For 'Cross-Company Posting Identified', group the BSEG table by document ID and identify documents with more than one distinct company code.
- Combine All Event Flows: Use a UNION transformation in your ETL tool to merge the outputs from all the individual event flows (Created, Parked, Approved, etc.) into a single event log table. Ensure the column names and data types are consistent across all flows.
- Map to Final Schema: Map the combined data to the required event log structure, creating the
JournalEntryId,ActivityName,EventTime,User, and other required and recommended attributes. Add static columns likeSourceSystemand use the ETL job's execution time forLastDataUpdate. - Configure Incremental Loading: For ongoing extractions, configure an incremental loading strategy. Use the last creation or change date (e.g., BKPF.CPUDT, CDHDR.UDATE) as a watermark to only pull new or updated records since the last run.
- Export for ProcessMind: Schedule the extraction job and configure the final output step to save the event log as a CSV or Parquet file in a location accessible by ProcessMind for upload.
Configuration
- Prerequisites: A licensed third-party ETL tool (e.g., Theobald Xtract Universal, Informatica, Talend) with a dedicated SAP connector. An SAP user account with RFC access and authorizations to read financial tables (e.g., S_TABU_DIS for table groups F_00, F_WF), workflow data, and change logs.
- Connection Parameters: You will need the SAP Application Server IP or hostname, System Number, and Client ID. Secure credential management should be used for the SAP username and password.
- Key Filters: Always apply filters on Company Code (BKPF.BUKRS) and Fiscal Year (BKPF.GJAHR) at the source to limit the data volume. It is highly recommended to filter on Document Creation Date (BKPF.CPUDT) to define a specific extraction period, for example, the last 6 months.
- Date Range Selection: For the initial load, select a representative period like 3 to 6 months. For subsequent delta loads, use a watermark on a timestamp field like
CPUDTto fetch only new records. - Performance Considerations: Joins on BSEG, CDPOS, and workflow tables can be very slow. Ensure your ETL tool pushes down filters to the SAP source where possible. Extract data in smaller chunks or packages if the tool allows, especially for large historical loads.
- Workflow Customization: The logic to identify workflow activities like 'Approved' or 'Rejected' depends heavily on your specific workflow templates. You will need to identify the correct workflow task IDs and user decision keys from your system to use in the filters.
a Sample Query config
/*
This is a logical representation of the extraction configuration in a third-party ETL tool.
It is not executable SQL but defines the sources, joins, and transformations for each activity.
Placeholders like [Your SAP Source], [Date Filter], and [Company Code Filter] must be configured in the tool.
*/
-- Extraction block for 'Journal Entry Parked'
SELECT
CONCAT(v.BUKRS, v.VBELN, v.GJAHR) AS JournalEntryId,
'Journal Entry Parked' AS ActivityName,
CAST(CONCAT(v.CPUDT, v.CPUTM) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
v.USNAM AS User,
v.BUKRS AS CompanyCode,
v.BLART AS DocumentType,
v.BUDAT AS PostingDate,
v.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].VBSEGK v
WHERE [Date Filter on v.CPUDT] AND [Company Code Filter on v.BUKRS]
UNION ALL
-- Extraction block for 'Journal Entry Created'
SELECT
CONCAT(h.BUKRS, h.BELNR, h.GJAHR) AS JournalEntryId,
'Journal Entry Created' AS ActivityName,
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].BKPF h
LEFT JOIN [Your SAP Source].VBSEGK v ON h.AWKEY = CONCAT(v.BUKRS, v.VBELN, v.GJAHR)
WHERE h.BSTAT = '' AND v.VBELN IS NULL AND h.STBLG IS NULL
AND [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
UNION ALL
-- Extraction block for 'Journal Entry Posted' (from parked)
SELECT
CONCAT(h.BUKRS, h.BELNR, h.GJAHR) AS JournalEntryId,
'Journal Entry Posted' AS ActivityName,
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime, -- Or a more precise posting time from change logs if available
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].BKPF h
JOIN [Your SAP Source].VBSEGK v ON h.AWKEY = CONCAT(v.BUKRS, v.VBELN, v.GJAHR)
WHERE [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
UNION ALL
-- Extraction block for 'Journal Entry Submitted', 'Approved', 'Rejected', 'Changes Requested'
SELECT
CONCAT(SUBSTRING(o.INSTID, 3, 4), SUBSTRING(o.INSTID, 7, 10), SUBSTRING(o.INSTID, 17, 4)) AS JournalEntryId,
CASE
WHEN wl.WI_TEXT LIKE '%Submit%' THEN 'Journal Entry Submitted'
WHEN wl.WI_TEXT LIKE '%Approve%' THEN 'Journal Entry Approved'
WHEN wl.WI_TEXT LIKE '%Reject%' THEN 'Journal Entry Rejected'
WHEN wl.WI_TEXT LIKE '%Request Changes%' THEN 'Journal Entry Changes Requested'
END AS ActivityName,
CAST(CONCAT(wl.WI_CD, wl.WI_CT) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
wl.EXEC_USER AS User,
SUBSTRING(o.INSTID, 3, 4) AS CompanyCode,
NULL AS DocumentType,
NULL AS PostingDate,
NULL AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].SWW_WI2OBJ o
JOIN [Your SAP Source].SWWLOGHIST wl ON o.WI_ID = wl.WI_ID
WHERE o.TYPEID = 'BKPF' AND o.CATID = 'BO'
AND wl.WI_TEXT IN ('[Your Submit Task Name]', '[Your Approve Task Name]', '[Your Reject Task Name]', '[Your Changes Request Task Name]')
AND [Date Filter on wl.WI_CD]
UNION ALL
-- Extraction block for 'Journal Entry Corrected'
SELECT
CONCAT(cd.OBJECTID_LONG_CHAR(3,4), cd.OBJECTID_LONG_CHAR(7,10), cd.OBJECTID_LONG_CHAR(17,4)) AS JournalEntryId,
'Journal Entry Corrected' AS ActivityName,
CAST(CONCAT(cd.UDATE, cd.UTIME) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
cd.USERNAME AS User,
cd.OBJECTID_LONG_CHAR(3,4) AS CompanyCode,
NULL AS DocumentType,
NULL AS PostingDate,
cd.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].CDHDR cd
WHERE cd.OBJECTCLAS = 'FIPP' AND cd.CHANGE_IND = 'U'
AND [Date Filter on cd.UDATE]
UNION ALL
-- Extraction block for 'Parked Journal Entry Deleted'
SELECT
CONCAT(cd.OBJECTID_LONG_CHAR(3,4), cd.OBJECTID_LONG_CHAR(7,10), cd.OBJECTID_LONG_CHAR(17,4)) AS JournalEntryId,
'Parked Journal Entry Deleted' AS ActivityName,
CAST(CONCAT(cd.UDATE, cd.UTIME) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
cd.USERNAME AS User,
cd.OBJECTID_LONG_CHAR(3,4) AS CompanyCode,
NULL AS DocumentType,
NULL AS PostingDate,
cd.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].CDHDR cd
WHERE cd.OBJECTCLAS = 'FIPP' AND cd.CHANGE_IND = 'D'
AND [Date Filter on cd.UDATE]
UNION ALL
-- Extraction block for 'Documentation Attached'
SELECT
CONCAT(SUBSTRING(r.INSTID_A, 3, 4), SUBSTRING(r.INSTID_A, 7, 10), SUBSTRING(r.INSTID_A, 17, 4)) AS JournalEntryId,
'Documentation Attached' AS ActivityName,
-- Note: A precise timestamp is often unavailable. Using document creation time as a proxy.
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].SRGBTBREL r
JOIN [Your SAP Source].BKPF h ON h.BUKRS = SUBSTRING(r.INSTID_A, 3, 4) AND h.BELNR = SUBSTRING(r.INSTID_A, 7, 10) AND h.GJAHR = SUBSTRING(r.INSTID_A, 17, 4)
WHERE r.TYPEID_A = 'BKPF' AND r.RELTYPE = '[Configure based on your system]'
AND [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
UNION ALL
-- Extraction block for 'Journal Entry Reversal Processed'
SELECT
CONCAT(h.BUKRS, h.BELNR, h.GJAHR) AS JournalEntryId,
'Journal Entry Reversal Processed' AS ActivityName,
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
TRUE AS IsReversed
FROM [Your SAP Source].BKPF h
WHERE h.STBLG IS NOT NULL AND h.STBLG <> ''
AND [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
UNION ALL
-- Extraction block for 'Is Reversed' flag on original document
SELECT
CONCAT(h_orig.BUKRS, h_orig.BELNR, h_orig.GJAHR) AS JournalEntryId,
'Is Reversed' AS ActivityName, -- This is an attribute update, modeled as an event
CAST(CONCAT(h_rev.CPUDT, h_rev.CPUTM) AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h_rev.USNAM AS User,
h_orig.BUKRS AS CompanyCode,
h_orig.BLART AS DocumentType,
h_orig.BUDAT AS PostingDate,
h_orig.TCODE AS TransactionCode,
TRUE AS IsReversed
FROM [Your SAP Source].BKPF h_rev
JOIN [Your SAP Source].BKPF h_orig ON h_rev.STBLG = h_orig.BELNR AND h_rev.BUKRS = h_orig.BUKRS AND h_rev.GJAHR_S = h_orig.GJAHR
WHERE h_rev.STBLG IS NOT NULL AND h_rev.STBLG <> ''
AND [Date Filter on h_rev.CPUDT] AND [Company Code Filter on h_rev.BUKRS]
UNION ALL
-- Extraction block for 'Journal Entry Line Item Cleared'
SELECT
CONCAT(i.BUKRS, i.BELNR, i.GJAHR) AS JournalEntryId,
'Journal Entry Line Item Cleared' AS ActivityName,
CAST(i.AUGDT AS TIMESTAMP) AS EventTime,
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
NULL AS User, -- User who performed clearing is on the clearing document header
i.BUKRS AS CompanyCode,
NULL AS DocumentType,
NULL AS PostingDate,
NULL AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].BSEG i
WHERE i.AUGBL IS NOT NULL AND i.AUGBL <> ''
AND [Date Filter on i.AUGDT] AND [Company Code Filter on i.BUKRS]
UNION ALL
-- Extraction block for 'Manual Entry Identified'
SELECT
CONCAT(h.BUKRS, h.BELNR, h.GJAHR) AS JournalEntryId,
'Manual Entry Identified' AS ActivityName,
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime, -- Same time as creation
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
FALSE AS IsReversed
FROM [Your SAP Source].BKPF h
WHERE h.TCODE IN ('FB01', 'F-02', 'FB50', 'FV50', '[Add other manual T-Codes]')
AND [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
UNION ALL
-- Extraction block for 'Cross-Company Posting Identified'
SELECT
JournalEntryId,
'Cross-Company Posting Identified' AS ActivityName,
EventTime, -- Same time as creation
'SAP ECC' AS SourceSystem,
NOW() AS LastDataUpdate,
User,
CompanyCode,
DocumentType,
PostingDate,
TransactionCode,
IsReversed
FROM (
SELECT
CONCAT(h.BUKRS, h.BELNR, h.GJAHR) AS JournalEntryId,
CAST(CONCAT(h.CPUDT, h.CPUTM) AS TIMESTAMP) AS EventTime,
h.USNAM AS User,
h.BUKRS AS CompanyCode,
h.BLART AS DocumentType,
h.BUDAT AS PostingDate,
h.TCODE AS TransactionCode,
FALSE AS IsReversed,
(SELECT COUNT(DISTINCT i.BUKRS) FROM [Your SAP Source].BSEG i WHERE i.BELNR = h.BELNR AND i.BUKRS = h.BUKRS AND i.GJAHR = h.GJAHR) as CompanyCodeCount
FROM [Your SAP Source].BKPF h
WHERE [Date Filter on h.CPUDT] AND [Company Code Filter on h.BUKRS]
) AS CrossCompanyCheck
WHERE CompanyCodeCount > 1