public without sharing class ReceivingNoteDetailHandler extends Oly_TriggerHandler {
    private Map<Id, ReceivingNoteDetail__c> newMap;
    private Map<Id, ReceivingNoteDetail__c> oldMap;
    private List<ReceivingNoteDetail__c> newList;
    private List<ReceivingNoteDetail__c> oldList;

    private static Datetime createdDate = Datetime.now();
    private static Date minDate;
    private static Date maxDate;
    private static Map<Date, Integer> dateIntMap = new Map<Date, Integer>();
    private static List<Date> dateList = new List<Date>();
    private static Date minDay;
    private static Date maxDay;
    private static Time ts = Time.newInstance(9, 0, 0, 0);
    private static Time te = Time.newInstance(17, 30, 0, 0);

    public ReceivingNoteDetailHandler() {
        this.newMap = (Map<Id, ReceivingNoteDetail__c>) Trigger.newMap;
        this.oldMap = (Map<Id, ReceivingNoteDetail__c>) Trigger.oldMap;
        this.newList = (List<ReceivingNoteDetail__c>) Trigger.new;
        this.oldList = (List<ReceivingNoteDetail__c>) Trigger.old;
    }

    protected override void beforeInsert() {
        beforeSetValue();
        setConsumablesFixedValue();

        // 新品收货功能LT时长统计
        setCalculateTime();
    }
    protected override void beforeUpdate() {
        beforeSetValue();

        // 新品收货功能LT时长统计
        setCalculateTime();
    }
    protected override void afterInsert() {
        setRNSFirst();
        //cleanReceivingStatus();
    }
    protected override void afterUpdate() {
        setRNSFirst();
        sendEmail();
    }
    /**
    @description 耗材在插入时三个字段赋固定值
    */
    public void setConsumablesFixedValue(){
        for (ReceivingNoteDetail__c nObj : newList) {
            if(nObj.Asset_loaner_category_F__c == '耗材'){
                nObj.unknow_serial_NO_product__c = 'FALSE';
                nObj.Loaner_accsessary__c = 'TRUE';
            }
        }
    }
    /**
    @description 变更点=‘新建’的明细插入时，把一览的【清空收货确认时间】和【外包装是否完好】清空
    */
    //private void cleanReceivingStatus(){
    //    Set<Id> rnsIdSet = new Set<Id>();
    //    for (ReceivingNoteDetail__c nObj : newList) {
    //        if(Trigger.isInsert && nObj.Change_Point__c == '新建' && nObj.DataConfirmation__c == false){
    //            rnsIdSet.add(nObj.ReceivingNoteSummary__c);
    //        }
    //    }
    //    List<ReceivingNoteSummary__c> rnsList = [
    //        SELECT Id
    //             , Package_Status_Memo__c
    //             , Package_Status__c
    //             , Received_Confirm_Staff__c
    //             , Received_Confirm_Time__c
    //          FROM ReceivingNoteSummary__c
    //         WHERE Id IN:rnsIdSet
    //          FOR UPDATE
    //        ];
    //    for(ReceivingNoteSummary__c rns:rnsList) {
    //        rns.Received_Confirm_Time__c = null;
    //        rns.Received_Confirm_Staff__c = null;
    //        rns.Package_Status__c = null;
    //        rns.Package_Status_Memo__c = null;
    //    }
    //    if(!rnsList.isEmpty()){
    //        update rnsList;
    //    }
    //}

    private void sendEmail() {
        Map<Id, List<ReceivingNoteDetail__c>> needSendEmailMap = new Map<Id, List<ReceivingNoteDetail__c>>();
        for (ReceivingNoteDetail__c nObj : newList) {
            ReceivingNoteDetail__c oObj;
            if (Trigger.isUpdate) {
                oObj = oldMap.get(nObj.Id);
                if (oObj.Arrival_wh_Request_time__c == null
                        && nObj.Arrival_wh_Request_time__c != null) {
                    if (needSendEmailMap.containsKey(nObj.ReceivingNote__c) == false) {
                        needSendEmailMap.put(nObj.ReceivingNote__c, new List<ReceivingNoteDetail__c>());
                    }
                    needSendEmailMap.get(nObj.ReceivingNote__c).add(nObj);
                }
            }
        }
        if (needSendEmailMap.isEmpty() == false) {
            List<ReceivingNote__c> rnList1 = new List<ReceivingNote__c>();
            List<ReceivingNote__c> rnList2 = new List<ReceivingNote__c>();
            for (Id rnId : needSendEmailMap.keySet()) {
                List<ReceivingNoteDetailWrapper> rndWrapperList = new List<ReceivingNoteDetailWrapper>();
                for(ReceivingNoteDetail__c rnd:needSendEmailMap.get(rnId)){
                    rndWrapperList.add(new ReceivingNoteDetailWrapper(rnd));
                }
                rndWrapperList.sort();

                String emailBody = '';
                for (ReceivingNoteDetailWrapper rndWrapper : rndWrapperList) {
                    emailBody += '\n' + rndWrapper.rnd.Fixture_Model_No_F__c;
                }

                rnList1.add(new ReceivingNote__c(Id = rnId, Please_Arrival_wh_Email__c = null));
                rnList2.add(new ReceivingNote__c(Id = rnId, Please_Arrival_wh_Email__c = emailBody));
            }
            update rnList1;
            update rnList2;
        }
    }

    public void setRNSFirst() {
        Map<String, ReceivingNoteSummary__c> rnsMap = new Map<String, ReceivingNoteSummary__c>();
        Map<String, ReceivingNoteDetail__c> rnsMyMap = new Map<String,ReceivingNoteDetail__c>();
        for (ReceivingNoteDetail__c nObj : newList) {
            if (String.isNotBlank(nObj.RNDAssert__c)) {
                if (rnsMap.containsKey(nObj.ReceivingNoteSummary__c) == false) {
                    rnsMap.put(nObj.ReceivingNoteSummary__c, new ReceivingNoteSummary__c(Id = nObj.ReceivingNoteSummary__c, First_RND__c = nObj.Id));
                }
                // 20230727 ljh 备品类型I和备品类型II放到保有设备上显示 start
                if(nObj.Loaner_category__c){
                    rnsMyMap.put(nObj.Fixture_Model_No_F__c.toUpperCase(),nObj);
                }
            }
        }
        if (rnsMap.isEmpty() == false) {
            update rnsMap.values();
        }
        // 20230727 ljh 备品类型I和备品类型II放到保有设备上显示 end
        if(rnsMyMap.size() > 0){
            List<Product2>  Product2List = [SELECT Id,Fixture_Model_No_T__c,Loaner_categoryI__c,Loaner_categoryII__c ,Product_Type__c
                                                 FROM Product2 
                                                WHERE Fixture_Model_No_T__c IN :rnsMyMap.keySet()];
            if(Product2List.size() > 0){
                Map<String,Product2> updateMap = new Map<String,Product2>();
                for(Product2 pro:Product2List){
                    Product2 p2 = new Product2();
                    p2.Id = pro.Id;
                    p2.Loaner_categoryI__c = rnsMyMap.get(pro.Fixture_Model_No_T__c.toUpperCase()).Loaner_categoryI__c;
                    p2.Loaner_categoryII__c =rnsMyMap.get(pro.Fixture_Model_No_T__c.toUpperCase()).Loaner_categoryII__c;
                    // 借用机会可视化UATbug25 zyh 20240106 start
                    p2.Product_Type__c =rnsMyMap.get(pro.Fixture_Model_No_T__c.toUpperCase()).Product_Type__c;
                    // 借用机会可视化UATbug25 zyh 20240106 end
                    if(p2.Loaner_categoryI__c.equals(pro.Loaner_categoryI__c)
                        && p2.Loaner_categoryII__c.equals(pro.Loaner_categoryII__c)
                        // 借用机会可视化UATbug25 zyh 20240106 start
                        && (String.isBlank(p2.Product_Type__c) || (String.isNotBlank(p2.Product_Type__c) && p2.Product_Type__c.equals(pro.Product_Type__c)))){
                        // 借用机会可视化UATbug25 zyh 20240106 end
                        continue;
                    }
                    updateMap.put(pro.Id,p2);
                }
                if(updateMap.size() > 0){
                    update updateMap.values();
                }
            }
        }
        // 20230727 ljh 备品类型I和备品类型II放到保有设备上显示 start
    }
    public void beforeSetValue() {
        // 获取明细所在的一览
        List<Id> rnsIdList = new List<Id>();
        for(ReceivingNoteDetail__c rnd:newList){
            rnsIdList.add(rnd.ReceivingNoteSummary__c);
        }
        List<ReceivingNoteSummary__c> rnsList = [
                SELECT Id
                     , Fixture_Set__r.Name
                     , Fixture_Set__c
                     , ReceivingNote__r.Name
                     , ReceivingNote__r.passNo7__c

                  FROM ReceivingNoteSummary__c
                 WHERE Id in :rnsIdList
            ];
        Map<Id, ReceivingNoteSummary__c> rnsMap = new Map<Id, ReceivingNoteSummary__c>();
        for(ReceivingNoteSummary__c rns:rnsList){
            rnsMap.put(rns.Id, rns);
        }
        //add by rentx 20210825 start 新品收货_集中备品_建立数据逻辑限制 
        Set<String> mxxhSet = new Set<String>();
        //add by rentx 20210825 end 新品收货_集中备品_建立数据逻辑限制 
        for (ReceivingNoteDetail__c nObj : newList) {
            nObj.FSD_Id__c = nObj.Fixture_Set_Detail__c;
            nObj.ReceivingNote__c = nObj.ReceivingNoteId_F__c;
            nObj.Loaner_centre_mail_address__c = nObj.Loaner_centre_mail_address_F__c;
            // 新建明细的管理种类默认为数量管理
            if(String.isBlank(nObj.Change_Point__c) && String.isBlank(nObj.Manage_type__c) && Trigger.isInsert){
                nObj.Manage_type__c = '数量管理';
            }
            // UniqueKey 赋值
            if (nObj.DataMigration_Flag__c == false
                    &&String.isNotBlank(nObj.FSD_Id__c)) {
                // System.debug('KKKKKis ' + nObj.IndexFromUniqueKey__c);
                nObj.UniqueKey__c = nObj.ReceivingNote__c + ':' + nObj.ReceivingNoteSummary__c + ':'+ nObj.FSD_Id__c
                            + ':' + nObj.passNo3__c;
                System.debug(nObj.passNo3__c + 'key is' + nObj.UniqueKey__c);
            }
            else {
                System.debug('nullId');
                // 因为收货清单明细取消的话精琢创建的明细不会删除;
                nObj.UniqueKey__c = null;
            }
            if (nObj.Delete_Flag__c) {
                nObj.UniqueKey__c += ':' + nObj.Id;
            }

            // Name赋值
            // ReceivingNoteSummary__c rns = rnsMap.get(nObj.ReceivingNoteSummary__c);
            nObj.Name = nObj.ReceivingNoteDetailNo__c;

        // if (nObj.DataMigration_Flag__c == false
            //         && rns != null
            //         && String.isNotBlank(rns.Fixture_Set__r.Name)
            //         //&& rns.IndexFromUniqueKey__c != null
            //         && nObj.IndexFromUniqueKey__c != null
            //         && (!Trigger.isUpdate || String.isNotBlank(rns.Fixture_Set__c))) {
            //     String split_RnNum = rns.ReceivingNote__r.passNo7__c;
            //     if (rns.ReceivingNote__r.Name.contains('_')) {
            //         // XXXX-YYYY_1 (ZZZZ_1)
            //         List<String> split_RnNumList = rns.ReceivingNote__r.Name.split('_');
            //         String raName = split_RnNumList[split_RnNumList.size() - 2];      // XXXX-YYYY (ZZZZ)
            //         split_RnNum = split_RnNumList[split_RnNumList.size() - 1];     // 1
            //         split_RnNumList = raName.split('-');     // [XXXX, YYYY]  ([ZZZZ])
            //         if (split_RnNumList.size() > 1) {
            //             // YYYY_1
            //             split_RnNum = split_RnNumList[split_RnNumList.size() - 1] + '_' + split_RnNum;
            //         } else {
            //             // ZZZZ_1
            //             split_RnNum = rns.ReceivingNote__r.Name;
            //         }
            //     }
            //     nObj.Name = nObj.ReceivingNoteDetailNo__c;
            //             //+ rns.IndexFromUniqueKey__c.format().leftpad(3, '0');

            //     // 如果是分配代替品名字加:Sub
            //     //if (nObj.Substitute_Select_Again__c) {
            //     //    nObj.Name += ':Sub';
            //     //}

            //     //一览时申请者收货NG的话名字添加NG
            //     //if (nObj.Received_Confirm_F__c == 'NG') {
            //     //    nObj.Name += ':NG';
            //     //}
            //     nObj.Name += ':' + nObj.IndexFromUniqueKey_Text__c + ':'
            //             + nObj.IndexFromUniqueKey__c.format().leftpad(3, '0');
            //     //取消的时候名字加Canceled
            //     //if (nObj.Cancel_Select__c) {
            //     //    nObj.Name += ':Canceled';
            //     //}
        // }


            //add by rentx 20210825 start 
            if (nObj.Asset_loaner_category_F__c == '固定资产') {
                nObj.unknow_serial_NO_product__c = 'FALSE';   
                nObj.Manage_type__c = '个体管理';
            }
            mxxhSet.add(nObj.Fixture_Model_No_F__c);
                
            //add by rentx 20210825 end
        }

        //根据备品配套明细型号去查备品配套明细//add by rentx 20210825 start 
        Map<String,String> tempMap = new Map<String,String>();
        List<Fixture_Set_Detail__c> fixdetaillist = new List<Fixture_Set_Detail__c>();
        fixdetaillist = [select id,Is_Body__c,Fixture_Model_No_F__c from Fixture_Set_Detail__c where Fixture_Model_No_F__c in :mxxhSet];
        if (fixdetaillist.size() > 0) {
            for (Fixture_Set_Detail__c detail : fixdetaillist ) {
                //是附属品
                if (!detail.Is_Body__c) {
                    tempMap.put(detail.Fixture_Model_No_F__c, 'TRUE');
                }else{
                    tempMap.put(detail.Fixture_Model_No_F__c, 'FALSE');
                }
            }
        }
        for (ReceivingNoteDetail__c nObj : newList) {
            if (tempMap.containsKey(nObj.Fixture_Model_No_F__c)) {
                String tempstr = tempMap.get(nObj.Fixture_Model_No_F__c);
                if (nObj.Loaner_accsessary__c == '' || nObj.Loaner_accsessary__c == null) {
                    nObj.Loaner_accsessary__c = tempStr;   
                }
            }
        }
        //add by rentx 20210825 end
    }

    public void setCalculateTime() {
        // 日期范围变化Flg
        Boolean minMaxDateIsChanged = false;
        // Map< Id, Map< 字段api名, Map<起始时间, 终了时间>>>
        Map<ReceivingNoteDetail__c, Map<String, Map<Datetime, Datetime>>> calculateMap = new Map<ReceivingNoteDetail__c, Map<String, Map<Datetime, Datetime>>>();
        for (ReceivingNoteDetail__c nObj : newList) {
            Boolean needSet = (null != nObj.Posting_Date_F__c // 发货日
                                                && null != nObj.Received_Confirm_Date_F__c // 收货确认日
                                                && nObj.Posting_Date_F__c <= nObj.Received_Confirm_Date_F__c); // 发货日 <= 收货确认日
            // 新品到货时长
            if ((needSet
                    && (Trigger.isInsert
                        || nObj.Posting_Date_F__c != oldMap.get(nObj.Id).Posting_Date_F__c // 发货日更新时
                        || nObj.Received_Confirm_Date_F__c != oldMap.get(nObj.Id).Received_Confirm_Date_F__c // 收货确认日更新时
                        || nObj.ProductArrivalTime_Day__c == null
                    )
                )
                || (nObj.ProductArrivalTime_Day__c != null
                        && needSet == false
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(
                        nObj,
                        Datetime.newInstance(nObj.Posting_Date_F__c, ts),
                        Datetime.newInstance(nObj.Received_Confirm_Date_F__c, te),
                        'ProductArrivalTime',
                        calculateMap,
                        minMaxDateIsChanged
                    );
                }
                else {
                    nObj.ProductArrivalTime_Day__c = null;
                }
            }
            Datetime cd = Trigger.isInsert ? createdDate : nObj.createdDate;
            needSet = (null != nObj.DataConfirmationTime__c // 数据确认时间
                        && cd <= nObj.DataConfirmationTime__c); // 创建日期 <= 数据确认时间
            // 受理数据确认时长
            if (
                (needSet &&
                    (Trigger.isInsert // 数据插入时
                        || nObj.DataConfirmationTime__c != oldMap.get(nObj.Id).DataConfirmationTime__c // 数据确认时间更新时
                        || nObj.AccepDataConfirmTime_Day__c == null
                        || nObj.AccepDataConfirmTime_Hour__c == null))
                || (needSet == false
                    && (nObj.AccepDataConfirmTime_Day__c != null
                        || nObj.AccepDataConfirmTime_Hour__c != null)
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, cd, nObj.DataConfirmationTime__c, 'AccepDataConfirmTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.AccepDataConfirmTime_Day__c = null;
                    nObj.AccepDataConfirmTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.DataConfirmationTime__c // 数据确认时间
                        && null != nObj.Received_Confirm_Time_F__c // 收货确认时间
                        && nObj.DataConfirmationTime__c <= nObj.Received_Confirm_Time_F__c); // 数据确认时间 <= 收货确认时间
            // 仓库收货时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                    || nObj.DataConfirmationTime__c != oldMap.get(nObj.Id).DataConfirmationTime__c // 数据确认时间更新时
                    || nObj.Received_Confirm_Time_F__c != oldMap.get(nObj.Id).Received_Confirm_Time_F__c // 收货确认时间更新时
                    || nObj.WarehouseReceiptTime_Day__c == null
                ))
                || (needSet == false && nObj.WarehouseReceiptTime_Day__c != null)
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.DataConfirmationTime__c, nObj.Received_Confirm_Time_F__c, 'WarehouseReceiptTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.WarehouseReceiptTime_Day__c = null;
                }
            }

            needSet = (null != nObj.Received_Confirm_Time_F__c // 收货确认时间
                        && null != nObj.AcceptanceTime__c // 清点时间
                        && nObj.Received_Confirm_Time_F__c <= nObj.AcceptanceTime__c); // 收货确认时间 <= 清点时间
            // 仓库清点时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.Received_Confirm_Time_F__c != oldMap.get(nObj.Id).Received_Confirm_Time_F__c // 收货确认时间更新时
                        || nObj.AcceptanceTime__c != oldMap.get(nObj.Id).AcceptanceTime__c // 清点时间更新时
                        || nObj.WarehouseAcceptanceTime_Day__c == null
                        || nObj.WarehouseAcceptanceTime_Hour__c == null
                    )
                )
                || (needSet == false
                        && (nObj.WarehouseAcceptanceTime_Day__c != null
                            || nObj.WarehouseAcceptanceTime_Hour__c != null
                        )
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.Received_Confirm_Time_F__c, nObj.AcceptanceTime__c, 'WarehouseAcceptanceTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.WarehouseAcceptanceTime_Day__c = null;
                    nObj.WarehouseAcceptanceTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.AcceptanceTime__c // 清点时间
                        && null != nObj.After_Inspection_time__c // 验收完毕时间
                        && nObj.AcceptanceTime__c <= nObj.After_Inspection_time__c); // 清点时间 <= 验收完毕时间
            // 检测验收时长
            if (
                (needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.AcceptanceTime__c != oldMap.get(nObj.Id).AcceptanceTime__c // 清点时间更新时
                        || nObj.After_Inspection_time__c != oldMap.get(nObj.Id).After_Inspection_time__c // 验收完毕时间更新时
                        || nObj.InspectionAcceptanceTime_Day__c == null
                        || nObj.InspectionAcceptanceTime_Hour__c == null
                    )
                )
                || (needSet == false
                        && (nObj.InspectionAcceptanceTime_Day__c != null
                                || nObj.InspectionAcceptanceTime_Hour__c != null
                            )
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.AcceptanceTime__c, nObj.After_Inspection_time__c, 'InspectionAcceptanceTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.InspectionAcceptanceTime_Day__c = null;
                    nObj.InspectionAcceptanceTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.After_Inspection_time__c // 验收完毕时间
                        && null != nObj.DataConfirmationAgainTime__c // 再数据确认时间
                        && nObj.After_Inspection_time__c <= nObj.DataConfirmationAgainTime__c); // 验收完毕时间 <= 再数据确认时间
            // 受理再数据确认时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.After_Inspection_time__c != oldMap.get(nObj.Id).After_Inspection_time__c // 验收完毕时间更新时
                        || nObj.DataConfirmationAgainTime__c != oldMap.get(nObj.Id).DataConfirmationAgainTime__c // 再数据确认时间更新时
                        || nObj.AcceptDataConfirmAgainTime_Day__c == null
                        || nObj.AcceptDataConfirmAgainTime_Hour__c == null
                    )
                )
                || (needSet == false
                        && (nObj.AcceptDataConfirmAgainTime_Day__c != null
                                || nObj.AcceptDataConfirmAgainTime_Hour__c != null
                            )
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.After_Inspection_time__c, nObj.DataConfirmationAgainTime__c, 'AcceptDataConfirmAgainTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.AcceptDataConfirmAgainTime_Day__c = null;
                    nObj.AcceptDataConfirmAgainTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.After_Inspection_time__c // 验收完毕时间
                            && null != nObj.Arrival_wh_Request_time__c // 入库指示时间
                            && nObj.After_Inspection_time__c <= nObj.Arrival_wh_Request_time__c); // 再数据确认时间 <= 入库指示时间
            // 受理再数据入库指示时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.After_Inspection_time__c != oldMap.get(nObj.Id).After_Inspection_time__c // 再数据确认时间更新时
                        || nObj.Arrival_wh_Request_time__c != oldMap.get(nObj.Id).Arrival_wh_Request_time__c // 入库指示时间更新时
                        || nObj.AcceptDataArrivalRequestAgainTime_Day__c == null
                        || nObj.AcceptDataArrivalRequestAgainTime_Hour__c == null
                    )
                )
                || (needSet == false
                        && (nObj.AcceptDataArrivalRequestAgainTime_Day__c != null
                                && nObj.AcceptDataArrivalRequestAgainTime_Hour__c != null
                            )
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.After_Inspection_time__c, nObj.Arrival_wh_Request_time__c, 'AcceptDataArrivalRequestAgainTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.AcceptDataArrivalRequestAgainTime_Day__c = null;
                    nObj.AcceptDataArrivalRequestAgainTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.Arrival_wh_Request_time__c // 入库指示时间
                        && null != nObj.Arrival_wh_time__c // 入库确认完成时间
                        && nObj.Arrival_wh_Request_time__c <= nObj.Arrival_wh_time__c); // 入库指示时间 <= 入库确认完成时间
            // 仓库入库时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.Arrival_wh_Request_time__c != oldMap.get(nObj.Id).Arrival_wh_Request_time__c // 入库指示时间更新时
                        || nObj.Arrival_wh_time__c != oldMap.get(nObj.Id).Arrival_wh_time__c // 入库确认完成时间更新时
                        || nObj.WarehouseArrivalTime_Day__c == null
                        || nObj.WarehouseArrivalTime_Hour__c == null
                    )
                )
                || (needSet == false
                        && (nObj.WarehouseArrivalTime_Day__c != null
                                || nObj.WarehouseArrivalTime_Hour__c != null
                            )
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.Arrival_wh_Request_time__c, nObj.Arrival_wh_time__c, 'WarehouseArrivalTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.WarehouseArrivalTime_Day__c = null;
                    nObj.WarehouseArrivalTime_Hour__c = null;
                }
            }

            needSet = (null != nObj.Received_Confirm_Time_F__c // 收货确认时间
                            && null != nObj.Arrival_wh_time__c // 入库确认完成时间
                            && nObj.Arrival_wh_Request_time__c <= nObj.Arrival_wh_time__c); // 收货确认时间 <= 入库确认完成时间
            // 新品收货操作总时长
            if ((needSet
                    &&(Trigger.isInsert // 数据插入时
                        || nObj.Received_Confirm_Time_F__c != oldMap.get(nObj.Id).Received_Confirm_Time_F__c // 收货确认时间更新时
                        || nObj.Arrival_wh_time__c != oldMap.get(nObj.Id).Arrival_wh_time__c // 入库确认完成时间更新时
                        || nObj.ProductReceiptTotalTime_Day__c == null
                    )
                )
                || (needSet == false
                        && nObj.ProductReceiptTotalTime_Day__c != null
                    )
            ) {
                if (needSet) {
                    minMaxDateIsChanged = editCalculateMap(nObj, nObj.Received_Confirm_Time_F__c, nObj.Arrival_wh_time__c, 'ProductReceiptTotalTime', calculateMap, minMaxDateIsChanged);
                }
                else {
                    nObj.ProductReceiptTotalTime_Day__c = null;
                }
            }
        }

        System.debug('####minDate: '+minDate);
        System.debug('####maxDate: '+maxDate);

        // 设置日期Map(仅日期范围扩大时需再次设置)
        if (true == dateIntMap.isEmpty() || true == minMaxDateIsChanged) {
            Integer idx = 0;
            if (false == dateIntMap.isEmpty()) {
                dateIntMap.clear();
            }
            dateIntMap.clear(); // Map clear
            minDay = null;
            for (OlympusCalendar__c workday : [
                    Select Date__c
                      From OlympusCalendar__c
                     Where Date__c >= :minDate And Date__c <= :maxDate
                       And IsWorkDay__c = 1
                  ORDER BY Date__c ASC
            ]) {
                dateIntMap.put(workday.Date__c, idx);
                dateList.add(workday.Date__c);
                if (minDay == null) {
                    minDay = workday.Date__c;
                }
                maxDay = workday.Date__c;
                idx ++;
            }
        }

        // 计算各项时长
        for (ReceivingNoteDetail__c nObj : calculateMap.keySet()) {
            Map<String, Map<Datetime, Datetime>> apiDateMap = calculateMap.get(nObj);
            for (String apiName : calculateMap.get(nObj).keySet()) {
                // 新品到货时长
                if ('ProductArrivalTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.ProductArrivalTime_Day__c = calculateResult[0];
                }

                // 受理数据确认时长
                if ('AccepDataConfirmTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.AccepDataConfirmTime_Day__c = calculateResult[0];
                    nObj.AccepDataConfirmTime_Hour__c = calculateResult[1];
                }

                // 仓库收货时长
                if ('WarehouseReceiptTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.WarehouseReceiptTime_Day__c = calculateResult[0];
                }

                // 仓库清点时长
                if ('WarehouseAcceptanceTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.WarehouseAcceptanceTime_Day__c = calculateResult[0];
                    nObj.WarehouseAcceptanceTime_Hour__c = calculateResult[1];
                }

                // 检测验收时长
                if ('InspectionAcceptanceTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.InspectionAcceptanceTime_Day__c = calculateResult[0];
                    nObj.InspectionAcceptanceTime_Hour__c = calculateResult[1];
                }

                // 受理再数据确认时长
                if ('AcceptDataConfirmAgainTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.AcceptDataConfirmAgainTime_Day__c = calculateResult[0];
                    nObj.AcceptDataConfirmAgainTime_Hour__c = calculateResult[1];
                }

                // 受理再数据入库指示时长
                if ('AcceptDataArrivalRequestAgainTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.AcceptDataArrivalRequestAgainTime_Day__c = calculateResult[0];
                    nObj.AcceptDataArrivalRequestAgainTime_Hour__c = calculateResult[1];
                }

                // 仓库入库时长
                if ('WarehouseArrivalTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.WarehouseArrivalTime_Day__c = calculateResult[0];
                    nObj.WarehouseArrivalTime_Hour__c = calculateResult[1];
                }

                // 新品收货操作总时长
                if ('ProductReceiptTotalTime' == apiName) {
                    List<Decimal> calculateResult = doCalculate(apiDateMap, apiname);
                    nObj.ProductReceiptTotalTime_Day__c = calculateResult[0];
                }
            }
        }
    }

    private Boolean editCalculateMap(ReceivingNoteDetail__c nObj, Datetime startDate, Datetime endDate, String apiName,
        Map<ReceivingNoteDetail__c, Map<String, Map<Datetime, Datetime>>> calculateMap, Boolean minMaxDateIsChanged
    ) {
        if (null == calculateMap.get(nObj)) {
            calculateMap.put(nObj, new Map<String, Map<Datetime, Datetime>>());
        }
        Map<String, Map<Datetime, Datetime>> apiDateMap = calculateMap.get(nObj);
        if (null == apiDateMap.get(apiName)) {
            apiDateMap.put(apiName, new Map<Datetime, Datetime>());
        }
        Map<Datetime, Datetime> dateMap = apiDateMap.get(apiName);
        if (null == dateMap.get(startDate)) {
            dateMap.put(startDate, endDate);
        }

        // 最大,最小日期设定
        if (null == minDate || minDate > startDate.date()) {
            minDate = startDate.date();
            minMaxDateIsChanged = true;
        }
        if (null == maxDate || maxDate < endDate.date()) {
            maxDate = endDate.date();
            minMaxDateIsChanged = true;
        }

        return minMaxDateIsChanged;
    }

    private List<Decimal> doCalculate (Map<String, Map<Datetime, Datetime>> apiDateMap, String apiName) {
        // 开始结束之间不包含工作日
        if (0 == dateIntMap.size()) {
            return new Decimal[] {0.00, 0.00};
        }
        System.debug('###apiName: '+apiName);
        System.debug('###apiDateMap: '+apiDateMap);
        // apiDateMap Key开始时间， Value结束时间
        Datetime startDate = (new List<Datetime> (apiDateMap.get(apiName).keySet()))[0];
        Datetime endDate = apiDateMap.get(apiName).values()[0];

        System.debug('###startDate0: '+startDate.format());
        System.debug('###endDate0: '+endDate.format());
        System.debug('###dateIntMap: '+dateIntMap);

        Boolean sFlg = dateIntMap.containsKey(startDate.date()) == false;
        Boolean eFlg = dateIntMap.containsKey(endDate.date()) == false;

        System.debug('###sFlg: '+sFlg);
        System.debug('###eFlg: '+eFlg);

        if (sFlg || eFlg) {
            // 循环次数
            Integer maxStartIdx = sFlg ? (startDate.date().daysBetween(maxDay) + 1) : 0;
            Integer maxEndIdx = eFlg ? (minDay.daysBetween(endDate.date()) + 1) : 0;
            System.debug('###maxStartIdx: '+maxStartIdx);
            System.debug('###maxEndIdx: '+maxEndIdx);
            Datetime sDt = startDate;
            Datetime eDt = endDate;
            for (Integer i = 0; i < Math.max(maxStartIdx, maxEndIdx); i++) {
                if (true == sFlg) {
                    sDt = sDt.addDays(1);
                    // 找到最近开始日期时
                    if (dateIntMap.containsKey(sDt.date())) {
                        startDate = Datetime.newInstance(sDt.year(), sDt.month(), sDt.day(), 9, 0, 0);
                        sFlg = false;
                    }
                }
                if (true == eFlg) {
                    eDt = eDt.addDays(-1);
                    // 找到最近结束日期时
                    if (dateIntMap.containsKey(eDt.date())) {
                        endDate = Datetime.newInstance(eDt.year(), eDt.month(), eDt.day(), 17, 30, 0);
                        eFlg = false;
                    }
                }
                // 开始结束日期都找到时，退出循环
                if (false == sFlg && false == eFlg) {
                    break;
                }
            }
        }

        System.debug('###startDate: '+startDate.format());
        System.debug('###endDate: '+endDate.format());

        if (startDate.date() <= maxDay && endDate.date() >= minDay && startDate < endDate) {
            // 总天数和
            Decimal totalDays = dateIntMap.get(endDate.date()) - dateIntMap.get(startDate.date()) + 1;
            System.debug('###totalDays: '+totalDays);

            // 第一天和最后一天以外的分钟数
            Decimal middleWorkMins = 0;
            if (1 < totalDays) {
                middleWorkMins = (totalDays - 2) * 510;
            }
            // 第一天的分钟数
            Decimal firstWorkMins = 0;
            Decimal firstTotalMins = startDate.hour() * 60 + startDate.minute();
            Decimal lastWorkMins = 0;
            Decimal lastTotalMins = endDate.hour() * 60 + endDate.minute();
            Decimal totalMins = 0;
            if (startDate.date() != endDate.date()) {
                System.debug(firstTotalMins);
                // 第一天开始时间小于9:00（570分钟）
                if (540 > firstTotalMins) {
                    firstWorkMins = 510;
                }
                // 第一天开始时间小于17:30（1050分钟）
                else if (1050 > firstTotalMins) {
                    firstWorkMins = 1050 - firstTotalMins;
                }
                // 最后一天分钟数
                System.debug(lastTotalMins);
                // 最后一天结束时间大与17:30（1050分钟）
                if (1 < totalDays && 1050 < lastTotalMins) {
                    lastWorkMins = 510;
                }
                // 最后一天结束时间大与9:00（540分钟）
                else if (1 < totalDays && 540 < lastTotalMins) {
                    lastWorkMins = lastTotalMins - 540;
                }
                System.debug(startDate);
                System.debug(endDate);
                System.debug(firstWorkMins);
                System.debug(lastWorkMins);
                totalMins = firstWorkMins + middleWorkMins + lastWorkMins;
            }
            else {
                if (540 > firstTotalMins) {
                    firstTotalMins = 540;
                }
                else if (1050 < firstTotalMins) {
                    firstTotalMins = 1050;
                }
                if (540 > lastTotalMins) {
                    lastTotalMins = 540;
                }
                else if (1050 < lastTotalMins) {
                    lastTotalMins = 1050;
                }
                totalMins = lastTotalMins - firstTotalMins;
            }
            // 总分钟数和
            System.debug('###totalMins: '+totalMins + '   ' + apiName);

            System.debug('###calculateResult: '+ (totalMins / 51.00).setScale(1, System.RoundingMode.HALF_UP) / 10.00 + ' , ' + (totalMins / 6.00).setScale(1, System.RoundingMode.HALF_UP) / 10.00);

            // 天数统计值, 小时数统计值
            return new Decimal[] {(totalMins / 51.00).setScale(1, System.RoundingMode.HALF_UP) / 10.00, (totalMins / 6.00).setScale(1, System.RoundingMode.HALF_UP) / 10.00};
        } else {
            return new Decimal[] {0.00, 0.00};
        }
        
    }

    /**
    @description 明细按No排序
    */
    public class ReceivingNoteDetailWrapper implements Comparable {

        public ReceivingNoteDetail__c rnd;

        // Constructor
        public ReceivingNoteDetailWrapper(ReceivingNoteDetail__c rnd1) {
            rnd = rnd1;
        }
        public Integer compareTo(Object compareTo) {
            ReceivingNoteDetailWrapper compareToRnd = (ReceivingNoteDetailWrapper)compareTo;
            Integer returnValue = 0;
            if (rnd.ReceivingNoteDetailNo__c > compareToRnd.rnd.ReceivingNoteDetailNo__c) {
                returnValue = 1;
            } else if (rnd.ReceivingNoteDetailNo__c < compareToRnd.rnd.ReceivingNoteDetailNo__c) {
                returnValue = -1;
            }
            return returnValue;
        }
    }
}