I'm new to Batch apex and trying to figure out how to create a scheduled job. In subsequent years, on the anniversary date of the related account, need to clone the existing cases for the new year, and trigger the related task workflows for these cases.

For eg. I have 1 account having anniversary date on it, whenever the anniversary of the account occurs, need to clone the latest case to it using batch apex

  • Edit

Please find below the updated code. Everything looks fine to me BUT the functionality is not working. That is, All cases should be cloned on anniversary of Account.

Any help would be appreciated

public class CaseCloneOnAccountAnniversary implements Database.Batchable<SObject>,Schedulable {

    public static final String BATCH_JOB_TITLE = 'My Batch Job';
    String errors = '';

    integer todayday = date.today().day();
    Integer currentmonth = date.today().month();

    public Map<Id, String> errorMap = new Map<Id, String>();
    public Map<Id,Case> IdToSObjectMap = new Map<Id, Case>();

    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Anniversary__c,Id from Account WHERE Anniversary__c = DAY_IN_MONTH(Anniversary__c) =:todayday AND CALENDAR_MONTH(Anniversary__c ) =: currentmonth') ;

    public void execute(Database.BatchableContext bc, List<SObject> scope) {
        if(scope.isEmpty()) return;
        //List<Account> accts = (List<Account>) scope;
        // Lis<Account> acctsList = new List<Account>();
        List<Case> caseToCreateList = new List<Case>();

        // for( Account aAccount : (Account)scope )
        for(Account aAccount:[Select Id,(Select Id from cases order by CreatedDate limit 1) from account where Id IN : scope]) //Add all field in case query which you want to copy {
            if(aAccount.cases.size() > 0) {
                Case objCase = new Case();
                objCase  = aAccount.cases[0].clone(false, true);

                // collecting the Cases to create

        try {
            if(!caseToCreateList.isEmpty()) { 

                Database.SaveResult[] srList = Database.insert(caseToCreateList, false);
                Integer index = 0;
                system.debug('---srList  first'+ srList );

                for(Database.SaveResult result : srList ) {
                    if(!result.isSuccess()) {
                        String errMsg = result.getErrors()[0].getMessage();
                        errorMap.put(caseToCreateList[index].Id, errMsg);
                        IdToSObjectMap.put(caseToCreateList[index].Id, caseToCreateList[index]);
                    } // End Inner If
                } // End for

            } // End Outer If
        } // End try
        catch( Exception ex ) {
            this.errors += ex.getMessage();

    public void finish(Database.BatchableContext context) {
        //Send an email to the User after your batch completes 
            AsyncApexJob a = [SELECT id,ApexClassId,JobItemsProcessed,TotalJobItems,NumberOfErrors, CreatedBy.Email FROM AsyncApexJob WHERE id = :context.getJobId()];

            String body = 'Your batch job '
                + 'CaseCloneOnAccountAnniversary'
                + 'has finished. \n' 
                + 'There were '
                + errorMap.size()
                + ' errors. Please find the error list attached to the mail.';

            // Creating the CSV file
            String finalstr = 'Id, Subject, Error \n';
            String subject = 'CaseCloneOnAccountAnniversary- Apex Batch Error List';
            String attName = 'CaseCloneOnAccountAnniversary Errors.csv';      

            for(Id id  : errorMap.keySet()){
                string err = errorMap.get(id);
                Case objCase = (Case) IdToSObjectMap.get(Id);
                String recordString = '"'+id+'","'+ objCase.Subject +'","'+ err +'"\n';
                finalstr = finalstr +recordString;

            // Define the email
            Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage(); 

            // Create the email attachment    
            Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();

            // Sets the paramaters of the email
            email.setSubject( subject );
            email.setToAddresses( new String[] {'[email protected]'} );
            email.setPlainTextBody( body );
            email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});

            // Sends the email
            Messaging.SendEmailResult [] r = 
                Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});   


    public void execute(SchedulableContext sc) {
        CaseCloneOnAccountAnniversary scheduleBatch= new CaseCloneOnAccountAnniversary();

  • What have you tried so far? Are you receiving any error messages? SFSE is here to help with any specific problems you might have, but a general question like this is very broad and may get closed.
    – Nick Cook
    Oct 19, 2016 at 5:56
  • I'm confused with how to proceed step by step and your help will be grateful. Thinking is , create another field on account (lets say, newdate) which will store the newly anniversary date. So, first Workflow rule to have criteria as Account:Anniversary NOT Equals Null and then to have formula on field update on Account :Anniversay + 365.
    – JJoseph
    Oct 19, 2016 at 6:15
  • Does it have to be batch apex?
    – Nick Cook
    Oct 19, 2016 at 6:17
  • Not mandatory. Becasue, we cannot do any case creation with Workflow. So workflow is cancelled. With Process Builder, we can create a case but how to have anniversary date for subsequent years. Hence Process builder is cancelled.
    – JJoseph
    Oct 19, 2016 at 6:19
  • Your help here will be appreciated.
    – JJoseph
    Oct 19, 2016 at 6:39

1 Answer 1


First In your query do something

integer todayday = date.today().day();
Integer currentmonth =  date.today().month();

 SELECT Anniversary__c,Id from Account WHERE Anniversary__c DAY_IN_MONTH(Anniversary__c ) =: todayday AND CALENDAR_MONTH(Anniversary__c ) =: currentmonth 

And then in execute method query the latest case and create a new case using standard clone method.

List<Case> CaseToCreate = new List<Case>();
for( Account aAccount : [Select Id, [Select Id from cases order by CreatedDate limit 1] FRom Account WHERE ID IN : scope]) //Add all field in case query which you want to copy
  if(aAccount.cases.size() > 0)
    Case objCase = new Case();
    objCase  = aAccount.cases[0].clone(false, true)

    // collecting the Cases to create

    insert CaseToCreate; 
  • Updated my code but now working. Please suggest where is this going wrong, scratching my head
    – JJoseph
    Oct 20, 2016 at 5:47
  • @JJoseph instead of writing not working it would be better if you can share what is not working. Although if you want to clone All case then remove inner query limit. Oct 20, 2016 at 7:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .