R/3’s Payroll functionality allows you to charge payroll costs from one company code to another. However, it does not always work the way you want it to. You may be unable to charge a cost to another code or an unwanted charge could appear on your company code. You can create a function module that alerts you to invalid cross charges so that you can verify the information and correct any errors.
One of the strengths of R/3’s Payroll functionality is the ability to charge payroll costs from one company code to another, commonly called “cross charging.” When posting the payroll results to FI/CO, payroll creates accounting documents for each company. However, a problem occurs when you want to allow cross-company postings for some companies but not for others.
A common example is when you process retiree or long-term disability payrolls in the same SAP system your operating companies use. Since retirement and disability payments are paid from trust funds (as opposed to the company’s operating funds), most often companies do not want to charge part of a retiree’s pension payments to an operating company, or charge part of an active employee’s payments to the disability trust fund. Even though the payrolls might be run together in the same system at the same time, co-mingling of the funds is not allowed. SAP Payroll has no standard functionality to allow cross charges in some cases while preventing them in others. I will show you how to create a function module that prevents cross charges between specific company codes.
Glossary
A function module is ABAP code designed to perform specific units of work. A function module can be created to control cross-company accounting in SAP HR/Payroll infotypes and Cross- Application Time Sheet (CATS).
How Cross Accounting Works
Some users might not be aware of the specific functionality that enables cross-company accounting for employee expenses. Table 1 lists commonly used infotypes that allow a user to override a default cost assignment. For example, if an employee’s infotype 0001 (organization assignment) is in company 1000 (manufacturing), but the employee is temporarily spending 50 percent of the time on a project in subsidiary company 2000 (distribution), then you can use infotype 0027 to charge 50 percent of all the costs to a cost center in company 2000. When payroll is posted to FI/CO, it creates an accounting document for the employee’s main assignment in company 1000 and a second document for the infotype 0027 cost center in company 2000.
0014, 0015
|
Edit>Maintain cost assignment
|
Wage type
|
0267
|
Goto>Cost assignment
|
Wage type
|
0221
|
Goto>Cost center
|
Wage type
|
2010
|
Goto>Accounting/Logistics specs>Cost assignment
|
Wage type
|
2001, 2002, ordirectly or via CATS
|
Goto>Accounting/Logistics specs>Cost assignment in 2001and 2002
|
Absence/attendance
|
0027
|
No menu path. Set the distribution code to 0001 for wage/salary
|
All wage types for an employee that are mapped to cost accounts
|
|
|
Table 1 |
Commonly used infotypes with cost assignment overrides |
|
Now let’s say that you pay retirees from company 9999. Users could put a company 1000 override cost assignment on a retiree’s wage types in infotypes 0014 or 0015, or charge a portion of all their costs with an infotype 0027 entry. This could have been a data-entry error or it could have been processed by someone who thought that part of a retiree’s charges needed to go to company 1000. When payroll posts to FI/CO, it would generate accounting documents for companies 1000 and 9999. This is the type of HR/Payroll transaction that accountants want to prevent, since it mixes funds between operating and trust companies.
Creating the Solution
To solve this problem, you can implement custom ABAP programming to return an error when someone attempts to cross charge between two specific company codes. For master data infotypes, you implement the AFTER_INPUT method in the HRPAD00INFTY BAdI, and for cross-application time sheets (CATS) you implement user exit CATS0003 (shown at the end of this section). Both call a custom function module that compares the employee’s home company code from infotype 0001 to the company code in the cost assignment override. If an invalid combination is found, it returns an error, warning, or informational message to the user. Depending on the type of message, the user would then correct, verify, or simply proceed.
First, you need a table that tells which company code combinations are invalid. Figure 1 shows the structure of this table. For each invalid company code combination, you specify an error type. An error type of E prevents users from saving the override; a W presents them with a warning message but still lets them save the data; an I error type simply returns a message without taking any action to prevent the saving of the data. Along with the table definition, it is good to create a table maintenance view to make it more convenient to maintain data in the table. To create a maintenance view, access the Utilities>Table maintenance generator menu path in the data dictionary.

Figure 1
Structure of the cross-charge table
Second, you’ll create a function module named ZPA_CHECK_COST_ASSIGNMENT that queries the table and returns an error condition if a match is found. Next I’ll explain the ABAP code for this function module in logical steps. Figure 2 shows that the input for this function module is two data structures. The field IPREF contains the override cost assignment and field INEW_INNNN contains the infotype values. For example, if the user is adding a cost assignment to an infotype 0014, IPREF contains the override cost assignment and INEW_NNNN contains the infotype 0014 values. The custom type ZCROSSCHARGEis a data type that was created to match the structure of table ZHPACROSSCHARGE.
function zpa_check_cost_assignment. *”——————————————————————————————————— *”*”Local interface: *” IMPORTING *” VALUE(INEW_INNNN) TYPE PRELP *” VALUE(IPREF) TYPE PREF *”——————————————————————————————————— * * This function determines if an infotype’s override * cost center is allowed according to table ZHPACROSSCHARGE * data: invalid_assignment, tab_0001 type standard table of prel_db, lw_0001 type p0001, cross_charge type zcrosscharge, error_begda(10) type c, error_endda(10) type c.
|
|
Figure 2 |
Definition of function ZPA_CHECK_COST_ASSIGNMENT |
|
To increase efficiency, before proceeding to read infotype 0001 (step 2), check to see if there is a cost assignment override (Figure 3). None of the following ABAP code needs to be executed if there is no cost assignment override.
* only proceed if there is something in ipref, which * has the cost assignment override data if not ipref-bukrs is initial. invalid_assignment = ‘’. * go get all the infotype 1’s in the ipref date range call function ‘HR_READ_INFOTYPE’ exporting tclas = ‘A’ pernr = inew_innnn-pernr infty = ‘0001’ begda = inew_innnn-begda endda = inew_innnn-endda tables infty_tab = tab_0001.
|
|
Figure 3
|
Check for cost override and read infotype 0001
|
|
The function’s second step is to read the employee’s infotype 0001 and retrieve the company code from the organization assignment. The R/3 standard function HR_READ_INFOTYPE is used to retrieve this data. There could be several infotype 0001 entries within the date range of the current infotype being created, and you should check them all. The HR_READ_INFOTYPE function returns all the matching infotypes within that date range to the table TAB_0001.
Now that you have read infotype 0001 and know the employee’s main company code, you can check it against the company code coming from the cost assignment override, as shown in Figure 4. For each of the infotype 0001 entries found, read table ZHPACROSSCHARGE using the infotype 0001 company code and the company code from the cost assignment override. Since infotypes are all date- effective, you read the ZHPACROSSCHARGE table with those dates, making sure to look for any cases in which the date ranges overlap. If you find one, set the invalid_assignment flag to an X and exit from the loop processing.
* look for invalid combinations of infotype 1 company and * the cost assignment company - first loop at all * infotype 1’s loop at tab_0001 into lw_0001. * search the ‘cross-charge not allowed table’ to see * if any company code combos are not allowed select single * from zhpacrosscharge into cross_charge where bukrs_in = lw_0001-bukrs and bukrs_out = ipref-bukrs and ( ( begda <= inew_innnn-endda and endda >= inew_innnn-begda ) or ( begda <= inew_innnn-begda and endda >= inew_innnn-endda ) ). * if we found one, it’s not a valid combo; there could * be multiple infotype 1 records in error, but let’s * just issue a message on the first one we find if sy-subrc = 0. invalid_assignment = ‘X’. exit. endif. endloop.
|
|
Figure 4 |
Comparing company code combination to list of invalid combinations |
|
If an invalid cross charge is found, a message is issued to the user, as shown in Figure 5. The begin and end dates of the infotype are written to display variables simply for better formatting. A case statement issues a message based on the type of error specified in ZHPACROSSCHARGE. In this example, message number 047 in a customer-specific message class ZH01 was used to display the cost enter, company code, and dates of the incorrect assignment. Use transaction SE91 for message class maintenance, as shown in Figure 6.
* if we found an invalid assignment, issue a message, * depending on the error type from the cross-charge * table entry that we found if invalid_assignment = ‘X’. write inew_innnn-begda to error_begda. write inew_innnn-endda to error_endda. case cross_charge-error_class. when ‘E’. * issue an error message e047(zh01) with ipref-kostl ipref-bukrs error_begda error_endda.. when ‘W’. * issue a warning message w047(zh01) with ipref-kostl ipref-bukrs error_begda error_endda.. when ‘I’. * issue an informational message message i047(zh01) with ipref-kostl ipref-bukrs error_begda error_endda.. when others. * the values should only be E/W/I, but just in case message w047(zh01) with ipref-kostl ipref-bukrs error_begda error_endda. endcase. endif. endif. “ on checking for external cost assignment indicator endfunction.
|
|
Figure 5 |
Issuing a message for invalid cross charges |
|

Figure 6
Messages in message class ZH01 using transaction SE91
Now that the function module and configuration table have been created, you need to plug them into the process of maintaining master data and CATS. Figure 7 shows an implementation of the HRPAD00INFTY BAdI, in the AFTER_UPDATE method, that calls your custom function module for infotypes 0014 and 0027. Infotypes 0015, 0221, 0267, 2001, 2002, and 2010 would be called in the same way as infotype 0014. Infotype 0027 has different processing, since it can have up to 25 different override cost centers and companies.
when ‘0027’. * read the infotype into working structures call method cl_hr_pnnnn_type_cast=>prelp_to_pnnnn exporting prelp = new_innnn importing pnnnn = lw_0027. do 25 times varying bukrs_27 from lw_0027-kbu01 next lw_0027-kbu02 varying gsber_27 from lw_0027-kgb01 next lw_0027-kgb02 varying kostl_27 from lw_0027-kst01 next lw_0027-kst02 varying percent_27 from lw_0027-kpr01 next lw_0027-kpr02. if bukrs_27 is initial. exit. else. clear ipref. move-corresponding lw_0027 to ipref. move bukrs_27 to ipref-bukrs. move gsber_27 to ipref-gsber. move kostl_27 to ipref-kostl. * Check for invalid cross-company charges call function ‘ZPA_CHECK_COST_ASSIGNMENT’ exporting inew_innnn = new_innnn ipref = ipref. clear ipref. endif. enddo. * all done - save the infotype call method cl_hr_pnnnn_type_cast=>pnnnn_to_prelp exporting pnnnn = lw_0027 importing prelp = new_innnn. endcase.
|
|
Figure 7 |
Using the custom function in BAdI HRPAD00INFTY |
|
CATS works a little differently than master data maintenance. Figure 8 on the next page shows how to plug ZPA_CHECK_COST_ASSIGNMENT into CATS user exit CATS0003. CATS doesn’t use the PREF structure for cost assignment overrides and it doesn’t store its data in infotype structures, so you have to construct that before calling the function. First, use BAPI_COSTCENTER_GETDETAIL1 to find the company code that the CATS cost center is assigned to, and add them both to IPREF. Then fill IPREF and IPRELP (the infotype structure) with the data required by the function. Now you’re ready to call the function to check for invalid cross charges.
Tip!
To learn how to implement BAdIs and user exits, read the user manual at
https://help.sap.com. In Enterprise Release 4.70, use this menu path:
SAP Library>SAP NetWeaver Components>SAP Web Application Server>ABAP Workbench (BC-DWB)>Changing the SAP Standard (BC). In 4.6B and 4.6C, use a slightly different menu path:
SAP Library>Basis Components>ABAP Workbench (BC-DWB) >Changing the SAP Standard (BC). At this point, for any release, review the sections on BAdIs and customer exits.
Figure 9 displays what the users see when they assign an invalid company code combination. In this case, it is a warning that the user entered cost center 99999999 and company code 9999 as an override for this infotype 0015 payment, and that is not valid as of 5/1/2004.

Figure 9
What the user sees when entering invalid cross charges
Implementation Steps
Implementing this new functionality requires two critical steps. First, determine the effective date of the data in table ZHPACROSSCHARGE. Making this a date in the future is probably preferable for most companies because it limits the number of retroactive corrections.
The second critical step is to make sure the master data is correct as of that effective date. Since CATS and master data maintenance (transaction PA30) verify the screen data whenever it is displayed, you will not be allowed to change or save an invalid date if it is already in the system. For example, suppose you specified in table ZHPACROSSCHARGE that charges cannot be made from company 1000 to 9999 as of 5/1/2004, and that you will display an error message. However, an employee in company 1000 already has an infotype 0014 with a begin date of 1/1/2004, an end date of 12/31/2004, and an override cost assignment in company 9999. When that employee’s infotype 0014 is displayed, the system verifies the data via the new function module and returns an error. The user is not able to change or save the data.
Before implementing this change, all the incorrect data must be corrected. The incorrect data can be identified with SAP Queries and with the data browser on view ASSOB_HR. Make the corrections date- effective to prevent retroactive changes to payroll results. Once the incorrect data is resolved, the new function module can be implemented.
Steve Bogner
Steve Bogner is a managing partner at Insight Consulting Partners and has been working with SAP HR since 1993. He has consulted for various public, private, domestic, and global companies on their SAP HR/Payroll implementations; presented at the SAP user's group ASUG; and been featured on the Sky Radio Network program regarding SAP HR.
Steve will be presenting at the upcoming HR Payroll Seminar November 7-8 in Chicago and November 27-28 in Orlando. For information on the event, click
here.
You may contact the author at sbogner@insightcp.com.
If you have comments about this article or publication, or would like to submit an article idea, please contact the editor.