Update Opportunity Stage for Inactive Accounts

In any CRM-driven business, knowing when to stop pursuing a lead or opportunity is just as important as knowing when to follow up. When an Account is no longer active, keeping open Opportunities tied to it makes little sense and can mislead reports, forecasts, and sales team activities.

In this blog, we explore a practical and high-impact Apex trigger that automatically updates all related Opportunities to “Closed Lost” when an Account’s Active field changes from “Yes” to “No.” The trigger runs in the after update context and ensures that only Opportunities that are not already “Closed Won” or “Closed Lost” are modified.

This automation ensures that your pipeline reflects reality—removing deadweight deals and keeping forecasts clean and actionable.

🧠 Why This Trigger Is Critical


Imagine your sales team continues to chase deals on an Account that is no longer active. It wastes time, pollutes your data, and disrupts performance reviews. Manual cleanup is inconsistent and error-prone. By automating this check:

  • You eliminate open Opportunities for inactive Accounts

  • You keep your pipeline lean and reflective of live deals

  • Sales reps are no longer distracted by outdated Opportunities

  • Reports and dashboards stay clean and meaningful

  • Forecasting becomes more accurate, enabling smarter business decisions

This is the kind of automation that improves data integrity without requiring additional effort from the user.

🔍 What This Blog Covers


  • How to detect a change in a custom field (Active__c) using Trigger.oldMap

  • How to use Parent-to-Child SOQL to access related Opportunities

  • How to filter Opportunities based on Stage

  • How to bulk update child records based on a parent-level field change

  • Why this pattern supports long-term CRM health and sales process compliance

  • How to structure your logic inside a trigger handler class for reusability

The automation is written to be clean, bulk-safe, and production-ready, with logic separated in a handler class for better testing and future maintenance.

🎯 Real-World Use Cases for This Trigger


  • Sales teams avoiding confusion from old or irrelevant Opportunities

  • Sales Ops managers trying to clean up pipeline clutter

  • Revenue leaders looking for clean, real-time forecasting

  • Account managers marking inactive clients in CRM after churn or inactivity

  • Integration-driven orgs syncing data from ERPs or external systems

This automation is ideal for B2B companies, subscription services, or any team where Account status directly impacts deal viability.

👨‍💻 Developer & Admin Tips


Here’s how the logic works:

  1. The trigger runs after update on the Account object.

  2. It checks if Active__c was changed from “Yes” to “No” using Trigger.oldMap.

  3. For all such Accounts, it collects their IDs in a Set.

  4. A single Parent-to-Child SOQL query fetches all related Opportunities.

  5. For each Opportunity, if the current Stage is neither “Closed Won” nor “Closed Lost,” the Stage is updated to “Closed Lost.”

  6. A single DML update applies the changes to all modified Opportunities.

This logic avoids unnecessary updates, preserves successful (won) deals, and ensures bulk-safe behavior even in large-scale updates. The use of a trigger handler method keeps code modular and testable.

This is also a great pattern to extend for other Account-based field changes—like auto-pausing campaigns, removing user access, or notifying assigned reps.

🎥 Learn By Watching – YouTube Playlist Available


To see this trigger in action, head over to the Salesforce Makes Sense YouTube playlist. The video walks through:

  • The trigger structure

  • How oldMap helps detect field changes

  • Writing Parent-to-Child queries in Apex

  • Building clean and efficient update loops

  • Testing and deploying the automation in your org

It’s all explained step-by-step in a real-world tone—no jargon, no fluff.

Solution:

trigger AccountTrigger on Account (after update) {
          if(Trigger.isUpdate){ if(Trigger.isAfter){
                               AccountTriggerHandler.updateOpportunityStage(Trigger.New, Trigger.oldMap);
                            }
        }
}
public class AccountTriggerHandler {

          public static void updateOpportunityStage(List
          accList,Map<Id,Account> oldMap){
          List<Opportunity> oppList=new
          List<Opportunity>(); Set<Id> idSet= new Set<Id>(); for(Account
          acc:accList){ if(acc.Active__c == ‘No’
          && acc.Active__c !=
                          oldMap.get(acc.Id).Active__c){ idSet.add(acc.Id);
                           }
           }
                           for(Account a:[SELECT Id,Active__c,(SELECT Id,StageName FROM
           Opportunities) FROM Account WHERE Id IN:idSet]){
                          if(acc.Opportunities!=null){ for(Opportunity opp:a.Opportunities){
                          if(opp.StageName!=’Closed
                                                        Won’&&opp.StageName!=’Closed Lost’){ opp.StageName=’Closed Lost’;
                                                                oppList.add(opp);
                                                        }
                                         }
                               }
                    } if(oppList.size( ) > 0){ update oppList;
                    }
         }
}

Want to Apply As Content Writer?

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Cart

Let's get you started!

Interested in writing Salesforce Content?

Fill in this form and we will get in touch with you :)