Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Real-time pricing

Optimizely Configured Commerce's real-time pricing feature provides a standardized way to implement on-demand pricing calls to an external system, rather than using the internal price matrix or basic list pricing. Real-time pricing is valuable when you have complex pricing rules or frequent pricing changes throughout the day.

When using real-time pricing, page loads are not dependent on the pricing data being immediately available. This lets the pages build up quickly and display product information without waiting for pricing to be obtained. The price shows a loading ellipsis, and the prices are "AJAXed" onto the page as they are available. The reference site's client-side code was built to enable this behavior.

The external call is made to an exposed API, and the web servers must communicate directly over the network with that exposed resource. Optimizely can provide IP addresses to whitelist.

Configured Commerce caches prices server-side by product, customer, ship-to address, currency, warehouse, and unit of measure, based on a system setting to improve performance and minimize load on external resources.

📘

Note

Configured Commerce caches prices on a per-price, customer, and warehouse combination basis.

Do the following to implement real-time pricing:

  1. Create a plug-in that implements IExternalPricingService in your project and calls an external pricing service.
  2. Use the Pricing Service setting to enable the real-time plug-in.

Admin Console configuration

See Real time pricing and inventory for the Admin Console configurations.

API

POST a list of products to /api/v1/realtimepricing and get back a list of prices.

Insite.catalog.ProductService.getProductRealTimePrices returns an object of type RealTimePricingModel.

public class RealTimePricingModel : BaseModel

public class MyClass // Assuming this property is part of a class
{
    /// <summary>The real time pricing results.</summary>
    public virtual Collection<ProductPriceDto> RealTimePricingResults { get; set; }
}

Server-side

  • ModuleRealtimePricing
  • API controllerRealTimePricingV1Controller
  • HandlerGetRealTimePricingHandler
  • MapperGetRealTimePricingMapper

Calls RealtimePricingEngine

The IPricingPipeline interface is used by all server-side code to get prices, from which every service is being used in real-time or otherwise.

Extensibility

The RealtimePricingEngine calls a class that implements IExternalPricingService and is configured in the Real Time Pricing Service settings.

public interface IExternalPricingService : IMultiInstanceDependency

public interface IPriceService // Assuming this is part of an interface
{
    IDictionary<Guid, PricingServiceResult> GetPrice(PricingServiceParameter productPriceParameter);
    IDictionary<Guid, PricingServiceResult> GetPrice(ICollection<PricingServiceParameter> productPriceParameter);
}

Sample real-time pricing plug-in

Configured Commerce has a sample pricing plug-in by default, called InsiteExternalPricingService. This plug-in calls the generic pricing service.

Use the following steps to enable the sample plug-in:

  1. Go to Administration > Settings in the Admin Console.
  2. Search for Pricing Service.
  3. Select RealTime from the drop-down list. The Real Time Pricing Service setting should be set to Insite.
  4. Use the Real-Time Service Delay Seconds setting to demonstrate the client-side spinners by setting it to a non-zero number.
📘

Note

Use the site's theme and its insite.module.ts file to manage change events for spinners, which are part of the ISpinnerService interface, SpinnerService class (insite.spinner.service.ts file), and SpinnerController class (insite.spinner.controller.ts file).

namespace Insite.RealTimePricing.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using Insite.Common.Logging;
    using Insite.Core.Interfaces.Data;
    using Insite.Core.Interfaces.Dependency;
    using Insite.Core.Interfaces.Plugins.Pricing;
    using Insite.Core.Plugins.EntityUtilities;
    using Insite.Core.Plugins.ExternalPricingService;
    using Insite.Core.Plugins.Utilities;
    using Insite.Core.SystemSetting.Groups.Catalog;
    using Insite.Plugins.Pricing;
    using Insite.RealTimePricing.Engines;
    using Insite.RealTimePricing.SystemSettings;

    [DependencyName("Insite")]
    public class InsiteExternalPricingService : IExternalPricingService
    {
        protected readonly PricingServiceGeneric PricingServiceGeneric;
        protected readonly RealTimePricingSettings RealTimePricingSettings;

        public InsiteExternalPricingService(
            IUnitOfWorkFactory unitOfWorkFactory,
            ICurrencyFormatProvider currencyFormatProvider,
            IOrderLineUtilities orderLineUtilities,
            IPricingServiceFactory pricingServiceFactory,
            PricingSettings pricingSettings,
            RealTimePricingSettings realTimePricingSettings)
        {
            this.RealTimePricingSettings = realTimePricingSettings;
            this.PricingServiceGeneric = new PricingServiceGeneric(unitOfWorkFactory, currencyFormatProvider, orderLineUtilities, pricingServiceFactory, pricingSettings);
        }

        public IDictionary<Guid, PricingServiceResult> GetPrice(PricingServiceParameter pricingServiceParameter)
        {
            var prices = new Dictionary<Guid, PricingServiceResult>();
            try
            {
                var price = this.PricingServiceGeneric.CalculatePrice(pricingServiceParameter);
                prices.Add(pricingServiceParameter.ProductId, price);
            }
            catch (Exception exception)
            {
                // Ignore records we cannot price.
                LogHelper.For(this).Info("Unable to calculate price for product " + pricingServiceParameter.ProductId, exception);
            }
            return prices;
        }

        public IDictionary<Guid, PricingServiceResult> GetPrice(ICollection pricingServiceParameters)
        {
            // This is used for testing purposes only. This setting should be 0 in a production environment.
            var timeoutDuration = Math.Abs(this.RealTimePricingSettings.ServiceDelay) * 1000;
            Thread.Sleep(timeoutDuration);

            var prices = new Dictionary<Guid, PricingServiceResult>();
            foreach (var pricingServiceParameter in pricingServiceParameters)
            {
                try
                {
                    var price = this.PricingServiceGeneric.Calculate

The plug-in contains two methods that you must implement:

  • One to get the price for a single product.
  • One to get prices for a list of products.

It does not need to be responsible for timeouts or caching, as the engine handles these concerns. You must change the DependencyName to something other than Insite.