This section comprises the sample callback class that enables you to apply an appropriate tax to a cart line item.

Before you define the tax callback ensure that you have set the following:

  • Go to the product price list item, click Edit > Tax & Billing and select the Taxable? checkbox. Also, ensure that the Tax Inclusive? checkbox is deselected. If it is selected, the product price specified includes the tax amount.
  • From the Tax & Billing tab, specify the tax code applicable for a product using a lookup. The tax code maps to a code in an external system where various taxes, tax charges, tax types are mapped against a tax code.
  • If a tax is applicable based on the billing or shipping address of the account, ensure that the account associated with the proposal has both specified.

The sample callback class comprises the following objects:


Data Object - Apttus_Config2.TaxInput
FieldTypeDescription
TaxCodeStringTax code for the line item as inherited from the Price list item or overridden at the line item level.
TaxAddressAddressTax Address.

Address as obtained for the line item based on precedence hierarchy specified. For example, Line Item  Location ==> Line Item Ship To ==> Line Item Bill To ==> Cart Header Ship To ==> Cart Header Bill To ==> Cart Header Sold to

TaxableAmountDecimalNet Price from the Line Item in case the tax needs to be calculated on the Net Price. In case the tax needs to be calculated based on List or Base Price then the total amount calculated based on list or base price needs to be used from the line item to calculate tax.
ItemSObjectApttus_Config2__LineItem__c. This is the reference to the cart line items. Implementation can use this cart line item to get any additional custom fields that might be needed to calculate tax.
HandbackObjectAny Apex Object passed by the caller and passed back to the caller in the result. Handback is used only in case when the tax needs to be calculated for an object other than Cart line item e.g. Billing Schedule line items. For calculating tax for cart line items, there is no need to pass the Handback object. It can be blank. For calculating the tax for object other than line items, "Item" field will be blank and the actual object will be passed as handback object to identify object for which tax is calculated.



Data Object - Apttus_Config2.CustomClass.TaxResult
FieldTypeDescription
TaxAmountDecimalThis is the total amount for the line item. This is sum of the breakup tax amounts for the line item. Line item is identified by the sequence in which the tax result is added. This needs to be calculated and populated by the implementation.
TaxBreakupsList<Apttus_Config2__TaxBreakup>Tax breakup provide the different components of the tax for a given line item. This needs to be implemented and provided by the implementation. Tax breakup has structure specified below.
HandbackObjectAny Apex Object passed by the calling class and passed back to the calling class in the result.

Handback is used only in case when the tax needs to be calculated for an object other than Cart line item e.g. Billing Schedule line items.

  • For calculating tax for cart line items, there is no need to pass the Handback object. It can be blank

  • For calculating the tax for object other than line items, "Item" field will be blank and the actual object will be passed as handback object to identify object for which tax is calculated.



Data Object - Apttus_Config2__TaxBreakup
FieldTypeDescription
TaxTypeStringType of tax to be applied. For example, sales, custom, excise
TaxRateDecimalTax percentage to be applied
TaxAppliesToStringThe field on which the tax is applied to. For example, net price.
TaxAmountDecimalThe tax amount calculated based on the formulae defined in the callback.
BreakupTypeStringIf you specify the breakup type as Detail, then the quote or order line items show the detailed tax break up for a cart line item.



Tax Breakup Type Example
Breakup TypeTax TypeTax RateTax Applies toTax Amount
DetailState Tax10Net Price100
DetailCity Tax1Net Price10
Total


110



Data Object - Apttus_Config2. CustomClass.Address
FieldType
StreetString
CityString
StateString
CountyString
PostalCodeString
CountryString


Once you have set a Tax Code for each price list item, create a Tax Callback class and specify the name of the callback class in Custom Settings > Config Custom Classes > (Edit) Custom Classes > Tax Callback Class.

In the sample callback class below, we fetch and create a list of all the products added to the cart. Then we fetch the tax charges applicable for a product using an SOQL query. If a corresponding tax code and a valid tax charge exists for a product in the order or quote line item, the total tax amount for a product is calculated using the formula- taxAmount += (taxRate != null ? (taxRate * input.TaxableAmount) / 100 : 0). After the total tax on a product is calculated, you can list the tax break up based on Tax types applied for each of the order or quote line items. The sample callback lists the parameters applicable for a tax break up. If you want to apply tax to shipping charges as well, you can capture shipping amount for each line item in a custom field and use the total amount (Net Price + Shipping Amount) from the line item to calculate tax. In this case shipping should be calculated first and then tax.

In the sample callback class, tax is calculated using hardcoded rates. For actual implementations, tax rates and tax amounts are fetched from external Tax calculation engines such as Avalara and Vertex to calculate tax. 


/**
 *  Apttus Config & Pricing
 *  QATaxCallBack
 *   
 *  @2013-2014 Apttus Inc. All rights reserved.
 */
global with sharing class QATaxCallBack implements Apttus_Config2.CustomClass.ITaxCallback2 {
    
    /**
     * Callback invoked to compute tax based on the given input
     * @param input the tax input 
     * @return the tax result
     */
    global Apttus_Config2.CustomClass.TaxResult computeTax(Apttus_Config2.CustomClass.TaxInput input) {
      // Compute Tax
      system.debug('Entering into computeTax');
      List<Apttus_Config2.CustomClass.TaxResult> results = computeTaxMultiple(new Apttus_Config2.CustomClass.TaxInput[]{input}); 
      return (!results.isEmpty() ? results[0] : new Apttus_Config2.CustomClass.TaxResult());  
    }
    
    /**
     * Callback invoked to compute tax based on the given list of inputs
     * @param inputs the list of tax inputs
     * @return the list of tax results
     */
    global List<Apttus_Config2.CustomClass.TaxResult> computeTaxMultiple(List<Apttus_Config2.CustomClass.TaxInput> inputs) {
      
        List<Apttus_Config2.CustomClass.TaxResult> results = new List<Apttus_Config2.CustomClass.TaxResult>();
     
        for (Apttus_Config2.CustomClass.TaxInput input : inputs) {
        
            Decimal taxAmount = 0;
        
            Apttus_Config2.CustomClass.TaxResult result = new Apttus_Config2.CustomClass.TaxResult();
            
            List<Apttus_Config2__TaxBreakup__c> taxBreakUps = new List<Apttus_Config2__TaxBreakup__c>();
            
            // Add the handback object to correlate the result with the input
            result.Handback = input.Handback;
            
            // Compute tax based on tax code and tax address

            // Tax Code is required
            if (input.TaxCode == null || input.TaxCode.trim().length() == 0 || input.TaxableAmount == null || input.TaxableAmount == 0) {
              
              // Tax Amount
              result.TaxAmount = 0;
            } else {
              
                List<QA_Tax_Rate__c> accountTaxRates = new List<QA_Tax_Rate__c>();
                
                SObject sObj = input.Item;
                Id taxCodeId = (Id) sObj.get('Apttus_Config2__TaxCodeId__c');
                
                accountTaxRates =  [SELECT Id, Name, Tax_Applies_To__c, Tax_Rate__c, Tax_Type__c 
                FROM QA_Tax_Rate__c
                WHERE Tax_Code__c =:  taxCodeId];
                
                for(QA_Tax_Rate__c accountTaxRate : accountTaxRates) {
                
                    Decimal taxRate = accountTaxRate.Tax_Rate__c;
                    String taxAppliesTo = accountTaxRate.Tax_Applies_To__c;
                    String taxType = accountTaxRate.Tax_Type__c;
                    
                    Apttus_Config2.CustomClass.Address addr = input.TaxAddress;
                    
                    // Calculate Tax Amount
                    taxAmount += (taxRate != null ? (taxRate * input.TaxableAmount) / 100 : 0);
                    
                    // Calculate Tax BreakUps
                    Apttus_Config2__TaxBreakup__c taxBreakUp = new Apttus_Config2__TaxBreakup__c();
                    taxBreakUp.Apttus_Config2__TaxType__c = taxType;
                    taxBreakUp.Apttus_Config2__TaxRate__c = taxRate;
                    taxBreakUp.Apttus_Config2__TaxAppliesTo__c = taxAppliesTo;
                    taxBreakUp.Apttus_Config2__TaxAmount__c = taxRate * input.TaxableAmount / 100;
                    taxBreakUp.Apttus_Config2__BreakupType__c = 'Detail';
                    
                    taxBreakUps.add(taxBreakUp);
                }
                               
                
                result.TaxBreakups = taxBreakUps;
                result.TaxAmount = taxAmount;
            }
            results.add(result);
        }
        return results;
    }
}
CODE