+ Start a Discussion
Tejasvi Rao 4Tejasvi Rao 4 

Help on a trigger.

Hello everyone,

I need help on writing a trigger. The requirement is to update a field named 'Account Status' on Account on basis of 3 of its child objects activites.

The 3 child objects of Account and its relationship with account :

Finance (custom obj) : look up relationship
Opportunities : Master-Detail relationship
Calls (Custom obj) : look up relationship

So, the requirement is to first check if Account has any Finance records associated with it. If Yes, then check if there are any opportunities linked to it. If the account has any opportunities linked to it, then check if any of its oppportunities were not modified in the last one year. 

If there any opportunities not modified in last one year, then check if the account has any call record created in last one year again.

If the above criteria meets, then the account status field on account should read "disengaged" else should read "engaged".

Can someone help me on this?

Many Thanks,

Brenda S FinnBrenda S Finn

When do you want this trigger to fire? Before Update? So what if an Account has 10 Opportunities and 1 of them has not been touched/modified within the last year, but the others have - would you set the Account Status to disengaged or engaged? Your description is confusing - it makes it sound as if you would set it to Disengaged if at least 1 has not been modified which seems incorrect to me?

Anyhow I think a query against the Account with sub-queries for the related objects within it is what you would need to do. Based on the answer to my above question, your query would potentially be different - you may want to filter the Opportunities and Calls by LastModifiedDate greater than a year ago today. This is what makes sense to me but it may not meet your requirements.

so you would have something like this:

trigger Account on Account(before update) {
	// set Account Status to Disengaged based on Opportunities and Calls
    if (Trigger.isBefore && Trigger.isUpdate) {
       Date aYearAgo = Date.today().addYears(-1);
       List<Account> lstAccts = [select Id, 
            (select Id from Finance__r) 
            (select Id, LastModifiedDate from Opportunities 
            where LastModifiedDate >=: aYearAgo) ,
            (select Id from Calls__r where 
            LastModifiedDate >= :aYearAgo)                    
            from Account where Id in :lstAccts];
        // then iterate over your Accounts 
       for (Account acct : lstAccts) {
    		// does Account has Finance records
    	        if (acct.Finance__r.size() > 0) {
                        // does it have any recent Opportunities
    			if (acct.Opportunities.size() > 0) {
                            // do we have any recent calls
                            if (acct.Calls__r.size() > 0) {
                                Trigger.newMap.get(acct.Id).Account_Status__c = 'Engaged';
                            } else { 
                                 Trigger.newMap.get(acct.Id).Account_Status__c = 'Disengaged';
    			} else { // no recent opportunities
                                 Trigger.newMap.get(acct.Id).Account_Status__c = 'Disengaged';
Bryan JamesBryan James
So instead of using a trigger for a solution, are you able to use the process builder instead? 
By first creating an invocalbeMethod you can use Process Builder to launch the invocableMethod which will then do the criteria logic in apex
and finally updating the Accounts that validate.

here is an example of an invocableMethod
public class UpdateAccountProcess {
    //add the InvocableMethod to a static method that accepts a list of Ids
    @InvocableMethod(label='Get list of valid Accounts' description='Returns a list of Accounts that have Finances,    Opportunities, and Calls')
        public static List<Account> getValidAccounts(List<Id> accIds){
            List<Account> accounts = new List<Account>();//Create a new Account List

            //Loop through  a list of accounts that have Finances, as Well as Opportunities that have been modified in the last year. Make sure to query for a list of Calls
            for(Account acc : [Select Status__c,(Select Account__c From Calls__r Where Account__c != null) From Account Where Id IN :accIds AND Id IN (Select AccountId From Opportunity Where LastModifiedDate = LAST_N_DAYS:365 AND AccountId in : accIds)
                AND Id in (Select Account__c From Finance__c Where Account__c in : accIds)])
                    //Since we passed our query criteria now check to see if there are any calls associated to the account
                    if(acc.Calls__r.size() > 0){
                        //if there are calls then set the Status__c field on this account to disengaged and add this account to our AccountList
                        acc.Status__c = 'disengaged';
            //If we have any accounts that met all the criteria go ahead and update those accounts.
            if(accounts.size() > 0){
                 update accounts;
            return null;
Now using the process builder you can set up criteria for the Finance Object, Opportunity Object, and Call Object to access this invocable Method.
For Example let use the Finance Object:
User-added image
In this example we start the process whether the Finance record is Created or Edited.

Next we need to add some Criteria
User-added image
In the Criteria we have made sure that an Account was chosen for the Finance Record.

Now for the Action we need call our InvocableMethod
User-added image
When prompted to choose an Action Type pick "Apex" then pick the name of the class that contains your InvocableMethod.
For Set Apex Variables set your variable of type List in our case accIds to a Type: Reference and Value of Account > AccountId.

Activate the process and run tests.
Tejasvi Rao 4Tejasvi Rao 4

@Brenda S Finn,

Thank you for your response. Well, I mean find if any opportunities were not modiifed in the last one year - then the status on account would be disengaged else engaged.

Ill go ahead try this code.

@Bryan James : Thank you, I'm new to apex coding. And your approach is different and I'll definitely try it. 

One point that I missed to add is - that a batch report needs to be sent to the account owner and his manager when account status is disengaged.

Will this be a battch class that way?

I'm pretty new, hence ilooking for some guidance.

Thanks a bunch!


Hi Tejasvi,

Trigger logic would be implemented on Account trigger, if yes. Please try below code: 

Trigger on Account(after insert, after update){
    Map<id, finance__c> financeMap = new Map<id,finance__c>();
    Map<id, Opportunity> OpptyMap = new Map<id,Opportunity>();
    Map<id, call__c> CallMap = new Map<id,call__c>();
    Date dt = system.addDays(-365)
    for(Finance__c f: select id, account__c from finance__c where account__c IN :trigger.newMap.keySet()){
        financeMap.put(f.account__c, f);
    for(Opportunity o: select id, account, lastmodifiedDate from Opportunity where accountId IN :trigger.newMap.keySet() and (NOT lastmodifiedDate > dt){
        OpptyMap.put(account, o);
    for(call__c c: select id, account__c, createdDate from call__c where account__c IN :trigger.newMap.keySet() AND NOT (createdDate > dt) ){
        CallMap.put(c.account__c, c);
    for(Account a: trigger.new){
        a.status = 'engaged'; 
        if(financeMap != null && financeMap.containsKey(a.id) && //Check for Finance__c condition
            OpptyMap != null && OpptyMap.containsKey(a.id) &&      // check for Opportunity condition
            CallMap != null && CallMap.containsKey(a.id)) // check for Call Object condition
                a.status = 'disengaged';

Let me know if you face any issues, please contact me on below details:
Email: gauravgarg.nmims@gmail.com
Skype: gaurav62990@gmail.com