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
Robert WamboldRobert Wambold 

ending completion email

Hello,

Taking my first shot at APEX.

I have created a Custom Field on my Quote table that determines a when a Quote can be deleted. I need my code to delete Quote records, then send an email showing how many Successes or Errors when my job completes.

Could someone be so kind as to review my code...any suggestions or comments would be appreciated.

 

Kind regrds,

Robert

global class QuoteDeleteBatchJob implements Database.Batchable<sObject> 
{
    global Database.QueryLocator start(Database.BatchableContext BC) 
    {
        String query = +
        'SELECT Id, Name, Deletable__c +
         FROM Quote__c +
         WHERE Deletable = TRUE';  
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<Quote__c> scope) 
    {
        for(Quote a : scope)
        {
            a.Name = a.Name + 'Deleted by QuoteDeleteBatchJob';
        }
        Delete scope;
    }
    global void finish(Database.BatchableContext BC) 
    
     AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
     FROM AsyncApexJob WHERE Id =:BC.getJobId()];
     
     List<User> userList = new List<User>();
     userList = [SELECT Id,Email,IsActive FROM User WHERE Profile.Name = 'System Administrator' AND IsActive = True] ;
          
     // Send an email to all active Admins notifying of job completion.     
     for(User u : userList)
     
     {           
       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
               
       //String[] toAddresses = new String[] {user.Id};
       //mail.setToAddresses(toAddresses);
       mail.setTargetObjectId(u.Id);
       mail.setSubject('QuoteDeleteBatchJob - ' + a.Status);
       mail.setSaveAsActivity(false);
       mail.setPlainTextBody
       ('The batch Apex job completed on  ' + a.CompletedDate + ',\n\n' +
        'Job Status : ' + a.Status + '\n'+
        'Total Job Items deleted : ' + a.TotalJobItems + '\n'+
        'Number of Job Items Deleted : ' + a.JobItemsProcessed + '\n' +
        'Number of Failures : '+ a.NumberOfErrors);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
     }  
          
}

 

Prem RPrem R
Hi Robert, 

Do you want to send an email that how many Quote records are successfully deleted and failed to deleted? correct? 

If yes, we can do some more optimization on this code. 

Thanks,
Prem
 
Robert WamboldRobert Wambold

Hi Prem,

That is exactly what I want. Please optimize the code.

With thanks in advance!

Robert

 

 

 

Prem RPrem R
Hi Robert, 

Do you want to send indiviual email for each Quote deletion or only one email you have to send per batch? 

Thanks,
Prem
Robert WamboldRobert Wambold
Just one email at completion.
Prem RPrem R
This case your code is perfect!!! Just remove below for loop, it's not required in execute method as we are going to delete the record. 
 
for(Quote a : scope)
        {
            a.Name = a.Name + 'Deleted by QuoteDeleteBatchJob';
        }

Thanks,
Prem
Robert WamboldRobert Wambold

Hi Prem,

I removed the code per your suggestion.

When I try to save my APEX Class I receive the following message:

"Error: Compile Error: Illegal string literal: Line breaks are not allowed in string literals at line 6 column 9"

Latest version of my code:

 

global class QuoteDeleteBatchJob implements Database.Batchable<sObject> 
{
    global Database.QueryLocator start(Database.BatchableContext BC) 
    {
        String query = +
        'SELECT Id, Name, Deletable__c +
         FROM Quote__c +
         WHERE Deletable = TRUE';  
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<Quote__c> scope) 
    {       
        Delete scope;
    }
    global void finish(Database.BatchableContext BC) 
    
     AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
     FROM AsyncApexJob WHERE Id =:BC.getJobId()];    
     List<User> userList = new List<User>();
     userList = [SELECT Id,Email,IsActive FROM User WHERE Profile.Name = 'System Administrator' AND IsActive = True] ;        
     // Send an email to all active Admins notifying of job completion.     
     for(User u : userList)    
     {           
       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();               
       //String[] toAddresses = new String[] {user.Id};
       //mail.setToAddresses(toAddresses);
       mail.setTargetObjectId(u.Id);
       mail.setSubject('QuoteDeleteBatchJob - ' + a.Status);
       mail.setSaveAsActivity(false);
       mail.setPlainTextBody
       ('The batch Apex job completed on  ' + a.CompletedDate + ',\n\n' +
        'Job Status : ' + a.Status + '\n'+
        'Total Job Items deleted : ' + a.TotalJobItems + '\n'+
        'Number of Job Items Deleted : ' + a.JobItemsProcessed + '\n' +
        'Number of Failures : '+ a.NumberOfErrors);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
     }  
          
}
 

Prem RPrem R
Please update the query line with below code. 
 
String query ='SELECT Id, Name, Deletable__c FROM Quote__c WHERE Deletable = TRUE';

 
Robert WamboldRobert Wambold

Prem, 

Thank you for your patience with me.

Now I am getting this error...

 

 

Error: Compile Error: Unexpected token 'AsyncApexJob'. at line 14 column 6

 

global class QuoteDeleteBatchJob implements Database.Batchable<sObject> 
{
    global Database.QueryLocator start(Database.BatchableContext BC) 
    {
        String query ='SELECT Id, Name, Deletable__c FROM Quote__c WHERE Deletable = TRUE';
    }
    global void execute(Database.BatchableContext BC, List<Quote__c> scope) 
    {       
        Delete scope;
    }
    global void finish(Database.BatchableContext BC) 
    
     AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
     FROM AsyncApexJob WHERE Id =:BC.getJobId()];    
     List<User> userList = new List<User>();
     userList = [SELECT Id,Email,IsActive FROM User WHERE Profile.Name = 'System Administrator' AND IsActive = True] ;        
     // Send an email to all active Admins notifying of job completion.     
     for(User u : userList)    

     {           
       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();               
       //String[] toAddresses = new String[] {user.Id};
       //mail.setToAddresses(toAddresses);
       mail.setTargetObjectId(u.Id);
       mail.setSubject('QuoteDeleteBatchJob - ' + a.Status);
       mail.setSaveAsActivity(false);
       mail.setPlainTextBody
       ('The batch Apex job completed on  ' + a.CompletedDate + ',\n\n' +
        'Job Status : ' + a.Status + '\n'+
        'Total Job Items deleted : ' + a.TotalJobItems + '\n'+
        'Number of Job Items Deleted : ' + a.JobItemsProcessed + '\n' +
        'Number of Failures : '+ a.NumberOfErrors);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
     }  
          
}

Robert WamboldRobert Wambold

Prem,

I think I got it! Thanks for your help and Patience!

Kind regards,

Robert

 


global class QuoteDeleteBatchJob implements Database.Batchable<sObject> 
{
    global Database.QueryLocator start(Database.BatchableContext BC) 
    {
        String query ='SELECT Id, Name, Deletable__c FROM Quote__c WHERE Deletable = TRUE';  
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<Quote__c> scope) 
    {       
        Delete scope;
    }
    global void finish(Database.BatchableContext BC) 
    {
     AsyncApexJob a = [SELECT Id,Status,JobType,NumberOfErrors,JobItemsProcessed,TotalJobItems,CompletedDate,ExtendedStatus
     FROM AsyncApexJob WHERE Id =:BC.getJobId()];    
     List<User> userList = new List<User>();
     userList = [SELECT Id,Email,IsActive FROM User WHERE Profile.Name = 'System Administrator' AND IsActive = True] ;        
     // Send an email to all active Admins notifying of job completion.     
     for(User u : userList)    
      {             
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();               
       //String[] toAddresses = new String[] {user.Id};
       //mail.setToAddresses(toAddresses);
       mail.setTargetObjectId(u.Id);
       mail.setSubject('QuoteDeleteBatchJob - ' + a.Status);
       mail.setSaveAsActivity(false);
       mail.setPlainTextBody
       ('The batch Apex job completed on  ' + a.CompletedDate + ',\n\n' +
        'Job Status : ' + a.Status + '\n'+
        'Total Job Items deleted : ' + a.TotalJobItems + '\n'+
        'Number of Job Items Deleted : ' + a.JobItemsProcessed + '\n' +
        'Number of Failures : '+ a.NumberOfErrors);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
      }  
    }
          
}

 

Prem RPrem R
Great.. please mark my answer is best.
Robert WamboldRobert Wambold

Finally got it work! My APEX is running daily.

 

//Batch Class
global class Batch_QuoteDelete implements Database.Batchable<sObject>,Database.stateful {
  
  //Variable to count Success and Error Records
    public Integer successCounter = 0;
    public Integer failureCounter = 0; 
         
    //Start Method 
    global Database.QueryLocator start(Database.BatchableContext BC) { 
    
        //Query to Fetch Records
        return Database.getQueryLocator([SELECT ID FROM Quote__c WHERE Deletable__c = TRUE]);
        
   
    }
    
    //Execute Method
    global void  execute(Database.BatchableContext BC, List<Quote__C> scope) {
      
    //Delete the Records those are in Contexts
        Database.DeleteResult[] delresults = Database.delete((scope),false);
        
        //Loop through records going to be deleted
        for(Database.DeleteResult dr : delResults){
        
            //If record is not successfully deleted
              if(!dr.isSuccess()){
            
                //List to hold Error
                Database.Error[] errs = dr.getErrors();
                
                //Loop through list of Error
                for(Database.Error err : errs) {
                    
                    //Debug to get Error Status
                    System.debug('$#$#$#$' + err.getStatusCode() + ' - ' + err.getMessage());
                    
                    //Debug to get Error Message
                    System.debug('ErrorMessage##########'+ err.getMessage());
                }
                
                //Increase counter for Failure
                 failureCounter++;
            }
            
            else {
            
                successCounter++;
            }
        }      
    }
    
    //Finish Method
    global void finish(Database.BatchableContext BC){
      
      // 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 = :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[] {a.CreatedBy.Email};
        mail.setToAddresses(toAddresses);
        mail.setSubject('Apex Quote Delete Job ' + a.Status);
        mail.setPlainTextBody
        ('Apex Quote Delete Job has been completed. There were total of ' + a.TotalJobItems 
              + ' batches with ' + successCounter + ' success and ' + failureCounter
              + ' failures.');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
    }
}

 

I receive an email:

Subject: Apex Quote Delete Job Completed

Body: Apex Quote Delete Job has been completed. There were total of 56 batches with 11064 success and 0 failures.