Asset Line Item Callback provides you a mechanism to define the criteria based on which you want to filter assets on the Installed Product page. The asset line items on the Installed product page are shown according to the business logic defined in the Asset Line Item Callback class. You can further filter the asset line items on the Installed Products page using the filters on the page. You can also use this callback to validate the termination of an asset on the Asset Termination page.

To use the Asset Line Item Callback you must create a custom Apex class that implements the Apttus_Config2.CustomClass.IAssetLineItemCallback4 interface and register the custom apex class with Asset Line Callback Class. You must write your custom logic in the custom apex class.

The following methods are available in the Apttus_Config2.CustomClass.IAssetLineItemCallback4 interface:

MethodSignatureDescription
finish()void finish()This the last method that is executed after the callback is invoked.
getAssetSearchScope()List getAssetSearchScope()You can use this method to return the asset search scope that was set in the start method.
getFilterExpr()String getFilterExpr(Apttus_Config2.CustomClass.ActionParams)You can use this method to set the search scope.
getQueryFilter()String getQueryFilter(Id)You can use this method to create and return the query filter.
start()void start(Apttus_Config2.ProductConfiguration, String, List)

This is the first method that is executed when the callback is invoked.

validateAssetTermination()Boolean validateAssetTermination(Set, Set, Date)You can use this method to validate the termination of asset.
getAssetTerminationDate()Date getAssetTerminationDate()You can use this method to fetch the termination date of asset.

You must update CPQ to the latest version in the Apex class that you create to implement the Apttus_Config2.CustomClass.IAssetLineItemCallback4 interface. Otherwise, any logic to default date is not executed. Follow the steps below to update the version setting.

  1. Go to Setup Develop > Apex Classes.
  2. Open the Apex class you created to implement the Asset Line Item Callback.
  3. Click Edit. Click Version Settings.
  4. Find the Conga Configuration & Pricing package. In the Version dropdown next to the package select the latest version of CPQ. For details about latest packages, refer to CPQ on Salesforce Release Notes.
  5. Click Save.


Examples

You can use Asset Filter Callback in the following scenarios. You can modify the code based on your requirements.

  • Defaulting date and custom validation.
  • Retrieving assets from multiple accounts.

The following sample code enables you to set a default date and define custom validation.

private Apttus_Config2.CustomClass.IAssetLineItemCallback4 callback = null;
private transient Apttus_Config2.ProductConfiguration cart = null;
private List<String> assetSearchScope = null;
private String assetSearchFilter = null;


/**
 * Callback at the beginning of the asset selection call.
 * Use the start method to initialize state
 * @param cart the cart object or null if there is no cart context
 * @param assetSearchFilter the preset static filter used in the asset search or null if there is no preset filter
 * @param assetSearchScope the list of asset fields to match the search text or empty to use the default list of fields
 */
global void start(Apttus_Config2.ProductConfiguration cart, String assetSearchFilter, List<String> assetSearchScope) 
{
    // delegate to the asset callback
    this.cart = cart;
    this.assetSearchFilter = assetSearchFilter;
    this.assetSearchScope = assetSearchScope;
}

global Date getAssetTerminationDate() 
{
    return Date.newInstance(2018,01,01);
}

/**
 * Callback to return part of SOQL filter clause
 * This filter is used in listing installed products
 * @param accountId is the context account id  
 * @return The query filter is like the following. 
 *      Name LIKE 'A%' AND Quantity__c > 100 
 *      Id IN ('000123', '000124')  
 */
global String getQueryFilter(ID accountId) 
{
    // delegate to the asset callback
    system.debug ('*************** AssetLineItemCallbackAdapter:' + accountId);
    return null;
    
}

global Boolean validateAssetTermination(Set<ID> assetIds, Set<ID> accountIds, Date eDate) 
{
    String nsPrefix = 'Apttus_Config2__';
    Apttus_Config2.CPQStruct.QueryAssetsRequestDO request = new Apttus_Config2.CPQStruct.QueryAssetsRequestDO();
    request.AccountIds = new List<Id>(accountIds);
    system.debug ('accountids' + accountIds);
    request.FieldNames = new List<String>();
    request.FieldNames.add(nsPrefix + 'StartDate__c');
    request.FieldNames.add(nsPrefix + 'EndDate__c');
    request.FieldNames.add( 'Name');

    //added new fields
    request.FieldNames.add(nsPrefix + 'BusinessObjectId__c');
    request.FieldNames.add(nsPrefix + 'ProductId__c');
    request.FieldNames.add(nsPrefix + 'LineNumber__c');
    request.FieldNames.add(nsPrefix + 'PrimaryLineNumber__c');
    request.FieldNames.add(nsPrefix + 'IsPrimaryRampLine__c');
    request.FieldNames.add(nsPrefix + 'IsPrimaryLine__c');
    request.FieldNames.add(nsPrefix +  'PriceGroup__c');
    request.FieldNames.add(nsPrefix +  'LineType__c');
    request.FieldNames.add(nsPrefix +  'ChargeType__c');
    request.FieldNames.add(nsPrefix + 'CurrentContractStartDate__c');

    if (assetIds != null && assetIds.size() >0) 
	{
        request.customFilter =  'Id IN  (';
        for (Id assetId : assetIds) 
		{
            request.customFilter +=  '\'' + assetId + '\',';
            system.debug ('assetids: ' + assetId);
        }   
        request.customFilter = request.customFilter.removeEnd(',');
        request.customFilter += ')';
        system.debug ('request.customFilter ' + request.customFilter);
    }

    Apttus_Config2.CPQStruct.QueryAssetsResponseDO assetResponseDO = Apttus_Config2.AssetService.getAssetLineItems(request);

    for (Apttus_Config2__AssetLineItem__c asset: assetResponseDO.AssetLineItems)
	{
        if (asset.Apttus_Config2__IsPrimaryRampLine__c && asset.Apttus_Config2__IsPrimaryLine__c) 
		{
			Apttus_Config2__AssetLineItem__c farthestLineItem = findFarthestRampLine(asset, assetResponseDO.AssetLineItems);
			if (eDate > farthestLineItem.Apttus_Config2__EndDate__c) 
			{
				ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.ERROR, 'Termination date : '+eDate + 'should not be greater than Ramp Farthest Asset End date: ' + farthestLineItem.Apttus_Config2__EndDate__c );
				ApexPages.addMessage(message);
				return false;

			}
        } 
		else if (asset.Apttus_Config2__IsPrimaryLine__c && asset.Apttus_Config2__LineType__c == 'Product/Service') 
		{
			if (eDate >= asset.Apttus_Config2__EndDate__c) 
			{
				ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.ERROR, 'Termination date should not greater than Asset End Date :Effective Date is ' + eDate );
				ApexPages.addMessage(message);
				return false;

			} 
			else if (eDate < asset.Apttus_Config2__StartDate__c)
			{
				ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.ERROR, 'Invalid Termination date');
				ApexPages.addMessage(message);
				return false;                    
			}
        }
        
       /* if (eDate < asset.Apttus_Config2__CurrentContractStartDate__c) {
            ApexPages.Message message = new ApexPages.Message(ApexPages.Severity.ERROR, 'Asset cannot be terminated before Contract start date');
            ApexPages.addMessage(message);
            return false; 
        } */   
    }
    return true;
}

/**
 * Callback to return the filter expression for the asset query where clause
 * This filter is used in listing installed products
 * @param params the parameters for the method
 * @return the filter expression or null to use the default filter. 
 * e.g. Name LIKE 'A%' AND Quantity__c > 100 
 *      Id IN ('000123', '000124')  
 */
global String getFilterExpr(Apttus_Config2.CustomClass.ActionParams params)
{
   // dispatch based on the location id parameter
    String clause = '';
    Boolean locationFound = false;
    Boolean accountFound = false;
    Boolean customParamsExist = false;
    String ns = 'Apttus_Config2__';
    List<String> fieldNames = new List<String>();
    fieldNames.add(ns + 'AccountId__c');

    if(params.CustomParams != null && params.CustomParams.size() > 0)
	{
        customParamsExist = true;
        Boolean isFirst = true;
        for(String fieldName: params.CustomParams.keySet()) 
		{
            if (isFirst) 
			{
                isFirst = false;
            }
			else
			{
                clause += ' AND ';
            }
                    
            if (fieldName.toLowerCase().contains('fromdate'))
			{
                clause += fieldName.substring(0, fieldName.toLowerCase().indexOf('fromdate')) + ' >= ' + params.CustomParams.get(fieldName);
            
            }
			else if (fieldName.toLowerCase().contains('todate'))
			{
                clause += fieldName.substring(0, fieldName.toLowerCase().indexOf('todate')) + ' <= ' + params.CustomParams.get(fieldName);
            }
			else
			{
                clause += fieldName + ' IN (' + params.CustomParams.get(fieldName) + ')';
            }   
        }
    }
    if(params.LocationIds != null && !params.LocationIds.isEmpty())
	{
        if (customParamsExist) 
		{
            clause += ' AND ';
        }   
        Boolean isFirst = true;
        for (ID Id : params.LocationIds)
		{
            if(isFirst)
			{
                isFirst = false;
                locationFound = true;           
                clause += ns + 'LocationId__c IN (\'' + Id;
            } 
			else 
			{
                clause += '\', \'' + Id;
            }
        }
        if (locationFound)
		{
            clause += '\')';
        }
    }   
        
    if(params.AccountIds != null && !params.AccountIds.isEmpty())
	{
        Boolean isFirstSource = true;
        for (String accountAPIName : fieldNames) 
		{
            if (isFirstSource) 
			{
                isFirstSource = false;
            } 
			else 
			{
                clause += ' OR ';
            }
            Boolean isFirst = true;
            for (ID Id : params.AccountIds) 
			{
                if(isFirst)
				{
                    if (locationFound || customParamsExist) 
					{
                        clause += ' AND ';
                    }
                    isFirst = false;
                    accountFound = true;
                    clause += accountAPIName + ' IN (\'' + Id;
                } 
				else 
				{
                    clause += '\', \'' + Id;
                }
            }
            if (accountFound) 
			{
                clause += '\')';
            }
        }
    }
    boolean isShowMultipleAccountsEnabled = false;
    //when account filter is not displayed and static asset filter is not present user cart account id
    
    if (!accountFound && !isShowMultipleAccountsEnabled && (assetSearchFilter == null || assetSearchFilter.trim().length() == 0) ) 
	{
        if (locationFound || customParamsExist) 
		{
            clause += ' AND ';
        }
        accountFound = true;
        Boolean isFirstSource = true;
        for (String accountAPIName : fieldNames) 
		{
            if (isFirstSource) 
			{
                isFirstSource = false;
                clause += accountAPIName + ' = \'' + params.AccountId + '\' ';
            } 
			else 
			{
                clause += ' OR ' + accountAPIName + ' = \'' + params.AccountId + '\' ';
            }
        }
    }
    //append static asset filter
    if (locationFound == true || accountFound == true || customParamsExist == true) 
	{
        if (!(assetSearchFilter == null || assetSearchFilter.trim().length() == 0)) 
		{
            return clause  +  ' AND '  + assetSearchFilter;
        }    
        return clause ;
    }           
    // account id is also available in the cart
    if (!(assetSearchFilter == null || assetSearchFilter.trim().length() == 0)) 
	{
        return assetSearchFilter;        
    }
   
    // the sample query filter
    String qryStr = '';
    Boolean isFirstSource = true;
    for (String accountAPIName : fieldNames) 
	{
        if (isFirstSource) 
		{
            isFirstSource = false;
            qryStr += accountAPIName + ' = \'' + params.accountId + '\' ';
        } 
		else 
		{
            qryStr += ' OR ' + accountAPIName + ' = \'' + params.accountId + '\' ';
        }
    }
    system.debug ('*************** qryStr'+ qryStr);
    return qryStr;
}

/**
 * Gets the asset search scope
 * @return thr asset search scope or null to use the default asset search scope
 */
global List<String> getAssetSearchScope()
{
    // delegate to the asset callback
    return null;  
}

/**
 * Callback after the filter is used
 * Use the finish method to release state
 */
global void finish() 
{
    // delegate to the asset callback   
}

private static Apttus_Config2__AssetLineItem__c findFarthestRampLine(Apttus_Config2__AssetLineItem__c primaryRampLine, List<Apttus_Config2__AssetLineItem__c> assetLineItems) 
{
   Apttus_Config2__AssetLineItem__c farthestAssetLineItem = primaryRampLine;
   if (assetLineItems != null && !assetLineItems.isEmpty()) {
        for (Apttus_Config2__AssetLineItem__c assetLineItem : assetLineItems) 
		{
		if (assetLineItem.Apttus_Config2__PriceGroup__c == 'Price Ramp'
			&& assetLineItem.Apttus_Config2__BusinessObjectId__c == primaryRampLine.Apttus_Config2__BusinessObjectId__c
			&& assetLineItem.Apttus_Config2__ProductId__c == primaryRampLine.Apttus_Config2__ProductId__c
			&& assetLineItem.Apttus_Config2__LineNumber__c.intValue() == primaryRampLine.Apttus_Config2__LineNumber__c.intValue()
			&& (primaryRampLine.Apttus_Config2__PrimaryLineNumber__c == null
				|| (assetLineItem.Apttus_Config2__PrimaryLineNumber__c != null
					&& assetLineItem.Apttus_Config2__PrimaryLineNumber__c.intValue() == primaryRampLine.Apttus_Config2__PrimaryLineNumber__c.intValue()))
			&& assetLineItem.Apttus_Config2__IsPrimaryRampLine__c == false
			&& assetLineItem.Apttus_Config2__EndDate__c > farthestAssetLineItem.Apttus_Config2__EndDate__c) 
			{
				farthestAssetLineItem = assetLineItem;
			}
        }
    }
    return farthestAssetLineItem;
} 
CODE


The following sample code enables you to fetch assets from multiple accounts.

/*
 * This class is used in Asset Line Item callback to show asset on Cart page.
 */
global with sharing class CurrentUserFilter_AssetLineItemCallback implements Apttus_Config2.CustomClass.IAssetLineItemCallback4 
	{

    private List<String> assetSearchScope = null;
    private String assetSearchFilter = null;
    private ID userId = null;

    /**
     * Callback at the beginning of the asset selection call.
     * Use the start method to initialize state
     * @param cart the cart object or null if there is no cart context
     * @param assetSearchFilter the preset static filter used in the asset search or null if there is no preset filter
     * @param assetSearchScope the list of asset fields to match the search text or empty to use the default list of fields
     */
    global void start(Apttus_Config2.ProductConfiguration cart, String assetSearchFilter, List<String> assetSearchScope) {
        this.userId = cart.getConfigSO().CreatedById;
    }

    /**
     * Callback to return part of SOQL filter clause
     * This filter is used in listing installed products
     * @param accountId is the context account id 
     * @return The query filter is like the following.
     *         Name LIKE 'A%' AND Quantity__c > 100
     *         Id IN ('000123', '000124') 
     */
    global String getQueryFilter(ID accountId) {
        // all Asset Lines created by the current user
        return 'CreatedById = \'' + userId + '\' AND CreatedDate > LAST_MONTH';
    }
    
    global Boolean validateAssetTermination(Set<ID> assetIds, Set<ID> accountIds, Date eDate) {
        return true;
    }
    
    global Date getAssetTerminationDate() {
        return Date.newInstance(2018,01,01);
    }

    /**
     * Callback to return the filter expression for the asset query where clause
     * This filter is used in listing installed products
     * @param params the parameters for the method
     * @return the filter expression or null to use the default filter.
     * e.g. Name LIKE 'A%' AND Quantity__c > 100
     *         Id IN ('000123', '000124') 
     */
    global String getFilterExpr(Apttus_Config2.CustomClass.ActionParams params) {
        return getQueryFilter(null);
    }

    /**
     * Gets the asset search scope
     * @return the asset search scope or null to use the default asset search scope
     */
    global List<String> getAssetSearchScope(){
        return this.assetSearchScope;
    }

    /**
     * Callback after the filter is used
     * Use the finish method to release state
     */
    global void finish() {
        
    }
}
CODE