global without sharing class RentalApplyDetailStatusUpdateBatch implements Database.Batchable<sObject>, Database.Stateful {
    global List<String> errorList = new List<String>();
    global Integer allCount = 0;
    global Integer doneCount = 0;
    private UpdateRentalApplyBatch.ScBean scB;

    global Database.QueryLocator start(Database.BatchableContext bc) {
        scB = UpdateRentalApplyBatch.setSc('RentalApplyDetailStatusUpdateSchedule', 9, 23, 0, '0 30 2', null);
        if (System.Test.isRunningTest() == false) {
            for(CronTrigger ct : [SELECT Id FROM CronTrigger WHERE CronJobDetail.Name =: scB.scName]) {
                System.abortJob(ct.Id);
            }
            system.schedule(scB.scName, scB.scTime, new RentalApplyDetailStatusUpdateSchedule());
        }

        String query = 'SELECT RAESD_Status__c'
                    + ' FROM Rental_Apply_Equipment_Set_Detail__c'
                    + ' WHERE RAESD_Status_Text_Update_F__c = true';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, list<Rental_Apply_Equipment_Set_Detail__c> raesdList) {
        allCount += raesdList.size();
        Savepoint sp = Database.setSavepoint();
        try {
            List<Rental_Apply_Equipment_Set_Detail__c> updateList = new List<Rental_Apply_Equipment_Set_Detail__c>();
            List<Database.SaveResult> updResultList = Database.update(raesdList, false);
            for (Integer i = 0; i < updResultList.size(); i++) {
                Database.SaveResult sr = updResultList[i];
                Rental_Apply_Equipment_Set_Detail__c raesd = raesdList[i];
                if (true == sr.isSuccess()) {
                    raesd.RAESD_Status_Text__c = raesd.RAESD_Status__c;
                    updateList.add(raesd);
                } else {
                    for (Database.Error err : sr.getErrors()) {
                        errorList.add(err.getStatusCode() + ':' + err.getMessage() + err.getFields());
                    }
                }
            }
            if(updateList.size() > 0) {
                Database.update(updateList);
                doneCount += updateList.size();
            }
        }
        catch (Exception e) {
            Database.rollback(sp);
            errorList.add(e.getMessage() + '\n' + e.getStackTraceString());
            System.debug(LoggingLevel.ERROR, e.getMessage() + '\n' + e.getStackTraceString());
            throw e;
        }
    }

    global void finish(Database.BatchableContext BC) {
        UpdateRentalApplyBatch.removeOtherSc('RentalApplyDetailStatusUpdateSchedule', scB.scName);
        if (allCount != doneCount || errorList.size() > 0) {
            BatchEmailUtil be = new BatchEmailUtil();
            String[] toList = new String[]{};
            String title = '借出明细状态更新batch失败';
            String[] ccList = new String[]{};
            for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName
                    FROM OrgWideEmailAddress
                    WHERE DisplayName like 'BatchNotify']) {
                toList.add(tmpEmailObj.Address);
            }
            be.failedMail(toList, ccList, title, String.join(this.errorList, '\n'), allCount, doneCount, errorList.size());
            be.send();
        }
    }
}