You can use the Pricing Extension Callback Class to define any logic or computation you need to execute before or after the pricing is calculated for the line items. You must define the pre-pricing or post-pricing hooks in the Pricing Extension Callback. The pre-pricing and post-pricing logic are executed separately from the pricing that is calculated when the Sales rep clicks Submit for Pricing(Async) button. This allows CPQ to run the pricing without executing custom logic every time.

The pre-pricing and post-pricing logic are executed when the Sales rep clicks Pre-Price and Post-Price buttons respectively, on the Cart page. If you define Auto Execute Post-Pricing Step and Auto Execute Pre-Pricing Step settings, the pre-pricing and post-pricing logics are executed automatically when the Sales rep clicks Submit for Pricing(Async). For more information, see Config System Properties.

The following methods are available to you in Pricing Extension Callback Class.

MethodSignatureDescription
afterPricing()Apttus_Config2.CustomClass.PricingExtensionResult afterPricing(Apttus_Config2.ProductConfiguration, Apttus_Config2.CustomClass.CartHelper)

You can use this method to execute logic that is required post-processing after line items are priced

beforePricing()Apttus_Config2.CustomClass.PricingExtensionResult beforePricing(Apttus_Config2.ProductConfiguration, Apttus_Config2.CustomClass.CartHelper)

You can use this method to execute logic that is required pre-processing to prepare the cart line items for pricing.

isAfterPricingEnabled()Boolean isAfterPricingEnabled()You can use this method to determine whether after-pricing should be invoked for the callback.
isBeforePricingEnabled()Boolean isBeforePricingEnabled()You can use this method to determine whether before-pricing should be invoked for the callback.

Pre-Pricing Logic

You can define logic in beforePricing() method of Pricing Extension callback to execute any computation that drives the pricing of the line item. For example, you can calculate the Total Quantity of reagents across all the locations and use that quantity to determine the tiered price for a line item. You must specify the fields you apply pre-price to in Custom Pre-Pricing Fields. For more information, see Config System Properties.

Post-Pricing Logic

You can define logic in afterPricing() method of Pricing Extension Callback to execute any computations that are dependent on the pricing fields like Net Price and Net Extended Price which are calculated after pricing. For example, if you want to calculate the annual value for a given line item with 3 years of Selling Term and after applying adjustments the Net Price is 3000, then the annual value is 3000/3 = 1000.

Example Code

/**
 *  Apttus Config & Pricing
 *  DefaultPricingExtensionCallback
 *   
 *  @2019-2020 Apttus Inc. All rights reserved.
 */
global with sharing class SamplePricingExtensionCallback3 implements Apttus_Config2.CustomClass.IPricingExtensionCallback 
{
    
    /**
     * Indicates whether the before pricing callback is enabled
     * Use this method to determine whether before pricing should be invoked for the callback
     * @return <code>true</code> if before pricing callback is enabled, <code>false</code> otherwise
     */
    global Boolean isBeforePricingEnabled() 
	{
        return true;
    }
        
    /**
     * Callback before pricing the given cart
     * Use this method to do all required pre-processing to prepare the cart line items for pricing.
     * @param cart the cart object to pre-process
     * @param helper the cart helper class
     * @return the pricing extension result object
     */
    global Apttus_Config2.CustomClass.PricingExtensionResult beforePricing(Apttus_Config2.ProductConfiguration cart, Apttus_Config2.CustomClass.CartHelper helper) 
	{
        Id cartId = cart.getConfigSO().Id;    
        List<Apttus_Config2__LineItem__c> lineItemsToUpdate = new List<Apttus_Config2__LineItem__c>();
        List<Apttus_Config2__LineItem__c> lineItems = [SELECT Id, Name , 
                                                       Total_reagent_qty_for_the_site__c , 
                                                       PrePricingCriteriaField__c,
                                                       Apttus_Config2__Quantity__c, 
                                                       Apttus_Config2__SyncStatus__c, 
                                                       Apttus_Config2__PricingStatus__c
                                                       FROM Apttus_Config2__LineItem__c 
                                                       WHERE Apttus_Config2__ConfigurationId__c = :cartId];
        
        system.debug ('******************* lineItems:' + lineItems);
        
		Decimal totalQty = 0;
        for (Apttus_Config2__LineItem__c lineItemSO : lineItems) 
		{
            //lineItemSO.Apttus_Config2__Quantity__c = 10;
            totalQty += lineItemSO.Apttus_Config2__Quantity__c + (lineItemSO.PrePricingCriteriaField__c != null
                                                                 ? lineItemSO.PrePricingCriteriaField__c
                                                                 : 0);            
            lineItemSO.Apttus_Config2__PricingStatus__c = 'Pending';
            lineItemSO.Apttus_Config2__SyncStatus__c = 'Pre-Pricing Complete';
            lineItemsToUpdate.add(lineItemSO);        
        }
        
        for (Apttus_Config2__LineItem__c lineItemSO : lineItemsToUpdate) 
		{
            lineItemSO.Total_reagent_qty_for_the_site__c = totalQty;
        }
        
        Database.update (lineItemsToUpdate);
        
        lineItemsToUpdate = new List<Apttus_Config2__LineItem__c>();
        
        List<Id> pricingCartIds = helper.getPricingCartsFor(cartId);
        for (Apttus_Config2__LineItem__c pricingItemSO : [SELECT Id, Name
                                        FROM Apttus_Config2__LineItem__c
                                        WHERE Apttus_Config2__ConfigurationId__c IN :pricingCartIds]) 
		{

            //pricingItemSO.Apttus_Config2__Quantity__c = 10;
            pricingItemSO.Total_reagent_qty_for_the_site__c = totalQty;
            pricingItemSO.Apttus_Config2__SyncStatus__c = 'Pre-Pricing Complete';
            lineItemsToUpdate.add(pricingItemSO);
        }


        Database.update (lineItemsToUpdate);
        return new Apttus_Config2.CustomClass.PricingExtensionResult();
        
    }
    
    /**
     * Indicates whether the after pricing callback is enabled
     * Use this method to determine whether after pricing should be invoked for the callback
     * @return <code>true</code> if after pricing callback is enabled, <code>false</code> otherwise
     */
    global Boolean isAfterPricingEnabled() {
        return true;
        
    }
        
    /**
     * Callback after pricing the given cart
     * Use this method to do all required post-processing after line items are priced.
     * @param cart the cart object to post-process
     * @param helper the cart helper class
     * @return the pricing extension result object
     */
    global Apttus_Config2.CustomClass.PricingExtensionResult afterPricing(Apttus_Config2.ProductConfiguration cart, Apttus_Config2.CustomClass.CartHelper helper) {
        Id cartId = cart.getConfigSO().Id;
        List<Apttus_Config2__LineItem__c> lineItemsToUpdate = new List<Apttus_Config2__LineItem__c>();

        List<Id> pricingCartIds = helper.getPricingCartsFor(cartId);
        for (Apttus_Config2__LineItem__c lineItemSO : [SELECT Id, Name, Apttus_Config2__SyncStatus__c
                                        FROM Apttus_Config2__LineItem__c
                                        WHERE Apttus_Config2__ConfigurationId__c
                                                IN :pricingCartIds]) {

            lineItemSO.Apttus_Config2__SyncStatus__c = 'Post-Pricing Complete';
            lineItemSO.Apttus_Config2__Description__c = 'Net Price should be updated as per the new quantity 10';
            //lineItemSO.Custom_Field__c = 'Post-price';
            lineItemsToUpdate.add(lineItemSO);
        }

        Database.update (lineItemsToUpdate);
        return new Apttus_Config2.CustomClass.PricingExtensionResult();
    }
    
}
CODE