/*2021-05-08  mzy
* 更新招标信息的询价状态
*/
global class UpdateTenderInformationBatch01 implements Database.Batchable<sObject>, Database.Stateful {

    Boolean IsNeedExecute = false;
    String tempOppId ='';    

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

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

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

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

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

    //询价 : 报错的询价Id
    String OpplogStr = '';

    //询价 : 报错信息
    String OpperrorStr = '';

    //询价 : 总件数
    Integer OpptotalCount = 0;

    //询价 : 失败件数
    Integer OppfailedCount = 0;

    global UpdateTenderInformationBatch01() {
    }

    global UpdateTenderInformationBatch01(String tempOppId) {
        this.tempOppId = tempOppId;
    }

    global UpdateTenderInformationBatch01(Boolean NeedExecute) {
        this.IsNeedExecute = NeedExecute;
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {
        //查询  招投标标识 字段 为 true 的询价
        String query = 'SELECT Id,StageName__c,Bidding_Project_Name_Bid__c, '
                     + 'Old_BiddingProject_Bid__c FROM Opportunity '
                     + 'WHERE Bidding_Flag__c = true';

        if(String.isNotBlank(this.tempOppId)){
            query += ' AND Id = :tempOppId';
        }
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<Opportunity> OpportunityList) {

        //定义一个保存点 , 目的 : 如果Batch执行失败,则整体rollback,标识不进行清除
        Savepoint sp = Database.setSavepoint();

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

            //获取所有招投标标识 字段 为 true 的询价的招标项目
            for(Opportunity tempOp :OpportunityList){
                //如果询价上记录了原来招投标项目的信息，则在batch里面需要重新计算询价状态和询价数量。
                if(!String.IsBlank(tempOp.Old_BiddingProject_Bid__c)){
                    BiddingProjectID.add(tempOp.Old_BiddingProject_Bid__c);
                }
                if(!String.IsBlank(tempOp.Bidding_Project_Name_Bid__c)){
                    BiddingProjectID.add(tempOp.Bidding_Project_Name_Bid__c);
                }
            }

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

            //计算询价数量
            updateTenderList = updateOpportunityNum(BiddingProjectOppMap,updateTenderList);
           
            //计算询价状态
            updateTenderList = updateOpportunityStatus(BiddingProjectOppMap,updateTenderList);

            //更新招标项目
            if(updateTenderList.size()>0){
                //update updateTenderList;

                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 +' ,';
                        TendererrorStr += saveTenderResults.get(i).getErrors() + '\n';
                        TenderfailedCount++ ;
                    }
                }

                //更新询价,清除标识
                for(Opportunity tempOp : OpportunityList){
                    tempOp.Bidding_Flag__c = false;
                    //如果询价中 原招投标项目Id有值则清空
                    if(!String.IsBlank(tempOp.Old_BiddingProject_Bid__c)){
                        tempOp.Old_BiddingProject_Bid__c = null;
                    }
                }

                Database.SaveResult[] saveOppResults = Database.update(OpportunityList,false);
                OpptotalCount = saveOppResults.size();
                for(Integer i = 0;i<saveOppResults.size();i++) {
                    if(!saveOppResults.get(i).isSuccess()){ 
                        if(OpplogStr.equals('')){
                            OpplogStr = '询价 : ' ;
                        }                     
                        OpplogStr += OpportunityList.get(i).id +' ,';
                        OpperrorStr += saveOppResults.get(i).getErrors() + '\n';
                        OppfailedCount++ ;
                    }
                }
                
            }

        }catch(Exception ex){
            //如果Batch执行失败,则整体rollback,标识不进行清除          
            Database.rollback(sp);
        }

                
    }



    global void finish(Database.BatchableContext BC) {
    UpdateTenderInformationSchedule.assignOneHours();
        BatchIF_Log__c TenderIfLog = new BatchIF_Log__c();
        TenderIfLog.Type__c = 'UpdateTenderInformationBatchErrorLog(Tender)';

        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;

        BatchIF_Log__c OppIfLog = new BatchIF_Log__c();
        OppIfLog.Type__c = 'UpdateTenderInformationBatchErrorLog(Opp)';

        if (OpplogStr.length() > 60000) {
            OpplogStr = OpplogStr.substring(0, 60000);
        }
        OppIfLog.Log__c = OpplogStr;
        OppIfLog.Log__c += '\n end';
        if (OpperrorStr.length() > 60000) {
            OppIfLog.ErrorLog__c = OpperrorStr.substring(0, 60000);
        } else {
            OppIfLog.ErrorLog__c = OpperrorStr.substring(0, OpperrorStr.length());
        }

        insert OppIfLog;


        emailMessages.add('失败日志ID为：' + TenderIfLog.Id );
        emailMessages.add('失败日志ID为：' + OppIfLog.Id );
        
        //发送失败邮件
        sendFieldEmail();

    }

    //更新招投标的询价信息
    WebService static String updateOpportunityInformation(List<String> TenderIdList){
        //定义一个保存点 , 目的 : 如果Batch执行失败,则整体rollback,标识不进行清除
        Savepoint sp = Database.setSavepoint();

        //定义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);

            //计算询价数量
            updateTenderList = updateOpportunityNum(BiddingProjectOppMap,updateTenderList);
           
            //计算询价状态
            updateTenderList = updateOpportunityStatus(BiddingProjectOppMap,updateTenderList);



            //更新
            if(updateTenderList.size()>0){
                update updateTenderList;

                //清除询价标识
                List<Opportunity> updateOppList = new List<Opportunity> ();

                for(String TenderId : TenderIdList){
                    if(BiddingProjectOppMap.get(TenderId)!= null){
                        for(Opportunity opp : BiddingProjectOppMap.get(TenderId)){
                            Opportunity tempOp = new Opportunity();
                            tempOp.Id = opp.Id;
                            tempOp.Bidding_Flag__c = false;
                            //如果询价中 原招投标项目ID有值则清空
                            if(!String.IsBlank(opp.Old_BiddingProject_Bid__c)){
                                tempOp.Old_BiddingProject_Bid__c = null;
                            }

                            updateOppList.add(tempOp);
                        }
                    }
                }                
               

               if(updateOppList.size()>0){
                  update updateOppList;
               }

            }

        }catch(NullPointerException ex){
          Database.rollback(sp);  
          return '空指针 :'+ex.getLineNumber();
        }catch(Exception ex2){          
          Database.rollback(sp);   
          return '出错了!'+ex2.getMessage();
        }
        
        return 'OK';

    }

    //计算询价数量
    public static List<Tender_information__c> updateOpportunityNum(Map<String,List<Opportunity>> tempMap,List<Tender_information__c> updateTenderList ){
        /*//询价数量
        for(Tender_information__c tempTender :updateTenderList){
            String fifteenId = String.valueOf(tempTender.Id).subString(0,15);
            tempTender.OpportunityNum__c = tempMap.get(fifteenId).size();
            if(tempMap.get(fifteenId).size() == 0){
            tempTender.OpportunityStatus__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();
            updateTenderList.add(tempTender);
        }

        return updateTenderList;
    }

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

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

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

            //获取当前招投标下的询价的战略科室
            List<String> OppDepartmentList = new List<String>();
            //创建招标项目
            //Tender_information__c tempTender = 

            //tempTender.Id = k;

            //判断状态
            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(!OppDepartmentList.contains(tempOp.Department_Class__c)){
                        OppDepartmentList.add(tempOp.Department_Class__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> fiveDepartmentMap = new Map<String,String>();
                fiveDepartmentMap.put('department__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.department__c);
                fiveDepartmentMap.put('subDepartment1__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.subDepartment1__c);
                fiveDepartmentMap.put('subDepartment2__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.subDepartment2__c);
                fiveDepartmentMap.put('subDepartment3__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.subDepartment3__c);
                fiveDepartmentMap.put('subDepartment4__c',BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.subDepartment4__c);   

                //如果招投标项目的 是否相关 字段不为否 , 并且 相关医院 相关战略科室 相关普通科室 为空时,则更新 为询价的 医院 战略科室 客户名
                if(!'否'.equals(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.IsRelateProject__c)){
                    //关联医院
                    if(BiddingDownOppList.get(0).Bidding_Project_Name_Bid__r.Hospital__c == null){
                        tempTender.Hospital__c = BiddingDownOppList.get(0).Hospital__c;
                    }
                   

                    //遍历招投标项目下所有询价的战略科室,给招投标项目的5个战略科室赋值 ---start
                    //遍历招投标项目下所有询价的战略科室 
                    for(Integer i = 0; i<OppDepartmentList.size();i++){
                        //当招投标项目的五个战略科室赋值完成后将不再赋值
                        Boolean isNeedBreak = false;
                        for(String ApiName : fiveDepartmentMap.keySet()){
                            isNeedBreak = fiveDepartmentMap.get(ApiName)==null?false:true;
                        }
                        if(isNeedBreak){
                            break;
                        }

                        //给招投标项目的5个战略科室设值
                        for(String ApiName : fiveDepartmentMap.keySet()){
                            String tempTenderDeptId = fiveDepartmentMap.get(ApiName)==null?'':fiveDepartmentMap.get(ApiName);
                            String oppDeptId = OppDepartmentList.get(i);
                            system.debug('tempTenderDeptId:'+tempTenderDeptId);
                            system.debug('oppDeptId:'+oppDeptId);

                            //如果招标项目已经有该战略科室就判断下一个询价的战略科室
                            if(tempTenderDeptId.contains(oppDeptId)){
                                break;
                            }

                            //战略科室为空,赋值战略科室(赋值之后进行赋值下一个战略科室)
                            if(String.isBlank( fiveDepartmentMap.get(ApiName) ) ){
                                fiveDepartmentMap.put(ApiName,oppDeptId);
                                break;
                            }
                        }
                    }

                    //赋值战略科室
                    tempTender.department__c = fiveDepartmentMap.get('department__c');
                    tempTender.subDepartment1__c = fiveDepartmentMap.get('subDepartment1__c');
                    tempTender.subDepartment2__c = fiveDepartmentMap.get('subDepartment2__c');
                    tempTender.subDepartment3__c = fiveDepartmentMap.get('subDepartment3__c');
                    tempTender.subDepartment4__c = fiveDepartmentMap.get('subDepartment4__c');

                    
                    //遍历招投标项目下所有询价的战略科室,给招投标项目的5个战略科室赋值 ---start

                }

                //如果 是否相关 字段已经选择否, 就不应该更新相关及相关的相关信息
                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.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[] {};
        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();
            }
        }
        be = new PretechBatchEmailUtil();
        title = '询价更新失败';        
        if (System.Test.isRunningTest()) {
            be.successMail('', 1);
        }
        if (emailMessages.size() > 0 && OppfailedCount > 0){
            be.failedMail(toList, ccList, title,this.emailMessages.get(1)+'\n',
                            OpptotalCount, OpptotalCount - OppfailedCount, OppfailedCount,'',true);
            if(!Test.isRunningTest()){
                be.send();
            }
        }

    }

    
}