Overwriting CatalogPriceCalculator script include

viktor_lukashov
Giga Contributor

The Wiki mentions that the ServiceNow default service catalog pricing model can be extended should a need be. However it does not provide much information on how this can be done. In the community there have been questions about that every once in a while but they tend to stay without answers. I've posted this same question to HI and then did some trial and error myself. Below is a summary of a working method how to extend the pricing model (keep in mind that it is not an official guide).

First, backup the OOB versions of the CatalogPriceCalculator and CatalogRecurringPriceCalculator script includes. You are going to overwrite them with custom versions so it's a good idea to keep OOB copies available in case you would need to restore them in some future upgrade. Set the 'active' flag to false on the both OOB script includes and keep them without any other modifications.

The idea is to create two custom fields on the catalog item table to be able to specify custom catalog price calculation scripts and to change the default scripts to check for these fields and either run OOB or custom calculations. Two different fields are necessary because the price calculation is divided into two parts: one for purchase price and another for recurring price.

The screenshots below show the definition of the 2 custom fields sc_cat_item.u_custom_price_calculator and sc_cat_item.u_custom_recurring_price_calculator. Both fields are references to the Script Include table.

u_custom_price_calculator.png

u_custom_recurring_price_calculator.png

The custom copy of the CatalogPriceCalculator script include looks as below. It checks if the custom field u_custom_price_calculator is defined on the catalog item and if so, tries to use the price calculator from that script include. If for any reason the custom price calculator class is not found, the OOB class is used instead (renamed to DefaultCatalogPriceCalculator).

On the ServiceNow versions starting from Fuji the system property glide.sc.use_custom_pricegenerator should be set to true in order to enable pricing calculations via script includes. When it's false all pricing calculations are handled inside ServiceNow in Java code completely out of reach for customization.

Note that when defining a custom price calculator class, its name should match the name of the script include where it is defined. An example will come further into the post.

// save a reference to the global scope

var __global = this;

/*

* For a given cart item, this routine will return the price

*/

var CatalogPriceCalculator = Class.create();

CatalogPriceCalculator.prototype = {

    initialize: function(/* GlideRecord */ gr) {

          var customPriceCalculatorSI = gr.cat_item.u_custom_price_calculator;

          if (customPriceCalculatorSI) {

                // gs.include() should define a class in the global scope

                // the class name shoudl be the same as the script include name

                gs.include(customPriceCalculatorSI.name);

                var CatalogPriceCalculatorImpl = __global[customPriceCalculatorSI.name];

          }

          if (typeof CatalogPriceCalculatorImpl !== 'function') {

                // by default use the out-of-the-box price calculator

                CatalogPriceCalculatorImpl = DefaultCatalogPriceCalculator;

          }

          this.cpc = new CatalogPriceCalculatorImpl(gr);

    },

    calcPrice : function() {

          return this.cpc.calcPrice();

    }

};

/*

* This is a [renamed] copy of the OOB CatalogPriceCalculator class.

*/

var DefaultCatalogPriceCalculator = Class.create();

DefaultCatalogPriceCalculator.prototype = {

  < full copy of the OOB CatalogPriceCalculator prototype goes here >

};

The custom copy of the CatalogRecurringPriceCalculator follows the same idea with the only difference being the name of the custom field on the catalog item.

All what has been explained so far was the preparation work. It does not actually change any price calculation logic on any catalog items. The actual custom pricing logic should be defined in a new script include (you can defined as many pricing models as necessary).

Here is an example (create a new script include)

  • Name: DynamicServerOrderPriceCalculator
  • API Name: global.DynamicServerOrderPriceCalculator
  • Client Callable: false
  • Application: Global
  • Accessible from: This application scope only

gs.include("CatalogPriceCalculator");

var DynamicServerOrderPriceCalculator = Class.create();

DynamicServerOrderPriceCalculator.prototype = Object.extendsObject(DefaultCatalogPriceCalculator, {

    calcPrice : function() {

          var base_price = this.cartItem.cat_item.price.getReferenceValue();

          var capacity = this.cartItem.variables['u_capacity'].getGlideObject().getValue();

          return 0.75 * base_price + 0.25 * capacity;

    }

});

To put this custom pricing script in use, it should be referenced from the u_custom_price_calculator field on a catalog item definition.

12 REPLIES 12

Hi Max,



just wondering if you finally get the result you want?



What I did based on this and other topics in community regarding customizing prices is:


script include u_CatalogPriceCalculator, marked as client callable:


gs.include("CatalogPriceCalculator");


var u_CatalogPriceCalculator = Class.create();


u_CatalogPriceCalculator.prototype = Object.extendsObject(DefaultCatalogPriceCalculator, {  


        initialize: function(/* GlideRecord */ gr) {  


                  this.cartItem = gr;  


        },  


calcPrice : function() {


                  var base_price = this.cartItem.cat_item.price.getReferenceValue();  


                // var discount = this.cartItem.variables['u_ritm_discount'].getGlideObject().getIntValue();


                  return base_price * 0.20; //discount;


  },  


type : u_CatalogPriceCalculator  


});



and also made the following client-script onChange of discount value:


function onChange(control, oldValue, newValue, isLoading) {


      if (isLoading || newValue == '0') {


            return;


  }else{


  alert('you changed Discount from ' + oldValue + ' to ' + newValue);


  var ga = new GlideAjax('u_CatalogPriceCalculator');


                ga.addParam('sysparm_name','calcPrice');


  getXMLWait();


        }


}



so, I do get informational message that I've changed discount from 0 to let say 20, but item price doesn't change.



I would much appreciate other experts help on this.


Hi Viktor,

I'm trying to do a similar task of dynamically updating the price in the cart.

I have a Catalog client script which has to call this script include 'DynamicCatalogPriceCalculator' (which extends the CatalogPriceCalculator script include) in order to update the price.

But my question is how do I trigger the price to change, where do I return the value to?

I can attach screenshots if required.

Any kind of help is appreciated.

Thanks in advance.

Rahul.  





divyavashishtha
Tera Contributor

Hi,



I am also not able to call the DynamicServerOrderPriceCalculator script include in client side.



please help how can i call this in client side so that the base price of item changes according to the change in quantity (catalog variable).



Regards


Divya Dattatray


Anyone having issues making this work on an Order Guide in the Service Portal?

 

Thanks,
Ayman

Rishi18
Kilo Expert

Hello,

 

Is there any way to return the Price(along with the currency) here?

 

Please let me know.

 

Thank in advance!