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
Serghei SleptovSerghei Sleptov 

Trigger that fires on Account change

I need a trigger that if there is a change on Account record gets all the Opportunities and Opportunity Products belong to that Account refreshed (edit and saved) using the updated information from parent Account record.
Can anybody advise?

Thank you,
Serghei
Best Answer chosen by Serghei Sleptov
mjohnson-TICmjohnson-TIC
Oops, I tried to update the <Id> list instead of the <sObject> list. Try this.
trigger AccountTrigger on Account (after update) {
	list<Id> al = new list<Id>();
	list<Id> ol = new list<Id>();
	list<Opportunity> ops = new list<Opportunity>();
	list<OpportunityLineItem> ils = new list<OpportunityLineItem>();
	for (Integer i = 0; i < trigger.new.size(); i++){
		if(trigger.old[i].FieldName != trigger.new[i].FieldName){
			al.add(trigger.new[i].Id);
		}
	}	
	if(al != null){
		try{
			for(Opportunity o: [Select Id from Opportunity where AccountId in: al]){
				ops.add(o);
				ol.add(o.Id);
			}
		}catch(exception e){
			
		}
		if(ol !=  null){
			try{
				for(OpportunityLineItem l: [Select Id from OpportunityLineItem where OpportunityId in: ol]){
					ils.add(l);
				}
			}catch(exception e){
				
			}
		}		
	}
	if(ops != null){	
		update ops;
	}
	if(ils != null){
		update ils;
	}	
}

All Answers

Balaji BondarBalaji Bondar
Hi Serghei,

Below is an example of trigger to update related Opportunities based on Account changes.Update this trigger based on your business need.
 
trigger updateopportunities on Account(after update) 
{
    Set<Id> accountIds = new Set<Id>();

    for(Account ac : Trigger.new)
    {
         if(ac.Status__c=='Cancelled')
              accounIds.add(ac.Id);
    }

     List<Opportunity> oppsToUpdate = new List<Opportunity>();

     for(Opportunity opp : [select id, StageName from Opportunity where AccountId in: accountIds])
     {
          opp.StageName='Closed - Cancelled';
          oppsToUpdate.add(opp);
     }

     update oppsToUpdate;
}

 
mjohnson-TICmjohnson-TIC
trigger AccountTrigger on Account (after update) {
	list<Id> al = new list<Id>();
	list<Id> ol = new list<Id>();
	list<Opportunity> ops = new list<Opportunity>();
	list<OpportunityLineItem> ils = new list<OpportunityLineItem>();
	for (Integer i = 0; i < trigger.new.size(); i++){
		if(trigger.old[i].FieldName != trigger.new[i].FieldName){
			al.add(trigger.new[i].Id);
		}
	}	
	if(al != null){
		try{
			for(Opportunity o: [Select Id from Opportunity where AccountId in: al]){
				ops.add(o);
				ol.add(o.Id);
			}
		}catch(exception e){
			
		}
		if(ol !=  null){
			try{
				for(OpportunityLineItem l: [Select Id from OpportunityLineItem where OpportunityId in: ol]){
					ils.add(l);
				}
			}catch(exception e){
				
			}
		}		
	}
	if(ops != null){	
		update ol;
	}
	if(ils != null){
		update ils;
	}	
}

This should do it - keep in mind limits though.
Serghei SleptovSerghei Sleptov

Hi, mjohnson-TIC,

Thanks for your help, however it failed with the following error:

# Deploy Results:
   File Name:    triggers/AccountTrigger.trigger
   Full Name:  AccountTrigger
   Action:  NO ACTION
   Result:  FAILED
   Problem: DML requires SObject or SObject list type: LIST<Id>

 

mjohnson-TICmjohnson-TIC
Oops, I tried to update the <Id> list instead of the <sObject> list. Try this.
trigger AccountTrigger on Account (after update) {
	list<Id> al = new list<Id>();
	list<Id> ol = new list<Id>();
	list<Opportunity> ops = new list<Opportunity>();
	list<OpportunityLineItem> ils = new list<OpportunityLineItem>();
	for (Integer i = 0; i < trigger.new.size(); i++){
		if(trigger.old[i].FieldName != trigger.new[i].FieldName){
			al.add(trigger.new[i].Id);
		}
	}	
	if(al != null){
		try{
			for(Opportunity o: [Select Id from Opportunity where AccountId in: al]){
				ops.add(o);
				ol.add(o.Id);
			}
		}catch(exception e){
			
		}
		if(ol !=  null){
			try{
				for(OpportunityLineItem l: [Select Id from OpportunityLineItem where OpportunityId in: ol]){
					ils.add(l);
				}
			}catch(exception e){
				
			}
		}		
	}
	if(ops != null){	
		update ops;
	}
	if(ils != null){
		update ils;
	}	
}
This was selected as the best answer
Serghei SleptovSerghei Sleptov

Perfect!

can you also help me to build Test coverage on that trigger?

Thank you

mjohnson-TICmjohnson-TIC
This should work if you don't have any validation rules I do not meet. If so, you may need to update fields on objects created in the test methods to fit your validations.
 
@isTest  
private class TestClass {
    static testmethod void AccountTrigger_Coverage(){       
        Account a = new Account();
        a.name = 'Test Account';
        insert a;
        Opportunity o = new Opportunity();
        o.Name = 'test';
        o.AccountId = a.Id;
        o.StageName = 'Discovery';
        o.Application_Category__c = 'test';
        o.Description = 'test';
        insert o;  
        Product2 p = new Product2();
        p.Name = 'Test Product';
        p.ProductCode = 'test';
        insert p;           		      	
		Pricebook2 b = new Pricebook2();
		b.IsActive = true;
		b.Description  = 'test';
		b.Name = 'test';
		insert b;
        PricebookEntry pb =  new PricebookEntry(pricebook2id = b.id, product2id = p.id, unitprice=1.0, isActive=true);
        insert pb;
		OpportunityLineItem ol = new OpportunityLineItem(opportunityid=o.id, pricebookentryid=pb.id, unitprice=1.0, quantity=2);
		insert ol;
		update a;
    }        
       
}

 
Serghei SleptovSerghei Sleptov

Thanks. mjohnson-TIC,

however it gave me an error:

Insert failed. First exception on row 0;
first error: STANDARD_PRICE_NOT_DEFINED, No standard price defined for this product
Can you tell me how I can set STANDARD_PRICE in test ?

Thank you

 

mjohnson-TICmjohnson-TIC
Ah, I forgot you cannot create a standard price book through api. Try this.
 
@isTest  
private class TestClass {
    static testmethod void AccountTrigger_Coverage(){       
        Account a = new Account();
        a.name = 'Test Account';
        insert a;
        Opportunity o = new Opportunity();
        o.Name = 'test';
        o.AccountId = a.Id;
        o.StageName = 'Discovery';
        o.Application_Category__c = 'test';
        o.Description = 'test';
        insert o;  
        Product2 p = new Product2();
        p.Name = 'Test Product';
        p.ProductCode = 'test';
        insert p;           		      	
		Pricebook2 b = [select Id from Pricebook2 where isStandard=true limit 1];
        PricebookEntry pb =  new PricebookEntry(pricebook2id = b.id, product2id = p.id, unitprice=1.0, isActive=true);
        insert pb;
		OpportunityLineItem ol = new OpportunityLineItem(opportunityid=o.id, pricebookentryid=pb.id, unitprice=1.0, quantity=2);
		insert ol;
		update a;
    }        
       
}

 
Serghei SleptovSerghei Sleptov

Thank you!

it is working now!

One more question: in the trigger if I want to monitor 2 fields change : Parent Account and/or another custom field, I think Ishould modify this line?
can you help me with correct syntax?

if(trigger.old[i].Total_All_Number_Fields__c != trigger.new[i].Total_All_Number_Fields__c){
            al.add(trigger.new[i].Id);
 

mjohnson-TICmjohnson-TIC
Use || for the OR syntax and && for AND.

if(trigger.old[i].Field1 != trigger.new[i].Field1 || trigger.old[i].Field2 != trigger.new[i].Field2){
Serghei SleptovSerghei Sleptov

Perfect!

Thanks a million!!!