Nue Knowledge Center

Nue Docs navigation

search
clear
/

Client Side Pricing Engine

Client Side Pricing Engine

The Client Side Pricing Engine is a powerful client-side calculation tool that mirrors Nue's server-side pricing logic, enabling real-time price calculations without server roundtrips. This ensures consistent pricing across your application while providing immediate feedback to users. The engine is designed to handle both New Order Price Calculations and Change Order Price Calculations with the same accuracy as server-side calculations, reducing latency and dependency on network requests.

Primary Use Cases

New Order Price Calculations

This functionality calculates prices for new products based on the following factors:

  • Base product pricing
  • Quantity selections
  • Term length
  • Unit of Measure (e.g., Monthly, Annual, One-Time)
  • Product options and configurations

Change Order Price Calculations

This functionality provides immediate pricing feedback when users make changes to existing subscriptions, such as:

  • Adjusting quantities
  • Changing subscription terms
  • Renewing subscriptions
  • Co-terming subscriptions
  • Cancelling subscriptions

Key Benefits

  • Real-Time Calculations: Instantly calculate prices based on product configurations and user actions.
  • Server-Side Parity: Ensures the same pricing logic is applied as on the server side, ensuring consistency.
  • Offline Capability: Calculate pricing without needing to rely on network connectivity.
  • Performance: Offload resource-heavy pricing calculations to the client, improving server performance.
  • Consistency: Accurate and uniform pricing across all platforms, ensuring a seamless experience.

Installation

Registry Setup

Add the following to your .npmrc file:

# Node version control
engine-strict=true

# Registry configuration
registry=https://registry.npmjs.org/
@nue-apps:registry=https://gitlab.com/api/v4/projects/42706932/packages/npm/
always-auth=true

# Authentication (contact Nue team for token)
//gitlab.com/api/v4/projects/42706932/packages/npm/:_authToken=${GITLAB_NPM_AUTH_TOKEN}

Package Installation

npm i @nue-apps/nue-pricing-clientjs

 

Typescript

TS types for all Nue Self Service-related objects are available in the nue-js library.

npm i @nue-apps/nue-js
// Usage

import type { Subscription, Product, LocalPricingEngineSubscriptionChange } from '@nue-apps/nue-js'

 

New Order Price Calculations

To calculate prices for new products, you typically need to retrieve product data (GET /catalog/product). Once the data is retrieved, it can be passed to the NueProductCalculator to perform the price calculation.

 

Example Code:

import {
  NueProductCalculator,
  ProductCalculationObject,
} from '@nue-apps/nue-pricing-clientjs';

// Example product data (usually fetched from an API)
const productResponse = {
  "id": "01tEi0000088M9QIAU",
  "name": "Revenue Dashboard",
  "sku": "REVENUE_DASHBOARD",
  "priceModel": "Recurring",
  "priceBookEntries": [
    {
      "id": "01uEi000002fr2dIAA",
      "listPrice": 9.9,
      "uom": {
        "name": "User/Month",
        "quantityDimension": "User",
        "termDimension": "Month"
      },
      "currencyIsoCode": "USD"
    }
  ],
  "uom": {
    "name": "User/Month",
    "quantityDimension": "User",
    "termDimension": "Month"
  }
};

// Assuming product data and price book entries are retrieved from API and prepared
const product = productResponse;
const priceBookEntry = product.priceBookEntries[0];

// Construct the product input object for price calculation
const productInput: ProductCalculationObject = {
  id: product.id,  // Product ID from API response
  priceInfo: {
    listPrice: priceBookEntry.listPrice, 
    priceTags: product.productPriceTags || [],  
  },
  productInfo: {
    sku: product.sku,  
    priceModel: product.priceModel,  
    name: product.name,  
    productCategory: product.productCategory, 
    recordType: product.recordType, 
    showIncludedProductOptions: product.showIncludedProductOptions,
    freeTrialType: product.freeTrialType,
    freeTrialUnit: product.freeTrialUnit
  },
//New order details
  quantity: 1,
  startDate: "2024-03-20", 
  term: 12,  
  uom: priceBookEntry.uom,  
  productOptions: product.productOptions || [], 
};

// Initialize the pricing calculator
const productCalculator = new NueProductCalculator({
  termBasis: "30/360",  
});

// Perform the pricing calculation
const result = productCalculator.calculate(productInput);

 

Example Response:

 

{
  "details": {
    "deltaACV": 60,
    "deltaARR": 60,
    "deltaCMRR": 5,
    "deltaTCV": 5,
    "discountAmount": 0,
    "discountPercentage": 0,
    "id": "01tfJ000000LWT9QAO",
    "listTotal": 5,
    "netSalesPrice": 5,
    "salesPrice": 5,
    "systemDiscount": 0,
    "systemDiscountAmount": 0,
    "subtotal": 5,
    "totalAmount": 5,
    "totalPrice": 5
  },
  "summary": {
    "discountAmount": 0,
    "discountPercentage": 0,
    "listTotal": 5,
    "subtotal": 5,
    "systemDiscountAmount": 0,
    "systemDiscountPercentage": 0,
    "totalAmount": 5,
    "totalPrice": 5
  }
}

 

Change Order Price Calculations

For Change Order Pricing, the Client Side Pricing Engine can handle subscription changes like adjusting quantities, modifying terms, renewing subscriptions, and co-terminating subscriptions.

 

API Request for Pricing Engine Data

To streamline the process of collecting data necessary for change order pricing calculations, we provide an API endpoint that fetches all relevant information in one request for a specific customer. This endpoint consolidates the pricing data from multiple sources, making it easier for the Client Side Pricing Engine to perform accurate price calculations for subscription changes across all customer subscriptions. 

Request: 

GET https://api.nue.io/ss/orders/pricing-engine-input?customerIds=["customerId"]

Example Response: 

{
  "status": "SUCCESS",
  "data": {
    "SUB-00000483": {
      "changes": [
        {
          "changeType": "NewProduct",
          "endDate": "2025-01-12",
          "lineType": "LineItem",
          "listTotal": 148.5,
          "netSalesPrice": 9.9,
          "quantity": 15,
          "startDate": "2024-12-13",
          "subtotal": 148.5,
          "term": 1,
          "totalAmount": 148.5,
          "totalPrice": 148.5
        },
        {
          "changeType": "UpdateQuantity",
          "endDate": "2025-01-12",
          "lineType": "LineItem",
          "listTotal": 29.7,
          "netSalesPrice": 9.9,
          "quantity": 3,
          "startDate": "2024-12-13",
          "subtotal": 29.7,
          "term": 1,
          "totalAmount": 29.7,
          "totalPrice": 29.7
        }
      ],
      "orderProduct": {
        "endDate": "2025-01-12",
        "listPrice": 9.9,
        "listTotal": 178.2,
        "priceTags": [
          {
            "active": true,
            "code": "10PERCENTOFFDEMO",
            "id": "a0XEi000003GRovMAG",
            "lastPublishedById": "005Ei00000GgD7tIAF",
            "lastPublishedDate": "2024-12-13",
            "name": "10% Discount Term-based",
            "priceTagType": "Term",
            "priceTiers": [
              {
                "chargeModel": "PerUnit",
                "discountPercentage": 10,
                "endUnit": 12,
                "id": "a0YEi000002EbJVMA0",
                "name": "PT-00000000",
                "startUnit": 0,
                "tierNumber": 1
              }
            ],
            "priceType": "Volume",
            "publishStatus": "Published",
            "recordType": "DiscountDimension",
            "startTime": "2023-03-31T16:01Z",
            "uomDimension": "Quarter"
          }
        ],
        "product": {
          "id": "01tEi0000088M9QIAU",
          "name": "Revenue Dashboard",
          "priceModel": "Recurring",
          "productCategory": "RecurringServices",
          "showIncludedProductOptions": false,
          "sku": "REVENUE_DASHBOARD"
        },
        "quantity": 18,
        "refId": "25bb7873-7649-4c84-b2bd-e8dda2929e03",
        "startDate": "2024-12-13",
        "subtotal": 178.2,
        "term": 1,
        "uom": {
          "decimalScale": 0,
          "name": "User/Month",
          "quantityDimension": "User",
          "roundingMode": "Up",
          "termDimension": "Month"
        }
      }
    }
  },
  "warnings": []
}

The response data is a map keyed by each subscription name.

// TypeScript

// You can also import this type from the @nue-apps/nue-js library
import type { LocalPricingEngineSubscriptionChange } from '@nue-apps/nue-js'

// TS type for each value in the map
type LocalPricingEngineSubscriptionChange = {
  changes: LocalPricingEngineChanges;
  orderProduct: LocalPricingEngineOrderProduct;
}

// TS type for full `data` map
type SubscriptionPricingEngineMap = Record<string, LocalPricingEngineSubscriptionChange>

 

Recalculating Subscription Pricing

 

Example Code:

import type { LocalPricingEngineSubscriptionChange, Subscription, SubscriptionWithProduct } from '@nue-apps/nue-js'

type SubscriptionPricingEngineMap = Record<string, LocalPricingEngineSubscriptionChange>

// Fetch Subscription pricing data (add own error handling)
async function getPricingEngineMap(customerId): SubscriptionPricingEngineMap {
  try {
    const response = await fetch(`https://api.nue.io/ss/orders/subscriptions/pricing-engine-input?customerIds=["customerId"]`);

    const parsed = await response.json();

    return parsed?.data
  } catch(err) {
    // handle error...
  }
};

 const pricingEngineMap = await getPricingEngineMap();

 //The object for the subscription being changed
 const subscription: Subscription | SubscriptionWithProduct = subscriptionBeingCalculated;

 // Find the matching pricing data from the pricingEngineMap
 const pricingData: LocalPricingEngineSubscriptionChange = pricingEngineMap?.[subscription.name];

  // Constructing the subscription input object
 const subscriptionInput: ChangeOrderCalculationAsset = {
    totalPrice: subscription.totalPrice,
    totalAmount: subscription.totalAmount,
    term: subscription.subscriptionTerm,
    assetNumber: subscription.assetNumber || '',
    startDate: subscription.subscriptionStartDate,
    endDate: subscription.subscriptionEndDate,
    quantity: subscription.quantity,
    listTotal: pricingData.orderProduct.listTotal,
    subtotal: pricingData.orderProduct.subtotal,
    ...pricingData, // Include rest of the pricing data
  };

 // Initialize and use the pricing change order calculator
 const changeOrderCalculator = new NuePricingChangeOrderCalculator();

 //Changes array that includes all changes to the subscription
 const changes = [{
  changeType: 'Renew',
  renewalTerm: 12
 }]
  
 const result = changeOrderCalculator.calculateWithAssetChanges(subscriptionInput, changes);

 

Example Response:

{
  "assetPrice": {
    "assetNumber": "SUB-000084",
    "changeItems": [
      {
        "deltaACV": 50000,
        "deltaARR": 50000,
        "deltaCMRR": 4166.666666666667,
        "deltaTCV": 600000,
        "discountAmount": 0,
        "discountPercentage": 0,
        "endDate": "2046-03-03",
        "listTotal": 600000,
        "netSalesPrice": 500,
        "quantity": 100,
        "salesPrice": 500,
        "startDate": "2034-03-04",
        "subtotal": 600000,
        "systemDiscount": 0,
        "systemDiscountAmount": 0,
        "term": 12,
        "changeType": "Renew",
        "totalAmount": 660000,
        "totalPrice": 600000
      }
    ],
    "endDate": "2046-03-03",
    "quantity": 100,
    "startDate": "2022-03-04",
    "term": 24
  },
  "priceSummary": {
    "totalAmount": 660000,
    "totalPrice": 600000
  }
}