---
schema_version: "1"
id: a9810d1e2b876d78f07f248ca25023e3915af719aeea07112614a3f05db51349
title: Customize the MarginValidation Interface Implementation
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/ind/264-0-0/comms_customize_the_marginvalidation_interface_implementation.md
canonical_url: https://help.salesforce.com/s/articleView?id=ind.comms_customize_the_marginvalidation_interface_implementation.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 4f9152d7e454c6096da64485bcc203b40aa05ae5cc4bd21512b1da532e001351
description: This interface implementation is called by the default Margin Range Loader interface implementation. You can overwrite this class to customize the margin validation.
products:
  - Communications
  - Media
  - Energy and Utilities
release: "264"
---
# 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.

![Note](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-ind-comms_media_energy_managed-264-0-0-production-enus/ff4079f6-a384-475c-b863-578bbbb0ef9b/images/icon_note.png)

Note

This step is optional. Skip it if you want to use the default MarginValidation interface implementation.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Margin Validation Interface Implementation Properties">
        <colgroup>
          <col>
          <col>
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d128199e64">
              <p style="margin-bottom:0;">Name</p>
            </th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d128199e70">
              <p style="margin-bottom:0;">Properties</p>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Name" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e64 ">
              <p style="margin-bottom:0;">Interface Name</p>
            </td>

            <td data-label="Properties" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e70 ">
              <p style="margin-bottom:0;">Margin Validation</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Name" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e64 ">
              <p style="margin-bottom:0;">Active Implementation Class</p>
            </td>

            <td data-label="Properties" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e70 ">
              <p style="margin-bottom:0;">DefaultMarginValidationImplementation</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Name" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e64 ">
              <p style="margin-bottom:0;">Purpose</p>
            </td>

            <td data-label="Properties" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e70 ">
              <p style="margin-bottom:0;">Introduced in the Winter '19 release, this interface
                implementation is used to validate the margin range on individual line
                items.</p>
            </td>

          </tr>
        </tbody>
      </table>

1. Specify your input and output parameters.
    
    <table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Input and Output Parameters">
            <colgroup>
              <col style="width:33.33333333333333%">
              <col style="width:33.33333333333333%">
              <col style="width:33.33333333333333%">
            </colgroup>
            <thead class="slds-text-title_caps ">
              <tr class="">
                <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d128199e155">
                  <p style="margin-bottom:0;">Input Map Key</p>
                </th>
                <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d128199e161">
                  <p style="margin-bottom:0;">Datatype</p>
                </th>
                <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d128199e167">
                  <p style="margin-bottom:0;">Description</p>
                </th>
              </tr>
            </thead>
            <tbody>
              <tr class="">
                <td class="slds-cell-wrap" colspan="3" style="vertical-align:top;" headers="d128199e155 d128199e161 d128199e167 ">
                  <p style="margin-bottom:0;">Input
                    Parameters</p>
                </td>

              </tr>
              <tr class="">
                <td data-label="Input Map Key" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e155 ">
                  <p style="margin-bottom:0;">parent</p>
                </td>

                <td data-label="Datatype" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e161 ">
                  <p style="margin-bottom:0;">sObject</p>
                </td>

                <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e167 ">
                  <p style="margin-bottom:0;">For order, opportunity, or quote</p>
                </td>

              </tr>
              <tr class="">
                <td data-label="Input Map Key" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e155 ">
                  <p style="margin-bottom:0;">lineItemList</p>
                </td>

                <td data-label="Datatype" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e161 ">
                  <p style="margin-bottom:0;">List&lt;sObject&gt;</p>
                </td>

                <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e167 ">
                  <p style="margin-bottom:0;">For OrderItem, QuoteLineItem, or
                    OpportunityLineItem</p>
                </td>

              </tr>
              <tr class="">
                <td data-label="Input Map Key" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e155 ">
                  <p style="margin-bottom:0;">lineItemIdToMarginRangeMap</p>
                </td>

                <td data-label="Datatype" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e161 ">
                  <p style="margin-bottom:0;">Map&lt;Id, Map &lt;String, Object&gt;&gt;</p>
                </td>

                <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d128199e167 ">
                  <p>For each line item, a map with the following keys:</p>
                  <ul>
                    <li>
                      <p>OneTimeMarginLowerBound</p>
                    </li>

                    <li>
                      <p>OneTimeMarginUpperBound</p>
                    </li>

                    <li>
                      <p>RecurringMarginLowerBound</p>
                    </li>

                    <li>
                      <p>RecurringMarginUpperBound</p>
                    </li>

                  </ul>
                </td>

              </tr>
              <tr class="">
                <td class="slds-cell-wrap" colspan="3" style="vertical-align:top;" headers="d128199e155 d128199e161 d128199e167 ">
                  <p style="margin-bottom:0;">Output
                    Parameters: None</p>
                </td>

              </tr>
            </tbody>
          </table>
2. 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.
3. 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, '|'));
                }
            }
        }
    }
    ```