At some R/3 sites, the labor time spent on any given Manufacturing Order is recorded at a standard value, possibly as part of a backflushing transaction; at others, the hope is to have the operators record their actual time spent on each given Manufacturing Order, leaving wide open the possibility that operators may introduce data entry errors. SAP R/3 does not have a standard-delivered report that can identify which Manufacturing Orders have significant errors. However, this article demonstrates a fairly simple ABAP report that can make this kind of "exception research" easy to do.
At some R/3 sites, the labor time spent on any given Manufacturing Order is recorded at a standard value, possibly as part of a backflushing transaction. But at other sites, the hope is to have the operators record their actual time spent on each given Manufacturing Order. R/3 supports this. However, this leaves wide open the possibility that operators will sometimes forget or occasionally insert significant typos. This causes a huge headache for the Accounting department since the labor hours recorded have a direct impact on all of the following:
Manufacturing Order work-in-progress (WIP) and variance calculations
Cost Center Over-/Under-absorbed analysis
Cost-of-Goods-Sold calculation (e.g., in the case of Make-to-Order and/or moving average valued finished goods)
At period-end, there might be thousands and thousands of Manufacturing Orders that had been worked on during the month. Which ones, if any, have significant data entry errors? SAP R/3 does not have a standard-delivered report to support this kind of research. But a fairly simple ABAP report can make this kind of "exception research" easy to do. Its output might look something similar to what’s shown in Figure 1.
At month-end, the Accounting department will be very happy to have a way to quickly identify any orders with large Plan vs. Actual labor cost and labor quantity differences, prior to running their WIP, Variance, and Results Analysis calculation transactions.

Figure 1
Labor Confirmation ABAP Report — Sample Output
How Labor Time Gets Recorded onto a Manufacturing Order
To best understand how to write an ABAP report that looks for problems with the “Plan Labor Cost” and “Actual Labor Cost” measurements, I find it helps to understand the factors in R/3 that cause “Plan” and “Actual” labor cost values to be linked to one of the PP module’s Production Orders ...
Your report will highlight two measurements in the Production Order that are typically of great interest to the Accounting department. One is “Plan Labor Cost,” and the other “Actual Labor Cost.”
When a new Manufacturing Order is created, it generally has a predefined life cycle. What determines where that order is in its life cycle is something called “Status.” The most common status segments are “Created,” “Released,” “Partially Confirmed,” “Delivered,” and “Final Confirmation.”
Once an order’s status is changed to “Released,” in most cases this triggers an automatic calculation of its planned resource consumption — raw material, labor hours, etc.
These calculated values come from the Bill of Material (BOM) and the Routing of the finished good (material #) that the order is requesting from the Manufacturing department. R/3 takes that quantity information, and finds some cost rates (e.g., Material Master standard price, and Labor “Activity Type” standard price). It then records both a planned expense and planned quantity for each BOM Routing item into the CO module’s cost accounting ledger summary table (R/3 Table COSS).
When an operator is ready to record his or her time onto an order, he or she typically accesses a transaction called “Confirmation.” Within that transaction, the operator has the opportunity to type in the actual amount of time that he or she worked on that order. When the operator saves this data entry, R/3 takes that quantity information, and then finds the cost rates for the particular Activity Type(s) typed in by the operator, and records both an actual expense and actual quantity into the CO module’s cost accounting ledger summary table, COSS.
Two or Three Tables Factor into This Report
There are many different versions of the ABAP report that can be designed. I offer you pseudocode in the next section to help get your design efforts started. Before you begin, however, you need to understand which elements must be factored into your design. These elements can be used differently, depending on the final specifications you decide to go with:
- Cost Accounting Table COSS. This table stores summaries, not individual labor confirmation data entry values. The cost data is summarized by each unique combination of several fields including Manufacturing Order # (represented as an "Object" #), Value Type (i.e., Plan vs. Actual), and Cost Element # (i.e., the account # R/3 uses to record the labor expense).
- Object Status Table JEST. This table lists every status achieved or canceled by a cost accounting object such as a Manufacturing Order. Therefore, for any given Manufacturing Order, you can expect to find several JEST records. The status itself is stored as a code (e.g., I0009), and there is no text explanation. You need to access related Table TJ02T to get the text. Typically, a Manufacturing Order’s Object # will begin with the alpha characters "OR." This is important since the order’s actual number (e.g., 1000243) might belong to several kinds of cost accounting objects. The alpha characters make the numeric value unique.
Selecting Subsets of "Planned" vs. "Actual" Exceptions
The order "Status" will be one good runtime parameter option for the report user to have available as a filter criterion. Another will be either the "Activity Type" or the "Cost Element" #.
- Activity Type. This runtime parameter represents one category of labor. It can be alpha (e.g., "EXTRU"), or it can be numeric (e.g., "901001"), depending on the decisions made by the FI/CO team.
- Cost Element. This parameter is almost always numeric (e.g., # 7904100), although it can be created as an alpha (e.g., EXTR_LABOR). The operator who is confirming his or her time has no opportunity at all to choose a Cost Element. Instead, he or she can merely type in the labor time next to one or more Activity Type rows, and then Save.
Each Activity Type is linked to one and only one Cost Element (use transaction code "KL03" to view the master data). However, each Cost Element # can be linked to multiple Activity Types.
Therefore, depending on several factors (including personal preference), you will probably want to give the "Plan vs. Actual Exceptions" report analyst the runtime parameter option of selecting records based on either the Activity Type or the Cost Element #, but not both.
Note: For the example shown in Figure 1, I chose to include only the Cost Element (and not the Activity Type) as a runtime parameter.
Sample Pseudocode for the Report
You can download a free copy of the sample code I used to generate the ABAP report in Figure 1 at the bottom of this article. Here’s the pseudocode I devised before creating this report — you can use the same pseudocode to create your report:
Specify the mandatory runtime parameters:
Give the report user the runtime parameters of "Current Period," "Current Fiscal Year," "Status," and "Cost Element."
Note that the fields "Current Period" and "Current Fiscal Year" are single dates only, not From/To ranges.
For the field "Status," the user should be able to search via a matchcode (Table TJ02’s ISTAT field has this matchcode). For the field "Cost Element," the user should also be able to search by a matchcode. But only those Cost Elements that are linked to an Activity Type should appear in the "Possible Selections" list. An example of this kind of matchcode exists in the "Alloc. Cost element" field of any Activity Type master (transaction code "KL03").
The final important runtime parameters are "Cutoff Deviation – Cost" and "Cutoff Deviation % – Qty," where the user types in something like "500" and "25" for $500 and 25 percent, respectively. Note that all runtime parameters mentioned here need to be mandatory entry.
Restrict the volume of orders:
As a way to limit the sheer volume of manufacturing orders the ABAP code must process, it will be useful to first ask the report user to limit the orders to be processed based on a From/To date range of when the orders were first created. We would also like to give the report user the option to restrict the analysis based on Company Code, Plant, and/or Order Type. The table to be read from is the Order Master table, "AUFK."
Get the individual order #s:
Once a set of Manufacturing Orders has been selected from table "AUFK," use the report user’s choice of Status to select the individual orders that have achieved at least that status in their lifecycles. Each order’s status is stored in table "JEST." Verify that there are no duplicates (i.e., the same Object # should not be in more than one selected record). Ignore any Status record where field "Inactive" equals "X."
Get the Actual and Plan cost records for each order:
For each Manufacturing Order selected from "AUFK" that also met the needed status requirement in "JEST," use the report user’s choice of Current Year and Cost Element # to select all matching records from table COSS where "Value Type" = either "01" or "04."
In most cases, you will end up with two records per Order # — one with the "01" value type (plan) and one with the "04" (actual).
Note that it is also possible to end up with more than one "01" record and/or "04" record. This is because a single Cost Element can have a relationship with more than one "Partner Object" (field PAROB).
Calculate a year-to-date summary:
The temporary table you use to store the COSS record (maybe "ycoss"?) will need to have two additional columns — one each to store a calculated grand total of cost (WTG001 + WTG002 + …) and quantity (MEG001 + MEG002 + …) for the records of Value Type "04." For the records of Value Type "01," there is almost always just a single WTGxxx and WEGxxx field populated. But, for consistency, you probably need to sum them all up anyway into your WGTSUM and WEGSUM columns.
Isolate the exceptions:
For each combination of Object # and Partner Object (PAROB) in your "ycoss" table, there will now be at most two records — one for Plan ("01") and one for Actual ("04").
Calculate the difference in WGTSUM and WEGSUM between the "01" and "04" records, and then compare the difference to the report user’s choice of "Cutoff Deviation – Cost" (WGTSUM) and "Cutoff Deviation % – Qty" (WEGSUM).
Only present to the report user those Object #s that have differences greater than the cutoff targets.
For combinations that have just one record, or that do not have any recorded lifetime "Actual" costs, save those to present to the report user in the footnotes of the report.
Always remember that your report must be sensitive to status. For example, every order that is merely at the "Released" stage of its life will always have a huge difference between its Plan vs. Actual data. Knowing that, however, does not help the Accounting department!
Tim Hodge
Tim Hodge is a Senior Consultant with ICM America. He graduated with a B.S. in Computer Science from the University of Virginia. His consulting experience includes extensive technical project work for Global 1000 companies across several industries in the US, Canada, and Australia. His latest project involves designing an e-procurement solution, which his client plans to implement at sites on five continents. Tim currently resides in Charlotte, North Carolina.
You may contact the author at thodge@icm.de.
If you have comments about this article or publication, or would like to submit an article idea, please contact the editor.