You need to sign in to do that
Don't have an account?
Apex trigger to copy primary contact from the contact roles list on an opportunity
Im trying to use a apex script that i have found. But it seems like it does not take care of the problem of opportunities not having a primary contact. If the primary contact is not defined it throws the following error.
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger trgMnCopyPrimaryContact caused an unexpected exception, contact your administrator: trgMnCopyPrimaryContact: execution of BeforeUpdate caused by: System.QueryException: List has no rows for assignment to SObject: Trigger.trgMnCopyPrimaryContact: line 6, column 13
trigger trgMnCopyPrimaryContact on Opportunity (before update) {
for (Opportunity o : Trigger.new) {
OpportunityContactRole contactRole =
[select ContactID from OpportunityContactRole where IsPrimary = true and OpportunityId = :o.id];
if (contactRole != null) {
o.Opportunity_contact__c = contactRole.ContactID;
}
}
}
Im not a java developer and wonder if someone can help me to add functionality that does not fail if the primary contact is missing.
I ended up with the following code that seems to work exactly as i want. You can't use "IsPrimary = true" since all opportunities that has been created by a lead beeing converted will have a contact role but the isPrimary will be FALSE.
When opportunities are created manually from the contact object then the isPrimary = TRUE.
Please vote for this idea to get this fixed ASAP: http://sites.force.com/ideaexchange/apex/ideaview?id=08730000000HKbnAAG
The following code picks the isPrimary contact if it has been defined or picks the fist added contact if not =)
trigger trgMnCopyPrimaryContact on Opportunity (before update) {
// THIS TRIGGER WILL OVERWRITE ANY CONTACT DEFINED IN THE CUSTOM FIELD OPPORTUNITY_CONTACT__C ON THE OPPORTUNITY OBJECT.
// SET THIS FIELD TO READ ONLY OR CHANGE THE FUNCTIONALITY BELOW TO AVIOD DATA BEEING OVERWRITTEN BY MISTAKE...
for (Opportunity o : Trigger.new) {
// o.NextStep = 'DEBUG: Running function...';
// CREATE ARRAY OF ALL CONTACT ROLES ON THIS OPPORTUNITY. THE REASON WHY WE DONT PICK THE PRIMARY CONTACT ROLE ONLY
// IS BECAUSE THE PRIMARY FLAG IS NOT SET WHEN LEADS ARE CONVERTED TO OPPORTUNITIES. ONLY WHEN CREATING OPPORTUNITIES
// MANUALLY FROM THE CONTACT OBJECT THE IS PRIMARY CHECKBOX IS CHECKED...
OpportunityContactRole[] contactRoleArray =
[select ContactID, isPrimary from OpportunityContactRole where OpportunityId = :o.id ORDER BY isPrimary DESC, createdDate];
if (contactRoleArray.size() > 0) {
// IF PRIMARY IS DEFINED THEN THIS WILL BE THE FIRST OBJECT. IF NOT THE FIRST ADDED CONTACT ROLE WILL BE ADDED...
o.Opportunity_contact__c = contactRoleArray[0].ContactID;
}else{
// IF NO CONTACT ROLES EXIST RETURN NULL...
o.Opportunity_contact__c = null;
// o.NextStep = 'DEBUG; CONTACT = null ';
}
}
}
All Answers
Hi Mattias - the problem is that unfortunately there is no 'HasPrimaryContact' field (or similar) against the Opportunity which would allow you to quickly check if there is one prior to getting the Id in the SOQL query. Because of this you'll always encounter errors as the query could return no value.
You have a couple of options:
1) You could write a seperate trigger to check if there is a primary contact first, which updates a boolean field on the opp. You could then use this value in your current trigger to check prior to your SOQL query
2) You could include a SOQL count() before your query, which would elimiate the error but it will also increase your SOQL count by 1. eg:
You might also want to check out my recent post which may help http://www.forcedotcom.com/2010/08/auto-update-opportunity-contact-role.html
//this will assign contact to opportunity if there is a primary contact role else does nothing (leaves o.Opportunity_contact__c blank)
//please let me know if this works and if this is wat u ar looking for
//
trigger trgMnCopyPrimaryContact on Opportunity (before update) {
for (Opportunity o : Trigger.new) {
Integer i = [select count() from OpportunityContactRole where OpportunityId = :o.id and IsPrimary = true];
if(i==1) {
OpportunityContactRole contactRole =
[select ContactID from OpportunityContactRole where OpportunityId = :o.id and IsPrimary = true];
o.op_Contact_c__c = contactRole.ContactID;
}
}
}
I ended up with the following code that seems to work exactly as i want. You can't use "IsPrimary = true" since all opportunities that has been created by a lead beeing converted will have a contact role but the isPrimary will be FALSE.
When opportunities are created manually from the contact object then the isPrimary = TRUE.
Please vote for this idea to get this fixed ASAP: http://sites.force.com/ideaexchange/apex/ideaview?id=08730000000HKbnAAG
The following code picks the isPrimary contact if it has been defined or picks the fist added contact if not =)
trigger trgMnCopyPrimaryContact on Opportunity (before update) {
// THIS TRIGGER WILL OVERWRITE ANY CONTACT DEFINED IN THE CUSTOM FIELD OPPORTUNITY_CONTACT__C ON THE OPPORTUNITY OBJECT.
// SET THIS FIELD TO READ ONLY OR CHANGE THE FUNCTIONALITY BELOW TO AVIOD DATA BEEING OVERWRITTEN BY MISTAKE...
for (Opportunity o : Trigger.new) {
// o.NextStep = 'DEBUG: Running function...';
// CREATE ARRAY OF ALL CONTACT ROLES ON THIS OPPORTUNITY. THE REASON WHY WE DONT PICK THE PRIMARY CONTACT ROLE ONLY
// IS BECAUSE THE PRIMARY FLAG IS NOT SET WHEN LEADS ARE CONVERTED TO OPPORTUNITIES. ONLY WHEN CREATING OPPORTUNITIES
// MANUALLY FROM THE CONTACT OBJECT THE IS PRIMARY CHECKBOX IS CHECKED...
OpportunityContactRole[] contactRoleArray =
[select ContactID, isPrimary from OpportunityContactRole where OpportunityId = :o.id ORDER BY isPrimary DESC, createdDate];
if (contactRoleArray.size() > 0) {
// IF PRIMARY IS DEFINED THEN THIS WILL BE THE FIRST OBJECT. IF NOT THE FIRST ADDED CONTACT ROLE WILL BE ADDED...
o.Opportunity_contact__c = contactRoleArray[0].ContactID;
}else{
// IF NO CONTACT ROLES EXIST RETURN NULL...
o.Opportunity_contact__c = null;
// o.NextStep = 'DEBUG; CONTACT = null ';
}
}
}
I'm trying to get this to work in my org. Did you get it to work successfully and update whenever the primary contact was changed?
What field type should the field OPPORTUNITY_CONTACT_C be?
Any other set up / security settings I need to be aware of?
How would i retrieve the contact email address going through the opportunity ?
I want to post the email address on an opportunity custom field.
How do i get the contact email address through a opportunity contact role?
Make it a lookup field
Once you have this trigger in place (or even without it, actually) you can create a workflow rule to populate an email field.
How would I add two custom fields to the trigger to be filled in? In the section below. The two custom fields are
Primary_Contact_Role_Email__c
Contact_First_Name__c
// IF PRIMARY IS DEFINED THEN THIS WILL BE THE FIRST OBJECT. IF NOT THE FIRST ADDED CONTACT ROLE WILL BE ADDED...
o.Opportunity_contact__c = contactRoleArray[0].ContactID;
}else{
I added phone and email via Workflow rule.
Yes, that's what I have but I was trying to add it to the trigger to get it all in one shot.
How do you add the email with a workflow?
Here is my workaround with the info gathered here:
1. Custom Email Field
2. Custom Primary Contact Field
3. Trigger which updates the two custom fields with the Primary Contact in Contact Role.
4. Workflow rule using Custom Email Field
Mattias Nordin
Thank you for your solution, what do i need to do to get the contact name rather than the ID coming through?