Вы находитесь на странице: 1из 22
Oracle 11i Advanced Pricing— Don’t Customize, Extend! An Oracle Technical White Paper May 2001

Oracle 11i Advanced Pricing— Don’t Customize, Extend!

An Oracle Technical White Paper May 2001

EXECUTIVE OVERVIEW

Don’t Customize. Extend!

Recently, Oracle demonstrated Advanced Pricing capabilities to an Internet Infrastructure Provider in the Silicon Valley. This company sells nothing but services, such as email server time and space, web hosting, e-commerce processing, etc. We felt Advanced Pricing was a perfect fit due to the large number of configurable service offerings sold by our prospect.

Our prospect required pricing rules that necessitated pricing calculations very tailored to this particular customer. Our analysis determined that these scenarios could be easily implemented using the standard Advanced Pricing functionality and the Get_Custom_Price public API.

The purpose of this white paper is to describe how our team was able to quickly and easily conform Advanced Pricing to meet these demanding requirements using this API, which is one of its key extensibility features.

Using API’s to Extend Advanced Pricing

It is important for everyone implementing Advanced Pricing including Customers, Sales Consultants, and Implementation Consultants, to understand that the use of Get_Custom_Price is an extension and not a customization because this is a public, supported API.

It is well understood that customizations are fraught with problems. Oracle recommends that customers avoiding customizations wherever possible. However, using the extensiblity API’s of Advanced pricing lets you extend the functionality of the product while avoiding the

downsides of customization.

over time, but the mechanics of Get_Custom_Price will not (or will be migrated if they do). In other words, if you keep all your custom code in this function, you're playing by the rules.

The data structure underlying Advanced Pricing may change

In many competitor systems, providing the kind of functionality this customer required would

have required an extensive, invasive customization.

Get_Custom_Price, the downsides of customization are readily avoided.

But with the extensibility features like

The Client’s Pricing Requirements

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 1

The scenarios the client presented us with were:

A prorated item. Any service fee should be prorated based on the number of days left in the

month.

A special surcharge item. Every sales order has, as its last item, a fee equal to 20% of the amount

of a specific group of items on a sales order.

A service refund credit item. The amount refunded on a monthly basis to a customer of our

prospect is based on a number of arbitrary "service credit" units. These service credit units are then used in a formula which takes into account, among other things, the amount spent on a specific group of services the prior month.

Quick Overview of Using Get_Custom_Price

We decided to use the Get_Custom_Price API with a formula to implement these scenarios. (Although it is possible to model a 20% surcharge on an order without the use of the custom API, the 20% surcharge is on the list price total of the order, not the selling price, the latter being the prospect's requirement.)

To use Get_Custom_Price, you define a formula in Oracle Advanced Pricing and source a formula line as a Function. After you save your formula, use Help—>Diagnostics—>Examine to get the formula_id attribute value. You will use this value in Get_Custom_Price to determine which block of code to execute for which formula.

Get_Custom_Price is a public function package QP_CUSTOM seeded as part of the QP installation. In fact, the install creates only a package header. It is up to you to create the package body function called Get_Custom_Price. This procedure has the following header declaration:

FUNCTION Get_Custom_Price (p_price_formula_id

IN NUMBER,

p_list_price

IN NUMBER,

p_price_effective_date IN DATE, p_req_line_attrs_tbl IN QP_FORMULA_PRICE_CALC_PVT.REQ_LINE_ATTRS_TBL) RETURN NUMBER IS

Key values are passed into the procedure, like formula_id and list_price. You can use the referenced PL/SQL table is to retrieve information about the order and order line.

To facilitate maintenance, we defined constants in our code:

C_surcharge_formula

C_prorate_formula CONSTANT

C_service_credit_formula CONSTANT INTEGER := 6177;

INTEGER := 6069;

CONSTANT INTEGER := 6026;

where the number value is the formula_id attribute from the Applications. In the body of the function, we use simple IF/THEN based on what formula is calling

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 2

Get_Custom_Price:

IF p_price_formula_id = C_prorate_formula THEN

.

.

END IF;

Client Scenario No. 2 – Prorated Item

We begin with the prorated item because it is the simplest scenario. This item has a list price which will be modified based on when this item is placed on (or repriced) on a sales order. Assuming this item costs $2000, then the prorated price will be $2000 on April 1, $1000 on April 15, and $66.67 on April 29. The formula for this is

price # of days left in month * ------------------ # of days in month

Fortunately, SQL*Plus has a function called last_day which returns the last day of the current month according to the sysdate global variable. The statement TO_CHAR ( LAST_DAY (sysdate), 'DD' ) returns the number of the last day of month (31, 30, 29, or 28).

The actual code block is as follows where

p_price_formula_id is passed automatically, C_prorate_formula is the constant for this formula_id,

l_number of days, l_todays date, l_number_of_days_left, and l_prorated_price

are local variables:

IF p_price_formula_id = C_prorate_formula THEN

-- get the last day of the month and the current day of the month

SELECT TO_NUMBER (TO_CHAR (LAST_DAY(SYSDATE), 'DD' )), TO_NUMBER (TO_CHAR (SYSDATE, 'DD' )) INTO l_number_of_days, l_todays_date FROM sys.dual;

l_number_of_days_left := l_number_of_days - l_todays_date;

-- apply the formula using the list price passed into this function l_prorated_price := (p_list_price / l_number_of_days) * l_number_of_days_left;

RETURN l_prorated_price;

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 3

To set up the price list line for this item, be sure to enter a list price and reference the formula

that calls Get_Custom_Price.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 4

Scenario No. 2 – Surcharge Item

Next, we discuss the 20% order surcharge item. This item's list price is 0 because it is dynamically derived based solely on properties of the current order. One formula component returns the selling price of the current order and other formula component is used to determine the percentage discount.

In order to determine the order total, we use one SQL statement to determine the header_id of the the parent header record of this line. Then we use another SQL statement to sum the selling price of all lines on the order except the surcharge item. (Counting the surcharge item would cause a recursive order amount increase on each line adjustment.)

SELECT

SUM ( ordered_quantity * unit_selling_price )

FROM

oe_order_lines_all

WHERE

inventory_item_id != C_surcharge_item_id

AND

header_id = [header_id for the surcharge item line]

The actual code block looks like this where p_price_formula_id is the formuld_id passed into the Get_Custom_Price call oe_order_pub.G_LINE.line_id retrieves the line_id for the current order line calling

Get_Custom_Price,

C_surcharge_item_id is the inventory_item_id value for the surcharge item you set up in the item master:

IF p_price_formula_id = C_surcharge_formula THEN

l_line_id := oe_order_pub.G_LINE.line_id; -- get current line

SELECT

oola.header_id

-- get the header id for the order

INTO

l_header_id

FROM

oe_order_lines_all oola

WHERE

oola.line_id = l_line_id;

-- sum the selling price of all lines except for the surcharge line -- in the current order

SELECT

SUM(oola.ordered_quantity * oola.unit_selling_price)

INTO

l_order_price

FROM

oe_order_lines_all oola

WHERE

oola.header_id = l_header_id

AND

oola.inventory_item_id != C_surcharge_item_id;

IF l_order_price IS NULL THEN l_order_price := NULL; END IF;

RETURN l_order_price; END IF;

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 5

Client Scenario No. 3 – Service Credit

The third formula is the service refund credit necessary to calculate the actual monetary amount to be refunded for services outages. This amount is based upon a tiered schedule of service credit units which are arbitrary. The formula provided by the prospect was:

#_

of

_

refund

_

units

#_

of

_

days

_

in

_

month

¥ previous

_

month s

'

_

subscription

_

fees

where the # of refund units is determined by the following tiered (range break) structure:

# of refund units

Factor

0

75

10

75

200

12

201

350

13

351

14

For this project, we used the current month subscription charges instead of the past month because the customer we set up in our demo system had no previous month's history. Assuming the only subscription item is an item called L53-SUBSCRIPTION, the following SQL script retrieves the total amount of L53-SUBSCRIPTION order lines for the current month that are on booked sales orders:

SELECT sum

( oola.ordered_quantity * oola.unit_selling_price )

FROM oe_order_lines_all oola, oe_order_headers_all ooha WHERE oola.sold_to_org_id = [customer_id] AND

oola.ordered_item = 'L53-SUBSCRIPTION'

AND

ooha.header_id = oola.header_id

AND

ooha.booked_flag = 'Y';

A better solution would be to define an item category that a customer would use to group

together items to be counted for the prior month subscription charges. In this case, you would reference inventory_category_id when selecting eligible lines for the total.

It is important to understand that the surcharge will be added to the list price which was set on

the price list as a price break header. For this reason, we subtract the list price for the service credit order line from the surcharge amount returned from Get_Custom_Price because this amount will be added right back by the pricing engine.

To use the price break feature to define the refund credit ranges, you need to set up the item

as a price break header on the price list to define the tiered ranges (range breaks).

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 6

Then, you create a modifier that applies a lumpsum surcharge for a range of 1-999999999 using the surcharge formula.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 7

Setup steps

1. Create inventory items for each pricing scenario. In this example,

we have created L53-PRORATE, L53-SURCHARGE, and

L53-SVCCREDIT.

2. Assign these items to the org(s) desired.

Setup for the prorated item

3. Create a pricing formula for the proration. In this example, we have

created L53-Monthly Proration.

4. Enter NVL (1, 2) in the Formula field on the formula header.

5. Create one formula line with a Formula Type of Function.

GET CUSTOM PRICE is automatically populated into the Component field and cannot be changed.

6. Enter 1 in the step field.

7. Create a second formula line with a Formula Type of Numeric

Constant, a Component of 0, and a Step of 2.

Numeric Constant , a Component of 0 , and a Step of 2 . 8. Save

8. Save the record.

9. Navigate to Help—>Diagnostics—>Examine and enter the

password APPS.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 8

10. Search for the PRICING_FORMULA_ID attribute and note the formula id. 11. Close the Pricing

10.

Search for the PRICING_FORMULA_ID attribute and note the formula id.

11.

Close the Pricing Formulas form and navigate to the Price Lists window.

12.

Add the L53-PRORATE item to a price list.

13.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 9

14. Enter a list price. In our example we used $2000.

3.

14. Enter a list price. In our example we used $2000. 3. © Oracle Corp 2001
14. Enter a list price. In our example we used $2000. 3. © Oracle Corp 2001

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 10

Surcharge item setup

14. In the Dynamic Formula field, enter the name of the formula you just created, L53-Monthly Proration in our example

15. Create a pricing formula for the surcharge item. In this example, we

have created 20% of Order.

16. Enter 2 * NVL(1, 3) in the Formula field on the formula header.

17. Create one formula line with a Formula Type of Function.

GET CUSTOM PRICE is automatically populated into the Component field and cannot be changed.

18. Enter 1 in the step field.

19. Create a second formula line with a Formula Type of Numeric

Constant, a Component of .2, and a Step of 2.

20. Create a third formula line with a Formula Type of Numeric Constant, a Component of 0, and a Step of 3.

21. Save the record.

22. Navigate to Help—>Diagnostics—>Examine and enter the password APPS.

23.

Search for the PRICING_FORMULA_ID attribute and note the formula

id.

Close the Pricing Formulas form and navigate to the Price Lists window.

24. Add the L53-SURCHARGE item to a price list.

25. Enter a list price. In our example we used $0.

26. In the Dynamic Formula field, enter the name of the formula you

just created, 20% of Order in our example.

Service credit refund item setup

27. Create a pricing formula for the service credit. In this example, we have created

JLS-Service Credit.

28. NVL ( 1, 2 ) in the Formula field on the formula header.

29. Create one formula line with a Formula Type of Function. GET CUSTOM PRICE is automatically populated into the Component field and cannot be changed.

30. Enter 1 in the step field.

31. Create a second formula line with a Formula Type of Numeric Constant, a Component of 0, and a Step of 2.

Save the record.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 11

32. Navigate to Help—>Diagnostics—>Examine and enter the password APPS . 33. Search for the

32. Navigate to Help—>Diagnostics—>Examine and enter the password APPS.

33. Search for the PRICING_FORMULA_ID attribute and note the formula id. Close the Pricing Formulas form and navigate to the Price Lists window.

34. Add the L53-SVCCREDIT item to a price list. Use Price Break Header as the line type.

35. Click the Price Breaks button and enter price breaks according to the following table:

From

To

Price

0

75

10

75

200

12

201

350

13

351

999999999

14

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 12

37. Close the Price Lists form. 38. Open the Define Modifiers form. 39. Create a

37. Close the Price Lists form.

38. Open the Define Modifiers form.

39. Create a new modifier of type Discount List. In our example, we called it JLS-07.

40. Create a modifier line and set these values in the Modifiers Summary tab.

Level

Modifier Type

Pricing Phase

Break Type

From

To

Line+

Surcharge

List Line Adjustment

Point

1

9999999999

List Line Adjustment Point 1 9999999999 41. Enter these values in the Discounts/Charges tab. Formula

41. Enter these values in the Discounts/Charges tab.

Formula

Application Method

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 13

JLS-Service Credit

Lumpsum

JLS-Service Credit Lumpsum 42. Save your work. 43. Modify the PL/SQL package provided here by setting

42. Save your work.

43. Modify the PL/SQL package provided here by setting the formula and item constants.

44. Set the formula contants for C_surcharge_formula, C_prorate_formula,

C_service_credit_formula to the values you obtained when setting up the formulae

45. Set the item contants for C_surcharge_item_id, C_subscription_item_id.

Note that you can use either the item_id or item_description.

46. Create function QP_CUSTOM.Get_Custom_Price by compiling the PL/SQL code that you have modified Make sure that your extension code written in get_custom_price is tuned for optimal performance. Otherwise, the Advanced Pricing engine performance will be negatively impacted.

47. Set the value of the profile option QP: Get Custom Price Customized.at the site level. If you have setup a formula to use the function but haven’t setup the profile then a runtime error will be displayed.

48. After the code compiles successfully, test your setup by creating a sales order. Make sure you add the surcharge item after you've added another item to have a sales order amount to discount.

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 14

© Oracle Corp 2001 All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM Page 15

Oracle Advanced Pricing:

Get_Custom_Price Code Example

WARNING: Your Get_custom_price routine should not issue any database commit. Issuing a commit will corrupt the Transaction data as well as Pricing data.

CREATE CREATE OR REPLACE PACKAGE BODY QP_CUSTOM AS

FUNCTION Get_Custom_Price (p_price_formula_id

IN NUMBER,

p_list_price

IN NUMBER,

RETURN NUMBER IS

p_price_effective_date IN DATE,

p_req_line_attrs_tbl

IN QP_FORMULA_PRICE_CALC_PVT.REQ_LINE_ATTRS_TBL)

l_number_of_days_left NUMBER;

l_number_of_days

l_prorated_price

-- number of days left in month -- number of days in month

NUMBER;

NUMBER (9,2); -- final prorated price

l_todays_date

NUMBER;

-- today's date day

l_order_price

NUMBER (9,2); -- total order selling price

l_header_id

NUMBER;

-- order header id

l_line_id

NUMBER;

-- order line id

l_line_quantity

NUMBER;

-- selling quantity

l_list_price

NUMBER;

-- line item list price

l_last_month_volume

NUMBER;

-- last month's sales volume for current customer

l_selling_price

NUMBER;

-- line price after discounts applied

l_line_list_price

NUMBER;

-- total line list price

l_refund_amount

NUMBER;

-- refund for service credit formula

l_surcharge

NUMBER;

-- surcharge for surcharge formula

-- formula constants identify which formula is being invoked -- according to formula_id

INTEGER := 6026; INTEGER := 6069;

C_service_credit_formula CONSTANT INTEGER := 6177;

C_surcharge_formula CONSTANT C_prorate_formula CONSTANT

-- surcharge formula ID -- proration formula ID -- service credit formula ID

-- The surcharge formula needs to know the inventory item id of the surcharge -- item so it doesn't use that item's price in the total order amount -- calculation. The service credit formula needs to know the item -- or items to count when determining prior month subscription charges. -- In this case, it's an item but it could be a group of items or a category

C_surcharge_item_id

CONSTANT INTEGER := 4534;

-- surcharge item ID

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM

Page 1

C_subscription_item_id

BEGIN

Oracle Advanced Pricing:

Get_Custom_Price Code Example

CONSTANT VARCHAR2(200) := 'L53-SUBSCRIPTION'

-------------------------------------------------------------------

-- Service credit refund formula

-------------------------------------------------------------------

IF p_price_formula_id = C_service_credit_formula THEN

-- use the oe_order_pub API to get header and line information

l_line_id

:= oe_order_pub.G_LINE.line_id;

l_line_quantity

:= oe_order_pub.G_LINE.ordered_quantity;

l_list_price

:= oe_order_pub.G_LINE.unit_list_price;

l_selling_price

:= oe_order_pub.G_LINE.unit_selling_price; -- after modifier applied

-- the following statement determines the total amount of item L53-SUBSCRIPTION -- ordered during the current month for the current customer. It only looks -- at booked orders.

SELECT sum ( oola.ordered_quantity * oola.unit_selling_price ) INTO l_last_month_volume FROM oe_order_lines_all oola, oe_order_headers_all ooha WHERE oola.sold_to_org_id = oe_order_pub.G_LINE.sold_to_org_id AND

oola.ordered_item = C_subscription_item_id

AND

ooha.header_id = oola.header_id

AND

ooha.booked_flag = 'Y';

-- l_last_month_volume := 10000; -- for testing purposes

-- get the number of days in the current month for the refund formula SELECT TO_NUMBER (TO_CHAR (LAST_DAY(SYSDATE), 'DD' )) INTO l_number_of_days FROM sys.dual;

Oracle Advanced Pricing:

Get_Custom_Price Code Example

-- because of the price-break component of this formula, we need to first get the list price -- of the refund item. This is the price break header price. In other words, the price break -- is set up on the price list, not in a modifier

l_line_list_price := l_line_quantity * l_list_price;

-- now we apply the formula to determine the total refund amount based on this month's volume l_refund_amount := ( l_line_list_price / l_number_of_days ) * l_last_month_volume;

-- because this formula is approved through a surcharge modifier, we now need to subtract the -- list price from the refund amount to get the surcharge. When this surcharge is added back -- to the list price, the refund amount is correct.

l_surcharge := (l_refund_amount - l_line_list_price) * -1 ;

-- the following is to insert values into a table -- for debugging purposes

--

--

insert into jls_Test

--

values ('QTY: ' || l_line_quantity || '

list: ' || l_list_price || ' selling: ' || l_selling_price

--

|| ' days: ' || l_number_of_days || ' line: ' || l_line_list_price || ' refund: '

--

|| l_refund_amount || ' surcharge: ' || l_surcharge || 'last month: ' || l_last_month_volume

--

|| ' line id: ' || l_line_id );

--

commit;

RETURN l_surcharge;

END IF;

-------------------------------------------------------------------

-- Proration formula

-------------------------------------------------------------------

IF p_price_formula_id = C_prorate_formula THEN

-- get the last day of the month and the current day of the month

SELECT TO_NUMBER (TO_CHAR (LAST_DAY(SYSDATE), 'DD' )),

© Oracle Corp 2001

All Rights Reserved Oracle Advanced Pricing: Extend Don’t Customize 5/16/01 9:51 AM

Page 3

Oracle Advanced Pricing:

Get_Custom_Price Code Example

TO_NUMBER (TO_CHAR (SYSDATE, 'DD' )) INTO l_number_of_days, l_todays_date FROM sys.dual;

l_number_of_days_left := l_number_of_days - l_todays_date;

-- apply the formula using the list price passed into this function l_prorated_price := (p_list_price / l_number_of_days) * l_number_of_days_left;

RETURN l_prorated_price;

END IF;

IF p_price_formula_id = C_surcharge_formula THEN

l_line_id := oe_order_pub.G_LINE.line_id; -- get current line

SELECT

oola.header_id

-- get the header id for the order

INTO

l_header_id

FROM

oe_order_lines_all oola

WHERE

oola.line_id = l_line_id;

-- sum the selling price of all lines except for the surcharge line -- in the current order

SELECT

SUM(oola.ordered_quantity * oola.unit_selling_price)

INTO

l_order_price

FROM

oe_order_lines_all oola

WHERE

oola.header_id = l_header_id

AND

oola.inventory_item_id != C_surcharge_item_id;

IF l_order_price IS NULL THEN l_order_price := NULL; END IF;

RETURN l_order_price; END IF;

END GET_CUSTOM_PRICE;

END QP_CUSTOM;

Oracle Advanced Pricing:

Get_Custom_Price Code Example

Oracle 11i Advanced Pricing Don’t Customize. Extend! May 2001 Author: Joshua Saffren Oracle Corporation World

Oracle 11i Advanced Pricing Don’t Customize. Extend! May 2001 Author: Joshua Saffren Oracle Corporation World Headquarters 500 Oracle Parkway Redwood Shores, CA 94065 U.S.A.

Worldwide Inquiries:

Phone: +1.650.506.7000

Fax: +1.650.506.7200

Web: www.oracle.com

This document is provided for informational purposes only and the information herein is subject to change without notice. Please report any errors herein to Oracle Corporation. Oracle Corporation does not provide any warranties covering and specifically disclaims any liability in connection with this document.

Oracle is a registered trademark, and Oracle Order Management is (are) a trademark(s) or registered trademark(s) of Oracle corporation. All other names may be trademarks of their respective owners.

Copyright © Oracle Corporation 2001 All Rights Reserved