An item’s original price instead of the current day price is used in the following situations:

The ItemPriceSource object allows you to provide pricing information based upon a specific Product/SKU combination. The override is then used in place of the default current day pricing.

This feature also provides the ability to generate a set of ItemPriceSource objects from the pricing information stored for the items within an order. This generates the source objects for pricing previously submitted orders and exchange orders by generating the source objects from the submitted order and the original purchase order.

ItemPriceSourceHandler Interface

The ItemPriceSourceHandler interface defines the API for generating ItemPriceSource objects from previously-priced items and consuming ItemPriceSource objects during a pricing operation. For example:

public interface ItemPriceSourceHandler
{
   //this method will be called when generating ItemPriceSources from previously
   //priced items in an Order. A true return value will indicate the handler
   //modified the ItemPriceSource.

    public boolean populateItemPriceSource(ItemPriceSource pPriceSource, Order
    pOrder,CommerceItenm pCommerceItem, CommerceItem pParentCommerceItem);

   //this method will be called by the individual calculators during a pricing
   //operation to get the matching ItemPriceSource for the item.

    public ItemPriceSource getItemPriceSource(ItemPriceInfo pPriceQuote,
    CommerceItem pItem, RepositoryItem pPricingModel, Locale pLocale,
    RepositoryItem pProfile, Map pExtraParameters);

   //this method will be called by the individual calculators during a pricing
   //operation to determine if the matching ItemPriceSource should be consumed by
   //the calculator. A false return means the calculator should bypass its normal
   //processing and immediately return.

   public boolean shouldConsumeSource(ItemPriceSource pItemPriceSource);
}
ItemPriceSourceHandler Implementing Calculators

The following ItemPriceCalculators and ItemSchemePriceCalculators implement the ItemPriceSourceHandler interface. The following calculators are stored in /atg/commerce/pricing/calculators:

Calculator Type

Calculator

Standard ItemPriceCalculators

ItemListPriceCalculator
ItemSalePriceCalculator
ConfigurableItemPriceCalculator

Price list ItemPriceCalculators

ItemPriceListCalculator
ItemPriceListSaleCalculator
ConfigurableItemPriceListCalculator
ConfigurableItemPriceListSaleCalculator

Scheme calculators

PriceListsListCalculator
PriceListsBulkCalculator
PriceListsTieredCalculator
SalePriceListsListCalculator
SalePriceListsBulkCalculator
SalePriceListsTieredCalculator

Generating ItemPriceSources from ItemPriceInfos

PricingTools provides the API for generating ItemPriceSources from an order. It instantiates an ItemPriceSource object for each CommerceItem and SubSkuItem in the order, as well as calling each ItemPriceSourceHandler to populate the calculator-specific values of the ItemPriceSource.

Each calculator provides a PricingAdjustment that details how the item price was adjusted by the calculator. These objects can be used to determine the original cost basis used by the calculator. Each PricingAdjustment created by a calculator contains a description specific to the calculator and each ItemPriceSourceHandler extracts their PricingAdjustment(s) from the ItemPriceInfo by matching the description.

For example, the standard list price calculator adds an adjustment:

PricingAdjustment adjustment =
      new PricingAdjustment(Constants.LIST_PRICE_ADJUSTMENT_DESCRIPTION,
                 null,
                 getPricingTools().round(adjustAmount),
                 quantity);

The Constants.LIST_PRICE_ADJUSTMENT_DESCRIPTION is a key to a resourced description in the atg.commerce.pricing.resources file that is unique to the calculator.

In the implementation of populateItemPriceSource, the calculator looks for an adjustment with the same resourced description:

public boolean populateItemPriceSource(pItemPriceSource, pOrder, pCommerceItem,
pParentItem pItemPriceInfo)
{
  for each pItemPriceInfo PriceAdjustment
  {
    if(adjustment.getAdjustmentDescription.equals(Constants.LIST_PRICE_ADJUSTMENT_
    DESCRIPTION))
   {
         double list = round(adjustment.getAmount() / adjustment.getQuantity());
         pItemPriceSource.setListPrice(list);
         return true;
   }
  }
}
Price List-Based ItemPriceSourceHandlers

Item calculators that delegate to scheme calculators for pricing also delegate to the scheme calculators when generating an ItemPriceSource.

The ItemPriceCalculator implementation of populateItemPriceSource iterates over each of its configured scheme calculators. Each scheme calculator that implements the ItemPriceSourceHandler interface is called through its populateItemPriceSource interface. The ItemPriceSource priceScheme property is set by the main calculator to the scheme that returns true from populateItemPriceSource.

The following describes how each scheme’s handler uses the PricingAdjustments to determine its original cost basis and populate the ItemPriceSource.

List Price Scheme

The ItemPriceSourceHandler for the ListPrice scheme sets the ItemPriceSource list price based on the single PricingAdjustment.

Bulk Price Scheme

Volume-based schemes use a list of volume levels as their cost basis. Each level defines a unit cost for a quantity. The ItemPriceSourceHandler determines the volume levels from the single PricingAdjustment added by the ItemBulkPriceCalculator. The generated list of volume levels contains only one entry.

For example, if the PricingAdjustment has amount=100, quantity=2, only one pricing level will be created:

Qty

Price

Equation

1

50

Quantity = 1 (First level is always set to one)
Price = PricingAdjustment.amount / PricingAdjustment.quantity

When performing bulk pricing, the calculator only adds one pricing adjustment to the item, so the system can recreate only one level of the scheme from the adjustments. For example, if the pricing levels are defined as:

Qty

Price

1

50

3

40

6

30

When the item quantity is 3, the original item is priced at $120 or 3 items at $40 each. Because the system generates a single level of 1 at 40, it cannot recreate the additional calculations of the 1 at 50 or 6 at 30 levels.

This may cause several issues to occur. For example, if the order is modified from a quantity of 3 to a quantity of 10, the additional 7 items are set at 40. Additionally, if the order is modified to a quantity of 1, the item is then priced at 40, not 50, since the system does not know the original first level.

This situation can also occur in returns. If the customer returns 2 of the original 3 items, the system cannot calculate the proper $10 adjustment for the 1 remaining item. As such, the net result is an $80 refund instead of a $70 refund, and the customer will receive the 1 item at $40 instead of $50.

Tiered Price Scheme

The ItemPriceSourceHandler for this volume-based scheme generates a list of volume levels using the PricingAdjustments added by the ItemTieredPriceCalculator.

For example, if the original pricing levels are defined as:

Qty

Price

1

50

3

40

6

30

The PricingAdjustments for an item quantity of three (3) would be generated as:

Qty

Adjustment

2

100

1

40

The ItemPriceSources list of volume levels contains one entry for each PricingAdjustment found:

Qty

Price

Equation

1

50

Quantity = 1 (First level is always set to one)

Price = PricingAdjustment.amount / PricingAdjustment.quantity
Thus, Price = 100 / 2

3

40

Quantity = Previous PricingAdjustment.quantity + Previous map entry quantity
Thus, Quantity = 2 + 1

Price = PricingAdjustment.amount / PricingAdjustment.quantity
Thus, Price = 40 / 1

The original pricing adjustments for tiered pricing may only be sufficient to generate a partial list of volume levels. The volume levels cannot be reconstructed up to the level covered by the item quantity originally priced. For example, if the levels are defined as: 1 at 50, 3 at 40, 6 at 30 and the item quantity is 3, the system can only calculate the levels to be 1 at 50 and 3 at 40. The last level, 6 at 30, cannot be determined from the available data stored in the item’s PricingAdjustments.

When modifying the same order with a quantity of 3 to a total quantity of 10, the shopper will not receive the $30 unit price for the last 4 items. The system will set the new 7 items at the $40 unit price.

In the case of an exchange, if you exchange 1 unit for 8 more units of the same item, the net result is the exchange order will identify the new 7 items at the $40 unit price.

Volume Price Levels

Volume-based ItemPriceSourceHandlers that generate a list of volume levels create new transient priceLevel repository items for each level it calculates from the PricingAdjustments. Creating repository items enables the substitution of the ItemPriceSource list of levels with the list normally attached to the price repository item.

The repository IDs for transient items are generated by an instance of the TransientIdGenerator, which is dynamically created through a property of the volume-based ItemPriceSourceHandlers.

Sale Price Handlers

Sale price versions of the handlers calculate the original sale prices from the order and ItemPriceSource. The ItemPriceSourceHandlers that generate sale price information require two sources of information to calculate the original sale price:

When determining the sale price, the SKU-based sale price handler refers to the ItemPriceSource list price and PricingAdjustment amount.

For example, calculating an original item (qty1) with a list price of $20 and a sale price of $15 would be calculated when the SKU-based sale price handler executes, setting the ItemPriceSource list price to $20. The PricingAdjustment contains an amount = (5.00), quantity 1. These two values are used to calculate a sale price of $15.

(ItemPriceSource List Price + (PricingAdjustment.amount /
PricingAdjustment.quantity)) = Sales Price

(20 + ((5.00) / 1)) = 15

Note that a list price is not a requirement for calculating sale prices. In the following example, the PricingAdjustment contains amount=15, resulting in the following calculation:

(ItemPriceSource List Price + (PricingAdjustment.amount /
PricingAdjustment.quantity)) = Sales Price

(0 + (15 / 1)) = 15

Note: Price list-based sales price handlers use the same logic as the SKU-based version.

Price List-Based Volume Sale Price Handlers

To generate the sale price volume levels, the list price volume levels and the PricingAdjustment(s) are used to calculate the appropriate values.

For example, if the original tier levels are defined:

List Price Qty

List Price

Sale Price Qty

Sale Price

1

50

1

45

3

40

3

35

6

30

6

25

The PricingAdjustments for an item quantity of three (3) are generated as:

List Price Qty

List Price Adjustment

Sale Price Qty

Sale Price Adjustment

2

100

2

(10)

1

40

1

(5)

Sale volume levels are generated as:

Qty

Price

Equation

1

45

Quantity = 1 (First level is always set to one)

Price = (List PricingAdjustment.amount / PricingAdjustment.quantity) + (Sale PricingAdjustment.amount / PricingAdjustment.quantity)
Thus, Price = (100 / 2) + (-10 / 2) = 45

3

35

Quantity = Previous PricingAdjustment.quantity + Previous map entry quantity.
Thus, Quantity = 2 + 1

Price = (List PricingAdjustment.amount / PricingAdjustment.quantity) + (Sale PricingAdjustment.amount / PricingAdjustment.quantity)
Thus, Price = (40 / 1) + (-5 / 1) = 35

It is possible that sale price levels that do not match the list price levels. For example, if the following prices are defined:

List Price Qty

List Price

Sale Price Qty

Sale Price

1

50

1

25

3

40

6

20

6

30

The PricingAdjustments for an item quantity of six (6) is generated as:

List Price Qty

List Price Adjustment

Sale Price Qty

Sale Price Adjustment

2

100

2

(50)

3

120

3

(45)

1

30

1

(10)

And the resulting sales price is calculated to:

Qty

Price

1

25

3

25

6

40

ItemPriceSource Integration

The ItemPriceSource is integrated with the pricing operation by passing a list of source objects into the pricing operation through the extra parameters map using a publicly defined key in atg.commerce.pricing.PricingConstants.

Using the list of source objects, the ItemPricingEngine generates a map in extraParameters that maps each commerce item in the order to its matching ItemPriceSource. This mapping operation occurs at the start of every pricing operation.

PricingTools provides the generateItemPricingSourceMap API for this mapping operation. Each item to be priced is matched to an ItemPriceSource object using the isItemMatch interface of ItemPriceSource. If a match is found, the ItemPriceSource currency code is verified to ensure that it matches the currency of the current pricing operation. If both conditions are met, the item is then mapped to the source object.

To map ItemPricingSources to CommerceItems, the algorithm that matches a CommerceItem to an ItemPriceSource is part of the ItemPriceSource API. The isItemMatch compares the productId, skuId, parentSkuId and commerceItemClassType properties of the CommerceItem to that in the ItemPriceSource. All values must match exactly for a successful comparison.

The resulting ItemPriceSourcesMap is stored in the extra parameters map using a key that is declared in atg.commerce.pricing.PricingConstants. Each calculator determines if there is a matching ItemPriceSource for an item by performing a lookup in the ItemPriceSourcesMap using the CommerceItemId as the key.

The ItemPriceSourceHandler interface defines the getItemPriceSource method that provides a matching ItemPriceSource object to the calculator during a pricing operation. A null return value means there is no ItemPriceSource and the calculator should continue to price the item normally. If an ItemPriceSource is returned, the calculator determines if it contains the necessary information for the calculator to price the item.

Each handler implements the shouldConsumeSource method that determines if an ItemPriceSource contains the necessary information to price the item. For example, the list price calculator needs a non-null value returned by the ItemPriceSource.getListPrice method. If that value is null, the calculator cannot consume the ItemPriceSource and will return false from the shouldConsumeSource method.

If shouldConsumeSource returns false, the calculator bypasses its normal processing completely and returns immediately. Only the calculators for which the ItemPriceSource provides the required data will consume it during a pricing operation.


Copyright © 1997, 2015 Oracle and/or its affiliates. All rights reserved. Legal Notices