/**备品智能化 * 2023-12-28 Add by dzk * 计划外的OPD根据当前日期与拍照日,判断按照上月还是当月排序 * 获取下月14号——下下月13号,符合条件的OPD计划状态为计划中的备品申请数据 */ global class OPDAutomaticSortBeforeBatch implements Database.Batchable { private final List sdcName = null; private BatchIF_Log__c iflog; private Date specialDate; private Boolean allOutofPlan = false; // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 start private Boolean executeCopyToBefore = false; // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 end global OPDAutomaticSortBeforeBatch(Boolean exe){ // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 start this.executeCopyToBefore = exe; // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 end this.iflog = new BatchIF_Log__c(); this.iflog.Type__c = 'OPDAutomaticSortBeforeBatch'; this.iflog.Log__c = 'OPDAutomaticSortBeforeBatch start\n'; this.iflog.ErrorLog__c = ''; insert this.iflog; } global OPDAutomaticSortBeforeBatch(List str){ this.sdcName = str; this.iflog = new BatchIF_Log__c(); this.iflog.Type__c = 'OPDAutomaticSortBeforeBatch'; this.iflog.Log__c = 'OPDAutomaticSortBeforeBatch start\n'; this.iflog.ErrorLog__c = ''; insert this.iflog; } global OPDAutomaticSortBeforeBatch(Date spDate) { this.specialDate = spDate; this.iflog = new BatchIF_Log__c(); this.iflog.Type__c = 'OPDAutomaticSortBeforeBatch'; this.iflog.Log__c = 'OPDAutomaticSortBeforeBatch start\n'; this.iflog.ErrorLog__c = ''; insert this.iflog; } global OPDAutomaticSortBeforeBatch(Boolean allOP, Date spDate) { this.allOutofPlan = allOP; this.specialDate = spDate; this.iflog = new BatchIF_Log__c(); this.iflog.Type__c = 'OPDAutomaticSortBeforeBatch'; this.iflog.Log__c = 'OPDAutomaticSortBeforeBatch start\n'; this.iflog.ErrorLog__c = ''; insert this.iflog; } global Database.QueryLocator start(Database.BatchableContext BC){ String sql = 'SELECT Id,Name,type__c FROM opp2AuxiliarySort__c '; sql += 'WHERE (type__c = 1 OR type__c = 11) '; if(sdcName <> null){ sql += 'AND Name IN :sdcName '; } sql += ' ORDER BY type__c'; System.debug('=sql='+sql); return Database.getQueryLocator(sql); } global void execute(Database.BatchableContext BC, List opp2AuxiliarySortList) { try{ // 获取当前日期 Date toDate = this.specialDate != null ? this.specialDate : Date.today(); // 获取当前月的拍照日 Date penultimateDate = getPenultimateWorkDayOfMonth(toDate); // 判断当前日期与拍照日的关系 // 今天大于当月拍照日 -> 当月拍照日 // 今天小于等于当月拍照日 -> 上月拍照日 penultimateDate = toDate > penultimateDate ? penultimateDate : getPenultimateWorkDayOfMonth(toDate.addMonths(-1)); // 根据拍照日确认计划实施日范围 // 获取从次月14日至再次月13日的日期 Date startDate = penultimateDate == Date.newInstance(2023, 12, 28) ? Date.newInstance(2024,1,1) : penultimateDate.addMonths(1).toStartOfMonth().addDays(13); Date endDate = penultimateDate.addMonths(2).toStartOfMonth().addDays(12); Map provinceSortMap = new Map(); // 获取符合条件的时间的已排序OPD计划最大排队序号 // 这里的话要检索自动排序或非自动排序但备品已分配的最大序号 // 上线后优化 // 1.增加排序号不为空的判断 // 2.增加计划外的OPD被取消的判断,状态取消也作为序号最大值的判断条件之一 // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 start String orderquery = 'SELECT Id, Name, OPDLendSort__c FROM OPDPlan__c '; orderquery += 'WHERE OPDPlanOCM_man_province_Rental__c = \'' + opp2AuxiliarySortList[0].Name + '\' '; orderquery += 'AND OPDPlan_ImplementDate__c >= :startDate '; orderquery += 'AND OPDPlan_ImplementDate__c <= :endDate '; orderquery += 'AND OPDLendSort__c != null '; // 20240227 ssm 备品可视化补充 start // 上月残留的就不进排序队列了,序号也不用 orderquery += 'AND Last_Month_Untreated__c = false '; // 20240227 ssm 备品可视化补充 end if (this.allOutofPlan) { orderquery += 'AND If_AutoSort__c = 1 '; } else { // 2024-02-01 ssm 增加非上月残留的条件 start // 上月残留的OPD计划就不再重新排序以及占用序号了 // orderquery += 'AND (If_AutoSort__c = 1 OR (If_AutoSort__c = 0 AND (Bollowdate__c != null OR Status__c = \'取消\'))) '; orderquery += 'AND (If_AutoSort__c = 1 OR (If_AutoSort__c = 0 AND (Bollowdate__c != null OR Status__c = \'取消\'))) '; // 2024-02-01 ssm 增加非上月残留的条件 end } orderquery += 'ORDER BY OPDLendSort__c DESC LIMIT 1 '; List beforeOPDPlanList = Database.query(orderquery); // List beforeOPDPlanList = [SELECT Id, Name, OPDLendSort__c // FROM OPDPlan__c // WHERE OPDPlanOCM_man_province_Rental__c =: opp2AuxiliarySortList[0].Name // AND OPDPlan_ImplementDate__c >=: startDate // AND OPDPlan_ImplementDate__c <=: endDate // AND OPDLendSort__c != null // AND (If_AutoSort__c = 1 OR (If_AutoSort__c = 0 AND (Bollowdate__c != null OR Status__c = '取消'))) // ORDER BY OPDLendSort__c DESC LIMIT 1]; // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 end iflog.Log__c += 'last sort: ' + beforeOPDPlanList != null && beforeOPDPlanList.size() > 0 ? beforeOPDPlanList[0].OPDLendSort__c : 0; // 获取符合条件的已排序的OPD计划数据 DateTime penultimateDateTime = DateTime.newInstance(penultimateDate, Time.newInstance(0, 0, 0, 0)); penultimateDateTime = penultimateDateTime.addHours(8); String soql = 'SELECT Id,SortDate__c,OPDPlanOCM_man_province_Rental__c,OPDLendSort__c,OPDLendSortDraft__c,SortOperator__c FROM OPDPlan__c '; //拼接SQL AccountType__c不一样 两种排序规则 String soql01 = ' WHERE OPDPlanOCM_man_province_Rental__c = \'' + opp2AuxiliarySortList[0].Name + '\''; // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 start if (this.allOutofPlan) { soql01 += ' and Status__c != \'草案中\' and Status__c != \'审批中\' '; } else { soql01 += ' and (Status__c = \'计划中\' OR (Status__c in (\'完毕未报告\', \'待提交报告\', \'完毕\') and OPDLendSort__c = null))'; } // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 end // soql01 += ' and OPDPlan_ImplementDate__c >=: startDate ' ; soql01 += ' and OPDPlan_ImplementDate__c <=: endDate '; // 2024-02-01 ssm 计划外进入条件调整 start // 考虑创建日和审批日不相同的情况,用审批日更合理一些。对象上增加审批通过日,在批准过程最终批准时增加赋值。 soql01 += ' and (CreatedDate >=: penultimateDateTime '; soql01 += ' or ApprovePassed__c >= :penultimateDate) '; // 2024-02-01 ssm 增加非上月残留的条件 end soql01 += ' and AccountType__c = \'学会会议\' '; // 2024-02-01 ssm 增加非上月残留的条件 start // 重新排序时也增加相应判断 soql01 += ' and Last_Month_Untreated__c = false '; // 2024-02-01 ssm 增加非上月残留的条件 end soql01 += ' and If_AutoSort__c != 1 '; soql01 += ' order by OPDPlan_ImplementDate__c ASC,CreatedDate ASC '; String soql02 = ' WHERE OPDPlanOCM_man_province_Rental__c = \'' + opp2AuxiliarySortList[0].Name + '\''; // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 start if (this.allOutofPlan) { soql02 += ' and Status__c != \'草案中\' and Status__c != \'审批中\' '; } else { soql02 += ' and (Status__c = \'计划中\' OR (Status__c in (\'完毕未报告\', \'待提交报告\', \'完毕\') and OPDLendSort__c = null))'; } // 20240115 ssm 为处理历史数据方便,增加所有计划外手动重新排队分支 end // soql02 += ' and OPDPlan_ImplementDate__c >=: startDate ' ; soql02 += ' and OPDPlan_ImplementDate__c <=: endDate '; // 2024-02-01 ssm 计划外进入条件调整 start // 考虑创建日和审批日不相同的情况,用审批日更合理一些。对象上增加审批通过日,在批准过程最终批准时增加赋值。 soql02 += ' and (CreatedDate >=: penultimateDateTime '; soql02 += ' or ApprovePassed__c >= :penultimateDate) '; // 2024-02-01 ssm 增加非上月残留的条件 end soql02 += ' and AccountType__c = \'医院\' '; // 2024-02-01 ssm 增加非上月残留的条件 start // 重新排序时也增加相应判断 soql02 += ' and Last_Month_Untreated__c = false '; // 2024-02-01 ssm 增加非上月残留的条件 end soql02 += ' and If_AutoSort__c != 1 '; // 通过再申请生成的OPD计划 优先度最高,排在最前面 soql02 += ' order by Reapply__c DESC nulls last, OPDPlan_ImplementDate__c ASC, if_HaveEquipment__c ASC,'; soql02 += ' if_Newest_HaveOpportunity__c DESC nulls last ,if_OPDTarget__c DESC nulls last,if_HaveSalestarget__c DESC nulls last'; //分别查询结果后拼接 在遍历排序赋值 List tempList01 = Database.query(soql+soql01); List tempList02 = Database.query(soql+soql02); tempList01.addAll(tempList02); // 省份与排序 for(OPDPlan__c opdbefore : tempList01){ if(beforeOPDPlanList == null || beforeOPDPlanList.size() == 0 || beforeOPDPlanList[0].OPDLendSort__c == null){ provinceSortMap.put(opdbefore.OPDPlanOCM_man_province_Rental__c, 0); }else{ provinceSortMap.put(opdbefore.OPDPlanOCM_man_province_Rental__c, Integer.valueOf(beforeOPDPlanList[0].OPDLendSort__c)); } } // 获取符合条件的OPD计划下的出借备品申请 List opdUpdateList = new List(); // for(OPDPlan__c opdp : sortedOPDList) { for(OPDPlan__c opdp : tempList01) { String opdProvince = opdp.OPDPlanOCM_man_province_Rental__c; opdp.OPDLendSort__c = provinceSortMap.get(opdProvince) + 1; opdp.OPDLendSortDraft__c = provinceSortMap.get(opdProvince) + 1; provinceSortMap.put(opdProvince, Integer.valueOf(opdp.OPDLendSort__c)); opdp.SortDate__c = Date.today(); opdp.SortOperator__c = userInfo.getUserId(); opdp.If_AutoSort__c = 0; opdUpdateList.add(opdp); } // if (sortedOPDList != null && sortedOPDList.size() > 0) { // update sortedOPDList; // } if (opdUpdateList != null && opdUpdateList.size() > 0) { update opdUpdateList; } }catch(Exception ex){ iflog.ErrorLog__c = ex.getLineNumber()+' 行错误 : '+ex.getMessage(); return; } } global void finish(Database.BatchableContext BC) { iflog.Log__c += '\nOPDAutomaticSortBeforeBatch end' ; String tmp = iflog.ErrorLog__c; if (tmp != null && tmp.length() > 65000) { tmp = tmp.substring(0, 65000); tmp += ' ...have more lines...'; iflog.ErrorLog__c = tmp; } update iflog; // 备品可视化 计划外OPD计算OPD排序No处理 // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 start // 增加一个代参的构造方法,在备品计划外排序完成后更新OPD上的上月残留标记 // Database.executebatch(new RentalAutomaticSortBeforeBatch(), 1); Database.executebatch(new RentalAutomaticSortBeforeBatch(executeCopyToBefore), 1); // 2024-01-24 ssm 增加一个判断,在月末倒数第二个工作日的时候执行上月排序拷贝操作 end } // 获取倒数第二个工作日 public Date getPenultimateWorkDayOfMonth(Date metaDate) { // 获取待查日期+1月的第一天 Date firstDayOfNextMonth = metaDate.addMonths(1).toStartOfMonth(); // 此表会维护一个工作日的日历 其中排除掉了周末及节假日 此处通过倒叙排序加limit 2 只拿到倒数第二个工作日 List olympusCalendarDate = [ Select Date__c From OlympusCalendar__c Where Date__c < :firstDayOfNextMonth And IsWorkDay__c = 1 ORDER BY Date__c DESC LIMIT 2 ]; Date firstWorkDayOfMonth = metaDate; if (olympusCalendarDate != null && olympusCalendarDate.size() > 1) { firstWorkDayOfMonth = olympusCalendarDate.get(1).Date__c; } return firstWorkDayOfMonth; } }