public without sharing class SSBackorderBatch implements Database.Batchable<SObject>, Database.Stateful {
    public final List<Id> TEST_ID = null;
    private BatchIF_Log__c iflog;

    /**
     * コンスタント、パラメータを受け取る
     */
    public SSBackorderBatch(List<Id> testId) {
        TEST_ID = testId;
        System.debug('TEST_ID=' + TEST_ID);
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = 'SSBackorderBatch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }

    /**
     * startには、queryを実行、引合全件
     */
    public Database.QueryLocator start(Database.BatchableContext BC) {
        // 注残
        SS_Batch_Column_Mapping__c staMapping = SS_Batch_Column_Mapping__c.getValues('Statu_Achievements__c');
        // select項目を staMapping より生成
        Set<String> apiTempSet = new Set<String>();
        for (Integer i = 1; i <= SSOpportunityBatch.FIELDMAX; i++) {
            String lpadI = ('00' + i).right(3);
            String fromColumn = 'From_Column_' + lpadI + '__c';
            String apiStr = String.valueOf(staMapping.get(fromColumn));
            if (String.isBlank(apiStr) == false) {
                String ssColumn = 'SS_Column_' + lpadI + '__c';
                String ssApiStr = String.valueOf(staMapping.get(ssColumn));
                if (ssApiStr.toLowerCase().startsWith('statu_achievements__c.')) {
                    // 注残の項目を更新、変更があるかどうか判断するため、元データも取得
                    System.debug('ssApiStr=' + ssApiStr + ', substring(22)=' + ssApiStr.substring(22));
                    apiTempSet.add(ssApiStr.substring(22));
                }
            }
        }
        String staSql = SSOpportunityBatch.makeSql(staMapping, apiTempSet);

        //staSql += ' where OverviewStatus__c <> \'无效合同\' and (OverviewStatus__c <> \'订单完成\' or (SS_backorderID__c <> null and OverviewStatus_SS_IsEqual__c = false))';
        //*************************************************************************************************************//
        //
        //*************************************************************************************************************//
        staSql += ' where (( OverviewStatus__c <> \'无效合同\' and (OverviewStatus__c <> \'订单完成\' or (SS_backorderID__c <> null and OverviewStatus_SS_IsEqual__c = false))) or Forecast_Equal__c=false)  ';
        //      staSql += ' where OverviewStatus__c <> \'无效合同\' and OverviewStatus__c <> \'订单完成\'';
        if (TEST_ID <> null) {
            staSql += ' and id IN :TEST_ID';
        }
        System.debug('staSql=' + staSql);
        return Database.getQueryLocator(staSql);
    }

    public void execute(Database.BatchableContext BC, List<Statu_Achievements__c> staList) {
        // SWAG-CE55BX 预测优化 start
        StaticParameter.EscapeOppandStaTrigger = true;
        // SWAG-CE55BX 预测优化 end
        System.debug('是否走方法-----');
        Map<Id, Statu_Achievements__c> updSelfMap = new Map<Id, Statu_Achievements__c>();
        List<SObject> insSSStaList = new List<SObject>();
        SS_Batch_Column_Mapping__c staMapping = SS_Batch_Column_Mapping__c.getValues('Statu_Achievements__c');
        Schema.SObjectType ssStaType = Schema.getGlobalDescribe().get(String.valueOf(staMapping.get('SS_TableName__c')));
        for (Statu_Achievements__c sta : staList) {
            // Statu_Achievements__cの場合、updSelfMap 必ずいれる
            updSelfMap.put(sta.Id, sta);
            SObject insSSSta = ssStaType.newSObject();
            insSSStaList.add(insSSSta);
            insSSSta.put('BackorderID__c', sta.Id);     // 設定しなくでも、入れる
            for (Integer i = 1; i <= SSOpportunityBatch.FIELDMAX; i++) {
                String lpadI = ('00' + i).right(3);
                String fromColumn = 'From_Column_' + lpadI + '__c';
                String apiStr = String.valueOf(staMapping.get(fromColumn));
                if (String.isBlank(apiStr) == false) {
                    String ssColumn = 'SS_Column_' + lpadI + '__c';
                    String ssApiStr = String.valueOf(staMapping.get(ssColumn));
                    if (ssApiStr.toLowerCase().startsWith('statu_achievements__c.')) {
                        // 注残の項目を更新、変更があるかどうか判断する
                        if (sta.get(ssApiStr.substring(22)) != sta.get(apiStr)) {
                            try {
                                sta.put(ssApiStr.substring(22), sta.get(apiStr));
                            } catch (Exception e) {
                                iflog.ErrorLog__c += 'ERROR [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                            }
                        }
                    } else {
                        try {
                            insSSSta.put(ssApiStr, SSOpportunityBatch.getValue(sta, apiStr));
                        } catch (Exception e) {
                            iflog.ErrorLog__c += 'ERROR ' + String.valueOf(staMapping.get('SS_TableName__c')) + ' [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                        }
                    }
                }
            }
        }
        //if (insSSStaList.size() > 0) insert insSSStaList;
        if (insSSStaList.size() > 0) {
            Database.SaveResult[] lsr = Database.insert(insSSStaList, false);
            for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
                Database.SaveResult sr = lsr[tIdx];
                if (!sr.isSuccess()) {
                    Database.Error emsg = sr.getErrors()[0];
                   // 2020-09-09  mzy update  日志修改 start
                    if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {
                      iflog.ErrorLog__c += 'ERROR ' + insSSStaList[tIdx].get('Order_no_without_0__c') + ' SS_Sta:' + emsg + '\n';
                    }
                  //  iflog.ErrorLog__c += 'ERROR ' + insSSStaList[tIdx].get('Order_no_without_0__c') + ' SS_Sta:' + emsg + '\n';
                 // 2020-09-09  mzy update  日志修改 end    
                }
            }
        }

        // SS_backorder_list__cのIDを注残に書き戻す
        for (SObject insSSSta : insSSStaList) {
            Id BackorderID = (Id) insSSSta.get('BackorderID__c');
            Statu_Achievements__c sa = updSelfMap.get(BackorderID);
            sa.SS_backorderID__c = (Id) insSSSta.get('Id');
        }
        if (updSelfMap.size() > 0) {
            // エラーをlogに書き出す
            List<Statu_Achievements__c> updSelfList = updSelfMap.values();
            Database.SaveResult[] lsr = Database.update(updSelfList, false);
            List<Statu_Achievements__c> reuseUpdateList = new List<Statu_Achievements__c>();
            System.debug('-=-=-=-=-=-='+lsr);
            for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
                Database.SaveResult sr = lsr[tIdx];
                if (!sr.isSuccess()) {
                    //wangweipeng   20210618   获取没有update的数据
                    reuseUpdateList.add(updSelfList[tIdx]);

                    //Database.Error emsg = sr.getErrors()[0];
                    //iflog.ErrorLog__c += 'ERROR ' + updSelfMap.values()[tIdx].Name + ' Statu_Achievements__c:' + emsg + '\n';
                }
            }
            //wangweipeng  20210618  如果update失败,重复更新，最多3次，如果失败记录日志  start 
            if(reuseUpdateList.size() > 0){
                reuseUpdate(reuseUpdateList,1);
            }
            //wangweipeng  20210618  如果update失败,重复更新，最多3次，如果失败记录日志  end 
        }
    }

    public void finish(Database.BatchableContext BC) {
        // chenjingwu 20240228 start   
        // if (Test.isRunningTest() == false) {
        //     Database.executeBatch(new SSOpportunity2Batch(null), 100);
        // }
        // chenjingwu 20240228 end 
        iflog.Log__c += '\nSSBackorderBatch end';
        String tmp = iflog.ErrorLog__c;
        if (tmp.length() > 65000) {
            tmp = tmp.substring(0, 65000);
            tmp += ' ...have more lines...';
            iflog.ErrorLog__c = tmp;
        }
        update iflog;
    }

    //wangweipeng  20210618  如果update失败,重复更新，最多3次，如果失败记录日志  start 
    //参数：updSelfList   要重新插入的数据     indexUpdate   第几次插入
    public void reuseUpdate(List<Statu_Achievements__c> updSelfList,Integer indexUpdate){
        System.debug('这是循环的第：'+indexUpdate+' 次。');
        Database.SaveResult[] lsr = Database.update(updSelfList, false);
        List<Statu_Achievements__c> reuseUpdateMap = new List<Statu_Achievements__c>();
        for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
            Database.SaveResult sr = lsr[tIdx];
            if (!sr.isSuccess()) {
                if(indexUpdate >= 3){
                    Database.Error emsg = sr.getErrors()[0];
                    iflog.ErrorLog__c += 'ERROR ' + updSelfList[tIdx].Name + ' Statu_Achievements__c:' + emsg + '\n';
                }else{
                    //获取没有update的数据
                    ID succId = sr.getId();
                    reuseUpdateMap.add(updSelfList[tIdx]);
                }
            }
        }
        if(indexUpdate < 3){
            indexUpdate ++;
            if(reuseUpdateMap != null && reuseUpdateMap.size() > 0){
                reuseUpdate(reuseUpdateMap,indexUpdate);
            }
        }
    }
    //wangweipeng  20210618  如果update失败,重复更新，最多3次，如果失败记录日志  end
}