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
Nonprofit_ITNonprofit_IT 

Automatically assign contact roles to opportunities - possible?

I'd like to have a program that would automatically connect all contacts associated with an account to an opportunity as contact roles. I already know that if you create an opportunity from a contact, that the contact is assigned as the contact role. However, I have multiple contacts associated with some of my accounts and I need them to be connected to the opportunity as well. I've created a flow to make opportunity entry easier for the office staff, however getting them to remember to go back and add the contact roles after they have created the opportunities is a pain. It would be so much nicer if this could be done behind the scenes with programing.  Is it possible to do this with a flow? I'm using the desktop flow developer, and I see you can make a data source/target with an opportunitycontactrole table. But I'm not sure how to go about adding this to my flow. I'm assuming I'd have to add another lookup element, have the person find the contact to attach, selected it and assign the role.  The problem with this, is that the operator, has to know who to add to the opportunity, which opens up a possbility of adding the wrong people. If there was a way to make it automatic, it would remove the potential for operator error. 

AmitSahuAmitSahu

This can be achieved with the help of trigger and class.You can query the account associated with the opportunity and add all contacts associated with that account to contact role.

Nonprofit_ITNonprofit_IT

I'm a beginner salesforce developer. Would it be possible for you to give me a bit more information about how to do this? 

 

Thanks so much,
Stephanie 

SamuelDeRyckeSamuelDeRycke

Not entirely sure if I got your question right, but this trigger will add all account contacts to the contact roles when you create a new opportunity. Though, one should still manually enter the specific roles for the contacts, and you should probably also write a test class for it.

 

trigger InsertAccountContactsToOpportunityContactRole on Opportunity (after insert) {

	//triggers always need to be bulkified!
List<Opportunity> opportunities_in = trigger.new; //get the id of all involved accounts Set<ID> accountIds = new Set<ID>(); for(Opportunity opt:opportunities_in){ accountIds.add(opt.AccountId); } //get all contacts for those accounts list<Contact> contacts = new list<Contact>(); contacts = [select id, AccountId from Contact where AccountId in: accountIds]; //organize these contacts by account Map<Id,List<Contact>> contactsByAccount = new Map<ID,List<Contact>>(); for(Contact c:contacts){ if(contactsByAccount.get(c.AccountId) == null){ contactsByAccount.put(c.AccountId,new List<Contact>()); } contactsByAccount.get(c.AccountId).add(c); } //create the OpportunityContactRole objects list<OpportunityContactRole> lstOCR = new list<OpportunityContactRole>(); for(Opportunity opt:opportunities_in){ if(contactsByAccount.get(opt.AccountId) != null){ for(Contact c: contactsByAccount.get(opt.AccountId)){ OpportunityContactRole ocr = new OpportunityContactRole(OpportunityId=opt.id, ContactId=c.id); lstOCR.add(ocr); } } } insert lstOCR; }

 If this is what you wanted, feel free to mark this as answer. But more importantly, if you'd implement this code, do make sure you understand it , or try to recode it yourself.

Joseph DindingerJoseph Dindinger
Thank you Samuel!  After a few changes (Insert + Update, and set the IsPrimary flag if it is the first contact created on the account), this is what I came up with for my requirements:
 
trigger CreateContactRole on Opportunity (after insert, after update) {

    //get the id of all involved accounts
    Set<ID> accountIds = new Set<ID>();
    for(Opportunity opt:Trigger.New){
        accountIds.add(opt.AccountId);
    }
    
    //get all contacts for those accounts
    list<Contact> contacts = new list<Contact>();
    contacts = [select id, AccountId from Contact where AccountId in: accountIds order by createddate Limit 5000];
    
    //organize these contacts by account
    Map<Id,List<Contact>> contactsByAccount = new Map<ID,List<Contact>>();
    for(Contact c:contacts){
        if(contactsByAccount.get(c.AccountId) == null){
            contactsByAccount.put(c.AccountId,new List<Contact>());
        }
        contactsByAccount.get(c.AccountId).add(c);
    }
    
    // check to see if the Opportunity already has a contact role.  If it does, add to a set of Ids to exclude
    List<OpportunityContactRole> existingOCR = new List<OpportunityContactRole>();
    Set<Id> existingOCRIds = new Set<Id>();
    existingOCR = [select OpportunityId from OpportunityContactRole where OpportunityId in:Trigger.newMap.keySet() limit 5000];
    for(OpportunityContactRole ocr:existingOCR) if(!existingOCRIds.contains(ocr.OpportunityId)) existingOCRIds.add(ocr.OpportunityId);
    
    //create the OpportunityContactRole objects
    list<OpportunityContactRole> lstOCR = new list<OpportunityContactRole>();
    for(Opportunity opt:Trigger.New){
        if(!existingOCRIds.contains(opt.Id) && contactsByAccount.get(opt.AccountId) != null){
            Boolean firstContact = true;
            for(Contact c: contactsByAccount.get(opt.AccountId)){
                OpportunityContactRole ocr = new OpportunityContactRole(OpportunityId=opt.id, ContactId=c.id);
                if(firstContact) {
                    ocr.IsPrimary = TRUE;
                    firstContact = FALSE;
                }
                lstOCR.add(ocr);
            }
        }
    }
    insert lstOCR;
}

 
Speedy Admin 1Speedy Admin 1
Just wondering, how you guys are handling when the lead is converted and it creates and Opportunity, I am using code above but it creates 2 roles after the lead convert
CushtyCushty
Hi,
Using the above trigger, How would I create the standard functionality where a user adds an opportunity from a contact and this adds the contact to that opportunity as a contact role?
I have a custom button which replaces the standard Opportunity New button because it defaults the stage field and others and therefore loose the standard contact role assignment 
SpartySparty
Hi,

I'm pretty new trying to learn apex triggers and classes but using the above trigger from Joseph Dindinger what would the apex test class be? I've watched a few videos and searche on how to create one based on that trigger but I'm completely lost. Thanks for any help. 

Thanks,
 
Joseph DindingerJoseph Dindinger
Sparty, we've all been there.  Here is some sample code that you can put into an Apex Class in order to meet the code coverage requirements.  However, keep in mind that this is not really a valid test of what you are doing, it merely runs the operations in a clean-room environment:
 
@isTest
public class TriggerTestSample{

    static testmethod void TriggerTest(){
        Account acc = new Account();
        acc.Name = 'TestAcc1';
        insert acc;

        Contact con = new Contact();
        con.AccountId = acc.Id;
        con.Lastname = 'Smith';
        con.Firstname = 'John';
        con.Email = 'not@giving.it';
        insert con;

        Opportunity opp = new Opportunity();
        opp.AccountId = acc.Id;
        opp.StageName = 'Qualifying';
        opp.CloseDate = system.today()+30;
        opp.Name = 'Test Opp';
        insert opp;

        opp.Description = 'Some Opp!';
        update opp;

        OpportunityContactRole ocr = new OpportunityContactRole();
        ocr.OpportunityId = opp.Id;
        ocr.ContactId = con.Id;
        ocr.Role = 'Decision Maker';
        insert ocr;

        ocr.IsPrimary = true;
        update ocr;

     }
}

 
John PollardJohn Pollard
Here is a non-code solution for this problem: https://automationchampion.com/2019/09/24/getting-started-with-process-builder-part-95-need-to-auto-add-opportunity-contact-role-to-an-opportunity-read-on/