function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Michael Hedrick 2Michael Hedrick 2 

Duplicate Insert trigger works but...

Hello,
I have an Apex Trigger that I needs to perform the following:
  • prevent duplicate lead from being inserted during an import
  • add task to existing Lead that was found within SF
The trigger belows does meet my requiremtns except that it also adds a task to the newly inserted Lead.  The Newly inserted Lead does not exsit in Salesforce so I am not sure why a task is being added.
trigger LeadPreventDuplicate on Lead (after insert,after update) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

      for (Lead lead : System.Trigger.new) 
      { 

       if ((lead.Email != null) && (System.Trigger.isInsert ||
            (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
            {
              leadMap.put(lead.Email, lead);
            }
      }

      List<task> addtask=New List<task>();
     
      for (Lead lead : [SELECT Email FROM Lead WHERE Email IN :leadMap.KeySet()]) 
      {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
        WhoID =lead.id, 
        Status = 'Active',
        Subject = 'Test Task',
        ActivityDate = system.today()));
      
       } 
       insert addtask; 
      
       Lead[] dupes = new Lead[0];
          Set<String> email = new Set<String>(), dupEmail = new Set<String>();
              for(Lead record: Trigger.new)
              email.add(record.email);
              email.remove(null);
              for(Lead record: [SELECT Id, Email FROM Lead WHERE Email IN :email])
                    if(!Trigger.newMap.containsKey(record.id))
                    dupEmail.add(record.Email);
              for(Lead record: Trigger.new)
        if(dupEmail.contains(record.Email))
            dupes.add(record.clone(true));
        else
            dupEmail.add(record.Email);
    delete dupes;
}

Thanks for the assistance.
M
 
Best Answer chosen by Michael Hedrick 2
Abdul KhatriAbdul Khatri
Please try with this one
 
trigger LeadPreventDuplicate on Lead (after insert) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

    for (Lead lead :[SELECT Id, Email FROM Lead WHERE Id = :Trigger.new]) 
    { 
        if ((lead.Email != null) && (System.Trigger.isInsert || (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
        {
            leadMap.put(lead.Email, lead);
        }
    }
    
    if(leadMap.isEmpty()) return;

    //For Update
    List<Lead> leadToUpdateList = new List<Lead>();  
    Map<String, Integer> emailCountMap = new Map<String, Integer>();

    AggregateResult[] groupedResults = [SELECT Email, Count(Id) FROM Lead WHERE Email IN :leadMap.keySet() GROUP BY Email];
    for (AggregateResult ar : groupedResults)  
   {   
        
        String email = String.valueOf(ar.get('Email'));
        Integer count = Integer.valueOf(ar.get('expr0'));
        
        emailCountMap.put(email , count );
        
        if(count == 1) continue;
      
        //For Update
        Lead leadToUpdate = new Lead(Id = leadMap.get(email).Id);
        leadToUpdate.Duplicate_Lead__c= true;

        leadToUpdateList.add(leadToUpdate);
    }       

    //For Update
    Database.update(leadToUpdateList);
                             
    List<task> addtask=New List<task>();
    
    //For Update
    for (Lead lead : [SELECT Email FROM Lead WHERE (Duplicate_Lead__c= false OR Duplicate_Lead__c = null) AND Email IN :leadMap.KeySet()]) 
    
    {

        if(emailCountMap.get(lead.Email) == 1) continue;

        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Existing Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask; 

 }

Here is the test class
 
@isTest
public class LeadPreventDuplicate_Test {

    static testMethod void  single_Lead_must_not_create_activity_test(){

		insert new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test');
        
        Lead lead = [SELECT Id, Duplicate_Lead__c FROM Lead LIMIT 1];
        
        List<Task> taskList = [SELECT Id FROM Task];
        
        system.assert(lead.Duplicate_Lead__c == false);
        
        system.assert(taskList.size() == 0);

    }    
    
    static testMethod void  duplicate_test(){
        
        List<Lead> leadToInsertList = new List<Lead> {
            new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test'),
			new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test')
        };
            
        Database.insert(leadToInsertList);

        List<Lead> leadList = [SELECT Duplicate_Lead__c FROM Lead WHERE Id = :leadToInsertList AND Duplicate_Lead__c = false];
        
        List<Task> taskList = [SELECT Id FROM Task];

        system.assert(taskList.size() == 1);        
        
    }
}

 

All Answers

Abdul KhatriAbdul Khatri
As per my understanding that is what you are doing creating task for newly inserted Lead and removing the old duplicate lead. This is the code that is doing it
 
List<task> addtask=New List<task>();
    
    for (Lead lead : [SELECT Email FROM Lead WHERE Email IN :leadMap.KeySet()]) 
    {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask;

what is the purpose of this code. To me it looks like it's not needed
 
for(Lead record: Trigger.new) {
        if(dupEmail.contains(record.Email))
            dupes.add(record.clone(true));
        else
            dupEmail.add(record.Email);
    }

You can do something like this
 
List<Lead> dupLeadsToDelete = new List<Lead>();
    email.remove(null);
    for(Lead record: [SELECT Id, Email FROM Lead WHERE Email IN :email]) {
        if(!Trigger.newMap.containsKey(record.id))
            dupLeadsToDelete.add(record);
    }
    
    delete dupLeadsToDelete;

Let me know if this help
Michael Hedrick 2Michael Hedrick 2
Hello Abdul,
Thanks for the reply.  The task should be created and associated to existing lead within Salesforce.  NOT to the newly inserted  Lead.  The second half of the trigger is where I was trying to delete the duplicates that were being imported.  Instead I might just flag them as a duplicate(checkbox) and allow the user to delete them at a later date. That seems like a safer approach.

So for this portion of the triggerI was trying to just add a task to the existing Leads.
List<task> addtask=New List<task>();
    
    for (Lead lead : [SELECT Email FROM Lead WHERE Email IN :leadMap.KeySet()]) 
    {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask;

The reason I do not want to add the same task to the new leads is that it may be confusing to the end user if existing leads and the newly created leads have the same Activty.  How can I break up the above code to create a specific lead for existing Leads and a different Lead for the newly inserted Leads. 
Thank you for the feedback.
Abdul KhatriAbdul Khatri
If I understood correctly you wanted to tag the new inserted lead(s) as duplicate if the lead with that email already exists. Is this Correct

Regarding the task, I understand you wanted to add the task for the existing lead and not for the new lead but my question is
  • Why you wanted to add a new task every time you insert a duplicate?
  • Can't we check if the task already exist for the existing lead not to create another?
  • What could be filteration to find that task?
Michael Hedrick 2Michael Hedrick 2
Hello Abdul,
We utilize Task to record customer engagements.  So if the Lead exist we need to record that tghe customer performed another engagement and not create another Lead with the same email address.  
Thanks,
M
 
Michael Hedrick 2Michael Hedrick 2
Abdul,
I mistyped the above information.  Here is what I was trying to say.
The reason I do not want to add the same task to the new leads is that it may be confusing to the end user if existing leads and the newly created leads have the same Activty message.  How can I break up the above code to create a specific activty for existing Leads and a different activty for the newly inserted Leads. 
Thanks

 
Abdul KhatriAbdul Khatri
I have tweaked you original code. It is for both cases Delete the new Lead or Update (commented) the new Lead, whatever you like.

it will only create a task against the existing lead.

Let me know if it will work for you or not.
 
trigger LeadPreventDuplicate on Lead (after insert,after update) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

    for (Lead lead :[SELECT Id, Email FROM Lead WHERE Id = :Trigger.new]) 
    { 
        if ((lead.Email != null) && (System.Trigger.isInsert ||
                                     (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
        {
            leadMap.put(lead.Email, lead);
        }
    }
    
    if(leadMap.isEmpty()) return;

    //For Update
    //List<Lead> leadToUpdateList = new List<Lead>();  
	List<Lead> leadToDeleteList = new List<Lead>();    
    AggregateResult[] groupedResults = [SELECT Email, Count(Id) 
                                        FROM Lead
          								WHERE Email IN :leadMap.keySet()
          								GROUP BY Email
		  								HAVING COUNT(Id) > 1];
    for (AggregateResult ar : groupedResults)  {
        
		leadToDeleteList.add(leadMap.get(String.valueOf(ar.get('Email'))));
        
        //For Update
        //Lead leadToUpdate = new Lead(Id = leadMap.get(String.valueOf(ar.get('Email'))).Id);
        //leadToUpdate.DupcheckBox = true;
	}	    

	Database.delete(leadToDeleteList);
    //For Update
    //Database.update(leadToUpdateList);
                             
    List<task> addtask=New List<task>();
    
    //For Update
	//for (Lead lead : [SELECT Email FROM Lead WHERE Email IN :leadMap.KeySet()] AND DupcheckBox = false) 
    for (Lead lead : [SELECT Email FROM Lead WHERE Email IN :leadMap.KeySet()]) 
    {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask; 
}

 
Michael Hedrick 2Michael Hedrick 2
Hello Abdul,
Thank you for the reply and help.



I am going to have to thoroughlt read threw the code to make sure I understand what each line of code is doing.  
The line of code
Lead leadToUpdate = new Lead(Id = leadMap.get(String.valueOf(ar.get('Email'))).Id);
leadToUpdate.DupcheckBox = true;
Will allow the duplicate lead to be created and the checkbox set to true?

The 2 for loops at the bottom of the trigger is for adding an activty to an existing Lead within Salesforce correct?  The only difference is that the commented out one has an additional criteria.  Correct?

Thanks for all your help.
M
Abdul KhatriAbdul Khatri
Exactly, you are all correct.
Abdul KhatriAbdul Khatri
How it is looking?
Michael Hedrick 2Michael Hedrick 2
Abdul,
Apologies on the delayed response.  I was pulled to another project.  I tested the above code and this is what I am seeing.
  • Activity are being inserted on new and exsiting Leads.
    • The activty should only be created on the existing Lead that was found.
  • Duplicate Lead checkbox is not being updated

Here is the Apex Class. It was determined to be safer to not delete the duplicate but to flag them as a duplicate.
trigger LeadPreventDuplicate on Lead (after insert) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

    for (Lead lead :[SELECT Id, Email FROM Lead WHERE Id = :Trigger.new]) 
    { 
        if ((lead.Email != null) && (System.Trigger.isInsert || (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
        {
            leadMap.put(lead.Email, lead);
        }
    }
    
    if(leadMap.isEmpty()) return;

    //For Update
    List<Lead> leadToUpdateList = new List<Lead>();  
    AggregateResult[] groupedResults = [SELECT Email, Count(Id) FROM Lead WHERE Email IN :leadMap.keySet() GROUP BY Email HAVING COUNT(Id) > 1];
    for (AggregateResult ar : groupedResults)  
   {         
        //For Update
        Lead leadToUpdate = new Lead(Id = leadMap.get(String.valueOf(ar.get('Email'))).Id);
        leadToUpdate.Duplicate_Lead__c= true;
    }       

    //For Update
    Database.update(leadToUpdateList);
                             
    List<task> addtask=New List<task>();
    
    //For Update
    for (Lead lead : [SELECT Email FROM Lead WHERE Duplicate_Lead__c= false AND Email IN :leadMap.KeySet()]) 
    
    {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Existing Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask; 
    
    }
Thanks for the help and your time,
M
 
Abdul KhatriAbdul Khatri
Sorry seems like there was one line missing so I added
leadToUpdateList.add(leadToUpdate);
Please try now
 
trigger LeadPreventDuplicate on Lead (after insert) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

    for (Lead lead :[SELECT Id, Email FROM Lead WHERE Id = :Trigger.new]) 
    { 
        if ((lead.Email != null) && (System.Trigger.isInsert || (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
        {
            leadMap.put(lead.Email, lead);
        }
    }
    
    if(leadMap.isEmpty()) return;

    //For Update
    List<Lead> leadToUpdateList = new List<Lead>();  
    AggregateResult[] groupedResults = [SELECT Email, Count(Id) FROM Lead WHERE Email IN :leadMap.keySet() GROUP BY Email HAVING COUNT(Id) > 1];
    for (AggregateResult ar : groupedResults)  
   {         
        //For Update
        Lead leadToUpdate = new Lead(Id = leadMap.get(String.valueOf(ar.get('Email'))).Id);
        leadToUpdate.Duplicate_Lead__c= true;

        leadToUpdateList.add(leadToUpdate);
    }       

    //For Update
    Database.update(leadToUpdateList);
                             
    List<task> addtask=New List<task>();
    
    //For Update
    for (Lead lead : [SELECT Email FROM Lead WHERE Duplicate_Lead__c= false AND Email IN :leadMap.KeySet()]) 
    
    {
        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Existing Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask; 
    
    }

 
Michael Hedrick 2Michael Hedrick 2
Hey Abdul,
This is so close.  Only remaining issue is that for some reason the activity is being added to the first inserted lead eventhough it is not a duplicate.
The new lead is not in the leadMap.KeySet so I am not sure why the new non duplicate lead is having an activty added to it.
Thanks for staying with this Abdul.

M


 
Michael Hedrick 2Michael Hedrick 2
Hey Abdul, 
should I also be filtering out Leads where the checkbox is set to true?  These records will never have abn activty added to them.
Abdul KhatriAbdul Khatri
so you don't need an activity if the lead is solo, I mean if there is no duplicate lead. 
Michael Hedrick 2Michael Hedrick 2
Yes I think we are saying the same thing.
Here is an example:
A lead with an email address of test@gmail.com is imported into Salesofrce on 01012019
This email address does not exist so the lead is created without an activty.

On 01032019 a lead is imported with an email address of test@gmail.com.  This lead is created and flagged as duplicate.
The lead with the email address test@gmail.com that was created on 010102019 will have an activty attached.

In a perfect scenerio the first lead would have an activty stating that the first customer activty was created on when teh lead was first imported.  Then all following activties would have a different message stating that a duplciate with the same email address was submitted into salesforce.

But right now if we can just the first scenerio working that would be an great.

M
Abdul KhatriAbdul Khatri
Please try with this one
 
trigger LeadPreventDuplicate on Lead (after insert) {

    Map<String, Lead> leadMap = new Map<String, Lead>();

    for (Lead lead :[SELECT Id, Email FROM Lead WHERE Id = :Trigger.new]) 
    { 
        if ((lead.Email != null) && (System.Trigger.isInsert || (lead.Email != System.Trigger.oldMap.get(lead.Id).Email))) 
        {
            leadMap.put(lead.Email, lead);
        }
    }
    
    if(leadMap.isEmpty()) return;

    //For Update
    List<Lead> leadToUpdateList = new List<Lead>();  
    Map<String, Integer> emailCountMap = new Map<String, Integer>();

    AggregateResult[] groupedResults = [SELECT Email, Count(Id) FROM Lead WHERE Email IN :leadMap.keySet() GROUP BY Email];
    for (AggregateResult ar : groupedResults)  
   {   
        
        String email = String.valueOf(ar.get('Email'));
        Integer count = Integer.valueOf(ar.get('expr0'));
        
        emailCountMap.put(email , count );
        
        if(count == 1) continue;
      
        //For Update
        Lead leadToUpdate = new Lead(Id = leadMap.get(email).Id);
        leadToUpdate.Duplicate_Lead__c= true;

        leadToUpdateList.add(leadToUpdate);
    }       

    //For Update
    Database.update(leadToUpdateList);
                             
    List<task> addtask=New List<task>();
    
    //For Update
    for (Lead lead : [SELECT Email FROM Lead WHERE (Duplicate_Lead__c= false OR Duplicate_Lead__c = null) AND Email IN :leadMap.KeySet()]) 
    
    {

        if(emailCountMap.get(lead.Email) == 1) continue;

        Lead newLead = leadMap.get(lead.Email);
        addtask.add(new Task(
            WhoID =lead.id, 
            Status = 'Active',
            Subject = 'Test Existing Task',
            ActivityDate = system.today()));
        
    } 
    insert addtask; 

 }

Here is the test class
 
@isTest
public class LeadPreventDuplicate_Test {

    static testMethod void  single_Lead_must_not_create_activity_test(){

		insert new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test');
        
        Lead lead = [SELECT Id, Duplicate_Lead__c FROM Lead LIMIT 1];
        
        List<Task> taskList = [SELECT Id FROM Task];
        
        system.assert(lead.Duplicate_Lead__c == false);
        
        system.assert(taskList.size() == 0);

    }    
    
    static testMethod void  duplicate_test(){
        
        List<Lead> leadToInsertList = new List<Lead> {
            new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test'),
			new Lead ( LastName = 'Test', Email = 'test@test.com', Company = 'Test')
        };
            
        Database.insert(leadToInsertList);

        List<Lead> leadList = [SELECT Duplicate_Lead__c FROM Lead WHERE Id = :leadToInsertList AND Duplicate_Lead__c = false];
        
        List<Task> taskList = [SELECT Id FROM Task];

        system.assert(taskList.size() == 1);        
        
    }
}

 
This was selected as the best answer
Abdul KhatriAbdul Khatri
It worked?
Michael Hedrick 2Michael Hedrick 2
Abdul,
You nailed it, thank you very much.  If you have time, would you put some comments on the trigger? This way I and others can fully understand the logic you used to resolve this problem. 

For example in line
if(emailCountMap.get(lead.Email) == 1)
Could I insert a specific task for this Lead sinc ethis is the first non duplicate lead?

Should all of the queries for the Lead object include where DupcheckBox = false)

Thanks again for all your help.

Cheers,
M
Abdul KhatriAbdul Khatri
No problem.

I personally don't like putting comments in the code, to me it muggy the code. Normally I design my code in parts by refactoring the code that takes time therefore I can't do that here.

As people look for quick solution here and developers here wanted to be the first to provide them so I do the same.

but I guess I divided my code in different session so it should be that hard to understand
  • First , collected information to be process 
  • Second, How the data is in the system and updating lead flag accordingly only for the one > 2
  • Third, creating task only for dups

I do not understand this part of yours, please clarify.

Could I insert a specific task for this Lead sinc ethis is the first non duplicate lead?

 
Michael Hedrick 2Michael Hedrick 2
Hello Abdul,
The business model that we use is that we record Consumer actions as Activty records on a Lead record.  So the Lead record is basically a shell that housesd all of the csutomer engagements(Activity records).

So if we go back to my prior example
A lead with an email address of test@gmail.com is imported into Salesofrce on 01012019
This email address does not exist so the lead is created and an activcty is created to specificy this was the customers first engagement

On 01032019 a lead is imported with an email address of test@gmail.com.  This lead is created and flagged as duplicate.
The lead with the email address test@gmail.com that was created on 010102019 will have an activty attached stating this was followup engagement.

And theoritacally I could now assign a task to a user when the lead count record meets a certain number? 
The trigger picks up that there 4 duplicate leads this could be our target threshold to send the inforamtion to our inside sales team since the customer has engages with a certain number of time.

This code is definitly opening up some possibilities for me to automate of business processes.  Thank you for all your help.

M  

 
Abdul KhatriAbdul Khatri
So if I understood correctly, you are saying that if I get fourth lead from the same customer, this will result in creating a third task as we are not creating a task for the very first lead. This task you need to assign to the Insider Sales Team. If this is correct, here are my few questions.
  • What is the process of task assignment?
  • To whom all previous task are getting assigned?
  • Do we need to reassign the previous tasks too?
Michael Hedrick 2Michael Hedrick 2
Hey Abdul,
Hope you had a good wekend. Here are my responses to your questions
  • So if I understood correctly, you are saying that if I get fourth lead from the same customer, this will result in creating a third task as we are not creating a task for the very first lead. This task you need to assign to the Insider Sales Team.
    • Correct.  Right now I have different departments creating Leads in Salesforce so I was thinking of using the Process builder to insert the first task based on the Lead record type and user profile ID.  
  • What is the process of task assignment?
    • By default most Leads will have a task associated to them when they are inserted via a webservice.  This process is to cover leads being inserted or created within Salesforce 
  • To whom all previous task are getting assigned?
    • All task are assigned to the Lead owner which 'should' be the Inside Sales team
  • Do we need to reassign the previous tasks too?
    • If the task is not assigned to Lead owner then yes,

 
Abdul KhatriAbdul Khatri
Thanks for the Response.

I asked this question specific to Task Assignment because in the above code I don't see you are any line that says as an example. So curios to know where the assignment is happening for all these task are getting created.
 
task.AssignedTo = lead.OwnerId;