The Pricing Callback class enables you to add pricing logic to your cart that cannot be achieved by out-of-the-box pricing mechanisms, such as Price Rulesets and Price Matrices. The Pricing Callback is executed for each bundled product or standalone in the cart. A separate transaction call is initiated for each product in the cart. The Pricing Callback is invoked when you are on the cart page. The pricing callback is invoked during pricing stages and executes the various methods in the BASEPRICE and ADJUSTMENT modes. This feature enables dynamic pricing adjustments based on specific conditions.

IBasePricing Callback

IBasePricing callback is invoked during different pricing stages and executes the various methods in the BASEPRICE and ADJUSTMENT modes.

Adjustment Line Item Callback can be achieved with IBasePricing callback using its method.

To use the Pricing Callback you must create a custom C# class that implements the following interfaces:

Interface

Description

IBasePricing

Provides a mechanism to define custom logic to be executed during different pricing stages.


Feature Flag
is-pricing-callback-enabled is the feature flag that enables the Product Filter callback.

The following methods are available in the  IBasePricing callback interface:

Method

Signature

Description

BeforePricingBatchAsync ()

Task BeforePricingBatchAsync(IBatchPriceRequest batchPriceRequest)

You can use this method to define custom logic that must be executed before Base Price is calculated.

OnPricingBatchAsync()

Task OnPricingBatchAsync(IBatchPriceRequest batchPriceRequest)

You can use this method to define custom logic that must be executed during the Base Price calculation. You can use the price list items to write the custom logic.

AfterPricingBatchAsync()

Task AfterPricingBatchAsync(IBatchPriceRequest batchPriceRequest)

You can use this method to define custom logic that must be executed after the Base Price is calculated.

OnProductOptionPriceAsync()

Task OnProductOptionPriceAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IProductOptionPrice> productOptionPrice)

You can use this extension point to modify product option prices for the given line item.

OnPriceMatrixAsync()

Task OnPriceMatrixAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceMatrixEntry>> priceMatrixEntries)

You can use this extension point to modify resolved price matrix for the given line item if required.

OnPriceRuleAsync()

Task OnPriceRuleAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceRuleEntry>> priceRuleEntries)

You can use this extension point to modify the resolved price rule entries for the given line item if required.

OnPipelinePriceRuleAsync()

Task OnPipelinePriceRuleAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceRuleEntry>> pipelinePriceRuleEntries)

You can use this extension point to modify the resolved price pipeline rule entries for the given line item if required


OnPriceEscalatorAsync()


Task OnPriceEscalatorAsync(IBatchPriceRequest batchPriceRequest, List<IPriceEscalator> priceEscalators)


You can use this extension point to modify the resolved price escalators if required.

Sample Code

This is just a sample Callback custom class to update the Quantity and Custom Dimension field of product based on the Price Type of Line Item.

using System;
using System.Linq;
using Conga.Revenue.Common.Callback.Models;
using Conga.Platform.Extensibility.CustomCode.Library;
using System.Collections.Generic;
using System.Threading.Tasks;
using Conga.Revenue.Common.Callback;
using Conga.Revenue.Common.Callback.Entities;
using Conga.Revenue.Common.Callback.Messages;

namespace APTestan
{
    /// <summary>
    /// Pricing Callback
    /// </summary>
    public class PricingBasePriceCallback : CodeExtensibility, IPricingBasePriceCallback
    {
        public async Task AfterPricingBatchAsync(IBatchPriceRequest batchPriceRequest)
        {
            await Task.CompletedTask;
        }

        public async Task BeforePricingBatchAsync(IBatchPriceRequest batchPriceRequest)
        {
            var batchLineItems = batchPriceRequest.GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
            
            foreach(var item in batchLineItems)
            {
            
                IPriceListItemModel priceListItemModel = item.GetPriceListItem();
                IPriceListItem priceListItemEntity = priceListItemModel.GetEntity();
                var entity = item.GetEntity();
                
                if(priceListItemEntity.PriceType == "One Time"){
                    entity.Quantity = 15;
                    entity.SetValue("Auto_Integer_Dimension2_c", 50);
                }else{
                    entity.Quantity = 10;
                    entity.SetValue("Auto_Integer_Dimension2_c", 25);
                }
            }
            
            await Task.CompletedTask;
        }

        public async Task OnPricingBatchAsync(IBatchPriceRequest batchPriceRequest)
        {
        
            var batchLineItems = batchPriceRequest.GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
            
                
            await Task.CompletedTask;
        }

        public async Task OnProductOptionPriceAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IProductOptionPrice> productOptionPrice)
        {
            var batchLineItems = batchPriceRequest.GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
            
          
            
            await Task.CompletedTask;
        }

        public async Task OnPriceMatrixAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceMatrixEntry>> priceMatrixEntries)
        {
            await Task.CompletedTask;
        }

        public async Task OnPriceRuleAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceRuleEntry>> priceRuleEntries)
        {
            await Task.CompletedTask;
        }

        public async Task OnPipelinePriceRuleAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IEnumerable<IPriceRuleEntry>> pipelinePriceRuleEntries)
        {
            await Task.CompletedTask;
        }

        public async Task OnPriceEscalatorAsync(IBatchPriceRequest batchPriceRequest, List<IPriceEscalator> priceEscalators)
        {
            await Task.CompletedTask;
        }
    }
}

CODE

ITotallingPricing Callback

ITotalingPricing Callback class enables you to add pricing totaling logic to your cart that cannot be achieved by out-of-the-box pricing mechanisms. The Pricing Totaling Callback is invoked when you are on the cart page. The pricing totaling callback is invoked during different pricing totaling stages and executes the various methods in the BASEPRICE and ADJUSTMENT modes. This feature enables dynamic pricing adjustments based on specific conditions.

Adjustment Spread Callback can be achieved with ITotallingPricing Callback using its method. 

Example:

Customer has a use case where they want to capture Total QTY (sum of QTY of all Similar Products in cart) against the Line Item. Also, they wanted to Capture Total Product Group QTY (Sum of QTY belonging to Similar Product Group). This intern was used to drive Pricing using Price Rules. In this case ITotalingPricing triggers to calculate Total QTY and Total Product Group QTY.

Interface

Description

ITotalingPricing

Provides a mechanism to define custom logic to be executed before, during, and after adjustment Calculation

Method

Signature

Description

BeforePricingCartAdjustmentAsync

Task BeforePricingBatchAsync(IBatchPriceRequest batchPriceRequest)

You can use this method to define custom logic that must be executed before Base Price is calculated.

AfterPricingCartAdjustmentAsync

Task AfterPricingBatchAsync(IBatchPriceRequest batchPriceRequest)

You can use this method to define custom logic that must be executed after the Base Price is calculated.

OnCartPricingCompleteAsync

Task OnProductOptionPriceAsync(IBatchPriceRequest batchPriceRequest, IDictionary<string, IProductOptionPrice> productOptionPrice)

You can use this extension point to modify product option prices for the given line item.


Sample Code

using System;
using System.Linq;
using Conga.Revenue.Common.Callback.Models;
using Conga.Platform.Extensibility.CustomCode.Library;
using System.Collections.Generic;
using System.Threading.Tasks;
using Conga.Revenue.Common.Callback;
using Conga.Revenue.Common.Callback.Entities;
using Conga.Revenue.Common.Callback.Messages;


namespace APTestan
{
    public class PricingTotallingCallback : CodeExtensibility, IPricingTotallingCallback 
    {     
	public async Task BeforePricingCartAdjustmentAsync(IAggregateCartRequest aggregateCartRequest)
        {
			var batchLineItems = aggregateCartRequest.GetCartContext().GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
			
			foreach(var item in batchLineItems){
				var entity = item.GetEntity();
				var cartName = entity.GetLookupValue<string>("Configuration.Name");
				if(cartName == "Auto_Pricing_TotalingCallbackAdjustment"){
					entity.AdjustmentType = "Discount Amount";
					entity.AdjustmentAmount = 10;
				}
			}
			
            await Task.CompletedTask;
        }
        public async Task AfterPricingCartAdjustmentAsync(IAggregateCartRequest aggregateCartRequest)
        {
            var batchLineItems = aggregateCartRequest.GetCartContext().GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
			
			foreach(var item in batchLineItems){
				var entity = item.GetEntity();
				var cartName = entity.GetLookupValue<string>("Configuration.Name");
				if(cartName == "Auto_Pricing_TotalingCallbackAdjustment"){
				
					if(entity.AdjustmentAmount > 0){
						var unitAdjustment = entity.AdjustmentAmount / entity.Quantity;
						entity.SetValue("Auto_Integer_Dimension1_c", unitAdjustment);
					}else{
						var unitAdjustment = (entity.AdjustedPrice / entity.Quantity) - entity.BasePrice;
						entity.SetValue("Auto_Integer_Dimension1_c", unitAdjustment);
					}
				}
			}
			
            await Task.CompletedTask;
        }

        public async Task OnCartPricingCompleteAsync(IAggregateCartRequest aggregateCartRequest)
        {
            var cartLineItems = aggregateCartRequest.GetCartContext().GetLineItems().SelectMany(x => x.GetChargeLines()).ToList();
            foreach(var cartLineItem in cartLineItems) {
			var entity = cartLineItem.GetEntity();
			var cartName = entity.GetLookupValue<string>("Configuration.Name");
				if(cartName == "Auto_Pricing_TotalingCallbackAdjustment"){
				
					if(entity.NetPrice < 1000) {
						entity.SetValue("Auto_String_Dimension3_c", "Red" );
					} else {
						entity.SetValue("Auto_String_Dimension3_c", "Green" );
					}
				}	
				
            }
            await Task.CompletedTask;
        }
    }
}
CODE

IRelatedPricing Callback

IRelatedPricing Callback allows you to apply custom logic to calculate the related pricing. This callback is invoked while CPQ is calculating related pricing after the main pricing is calculated.

To use the Related Pricing Callback you must create a custom C# class that implements the IRelatedPricing callback interface and register the custom C# class with Related Pricing Callback Class. You must write your custom logic in the custom C# class.

If you have defined Pricing Callback class, Related Pricing Callback is always invoked after the Pricing Callback is executed.

Interface

Description

IRelatedPricing

Provides a mechanism to define custom logic for calculating the pricing for related product line items


The following methods are available in the Apttus_Config2.CustomClass.IRelatedPricingCallback interface:

MethodSignatureDescription
computeBasePrice()Apttus_Config2.CustomClass.RelatedPriceResult computeBasePrice(Apttus_Config2.ProductConfiguration, Apttus_Config2.LineItem, List)You can use this method to apply custom logic for related pricing calculation and override the default CPQ related pricing logic. 


Example

In the following sample code, Related Pricing Callback to calculates the price on related line items. 

using System;
using System.Linq;
using Conga.Revenue.Common.Callback.Models;
using Conga.Platform.Extensibility.CustomCode.Library;
using System.Collections.Generic;
using System.Threading.Tasks;
using Conga.Revenue.Common.Callback;
using Conga.Revenue.Common.Callback.Entities;
using Conga.Revenue.Common.Callback.Messages;


namespace DemoRelatedPricingCallback
{
	public class RelatedPricingCallback : CodeExtensibility, IRelatedPricingCallback
	{
		public async Task<List<IRelatedPricingBatchResponse>> ComputeBasePriceBatchAsync(IRelatedPricingBatchRequest relatedPricingBatchRequest)
		{
			List<IRelatedPricingBatchResponse> relatedPricingBatchResponseResult = new List<IRelatedPricingBatchResponse>();
			List<ILineItemModel> relatedLineItems = relatedPricingBatchRequest.GetRelatedLineItems();

			
			foreach(var relatedLineItem in relatedLineItems) {
				var cartName = relatedLineItem.GetLookupValue<string>("Configuration.Name");
				if(cartName.Contains("RelatedPriceCallback01")){
					var priceBreakupRecords = relatedLineItem.GetPriceBreakupRecords();

					IRelatedPricingBatchResponse relatedPricingResponse = relatedPricingBatchRequest.CreateRelatedPricingBatchResponse(relatedLineItem);
					relatedPricingResponse.BasePrice = 500;
					relatedPricingBatchResponseResult.Add(relatedPricingResponse);
				}
			}
			return await Task.FromResult(relatedPricingBatchResponseResult);
		}
	}
}
CODE