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

apex trigger stage opportunity

Hey Guys


I am new to Apex coding so please be gentle


I need some help


Basically i have a huge backlog in my pipeline report, i thought of a way that i can overcome this but i am not sure its its viable


What i want to achieve is that is if the opportunity stage are any of the following

Application Docs Out
Application docs in (Complete)
Sent to Risk
Approved by Risk


and there has been no activity ( last modified date in the last 6months from todays date) then change the stage to "Opportunity lost"


Is this easily achievable ?

If any one can supply some basic coding for one /two of the stages above it would be truly appreciated


Many thanks


Hi ,


This is achievable by making an Apex Trigger and then make fake update operation in bulk on Opportunity.What I mean to say is below :-


1.) Create a dummy field checkbox may be and update it to true using Data Loader or Apex Batch class that will invoke the Apex Trigger to Fire.Data Loader would be easy for updating.You don't need to show this dummy foeld on the layout,this is only to invoke Trigger action.


2.) Then,In your Trigger for update Action check if LastModifiedDate is greater than 6 months ago using addMonths method,if it is more than 6 Months ,then update the Opportunity StageName field to 'Closed Lost'.


I tried to make things simple for you here.





Jake GmerekJake Gmerek

That will work, but if you are more comfortable outside of Apex, you could use the data loader to download all of your opportunities, open the .csv in excel, use excel filtering to find and edit the records that you need and then update using the data loader again.



Whatever these guys suggested is a manual one time fix for your scenario. 


However, if you want to do it on an ongoing basis automatically, you should create a Batch Apex class that can be made to run as  frequently as you desire it to be.


This is not a trigger but it is an Apex class that implements Batchable interface and you have to implement the three methods start, execute and finish from that interface. This Apex class does the work of getting your opportunites based on SOQL query with the criteria you specify in the start method - criteria will include your Opportunity Lastmodified date <= 6 months and Opportunity StageName NOT IN ('Closed Won', 'Closed Lost') . Your execute method takes each of these Opportunities and updates the StageName to 'Closed Lost' or whatever you call it in your org. The finish method can do clean up activities like setting lists to null and also sending an email to the Job owner with the details of processing


You will also have another class that implements Schedulable that calls this first class that implemented Batchable.


And finally you will go into the setup menu to schedule this implemented Schedulable class to run at regular intervals.


Hope that makes sense.


Sorry meant to say Opportunity Lastmodified date <= ( Current Date - 6 months) for the filtering criteria


#1) Here is the code for the first class OpprtunityBatchUpdate.cls - This needs to be created as an Apex class and notice that I implemented Batchable Interface and three methods start, execute and finish. Change the filter at the red highlighted lcation to retrive the Opportunities in various stages. The Query below already has the criteria to check Opportunities with LastModifiedDate older than 6 months


global class OpprtunityBatchUpdate implements Database.Batchable<SObject> {

global Database.QueryLocator start(Database.BatchableContext BC){

Datetime dateTm =;

String query = 'Select, o.StageName, o.LastModifiedDate From Opportunity o where '
+ 'o.LastModifiedDate <= ' +dateTm.formatGMT('yyyy-MM-dd') + 'T' + dateTm.formatGMT('HH:mm:ss.SSS') + 'Z and '
+ 'o.StageName in (\'Prospecting\',\'Qualification\',\'Needs Analysis\') ';  //Add your Stages using escape sequence

return Database.getQuerylocator(query);

global void execute(Database.BatchableContext BC, List<sObject> scope){
List<Opportunity> opps = new List<Opportunity>();

system.debug('opportunity size '+scope.size());

for(sObject s : scope){
Opportunity o = (Opportunity)s;
system.debug('opportunity name ';
o.StageName = 'Closed Lost';

update opps;

global void finish(Database.BatchableContext BC){

// Get the ID of the AsyncApexJob representing this batch job
// from Database.BatchableContext.
// Query the AsyncApexJob object to retrieve the current job's information.
AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob WHERE Id =
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setSubject('Apex Sharing Recalculation ' + a.Status);
('The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + ' failures.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });



#2) Then you need to implement this second Apex class that implements Schedulable


global class OpportunityBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc){
database.executeBatch(new OpprtunityBatchUpdate());


#3) Go into Your Name - Setup - Develop - Apex Classes - Schedule Apex 


Give a Job name and select the OpportunityBatchScheduler to run. 


Tip: If you want to run it once, just use Start  Date and End Date as the same and choose a time, else run it as frequently as you want.