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
travis.truetttravis.truett 

Apex Trigger Error When Updating Opportunity

I'm getting the following error when I try to set an opportunity to closed won:

Error:Apex trigger Create_followup caused an unexpected exception, contact your administrator: Create_followup: execution of BeforeUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, editSchedule: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0 with id 00oU0000002ulNkIAI; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id] Trigger.editSchedule: line 144, column 1: []: Trigger.Create_followup: line 88, column 1

The two triggers mentioned in the error are both triggers I wrote. Can anyone tell me what this type of error might be caused by?

Thanks
Best Answer chosen by travis.truett
R Z KhanR Z Khan
Oops. my bad. try following link. it has an example how to avoid recursion. Basically u need a static boolean that u set to true first time u run a  trigger but before u set it to true or run any logic in the trigger u make sure that this boolean is false
https://help.salesforce.com/apex/HTViewSolution?id=000133752&language=en_US

All Answers

CodeITCodeIT
Insert will fail if you specify the ID in your object, e.g.
/*Code Formatted by ForceXtra.com*/
Account newAcc = new  Account(Id = '0010000000132ad2', name = 'abc');
insert newAcc;

 
R Z KhanR Z Khan
Can you post your code?
If records already existed you need to call an update, not insert. If you are modifying records from the trigger in before update then you don't need to make a DML call at all. it will jsut take your changes and commit to DB
travis.truetttravis.truett
That's what I don't understand, though. Neither of these two triggers reference a specific Id number. Further, both of these triggers have been running fine for months, but for some reason, with this particular opportunity, this error is being thrown.
R Z KhanR Z Khan
Can you post the code. its hard to tell what your trigger is doing
travis.truetttravis.truett
There are two triggers firing, one that automatically duplicates the opportunity and creates a followup opportunity, and another that edits the revenue schedule of the followup opportunity. I'll post both:

1: Create Followup

trigger Create_followup on Opportunity (before update, after insert) {
    List<Pricebook2> standardBook = [SELECT Id FROM Pricebook2 WHERE Name = :'Ambition'];//Create an instance of the standard pricebook
    
    if(Trigger.isUpdate){
        List<Opportunity> listOppor = new List<Opportunity>();
        for (Opportunity o: Trigger.new){
            if (o.StageName == 'Closed Won' && o.Stage_Change__c == false){

                Opportunity oppNew = o.clone();
                if(Integer.valueOf(o.Duration__c) >= 12){
                oppNew.Is_Renewal__c = true;
                } else{
                oppNew.Is_Renewal__c = false;
                }
                oppNew.Name = oppNew.Name.substringBefore('-')  + '- ' + Integer.valueOf(o.Seats__c) + 'U.' + Integer.valueOf(o.Duration__c) + 'M.' + o.Discounted_Price__c + '$' + ' = ' + o.Total__c;
                
                if(o.Renewal_Date__c != null){
                oppNew.Renewal_Date__c = o.Renewal_Date__c.addYears(1);
                oppNew.CloseDate = o.Renewal_Date__c;
                oppNew.Contract_Start_Date__c = o.Renewal_Date__c;}
                
                oppNew.StageName = 'Discovery';
                oppNew.Probability = 25;
                oppNew.Parent_Opportunity__c = o.Id;
                
                
                oppNew.Pricebook2Id = standardBook[0].Id;//associate the standard pricebook with this opportunity
                
                oppNew.Is_Clone__c = true;
                listOppor.add(oppNew);
                o.Stage_Change__c = true;
                
            }

        }//end of for loop

        if(listOppor.size() > 0){
            insert listOppor;
            
            List<OpportunityContactRole> ocrList = [SELECT OpportunityId, ContactId, Role FROM OpportunityContactRole WHERE OpportunityId IN :Trigger.New];
            List<OpportunityContactRole> newOcrList = new List<OpportunityContactRole>();

            if(!ocrList.isEmpty()) {
                Map<Id, Id> oldOpNewOpIdMap = new Map<Id, Id>();
                for(Opportunity opNew : listOppor) {
                    oldOpNewOpIdMap.put(opNew.Parent_Opportunity__c, opNew.Id);
                }   
                for(OpportunityContactRole ocr : ocrList) {
                    OpportunityContactRole newOcr = new OpportunityContactRole();
                    newOcr.ContactId = ocr.ContactId;
                    newOcr.Role = ocr.Role;
                    newOcr.OpportunityId = oldOpNewOpIdMap.get(ocr.OpportunityId);
                    newOcrList.add(newOcr);
                }
                insert newOcrList;
            }
            
          List<OpportunityLineItem> oliList = [SELECT OpportunityId, PricebookEntryId, UnitPrice, Quantity, Duration__c, Payment_Terms__c, Discount, Product2.Family FROM OpportunityLineItem WHERE OpportunityId IN :Trigger.New];
          List<OpportunityLineItem> newoliList = new List<OpportunityLineItem>();
          
          if(!oliList.isEmpty()) {
                Map<Id, Id> oldOpNewOpIdMap2 = new Map<Id, Id>();
               for(Opportunity opNew : listOppor) {
                    oldOpNewOpIdMap2.put(opNew.Parent_Opportunity__c, opNew.Id);
                }   
                
                for(OpportunityLineItem oli : oliList) {
                    
                    if(oli.Product2.Family == 'Enterprise Product'){
                    
                    OpportunityLineItem newOli = new OpportunityLineItem();
                    newOli.UnitPrice = oli.UnitPrice;
                    
                    newOli.PricebookEntryId = oli.PricebookEntryId;
                    newOli.Quantity = oli.Quantity;
                    newOli.Duration__c = 12;
                   
                    newOli.Payment_Terms__c = oli.Payment_Terms__c;
                    newOli.Discount = oli.Discount;
                    
                    newOli.OpportunityId = oldOpNewOpIdMap2.get(oli.OpportunityId);
                    
                    
                    newoliList.add(newOli);
                    }
                }
                
                insert newoliList;
            }

            
        }
        
        

    }

    if(trigger.isInsert){
        try{
            //OpportunityLineItem[] lines = new OpportunityLineItem[0];
            //PricebookEntry entry = [SELECT Id, UnitPrice FROM PricebookEntry WHERE Pricebook2Id = :standardBook.Id AND Product2.ProductCode = 'ENTERPRISE_ANNUAL_UPFRONT'];
            List<Event> eventList = new List<Event>();
            //List<Note> noteList = new List<Note>();


List<User> lsuserRecords=[Select Id FROM User WHERE Alias='cwilli'];



            for(Opportunity o: Trigger.new){
                if(o.Is_Clone__c == true){

                    //noteList.add(new Note(ParentId=o.id,Title='Matt is the Apex_God',Body='Matt is the Apex_God',isPrivate=false));

                    //lines.add(new OpportunityLineItem(PricebookEntryId=entry.Id, OpportunityId=o.Id, UnitPrice=entry.UnitPrice, Quantity=1));

                    if(o.Renewal_Date__c != null){
                    
                    if(lsuserRecords!=null && !lsuserRecords.isEmpty())
{

                        DateTime myDateTime = o.Renewal_Date__c.addMonths(-10);
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime,subject='Account Management Follow-Up', EndDateTime=myDateTime, IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(2),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(2), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(4),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(4), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(6),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(6), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(8),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(8), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Renewal',EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
                        eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(9),subject='Sales Contract Follow-Up',EndDateTime=myDateTime.addMonths(9), IsAllDayEvent=true, OwnerId = lsuserRecords[0].id));
}
                    }//end of if

                }
            }
            //insert lines;
            insert eventList;
            //insert noteList;

        }
        catch(Exception e){

        }
    }
}


2: Edit Schedule


trigger editSchedule on OpportunityLineItem (after insert) {

if(Trigger.isInsert){

Map<Id, Opportunity> opportunities = new Map<Id, Opportunity>();
Date myDate = Date.newInstance(1990, 2, 17);

for(OpportunityLineItem oli: Trigger.new) {
    opportunities.put(oli.OpportunityId, null);
}
opportunities.putAll([SELECT Contract_Start_Date__c FROM Opportunity WHERE Id in :opportunities.keySet()]);
for(OpportunityLineItem oli: Trigger.new) {
     Opportunity thisLineItemOpp = opportunities.get(oli.OpportunityId);
     myDate = thisLineItemOpp.Contract_Start_Date__c;
      // thisLineItemOpp.CloseDate is the close date you're looking for
}

List<OpportunityLineItemSchedule> listOLIS = new List<OpportunityLineItemSchedule>();




for (OpportunityLineItem oli: Trigger.new){
Set<Id> setOpptyOLI = new set<Id>();
setOpptyOLI.add(oli.Id);
List<OpportunityLineItem> OpptyOlilst=[Select Product2.Family FROM OpportunityLineItem WHERE Id IN:setOpptyOLI ];

Decimal DiscountedPrice;



DiscountedPrice = oli.Discounted_Price__c;


if(oli.Payment_Terms__c == 'Monthly'){

for(OpportunityLineItem record : OpptyOlilst){
if(record.Product2.Family=='Services'){
    
    
for(Integer duration = (Integer)oli.Duration__c; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity/oli.Duration__c, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addMonths(1);

}//end of loop
    
    }//end of inner IF
    
else {
for(Integer duration = (Integer)oli.Duration__c; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addMonths(1);

}//end of loop

}//end of else

}//end of OpptyOlilstForLoop

}//end of Monthly IF


    else if(oli.Payment_Terms__c == 'Quarterly'){
    
for(OpportunityLineItem record : OpptyOlilst){
if(record.Product2.Family=='Services'){
    
for(Integer duration = (Integer)oli.Duration__c/3; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity*3/oli.Duration__c, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addMonths(3);

}//end of loop
    
    }//end of inner IF

else{
for(Integer duration = (Integer)oli.Duration__c/3; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity*3, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addMonths(3);

}//end of loop

}//end of else

}//end of OpptyOlilstForLoop

}//end of Quarterly IF


    else if(oli.Payment_Terms__c == 'Annually'){
    
for(OpportunityLineItem record : OpptyOlilst){
if(record.Product2.Family=='Services'){
          
    
for(Integer duration = (Integer)oli.Duration__c/12; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity*12/oli.Duration__c, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addYears(1);

}//end of loop
    
    }//end of inner IF

else{
for(Integer duration = (Integer)oli.Duration__c/12; duration > 0; duration--){

listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity*12, ScheduleDate = myDate, Type = 'Revenue'));
myDate = myDate.addYears(1);

}//end of loop

}//end of else

}//end of OpptyOlilstForLoop

}//end of Annually IF


    else if(oli.Payment_Terms__c == 'Up Front'){
    
for(OpportunityLineItem record : OpptyOlilst){
if(record.Product2.Family=='Services'){
    
    
listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity, ScheduleDate = myDate, Type = 'Revenue'));
  
    }//end of inner IF

else{
listOLIS.add(new OpportunityLineItemSchedule(OpportunityLineItemId = oli.Id, Revenue = DiscountedPrice*oli.Quantity*oli.Duration__c, ScheduleDate = myDate, Type = 'Revenue'));

}//end of else

}//end of OpptyOlilstForLoop

}//end of Up Front IF 


insert listOLIS;

}

}//end of isInsert

}//end of trigger
R Z KhanR Z Khan
When you insert OpportunityLineItemSchedule on OpportunityLineItem trigger it causes a recursive trigger. Use the link below to avoid recursion
https://developer.salesforce.com/docs/atlas.en-us.cookbook.meta/cookbook/apex_controlling_recursive_triggers.htm

let me knwo if it helps
travis.truetttravis.truett
Thanks for the help. The page you linked isn't working, though. It's just a blank page. Also, which line of the trigger are you referring to that's making the recursive call?
R Z KhanR Z Khan
Oops. my bad. try following link. it has an example how to avoid recursion. Basically u need a static boolean that u set to true first time u run a  trigger but before u set it to true or run any logic in the trigger u make sure that this boolean is false
https://help.salesforce.com/apex/HTViewSolution?id=000133752&language=en_US
This was selected as the best answer
travis.truetttravis.truett
Ok, I'll look into that. Thank you.
R Z KhanR Z Khan
You welcome!
Don;t forget to mark the question as resolved if it works for you.

Good luck!
travis.truetttravis.truett
I tried to add the code to stop the recursive calling of the trigger, but when I try to save the code, I get an unexpected token error. It doesn't like that I'm adding a class before the beginning of the trigger, even though that's how it's shown in the page you linked.
R Z KhanR Z Khan
You need to create a separate class and reference it in your trigger
travis.truetttravis.truett
Oh, ok. thanks