global class UpdateNFM110 implements Database.Batchable<sObject> , Database.Stateful {
    public String query;
    public Date startDate;
    public  Date endDate;
    public List<String> emailMessages = new List<String>();
    public list<string> testIDList = new list<string>();

    global UpdateNFM110() {
        this.query = query;
    }
    global UpdateNFM110(list<string> testIDList) {
        this.testIDList = testIDList;
    }
    global UpdateNFM110(Date startDate, Date endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {
        query =
            'SELECT Id, Name, Log__c, ErrorLog__c, Log2__c, ' +
            ' Log3__c, Log4__c, Log5__c, Log6__c,' +
            'Log7__c, Log8__c, Log9__c, Log10__c, Log11__c, Log12__c, ' +
            'MessageGroupNumber__c,Type__c,retry_cnt__c ' +
            'FROM BatchIF_Log__c where RowDataFlg__c = true ' +
            ' and Type__c = \'NFM110\' ';
        if (startDate != null) {
            this.query += ' and createddate__c >=: startDate';
        }
        if (endDate != null) {
            this.query += ' and createddate__c <= : endDate';
        }
        if (testIDList.size() > 0) {
            this.query += ' and id in: testIDList ';
        }
        this.query += '  order by  createddate ';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, list<BatchIF_Log__c> batchList) {
        BatchIF_Log__c batch = batchList[0];
        StaticParameter.ConsumableAssetHanderTrigger = true;
        StaticParameter.EscapeConsumableOrderDetail2Trigger = true;
        Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);
        String rowDataStr = NFMUtil.getRowDataStr(batch);
        List<GeneralData> generalDataList = (List<GeneralData>) JSON.deserialize(rowDataStr, List<GeneralData>.class);
        NFM110Rest.isRunning = true;
        if (generalDataList == null || generalDataList.size() == 0) {
            return;
        }
        Savepoint sp = Database.setSavepoint();
        try {
            // 更新対応配列とMapなどをセット
            Set<String> soNoList = new Set<String>();
            Set<String> productCodeList = new Set<String>();
            Set<String> productSerialNoList = new Set<String>();
            Set<String> inquiryNoList = new Set<String>();



            // CHAN-BBLAAP 汇总这条数据的DN号 start
            Set<String> DNNoSet = new Set<String>();
            set<String> DNdetailNoSet = new Set<String>();
            // CHAN-BBLAAP 汇总这条数据的DN号 start

            for (GeneralData infoH : generalDataList) {
                if (String.isBlank(infoH.DeliveryNote)) {
                    continue;
                }
                // CHAN-BBLAAP 汇总这条数据的DN号 start
                DNNoSet.add(infoH.DeliveryNote);
                // CHAN-BBLAAP 汇总这条数据的DN号 start


                if (String.isBlank(infoH.SoNo) == false) {
                    soNoList.add(infoH.SoNo);
                }
                string tempInquiryNo = '';
                // SWAG-BDV589 end
                if (String.isBlank(infoH.InquiryNo) == false) {
                    String[] Inquiry;
                    if (infoH.InquiryNo.contains(',')) {
                        Inquiry = infoH.InquiryNo.split(',');
                        // SWAG-BDV589 start
                        tempInquiryNo = Inquiry[0];
                        // SWAG-BDV589 end
                        inquiryNoList.add(Inquiry[0]);
                    } else {
                        //根据数据传的样式决定
                    }
                }

                for (DnInformation dnInfo : infoH.DnInformation) {
                    dnInfo.SerialNoorLotNo = checkSerialNoorLotNo(dnInfo.SerialNoorLotNo);
                    productCodeList.add(dnInfo.OTCode);
                    // HHOA-AGN2EH start
                    productSerialNoList.add(dnInfo.SerialNoorLotNo);
                    productSerialNoList.add(dnInfo.SerialNoorLotNo + '(' + dnInfo.TracingCode + ')');
                    string Product_Serial_No = '';
                    if (dnInfo.SorLMark == 'S') {
                        Product_Serial_No =
                            dnInfo.OTCode + ':' + dnInfo.SerialNoorLotNo;
                    } else {
                        Product_Serial_No  =
                            dnInfo.OTCode + ':' + dnInfo.SerialNoorLotNo
                            + '(' + dnInfo.TracingCode + ')';

                    }
                    DNdetailNoSet.add(infoH.DeliveryNote + ':' + Product_Serial_No);
                }
            }
            // CHAN-BBLAAP  start
            // 检索出DN 并生成DN Map
            map <string, Statu_Achievements_DN__c> DNMap = new  map <string, Statu_Achievements_DN__c>();
            List<Statu_Achievements_DN__c> DNList =
                [select id, Name,
                 DeliveryDate_Raw__c,
                 DeliveryNote_Raw__c,
                 DepartmentNo_Raw__c,
                 EndUserNo_Raw__c,
                 InquiryNo_Raw__c,
                 ReturnMark_Raw__c,
                 SoNo_Raw__c,
                 Statu_Achievements__c
                 from Statu_Achievements_DN__c where
                 Name in: DNNoSet];
            for (Statu_Achievements_DN__c dn : DNList) {
                DNMap.put(dn.Name, dn);
            }
            List<Statu_Achievements_DN__c> UpsertDNList = new List<Statu_Achievements_DN__c>();

            // 检索出DN明细 并生成DN detail Map

            List<Statu_Achievements_DN_details__c> DNdetailList =
                [SELECT Id, Name, Statu_Achievements_DN__c,
                 Barcode_Raw__c, GuaranteePeriod_Raw__c,
                 NetWorth_Raw__c, OTCode_Raw__c,
                 Qty_Raw__c,  SerialNoorLotNo_Raw__c,
                 SerialNumber__c, ShippedAmount__c,
                 ShippedAmount_without_tax__c, SorLMark_Raw__c,
                 TracingCode_Raw__c, ValidTo_Raw__c,
                 asset__c, Statu_Achievements__c,
                 Product_Serial_No__c, DNProduct_Serial_No__c
                 FROM Statu_Achievements_DN_details__c
                 where DNProduct_Serial_No__c in: DNdetailNoSet];
            map <string, Statu_Achievements_DN_details__c> DNdetailMap =
                new map <string, Statu_Achievements_DN_details__c>();
            for (Statu_Achievements_DN_details__c DNdetail : DNdetailList) {
                DNdetailMap.put(DNdetail.DNProduct_Serial_No__c, DNdetail);
            }

            //  需要插入的DN明细
            List<DNdetail> upsertDNdetailList = new List<DNdetail>();



            // CHAN-BBLAAP  end
            List<Statu_Achievements__c> boList = [select Id, Name
                                                  from Statu_Achievements__c
                                                  where Name in :soNoList and OverviewStatus__c <> '无效合同'];
            Map<String, String> boMap = new Map<String, String>();
            for (Statu_Achievements__c bo : boList) {
                boMap.put(bo.Name, bo.Id);
            }
            List<Product2> prdList = [select Id, Name, ProductCode, ProductCode_Ext__c, MDM_Model_No__c
                                      from Product2
                                      where ProductCode_Ext__c in :productCodeList];
            Map<String, Product2> prdsMap = new Map<String, Product2>();
            for (Product2 prd : prdList) {
                prdsMap.put(prd.ProductCode_Ext__c, prd);
            }
            List<Product2__c> prdSearchList = [select Id, Name, Product2__r.ProductCode_Ext__c, Pro2_Dealer_ENG__c,
                                               Intra_Trade_List_RMB__c, Asset_Model_No__c, Pro2_Dealer_Object__c
                                               from Product2__c
                                               where Product2__r.ProductCode_Ext__c in :productCodeList];
            Map<String, Product2__c> prdSearchMap = new Map<String, Product2__c>();
            for (Product2__c prd2 : prdSearchList) {
                prdSearchMap.put(prd2.Product2__r.ProductCode_Ext__c, prd2);
            }
            List<Asset> astList = [select Id, Name, Product2.ProductCode, Product2.Dealer_special_Object__c , Product2.Dealer_Object__c,
                                   SerialNumber, Product_Serial_No__c, Repair_Count__c, TracingCode__c,
                                   Product2Id, AccountId, Account.Management_Code__c, Department_Class__c, Hospital__c,
                                   Posting_Date__c, InstallDate, SLMark__c, MDM_Model_No__c, OT_CODE__c,
                                   Guarantee_period_for_products__c, Installation_Site__c, Delete_Flag__c, Return_Flag__c,
                                   Extend_Gurantee_DateTo__c, guarantee_period__c, Proviston_period__c
                                   from Asset
                                   where SerialNumber in :productSerialNoList
                                   and IsCompetitorProduct = false
                                           and Information_From__c <> '失单'];
            Map<String, Asset> astsMap = new Map<String, Asset>();
            for (Asset ast : astList) {
                astsMap.put(ast.MDM_Model_No__c + ast.SerialNumber, ast);
            }
            List<Opportunity> oppList =
                [Select Id, Purchase_Type__c,
                 Opportunity_No__c, Sales_Root__c,
                 SAP_Province__c, Trade__c, Agency1__c,
                 Opportunity_Category__c
                 From Opportunity
                 Where Opportunity_No__c IN :inquiryNoList];
            Map<String, Opportunity> oppMap = new Map<String, Opportunity>();
            for (Opportunity opp : oppList) {
                oppMap.put(opp.Opportunity_No__c, opp);
            }
            for (GeneralData infoH : generalDataList) {
                // CHAN-BBLAAP 检索出DN 并生成DN Map start
                Statu_Achievements_DN__c tempSADN =
                    DNMap.get(infoH.DeliveryNote);
                if (infoH.DeliveryNote != null) {
                    if (tempSADN == null) {
                        tempSADN = new Statu_Achievements_DN__c();
                        tempSADN.Statu_Achievements__c = null;
                        tempSADN = SetSADN(tempSADN, infoH, boMap, oppMap);
                        if (tempSADN.Statu_Achievements__c != null)
                            UpsertDNList.add(tempSADN);
                    } else {
                        if (infoH.SoNo != tempSADN.SoNo_Raw__c ||
                                infoH.InquiryNo != tempSADN.InquiryNo_Raw__c ||
                                infoH.ReturnMark != tempSADN.ReturnMark_Raw__c ||
                                infoH.DeliveryDate != tempSADN.DeliveryDate_Raw__c ||
                                infoH.EndUserNo != tempSADN.EndUserNo_Raw__c ||
                                infoH.DepartmentNo != tempSADN.DepartmentNo_Raw__c ||
                                infoH.DeliveryNote != tempSADN.DeliveryNote_Raw__c
                           ) {
                            tempSADN = SetSADN(tempSADN, infoH, boMap, oppMap);
                            if (tempSADN.Statu_Achievements__c != null)
                                UpsertDNList.add(tempSADN);
                        }
                    }
                }

                for (DnInformation dnInfo : infoH.DnInformation) {
                    Product2 prd = prdsMap.get(dnInfo.OTCode);
                    Asset ast = astsMap.get(prd.MDM_Model_No__c + dnInfo.SerialNoorLotNo);
                    if (dnInfo.SorLMark == 'S') {
                        ast = astsMap.get(prd.MDM_Model_No__c + dnInfo.SerialNoorLotNo);
                    } else {
                        ast = astsMap.get(prd.MDM_Model_No__c + dnInfo.SerialNoorLotNo + '(' + dnInfo.TracingCode + ')');
                    }
                    //  CHAN-BBLAAP 插入保有设备明细时插入对应DN start
                    boolean tempReturnFlg = infoH.ReturnMark == '1' ? true : false;
                    DNdetail tempDNdetail
                        = SetSADNDetails(infoH.DeliveryNote, tempReturnFlg, dnInfo, ast);

                    Statu_Achievements_DN_details__c tempSADNdetail =
                        DNdetailMap.get(tempDNdetail.DNd.DNProduct_Serial_No__c);

                    if (tempSADNdetail != null ) {
                        tempDNdetail.DND.id = tempSADNdetail.id;
                    }
                    UpsertDNdetailList.add(tempDNdetail);
                    //  CHAN-BBLAAP 插入保有设备明细时插入对应DN end


                }
            }
            if (UpsertDNList.size() > 0) {
                upsert UpsertDNList;
            }
            // key 为DN号（名字Name）,value 为发货DN;
            Map<string, Statu_Achievements_DN__c> upsertDNMap = new  Map<string, Statu_Achievements_DN__c>();
            for (Statu_Achievements_DN__c tempSADN : UpsertDNList) {
                upsertDNMap.put(tempSADN.Name, tempSADN);
            }
            list<Statu_Achievements_DN_details__c> upsertSADNdetailList
                = new  list<Statu_Achievements_DN_details__c>();
            for (DNdetail tempDNd : upsertDNdetailList) {
                if (upsertDNMap.containskey(tempDNd.DeliveryNote)) {
                    tempDNd.DNd.Statu_Achievements_DN__c = upsertDNMap.get(tempDNd.DeliveryNote).id;
                    tempDNd.DNd.Statu_Achievements__c = upsertDNMap.get(tempDNd.DeliveryNote).Statu_Achievements__c;
                    upsertSADNdetailList.add(tempDNd.DNd);
                }
            }
            if (upsertSADNdetailList.size() > 0) {
                upsert upsertSADNdetailList;
            }

        } catch (Exception ex) {
            Database.rollback(sp);
            emailMessages.add(batch.id + ': ' + ex.getMessage());
        }
    }

    global void finish(Database.BatchableContext BC) {
        BatchIF_Log__c iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Is_Error__c = 0;
        iflog.Log__c = 'UpdateNFM110 start1\n';
        for (String str : emailMessages) {
            iflog.Log__c += str + '\n';
        }
        if (iflog.Log__c.length() > 131060) {
            iflog.Log__c = iflog.Log__c.substring(0, 131072);
            iflog.Log__c += ' ...have more lines...';
        }
        iflog.Log__c += '\nend';
        insert iflog;

    }

    //public transient static List<Id> orderoutIdList;
    public transient static List<Id> orderReturnIdList;
    // Integer batchsize = 200;  考量する必要がないと思います。
    global class ProductsDeliveryRest {
        public ProductsDelivery ProductsDelivery;
    }
    global class ProductsDelivery {
        public NFMUtil.Monitoring Monitoring;
        public GeneralData[] GeneralData;
    }
    global class GeneralData {
        public String SoNo;
        public String InquiryNo;
        public String ReturnMark;
        public String DeliveryDate;
        public String EndUserNo;
        public String DepartmentNo;
        public String DeliveryNote;
        public DnInformation[] DnInformation;
    }
    global class DnInformation {
        public String OTCode;
        public String VALUE;
        public String SerialNoorLotNo;
        public String SorLMark;
        public String GuaranteePeriod;  // 期限——》年限 2019 0719
        // 多年保修价格 2019 0719
        public String GuaranteePrice;
        // 多年保修 start
        public string GuaranteeType;
        public string MaintenancePrice;
        // no discount
        public string ServicePrice;
        public String ProvistonPeriod;  // 计提年限
        // 多年保修 end

        public String TracingCode;
        public String ValidTo;
        public String Barcode;
        //CHAN-BC53ZG start
        public string NetWorth;
        //CHAN-BC53ZG end
        //CHAN-BGYE7C LHJ Start
        public string NetWorthNoProviston;  // 净值（不含计提）
        public string ProduceDate;  // 生产日期
        //CHAN-BGYE7C LHJ End
    }

    private class DNdetail {
        private string DeliveryNote;
        private Statu_Achievements_DN_details__c DNd;
    }



    // CHAN-AXQBDY: 传过来的机身号最后5位都是字母并且倒数6,7,8位是052, SFDC删除机身号的最后8位
    private static String checkSerialNoorLotNo(String sn) {
        if (sn == null || sn == '' || sn.length() < 8) {
            return sn;
        }
        String regEx = '[a-zA-Z]';
        Pattern pattern = Pattern.compile(regEx);
        boolean strCheck = true;
        boolean numCheck = true;
        for (Integer i = 0; i < 8; i++) {
            String s = sn.substring(sn.length() - i - 1, sn.length() - i);
            if (i < 5) {
                Matcher matcher = pattern.matcher(s);
                if (!matcher.matches()) {
                    strCheck = false;
                    break;
                }
            } else {
                if (i == 5) {
                    if (s != '0') {
                        numCheck = false;
                        break;
                    }
                } else if (i == 6) {
                    if (s != '5') {
                        numCheck = false;
                        break;
                    }
                } else if (i == 7) {
                    if (s != '2') {
                        numCheck = false;
                        break;
                    }
                }
            }
        }
        if (strCheck && numCheck) {
            return sn.substring(0, sn.length() - 8);
        }
        return sn;
    }

    // CHAN-BBLAAP 初始化DN start
    private static Statu_Achievements_DN__c SetSADN(
        Statu_Achievements_DN__c tempSADN,
        GeneralData infoH,
        Map<String, String> boMap,
        Map<String, Opportunity> oppMap) {
        tempSADN.SoNo_Raw__c = infoH.SoNo;
        tempSADN.InquiryNo_Raw__c = infoH.InquiryNo ;
        tempSADN.ReturnMark_Raw__c = infoH.ReturnMark ;
        tempSADN.DeliveryDate_Raw__c = infoH.DeliveryDate ;
        tempSADN.EndUserNo_Raw__c = infoH.EndUserNo ;
        tempSADN.DepartmentNo_Raw__c = infoH.DepartmentNo ;
        tempSADN.DeliveryNote_Raw__c = infoH.DeliveryNote ;

        tempSADN.name = infoH.DeliveryNote;
        tempSADN.ReturnMark__c = infoH.ReturnMark == '1' ? true : false;
        if (tempSADN.Statu_Achievements__c == null) {
            tempSADN.Statu_Achievements__c = boMap.get(infoH.SoNo);
        }
        tempSADN.DeliveryDate__c = NFMUtil.parseStr2Date(infoH.DeliveryDate);
        String[] Inquiry;
        if (infoH.InquiryNo != null && infoH.InquiryNo.contains(',')) {
            Inquiry = infoH.InquiryNo.split(',');
            if (oppMap.get(Inquiry[0]) != null) {
                tempSADN.Opportunity__c = oppMap.get(Inquiry[0]).id;
            }
            if (Inquiry.size() > 1) {
                tempSADN.Order_No__c = Inquiry[1];
            }
        }
        return tempSADN;
    }
    private static DNdetail SetSADNDetails(string DNnumber, boolean returnFlg, DnInformation dnInfo, asset ast) {
        DNdetail tempDNdetail = new DNdetail();
        Statu_Achievements_DN_details__c DNd = new Statu_Achievements_DN_details__c();

        DNd.ShippedAmount_without_tax__c = String.isBlank(dnInfo.NetWorth) ?
                                           0 : returnFlg == false ?
                                           Decimal.valueOf(dnInfo.NetWorth.trim()) : - Decimal.valueOf(dnInfo.NetWorth.trim());

        DNd.ShippedAmount__c = String.isBlank(dnInfo.VALUE) ?
                               0 : returnFlg == false ?
                               Decimal.valueOf(dnInfo.VALUE.trim()) : - Decimal.valueOf(dnInfo.VALUE.trim());

        DNd.NetWorthNoProviston__c = String.isBlank(dnInfo.NetWorthNoProviston) ?
                                     0 : returnFlg == false ?
                                     Decimal.valueOf(dnInfo.NetWorthNoProviston.trim()) : - Decimal.valueOf(dnInfo.NetWorthNoProviston.trim());

        if (dnInfo.SorLMark == 'S') {
            DNd.SerialNumber__c = dnInfo.SerialNoorLotNo;
        } else {
            DNd.SerialNumber__c  = dnInfo.SerialNoorLotNo + '(' + dnInfo.TracingCode + ')';
        }

        DNd.Product_Serial_No__c = dnInfo.OTCode + ':' + DNd.SerialNumber__c;
        DNd.DNProduct_Serial_No__c = DNnumber + ':' + DNd.Product_Serial_No__c;
        DNd.Barcode_Raw__c = dnInfo.Barcode;
        DNd.OTCode_Raw__c = dnInfo.OTCode;
        DNd.Qty_Raw__c = dnInfo.VALUE;
        DNd.SerialNoorLotNo_Raw__c = dnInfo.SerialNoorLotNo;
        DNd.SorLMark_Raw__c = dnInfo.SorLMark;
        DNd.GuaranteePeriod_Raw__c = dnInfo.GuaranteePeriod;
        DNd.TracingCode_Raw__c = dnInfo.TracingCode;
        DNd.ValidTo_Raw__c = dnInfo.ValidTo;
        DNd.NetWorth_Raw__c = dnInfo.NetWorth;

        DNd.GuaranteePrice_Raw__c    = dnInfo.GuaranteePrice;
        DNd.GuaranteeType_Raw__c     = dnInfo.GuaranteeType;
        DNd.MaintenancePrice_Raw__c = dnInfo.MaintenancePrice;
        DNd.NetWorthNoProviston_Raw__c = dnInfo.NetWorthNoProviston;
        DNd.ProduceDate_Raw__c = dnInfo.ProduceDate;
        DNd.ProvistonPeriod_Raw__c = dnInfo.ProvistonPeriod;
        DNd.ServicePrice_Raw__c = dnInfo.ServicePrice;
        DNd.VALUE_Raw__c = dnInfo.VALUE;
        DNd.NetWorth_Raw__c = dnInfo.NetWorth;


        tempDNdetail.DeliveryNote = DNnumber;
        tempDNdetail.DNd = DNd;
        if (ast != null && ast.id != null) {
            tempDNdetail.DNd.asset__c = ast.id;
        }
        return tempDNdetail;

    }
     // CHAN-BBLAAP 初始化DN end
    @TestVisible private void testclass() {
        Integer i = 0;
        
    }
   
}