This API takes several parameters and updates the reapproval data in the process instance so that proposal line items can be automatically reapproved when resubmitted after finalizing new items in the cart. This API is available in the base Approvals package, 

APISignature
updateApprovalDatawebService static Boolean updateApprovalData(Id instanceId, String sObjectType, Id contextObjId, List oldContextObjIds, List newContextObjIds)
Request Parameters
NameTypeRequired?Description
instanceIdIDYesThe process instance ID currently running in the system
sObjectTypeStringYesThe sObject type used to identify the object type
contextObjIdIDYesThe ID of the context object
oldContextObjIdsList<ID>oldContextObjIdsYesThe list of approval data context object IDs to be replaced
newContextObjIdsList<ID> newContextObjIdsYesThe list of new approval data context object IDs
Response Parameter
NameTypeRequiredDescription
OkBooleanYesDefines if the operation was successful. Returns true if yes, otherwise false.


Code Sample

The sample below enables you to execute auto re-approvals over proposal line items by considering input parameters such as process instance, sObject type, context object, and lists of old and new context object IDs. These IDs represent the proposal line-item IDs before and after the cart is finalized. You can use this API, for example, when a quote or proposal is approved but the approvals manager changes the discount from 10 to 15% on a proposal line item. You can resubmit the approval request for re-approval. The system honors the auto-reapproval criteria, using which, a request once approved by certain assignees is auto-approved.

/**
*Apttus Approvals Management
*CustomProposalLineItemTrigger         
*@2017 Apttus Inc. All rights reserved.
*/


trigger CustomProposalLineItemTrigger on Apttus_Proposal__Proposal_Line_Item__c (before delete, after insert)
{
    if (Trigger.isBefore && Trigger.isDelete)
	{
       // save map of old line items to attributes before they are deleted
		CustomProposalLineItemSupport.doBeforeDelete(Trigger.old, Trigger.oldMap);
	}
	if (Trigger.isAfter && Trigger.isInsert)
	{
        // update reapproval data with new line items after they are inserted
		CustomProposalLineItemSupport.doAfterInsert(Trigger.new, Trigger.newMap);
    }
}
/**
*Apttus Approvals Management
*CustomProposalLineItemSupport
* @2017 Apttus Inc. All rights reserved.
*/

public with sharing class CustomProposalLineItemSupport extends CustomApprovalsConstants
{
	// line item types
    private static final String LINETYPE_PRODUCT = 'Product/Service';
    private static final String LINETYPE_OPTION = 'Option';

    // proposal
	private static final String PROPOSAL_SOBJECT_TYPE = 'Apttus_Proposal__Proposal__c';
    private static ID quoteId = null;

    // associated process instance
	private static Apttus_Approval__ApprovalProcessInstance__c quoteProcessInstance = null;   

    // map of old line item ids to attribute key
    private static Map<ID,String> oldLineId2KeyMap = new Map<ID,String>();

    // map of new line item attribute key to id
    private static Map<String,ID> newLineKey2IdMap = new Map<String,ID>();

    // map of old line item ids to new line item ids
    private static Map<ID,ID> lineOldId2NewIdMap = new Map<ID,ID>();

    /**
     * Process old ProposalLineItems before they are deleted when a cart is finalized
     *	@param oldLineItems - a list of the old versions of the sObject records
     *  @param oldLineItemsMap - a map of IDs to the old versions of the sObject records
     */

    public static void doBeforeDelete( List<Apttus_Proposal__Proposal_Line_Item__c> oldLineItems, Map<ID, Apttus_Proposal__Proposal_Line_Item__c> oldLineItemsMap)
{      
	// iterate over line items about to deleted
	for (Integer i=0; i<oldLineItems.size(); i++)
	{
		Apttus_Proposal__Proposal_Line_Item__c oldLineItem = oldLineItems[i];
	// get quote from line item
        quoteId = oldLineItem.Apttus_Proposal__Proposal__c;
    // get line item attributes
		String lineNumber = String.valueOf(oldLineItem.Apttus_QPConfig__PrimaryLineNumber__c);
		String lineType = oldLineItem.Apttus_QPConfig__LineType__c;       
		String productId = null;
		
		if (lineType == LINETYPE_PRODUCT)
		{ 
			productId = oldLineItem.Apttus_Proposal__Product__c;         
		}
		else if (lineType == LINETYPE_OPTION)
		{        
			productId = oldLineItem.Apttus_QPConfig__OptionId__c;
      
        //productId = oldLineItem.Apttus_QPConfig__ProductOptionId__c;
		} 
		
		String chargeType = oldLineItem.Apttus_QPConfig__ChargeType__c;
		// create attribute key
			String oldLineKey = lineNumber + ':' + productId + ':' + chargeType;
		// save in map  
			oldLineId2KeyMap.put(oldLineItem.Id, oldLineKey);
    }
} 
/**
* Process new ProposalLineItems after they are inserted when a cart is finalized
* @param newLineItems - a list of the new versions of the sObject records
* @param newLineItemsMap - a map of IDs to the new versions of the sObject records
*/
	public static void doAfterInsert(List<Apttus_Proposal__Proposal_Line_Item__c> newLineItems, Map<ID, Apttus_Proposal__Proposal_Line_Item__c> newLineItemsMap)
	{      
		// iterate over line items about to deleted
        for (Integer i=0; i<newLineItems.size(); i++)
		{        
			Apttus_Proposal__Proposal_Line_Item__c newLineItem = newLineItems[i];
			
		// get quote from line item
			quoteId = newLineItem.Apttus_Proposal__Proposal__c;
			
		// get line item attributes
			String lineNumber = String.valueOf(newLineItem.Apttus_QPConfig__PrimaryLineNumber__c);
			String lineType = newLineItem.Apttus_QPConfig__LineType__c;
			String productId = null;
			
			if (lineType == LINETYPE_PRODUCT)
			{
				productId = newLineItem.Apttus_Proposal__Product__c;
			}
			else if(lineType == LINETYPE_OPTION)
			{
				productId = newLineItem.Apttus_QPConfig__OptionId__c;       
				//productId = newLineItem.Apttus_QPConfig__ProductOptionId__c;
			}
			String chargeType = newLineItem.Apttus_QPConfig__ChargeType__c;

			// create attribute key
				String newLineKey = lineNumber + ':' + productId + ':' + chargeType; 
			// save in map  
				newLineKey2IdMap.put(newLineKey, newLineItem.Id);

        }
		// create map of old line item ids to new line item ids
			Set<ID> oldLineItemIds = oldLineId2KeyMap.keySet();
			List<ID> newLineItemIds = new List<ID>();

			for (String oldLineItemId : oldLineItemIds)
			{      
				// get attribute key
				String attrKey = oldLineId2KeyMap.get(oldLineItemId);
				// lookup key in new line items map
				String newLineItemId = null;
				if(newLineKey2IdMap.containsKey(attrKey))
				{
					newLineItemId = newLineKey2IdMap.get(attrKey);
					newLineItemIds.add(newLineItemId);
					// associate old key with new one
					lineOldId2NewIdMap.put(oldLineItemId, newLineItemId);
				}		

			}

      // update reapprovals data by calling API in approvals package
     
		List<ID> oldContextObjIds = new List<ID>(oldLineItemIds);
		List<ID> newContextObjIds = newLineItemIds;
		
        system.debug(LoggingLevel.INFO,'sObjectType='+PROPOSAL_SOBJECT_TYPE);

        system.debug(LoggingLevel.INFO,'contextObjId='+quoteId);

        system.debug(LoggingLevel.INFO,'oldContextObjIds='+oldContextObjIds);

        system.debug(LoggingLevel.INFO,'newContextObjIds='+newContextObjIds);

        if (!oldContextObjIds.isEmpty() && !newContextObjIds.isEmpty() && oldContextObjIds.size() == newContextObjIds.size())
		{
            // get process instance associated with the old quote
			Apttus_Approval__ApprovalProcessInstance__c instanceSO = getProcessInstance(quoteId);
			system.debug(LoggingLevel.INFO,'instanceSO='+instanceSO);
			
            // call API to update reapproval data
            Boolean ok = Apttus_Approval.ApprovalsWebService.updateApprovalData(instanceSO.Id, PROPOSAL_SOBJECT_TYPE, quoteId, oldContextObjIds, newContextObjIds);
			
            system.debug(LoggingLevel.INFO,'Apttus_Approval.ApprovalsWebService.updateApprovalData='+ok);

        }
    }

/**
* Get process instance for the given proposal id
* @param proposalId
* @return process instance object
*/

	private static Apttus_Approval__ApprovalProcessInstance__c getProcessInstance(ID proposalId)
	{
		List<Apttus_Approval__ApprovalProcessInstance__c> instanceList = [select Id, Name, LastModifiedDate, LastModifiedById, LastActivityDate, CreatedDate, CreatedById, Apttus_Approval__Status__c, Apttus_Approval__StartTime__c, Apttus_Approval__ReassignmentEmailTemplate__c, Apttus_Approval__PrevProcessInstanceId__c, Apttus_Approval__NotifyOnlyEmailTemplate__c, Apttus_Approval__InstanceNumber__c, Apttus_Approval__EscalationEmailTemplate__c, Apttus_Approval__EndTime__c, Apttus_Approval__Data__c, Apttus_Approval__ConsolidationVersionNumber__c, Apttus_Approval__CancellationEmailTemplate__c, Apttus_Approval__BusinessObjectType__c, Apttus_Approval__BusinessObjectLink__c, Apttus_Approval__BusinessObjectId__c, Apttus_Approval__AssignmentEmailTemplate__c, Apttus_Approval__ApprovalProcessId__c From Apttus_Approval__ApprovalProcessInstance__c where Apttus_Approval__BusinessObjectId__c = :proposalId order by CreatedDate DESC limit 1]; 
		if ( ! nullOrEmpty(instanceList))
		{
			return instanceList[0];
        }
		
		return null;
    }
/**
* Checks if the given string value is null or empty.
* @param strValue the string to check
* @return <code>true</code> if the string value is null or empty, <code>false</code> otherwise
*/
	public static Boolean nullOrEmpty(String strValue)
	{ 
		// check if null or zero length string
		return (strValue == null || strValue.trim().length() == 0);
    }

/**
* Checks if the given list of objects is null or empty.
* @param objList the list of objects to check
* @return <code>true</code> if the list is null or empty, <code>false</code> otherwise
*/
	public static Boolean nullOrEmpty(List<Object> objList)
	{
		// check if null or empty
		return (objList == null || objList.isEmpty());
	}
}
CODE