Sie sind auf Seite 1von 13

Advanced Pricing Design: Avoid Black Box Approach

Sanjay Jain Fujitsu America

About Fujitsu America


Fujitsu provides a broad portfolio of integrated IT services and platforms including a complete line of scalable and reliable server, storage, and mobile solutions and a comprehensive suite of services for enterprise information management, packaged and custom application implementation, full platform, system and application lifecycle managed services, including customer services and infrastructure services. Fujitsu combines platform technologies, lifecycle services and industry expertise to create solutions for retail, manufacturing, healthcare, government & education, financial services and telecommunications sectors.

Abstract
Advanced Pricing is best exploited with extensions and the application provides extreme flexibility and a wide choice of the methods to implement extensions. This paper discusses the various supported methods available for extensions and suggests avoiding the black-box approach by making the setup maintenance friendly. A single complicated requirement is taken as a case-study and multiple extensions solutions are compared to arrive at the best!

Introduction
Advanced Pricing is a mature application and provides a host of tools and functionalities to meet the most complex pricing requirements. Since pricing strategies for various businesses can be extremely varied, no application can probably cover all kinds of scenarios. Advanced Pricing application, therefore provides extension tools which can be exploited when seeded functionality cannot meet the requirements. This paper provides a critical review of the extension features of Advanced Pricing application and then provides recommendations on specific extension features.

Customization v/s Extension


It is important to underline the difference between Customization and Extension. An extension is a custom code used within public API provided by the application. The code must be written per guidelines provided with the public API. Since these are supported APIs, the custom code is not considered a customization. In Pricing context, if there is a requirement to get the price of an item from a custom table, a customization approach would be, to have a form personalization, to auto-populate List Price field( Manual Pricing will be enabled through profile setup), from the custom table. An extension approach on the other hand could use the same logic in an extensible API (like QP_CUSTOM.Get_Custom_Price) which would be supported and easy to debug in case one runs into issues.

Extension Methods in Advanced Pricing


Advanced Pricing design is largely dependent on three kinds of attributes Product, Pricing and Qualifier attributes. Each of these can be grouped under one or more Contexts (Product Attributes have only a single context of ITEM). Application provides several seeded contexts and attributes, which may or may not be relevant to the business using this application. Custom

attributes can be defined in such scenarios which meet specific requirements of the business. As an example, age of wine could be an attribute determining its price. There is no seeded attribute for Age of Wine. A custom attribute is therefore needed. Attributes are used in Pricing entities viz. Price Lists, Modifiers and Formulae to ultimately fetch a numerical Price. The programmatic logic behind each of the attributes comes within the scope of extension and is called Attribute Sourcing. Following methods are available for Attribute Sourcing: User Entered Custom Sourced Attribute Mapping Runtime Sourcing

Of the above, User Entered is trivial as it is input by the user and there is no extension involved. This will therefore not be discussed in this work.

Custom Sourced:
Custom code is written in the package procedure QP_CUSTOM_SOURCE.Get_Custom_Attribute_Values. This is a public procedure without body where one can write custom code to assign values to the attributes. The Attribute manager API program (Build_Contexts) calls this procedure to pick up custom-sourced attributes if profile option QP_CUSTOM_SOURCED is set to Yes.

Attribute Mapping:
Custom code is written in a custom package which typically uses Global Structure tied to the Request type. Attribute mapping is also the mapping method used for most of the seeded attributes. It is possible to use your own mapping function instead of the seeded one in case this is needed. One place where it may be needed is the seeded Product Attribute of ALL Items. Seeded mapping for this attribute returns a constant value of ALL. It may be needed to identify subgroups within ALL for the purpose of pricing. So the User source type is specified as PL/SQL API Multi-Record and User value string contains the custom function returning multiple values as per custom Logic, including value of ALL.

Runtime Sourcing:
Runtime sourcing applies specific to accumulation attributes used for accumulated range break calculations. The logic for calculation is written in the package function QP_RUNTIME_SOURCE. Get_numeric_attribute_value During accumulated range break calculations, the pricing engine calls the Runtime Sourcing API to acquire an accumulation value for the accumulation attribute.

Extension Hook: Get_Custom_Price


Another extension hook provided is called GET_Custom_Price. This is a public function in seeded package QP_CUSTOM. The function has all pricing attributes available to it at runtime which can be used within the custom code written within. The code references one or more formulae. The function returns a Numeric value. Table 1.1 gives a comparison between the four extension methods in terms of their features.

Custom Sourced Used to source Product, Pricing and Qualifier Attributes Can return single as well as multiple values for the same Attribute Returns Char values which can be used for Numeric attributes using implicit conversion Procedure signature is fixed : QP_CUSTOM_SOURCE.Get_Custom_ Attribute_Values (p_req_type_code IN Varchar2 ,p_pricing_type_code IN Varchar2 ,x_qual_ctxts_result_tbl OUT ,QP_ATTR_MAPPING_PUB.contexts_re sult_tbl_type) Additional Parameters cannot be passed

Runtime Sourced Used to source Accumulation Attributes Returns a single Value used at runtime only Returns Numeric Value only Function Signature is fixed: Get_numeric_attribute_value( p_list_line_id IN NUMBER, p_list_line_no IN VARCHAR2, p_order_header_id IN NUMBER, p_order_line_id IN NUMBER, p_price_effective_date IN DATE, p_req_line_attrs_tbl IN ACCUM_REQ_LINE_ATTRS_TBL , p_accum_rec IN ACCUM_RECORD_TYPE ) Additional Parameters cannot be passed Profile Option QP: Accumulation Attribute Enabled must be set to Yes for this to work

Attribute Mapping Used to source Product, Pricing and Qualifier Attributes Can return single as well as multiple values for the same Attribute Returns Char as well as Numeric values as needed Mapping package is totally custom: so the functions can be defined with any signature, with as many parameters as needed.

QP_CUSTOM.Get_custom_Price Used to evaluate a Formula Step of type Function Returns a single Value Returns Numeric Value only. Function signature is fixed: 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.R EQ_LINE_ATTRS_TBL) Additional Parameters cannot be passed

Profile Option QP: Custom Sourced must be set to Yes for this to work

No Profile Option needed specifically for this to work

Profile Option QP: Get Custom Price Customized must be set to Yes for this to work

Table 1.1

Based on the above comparison alone; it is obvious that Attribute Mapping offers maximum flexibility and features and this shall be illustrated using an example requirement.

Requirement:
Client runs an Event Management business and offers Services to Event participants and Sponsors. Services are priced differently for Sponsor and participant. The price of a service depends on several factors like Date of Order, Date of Service, Install or Dismantle, Type of Event, Date of detailed plan received, UOM and a few others. Since the factors affecting the price are several, but similar for various events, client is maintaining the Pricing data on a custom form with all factors linearly displayed- which are better understood and easier to maintain than the seeded oracle feature of Effectivity Dates, Date Types and Pricing Attributes.

Solution:
To meet the above requirement, any of the three extension methods could be used: A price List is setup and a Dynamic Formula is used on the Price List Line.

COLLABORATE 09

Page 5

Copyright 2009 by Sanjay Jain

Using QP_CUSTOM.Get_custom_Price The formula step shall be setup with Formula Type of Function:

This Formula is referenced in the Body of Get_Custom_Price function and the complete Logic of getting the Price is written within: 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 lv_requested_item VARCHAR2 (240); lv_item_id_num NUMBER; lv_quantity_num NUMBER; lv_price_low_num NUMBER; lv_price_high_num NUMBER; lv_qty_low_num NUMBER; lv_uom_txt VARCHAR2 (3); lv_message_txt VARCHAR2 (240); lv_min_qty NUMBER; lv_min_qty1 NUMBER; CURSOR cur_price ( p_item_id NUMBER, p_quantity NUMBER) IS SELECT l_price_low, l_price_high, l_qty_low, o_uom FROM xxges.xgec_om_logistic_pricehint_stg WHERE 1 = 1 AND o_inventory_item_id = p_item_id AND p_quantity BETWEEN l_qty_low AND l_qty_high;

COLLABORATE 09

Page 6

Copyright 2009 by Sanjay Jain

CURSOR cur_price_formula ( p_formula_id NUMBER) IS SELECT NAME FROM qp_price_formulas_vl WHERE 1 = 1 AND price_formula_id = p_formula_id; BEGIN FOR formula_rec IN cur_price_formula (p_price_formula_id) LOOP --BEGIN IF formula_rec.NAME = 'Event Price' THEN BEGIN lv_item_id_num := oe_order_pub.g_line.inventory_item_id; lv_quantity_num := oe_order_pub.g_line.ordered_quantity; ----( complete code not reproduced)

Pricing Failure and Debugging


If pricing request fails for any reason, the user gets this message on the Order Screen:

To Debug this, it will be required to look at the OM debug file or Pricing debug file which are very detailed and not very user friendly.

COLLABORATE 09

Page 7

Copyright 2009 by Sanjay Jain

Using Custom Attributes with mapping method Custom Sourced


The factors affecting the Price are broken down into multiple Pricing Attributes as far as possible. Event Price itself is another Pricing Attribute.

The formula is still used, but uses the Formula Type of Pricing Attribute instead of Function:

COLLABORATE 09

Page 8

Copyright 2009 by Sanjay Jain

The Pricing code will be written in QP_CUSTOM_SOURCE.Get_Custom_Attribute_Values PROCEDURE Get_Custom_Attribute_Values ( p_req_type_code IN VARCHAR2 , p_pricing_type_code IN VARCHAR2 , x_qual_ctxts_result_tbl OUT QP_ATTR_MAPPING_PUB.CONTEXTS_RESULT_TBL_TYPE , x_price_ctxts_result_tbl OUT QP_ATTR_MAPPING_PUB.CONTEXTS_RESULT_TBL_TYPE ) IS lv_service_date DATE; lv_uom_class VARCHAR2 (100); lv_event_price_num NUMBER; lv__mode_txt VARCHAR2 (100); lv_primary_uom_code_txt mtl_system_items.primary_uom_code%TYPE; lv_rate_rec xgec_qp_matl_labor_rates%ROWTYPE; lv_no_of_tiers NUMBER; t_item_cat type_item_cat_plt; lv_pricing_tier_txt VARCHAR2 (30); lv_conversion_rate_num NUMBER; lv_order_uom_code_txt VARCHAR2 (30); lv_rec_cnt NUMBER; lv_line_type_txt VARCHAR2 (100); lv_line_type_id_out NUMBER; -BEGIN --- Use OE_ORDER_PUB.G_LINE global structure and write Logic to fetch various factors which decide the price -- and then assign the values of various attributes if p_req_type_code = 'ONT' and p_pricing_type_code in ('L','H') then -- Sourcing pricing attributes. x_price_ctxts_result_tbl(1).context_name := 'CUSTOM'; x_price_ctxts_result_tbl(1).attribute_name := 'PRICING_ATTRIBUTE1'; x_price_ctxts_result_tbl(1).attribute_value:= lv_event_price_num ; x_price_ctxts_result_tbl(2).context_name := 'CUSTOM'; x_price_ctxts_result_tbl(2).attribute_name := 'PRICING_ATTRIBUTE2'; x_price_ctxts_result_tbl(2).attribute_value:= lv_line_type_txt; x_price_ctxts_result_tbl(1).context_name := 'CUSTOM'; x_price_ctxts_result_tbl(1).attribute_name := lv_pricing_tier_txt; x_price_ctxts_result_tbl(1).attribute_value:= 'ALL'; x_price_ctxts_result_tbl(2).context_name := 'CUSTOM'; x_price_ctxts_result_tbl(2).attribute_name := 'PRICING_ATTRIBUTE3'; x_price_ctxts_result_tbl(2).attribute_value:= lv__mode_txt; End Get_Custom_Attribute_Values; END QP_CUSTOM_SOURCE; /
COLLABORATE 09 Page 9 Copyright 2009 by Sanjay Jain

Notice in the above code, several variables are defined which will be used to assign values to various pricing attributes. By doing so, we are exposing the price determining Attributes clearly to the user. These attributes shall be visible in the Pricing Engine Request Viewer:

Pricing Failure and Debugging


In this scenario, if the Pricing Request fails, user will still get the message Error in Formula Processing:

But, User shall be able to easily debug based on the various pricing attributes values fetched by the Pricing Engine and neatly displayed in the Request Viewer.

COLLABORATE 09

Page 10

Copyright 2009 by Sanjay Jain

In the code, instead of returning NULL in case of exceptions, an Invalid value should be returned. This INVALID value shows up in Red color in the request viewer- and through this, the source of error could easily be pinpointed:

One could always go to Debug Log still for more details; but most of the times, request viewer gives enough information for troubleshooting. The success of this approach depends on the way code is structured. In the above example, it is not always necessary to define attributes just for the purpose of ease of debugging. So, while designing and coding, ease of debugging must be considered- so that Pricing Engine calculations are as visible as possible. For Custom Sourced method, in summary, the following points should be considered: Define intermediate factors as attributes and explicitly evaluate and assign their values in the code. Exceptions should be handled such that an INVALID value is returned in case of exception instead of a NULL Detailed debug messages should be included so that debug Log could provide details about the pricing request calculations.

COLLABORATE 09

Page 11

Copyright 2009 by Sanjay Jain

Using Custom Attributes with mapping method Attribute Mapping


Attribute Mapping behavior is similar to Custom Sourced; except the fact, that Attributes are individually mapped to a custom function:

Note, there are several parameters passed in the above example mapping function.

COLLABORATE 09

Page 12

Copyright 2009 by Sanjay Jain

Parameterization provides further visibility and flexibility to the design. As an example, originally, the Pricing Date was supposed to decide the Price. Later, the business said, although order is placed- but the order is not complete till specific detailed information is provided by the customer. This date is captured on a DFF. This could be easily handled without code change, by manipulating the Pricing Date parameter in the mapping function. Another advantage of using parameters is, the mapping function can be re-used. As an example, consider a Pricing Attribute A which returns Segment1 of a specific Category. A mapping function could be written to meet this requirement: Get_Value_A(p_inventory_item_id IN). Now, if a second Attribute is needed, which evaluates another segment of the same category or another category, one would need to code another mapping function. Instead, if the original function is structured with parameters: Get_Cat_Segment_Value( p_inventory_item_id IN, p_category_Set_Name IN, p_segment IN) This structure provides two distinct advantages: Looking at this mapping in Attribute mapping window, it is easy to understand, what this function is exactly doing. This function can be re-used to map multiple attributes, by just changing the parameters

So over custom sourced, attribute mapping offers further advantages: Infinite parameterization which exposes the code further and makes it easy to modify and reuse. Some Level of code Logic: like Case statement and decodes can be written within the parameters which is visible, maintainable and easy to change Another function can be passed as parameter to the mapping function: again helping with maintainability and re-usability.

Runtime Sourced
Runtime Sourced is very specific in application- since it can only be used for Accumulation Attributes for accumulated range break calculation. Its behavior is similar to Get_custom_price except; that it is used to map an attribute instead of evaluating a function formula. Attribute Mapping can still be used to map the same accumulation attribute.

Conclusion & Recommendations


Based on above analysis, it is recommended that Attribute Mapping method should be used as a choice over the other three extension methods. Additionally, to take full advantage of the features so that the code is most visible for the purpose of understanding, re-using and debugging, maximum parameters should be used in mapping functions. Exceptions should be handled by returning not-null Invalid values. Detailed debug statements should be embedded in the code which will come handy when the attribute view alone does not help troubleshoot the pricing issues.
COLLABORATE 09 Page 13 Copyright 2009 by Sanjay Jain

Das könnte Ihnen auch gefallen