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
Abby BeckerAbby Becker 

Update contact on opportunity before insert trigger

I am new to Apex development and have the following code. I'd appreciate any help or suggestions.

Requirements: 
I will be uploading Opportunities periodically through Dataloader, all of record type "Outbound Call Opportunity." The file will contain the following info for each opp:
  • RecordTypeID
  • TIN__c (Tax ID Number)
  • Product__c
  • Outbound_Call_Score__c
I need my code to do the following:
  • Query Contacts where the Opp's TIN__c matches Contact's Tax_ID_Number__c and set Contact as Opp Owner
  • Confirm before insert that there are no other Outbound Call Opportunities with the same Contact and Product, in other words, there can only be one Outbound Call Opportunity per Contact per Product.
  • Give error if a Outbound Opportunity exists already with that contact and product, else update pertinent fields
I think I have that sorted out, but I have one remaining requirement:
  • Rollup Outbound_Call_Score__c to related Contact. Each Opp with have a numeric weight signifying how "important" it is. I want that number to aggregate and rollup to the Contact on a field also named Outbound_Call_Score__c. I am not sure how to accompish that, any help would be appreciated!
Trigger:
trigger OpportunityTrigger on Opportunity (before insert) {

  if (Trigger.isBefore) {
    if (Trigger.isInsert) {
      OpportunityHandler.insertOutboundCallLists(Trigger.new);
    } 
  }
}

Handler class:
 
public class OpportunityHandler {
    
    public OpportunityHandler() { }
    
    public static void insertOutboundCallLists(List<Opportunity> newOpps){
        Set<String> oppTINs = new Set<String>();
        String outboundCallRecTypeID = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Outbound Call Opportunity').getRecordTypeId();
        
        for(Opportunity opp : newOpps){
            oppTINs.add(opp.TIN__c);
        }        
        //system.debug(oppTINs);
        
        List<Contact> contacts = [SELECT Id, OwnerId, Tax_ID_Number__c, Outbound_Call_Score__c 
                                  FROM Contact WHERE Tax_ID_Number__c IN :oppTINs]; 
        List<Opportunity> existingOutboundOpps = new List<Opportunity>([SELECT Id, Product__c, Contact__r.Id, Contact__r.Tax_ID_Number__c 
                                                                        FROM Opportunity WHERE RecordTypeId = :outboundCallRecTypeId 
                                                                        AND Contact__r.Id IN :contacts]);
        system.debug(contacts);
        system.debug(existingOutboundOpps);
        
        if(contacts.size() > 0){
            for(Opportunity opp : newOpps){
                for(Integer i = 0; i < existingOutboundOpps.size(); i++){
                    if(opp.TIN__c == existingOutboundOpps[i].Contact__r.Tax_ID_Number__c && opp.Product__c == existingOutboundOpps[i].Product__c){
                        opp.addError('Outbound Opportunity Already Exists.');
                    } else {
                        for(Integer j = 0; j < contacts.size(); j++){
                            if(opp.TIN__c == contacts[j].Tax_ID_Number__c && opp.RecordTypeId == outboundCallRecTypeID){
                                opp.Name = 'test';
                                opp.CloseDate = system.today() + 14;
                                opp.StageName = 'Prospecting';
                                opp.OwnerId = contacts[j].OwnerId;
                                opp.Contact__c = contacts[j].Id;
                                //contacts[j].Outbound_Call_Score__c = contacts[j].Outbound_Call_Score__c + opp.Outbound_Call_Score__c;
                            }   
                        }
                    }
                }  
            } 
        } 
    }     
}



 
Maharajan CMaharajan C
Hi Abby,

Try the below change:
 
public class OpportunityHandler {
    
    public OpportunityHandler() { }
    
    public static void insertOutboundCallLists(List<Opportunity> newOpps){
        Set<String> oppTINs = new Set<String>();
		List<Contact> contactstoUpdate = new List<Contact>();
        String outboundCallRecTypeID = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Outbound Call Opportunity').getRecordTypeId();
        
        for(Opportunity opp : newOpps){
            oppTINs.add(opp.TIN__c);
        }        
        //system.debug(oppTINs);
        
        List<Contact> contacts = [SELECT Id, OwnerId, Tax_ID_Number__c, Outbound_Call_Score__c 
                                  FROM Contact WHERE Tax_ID_Number__c IN :oppTINs]; 
        List<Opportunity> existingOutboundOpps = new List<Opportunity>([SELECT Id, Product__c, Contact__r.Id, Contact__r.Tax_ID_Number__c 
                                                                        FROM Opportunity WHERE RecordTypeId = :outboundCallRecTypeId 
                                                                        AND Contact__r.Id IN :contacts]);
        system.debug(contacts);
        system.debug(existingOutboundOpps);
        
        if(contacts.size() > 0){
            for(Opportunity opp : newOpps){
                for(Integer i = 0; i < existingOutboundOpps.size(); i++){
                    if(opp.TIN__c == existingOutboundOpps[i].Contact__r.Tax_ID_Number__c && opp.Product__c == existingOutboundOpps[i].Product__c){
                        opp.addError('Outbound Opportunity Already Exists.');
                    } else {
                        for(Integer j = 0; j < contacts.size(); j++){
                            if(opp.TIN__c == contacts[j].Tax_ID_Number__c && opp.RecordTypeId == outboundCallRecTypeID){
                                opp.Name = 'test';
                                opp.CloseDate = system.today() + 14;
                                opp.StageName = 'Prospecting';
                                opp.OwnerId = contacts[j].OwnerId;
                                opp.Contact__c = contacts[j].Id;
                                //contacts[j].Outbound_Call_Score__c = contacts[j].Outbound_Call_Score__c + opp.Outbound_Call_Score__c;
								contactstoUpdate.add(new Contact(Id=contacts[j].Id, Outbound_Call_Score__c = contacts[j].Outbound_Call_Score__c + opp.Outbound_Call_Score__c));
                            }   
                        }
                    }
                }  
            } 
        } 
		if(!contactstoUpdate.IsEmpty())
			update contactstoUpdate;
    }     
}

Thanks,
Maharajan.C
Maharajan CMaharajan C
Hi Abby,

I will suggest you to write a code like below :

So Don't copy and paste it directly just use the below as reference.  You need to bulkify like below. Don't use multiple loop inside loop
 
public class OpportunityHandler {
    
    public OpportunityHandler() { }
    
    public static void insertOutboundCallLists(List<Opportunity> newOpps){
        Set<String> oppTINs = new Set<String>();
		List<Contact> contactstoUpdate = new List<Contact>();
		Map<String,Contact> conMap = new Map<String,Contact>();
		set<String> duplicateOppSet = new set<String>();
		set<Id> contacts = new set<Id>();
        String outboundCallRecTypeID = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Outbound Call Opportunity').getRecordTypeId();
        
        for(Opportunity opp : newOpps){
            oppTINs.add(opp.TIN__c);
        }        

		for(Contact con : [SELECT Id, OwnerId, Tax_ID_Number__c, Outbound_Call_Score__c FROM Contact WHERE Tax_ID_Number__c IN :oppTINs]){
			conMap.put(con.Tax_ID_Number__c, con);
			contacts.add(con.Id);
		}
								  
		for(Opportunity opp : [SELECT Id, Product__c, Contact__r.Id, Contact__r.Tax_ID_Number__c 
                                                                        FROM Opportunity WHERE RecordTypeId = :outboundCallRecTypeId 
                                                                        AND Contact__r.Id IN :contacts]){
			String str = String.ValueOf(opp.Contact__r.Tax_ID_Number__c) + '-' + opp.Product__c 
			duplicateOppSet.add(str);
		}
																		
        system.debug(contacts);
        system.debug(existingOutboundOpps);
        
		for(Opportunity opp : newOpps){
			String checkstr = String.ValueOf(opp.TIN__c) + '-' + opp.Product__c;
 			if(duplicateOppSet.contains(checkstr))
				opp.addError('Outbound Opportunity Already Exists.');
			else if(opp.RecordTypeId == outboundCallRecTypeID && conMap.containsKey(opp.TIN__c)){
				opp.Name = 'test';
				opp.CloseDate = system.today() + 14;
				opp.StageName = 'Prospecting';
				opp.OwnerId = conMap.get(opp.TIN__c).OwnerId;
				opp.Contact__c = conMap.get(opp.TIN__c).Id;
				contactstoUpdate.add(new Contact(Id=conMap.get(opp.TIN__c).Id, Outbound_Call_Score__c = conMap.get(opp.TIN__c).Id.Outbound_Call_Score__c + opp.Outbound_Call_Score__c));
				}
		} 
		if(!contactstoUpdate.IsEmpty())
			update contactstoUpdate;
    }     
}

Thanks,
Maharajan.C
Abby BeckerAbby Becker
Thanks for your reply Maharajan. I have taken your advice and bulkified my code. New to this and still learning the ropes!

I am getting the following error on the line adding the contact to the contactstoUpdate list. 

"A non foreign key field cannot be referenced in a path expression: Id"

Not really sure what that means. Should I attempt to do the "rollup" function outside of this trigger? Suggestions? Thanks in advance