/*根据招投标项目的反应询价标识
* 更新招投标上的询价状态和询价数量
* 更新招投标上的五个医院
* 2021-07-15  mzy
*/
global class UpdateTenderInformationBatchByTender implements Database.Batchable<sObject>, Database.Stateful  {
    String tempTenderId ='';
    Boolean IsOnlyTrue = true;
    List<String> tempTenderList = new List<String>(); 

    //邮件信息
    List<String> emailMessages = new List<String>();

    //招投标: 报错的招投标Id
    String TenderlogStr = '';

    //招投标: 报错信息
    String TendererrorStr = '';

    //招投标: 总件数
    Integer TendertotalCount = 0;

    //招投标: 失败件数
    Integer TenderfailedCount = 0; 


    global UpdateTenderInformationBatchByTender(String tempOppId) {
        this.tempTenderId = tempOppId;
    }

    global UpdateTenderInformationBatchByTender(List<String> tempTenderList) {
        this.tempTenderList = tempTenderList;
    }
    //处理历史数据
    global UpdateTenderInformationBatchByTender(String tempOppId, Boolean IsOnlyTrue) {
        this.IsOnlyTrue = IsOnlyTrue;
    }

    global UpdateTenderInformationBatchByTender() {
        
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {
        String query = 'SELECT Id ';
               query += 'FROM Tender_information__c ';
            if(IsOnlyTrue){               
               query += 'WHERE IsReactionOpp__c = true'; 
            }   
            if(String.isNotBlank(this.tempTenderId)){
               query += ' AND Id = :tempTenderId';
            }
            if(tempTenderList.size()>0){
               query += ' AND Id In :tempTenderList';
            }
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, list<Tender_information__c> TenderList) {

        //定义List封装需要更新的招标项目
        List<Tender_information__c> updateTenderList = new List<Tender_information__c>();
        //定义List封装所有询价的招标项目Id
        Set<String> BiddingProjectID = new Set<String>();
        for(Tender_information__c tempTender : TenderList){
            BiddingProjectID.add(tempTender.Id);
        }

        //查询招标项目下的所有询价
        Map<String,List<Opportunity>> BiddingProjectOppMap = findTenderRelativeOpp(BiddingProjectID);

        //计算询价数量
        List<Tender_information__c> updateTenderNumList = updateOpportunityNum(BiddingProjectOppMap);


        //计算询价状态
        List<Tender_information__c> updateTenderNumStatusList = updateOpportunityStatus(BiddingProjectOppMap,updateTenderNumList);




        updateTenderList.addAll(updateTenderNumStatusList);

        //更新招投标 询价数量和状态
        if(updateTenderList.size()>0){
            //一个招投标项目更新失败
            List<String> failedTenderList = new List<String>();
            ///////////////
            //测试
            //updateTenderList.get(1).OwnerId = '00510000003KwKO';
            ///////////////
            Database.SaveResult[] saveTenderResults = Database.update(updateTenderList,false);
            //招投标项目的总数
            TendertotalCount = saveTenderResults.size();

            for(Integer i = 0;i<saveTenderResults.size();i++) {
                if(!saveTenderResults.get(i).isSuccess()){ 
                    if(TenderlogStr.equals('')){
                        TenderlogStr = '招标项目 : ' ;
                    }                     
                    TenderlogStr += updateTenderList.get(i).id +' ,';
                    String statusCode = String.ValueOf(saveTenderResults.get(i).getErrors()[0]).split(';')[2].split('=')[1];
                    String errorMsg = String.ValueOf(saveTenderResults.get(i).getErrors()[0]).split(';')[1].split('=')[1];
                    TendererrorStr += '失败招标项目 :'+updateTenderList.get(i).id+'  失败原因:'+ statusCode +' : '+errorMsg + '\r\n';
                    TenderfailedCount++ ;
                    //将更新失败的招投标项目添加掉集合中
                    failedTenderList.add(String.valueOf( updateTenderList.get(i).id ).substring(0,15));
                }
            }
            //更新成功后,清除招投标的反应询价标识
            List<Tender_information__c> successTenderList = new List<Tender_information__c>();
            for(Tender_information__c tempTender:TenderList){
                if(failedTenderList.contains( String.valueOf( tempTender.id ).substring(0,15)  )){
                    //更新失败,则不清除标识
                }else {
                    //更新成功,清除标识
                    tempTender.IsReactionOpp__c = false;
                    successTenderList.add(tempTender);
                }
            }

            //清除标识
            if(successTenderList.size()>0){
                update successTenderList;
            }
        }

    }

    global void finish(Database.BatchableContext BC) {

        //UpdateTenderInformationSchedule.assignOneHours();
        BatchIF_Log__c TenderIfLog = new BatchIF_Log__c();
        TenderIfLog.Type__c = 'UpdateTenderInformationBatchByTenderErrorLog';

        if (TenderlogStr.length() > 60000) {
            TenderlogStr = TenderlogStr.substring(0, 60000);
        }
        TenderIfLog.Log__c = TenderlogStr;
        TenderIfLog.Log__c += '\n end';
        if (TendererrorStr.length() > 60000) {
            TenderIfLog.ErrorLog__c = TendererrorStr.substring(0, 60000);
        } else {
            TenderIfLog.ErrorLog__c = TendererrorStr.substring(0, TendererrorStr.length());
        }

        insert TenderIfLog;

        emailMessages.add('失败日志ID为：' + TenderIfLog.Id + '\r\n失败信息:\r\n'+TendererrorStr);

        //发送邮件
        sendFieldEmail();

    }
    //批量更新招投标的询价信息
    WebService static String updateOpportunityInformation(List<String> TenderIdList){
        //存储错误信息
        String errorMessage = '';
        //目的 : 如果Batch执行失败,则整体rollback,标识不进行清除
        //定义List封装需要更新的招标项目
        List<Tender_information__c> updateTenderList = new List<Tender_information__c>();
        try{

            Set<String> BiddingProjectID = new Set<String>();
            for(String TenderId:TenderIdList){                  
                BiddingProjectID.add(TenderId);
            }

            //查询招标项目下的所有询价
            Map<String,List<Opportunity>> BiddingProjectOppMap = findTenderRelativeOpp(BiddingProjectID);

            //计算询价数量
            List<Tender_information__c> updateTenderNumList = updateOpportunityNum(BiddingProjectOppMap);

            //计算询价状态
            List<Tender_information__c> updateTenderNumStatusList = updateOpportunityStatus(BiddingProjectOppMap,updateTenderNumList);

            updateTenderList.addAll(updateTenderNumStatusList);

            //更新
            if(updateTenderList.size()>0){
                List<String> failedTenderList = new List<String>();               
                Database.SaveResult[] saveTenderResults = Database.update(updateTenderList,false);
                for(Integer i = 0;i<saveTenderResults.size();i++) {
                    if(!saveTenderResults.get(i).isSuccess()){ 
                        String statusCode = String.ValueOf(saveTenderResults.get(i).getErrors()[0]).split(';')[2].split('=')[1];
                        String errorMsg = String.ValueOf(saveTenderResults.get(i).getErrors()[0]).split(';')[1].split('=')[1];
                        errorMessage += '失败招标项目 :'+updateTenderList.get(i).id+'  失败原因:'+ statusCode +' : '+errorMsg + '\r\n';
                        //将更新失败的招投标项目添加掉集合中
                        failedTenderList.add(String.valueOf( updateTenderList.get(i).id ).substring(0,15));
                    }
                }

                //更新成功后,清除招投标的反应询价标识
                List<Tender_information__c> successTenderList = new List<Tender_information__c>();
                for(String tempTenderId:TenderIdList){
                    if(failedTenderList.contains( String.valueOf( tempTenderId ).substring(0,15)  )){
                        //更新失败,则不清除标识
                    }else {
                        //更新成功,清除标识
                        Tender_information__c tempTender = new Tender_information__c();
                        tempTender.Id = String.valueOf( tempTenderId ).substring(0,15);
                        tempTender.IsReactionOpp__c = false;
                        successTenderList.add(tempTender);
                    }
                }

                //清除标识
                if(successTenderList.size()>0){
                    update successTenderList;
                }

            }


        }catch(NullPointerException ex){         
            system.debug('aa1:'+ex.getMessage());
            return '空指针 :'+ex.getLineNumber();
        }catch(Exception ex2){          
            system.debug('aa2:'+ex2.getMessage());
            return '出错了!'+ex2.getMessage();
        }

        if(String.isNotBlank(errorMessage)){
            return errorMessage;
        }

            system.debug('aa');
            return 'OK';

    }



    //0.计算询价数量
    public static List<Tender_information__c> updateOpportunityNum(Map<String,List<Opportunity>> tempMap){
        List<Tender_information__c> updateTenderNumList = new List<Tender_information__c>();
        //遍历Map的key
        for(String k : tempMap.keySet()){
            Tender_information__c tempTender = new Tender_information__c();
            tempTender.id = k;
            String fifteenId = String.valueOf(tempTender.Id).subString(0,15);
            tempTender.OpportunityNum__c = tempMap.get(fifteenId).size();
            updateTenderNumList.add(tempTender);
        }


        return updateTenderNumList;
    }


    //1.计算询价状态
    //2.赋值医院
    //3.赋值战略科室
    //  1)  如果招投标项目的关联医院为空，那么就更新为询价的医院;
    //  2)  如果招投标项目的关联主战略科室为空，那么就更新为询价创建时间最早的询价的战略科室；
    //  3)  如果招投标项目的关联副战略科室为空，那么就更新为排名优先级高的战略科室之外的其他询价的战略科室，也是以创建时间更早为先后顺序；
    //  4） 如果更新满了，多的战略科室就不更新；
    public static List<Tender_information__c> updateOpportunityStatus(Map<String,List<Opportunity>> BiddingProjectOppMap,List<Tender_information__c> updateTenderNumList){
        //询价状态
        //定义List封装需要更新的招标项目
        List<Tender_information__c> updateTenderList = new List<Tender_information__c>();

        //遍历Map的key
        for(Tender_information__c tempTender : updateTenderNumList){

            String fifteenId = String.valueOf(tempTender.Id).subString(0,15);
            //获取当前招投标下的询价
            List<Opportunity> BiddingDownOppList= BiddingProjectOppMap.get(fifteenId) == null ? new List<Opportunity>() : BiddingProjectOppMap.get(fifteenId);

            //获取当前招投标下的询价的医院
            List<String> OppHospitalList = new List<String>();

            //判断状态
            if(BiddingDownOppList.size() > 0){
                //<!---- 询价状态  start --->
                //WIN num
                Integer WinNum = 0;
                //失单 num
                Integer SHDNum = 0;

                //获取当前key的List
                for(Opportunity tempOp :BiddingDownOppList){
                // 李慧娟备注 ： 这里请替换成<SAP上传(WIN)>标识判断
                    if(tempOp.SAP_Send_OK__c){
                      //win 
                      WinNum += 1; 
                    }else if(tempOp.StageName__c.equals('失单')){
                      //失单  
                      SHDNum += 1;
                    }
                    //获取询价的医院(相关性时用)
                    if(!OppHospitalList.contains(tempOp.Hospital__c)&&tempOp.Hospital__c!=null){
                        OppHospitalList.add(tempOp.Hospital__c);
                    }

                }


                if(WinNum == BiddingDownOppList.size()){
                    //全部为Win,OLY确认状态 为 成交
                    tempTender.OpportunityStatus__c = '成交';
                }else if(SHDNum == BiddingDownOppList.size()){
                    //全部为失单.状态为 失单
                    tempTender.OpportunityStatus__c = '失单';
                }else if(WinNum>0&&SHDNum>0&&(WinNum + SHDNum) == BiddingDownOppList.size() ){
                    //部分Win,部分失单时, 状态为  部分成交
                    tempTender.OpportunityStatus__c = '部分成交';
                }else if(tempTender.OpportunityNum__c > 0){
                    //如果询价数量大于0的话就是 跟进中
                    tempTender.OpportunityStatus__c = '跟进中';
                }else{
                    //其他都是 ''
                    tempTender.OpportunityStatus__c = '';
                }
                //<!---- 询价状态  end --->

                //<!------ 相关性 信息   start ----> 
                //定义Map存放当前招投标项目的五个医院
                Map<String,String> fiveHospitalMap = new Map<String,String>();
                fiveHospitalMap.put('Hospital__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital__c);
                fiveHospitalMap.put('Hospital1__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital1__c);
                fiveHospitalMap.put('Hospital2__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital2__c);
                fiveHospitalMap.put('Hospital3__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital3__c);
                fiveHospitalMap.put('Hospital4__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital4__c);


                //如果招投标项目的 是否相关 字段不为否 , 并且 相关医院 相关战略科室 相关普通科室 为空时,则更新 为询价的 医院 战略科室 客户名
                if(!'否'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsRelateProject__c)){
                    //一.关联医院
                    //遍历招投标项目下所有询价的医院,给招投标项目的5个医院赋值 ---start
                    //遍历招投标项目下所有询价的医院
                    if(OppHospitalList.size()>0){                        
                        for(Integer i = 0; i<OppHospitalList.size();i++){
                            //当招投标项目的五个医院赋值完成后不再赋值
                            Boolean HospitalIsNeedBreak = false;
                            for(String ApiName :fiveHospitalMap.keySet()){
                                HospitalIsNeedBreak = fiveHospitalMap.get(ApiName)==null?false:true;
                            }
                            
                            if(HospitalIsNeedBreak){
                                break;
                            }

                            //给招投标项目的5个医院设值
                            for(String ApiName : fiveHospitalMap.keySet()){
                                String tempTenderHospId = fiveHospitalMap.get(ApiName)==null?'':fiveHospitalMap.get(ApiName);
                                String oppHospId = OppHospitalList.get(i); 
                                //如果招标项目已经有该医院就判断下一个询价的医院
                                if(tempTenderHospId.contains(oppHospId)){
                                    break;
                                }

                                //医院为空,赋值医院(赋值之后进行赋值下一个医院)
                                if(String.isBlank( fiveHospitalMap.get(ApiName) )){
                                    fiveHospitalMap.put(ApiName,oppHospId);
                                    break;
                                }
                            }

                        }
                    }

                    //赋值医院
                    tempTender.Hospital__c = fiveHospitalMap.get('Hospital__c');
                    tempTender.Hospital1__c = fiveHospitalMap.get('Hospital1__c');
                    tempTender.Hospital2__c = fiveHospitalMap.get('Hospital2__c');
                    tempTender.Hospital3__c = fiveHospitalMap.get('Hospital3__c');
                    tempTender.Hospital4__c = fiveHospitalMap.get('Hospital4__c');
                    //遍历招投标项目下所有询价的医院,给招投标项目的5个医院赋值 ---end

                }

                //如果 是否相关 字段已经选择否, 就不应该更新相关及相关的相关信息
                if(!'否'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsRelateProject__c)
                    &&!'是'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsRelateProject__c)){
                    tempTender.IsRelateProject__c = '是';     
                }
                //<!------ 相关性 信息   end ---->

                //<!------ 应标 信息    start---->
                //如果 是否应标 字段已经选择否,就不应该更新应标及相关的相关信息
                if(!'否'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsBid__c)
                    &&!'是'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsBid__c)){
                    tempTender.IsBid__c = '是';     
                }
                //<!------ 应标 信息    end---->

            }else {
                //清空
                tempTender.OpportunityStatus__c = '';
            }
            updateTenderList.add(tempTender);
        }


        return updateTenderList;

    }


    //查询招标项目下的所有询价
    //param : 需要查询的招标项目Id
    //return Map<招投标项目Id,List<询价>>
    public static Map<String,List<Opportunity>> findTenderRelativeOpp(Set<String>  BiddingProjectID){
        //定义Map封装数据
        Map<String,List<Opportunity>> BiddingProjectOppMap = new Map<String,List<Opportunity>>();
        //查询招标项目下的所有询价
        List<Opportunity> allRelativeOppList = [SELECT Id ,AccountId,Hospital__c,Department_Class__c,SAP_Send_OK__c,CreatedDate, 
        Old_BiddingProject_Bid__c,Bidding_Project_Name_Bid__c ,StageName__c ,Bidding_Project_Name_Bid__r.Hospital__c,Bidding_Project_Name_Bid__r.Hospital1__c,
        Bidding_Project_Name_Bid__r.Hospital2__c,Bidding_Project_Name_Bid__r.Hospital3__c,Bidding_Project_Name_Bid__r.Hospital4__c,
        Bidding_Project_Name_Bid__r.IsRelateProject__c ,Bidding_Project_Name_Bid__r.IsBid__c ,Bidding_Project_Name_Bid__r.department__c,
        Bidding_Project_Name_Bid__r.subDepartment1__c,Bidding_Project_Name_Bid__r.subDepartment2__c,Bidding_Project_Name_Bid__r.subDepartment3__c,
        Bidding_Project_Name_Bid__r.subDepartment4__c FROM Opportunity WHERE Bidding_Project_Name_Bid__c in :BiddingProjectID ORDER By createdDate ASC];
       
        //遍历询价集合
        //2.按创建时间排序(正序),创建map
        for(Opportunity tempOp :allRelativeOppList){
            //判断当前询价是否有招标项目
            if(tempOp.Bidding_Project_Name_Bid__c!=null){
                String fifteenTenderId = String.valueOf(tempOp.Bidding_Project_Name_Bid__c).subString(0,15);
                //Map里面没有保存当前询价的招标项目下的询价
                if(!BiddingProjectOppMap.containsKey(fifteenTenderId)){
                    //第一次存放
                    List<Opportunity> tempOppList = new List<Opportunity>();
                    tempOppList.add(tempOp);
                    BiddingProjectOppMap.put(fifteenTenderId,tempOppList);
                }else {
                    //以后存放
                    List<Opportunity> tempOppListE =BiddingProjectOppMap.get(fifteenTenderId);
                    tempOppListE.add(tempOp);
                    BiddingProjectOppMap.put(fifteenTenderId,tempOppListE);
                } 
            }
        }
        //完善Map : 询价为0的招投标项目应该也有一列
        for(String TenderId : BiddingProjectID){
            String fifteenTenderId = TenderId.subString(0,15);
            if(!BiddingProjectOppMap.containsKey(fifteenTenderId)){
                List<Opportunity> tempOppList = new List<Opportunity>();
                BiddingProjectOppMap.put(fifteenTenderId,tempOppList);
            }
        }

        return BiddingProjectOppMap;
    }


    // 发送提醒邮件
    private void sendFieldEmail() {
        PretechBatchEmailUtil be = new PretechBatchEmailUtil();
        String[] toList = new String[] {UserInfo.getUserEmail()};
        String title = '招标项目询价状态和询价数量更新失败';
        //String[] ccList = new String[] {'Xiaochen_You@olympus.com.cn'};
        String[] ccList = new String[] {'miaoziyang@prec-tech.com'};
        if (System.Test.isRunningTest()) {
            be.successMail('', 1);
        }
        if (emailMessages.size() > 0 && TenderfailedCount > 0) {
            be.failedMail(toList, ccList, title, this.emailMessages.get(0)+'\n',
                            TendertotalCount, TendertotalCount - TenderfailedCount, TenderfailedCount,'',true);
            if(!Test.isRunningTest()){
                be.send();
            }
        }       
    }

}