/* 发货 到货 出库 的明细2 每个月做快照 */
public without sharing class SSdetails2Batch implements Database.Batchable<sObject>, Database.Stateful {
    public String query;
    public Integer FIELDMAX = 200;
    public String testId;
    public BatchIF_Log__c iflog;
    public Date tempDate;
    //查询开始日 
    public Date startDay;
    //查询结束日 
    public Date endDay;

    //今天
    Date today = Date.today();    


    public SSdetails2Batch() {
        this.query = query;
        //获取当前月的第一天
        Date tempDay = Date.newInstance(today.year(), today.month(), 1);
        //结束日 当前月第一天的的前一天
        endDay = tempDay.addDays(-1);
        //开始日, 结束日当月的第一天
        startDay = Date.newInstance(endDay.year(), endDay.month(), 1);
        
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'details2Snapshot';
        iflog.Log__c  = 'SSdetails2Batch start\n';
        iflog.Log__c += '开始日期:'+startDay +'\n';
        iflog.Log__c += '结束日期:'+endDay +'\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    //传入了id 则以id为条件啊进行查询,不需要日期了
    public SSdetails2Batch(String testId) {
        this.query = query;
        this.testId = testId;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'details2Snapshot';
        iflog.Log__c  = 'SSdetails2Batch start\n';
        iflog.Log__c += '传入id:'+testId +'\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    //快照 传入日期的 发货 到货 出库 数据
    // public SSdetails2Batch(Date tempDate) {
    //     this.query = query;
    //     this.testId = testId;
    //     //开始日 传入日期的前一天
    //     startDay = tempDate.addDays(-1);
    //     //结束日, 传入日期的后一天
    //     endDay = tempDate.addDays(1);

    //     iflog = new BatchIF_Log__c();
    //     iflog.Type__c = 'details2Snapshot';
    //     iflog.Log__c  = 'SSdetails2Batch start\n';
    //     iflog.ErrorLog__c = '';
    //     insert iflog;
    // }

    public Database.QueryLocator start(Database.BatchableContext bc) {

        //从快照表里取得待查询的字段
        SS_Batch_Column_Mapping__c columnsmap = SS_Batch_Column_Mapping__c.getValues('Consumable_order_details2__c');
        Set<String> apiTempSet = new Set<String>();
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String lpadI = ('00' + i).right(3);
            String fromColumn = 'From_Column_' + lpadI + '__c';
            String apiStr = String.valueOf(columnsmap.get(fromColumn));
            if (String.isBlank(apiStr) == false) {
                apiTempSet.add(apiStr);
            }
        }
        //
        query = 'select id, '+String.join(new List<String>(apiTempSet), ',') + ' from Consumable_order_details2__c where ';
        if (testId != null && testId != '') {
            query += ' id = :testId';    
        }else{
            // query += ' (Deliver_date__c >= :startDay and Deliver_date__c <= :endDay) ';
            query += ' (Deliver_date__c >= :startDay and Deliver_date__c <= :endDay) ';
            query += ' or (Arrive_date__c >= :startDay and Arrive_date__c <= :endDay) ';
            query += ' or (Product_OutDate__c >= :startDay and Product_OutDate__c <= :endDay)';
        }
        
        return Database.getQueryLocator(query);
    }

    public void execute(Database.BatchableContext BC, list<Consumable_order_details2__c> detailList) {
        //获取待快照的表中字段
        SS_Batch_Column_Mapping__c condet2map = SS_Batch_Column_Mapping__c.getValues('Consumable_order_details2__c');
        Schema.SObjectType condetType = Schema.getGlobalDescribe().get(String.valueOf(condet2map.get('SS_TableName__c')));

        //待添加的数据(快照表)
        List<SObject> insList = new List<SObject>();

        for (Consumable_order_details2__c contet2 : detailList) {
            //创建新的快照表对象
            SObject orderDetail2 = condetType.newSObject();
            for (Integer i = 1; i <= FIELDMAX; i++) {
                String lpadI = ('00' + i).right(3);
                String fromColumn = 'From_Column_' + lpadI + '__c';
                //获取到明细2表的api名称
                String apiStr = String.valueOf(condet2map.get(fromColumn));
                if (String.isBlank(apiStr) == false) {
                    String ssColumn = 'SS_Column_' + lpadI + '__c';
                    //快照表的api
                    String ssApiStr = String.valueOf(condet2map.get(ssColumn));
                    try {
                        //赋值
                        orderDetail2.put(ssApiStr, getValue(contet2, apiStr));
                    } catch (Exception e) {
                        iflog.ErrorLog__c = 'ERROR ' + String.valueOf(condet2map.get('SS_TableName__c')) + ' [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                    }
                    
                }
            }
            insList.add(orderDetail2);
        }

        if (insList.size() > 0) {
            Database.SaveResult[] lsr = Database.insert(insList, false);
            for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
                Database.SaveResult sr = lsr[tIdx];
                //插入失败 保存失败原因
                if (!sr.isSuccess()) {
                    Database.Error emsg = sr.getErrors()[0];
                    iflog.ErrorLog__c += '插入失败: ' + insList[tIdx].Id +' error:'+ emsg + '\n';
                }
            }
        }
        
    }

    public static Object getValue(SObject sobj, String field) {
        List<String> fieldPathList = field.split('\\.');
        Object rtn = null;
        for (Integer i = 0; i < fieldPathList.size(); i++) {
            String fieldPath = fieldPathList[i];
            if (i == fieldPathList.size() - 1) {
                rtn = sobj.get(fieldPath);
                System.debug(rtn + '= sobj.get(' + fieldPath + ')');
            } else {
                sobj = sobj.getSObject(fieldPath);
                if (sobj == null) {
                    break;
                }
                System.debug(sobj + '= sobj.getSObject(' + fieldPath + ')');
            }
        }
        return rtn;
    }

    public void finish(Database.BatchableContext BC) {
        iflog.Log__c += '\nSSdetails2Batch 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;
    }
}

/*public without sharing class SSdetails2Batch implements Database.Batchable<sObject>, Database.Stateful {
    public static Integer FIELDMAX = 200;
    private final List<Id> TEST_ID = null;
    private BatchIF_Log__c iflog;

    public SSdetails2Batch() {
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'details2Snapshot';
        iflog.Log__c  = 'SSdetails2Batch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    
    //消耗品明细2的数据快照到一个新的快照,连续接受参数。
     
    public SSdetails2Batch(List<Id> testId) {
        TEST_ID = testId;
        System.debug('TEST_ID=' + TEST_ID);
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'details2Snapshot';
        iflog.Log__c  = 'SSdetails2Batch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    
    //创造soql
    public static String makeSql(SS_Batch_Column_Mapping__c setting, Set<String> apiTempSet) {
        apiTempSet.add('Id');
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String fromColumn = 'From_Column_' + ('00' + i).right(3) + '__c';
            String apiStr = String.valueOf(setting.get(fromColumn));
            if (String.isBlank(apiStr) == false && apiTempSet.contains(apiStr) == false) {
                apiTempSet.add(apiStr);
            }
        }
        String soql = 'Select ' + String.join(new List<String>(apiTempSet), ',') + ' from ' + setting.Name;
        return soql;
    }

    //取值
    public static Object getValue(SObject sobj, String field) {
        List<String> fieldPathList = field.split('\\.');
        Object rtn = null;
        for (Integer i = 0; i < fieldPathList.size(); i++) {
            String fieldPath = fieldPathList[i];
            if (i == fieldPathList.size() - 1) {
                rtn = sobj.get(fieldPath);
System.debug(rtn + '= sobj.get(' + fieldPath + ')');
            } else {
                sobj = sobj.getSObject(fieldPath);
                if (sobj == null) {
                    break;
                }
System.debug(sobj + '= sobj.getSObject(' + fieldPath + ')');
            }
        }
        return rtn;
    }

    //在start中，执行查询并合并所有项目
    public Database.QueryLocator start(Database.BatchableContext BC) {
        // 从 condet2map 生成 select 项
        SS_Batch_Column_Mapping__c condet2map = SS_Batch_Column_Mapping__c.getValues('Consumable_order_details2__c');
        Set<String> apiTempSet = new Set<String>();
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String lpadI = ('00' + i).right(3);
            String fromColumn = 'From_Column_' + lpadI + '__c';
            String apiStr = String.valueOf(condet2map.get(fromColumn));
            if (String.isBlank(apiStr) == false) {
                String ssColumn = 'SS_Column_' + lpadI + '__c';
                String ssApiStr = String.valueOf(condet2map.get(ssColumn));
                if (ssApiStr.toLowerCase().startsWith('Consumable_order_details2__c')) {
                    // 更新消耗品明细2中的字段,并检索原始数据以确定是否有任何更改
                    System.debug('ssApiStr=' + ssApiStr + ', substring(28)=' + ssApiStr.substring(28));
                    apiTempSet.add(ssApiStr.substring(28));
                }
            }
        }
        String soql = makeSql(condet2map, apiTempSet);
        if (TEST_ID <> null) {
            soql += ' where Id IN: TEST_ID';
        } else {
// SS_Prospect_5days_list__c  の対象かどうか、loopの中単独判断
//            soql += ' where StageName = \'引合\'';

            // CHAN-AUE3TB Batch SSOpportunity的执行数据筛选
                Date nowDay = Date.today();
                Integer nowMonth = nowDay.month();
                soql += ' where (CALENDAR_MONTH(Deliver_date__c) = :nowMonth or CALENDAR_MONTH(Arrive_date__c) = :nowMonth or CALENDAR_MONTH(Product_OutDate__c)= :nowMonth)';
        }
        System.debug('soql=' + soql);
        return Database.getQueryLocator(soql);
    }
    
    public void execute(Database.BatchableContext BC, List<Consumable_order_details2__c> oppList) {
        List<Consumable_order_details2__c> updSelfList = new List<Consumable_order_details2__c>();
        List<SObject> insSSOppList = new List<SObject>();
        List<Id> insSSOppId = new List<Id>();
        List<SObject> insSSOliList = new List<SObject>();
        // 商談
        SS_Batch_Column_Mapping__c condet2map = SS_Batch_Column_Mapping__c.getValues('Consumable_order_details2__c');
        Schema.SObjectType condetType = Schema.getGlobalDescribe().get(String.valueOf(condet2map.get('SS_TableName__c')));
        for (Consumable_order_details2__c contet2 : oppList) {
            Boolean updSelfFlg = false;
            SObject orderDetail2 = condetType.newSObject();
            for (Integer i = 1; i <= FIELDMAX; i++) {
                String lpadI = ('00' + i).right(3);
                String fromColumn = 'From_Column_' + lpadI + '__c';
                String apiStr = String.valueOf(condet2map.get(fromColumn));
                if (String.isBlank(apiStr) == false) {
                    String ssColumn = 'SS_Column_' + lpadI + '__c';
                    String ssApiStr = String.valueOf(condet2map.get(ssColumn));
                    if (ssApiStr.toLowerCase().startsWith('Consumable_order_details2__c')) {
                        // 更新每月初追溯清单中的字段，以确定是否有任何更改
                        if (contet2.get(ssApiStr.substring(12)) != contet2.get(apiStr)) {
                            try {
                                contet2.put(ssApiStr.substring(12), contet2.get(apiStr));
                                updSelfFlg = true;
                            } catch (Exception e) {
                                iflog.ErrorLog__c = 'ERROR [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                            }
                        }
                    } else {
                        try {
                            orderDetail2.put(ssApiStr, getValue(contet2, apiStr));
                        } catch (Exception e) {
                            iflog.ErrorLog__c = 'ERROR ' + String.valueOf(condet2map.get('SS_TableName__c')) + ' [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                        }
                    }
                }
            }
            if (updSelfFlg) {
                updSelfList.add(contet2);
            }
            // SS_Prospect_5days_list__c  の対象かどうか、loopの中単独判断
            //if (contet2.StageName == '引合') {
            Date nowDay = Date.today();
            Integer nowMonth = nowDay.month();
            if ((contet2.Deliver_date__c    != null && contet2.Deliver_date__c.month()    == nowMonth) ||
                (contet2.Arrive_date__c     != null && contet2.Arrive_date__c.month()     == nowMonth) || 
                (contet2.Product_OutDate__c != null && contet2.Product_OutDate__c.month() == nowMonth)) {
                insSSOppList.add(orderDetail2);
                insSSOppId.add(contet2.Id);
            }
        }

        // エラーをlogに書き出す
        if (updSelfList.size() > 0) {
System.debug('updSelfList:' + updSelfList);
            Database.SaveResult[] lsr = Database.update(updSelfList, false);
            for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
                Database.SaveResult sr = lsr[tIdx];
System.debug('sr.isSuccess:' + sr.isSuccess());
                if (!sr.isSuccess()) {
                    Database.Error emsg = sr.getErrors()[0];
                    //update by Gzw 2020-10-30 start
                    if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {
                        iflog.ErrorLog__c += 'ERROR ' + updSelfList[tIdx].Bar_Code__c + ' Consumable_order_details2__c:' + emsg + '\n';
                    }
                        // iflog.ErrorLog__c += 'ERROR ' + updSelfList[tIdx].Opportunity_No__c + ' Opportunity:' + emsg + '\n';
                    //update by Gzw 2020-10-30 end
                }
            }
        }

        //insert insSSOppList;
        Database.SaveResult[] lsr2 = Database.insert(insSSOppList, false);
        for (Integer tIdx = 0; tIdx < lsr2.size(); tIdx++) {
            Database.SaveResult sr = lsr2[tIdx];
            if (!sr.isSuccess()) {
                Database.Error emsg = sr.getErrors()[0];
                //update by rentx 2020-10-27 start
                    if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {
                        iflog.ErrorLog__c += 'ERROR ' + insSSOppList[tIdx].get('Bar_Code__c') + ' SS_opp:' + emsg + '\n';
                    }
                //update by rentx 2020-10-27 end                 
                // iflog.ErrorLog__c += 'ERROR ' + insSSOppList[tIdx].get('Opportunity_No__c') + ' SS_opp:' + emsg + '\n';
            }
        }
        //insert insSSOliList;
        Database.SaveResult[] lsr3 = Database.insert(insSSOliList, false);
        for (Integer tIdx = 0; tIdx < lsr3.size(); tIdx++) {
            Database.SaveResult sr = lsr3[tIdx];
            if (!sr.isSuccess()) {
                Database.Error emsg = sr.getErrors()[0];
                //update by Gzw 2020-10-30 start
                if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {
                    iflog.ErrorLog__c += 'ERROR  ' + insSSOliList[tIdx].get('Bar_Code__c') + '  SS_oli:' + emsg + '\n';
                }
                // iflog.ErrorLog__c += 'ERROR  ' + insSSOliList[tIdx].get('Opportunity_number__c') + '  SS_oli:' + emsg + '\n';
                //update by Gzw 2020-10-30 end
            }
        }
    }
    
    public void finish(Database.BatchableContext BC) {

        if (Test.isRunningTest() == false && TEST_ID == null) {
            Database.executeBatch(new SSBackorderBatch(null), 100);
        }

        iflog.Log__c += '\nSSdetails2Batch 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;
    }
}*/