ClickLink – a tool provided by FinancialForce and packaged with their other products – allows you to synchronize objects in Salesforce, helping you reduce the duplication of data and avoiding the lack of updating related objects. Yes, you could all do this in one or many triggers, but ClickLink is within the interface, so it is easier to add a custom field to be synchronized, and you don’t have to write lengthy test classes to deploy the solution. You will still have to write test classes since you must create as many triggers as there are objects to synchronize, but most of these triggers will only have one line calling to the ClickLink method that handles everything.
A little bit of background. I had a customer who has a multi-tier pricing structure:
- the list price provided by the supplier
- a multiplier provided by the supplier that would allow the client to calculate his cost from the list price
- then the client would define 3 profit margins to calculate prices for 3 different types of customer, these prices would be related one to another.
SCM provides 2 different objects that have prices on them: the Supplier Catalogue Item, which only has one field called ‘List Price’ and a related list of Catalogue Price Breaks, then we have the “Price List” object, which has a field called “Cost” and a related list of very configurable Prices (so these two last ones are the objects you want to use to specify cost and prices… but you still need the Supplier Catalogue Item to automate ordering process).
For ClickLink I had one source object, the Supplier Catalogue Item, and 2 levels of target objects, the Price List and its Prices related list. ClickLink can map both targets to the single source (scenario C in ClickLink documentation), but then I would have to specify a different “Target Record Type” (a field in ClickLink Mapping object) for each of the prices I would have added to the price list. Unfortunately, ClickLink does not allow to synchronize mappings with Target Record Type that are different from “Default”. So, I had to create a new custom object with a lookup (related list) to the Supplier Catalogue Item to map with the Prices of the Price List. In this new object, I added also a lookup to the Price Type object, which is a list of names for Customer Agreement (level of pricing), the profit margins (all of them, since in this case the prices were related to each other) and a formula to calculate the price. In the Supplier Catalogue Item itself, I added the multiplier and a formula to calculate the cost, and because SCM is using the Price List object’s Name field to do some exact match with the Item Master instead of using lookup field for this, I also created a formula to get the Name of the Item Master referenced by the Supplier Catalogue Item, to be able to push it as the Name for the Price List object.
Next up, configuring ClinkLink to synchronize these 4 objects. Before creating the rules, you still have 3 fields to add to each of the target objects(Price, Price List): a lookup to its source object, an “IsSyncing” checkbox, and a pick list or a text field to specify when synchronization will occur.
In this example, synchronization should always be active, so I added a picklist “Synchronization” with 2 values (Active, Inactive) in case the customer would like to turn it off, but it should not happen. A real use case of this synchronization pick list would be if you wanted to synchronize a sales invoice with a “in progress” and “review” statuses to time sheets, but not after the invoice has been set to “complete” status. I also find it useful to add lookups to the target objects in their related source object, but it is not mandatory.
When you added the 2 synchronization fields to each of the target object, you can go to the ClickLink Rules tab. You will do the mappings and relationships just like they were done in the example where we created a sales invoice in FFA from an opportunity in Salesforce, except you will add the synchronization fields in the rule objects, and specify which mapping object should be synchronized by enabling that Source Sync on the bottom of the mapping object (literal values that you would push there cannot be synchronized). The ID of the source object must be mapped and synchronized to its lookup field in the target object, and you would likely want to initialize IsSyncing to true, and Synchronization to Active (using “Literal” mappings). Also, make sure you map all the fields that are mandatory in the target objects.
Once your rules are set up for both parent and child levels, and you have added the relationship between them, instead of creating a VisualForce page and linking to it with a button, you will create triggers for each of the source and target objects. These triggers are very simple:
trigger PriceSync on SCMC__Price__c (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
ffirule.IntegrationRuleEngine.triggerHandler();
}
All you have to do here is to change the name and the sObject on which the trigger applies, and copy-paste. The only trigger that would likely be a little bit different is the trigger for the source object at parent level. In my case, I want any update to my source parent to also force an update to the child records, so that both the new cost and the new prices are pushed to Price List and Prices object when someone update the multiplier or the list price on the Supplier Catalogue Item. So this trigger was slightly modified to be this:
trigger SupplierCatalogueItemSync on SCMC__Supplier_Catalogue_Item__c (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
ffirule.IntegrationRuleEngine.triggerHandler();
if(Trigger.isUpdate && Trigger.isAfter){
for(List <ProfitMargins__c> margins:[SELECT Id FROM ProfitMargins__c WHERE CatalogueItem__c IN:Trigger.new]){
update margins;
}
}
}
The screenshot shows what the parent rule looks like when it is synchronized (the child rule is the same).