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
Ty WhitfieldTy Whitfield 

How to retrieve contact role information from an opportunity

Diving back into Apex so I'm a bit rusty.  What we are looking to do is to create a trigger after insert and after update that will identify the Primary contact on the opportunity.  For that Primary contact, pull a custom field from the contact and then update a custom field on the opportunity with that value.

I know how to update the opportunity field but what I don't understand is how to pull the contact role information.  Can someone point me in the right direction?
Best Answer chosen by Ty Whitfield
Wilfredo Morillo 20Wilfredo Morillo 20
try this.
trigger oppMarketingQualifiedFieldUpdate on Opportunity (before update) {
     
        map<id,id>OppContactMap = new Map<id,id>();
        map<id,Contact> allPrimaryContacts = new Map<id,Contact>();

        for(OpportunityContactRole contactRole :[Select contactId,opportunityId FROM OpportunityContactRole 
        Where OpportunityId = :oppObj.id and isPrimary = true]){
               OppContactMap.put(contactRole.OpportunityId,contactRole.contactId); 
        }

        if(!OppContactMap.isEmpty()){

            map<id,Contact> allPrimaryContacts = new Map<id,Contact>(select id,Marketing_Qualified_Action__c from contact where id in :OppContactMap.values());

            for(Opportunity opp :trigger.new){
                Contact primary = allPrimaryContacts.get(OppContactMap.get(opp.id));

                opp.Marketing_Qualified_Action__c = primary.Marketing_Qualified_Action__c;

            }
        }
    }

All Answers

Wilfredo Morillo 20Wilfredo Morillo 20
The information for Opportunity Contacts is in the OpportunityContactRole:
you need to change "YourCustomField" and "YourOpportunity" to the proper values and you should get the id and the field for the contact. 
contact primaryContact = [Select id,yourCustomField from contact where id in (Select contactId FROM OpportunityContactRole Where OpportunityId = :YourOpportunity.id and isPrimary = true) limit 1];
Let me know if it was helpful for you. 
Ty WhitfieldTy Whitfield
That definitely helps me to create the trigger.  I'm now just a bit confused on how I would create the test.  It appears that there is a problem with the order.  I get an error stating List has no rows for assignment to Sobject on my trigger and states line 5 below (the contact select statement) and from the test class it is stating the line where I go to insert the opp. 

What I'm thinking is that when I try to insert the opportunity in the test, I insert the opportunity then the opportunitycontactrole so when my trigger starts after insert, a contact hasn't been tied to the opportunitycontactrole.

Here is my Trigger:
trigger oppMarketingQualifiedFieldUpdate on Opportunity (after insert, after update) {
      
    for(Opportunity oppObj: Trigger.new)
    {
        contact primaryContact = [Select id, Marketing_Qualified_Action__c from contact where id in (Select contactId FROM OpportunityContactRole 
        Where OpportunityId = :oppObj.id and isPrimary = true) limit 1];
        
        oppObj.Marketing_Qualified_Action__c = primaryContact.Marketing_Qualified_Action__c;
    }
}

Here is my test
@isTest
private class TestOppCreate {
    @isTest static void TestOppCreateWith()
    {
        Account acct = new Account(Name='Test Account');
        insert acct;
        
        Contact contact = new Contact(Email = 'test@test.com', Marketing_Qualified_Action__c = 'Video', FirstName = 'Test', LastName= 'Tester', AccountId = acct.Id);
        insert contact;        
       
        
        Opportunity opp = new Opportunity(Name=acct.Name + ' Opportunity',
                                       StageName='Prospecting',
                                       CloseDate=System.today().addMonths(1),                                          
                                       AccountId=acct.Id);
        insert opp;
        
         OpportunityContactRole primary = new OpportunityContactRole(IsPrimary = True, OpportunityId = opp.Id	, ContactId = contact.id);
        insert primary;
        
        // Perform test
        Test.startTest();
       
        Test.stopTest();


    }

}


Wilfredo Morillo 20Wilfredo Morillo 20
try this.
trigger oppMarketingQualifiedFieldUpdate on Opportunity (before update) {
     
        map<id,id>OppContactMap = new Map<id,id>();
        map<id,Contact> allPrimaryContacts = new Map<id,Contact>();

        for(OpportunityContactRole contactRole :[Select contactId,opportunityId FROM OpportunityContactRole 
        Where OpportunityId = :oppObj.id and isPrimary = true]){
               OppContactMap.put(contactRole.OpportunityId,contactRole.contactId); 
        }

        if(!OppContactMap.isEmpty()){

            map<id,Contact> allPrimaryContacts = new Map<id,Contact>(select id,Marketing_Qualified_Action__c from contact where id in :OppContactMap.values());

            for(Opportunity opp :trigger.new){
                Contact primary = allPrimaryContacts.get(OppContactMap.get(opp.id));

                opp.Marketing_Qualified_Action__c = primary.Marketing_Qualified_Action__c;

            }
        }
    }
This was selected as the best answer
Ty WhitfieldTy Whitfield
That worked.  Thanks so much.  

If you can just explain to me the map statements.  I don't quite understand what is being done.
map<id,id>OppContactMap = new Map<id,id>();
        map<id,Contact> allPrimaryContacts = new Map<id,Contact>();

 map<id,Contact> allPrimaryContacts2 = new Map<id,Contact>
                ([select id,Marketing_Qualified_Action__c from contact where id in :OppContactMap.values()]);

 
Wilfredo Morillo 20Wilfredo Morillo 20
OppContactMap to map an opportunity to the main contact. Then allPrimaryContacts to get the value of the field you needed .

the last part is to get the primary contact related to the oppotyunity in the loop. 

remove the "Map<id,contact>" and the 2. That was a typo. 

read this: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_map.htm

mark my answer as the best if it helped you.