+ Start a Discussion
Uma PrabhakarUma Prabhakar 

How to write Batch class to send an Email alert when Lead is not modified for 24Hrs

Hello Everyone

I need some help and suggestion regarding the email alert when lead is not modified for 24 Hrs, i tried with the workflow alert and time based Triggers but it was not working, 
Workflow rule:-

Evaluation criteria:- Every time record is created & subsequently meet criteria

Formula:- LastmodifiedDate=Created Date

and Created a Timetrigger actions for 24 Hrs, but it did not fire

I have Faced a lot of issues with Workflows and Prosess Builders, so i need help for designing a Batch class When Lead  is Created and if the lead is not modified for 24Hrs it should send an Email alert
This is what i have come up with till now
global class Emailalertbatchclass implements Database.Batchable<sObject>, Schedulable, Database.Stateful {

    //Variable Section
    global FINAL String strQuery;
    global List<String> errorMessages = new List<String>();
    
    global Emailalertbatchclass() { 
        this.strQuery = getBatchQuery();
    }
    
    //Returns the Query String to Batch constructor to fetch right records.
    private String getBatchQuery() {
        String strQuery = 'SELECT Id, name, Owner.Email FROM Lead WHERE CreatedDate >= YESTERDAY'; 
        return strQuery;
    }
    
    //Batch Start method
    global Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator(strQuery);
    }

    //Batch Execute method calls findCostForWoD method
    global void execute(Database.BatchableContext BC, List<sObject> scopeList) {
        System.debug(LoggingLevel.INFO, '== scopeList size ==' + scopeList.size());
        
        List<Lead> ld = (List<Lead>) scopeList;
        if(!ld.isEmpty()) { 
            List<Messaging.SingleEmailMessage> mailList = new List<Messaging.SingleEmailMessage>();
            for (Lead prod : ld)
            {               
                
                Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); 
                String[] toAddresses = new String[] {prod.Owner.Email};
                Message.setToAddresses(toAddresses); 
                Message.SaveAsActivity = false;
                mailList.add(Message);
                
            }
            if(!mailList.isEmpty()) {
                try{
                    Messaging.sendEmail(mailList);
                }
                catch (Exception ex) {
                    errorMessages.add('Unable to send email to Tech: '+ ex.getStackTraceString());
                }
            }
        }
    }  

    //Batch Finish method for after execution of batch work
    global void finish(Database.BatchableContext BC) { 
        AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id =:BC.getJobId()];
        
        // Send an email to the Apex job's submitter notifying of job completion.
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {aaj.CreatedBy.Email};
        mail.setToAddresses(toAddresses);
        mail.setSubject('JOB Salesforce Send Notification Batch: ' + aaj.Status);
        String bodyText='Total Job Items ' + aaj.TotalJobItems + ' Number of records processed ' + aaj.JobItemsProcessed + ' with '+ aaj.NumberOfErrors + ' failures.\n';
        bodyText += 'Number of Error Messages ' + errorMessages.size() + '\n';
        bodyText += 'Error Message' + String.join(errorMessages, '\n');
        mail.setPlainTextBody(bodyText);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
    
    //Method which schedules the ProductDownloadBatch
    global void execute(SchedulableContext sc) {        
        Emailalertbatchclass snInstance = new Emailalertbatchclass();
        ID batchprocessid = Database.executeBatch(snInstance);
    }
}
Any help would be Highly Appericiated 



 
paul diracpaul dirac

First of all, It's a better practice to create an appropriate class for your schedulable method:


global class schedule*yourbatchname* implements Schedulable {
global void execute(SchedulableContext SC) { 
         Emailalertbatchclass snInstance = new Emailalertbatchclass();
        ID batchprocessid = Database.executeBatch(snInstance); }
}

I really don't understand the purpose of the below class, you define the query as string ( as a variable ) and pass it to the start() method:

//Returns the Query String to Batch constructor to fetch right records.
    private String getBatchQuery() {
        String strQuery = 'SELECT Id, name, Owner.Email FROM Lead WHERE CreatedDate >= YESTERDAY'; 
        return strQuery;
    }

However the main query can be more specific for the use case:

SELECT Id, name, Owner.Email FROM Lead WHERE CreatedDate >= YESTERDAY AND Lastmodifieddate==Createddate

Since the createddate and lastmodifieddate are equal values if it was never modified, check it in the developer console:
 

Account acc= new Account(name = 'a1');
insert acc;
Account lacc = [select id,createddate,lastmodifieddate FROM Account where name='a1'];
system.debug('created:: '+lacc.createddate+' modified'+lacc.lastmodifieddate);

Passing the list of unmodified Leads to the execute will let you send the emails to all of them, if I understand this is what you needed. Also, you can scheduled this job one time every day. To dive in depht to job scheduling via script see this topic:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm

Uma PrabhakarUma Prabhakar
@Paul
Thank you for the Link, i tried to modified the code as below, i am getting an error in the logs

Emailalertbatchclass
 
global class Emailalertbatchclass implements Database.Batchable<sObject>, Schedulable, Database.Stateful {

    //Variable Section
    global FINAL String strQuery;
    global List<String> errorMessages = new List<String>();
    
    global Emailalertbatchclass() { 
        this.strQuery = getBatchQuery();
    }
    
    //Returns the Query String to Batch constructor to fetch right records.
    private String getBatchQuery() {
        String strQuery = 'SELECT Id, name,Email FROM Lead WHERE CreatedDate >= YESTERDAY AND Lastmodifieddate==Createddate'; 
        return strQuery;
    }
    
    //Batch Start method
    global Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator(strQuery);
    }

    //Batch Execute method calls findCostForWoD method
    global void execute(Database.BatchableContext BC, List<sObject> scopeList) {
        System.debug(LoggingLevel.INFO, '== scopeList size ==' + scopeList.size());
        
        List<Lead> ld = (List<Lead>) scopeList;
        if(!ld.isEmpty()) { 
            List<Messaging.SingleEmailMessage> mailList = new List<Messaging.SingleEmailMessage>();
            for (Lead prod : ld)
            {               
                
                Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); 
                String[] toAddresses = new String[] {prod.Email};
                Message.setToAddresses(toAddresses); 
                Message.SaveAsActivity = false;
                mailList.add(Message);
                
            }
            if(!mailList.isEmpty()) {
                try{
                    Messaging.sendEmail(mailList);
                }
                catch (Exception ex) {
                    errorMessages.add('Unable to send email to Tech: '+ ex.getStackTraceString());
                }
            }
        }
    }  

    //Batch Finish method for after execution of batch work
    global void finish(Database.BatchableContext BC) { 
        AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id =:BC.getJobId()];
        
        // Send an email to the Apex job's submitter notifying of job completion.
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {aaj.CreatedBy.Email};
        mail.setToAddresses(toAddresses);
        mail.setSubject('JOB Salesforce Send Notification Batch: ' + aaj.Status);
        String bodyText='Total Job Items ' + aaj.TotalJobItems + ' Number of records processed ' + aaj.JobItemsProcessed + ' with '+ aaj.NumberOfErrors + ' failures.\n';
        bodyText += 'Number of Error Messages ' + errorMessages.size() + '\n';
        bodyText += 'Error Message' + String.join(errorMessages, '\n');
        mail.setPlainTextBody(bodyText);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
    
    //Method which schedules the ProductDownloadBatch
    global void execute(SchedulableContext sc) {        
        Emailalertbatchclass snInstance = new Emailalertbatchclass();
        ID batchprocessid = Database.executeBatch(snInstance);
    }
}

Scheduleerclassemailalert
 
global class Scheduleerclassemailalert implements Schedulable {
global void execute(SchedulableContext SC) { 
         Emailalertbatchclass snInstance = new Emailalertbatchclass();
        ID batchprocessid = Database.executeBatch(snInstance); }
}

i tried to excute in excutable window

Emailalertbatchclass snInstance = new Emailalertbatchclass();
ID batchprocessid = Database.executeBatch(snInstance);


i am getting unexpected token error in the SOQL query of the emailalertbatchclass line 13

User-added image

However the account record is getting inserted from the excutable window
Uma PrabhakarUma Prabhakar
@Any Suggestions??
paul diracpaul dirac
I wrongly write == in the query, actully the equal operator fot SOQL is '=' and not '==', sorry!