liuyn
2024-03-11 a87f1c3df03078814ee97ad0c8ac200a232419e9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/**备品智能化
 * 2023-12-28 Add by dzk
 * 计划外的OPD根据当前日期与拍照日,判断按照上月还是当月排序
 * 获取下月14号——下下月13号,符合条件的OPD计划状态为计划中的备品申请数据
 */
global class OPDAutomaticSortBeforeBatch implements Database.Batchable<sObject> {
    private final List<String> 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<String> 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<opp2AuxiliarySort__c> 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<String,Integer> provinceSortMap = new Map<String,Integer>();
            // 获取符合条件的时间的已排序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<OPDPlan__c> beforeOPDPlanList = Database.query(orderquery);
            // List<OPDPlan__c> 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<OPDPlan__c> tempList01 = Database.query(soql+soql01);
            List<OPDPlan__c> 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<OPDPlan__c> opdUpdateList = new List<OPDPlan__c>();
            // 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<OlympusCalendar__c> 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;
    }
}