+ Start a Discussion
BobBob 

Trigger to add before insert before update getting an error

I have a trigger that I am trying to add a before update to a before insert trigger but i keep getting the following error. 
What can I change on this code to make it allow insert and updates? I need it to set to 'true' for any new Quotes and 'false' for any Quotes that get updated?

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger MarkPrimaryQuote caused an unexpected exception, contact your administrator: MarkPrimaryQuote: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0Q0n0000000DRrLCAW; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 0Q0n0000000DRrL) is currently in trigger MarkPrimaryQuote, therefore it cannot recursively update itself: []: Trigger.MarkPrimaryQuote: line 19, column 1
 
trigger MarkPrimaryQuote on Quote (before insert, before update) {
    
  
 List<DateTime> oracleQuoteList = new List<DateTime>();
    for(Quote qRec : Trigger.new) {
    
    if(qRec == null )
        qRec.Primary_Quote__c = true;
        oracleQuoteList.add(qRec.Created_Date__c );      
    }
    
    List<Quote> quoteListToUpdate = new List<Quote>();
    for(Quote qRec : [SELECT id,Primary_Quote__c,Created_Date__c from Quote WHERE Created_Date__c= TODAY AND HOUR_IN_DAY(LastModifiedDate) > 1]) {
        qRec.Primary_Quote__c =false;
        quoteListToUpdate.add(qRec);    
    }
    
    if(quoteListToUpdate != null && quoteListToUpdate .size() > 0) {
        update quoteListToUpdate;
    }

  
  
}

 
Abhishek BansalAbhishek Bansal
Hi Bob,

You are getting this error because you are updating the same record in your before trigger and due to this the trigger is called again and again.
As per your requirement i have updated the trigger code as below :
trigger MarkPrimaryQuote on Quote (before insert, before update) {
	for(Quote qRec : Trigger.new){
		if(trigger.isInsert){
			qRec.Primary_Quote__c = true;
		}
		else if(trigger.isUpdate){
			//you can add your condition here if you want to add any
			//(qRec.Created_Date__c == TODAY && qRec.HOUR_IN_DAY(LastModifiedDate) > 1)
			qRec.Primary_Quote__c = false;
		}
	}
}

Please use and modify the above trigger accorddingly and let me know if you need more help or information on this.

Thanks,
Abhishek Bansal
Dhanya NDhanya N
Hi Bob,

When you use before insert or before update events, you no need to explicitly update list.

Thanks,
Dhanya
BobBob
How would i add a condition where if a quote fields have been updated, the primary quote checkbox is true. I want to add this code "if(Trigger.oldmap.get(qRec.id).Oracle_Quote__c!= qRec.Oracle_Quote__c ){}" in the trigger but i'm not sure where to add it. I need to have the following fields to checked for old and new values.
Stage__c , Oracle_Quote__c,Pricebook__c,Name, Net_Revenue__c,Amount__c,Order_Type__c. Any help would be greatly appreciated. 
 
Abhishek BansalAbhishek Bansal
Hi Bob,

I have updated the trigger code, Please find below the updated code :
trigger MarkPrimaryQuote on Quote (before insert, before update) {
	for(Quote qRec : Trigger.new){
		if(trigger.isInsert){
			qRec.Primary_Quote__c = true;
		}
		else if(trigger.isUpdate){
			//you can add your condition here if you want to add any
			Quote oldQuote = trigger.oldMap.get(qRec.id);
			//I have added the updation check for some fields and you can add more as per your requirement 
			if(oldQuote.Stage__c != qRec.Stage__c || oldQuote.Oracle_Quote__c != qRec.Oracle_Quote__c || oldQuote.Pricebook__c != qRec.Pricebook__c){
				qRec.Primary_Quote__c = false;
			}
		}
	}
}
I have added the updation check for some fields and you can add for more fields as per your requirement.
Please let me know if yopu need more help on this.

Thanks,
Abhishek Bansal
mritzimritzi
@Bob
trigger MarkPrimaryQuote on Quote (before insert, before update) {

	//this runs for all newly created Quote records just before they are inserted
    if(Trigger.isBefore && Trigger.isInsert){
		List<DateTime> oracleQuoteList = new List<DateTime>();
		for(Quote qRec:Trigger.new){
			qRec.Primary_Quote__c = true;
			oracleQuoteList.add(qRec.Created_Date__c );
		}
		// here you can do all that you want to do with oracleQuoteList
	}
	// this runs for all pre-existing Quote records just before they are updated 
	else if(Trigger.isBefore && Trigger.isBefore){
		for(Quote qRec:Trigger.new){
			qRec.Primary_Quote__c = false;
			if(Trigger.oldmap.get(qRec.id).Oracle_Quote__c!= qRec.Oracle_Quote__c ){
				// your logic goes here
				// check values of Stage__c , Oracle_Quote__c,Pricebook__c,Name, Net_Revenue__c,Amount__c,Order_Type__c
				
			}
		}
	}  
}


If this answer helps you out, please mark it as Best Answer.
BobBob
Abhishek Bansal, How can i get your trigger to only check the most recently inserted record and uncheck all others ?
Abhishek BansalAbhishek Bansal
Hi Bob,

The below section will check the recently inserted records :
trigger MarkPrimaryQuote on Quote (before insert, before update) {
	for(Quote qRec : Trigger.new){
		if(trigger.isInsert){
			//This will check recently inserted records
			qRec.Primary_Quote__c = true;
		}
	}
}

Please let me know if you need more information on this.

Thanks,
Abhishek Bansal
BobBob
What part of the code will uncheck all records that are not the most recent quote?
BobBob
mritzi, I added the following to the section of the trigger the is  // here you can do all that you want to do with oracleQuoteList. I'm trying to uncheck all the previous quotes primary checkbox's is a new quote is created. The new quote should get the check box checked. But the below code does not blank the quotes in the related list. 

for(Quote qRec : [SELECT id,Primary_Quote__c,Created_Date__c from Quote WHERE Created_Date__c= TODAY AND HOUR_IN_DAY(Created_Date__c) > 1]) {
        qRec.Primary_Quote__c =false;
          
    }
mritzimritzi
@Bob,
If all that you need to do is to mark the field Primary_Quote__c = true for each newly inserted record.
And mark it false for each recently updated record. Then the following trigger would serve the purpose for you.
trigger MarkPrimaryQuote on Quote (before insert, before update) {

	//this runs for all newly created Quote records just before they are inserted
    if(Trigger.isBefore && Trigger.isInsert){
		List<DateTime> oracleQuoteList = new List<DateTime>();
		for(Quote qRec:Trigger.new){
            // this sets the value to true, for all records that are updated
			qRec.Primary_Quote__c = true;
		}
	}
	// this runs for all pre-existing Quote records just before they are updated 
	else if(Trigger.isBefore && Trigger.isUpdate){
		for(Quote qRec:Trigger.new){
            // this sets the value to false, for all records that are updated
			qRec.Primary_Quote__c = false;
			}
		}
	}  
}


Remember: Trigger.new is a bulkified List. meaning that it contains all recently inserted and updated records from multiple instances.
You dont need to perform SOQL query to fetch recently updated Quotes. You already have it in this list.
Plus, You don't need to use Update/ Insert command on Quote records.
The purpose of the trigger is to perform some operations either before or after DML operation. After the logic ends, all the records are Inserted/Updated/Deleted by the system.

Updatation/Deletion/Insertion is already in progress or completed when a trigger is fired.

Mark this as Best Answer, if it solves your problem.
BobBob
The requirements for this trigger are as follows.
  1. Opportunity has a intial quote created the primary quote checkbox is checked.
  2. If there is another quote created, the quote with the newest created date should have the primary quote checkbox checked, the older created quote checkbox is unchecked.
  3. If there is a list of quotes, a user may update one of  the fields in one of the quotes  in Oracle, When this happen the newly updated quote is synced to SFDC and that quote should now have the primary checkbox checked and all others should be unchecked.

Does this make sense?

 
Abhishek BansalAbhishek Bansal
Hi Bob,

Yes your requirement makes sense and based on this i have creted a trigger code. Please find the triggercode below :
trigger MarkPrimaryQuote on Quote (before insert, before update) {
	List<Quote> quoteListToUpdate = new List<Quote>();
	
	Set<Id> opppIds = new Set<Id>();
	for(Quote qRec : Trigger.new){
		if(qRec.Opportunity__c != null){
			opppIds.add(qRec.Opportunity__c);
		}
	}
	Map<Id,Opportunity> mapOfOpps = new Map<Id,Opportunity>([Select id,(Select Primary_Quote__c from Quotes) from Opportunity where Id IN :opppIds]);
	if(trigger.isInsert){
		for(Quote qRec : Trigger.new){
			qRec.Primary_Quote__c = true;
		}
		for(Opportunity opp : mapOfOpps.values()){
			for(Quote existingQuote : opp.Quotes){
				existingQuote.Primary_Quote__c =false;
				quoteListToUpdate.add(existingQuote);
			}
		}
		if(quoteListToUpdate.size() > 0){
			update quoteListToUpdate;
		}
	}
	else if(trigger.isUpdate){
		for(Quote qRec : Trigger.new){
			Quote oldQuote = trigger.oldMap.get(qRec.id);
			if(oldQuote.Oracle_Quote__c != qRec.Oracle_Quote__c){//Please add other fields also if you want to check any
				qRec.Primary_Quote__c =false;
				
				if(qRec.Opportunity__c != null && mapOfOpps.containsKey(qRec.Opportunity__c)){
					for(Quote existingQuote : mapOfOpps.containsKey(qRec.Opportunity__c).Quotes){
						if(existingQuote.id != qRec.id){
							quoteListToUpdate.add(existingQuote);
						}
					}
				}
			}
		}
		if(quoteListToUpdate.size() > 0){
			update quoteListToUpdate;
		}
	}
}
Please take care of the API name of fields and any other syntax error as i have not tested this code.
Please let me know If you face any issue.

Thanks,
Abhishek Bansal
BobBob
Abhishek I received the following error  Invalid field Opportunity__c for SObject Quote at line 7 column 25 Then I changed the Opportunity__c to the Opportunity.Id field and received the following error message


Initial term of field expression must be a concrete SObject: Boolean at line 32 column 90

Thanks for your help
 
trigger MarkPrimaryQuote on Quote (before insert, before update) {
    List<Quote> quoteListToUpdate = new List<Quote>();
    
    Set<Id> opppIds = new Set<Id>();
    for(Quote qRec : Trigger.new){
        if(qRec.Opportunity.Id   != null){
            opppIds.add(qRec.Opportunity.Id  );
        }
    }
    Map<Id,Opportunity> mapOfOpps = new Map<Id,Opportunity>([Select id,(Select Primary_Quote__c from Quotes) from Opportunity where Id IN :opppIds]);
    if(trigger.isInsert){
        for(Quote qRec : Trigger.new){
            qRec.Primary_Quote__c = true;
        }
        for(Opportunity opp : mapOfOpps.values()){
            for(Quote existingQuote : opp.Quotes){
                existingQuote.Primary_Quote__c =false;
                quoteListToUpdate.add(existingQuote);
            }
        }
        if(quoteListToUpdate.size() > 0){
            update quoteListToUpdate;
        }
    }
    else if(trigger.isUpdate){
        for(Quote qRec : Trigger.new){
            Quote oldQuote = trigger.oldMap.get(qRec.id);
            if(oldQuote.Oracle_Quote__c != qRec.Oracle_Quote__c){//Please add other fields also if you want to check any
                qRec.Primary_Quote__c =false;
                
                if(qRec.Opportunity__c  != null && mapOfOpps.containsKey(qRec.Opportunity.Id  )){
                    for(Quote existingQuote : mapOfOpps.containsKey(qRec.Opportunity.Id).Quotes){
                        if(existingQuote.id != qRec.id){
                            quoteListToUpdate.add(existingQuote);
                        }
                    }
                }
            }
        }
        if(quoteListToUpdate.size() > 0){
            update quoteListToUpdate;
        }
    }
}

 
Abhishek BansalAbhishek Bansal
Hi Bob,

Please find the updated code below :
trigger MarkPrimaryQuote on Quote (before insert, before update) {
    List<Quote> quoteListToUpdate = new List<Quote>();
    
    Set<Id> opppIds = new Set<Id>();
    for(Quote qRec : Trigger.new){
        if(qRec.Opportunity.Id   != null){
            opppIds.add(qRec.Opportunity.Id  );
        }
    }
    Map<Id,Opportunity> mapOfOpps = new Map<Id,Opportunity>([Select id,(Select Primary_Quote__c from Quotes) from Opportunity where Id IN :opppIds]);
    if(trigger.isInsert){
        for(Quote qRec : Trigger.new){
            qRec.Primary_Quote__c = true;
        }
        for(Opportunity opp : mapOfOpps.values()){
            for(Quote existingQuote : opp.Quotes){
                existingQuote.Primary_Quote__c =false;
                quoteListToUpdate.add(existingQuote);
            }
        }
        if(quoteListToUpdate.size() > 0){
            update quoteListToUpdate;
        }
    }
    else if(trigger.isUpdate){
        for(Quote qRec : Trigger.new){
            Quote oldQuote = trigger.oldMap.get(qRec.id);
            if(oldQuote.Oracle_Quote__c != qRec.Oracle_Quote__c){//Please add other fields also if you want to check any
                qRec.Primary_Quote__c =false;
                
                if(qRec.Opportunity__c  != null && mapOfOpps.containsKey(qRec.Opportunity.Id  )){
                    for(Quote existingQuote : mapOfOpps.get(qRec.Opportunity.Id).Quotes){
                        if(existingQuote.id != qRec.id){
                            quoteListToUpdate.add(existingQuote);
                        }
                    }
                }
            }
        }
        if(quoteListToUpdate.size() > 0){
            update quoteListToUpdate;
        }
    }
}

Thanks,
Abhishek Bansal
BobBob
Abhishek, Thank you so much for your help. I was able to change the code to work like you have done. One more request. I've been trying to add an if statement to the update part of the code so it can compare the last modified date on all the qoute records and check the primary quote checkbox on the quote record with the most recently last modified date, but i havent had much success. Do you know how I can do this?