global without sharing class FixtureSetDetailDailyUpdateBatch implements Database.Batchable<sObject>, Database.Stateful {
    global List<String> errorList = new List<String>();
    global Integer allCount = 0; // 总明细条目
    global Integer allCountDone = 0;
    global Integer updatedCount = 0; // 实际更新的条目

    Boolean IsNeedExecute = false; // 2021-03-05  mzy  WLIG-BYHD79  SFDC环境batch合并调查  是否符合执行条件

    global FixtureSetDetailDailyUpdateBatch() {}

    // 2021-03-05  mzy  WLIG-BYHD79  SFDC环境batch合并调查  start
    global FixtureSetDetailDailyUpdateBatch(Boolean NeedExecute) {
        this.IsNeedExecute = NeedExecute;
    }
    // 2021-03-05  mzy  WLIG-BYHD79  SFDC环境batch合并调查  end

    global Database.QueryLocator start(Database.BatchableContext bc) {
        String query ='SELECT Id , Fixture_Model_No_F__c , Product_Status_Flag__c, Is_Body__c FROM Fixture_Set_Detail__c';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, list<Fixture_Set_Detail__c> fsdList) {
        allCount += fsdList.size();
        Savepoint sp = Database.setSavePoint();
        try {
            List<Fixture_Set_Detail__c> fsdUpdateList = new List<Fixture_Set_Detail__c>();
            updateProductStatusFlag(fsdList, fsdUpdateList, errorList);
            if(fsdUpdateList.size() > 0) {
                Database.update(fsdUpdateList);
                updatedCount += fsdUpdateList.size();
            }
            allCountDone += fsdList.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;
        }
    }
    /**
    @param fsdList 待更新的配套明细列表
    */
    public static void updateProductStatusFlag(list<Fixture_Set_Detail__c> fsdList) {
        updateProductStatusFlag(fsdList, new List<Fixture_Set_Detail__c>() , new List<String>());
    }
    /**
    @param fsdList 待更新的配套明细列表，在FixtureSetManageController里用作返回值
    @param fsdUpdateList 实际需要更新的配套明细列表，用作返回值
    @param errorList 错误列表，用作返回值
    */
    private static void updateProductStatusFlag(list<Fixture_Set_Detail__c> fsdList, List<Fixture_Set_Detail__c> fsdUpdateList, List<String> errorList) {
        Map<String, Boolean> modelStatusMap = new Map<String, Boolean>();
        // 所有型号都初始为不可用
        for(Fixture_Set_Detail__c fsd:fsdList){
            modelStatusMap.put(fsd.Fixture_Model_No_F__c, fsd.Is_Body__c == false);
        }
        List<Product2> proList = [
                SELECT Id
                     , SFDA_Status__c
                     , Fixture_Model_No_T__c
                  FROM Product2
                 WHERE Fixture_Model_No_T__c IN:modelStatusMap.keySet()
                   AND (SFDA_Status__c != '停止' OR Manual_Entry__c = true)
        ];
        for(Product2 pro:proList) {
            modelStatusMap.put(pro.Fixture_Model_No_T__c, true);
        }
        List<Database.SaveResult> updResultList = Database.update(fsdList, false);
        for(Integer i = 0; i < updResultList.size(); i++){
            Database.SaveResult sr = updResultList[i];
            Fixture_Set_Detail__c fsd = fsdList[i];
            if(sr.isSuccess() || fsd.Id == null) {
                // 产品状态有变化则更新
                if(modelStatusMap.containsKey(fsd.Fixture_Model_No_F__c)
                    && fsd.Product_Status_Flag__c != modelStatusMap.get(fsd.Fixture_Model_No_F__c)){
                    fsd.Product_Status_Flag__c = modelStatusMap.get(fsd.Fixture_Model_No_F__c);
                    fsdUpdateList.add(fsd);
                }
            }
            else{
                for (Database.Error err : sr.getErrors()) {
                    errorList.add(err.getStatusCode() + ':' + err.getMessage() + err.getFields());
                }
            }
        }
    }
    global void finish(Database.BatchableContext BC) {
        if (allCount != allCountDone || errorList.size() > 0) {
            BatchEmailUtil be = new BatchEmailUtil();
            String[] toList = new String[]{};
            String title = '配套明细状态更新batch失败';
            String[] ccList = new String[]{};
            toList.add('shuo_wang@olympus.com.cn');
            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, allCountDone, errorList.size());
            be.send();
        }
     // 20201126 youchang start   OPD计划&备品申请取消  SWAG-BUF6J5   
      Database.executeBatch(new OPDPlanCancelPostponePlanLogicBatch(), 50);
     // 20201126 youchang end 
    }
}