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
Chad MoutesChad Moutes 

Apex Trigger to create Opportunity Contact Role based on Contact Lookup field

Hey all,

I have created the following Apex trigger that will create, update and delete Opportunity Contact Roles based on a Contact Lookup field placed on the Opportunity. Everything works great currently. I am just trying to figure out one final scenario. If John Doe already has a Contact Role but is not the Primary Contact Role and I want him to be. I want to be able to change my look up field to him and then have that check him as the primary. Currently it just creates a new one and checks them both as primary. So what I need to do is check the current Contact Roles and if there is already one with the same name as in the Lookup field then just check that one as primary, but if there isn't then create a new one. Below is the code. Please let me know if you need further description.

Thanks,
 
trigger CreateContactRole on Opportunity (after insert, after update) {
    
    List<OpportunityContactRole> newContactRoleList = new List<OpportunityContactRole>();
    List<OpportunityContactRole> oldContactRoleList = new List<OpportunityContactRole>();
    Set<Id> OppId = new Set<Id>();
    sET<Id> ContactId = new Set<Id>();
    
    if(Trigger.isInsert) {
        for(Opportunity opp : Trigger.new) {
          if(opp.Primary_Contact__c != null) {
              //Creating new Contact Role
              newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
          }
      }
    }
    
    if(Trigger.isUpdate) {      
      for(Opportunity opp : Trigger.new) {
          if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c == null) {
                //Creating new Contact Role
              newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
          }
            else if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
                //Create New Contact Role make new CR Primary over the old CR
                Opportunity OldOpp = Trigger.oldMap.get(opp.Id);
                OppId.add(OldOpp.id);
                ContactId.add(OldOpp.Primary_Contact__c);
                newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
            }
          else if(opp.Primary_Contact__c == null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
                Opportunity OldOpp = Trigger.oldMap.get(opp.Id);
                OppId.add(OldOpp.id);
                ContactId.add(OldOpp.Primary_Contact__c);
                try {
                //Deleting old Contact Roles
                if(oldContactRoleList.size()>0) delete oldContactRoleList;
                }
                catch(Exception e) {
                    System.debug(e);
                    trigger.new[0].addError('An error has occurred. Please contact your system administrator.');
                }
          }
      }
    }
    
    try {
        //inserting new contact roles
        if(newContactRoleList.size()>0)insert newContactRoleList;
        
        //Selecting old Contact Roles
        if(OppId.size()>0) oldContactRoleList = [Select Id from OpportunityContactRole where ContactId in : ContactId and OpportunityId in : OppId];        
        
    }
    catch(Exception e) {
        System.debug(e);
        trigger.new[0].addError('An error has occurred. Please contact your system administrator.');
    }
}


 
Anupama SamantroyAnupama Samantroy
Hi Chad,

Please use the below code.
trigger CreateContactRole on Opportunity (after insert, after update) {
    
    List<OpportunityContactRole> newContactRoleList = new List<OpportunityContactRole>();
    List<OpportunityContactRole> oldContactRoleList = new List<OpportunityContactRole>();
    Set<Id> OppId = new Set<Id>();
    sET<Id> ContactId = new Set<Id>();
    
    if(Trigger.isInsert) {
        for(Opportunity opp : Trigger.new) {
          if(opp.Primary_Contact__c != null) {
              //Creating new Contact Role
              newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
          }
      }
    }
    List<Opportunity> lstopp = [Select Id, Primary_Contact__c ,(Select id, name,IsPrimary from OpportunityContactRoles ) from Opportunity where iD in: Trigger.new ];
    if(Trigger.isUpdate) {      
		for(Opportunity opp : lstopp) {
			Boolean contactRoleFound= false;
			if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c == null) {
			  //Creating new Contact Role
			  newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
			}
			else if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
					for(OpportunityContactRole conrole: opp.OpportunityContactRoles){
							if(opp.Primary_Contact__c == conrole.Id && !conrole.IsPrimary){
									conrole.IsPrimary = true;
									newContactRoleList.add(conrole);
									contactRoleFound = true;
									break;
							}
					}
					//if no contact role found then create new
					if(!contactRoleFound){}
						//Create New Contact Role make new CR Primary over the old CR
						Opportunity OldOpp = Trigger.oldMap.get(opp.Id);
						OppId.add(OldOpp.id);
						ContactId.add(OldOpp.Primary_Contact__c);
						newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
					}
				}
			else if(opp.Primary_Contact__c == null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
				Opportunity OldOpp = Trigger.oldMap.get(opp.Id);
				OppId.add(OldOpp.id);
				ContactId.add(OldOpp.Primary_Contact__c);
				try {
					//Deleting old Contact Roles
					if(oldContactRoleList.size()>0) delete oldContactRoleList;
				}
				catch(Exception e) {
					System.debug(e);
					trigger.new[0].addError('An error has occurred. Please contact your system administrator.');
				}
			}
		}
    }
    
    try {
        //inserting new contact roles
        if(newContactRoleList.size()>0)upsert newContactRoleList;
        
        //Selecting old Contact Roles
        if(OppId.size()>0) oldContactRoleList = [Select Id from OpportunityContactRole where ContactId in : ContactId and OpportunityId in : OppId];        
        
    }
    catch(Exception e) {
        System.debug(e);
        trigger.new[0].addError('An error has occurred. Please contact your system administrator.');
    }
}

Thanks
Anupama
Chad MoutesChad Moutes
Anupama,

Thanks for the response. I attempted to use your code and it is still not working properly.
Kelly KKelly K

Assuming not working properly means it's creating a duplicate contact role? If that's the case, you should consider switching to a map instead of using a list. This way you're not creating duplicates.

I would first build the map of contact roles to opportunities (so a map of a map). We use something like this to create contact roles for opportunities when the opp is created, moved to another account or closed. Something like this:

//Master map, includes all opportunities by contact by contact role: Mapping = Opportunity.Id { Contact.Id { OpportunityContactRole } }
		    map<Id, map<Id, OpportunityContactRole>> existingOpportunitiesContactRolesByContactId = new map<Id, map<Id, OpportunityContactRole>> ();

			//Section checks the opportunities for existing contact roles and adds it to the master map
		    for (Opportunity opportunity : [SELECT Id, AccountId, (SELECT Id, ContactId FROM OpportunityContactRoles) FROM Opportunity WHERE Id IN :opportunities.keySet()]) {	
		    	//Singluar map for one opportunity by contacts by contact roles
		    	map<Id, OpportunityContactRole> existingOpportunityContactRolesByContactId = new map<Id, OpportunityContactRole>();    	
		    	
		    	//Cycle through the opportunity contact roles for this opportunity and assign them to the map
	    		for (OpportunityContactRole opportunityContactRole : opportunity.OpportunityContactRoles)
	    			existingOpportunityContactRolesByContactId.put(opportunityContactRole.ContactId, opportunityContactRole);
		    		
		    	//Updates the master map by adding the opportunity and the corresponding opportunity roles.
		    	existingOpportunitiesContactRolesByContactId.put(opportunity.Id, existingOpportunityContactRolesByContactId);
		    }
 

Then when you're iterating through your opportunities to determine if the Primary_Contact__c has been updated, then you'll use something like this to pull the list of existing contact roles:
 

for (Opportunity opportunity : opportunities.values()) {
		    	//Pulls all exsiting contact roles from the map for this current opportunity
		    	map<Id, OpportunityContactRole> existingOpportunityContactRolesByContactId = existingOpportunitiesContactRolesByContactId.get(opportunity.Id);

Then something like this to update the existing one if it matches:

Id hasExistingOpportunityContactRole = null;

		        	if(existingOpportunityContactRolesByContactId.containsKey(contact.Id))
		        		hasExistingOpportunityContactRole = existingOpportunityContactRolesByContactId.get(contact.Id).Id;

					//updates master contact roles array for upsert
		            opportunityContactRoles.add( new OpportunityContactRole(Id = hasExistingOpportunityContactRole, Primary = true));

And then you'll upsert on the map like this

if(existingOpportunityContactRolesByContactId != null) {
			    	for(OpportunityContactRole contactRole : existingOpportunityContactRolesByContactId.values()) {

                        if(!contactIdsByAccount.contains(contactRole.ContactId)) 
			        		deleteOpportunityContactRoles.add(contactRole);	
			    	}
			    }
 


Hopefully I've given you enough examples to make something of it, but using the list is definitely the source of your woes because you're not updating the existing contact role.





 

Kelly KKelly K

sorry - wrong upsert statement listed above - use this for upsert:

//Upsert contact roles
			if(!opportunityContactRoles.isEmpty())
			    upsert opportunityContactRoles;
Chad MoutesChad Moutes
Kelly,

I have altered my code quite a bit since I made this post. Below is my new code. The same issue is still relevant though.
 
trigger CreateContactRole on Opportunity (after insert, after update) {
    
    List<OpportunityContactRole> newContactRoleList = new List<OpportunityContactRole>();
    List<OpportunityContactRole> oldContactRoleList = new List<OpportunityContactRole>();
    List<OpportunityContactRole> toDelete           = new List<OpportunityContactRole>();
    Set<Id> OppId = new Set<Id>();
    sET<Id> ConId = new Set<Id>();
    
    if(Trigger.isInsert) {
        for(Opportunity opp : Trigger.new) {
          if(opp.Primary_Contact__c != null) {
              //Creating new Contact Role
              newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
          }
        }
    }
    map<Id,Id>OppOldOCR = new map<Id,Id>();
  map<Id,Id>OppNewOCR = new map<Id,Id>();

  if(Trigger.isUpdate) {
    for(Opportunity opp : Trigger.new) {
          if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c == null) {
              //Creating new Contact Role
              newContactRoleList.add(new OpportunityContactRole(ContactId=opp.Primary_Contact__c,OpportunityId=opp.Id,Role='Decision Maker',IsPrimary=true));
          }
          else if(opp.Primary_Contact__c != null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
              //Create New Contact Role make new CR Primary over the old CR
              OppNewOCR.put(opp.Id,opp.Primary_Contact__c);
              OppOldOCR.put(opp.Id,Trigger.oldMap.get(opp.Id).Primary_Contact__c);
                toDelete = [SELECT Id, ContactId FROM OpportunityContactRole WHERE ContactId IN : ConId];
            }
          else if(opp.Primary_Contact__c == null && Trigger.oldMap.get(opp.Id).Primary_Contact__c != null) {
              OppOldOCR.put(opp.Id,Trigger.oldMap.get(opp.Id).Primary_Contact__c);
                
                ConId.addALL(OppOldOCR.values());
        toDelete = [SELECT Id, ContactId FROM OpportunityContactRole WHERE ContactId IN : ConId];
            }
      }

    for(Id oId:OppNewOCR.keyset()) {
          newContactRoleList.add(new OpportunityContactRole(ContactId=OppNewOCR.get(oId),OpportunityId=oId,Role='Decision Maker',IsPrimary=true));
    }

  }

  if(!toDelete.isEmpty()) delete toDelete;

  if(!newContactRoleList.isEmpty()) insert newContactRoleList; 

}

 
Kelly KKelly K
The issue is still persisting because you're not pulling and updating the existing contact role. You're still using new OpportunityContactRole() instead of updating using the existing contact role Id.

You also do not need to be using a query in a for loop. That will eat up your governor limits very quickly. While we're on best practices, I highly suggest taking the 'functionality' of your code and moving it to a class and limiting your trigger to just identifying opps that meet a critiera.
RAJEEV REDDY 3RAJEEV REDDY 3
I think on OpportunityContactRole.
We can’t add any custom fields into OpportunityContactRole Object.
We can’t add any validation rules on OpportunityContactRole object.
We can’t create any trigger on this OpportunityContactRole Object.
Please refer below link for your reference.
http://sfdcsrini.blogspot.com/2014/04/what-is-opportunity-contact-role.html 
RAJEEV REDDY 3RAJEEV REDDY 3
I think on OpportunityContactRole.
We can’t add any custom fields into OpportunityContactRole Object.
We can’t add any validation rules on OpportunityContactRole object.
We can’t create any trigger on this OpportunityContactRole Object.
Please refer below link for your reference.

http://sfdcsrini.blogspot.com/2014/04/what-is-opportunity-contact-role.html