Standard SAP sales and distribution (SD) pricing functionality can be quite tricky to configure in typical cost plus mark-up scenarios. Take a close look at all the necessary logic within the condition technique and ABAP pricing routines to take full control of the way SD calculates mark-ups on sales documents.
Key Concept
Cost plus mark-up is one of the most common pricing strategies used by companies across a wide range of industries. This pricing strategy requires the maintenance of two key pricing condition types in the SAP system — cost of the material and mark-up percentage. The cost condition type is then marked up by the percentage value of the mark-up condition type to determine the customer price on a sales document.
My example scenario of a rounding issue will help you overcome this problem. The example will lead you through the steps of using user exists and manipulating SAP standard behavior in pricing.
Standard SAP Behavior
Let me give you an example of a typical SD configuration for mark-up pricing and the system’s standard response to such configuration. Figure 1 demonstrates the pricing condition detail of a sales order line item that was priced using a custom mark-up condition ZMP1 (mark-up percentage). This mark-up was applied directly against the standard system condition type VPRS, which represents the cost of the material coming from material master data.

Figure 1
Rounding issues with standard SAP response
You can see that the customer is buying three CD players on this sales order. The moving average cost of the CD players, represented by the VPRS condition type, is equal to $19.99 per one player or $59.97 for all three. Condition type ZMP1 applies a 30% mark-up to the total value of condition type VPRS ($59.97 X 1.3) resulting in a total charge of $77.96 to the customer. When calculating the actual customer price per one CD player, standard SAP divides the total charge to the customer by the quantity that is being sold — $77.96 / three each (EA) — resulting in $25.9866... This price is in turn rounded to $25.99, as seen on the last Subtotal line in Figure 1. This is where the standard SAP response runs into a problem. How can you explain to your customer that $25.99 times three EA equals $77.96 and not $77.97? The core issue lies with the fact that the system applies the mark-up to the total value of the VPRS condition type and then calculates the rate of the net price backwards, resulting in rounding issues.
The steps that follow use two custom condition types. The first condition type ZMP1 (mark-up percentage) determines the mark-up percentage (e.g., 15%, 30%) and uses the condition technique to come up with its rate. The second custom condition type ZPRS (mark-up rate) uses the mark-up percentage from ZMP1 and calculates the rate of the customer price. Using the example in Figure 1, ZPRS calculates the price by taking the rate of condition type VPRS (cost) of $19.99 and marking it up 30% to come up with a rounded $25.99. From that point, the system takes over and calculates the net value of the item by multiplying the price of $25.99 by the quantity of three EA. The result is a total value of $77.97, thereby avoiding the rounding issues seen before. You need to use ABAP pricing routines and user exits to achieve some of this behavior.
Step 1. Create pricing routines. You first need to create a number of pricing routines that are later used in the pricing procedure to help control the behavior of the mark-up condition types. These routines are small ABAP functions that an ABAP programmer with a developer key needs to create. Proceed to transaction VOFM to access the routines overview screen. Select Requirements > Pricing.
The first routine you need to create is a requirements routine. This ensures that your ZPRS (mark-up rate) condition type is present on a sales order item only when ZMP1 (mark-up percentage) is present as well. Once you are in the Maintain: Requirements Pricing screen, create a new requirements routine by filling in the required fields on one of the new lines in the routines overview table (Figure 2). Make sure to select Application V (SD) to ensure that your requirements routine can be used in SD pricing.

Figure 2
Create the requirements routine
Once you've specified the routine number and added a description, click the source code icon in the top left corner to maintain the ABAP syntax of the routine. Use the example in Figure 3 for the necessary syntax. The new requirement routine makes sure to only include the ZPRS condition type if a) the sales order item is relevant for pricing, b) there is no condition exclusion taking place, and c) there is already an active ZMP1 condition type present on that line item.

Figure 3
Requirement routine ABAP syntax
Once the ABAP syntax of the new requirement routine has been specified, activate the routine. Select Program > Activate. Alternatively, you can press Ctrl-F3.
Now that the ABAP syntax has been activated, click the green arrow back icon at the top of the screen to go back to the list of the available requirement routines. You need to activate the routine once again from within this screen. To do so, first select the new requirement routine and then use menu path Edit > Activate. Refer to Figure 4 for an example of this activation. A check in the Active column indicates that you have successfully activated the new routine.

Figure 4
Activate the routine
Next, you need to create a condition value routine to help you address some of the rounding issues I explained earlier. Click the green arrow back icon to return to the initial VOFM overview screen. This time, use menu path Formulas > Condition Value (Figure 5) to see a list of all existing condition value routines.

Figure 5
Condition value routine
The general process here is similar to the one that you've used with the requirement routine. First, specify a valid routine number and description and set the Application to V, as shown in Figure 6.

Figure 6
Create the condition value routine
Next, click the source code icon to maintain the ABAP syntax. Refer to Figure 7 for an example of the desired logic. In this routine, you are basically performing the same general calculation of taking the rate or price in the pricing unit of measure and converting it into a total value of the line item, taking into consideration any conversions between pricing and sales units of measure. The difference is that you are performing all of the multiplication before you do any division, which helps you avoid rounding issues during the calculation process.

Figure 7
Condition value routine ABAP syntax
Follow the same steps that you've used for the requirement routine to active the new condition value routine. Refer to Figures 4 and 5 for a reminder.
Step 2. Modify the user exit. In this step, you use an SD pricing user exit to calculate the rate of condition type ZPRS. This rate reflects the unit price by taking the unit cost from condition type VPRS and marking it up by the percentage specified in condition type ZMP1. Standard SAP does not provide for modification of condition rate via VOFM routines, which is why you need a user exit instead. Just as in step 1, an ABAP programmer with a valid developer key needs to perform step 2 as well.
First you need to create a subroutine pool that stores the main logic for determining the mark-up rate. This way you can always reuse this logic for other user exits, if necessary. Proceed to transaction SE38, specify the name for the new subroutine pool, and click the create icon (Figure 8). In my example, I named the subroutine pool SAPFZMV45AFZZ.

Figure 8
Create a new subroutine pool
On the next screen, you need to specify a description, type, status, and application for your new subroutine pool (Figure 9). Click the save icon when you are done.

Figure 9
Subroutine pool attributes
Figure 10 shows the ABAP syntax of the get_zprs_rate routine. The routine first checks that both condition types VPRS (cost) and ZMP1 (mark-up percentage) are present because they are both needed to calculate the marked-up price. It then performs the calculation by taking the rate of condition type VPRS and marking it up by the rate of condition type ZMP1. Finally, the routine checks for any overflow issues where the resulting rate of ZPRS ends up being an extremely large number. This is necessary to prevent ABAP dumps. Make sure to activate the new subroutine pool by using the top menu path Program > Activate, similar to the way it is done in Figure 4.

Figure 10
ZPRS rate routine
Now that you have your routine for the calculation of the ZPRS rate encapsulated within a subroutine pool you need to actually call it within an SD pricing user exit. To do so, proceed to transaction SE38, enter program RV61AFZB , and click the Change button (Figure 11). As before, an ABAP developer must perform this step.

Figure 11
Modify the SD pricing user exit
Insert the call to the get_zprs_rate subroutine in the USEREXIT_XKOMV_BEWERTEN_INIT form of the RV61AFZB include. Figure 12 shows an example of this call. Make sure to activate the change to the user exit by going to Program > Activate.

Figure 12
Implement the call to get_zprs_rate
Step 3. Make configuration changes. First, you need to create our two new condition types within SD pricing configuration. Follow IMG menu path Sales and Distribution > Basic Functions > Pricing > Pricing Control > Define Condition Types or use transaction V/06. When you are in the SD condition type configuration overview screen, click the New Entries button at the top of the screen (Figure 13).

Figure 13
Condition type overview
The first condition type ZMP1 (mark-up percentage) is responsible for determining the appropriate percentage for the mark-up. Take a look at Figure 14 for an example of the necessary configuration. Note the use of A Percentage calculation type and A Positive in the Plus/minus field. These settings mean that only positive values are allowed for this condition type.

Figure 14
Condition type ZMP1
This condition type is going to use the standard condition technique to determine the mark-up percentage, meaning that various percentages are maintained as master data within the pricing condition records (transaction VK11) and the appropriate percentage is determined within the sales order by going through the access sequence that is assigned to the ZMP1 condition type. Note that in Figure 14 I've assigned access sequence K004 to the condition type. This is a standard access sequence, which works for the purposes of demonstration. However, you are more than likely going to create and assign a custom access sequence to fit your requirements for determining the appropriate mark-up percentage within the sales order. Leave the remaining settings blank.
Now that you are done with the configuration of condition type ZMP1, click the green arrow back icon in the top left corner of the screen to go back to the overview of condition types (Figure 14 ). Click the New Entries button to create the next condition type ZPRS.
The condition type ZPRS is not going to use the condition technique. Instead it uses the ABAP logic that you wrote in the first two steps to calculate its rate and value based on the cost (standard condition type VPRS) and the mark-up percentage (custom condition type ZMP1). Figure 15 shows an example of the appropriate configuration for the new condition type ZPRS. Note the use of B Prices in the Cond. class and C Quantity in the Calculat.type fields. Leave the access sequence assignment blank because you are using the user exit to determine the value of this condition type within the sales order. Click the save icon twice to save your changes to the condition type configuration.

Figure 15
Condition type ZPRS
Now that you have created both of the condition types, you need to add them to the pricing procedure. Use menu path Sales and Distribution > Basic Functions > Pricing > Pricing Control > Define and Assign Pricing Procedures > Maintain Pricing Procedures or use transaction V/08 to access this configuration step. Select the relevant pricing procedure and double-click the Control data node on the left side of the screen. In my example, I selected the pricing procedure ZPCBP1 (Figure 16), but you should select the pricing procedure that is used in sales order processing within your system’s environment.

Figure 16
Select the pricing procedure
Once you are within the detailed configuration of the pricing procedure, assign the two new condition types that you've just created. The specifics of this assignment depend on the current pricing procedure configuration, but you can refer to Figure 17 for an example of such an assignment. I assigned both of the condition types at the top of the pricing procedure, right under the cost condition type VPRS. I assigned the From column for condition type ZMP1 to 999 to prevent the calculation of the actual value of this condition type within the sales order.

Figure 17
Assign condition types to the pricing procedure
The ZMP1 condition type is only needed to determine the desired mark-up percentage from the pricing master data. Otherwise, having the value of this condition type within the sales order screen is confusing, especially since it is susceptible to rounding issues. Also, note that ZMP1 has been marked as statistical, designated by the check in the Stat... column. You have assigned the requirements routine 907 that you've created in step 1 of this article to your condition type ZPRS, to prevent it from appearing when there is no ZMP1 condition type present in the sales order item. You have also assigned the condition value routine 901 that you've created for condition type ZPRS to address some of the rounding issues in your calculations. Click the save icon twice at the top of the screen to save your changes to the pricing procedure configuration.
Step 4. See it in action.You are now ready to test your configuration and ABAP changes. First, you need to create the pricing master data for the mark-up percentage condition type ZMP1 so that you get an automatic price for the item within the sales order. Proceed via transaction VK11 to maintain pricing condition records. Enter condition type ZMP1 and press Enter or click the enter icon (Figure 18).

Figure 18
Create Condition Record initial screen
Remember that you've used the standard access sequence K004, which only has one condition table assigned to it. Note that if you decided to use a different custom access sequence, you might have to select the desired condition table in the next step. Otherwise, go ahead and maintain the condition record, similar to how it is done in Figure 19. In my example, I created a mark-up percentage of 30% for a CD player material. When you finish, click the save icon to save the new condition record.

Figure 19
Maintain the condition record
You are now ready to create the sales order for the CD player and see if you have been able to overcome the rounding issues. Use transaction VA01 to create a sales order, enter the material for which you've maintained the condition record (in this case, a CD player), and take a look at the condition detail of the sales order line item. You should see something similar to what is shown in Figure 20.

Figure 20
No more rounding issues
As you can see, you have been able to calculate the mark-up price correctly. The rate of the cost condition type VPRS of $19.99 has been marked up by 30% to achieve the price of $25.99, as seen in condition type ZPRS. This price was then multiplied by the quantity of three EA resulting in the correct total for the line of $77.97.
Anton Karnaukhov
Anton Karnaukhov is a senior IT manager at Pacific Coast Companies, Inc., in Sacramento, California. He earned an MBA degree at Heriot-Watt University and a BS/BA degree with a specialization in computer information systems at Western Carolina University. Anton has more than eight years of SAP implementation and development experience focusing on business intelligence and logistics modules in the manufacturing and resale industries.
You may contact the author at anton.karnaukhov@paccoast.com.
If you have comments about this article or publication, or would like to submit an article idea, please contact the editor.