global without sharing class ConsumAutoCancelRequestBatch implements Database.Batchable<sObject>, Database.Stateful {

    global List<String> emailMessages = new List<String>();
    global Integer totalCount = 0; // 総処理件数
    global Integer totalCountDone = 0; // 処理済件数
    global Integer failedCount = 0; // 処理失敗件数
    private Date td = Date.today();

    /**
    * startには、queryを実行、耗材备品申請を検索
    */
    global Database.Querylocator start(Database.BatchableContext bc) {
        String soql = 'select Id'
                + '     , Salesdepartment__c'
                + '     , Request_shipping_day__c'
                + '     , demo_purpose2__c'
                + ' from Consum_Apply__c'
                + ' where Status__c = \'申请中\''
                + ' and Request_shipping_day__c != null'
                + ' order by Id';
        return Database.getQueryLocator(soql);
    }

    global void execute(Database.BatchableContext bc,List<Consum_Apply__c> csmApyList) {
        totalCount += csmApyList.size();
        Savepoint sp = Database.setSavepoint();
        try {
            Consum_Apply__c ca = csmApyList[0];
            Map<Date, OlympusCalendar__c> calendarMap = Consum_ApplyUtil.getOlympusCalendarMAp(ca.Request_shipping_day__c, ca.Request_shipping_day__c);
            Date td1;
            if (calendarMap.get(ca.Request_shipping_day__c).Before_7_WorkDay__c != null) {
                td1 = calendarMap.get(ca.Request_shipping_day__c).Before_7_WorkDay__c;
            }
            else {
                td1 = Consum_ApplyUtil.getWD_addday(ca.Request_shipping_day__c, -7);
            }
            if (td1 <= td) {
                String msg = ConsumApplyWebService.ConsumApplyCancel(ca.Id, true);
                if (msg != '1') {
                    throw new ControllerUtil.myException(msg);
                }
            }
            totalCountDone += csmApyList.size();
        }
        catch (Exception e) {
            emailMessages.add(e.getMessage());
            failedCount += csmApyList.size();
            Database.rollback(sp);
        }
    }

    global void finish(Database.BatchableContext bc) {
        String email = UserInfo.getUserEmail();
        String title = '耗材自动取消申请分配';
        String emailLabel = 'BatchNotify';
        for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName 
                FROM OrgWideEmailAddress
                WHERE DisplayName like :emailLabel]) {
            email = tmpEmailObj.Address;
        }
        List<String> ccList = new List<String>();
        for (Consum_Apply_Meta__mdt camd : [SELECT Id
                    , Key__c
                    , ValueLong__c
                 FROM Consum_Apply_Meta__mdt
                WHERE Package__c = 'ConsumAutoCancelRequestBatch'
                  AND (Key__c = 'ErrorMailAddress'
                          OR Key__c = 'ErrorMailTitle'
                      )
                ORDER BY Key__c]) {
            if (camd.Key__c == 'ErrorMailAddress') {
                if (String.isNotBlank(camd.ValueLong__c)) {
                    ccList.addAll(camd.ValueLong__c.split(','));
                }
            }
            else if (camd.Key__c == 'ErrorMailTitle') {
                title = camd.ValueLong__c;
            }
        }
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{email};
        if (!(totalCountDone == totalCount && 0 == emailMessages.size())) {
            be.failedMail(toList, ccList, title,
                String.join(this.emailMessages, '\n'),
                totalCount, totalCountDone, failedCount);
            be.send();
        }
    }

    // 需要掉用 ConsumApplyWebService、固定 1
    public static void run() {
        Database.executeBatch(new ConsumAutoCancelRequestBatch(), 1);
    }

    @TestVisible private static void test() {
        if (false == Test.isRunningTest()) return;
        Integer i = 0;
        
    }
}