Examples & Use Cases
Set Master record in Merge
Basic Example Code
global class DefaultMergeGenericPlugin implements dupcheck.dc3Plugin.InterfaceMerge {
private static Set<String> implementedEvents = new Set<String>{ 'MERGE_SET_MASTER' };
global Boolean isAvailable(dupcheck.dc3Plugin.PluginEventType eventType) {
return implementedEvents.contains(eventType.name());
}
global Object execute(dupcheck.dc3Plugin.PluginEventType eventType, Object eventData) {
if (eventType.name() == 'MERGE_SET_MASTER') {
return mergeSetMaster((dupcheck.dc3PluginModel.MergeSetMasterInput) eventData);
}
return null;
}
// Basic implementation: By default, use the master record provided by the merge rules.
public dupcheck.dc3PluginModel.MergeSetMasterOutput mergeSetMaster(dupcheck.dc3PluginModel.MergeSetMasterInput input) {
dupcheck.dc3PluginModel.MergeSetMasterOutput output = new dupcheck.dc3PluginModel.MergeSetMasterOutput(input);
return output;
}
}
Example 1: Account with most Opportunities is Master
This example demonstrates how to override the default master record selection using the Generic Plugin interface (dupcheck.dc3PluginInterface
). In this scenario, instead of the standard merge rules, the plugin selects the Account record with the highest number of related Opportunities as the master record.
global class HighestOpportunityMergeGenericPlugin implements dupcheck.dc3PluginInterface {
// This plugin supports only the MERGE_SET_MASTER event.
private static Set<String> implementedEvents = new Set<String>{ 'MERGE_SET_MASTER' };
global Boolean isAvailable(dupcheck.dc3Plugin.PluginEventType eventType) {
return implementedEvents.contains(eventType.name());
}
global Object execute(dupcheck.dc3Plugin.PluginEventType eventType, Object eventData) {
switch on eventType {
when MERGE_SET_MASTER {
return mergeSetMaster((dupcheck.dc3PluginModel.MergeSetMasterInput) eventData);
}
when else {
return null;
}
}
}
// Custom logic: Select the master Account based on the highest number of related Opportunities.
public dupcheck.dc3PluginModel.MergeSetMasterOutput mergeSetMaster(dupcheck.dc3PluginModel.MergeSetMasterInput input) {
dupcheck.dc3PluginModel.MergeSetMasterOutput output = new dupcheck.dc3PluginModel.MergeSetMasterOutput(input);
// Process only for Account records (object prefix '001')
if (input.objectPrefix == '001') {
Set<Id> accountIds = new Set<Id>();
for (Sobject rec : input.objectDataList) {
accountIds.add(rec.Id);
}
// Query the count of related Opportunities for each candidate Account.
List<AggregateResult> aggResults = [
SELECT AccountId, COUNT(Id) cnt
FROM Opportunity
WHERE AccountId IN :accountIds
GROUP BY AccountId
];
// Build a map of AccountId to Opportunity count.
Map<Id, Integer> oppCountMap = new Map<Id, Integer>();
for (AggregateResult ar : aggResults) {
oppCountMap.put((Id) ar.get('AccountId'), (Integer) ar.get('cnt'));
}
// Determine the candidate with the highest Opportunity count.
Id selectedMasterId;
Integer highestCount = 0;
for (Sobject rec : input.objectDataList) {
Id accId = rec.Id;
Integer count = oppCountMap.containsKey(accId) ? oppCountMap.get(accId) : 0;
if (count > highestCount) {
highestCount = count;
selectedMasterId = accId;
}
}
// Override the master record ID if a candidate is found.
if (selectedMasterId != null) {
output.masterRecordId = selectedMasterId;
}
}
return output;
}
}
Example 2: Decision Tree Contact Master Plugin
This example demonstrates how to decide the master Contact record based on a decision tree. The logic is as follows:
- Select the candidate if its LeadSource equals "Phone Inquiry".
- If not, select the candidate if its LeadSource equals "Partner Referral".
- Otherwise, choose the candidate that was most recently modified.
global class DecisionTreeContactMasterGenericPlugin implements dupcheck.dc3PluginInterface {
// This plugin supports only the MERGE_SET_MASTER event.
private static Set<String> implementedEvents = new Set<String>{ 'MERGE_SET_MASTER' };
global Boolean isAvailable(dupcheck.dc3Plugin.PluginEventType eventType) {
return implementedEvents.contains(eventType.name());
}
global Object execute(dupcheck.dc3Plugin.PluginEventType eventType, Object eventData) {
switch on eventType {
when MERGE_SET_MASTER {
return mergeSetMaster((dupcheck.dc3PluginModel.MergeSetMasterInput) eventData);
}
when else {
return null;
}
}
}
public dupcheck.dc3PluginModel.MergeSetMasterOutput mergeSetMaster(dupcheck.dc3PluginModel.MergeSetMasterInput input) {
dupcheck.dc3PluginModel.MergeSetMasterOutput output = new dupcheck.dc3PluginModel.MergeSetMasterOutput(input);
// Process only for Contact records (object prefix '003')
if (input.objectPrefix == '003') {
List<Contact> candidates = new List<Contact>();
// Re-query each candidate to ensure complete field data.
for (SObject rec : input.objectDataList) {
candidates.add([SELECT Id, LeadSource, LastModifiedDate FROM Contact WHERE Id = :rec.Id LIMIT 1]);
}
Contact selectedMaster = null;
// 1. Pick master if LeadSource equals "Phone Inquiry"
for (Contact c : candidates) {
if (c.LeadSource != null && c.LeadSource.equalsIgnoreCase('Phone Inquiry')) {
selectedMaster = c;
break;
}
}
// 2. If no candidate from step 1, pick master if LeadSource equals "Partner Referral"
if (selectedMaster == null) {
for (Contact c : candidates) {
if (c.LeadSource != null && c.LeadSource.equalsIgnoreCase('Partner Referral')) {
selectedMaster = c;
break;
}
}
}
// 3. If still no candidate, select the candidate with the most recent LastModifiedDate.
if (selectedMaster == null && !candidates.isEmpty()) {
selectedMaster = candidates[0];
for (Contact c : candidates) {
if (c.LastModifiedDate > selectedMaster.LastModifiedDate) {
selectedMaster = c;
}
}
}
// Override the master record ID if a candidate is found.
if (selectedMaster != null) {
output.masterRecordId = selectedMaster.Id;
}
}
return output;
}
}
Example 3: Decide a master record based on a calculated score
This plugin determines the master record during a merge by scoring each candidate based on its related records. It awards points as follows:
- Related Entitlement: 1000 points
- Related Asset: 500 points
- Related Project: 200 points
- Related Opportunity: 100 points
- Related Case: 50 points
- Related Account Plan: 10 points
The plugin iterates over the records involved in the merge event, computes a total score for each, and selects the record with the highest score as the master. If two records have the same score, the newest record is chosen. This approach ensures that the record with the strongest business relationships is preserved as the master after a merge.
global class dc3GenericPluginHierarchy implements dupcheck.dc3PluginInterface {
private static Set<String> implementedEvents = new Set<String>{'MERGE_SET_MASTER'};
global Boolean isAvailable(dupcheck.dc3Plugin.PluginEventType eventType) {
return dc3GenericPluginHierarchy.implementedEvents.contains(eventType.name());
}
global Object execute(dupcheck.dc3Plugin.PluginEventType eventType, Object eventData) {
switch on eventType {
when MERGE_SET_MASTER {
return this.mergeSetMaster((dupcheck.dc3PluginModel.MergeSetMasterInput) eventData);
}
when else {
return null;
}
}
}
public dupcheck.dc3PluginModel.MergeSetMasterOutput mergeSetMaster(dupcheck.dc3PluginModel.MergeSetMasterInput input) {
dupcheck.dc3PluginModel.MergeSetMasterOutput output = new dupcheck.dc3PluginModel.MergeSetMasterOutput(input);
if (input.objectPrefix == '001') {
//Check if there are related Entitlement records for the records involved in the merge event
List<Entitlement> Ents = [SELECT AccountId FROM Entitlement WHERE AccountId IN: input.objectDataList];
//create a set of Account ids that have related Entitlement records
set<Id> EntIds = new set<Id>();
if(Ents.size() > 0){
for(Entitlement ent: Ents) {
EntIds.add(ent.AccountId );
}
}
//Check if there are related Asset records for the records involved in the merge event
List<Asset> Assets = [SELECT Id, Name, AccountId FROM Asset WHERE AccountId IN: input.objectDataList];
//create a set of Account ids that have related Asset records
set<Id> AsIds = new set<Id>();
if(Assets.size() > 0){
for(Asset asse: Assets) {
AsIds.add(asse.AccountId );
}
}
//Check if there are related Project records for the records involved in the merge event
List<Project__c> Projects = [SELECT Id, Name, Account__c FROM Project__c WHERE Account__c IN: input.objectDataList];
//create a set of Account ids that have related Project records
set<Id> ProIds = new set<Id>();
if(Projects.size() > 0){
for(Project__c pro: Projects) {
ProIds.add(pro.Account__c );
}
}
//Check if there are related Opportunity records for the records involved in the merge event
List<Opportunity> Opps = [SELECT Id, Name, AccountId FROM Opportunity WHERE AccountId IN: input.objectDataList];
//create a set of Account ids that have related Opportunity records
set<Id> OppIds = new set<Id>();
if(Opps.size() > 0){
for(Opportunity opp: Opps) {
OppIds.add(opp.AccountId );
}
}
//Check if there are related Case records for the records involved in the merge event
List<Case> Cases = [SELECT Id, AccountId FROM Case WHERE AccountId IN: input.objectDataList];
//create a set of Account ids that have related Opportunity records
set<Id> CasIds = new set<Id>();
if(Cases.size() > 0){
for(Case cas: Cases) {
CasIds.add(cas.AccountId );
}
}
//Check if there are related Account Plan records for the records involved in the merge event
List<Account_Plan__c> Acps = [SELECT Id, Account__c FROM Account_Plan__c WHERE Account__c IN: input.objectDataList];
//create a set of Account ids that have related Account Plan records
set<Id> AcpIds = new set<Id>();
if(Acps.size() > 0){
for(Account_Plan__c acp: Acps) {
AcpIds.add(acp.Account__c );
}
}
//keep track of highest record value and latest created date
Integer MasterValue = 0;
DateTime dt = DateTime.newInstance(2000, 01, 20, 22, 0, 0);
for (Sobject acc : input.objectDataList) {
Integer RecordValue = 0;
Account accData = (Account) acc;
//check if the account has an entitlement record, if yes gain 1000 points
if(Ents.size() > 0){
if(EntIds.contains(accData.Id)){
RecordValue = RecordValue+1000;
}
}
//check if the account has an asset record, if yes gain 500 points
if(Assets.size() > 0){
if(AsIds.contains(accData.Id)){
RecordValue = RecordValue+500;
}
}
//check if the account has an project record, if yes gain 200 points
if(Projects.size() > 0){
if(ProIds.contains(accData.Id)){
RecordValue = RecordValue+200;
}
}
//check if the account has an opportunity record, if yes gain 100 points
if(Opps.size() > 0){
if(OppIds.contains(accData.Id)){
RecordValue = RecordValue+100;
}
}
//check if the account has an Case record, if yes gain 50 points
if(Cases.size() > 0){
if(CasIds.contains(accData.Id)){
RecordValue = RecordValue+50;
}
}
//check if the account has an Case record, if yes gain 50 points
if(Acps.size() > 0){
if(AcpIds.contains(accData.Id)){
RecordValue = RecordValue+10;
}
}
// Change master record if current record scores more points
if(RecordValue > MasterValue){
MasterValue = RecordValue;
output.masterRecordId = accData.Id;
dt = accData.CreatedDate;
}
// Change master record if current record hase same score, but later created date
else if(RecordValue == MasterValue & accData.CreatedDate > dt ){
output.masterRecordId = accData.Id;
dt = accData.CreatedDate;
}
}
}
return output;
}
}
Updated 17 days ago