You are here:
Customize the MarginValidation Interface Implementation
This interface implementation is called by the default Margin Range Loader interface implementation. You can overwrite this class to customize the margin validation.
-
Using the Load Margin Ranges interface implementation, the pricing service queries the named calculation procedure to find the margin ranges for the product specified in the line item and passes it to the Margin Validation interface implementation.
-
Next, the Margin Validation interface implementation compares the line item's margin to determine whether the range is within the specified limits.
-
If the margin is outside the valid range, it returns an error message in the CPQ pricing message field to the Industries CPQ Cart.
This step is optional. Skip it if you want to use the default MarginValidation interface implementation.
Name |
Properties |
|---|---|
Interface Name |
Margin Validation |
Active Implementation Class |
DefaultMarginValidationImplementation |
Purpose |
Introduced in the Winter '19 release, this interface implementation is used to validate the margin range on individual line items. |
-
Specify your input and output parameters.
Input Map Key
Datatype
Description
Input Parameters
parent
sObject
For order, opportunity, or quote
lineItemList
List<sObject>
For OrderItem, QuoteLineItem, or OpportunityLineItem
lineItemIdToMarginRangeMap
Map<Id, Map <String, Object>>
For each line item, a map with the following keys:
-
OneTimeMarginLowerBound
-
OneTimeMarginUpperBound
-
RecurringMarginLowerBound
-
RecurringMarginUpperBound
Output Parameters: None
-
-
Specify an error message in the 'CpqPricingMessage__c' field of the
line items. Error messages for one-time margins and recurring margins are
displayed for each line item in the Industries CPQ Cart when the margin
ranges are violated.
For example, the one-time margin must be between 5.0% to 10.0% is displayed in the cart for a line item when the validation.
-
Customize the margin validation implementation using the sample
implementation code.
global class CustomMarginValidationImplementation implements vlocity_cmt.VlocityOpenInterface { private static String ONE_TIME_MARGIN_PREFIX = 'OneTimeMargin'; private static String RECURRING_MARGIN_PREFIX = 'RecurringMargin'; private static String nsp = 'vlocity_cmt__'; /* * invoke method. */ public Boolean invokeMethod(String methodName, Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) { if (methodName.equals('validateMarginRange')) { validateMarginRange(input, output, options); return true; } return false; } /* * validate margin ranges. * */ private void validateMarginRange(Map<String, Object> input, Map<String, Object> output, Map<String, Object> options) { List<SObject> lineItemList = (List<SObject>) input.get('lineItemList'); //map, which has margin range details. Map<Id, Map<String, Object>> itemIdTomarginRangeMap = (Map<Id, Map<String, Object>>) input.get('lineItemIdToMarginRangeMap'); for (SObject item : lineItemList) { String oneTimeMarginMessage = null; String recurringMarginMessage = null; Id lineItemId = (Id) item.get('Id'); //margin range map also has all output columns of martix. Map<String, Object> marginRangeMap = itemIdTomarginRangeMap.get(lineItemId); if (marginRangeMap != null) { Decimal oneTimeMargin = (Decimal) item.get(nsp + 'OneTimeMargin__c'); Decimal recurringMargin = (Decimal) item.get(nsp + 'RecurringMargin__c'); Decimal oneTimeMarginLowerBound = (Decimal) marginRangeMap.get('OneTimeMarginLowerBound'); Decimal oneTimeMarginUpperBound = (Decimal) marginRangeMap.get('OneTimeMarginUpperBound'); Decimal recurringMarginLowerBound = (Decimal) marginRangeMap.get('RecurringMarginLowerBound'); Decimal recurringMarginUpperBound = (Decimal) marginRangeMap.get('RecurringMarginUpperBound'); if (oneTimeMarginLowerBound != null && oneTimeMarginUpperBound != null && (oneTimeMargin > oneTimeMarginUpperBound || oneTimeMargin < oneTimeMarginLowerBound)) { oneTimeMarginMessage = ONE_TIME_MARGIN_PREFIX + ':' + 'One time margin must be between ' + oneTimeMarginLowerBound + ' and ' + oneTimeMarginUpperBound + '.'; } if (recurringMarginLowerBound != null && recurringMarginUpperBound != null && (recurringMargin > recurringMarginUpperBound || recurringMargin < recurringMarginLowerBound)) { recurringMarginMessage = RECURRING_MARGIN_PREFIX + ':' + 'Recurring margin must be between ' + recurringMarginLowerBound + ' and ' + recurringMarginUpperBound + '.'; } } //read previous message and update String message = (String) item.get(nsp + 'CpqPricingMessage__c'); List<String> errorList = new List<String>(); if (String.isNotBlank(message)) { List<String> messageList = message.split('\\|'); for (String m : messageList) { List<String> mList = m.split(':'); if (mList.size() > 1) { if (!mList[0].equals(ONE_TIME_MARGIN_PREFIX) && !mList[0].equals(RECURRING_MARGIN_PREFIX)) { errorList.add(m); } } } } if (oneTimeMarginMessage != null) { errorList.add(oneTimeMarginMessage); } if (recurringMarginMessage != null) { errorList.add(recurringMarginMessage); } //update pricing message. if (errorList.isEmpty()) { item.put(nsp + 'CpqPricingMessage__c', null); } else { item.put(nsp + 'CpqPricingMessage__c', String.join(errorList, '|')); } } } }

