Enable pricing guidance and data in quotes
  • 06 Aug 2024
  • 4 Minutes to read
  • Dark
    Light

Enable pricing guidance and data in quotes

  • Dark
    Light

Article summary

Zilliant CPQ supports integration with Zilliant Price IQ and Zilliant Price Manager. This integration enables you to seamlessly attach pricing guidance and price data to your quotes to derive insights into your pricing strategy.

The following image shows the results of adding pricing data from Price IQ and Price Manager. Std. Price / Unit column values come from Price Manager. Start Discount, Target Discount, and Floor Discount columns values come from Price IQ. Based on those values and manually entered Discount values, CPQ calculates Health values and Total Price values for each line in the quote.

PIQ and PM integration with CPQ

Prerequisites

To get started, contact your Zilliant representative. They will perform prerequisite setup tasks to facilitate integration.

Configure integration

The integration operates by using a Groovy script. This script calls specific Zilliant database formulas and returns values to designated fields in a quote.

To attach price guidance and list prices to quotes, you must:

  1. Create a Groovy script.
  2. Upload the Groovy script to Zilliant CPQ.
  3. Attach the Groovy script to a pricing step in the active pricing schema.

Create a Groovy script

Create a Groovy script that calls specific Zilliant database formulas and returns the values to designated fields on the quote. In addition to the common binding variables, the com.imc.iss.groovy.priceiq package and com.imc.iss.groovy.salesitem package are available for this script.

Example Groovy script with comments
@Grab(group='org.codehaus.groovy', module='groovy-json', version='2.4.7')

// Import necessary classes and libraries
import com.imc.context.BaseContext;
import com.imc.datamodel.BusinessObject
import com.imc.iss.groovy.GroovyCtxUtil
import com.imc.iss.groovy.priceiq.GroovyPriceIQHelper
import com.imc.iss.price.model.input.document.SalesItem;
import com.imc.iss.price.services.pricing.PriceAmount;
import com.imc.model.Amount;
import com.imc.model.Currency;
import com.imc.vocabulary.Schema;

import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import groovy.json.JsonSlurper;

SalesItem salesItemDTOBean = prizableDTOBean; // Retrieve the sales item DTO bean
GroovyCtxUtil groovyCtxUtil = groovyCtxUtil;// Retrieve the utility class for ad-hoc data access
BaseContext ctx = groovyCtxUtil.getCtx(); // Retrieve the base context from the utility

// Retrieve business objects related to the sales item
final BusinessObject salesItemBO = salesItemDTOBean.getInstance();
final BusinessObject quoteBO = salesItemDTOBean.getQuoteBO();
final BusinessObject ihpiBO = ctx.commandFactory().getRelAttrValue().businessObject(salesItemBO).businessAttribute(Schema.includesItemHeaderPriceItem).execute().get();
final BusinessObject productBO = ctx.commandFactory().getRelAttrValue().businessObject(salesItemBO).businessAttribute(Schema.isProduct).execute().get();
// If the system uses an opportunity, additional verification is needed here
final BusinessObject accountBO = ctx.commandFactory().getRelAttrValue().businessObject(quoteBO).businessAttribute(Schema.quoteContainedBy).execute().get();

// Retrieve ERP IDs, quantity, and other information needed for discount calculation
final String productErpId = (String) ctx.commandFactory().getDataAttrValue().businessObject(productBO).businessAttribute(Schema.objectERPId).execute().orElse("");
final String accountErpId = (String) ctx.commandFactory().getDataAttrValue().businessObject(accountBO).businessAttribute(Schema.objectERPId).execute().orElse("");
final BigDecimal qty = (BigDecimal) ctx.commandFactory().getDataAttrValue().businessObject(ihpiBO).businessAttribute(Schema.itemHeaderQuantity).execute().get();

// Retrieve discount guidance from the Zilliant database based on product ERP ID, account ERP ID, and quantity
Guidance guidance = getGuidance(productErpId, accountErpId, qty);

// Set discount guidance to the line item table
if(guidance == null)
{
	// If no guidance is available, set default values
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute18).values(0).allowSetReadOnlyValue().execute();
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute19).values(0).allowSetReadOnlyValue().execute();
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute20).values(0).allowSetReadOnlyValue().execute();
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute21).values("").allowSetReadOnlyValue().execute();
}
else
{
	// If guidance is available, set the calculated values
    ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute18).values(guidance.startDiscount).allowSetReadOnlyValue().execute();
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute19).values(guidance.targetDiscount).allowSetReadOnlyValue().execute();
	ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute20).values(guidance.floorDiscount).allowSetReadOnlyValue().execute();
	
	// Update health status based on the calculated discount
	BigDecimal discount = (BigDecimal) ctx.commandFactory().getDataAttrValue().businessObject(ihpiBO).businessAttribute(Schema.itemHeaderDiscount).execute().orElse(BigDecimal.ZERO);
	if(discount.compareTo(guidance.targetDiscount) <= 0)
	{
		ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute21).values("🟢 GOOD").allowSetReadOnlyValue().execute();
	}
	else if(discount.compareTo(guidance.floorDiscount) <= 0)
	{
		ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute21).values("🟡 MEDIUM").allowSetReadOnlyValue().execute();
	}
	else
	{
		ctx.commandFactory().setDataAttrValues().businessObject(salesItemBO).businessAttribute(Schema.salesItemAttribute21).values("🔴 BAD").allowSetReadOnlyValue().execute();
	}
}

// Return a PriceAmount object with a base amount set to zero
return getPriceAmountZERO();

// Functions to retrieve guidance based on product ERP ID, account ERP ID, and quantity
Guidance getGuidance(String productErpId, String accountErpId, BigDecimal qty)
{
	if(productErpId.isEmpty() || accountErpId.isEmpty())
		return null;

	def jsonPayload = """
		{
			"formulas": [
				"piq_fx_StartDiscount",
				"piq_fx_TargetDiscount",
				"piq_fx_FloorDiscount"
			],
			"responseDetails": [
				"none"
			],
			"lines": [
				{
					"p_CustomerId": "${accountErpId}",
					"p_LineLevel": "Product",
					"p_LevelValue": "${productErpId}",
					"p_Country": "United States",
					"p_CurrCode": "USD",
					"piq_fx_ExpectedDefaultUnits": ${qty.toPlainString()},
					"p_Uom": "each"
				}
			]
		}
	"""

	// Make request to the Formula Evaluation service
	def responseBody = groovyPriceIQHelper.formulaEvaluation(jsonPayload);
	def jsonResponse = new JsonSlurper().parseText(responseBody);
	
	// Retrieve guidance values from the response
	def startOutput = jsonResponse["piq_fx_StartDiscount"]["outputResults"][0];
	def targetOutput = jsonResponse["piq_fx_TargetDiscount"]["outputResults"][0];
	def floorOutput = jsonResponse["piq_fx_FloorDiscount"]["outputResults"][0];
	if(startOutput == null || targetOutput == null || floorOutput == null)
	{
		return null;
	}
	
	def start = startOutput["piq_fx_StartDiscount"][0];
	def target = targetOutput["piq_fx_TargetDiscount"][0];
	def floor = floorOutput["piq_fx_FloorDiscount"][0];
	if(start == "null" && target == "null" && floor == "null")
	{
		return null;
	}
	
	return new Guidance(start*100, target*100, floor*100);
}

// Function to return PriceAmount object with base amount set to zero
PriceAmount getPriceAmountZERO()
{
	// Set base amount 
	SalesItem salesItemDTOBean = prizableDTOBean;
	
	final Currency salesItemCurrency = salesItemDTOBean.getCurrency(); //sales item currency
	BigDecimal targetTotalAmountValue = BigDecimal.ZERO;
	Amount amount = new Amount();
	amount.setAmountCurrency(salesItemCurrency);
	amount.setAmountValue(targetTotalAmountValue);
	
	PriceAmount pa = new PriceAmount();
	pa.setBaseAmount(amount);
	pa.setPricingStep(pricingStep);
	return pa;
}

// Class to hold guidance values
class Guidance
{
	public BigDecimal startDiscount;
	public BigDecimal targetDiscount;
	public BigDecimal floorDiscount;
	
	public Guidance(BigDecimal startDiscount, BigDecimal targetDiscount, BigDecimal floorDiscount)
	{
		this.startDiscount = startDiscount;
		this.targetDiscount = targetDiscount;
		this.floorDiscount = floorDiscount;
	}
}

As shown in this example image, this Groovy script performs the following tasks:

  • Imports necessary classes and libraries.
  • Retrieves information about sales items, quotes, and related business objects.
  • Retrieves discount guidance from the Zilliant database based on product ERP ID, account ERP ID, and quantity.
  • Calculates the start, target, and floor discounts for each quote line based on the retrieved discount guidance.
  • Updates the health status for the quote lines by comparing the manually entered discount with the calculated start, target, and floor discounts.

Upload a Groovy script

Upload the Groovy script to Zilliant CPQ. Select Internal Pricing – Custom Item Calculation as the script type.

Attach a Groovy script to a pricing scheme

  1. Sign in to Zilliant CPQ with your administrator credentials.
  2. Identify or create a price item type to use for the pricing step that retrieves values from the Zilliant database. Its price item type category must be Groovy Script.
  3. From the left navigation area, select Pricing.
  4. From the top navigation bar, select Pricing Schemes.
  5. Select or create an active pricing scheme.
  6. Select or create a pricing step that retrieves values from the Zilliant database.
  7. On the pricing step editing dialog, from the Groovy Script dropdown list, select your Groovy script.

Was this article helpful?

What's Next
Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.