I want to make contact role required when saving an Opportunity - Answers - Salesforce Trailblazer Community
Trailblazer Community
Ask Search:
Louise CabralLouise Cabral 

I want to make contact role required when saving an Opportunity

I would like to have a contact as required information on an Opportunity.  I see new contact role on an opp.

I would like to have this information required upon save, clone, or editing an existing opportunity.

I was thinking that this could be done as a validation rule, yet there is no Field = Contact nor Contact Role.  I see only a related list = Contact Role.

How would I do this?

Thanks!
Best Answer chosen by Louise Cabral
Jodi HrbekJodi Hrbek
I haven't tried it, but there is freebie on the AppExchange that supports this.  (It does require EE or higher.)

http://sites.force.com/appexchange/listingDetail?listingId=a0N300000025Vs1EAE

All Answers

Jodi HrbekJodi Hrbek
I haven't tried it, but there is freebie on the AppExchange that supports this.  (It does require EE or higher.)

http://sites.force.com/appexchange/listingDetail?listingId=a0N300000025Vs1EAE
This was selected as the best answer
Louise CabralLouise Cabral
Thanks!  I will check into this option.  I appreciate your time.
Erica KuhlErica Kuhl
 @needinfo - when you get a chance to try this option out, let us know if it worked so you can spread the love to the community :)
Louise CabralLouise Cabral
I have some development going on in Sandbox with Opp's, so cannot pull into test just yet.  I will let everyone know when I get the chance.  Thanks.
Jeannie FrantzJeannie Frantz
Anybody have a solution to this issue for Professional edition users?
Oliver JobsonOliver Jobson
Would love to know if anyone managed to get this working with or without an app.

Cheers.
Launa SaundersLauna Saunders
You will need to create a new field (checkbox for "Primary Contact Assigned"), then create a trigger to calculate that field, and then a VR to check whether or not the Contact Role is in fact assigned.

And here's the trigger (will need to create the custom field first)


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
trigger updatecontactrolecount on Opportunity (before insert, before update)
{

Boolean isPrimary;
Integer iCount;

Map<String, Opportunity> oppty_con = new Map<String, Opportunity>();//check if the contact role is needed and add it to the oppty_con map
for (Integer i = 0; i < Trigger.new.size(); i++) 
{
        oppty_con.put(Trigger.new[i].id,
        Trigger.new[i]);      
}
isPrimary = False; 
for (List<OpportunityContactRole> oppcntctrle :[select OpportunityId from OpportunityContactRole where (OpportunityContactRole.IsPrimary = True and OpportunityContactRole.OpportunityId in :oppty_con.keySet())])
{
 if (oppcntctrle .Size() >0)
 {
 isPrimary = True;     
 }
}
iCount = 0;
for (List<OpportunityContactRole> oppcntctrle2 : [select OpportunityId from OpportunityContactRole where (OpportunityContactRole.OpportunityId in :oppty_con.keySet())])//Query for Contact Roles
{    
 if (oppcntctrle2 .Size()>0)
 {
 iCount= oppcntctrle2 .Size();     
 }
}
for (Opportunity Oppty : system.trigger.new) //Check if  roles exist in the map or contact role isn't required 
{
Oppty.Number_of_Contacts_Roles_Assigned__c = iCount;
Oppty.Primary_Contact_Assigned__c =isPrimary; 
}
}

 

Validation Rule: (the below requires it to change the stage to closed won:

AND
(
NOT(Primary_Contact_Assigned__c),
ISPICKVAL(StageName ,"Closed Won")
)


To give credit where credit is due: This existed in my org before I started here. @Rhonda Ross created this before I came aboard and deserves all of the kudos for it.

Angela WickwareAngela Wickware
@ Luana -  Do you have pointers on how to put the test class together?
Clare HaywardClare Hayward
Could I ask for some help on this? There are two custom fields to create, Primary Contact Assigned (as a checkbox field on the opportunity) and the Number of Contacts Roles Assigned. However with the 'number of..' field which object is this count field supposed to be on? It doesn't work as an opportunity count (roll up summary) so i'm a bit lost as to how to create this second custom field, before setting up this trigger?

Any help would be greatly appreciated.
Carrie Anderson (Philipp)Carrie Anderson (Philipp)
The field Number of Contacts Roles Assigned is a Number field on the Opportunity with a length of 1 and 0 Decimal Places.
Carrie Anderson (Philipp)Carrie Anderson (Philipp)
Would love to see this Trigger for the Partner Related List on Opportunities.
Carrie Anderson (Philipp)Carrie Anderson (Philipp)
Partner Trigger thanks to @RVJ https://developer.salesforce.com/forums/ForumsProfile?communityId=09aF00000004HMG&userId=005F0000003Fh4A&showHeader=false (https://developer.salesforce.com/forums/ForumsProfile?communityId=09aF00000004HMG&userId=005F0000003Fh4A&showHeader=false)

Requires you create two fields on the Opportunity record.

trigger updatepartnercount on Opportunity (before insert, before update)
{
 
Boolean isPrimary;
Integer iCount;
 
Map<String, Opportunity> oppty_con = new Map<String, Opportunity>();//check if the contact role is needed and add it to the oppty_con map
for (Integer i = 0; i < Trigger.new.size(); i++)
{
oppty_con.put(Trigger.new[i].id,
Trigger.new[i]);
}
isPrimary = False;
for (List<Opportunitypartner> oppcntctrle :[select OpportunityId from Opportunitypartner where (Opportunitypartner.IsPrimary = True and Opportunitypartner.OpportunityId in :oppty_con.keySet())])
{
if (oppcntctrle .Size() >0)
{
isPrimary = True;
}
}
iCount = 0;
for (List<Opportunitypartner> oppcntctrle2 : [select OpportunityId from Opportunitypartner where (Opportunitypartner.OpportunityId in :oppty_con.keySet())])//Query for Contact Roles
{
if (oppcntctrle2 .Size()>0)
{
iCount= oppcntctrle2 .Size();
}
}
for (Opportunity Oppty : system.trigger.new) //Check if roles exist in the map or contact role isn't required
{
Oppty.Number_of_Partners_Roles_Assigned__c = iCount;
Oppty.Primary_Partner_Assigned__c =isPrimary;
}
}

 
And a Validation Rule on the Opportunity, this will enforce a Partner at Stage 7 - Closed/Won you can insert your own stage or rewrite for different Stages.

Validation Rule
AND
(
NOT(Primary_Partner_Assigned__c),
ISPICKVAL(StageName ,"7 - Closed/Won")
)

NOTE: you may need to do some data backfill on your custom fields if you are receiving erroneous errors on Opportunities that already have a Partner filled in. Same goes for the Contact Role Trigger mentioned above.
Brian FordBrian Ford
I used Luana's code and it works great. Here's the test class we deployed in our org to go along with it

@isTest
public class requireContactRoleTEST {
    
    static testMethod void testContactRole() {

        //create an account
        Account acc = new Account();
        acc.Name = 'Acc-ContactRoles';
        acc.BillingCountry = 'United States';

        //create 2 contacts
        Contact con1 = new Contact();
        con1.FirstName = 'ContactRoles1';
        con1.LastName = 'Surname1';
        con1.AccountId = acc.Id;
        
        Contact con2 = new Contact();
        con2.FirstName = 'ContactRoles2';
        con2.LastName = 'Surname2';
        con2.AccountId = acc.Id;

        //create an opportunity
        Opportunity opp = new Opportunity();
        opp.Name = 'Opp-ContactRoles';
        opp.AccountId = acc.Id;
        opp.StageName = 'Qualification';
        opp.Amount = 10000;
        opp.CloseDate = System.Today();

        //add 2 contact roles and make 1 the primary
        OpportunityContactRole ocr1 = new OpportunityContactRole();
        ocr1.OpportunityId = opp.Id;
        ocr1.ContactId = con1.Id;
        ocr1.IsPrimary = TRUE;

        OpportunityContactRole ocr2 = new OpportunityContactRole();
        ocr2.OpportunityId = opp.Id;
        ocr2.ContactId = con2.Id;
        ocr2.IsPrimary = FALSE;
        
        insert acc;
        insert con1;
        insert con2;
        insert opp;
        insert ocr1;
        insert ocr2;
        
        Integer oppAmount = 0;
        Integer singleAmount = 1;
        for (Opportunity o:[SELECT Id FROM Opportunity 
                            WHERE Name = 'Opp-ContactRoles' AND
                                  Number_of_contact_roles__c > 0 AND
                                  Primary_contact_assigned__c = TRUE]) {
                                oppAmount++;
                            }
        System.assertEquals(singleAmount, oppAmount);
    }
}


Joe HamletJoe Hamlet
Great solution. Thank you for sharing.

I bet that this trigger can be accomplished with a process builder flow ... has anyone tried that yet? 
Joe HamletJoe Hamlet
Here is a solution I found using Auto-launched Flows / Process Builder Flows to update the Opportunity from Contact Roles. 
http://judisohn.com/2015/04/06/using-salesforce-process-builder-flow-with-opportunity-contact-roles/
Mike ArthurMike Arthur
@Joe @Judi (and anyone else!)

I really like Judi's solution, it's as close as you can get without code given the restrictions to be worked around, however as I see it the PB and hence flow will only fire when the Opp is updated.  So if I have an Opp with no primary contact and my validation rule complains, I add a contact role, but this doesn't update the opp so the PB and flow wouldn't fire and my validation rule still complains.

Is that the case or have I missed something?

Thanks,
Mike.
K CarmenK Carmen
Hi All - is there a validation rule that will work AFTER a user adds a contact role to the Opportunity??

I also want to know how to write a validation rule that gives the error whenever someone changes a stage above the first stage but it isn't working well for me (see below). Help!!!!

AND 

NOT(Primary_Contact_Assigned__c), 
AND(OR(ISPICKVAL(StageName,'Value Proposition'),ISPICKVAL(StageName,'Proposal/Price Quote'),ISPICKVAL(StageName,'Negotiation/Review'), ISPICKVAL(StageName ,'Closed Won'),ISPICKVAL(StageName ,'Closed Lost'))))