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
SMGSFDCDEVSMGSFDCDEV 

AfterInsert Error on Opportunity Trigger

Thanks for your contribution 

Hello Salesforce/Apex Developers
I am receiving the following error when I try to fire a trigger that associates the PrimaryContactRole in a custom contact field on a newly created Opportunity:

"Apex trigger InsertPrimaryContactonOpportunity caused an unexpected exception, contact your administrator: InsertPrimaryContactonOpportunity: execution of AfterInsert caused by: System.FinalException: Record is read-only: Trigger.InsertPrimaryContactonOpportunity: line 11, column 1"

/*
Date: November 14th, 2011
Description: This trigger inserts the Contact to the Opportunity based on the Primary Contact associated on the ContactRole
*/
 
trigger InsertPrimaryContactonOpportunity on Opportunity (after insert, before update) {
 
for(Opportunity o : Trigger.new){
 
   if(o.AssociatecnttoOpp__c = true){
OpportunityContactRole contactRole = 
[Select ContactID from OpportunityContactRole where isPrimary = true and OpportunityID = :o.Id];
if(contactRole != null){
o.Contact__c = contactRole.ContactID;
}
}
 
}
}

This trigger works correctly if I take out the after insert DML operation.  But this does not work if I put the after Insert DML operation.

At first I thought this could be an issue with the Sharing Settings related to the opportunity standard object.  But then I changed all my sharing settings on my sandbox to READ/WRITE I still received the same error.

Does anybody know why this would occur with the AfterInsert DML operation and not the beforeUpdate operation?

SMGSFDCDEVSMGSFDCDEV

Any additional help you could provide would be appreciated as well

Hello SeanRipTide

First off, thank you for the response.  I greatly appreciate your contribution.

 

I actually tried entering the before insert DML operation as well and I received the following error when I replaced “After Insert” with “Before Insert”:

 

Description: https://cs7.salesforce.com/s.gif

Opportunity Edit
 

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger InsertPrimaryContactonOpportunity caused an unexpected exception, contact your administrator: InsertPrimaryContactonOpportunity: execution of BeforeInsert caused by: System.QueryException: List has no rows for assignment to SObject: Trigger.InsertPrimaryContactonOpportunity: line 12, column 1

 

 

_Prasu__Prasu_

In first case "AFTER INSERT" trigger,

It is not allowed to assign a value to field of the records on which trigger has fired. So its giving you the error.

 

In the second case i.e. "BEFORE INSERT" trigger,

Opportunity is created in the Salesforce but not commited, so its related Contact doesnot exsits in the Salesforce. In trigger you are making a query on the ContactRoles and its returnining no results. so its giving an exception.

 

I hope this helps

SMGSFDCDEVSMGSFDCDEV

Hi eprasu

Thank you for the response.  now I understand I can only use the "before Update" DML operation.

 

Can you please let me know what I am doing incorrectly with this test class for the above trigger.  I have 0% coverage code and can't figure out why:

 


@isTestprivate class TestContactonOpportunity{static testMethod void testInsertPrimaryContactonOpp(){
test.startTest();//Setup the Account recordAccount a = new Account(Name='TestAccount');insert a;//Setup the Opportunity recordString opportunityName = 'My Opp';Opportunity o = new Opportunity(AccountID = a.Id, Name=opportunityName, StageName='Indication', CloseDate=Date.today());insert o;test.stopTest();}
}

SMGSFDCDEVSMGSFDCDEV

Test class associated with Apex Trigger above:

 


@isTestprivate class TestContactonOpportunity{static testMethod void testInsertPrimaryContactonOpp(){
test.startTest();

 

//Setup the Account record

Account a = new Account(Name='TestAccount');

insert a;

//Setup the Opportunity recordString

opportunityName = 'My Opp';

Opportunity o = new Opportunity(AccountID = a.Id, Name=opportunityName, StageName='Indication', CloseDate=Date.today());

insert o;

test.stopTest();}
}

SMGSFDCDEVSMGSFDCDEV

Hi Prasana

Below is the test class I wrote for this trigger.  Unfortunately, after running this test class returns 0% code coverage for this trigger.  I thought this would at least cover part of the instantiation of the creation Opportunity:

 

//Annotation used in every Test class on Opportunities
@isTest

private class TestContactonOpportunity{
static testMethod void testInsertPrimaryContactonOpp(){


//Start the test
test.startTest();

//Create an Account
Account a = new Account(Name='TestAccount');
insert a;

//Create a Contact
Contact c = new Contact(firstname='Barack',lastname='Obama',accountid = a.id,email='test@cnn.com');
insert c;

//Setup the Opportunity record
String opportunityName = 'Obama opp';
Opportunity o = new Opportunity
(contact__c = c.id, AccountID = a.Id, name = 'Opportunity Name',
stagename='stagename',closedate=System.today());

o.CloseDate = date.valueOf('2011-01-01');
o.Name = 'Test Opp';
o.Amount = 500000;
o.StageName='Prospecting';
o.Contact__c = c.Id;
o.AssociateCntToOpp__c = true;
insert o;

o = [Select Name, Amount, Investor_Name__c, Contact__c from Opportunity where id = :o.Id];

//System.assertEquals(o.Contact__c, o.Id);




//Stop the Test
test.stopTest();

}

}

_Prasu__Prasu_

From all your comments it seems you have written trigger on before update event, and in test method you have just inserted opportunity and you are not updating it. Thats why its not firing trigger.

//Add at last 
update o;

 

 

SMGSFDCDEVSMGSFDCDEV

Hi Prasana

Thank you for the quick response.  That makes complete sense.

 

After I added the "update o" line of code I received the following error:

 

System.DmlException: Update failed. First exception on row 0 with id "006......."; first error: CANNOT_INSERT_UPDATE_ACTIVITY_ENTITY, InsertPrimaryContactonOpportunity, execution of update failed.

 

Pls let me know if you have any ideas why this is happening.

 

btw...I really liked your blog, some useful methods

SMGSFDCDEVSMGSFDCDEV

Hi Prasana

Here is the full error message:

 

"System.DmlException: Update failed. First exception on row 0 with id 006M0000003LEAGIA4; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, InsertPrimaryContactonOpportunity: execution of BeforeUpdate caused by: System.QueryException: List has no rows for assignment to SObject Trigger.InsertPrimaryContactonOpportunity: line 19, column 1: []"

SMGSFDCDEVSMGSFDCDEV

Hi Prasana

I got much further and was able to obtain 100% code coverage on this trigger for both the Opportunity and OpportunityContactRole objects.

 

Current, my trigger is hung up on the following error message:

 

System.DmlException: Update failed. First exception on row 0 with id 006M0000003LEQRIA4; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, InsertPrimaryContactonOpportunity: execution of BeforeUpdate caused by: System.ListException: List index out of bounds: 0 Trigger.InsertPrimaryContactonOpportunity: line 23, column 1: []

 

After adding the Collections List I was able to get past the previous error.  Now the List I have is returning an Index out of bounds message:

 

//This trigger can only use the Before Update DML operation because the contact id of Contact Roles
//have to be queried after adding the Opportunity is added to salesforce
trigger InsertPrimaryContactonOpportunity on Opportunity (before update) {

//Enhanced For Loop that creates a Set of the Opportunities to be queried
for(Opportunity o : Trigger.new){


//The custom field AssociatedcnttoOpp__c is automatically checked
if(o.AssociatecnttoOpp__c = true){

 

//Create an object for the OpportunityContactRole to query all the contacts where the contact is set to Primary on the Contact Role
List<OpportunityContactRole> contactRole = new List<OpportunityContactRole>();
contactRole = [Select ContactID from OpportunityContactRole where isPrimary = true and OpportunityID = :o.Id];
if(contactRole != null){

 

 

//Assign the custom Contact__c field to the contact ID related to the contactRole of the opportunity
o.Contact__c = contactRole[0].ContactID;

}

}
}

 

 

 

if possible, can you please let me know where I am going wrong with the following code

SMGSFDCDEVSMGSFDCDEV

Prasana

First off, thank you for all your help on this.  I could not have got this far without your guidance.

 

Last question:  I have the trigger fully working and 83% code coverage on the trigger.

How would I write a test method to cover the following line of the code:

o.Contact__c = contactRole[0].ContactID;

 

  contactRole = [Select ContactID, Contact.Name from OpportunityContactRole where isPrimary = true and OpportunityID = :o.Id limit 1];
      if(contactRole.size()>0 && contactRole != null)
      {
        //Assign the custom Contact__c field to the contact ID related to the contactRole of the opportunity
        o.Contact__c = contactRole[0].ContactId;
_Prasu__Prasu_

try creating OpportunityContactRole record in test method after inserting Opportunity ;)

SMGSFDCDEVSMGSFDCDEV

Hi Prasana

I tried that with the following lines of code in the test class:

 

OpportunityContactRole contactRole = new OpportunityContactRole();
contactRole.IsPrimary = true;
contactRole.Role = 'Advisor';

//assign the ContactID on the Contact Role to the ID on the Contact object
contactRole.ContactId = c.id;

//assign the Opportunity ID on the contact Role to the ID on the Opportunity object
contactRole.OpportunityId = o.id;

//contactRole = [Select ID from OpportunityContactRole where isPrimary = true];
insert contactRole;

 

 

The only line of code that Eclipse is stating that I have not covered is this in the body of my trigger:

      //Assign the custom Contact__c field to the contact ID related to the contactRole of the opportunity
        o.Contact__c = contactRole[0].ContactId;

 

any thoughts?

thanks