# Pricing (and Entitlements)
The OOTB way to set up prices in B2B commerce is by using pricelists. Besides the price, they also drive the entitlements (aka the list of products your account can see). You can combine several pricelists and B2B commerce will take care of figuring out which price to display. OOTB the price for a product is in the price list item.
# Key Definitions
Keyword | Object Name | Description |
---|---|---|
Account Group | ccrz__E_AccountGroup__c | Group multiple accounts together to provide pricing and/or entitlements. |
Price Group | ccrz__E_PriceGroup__c | Alternative pricing for accounts. Primary used for contracts, relative (upgrade/downgrade), segmented and contextual based pricing. |
Pricelist | ccrz__E_PriceList__c | Represents a grouping of products to control pricing and entitlements per currency |
Pricelist item | ccrz__E_PriceListItem__c | A Price List entry. Contains a reference to the product and hold a price value |
Product | ccrz__E_Product__c | B2B Commerce Product object (not to be confused with Product2) |
# Pricing/Entitlement flows
The most common path used to find the price list is via account groups:
- An account can have ONE account group
- An account group can have ONE or MORE pricelists.
- Each pricelist consist of ONE or MORE pricelist items.
- Each pricelist item refers to ONE product (aka SKU), and contains the price for it.
In the approach above, you can only have one account group per account.
Another common route is via price groups:
- An account can have ONE or MORE price groups (via the price group account object)
- A price group can have ONE or MORE pricelists (via the price group price list object)
- Each pricelist consist of ONE or MORE pricelist items.
- Each pricelist item refers to ONE product (aka SKU), and contains the price for it.
This is the typical approach for Contract Pricing (where the same account may have multiple contracts, each with different terms of what they can buy and at which price)
# Effective Account
WIP
# Contract Pricing
WIP
# Extending how the price/entitlements are determined
If this OOTB approach is not how your business sets the prices for its users (not standard, but not uncommon), you will have to either:
- Extend the way the pricelists are determined (e.g. based on an additional condition, like some attribute in the User object)
- Extend how the price itself is calculated (e.g. external pricing, custom pricing rules, etc.)
B2B commerce golden rule:
- Try to use configuration settings first.
- Use extensions when it makes sense.
- Avoid creating new custom classes that duplicates functionality (prefer extensions).
# Pricelist entitlements (example)
# Use case
On the day before, during and after the contact's birthday, offer special prices and products (e.g. cakes, party supplies, discounts in drinks).
# Why an extension?
If we were to do it without code, this approach would require one account per user. Or maybe do some outside the box thinking and email coupons and the list of products under the birthday promotion. Either way, this may require quite a lot of records...and hopefully they were set up correctly (and you don't want to use additional coupons that day).
With an extension, you can set a pricelist for the birtday range and you're done.
# General approach
- Get the birthdate of the logged contact
- If the birthday is greater than Yesterday, but less than Tomorrow, find the current birthday pricelist and add it to the list of entitled pricelists.
# Design
- To keep it simple, we'll add a checkbox field to the pricelist object, to indicate whether they are birthday pricelists or not. We'll take advantage of the one to many relationship between the pricelist and pricelist items to display the products and their prices, as well as the date validation and sorting strategies (e.g. either by best price or by sequence)
- Create an extension class to the
ccLogicPLEntLists
class (overridingfetchPriceGroupPriceListIDs
and/orfetchAccountGroupPriceListIDs
) to return the additional birthday pricelists if applicable. - In your org, go to CC Admin and replace the value of
ccLogicPLEntLists
under the Service Management option with your custom class.
# Sample code
Coming Soon
# Overriding Price (example)
# Use case
On the day before, during and after the contact's birthday, offer 5% discount to all the products ordered.
# Why an extension?
If we were to do it without code, the best solution would probably involve the use of a coupon. But you won't see the new price until you actually add it to the cart and apply it. And you won't be able to stack coupons (current OOTB limitation)
With an extension, you can see the discounted price when navigating through the product list.
# General approach
- Get the birthdate of the logged contact
- If the birthday is greater than Yesterday, but less than Tomorrow, modify the prices shown in the storefront.
# Design
- Create an extension class to the
ccLogicProductPricing
class (overridingdeterminePrice
) to return the price -5% if applicable. - In your org, go to CC Admin and replace the value of
ccLogicProductPricing
under the Service Management option with your custom class.
# Sample code
WARNING
Homework: find the contact's birthdate and determine whether the discount applies
global with sharing class ckz54_ccLogicProductPricing extends ccrz.ccLogicProductPricing{
global override Map<String, Object> determinePrice(Map<String, Object> inputData) {
Map<String, Object> retData;
if (Test.isRunningTest()) {
retData = new Map<String, Object>{
//replace with your custom test data
};
} else {
//calls the super of the method
retData = super.determinePrice(inputData);
}
Decimal regularPrice=(Decimal)(retData.get('price'));
ccrz.ccLog.log(LoggingLevel.DEBUG,'M:X:ckz54_LogicProductPricing:determinePrice:regularPrice',regularPrice);
//TBD: check the birthday
//note that this will also apply the discount on the base pricelist (you may want to avoid this)
retData.put('price', (regularPrice*0.95).setScale(2, System.RoundingMode.HALF_EVEN));
ccrz.ccLog.log(LoggingLevel.DEBUG,'M:X:ckz54_LogicProductPricing:determinePrice:retData',retData);
return retData;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Demo
With the 5% applied to the regular price. E.g.
- For 2800 5% discount results in
2660
- For 2975, this is
2826.25
TIP
Another alternative would be to extend ccServicePL (for the pricelist) and/or ccServicePLI (for the pricelist items) service classes, and leave the logic to the query itself, instead of the logic classes.
# Extras
# Pricing data in the CCRZ object (for Handlebars)
Consider using these CCRZ objects in your custom Handlebars templates or js code. They contain a lot of the pricing data you may need (and you can extend them if something is missing)
Page | CCRZ object |
---|---|
PDP | CCRZ.productDetailModel.attributes.product |
PLP | CCRZ.productListPageView.productItemsView.itemViews[x].model.attributes |
Featured and Spotlight products | CCRZ.views.spotView.model.attributes |
Cart items | CCRZ.cartDetailModel.attributes.ECartItemsS.models[x].attributes |
WARNING
The CCRZ object list above may not be 100% accurate and may vary depending on how you are using B2B commerce. Why this inconsistency? The above are not documented, but there are different js objects that could contain pricing data. Give this a try first, and if it doesn't work, look around using the browser's inspector tools
# Contract Pricing Selector
WIP
References: https://cloudcraze.atlassian.net/wiki/spaces/B2BDOCS410/pages/888998151/Pricing+and+Entitlements+Data