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
Josh LauerJosh Lauer 

Trigger Before Update Error

Hi

I am a newbie and I wrote the trigger code below to test a field to see whetherit has been updated then if so call new code...  when i runs i get the error below..  If anyone can help me to resolveit, would be greatly appreciated
THe code is meant to check Pricebook2id to see if it has changed, then if it has changed load all the products from the pricebook into the opportunity

Update failed. First exception on row 0 with id 00661000002hNvAAAU; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, UpdateProduct: execution of BeforeUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: PricebookEntryId (pricebook entry is in a different pricebook than the one assigned to the opportunity): [PricebookEntryId] Class.PricebookPicklist.updateRecords:"
 
trigger UpdateProduct on Opportunity (before update) {    for(Opportunity o: Trigger.new)
    {
        if(system.trigger.OldMap.get(o.Id).Pricebook2Id != system.trigger.NewMap.get(o.Id).Pricebook2Id)
        {
            //Populate records
            PricebookPicklist obj = new PricebookPicklist();
            obj.updateRecords(system.trigger.NewMap.get(o.Id).Id, system.trigger.NewMap.get(o.Id).Pricebook2Id);
   
            o.NextStep = 'Changed';
           
        }
        else
        {
            o.NextStep = 'Unchanged';
        }
    }
}

   public PageReference updateRecords(String oppid, String id)
    {
        Opportunity opp = [Select pricebook2Id from Opportunity where Id = :oppid]; //Find opportunity page using the parameter
        List<PricebookEntry> pbeList = [Select Product2.ProductCode, UnitPrice, Product2ID From PricebookEntry where pricebook2Id = :id];
        List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
        for(PricebookEntry pbe: pbeList)
         {
                OpportunityLineItem oli = new OpportunityLineItem();
                oli.OpportunityId = opp.id;
                oli.PricebookEntryId = pbe.id;
                oli.Quantity = 1;
                oli.UnitPrice = pbe.UnitPrice;
                oliList.add(oli);
        }
        insert oliList;
        return null;  
    }

 
Best Answer chosen by Josh Lauer
Abhishek BansalAbhishek Bansal
Hi Josh,

I have go through the code of your trigger and figure out what you want to achieve.
Please change your trigger code from below mentioned code :
 
trigger UpdateProduct on Opportunity (before update, after update) {    
	if(trigger.isBefore && trigger.isUpdate){
		for(Opportunity opp : trigger.new){
			Opportunity oldOpp = trigger.oldMap.get(opp.id);
			if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
				opp.NextStep = 'Changed';
			}
			else{
				opp.NextStep = 'Unchanged';
			}
		}
	}
	
	if(trigger.isAfter && trigger.isUpdate){
		Map<Id,Id> priceBookIdWithOppId = new Map<Id,Id>();
		for(Opportunity opp : trigger.new){
			Opportunity oldOpp = trigger.oldMap.get(opp.id);
			if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
				priceBookIdWithOppId.put(opp.Pricebook2Id,opp.id);
			}
		}
		Map<Id,PricebookEntry> pbeMap = new Map<Id,PricebookEntry>([Select pricebook2Id,Product2.ProductCode, UnitPrice, Product2ID From PricebookEntry where pricebook2Id = :priceBookIdWithOppId.keySet()]);
		List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
		OpportunityLineItem oli;
    	for(PricebookEntry pbe: pbeMap.values()){
    		oli = new OpportunityLineItem();
            oli.OpportunityId = priceBookIdWithOppId.get(pbe.pricebook2Id);
            oli.PricebookEntryId = pbe.id;
            oli.Quantity = 1;
            oli.UnitPrice = pbe.UnitPrice;
            oliList.add(oli);
    	}
    	if(oliList.size() > 0){
    		insert oliList;
    	}
	}
}

As we can only update any other object which is not related to current object of trigger in AFTER event only so i have written the code to update OLI in after update trigger.
Hope this will help you and please let me know if you have any issues in it.

Thanks,
Abhishek

All Answers

Josh LauerJosh Lauer
Addendum: The above error is running a code if Pricebook2Id is already populated before. If Pricebook2Id is unpopulated, the following error is received: Update failed. First exception on row 0 with id 00661000002hNvAAAU; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, UpdateProduct: execution of BeforeUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 00661000002hNvA) is currently in trigger UpdateProduct, therefore it cannot recursively update itself: [] Class.PricebookPicklist.updateRecords: line 108, column 1 Trigger.UpdateProduct:
Abhishek BansalAbhishek Bansal
Hi Josh,

I have go through the code of your trigger and figure out what you want to achieve.
Please change your trigger code from below mentioned code :
 
trigger UpdateProduct on Opportunity (before update, after update) {    
	if(trigger.isBefore && trigger.isUpdate){
		for(Opportunity opp : trigger.new){
			Opportunity oldOpp = trigger.oldMap.get(opp.id);
			if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
				opp.NextStep = 'Changed';
			}
			else{
				opp.NextStep = 'Unchanged';
			}
		}
	}
	
	if(trigger.isAfter && trigger.isUpdate){
		Map<Id,Id> priceBookIdWithOppId = new Map<Id,Id>();
		for(Opportunity opp : trigger.new){
			Opportunity oldOpp = trigger.oldMap.get(opp.id);
			if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
				priceBookIdWithOppId.put(opp.Pricebook2Id,opp.id);
			}
		}
		Map<Id,PricebookEntry> pbeMap = new Map<Id,PricebookEntry>([Select pricebook2Id,Product2.ProductCode, UnitPrice, Product2ID From PricebookEntry where pricebook2Id = :priceBookIdWithOppId.keySet()]);
		List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
		OpportunityLineItem oli;
    	for(PricebookEntry pbe: pbeMap.values()){
    		oli = new OpportunityLineItem();
            oli.OpportunityId = priceBookIdWithOppId.get(pbe.pricebook2Id);
            oli.PricebookEntryId = pbe.id;
            oli.Quantity = 1;
            oli.UnitPrice = pbe.UnitPrice;
            oliList.add(oli);
    	}
    	if(oliList.size() > 0){
    		insert oliList;
    	}
	}
}

As we can only update any other object which is not related to current object of trigger in AFTER event only so i have written the code to update OLI in after update trigger.
Hope this will help you and please let me know if you have any issues in it.

Thanks,
Abhishek
This was selected as the best answer
Josh LauerJosh Lauer
Thank you so much Abhishek! That was exactly what I needed.

I do have one more issue: I'm trying to also clear the old items so it can change pricebooks without the user needing to manually delete the old items. I have code that works in an Apex Class but can't figure out where it needs to go in the Apex Trigger. At the moment I just have it grab a list of the old OpportunityLineItems, iterate through and delete them. That should work, I just have no idea where the code needs to go in order to run successfully.
 
trigger UpdateProduct on Opportunity (before update, after update) {    
    if(trigger.isBefore && trigger.isUpdate){
        for(Opportunity opp : trigger.new){
            Opportunity oldOpp = trigger.oldMap.get(opp.id);
            if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
                opp.NextStep = 'Changed';
            }
            else{
                opp.NextStep = 'Unchanged';
            }
        }
    }
    
    if(trigger.isAfter && trigger.isUpdate){
        Map<Id,Id> priceBookIdWithOppId = new Map<Id,Id>();
        
        double Quan;
        for(Opportunity opp : trigger.new){
            Opportunity oldOpp = trigger.oldMap.get(opp.id);
            List<OpportunityLineItem> oldItemList = [Select Id from OpportunityLineItem where OpportunityId = :oldOpp.id];
            Quan = trigger.oldMap.get(opp.id).Default_Product_Quantity__c;
            if(opp.Pricebook2Id != oldOpp.Pricebook2Id)
            {
                for(OpportunityLineItem item : oldItemList)
                {
                    delete(item);
                }
                priceBookIdWithOppId.put(opp.Pricebook2Id,opp.id);
            }
        }
        
        Map<Id,PricebookEntry> pbeMap = new Map<Id,PricebookEntry>([Select pricebook2Id,Product2.ProductCode, UnitPrice, Product2ID From PricebookEntry where pricebook2Id = :priceBookIdWithOppId.keySet()]);
        List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
        OpportunityLineItem oli;
        for(PricebookEntry pbe: pbeMap.values()){
            oli = new OpportunityLineItem();
            oli.OpportunityId = priceBookIdWithOppId.get(pbe.pricebook2Id);
            oli.PricebookEntryId = pbe.id;
            oli.Quantity = Quan;
            oli.UnitPrice = pbe.UnitPrice;
            oliList.add(oli);
        }
        if(oliList.size() > 0){
            insert oliList;
        }
    }
}

 
Abhishek BansalAbhishek Bansal
Hi Josh.,

I have updated your trigger as per your requirement.
Please find the modified trigger below :
 
trigger UpdateProduct on Opportunity (before update, after update) {    
    if(trigger.isBefore && trigger.isUpdate){
        for(Opportunity opp : trigger.new){
            Opportunity oldOpp = trigger.oldMap.get(opp.id);
            if(opp.Pricebook2Id != oldOpp.Pricebook2Id){
                opp.NextStep = 'Changed';
            }
            else{
                opp.NextStep = 'Unchanged';
            }
        }
    }
    
    if(trigger.isAfter && trigger.isUpdate){
        Map<Id,Id> priceBookIdWithOppId = new Map<Id,Id>();
        
        double Quan;
        for(Opportunity opp : trigger.new){
            Opportunity oldOpp = trigger.oldMap.get(opp.id);
            //List<OpportunityLineItem> oldItemList = [Select Id from OpportunityLineItem where OpportunityId = :oldOpp.id];
            Quan = trigger.oldMap.get(opp.id).Default_Product_Quantity__c;
            if(opp.Pricebook2Id != oldOpp.Pricebook2Id)
            {
                /*for(OpportunityLineItem item : oldItemList)
                {
                    delete(item);
                }*/
                priceBookIdWithOppId.put(opp.Pricebook2Id,opp.id);
            }
        }
        
        delete [Select id from OpportunityLineItem where OpportunityId IN :priceBookIdWithOppId.values()];
        
        Map<Id,PricebookEntry> pbeMap = new Map<Id,PricebookEntry>([Select pricebook2Id,Product2.ProductCode, UnitPrice, Product2ID From PricebookEntry where pricebook2Id = :priceBookIdWithOppId.keySet()]);
        List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
        OpportunityLineItem oli;
        for(PricebookEntry pbe: pbeMap.values()){
            oli = new OpportunityLineItem();
            oli.OpportunityId = priceBookIdWithOppId.get(pbe.pricebook2Id);
            oli.PricebookEntryId = pbe.id;
            oli.Quantity = Quan;
            oli.UnitPrice = pbe.UnitPrice;
            oliList.add(oli);
        }
        if(oliList.size() > 0){
            insert oliList;
        }
    }
}

Hope this will help you :)

Abhishek.
Josh LauerJosh Lauer
Hi Abhishek,

Unfortunately no luck. I'm getting the following error message:
Update failed. First exception on row 0 with id 00661000002hNvAAAU; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: Pricebook2Id (cannot change pricebook on opportunity with line items): [Pricebook2Id]

I think the main issue is that the old product items are still in Opportunity and I need to clear them. The delete doesn't seem to be running through. Would it be easier to do this as a Skype call?
Abhishek BansalAbhishek Bansal
Skype Id : abhishek.bansal2790
Vaibhav Parashar 2Vaibhav Parashar 2
Hi Guys, this is the exact requirement I have now. I am unable to delete the Opportunity Line Items. I want to automatically add line items on Price book Lookup change. Kindly Provide the solution, if you were able to figure it out.