jin.shuai

农信停餐

...@@ -84,6 +84,24 @@ public class AutoCreateMealOrderTask { ...@@ -84,6 +84,24 @@ public class AutoCreateMealOrderTask {
84 final var thisWeekEnd = today.with(DayOfWeek.SUNDAY).atTime(LocalTime.MAX).atZone(DateUtil.CHINA_ZONE); 84 final var thisWeekEnd = today.with(DayOfWeek.SUNDAY).atTime(LocalTime.MAX).atZone(DateUtil.CHINA_ZONE);
85 final var nextWeekStart = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).atStartOfDay().atZone(DateUtil.CHINA_ZONE); 85 final var nextWeekStart = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).atStartOfDay().atZone(DateUtil.CHINA_ZONE);
86 86
87 + // 获取下周每天的节假日信息
88 + final var holidayMap = new HashMap<String, Integer>();
89 + for (int i = 0; i < 7; i++) {
90 + final var date = nextWeekStart.plusDays(i);
91 + final var dateStr = date.format(DateUtil.YYYY_MM_DD);
92 + try {
93 + final var url = String.format("https://api.haoshenqi.top/holiday?date=%s", dateStr);
94 + final var response = new java.net.URL(url).openConnection();
95 + final var reader = new java.io.BufferedReader(new java.io.InputStreamReader(response.getInputStream()));
96 + final var jsonResponse = reader.readLine();
97 + final var jsonNode = new com.fasterxml.jackson.databind.ObjectMapper().readTree(jsonResponse);
98 + final var status = jsonNode.get(0).get("status").asInt();
99 + holidayMap.put(dateStr, status);
100 + } catch (Exception e) {
101 + log.error("检查节假日失败: {}", dateStr, e);
102 + }
103 + }
104 +
87 // 查询本周已订餐学生 ID 105 // 查询本周已订餐学生 ID
88 final var mealOrders = mealOrderServiceRpcClient.queryMealOrdersByCondition(enterpriseId, null, thisWeekStart.toInstant().toEpochMilli(), thisWeekEnd.toInstant().toEpochMilli()); 106 final var mealOrders = mealOrderServiceRpcClient.queryMealOrdersByCondition(enterpriseId, null, thisWeekStart.toInstant().toEpochMilli(), thisWeekEnd.toInstant().toEpochMilli());
89 final var dinerIds = mealOrders.stream().map(SingleMealOrderRpcResponse::getDinerId).sorted(Comparator.comparingInt(Integer::intValue)).collect(Collectors.toCollection(LinkedHashSet::new)); 107 final var dinerIds = mealOrders.stream().map(SingleMealOrderRpcResponse::getDinerId).sorted(Comparator.comparingInt(Integer::intValue)).collect(Collectors.toCollection(LinkedHashSet::new));
...@@ -110,14 +128,16 @@ public class AutoCreateMealOrderTask { ...@@ -110,14 +128,16 @@ public class AutoCreateMealOrderTask {
110 enterpriseId, 128 enterpriseId,
111 clientIds, // 使用0表示查询所有 129 clientIds, // 使用0表示查询所有
112 null, 130 null,
113 - null 131 + List.of(0)
114 ); 132 );
115 133
116 if (schoolSuspensionRecords != null) { 134 if (schoolSuspensionRecords != null) {
117 - var currentTime = System.currentTimeMillis(); 135 + final var nextWeekStartTime = nextWeekStart.toInstant().toEpochMilli();
136 + final var nextWeekEndTime = nextWeekStart.plusDays(6).with(LocalTime.MAX).toInstant().toEpochMilli();
137 +
118 schoolSuspensionRecords.stream() 138 schoolSuspensionRecords.stream()
119 .filter(record -> clientIds.contains(record.getClientId())) 139 .filter(record -> clientIds.contains(record.getClientId()))
120 - .filter(record -> currentTime >= record.getStartAt() && currentTime <= record.getEndAt()) 140 + .filter(record -> !(record.getEndAt() < nextWeekStartTime || record.getStartAt() > nextWeekEndTime))
121 .collect(Collectors.groupingBy( 141 .collect(Collectors.groupingBy(
122 SingleDinerMealSuspensionRecordRpcResponse::getClientId, 142 SingleDinerMealSuspensionRecordRpcResponse::getClientId,
123 Collectors.collectingAndThen( 143 Collectors.collectingAndThen(
...@@ -142,14 +162,15 @@ public class AutoCreateMealOrderTask { ...@@ -142,14 +162,15 @@ public class AutoCreateMealOrderTask {
142 ); 162 );
143 163
144 if (studentSuspensionRecords != null) { 164 if (studentSuspensionRecords != null) {
145 - var currentTime = System.currentTimeMillis(); 165 + final var nextWeekStartTime = nextWeekStart.toInstant().toEpochMilli();
166 + final var nextWeekEndTime = nextWeekStart.plusDays(6).with(LocalTime.MAX).toInstant().toEpochMilli();
146 var dinerIdSet = notReservedDiners.stream() 167 var dinerIdSet = notReservedDiners.stream()
147 .map(SingleDinerRpcResponse::getId) 168 .map(SingleDinerRpcResponse::getId)
148 .collect(Collectors.toSet()); 169 .collect(Collectors.toSet());
149 170
150 studentSuspensionRecords.stream() 171 studentSuspensionRecords.stream()
151 .filter(record -> dinerIdSet.contains(record.getDinerId())) 172 .filter(record -> dinerIdSet.contains(record.getDinerId()))
152 - .filter(record -> currentTime >= record.getStartAt() && currentTime <= record.getEndAt()) 173 + .filter(record -> !(record.getEndAt() < nextWeekStartTime || record.getStartAt() > nextWeekEndTime))
153 .collect(Collectors.groupingBy( 174 .collect(Collectors.groupingBy(
154 SingleDinerMealSuspensionRecordRpcResponse::getDinerId, 175 SingleDinerMealSuspensionRecordRpcResponse::getDinerId,
155 Collectors.collectingAndThen( 176 Collectors.collectingAndThen(
...@@ -174,7 +195,8 @@ public class AutoCreateMealOrderTask { ...@@ -174,7 +195,8 @@ public class AutoCreateMealOrderTask {
174 mpAccountDinerRefMap, 195 mpAccountDinerRefMap,
175 nextWeekStart, 196 nextWeekStart,
176 schoolSuspensionMap, 197 schoolSuspensionMap,
177 - studentSuspensionMap 198 + studentSuspensionMap,
199 + holidayMap
178 )) 200 ))
179 .filter(Objects::nonNull) 201 .filter(Objects::nonNull)
180 .toList(); 202 .toList();
...@@ -202,24 +224,22 @@ public class AutoCreateMealOrderTask { ...@@ -202,24 +224,22 @@ public class AutoCreateMealOrderTask {
202 Map<Integer, SingleMpAccountDinerRefRpcResponse> mpAccountDinerRefMap, 224 Map<Integer, SingleMpAccountDinerRefRpcResponse> mpAccountDinerRefMap,
203 ZonedDateTime startOfNextWeek, 225 ZonedDateTime startOfNextWeek,
204 Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> schoolSuspensionMap, 226 Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> schoolSuspensionMap,
205 - Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> studentSuspensionMap) { 227 + Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> studentSuspensionMap,
228 + Map<String, Integer> holidayMap) {
206 final var menu = menuMap.get(diner.getClientId()); 229 final var menu = menuMap.get(diner.getClientId());
207 final var client = clientMap.get(diner.getClientId()); 230 final var client = clientMap.get(diner.getClientId());
208 final var gradeClass = classMap.get(diner.getClassId()); 231 final var gradeClass = classMap.get(diner.getClassId());
209 final var mpAccountDinerRef = mpAccountDinerRefMap.get(diner.getId()); 232 final var mpAccountDinerRef = mpAccountDinerRefMap.get(diner.getId());
210 if (menu == null || client == null || gradeClass == null) return null; 233 if (menu == null || client == null || gradeClass == null) return null;
211 234
212 - // 检查学校级别的停餐信息 235 + // 获取停餐信息,优先使用学校级别的
213 - if (schoolSuspensionMap.containsKey(diner.getClientId())) { 236 + SingleDinerMealSuspensionRecordRpcResponse suspensionRecord = schoolSuspensionMap.get(diner.getClientId());
214 - log.info("学校 {} 当前处于停餐状态,跳过自动订餐", client.getName()); 237 + if (suspensionRecord == null) {
215 - return null; 238 + suspensionRecord = studentSuspensionMap.get(diner.getId());
216 } 239 }
217 240
218 - // 检查学生级别的停餐信息 241 + // 构建下周的餐食安排
219 - if (studentSuspensionMap.containsKey(diner.getId())) { 242 + List<MenuSchedule> meals = buildNextWeekMeals(startOfNextWeek, suspensionRecord, holidayMap);
220 - log.info("学生 {} 当前处于停餐状态,跳过自动订餐", diner.getName());
221 - return null;
222 - }
223 243
224 return MealOrderCreation.newBuilder() 244 return MealOrderCreation.newBuilder()
225 .setClientId(diner.getClientId()) 245 .setClientId(diner.getClientId())
...@@ -233,24 +253,50 @@ public class AutoCreateMealOrderTask { ...@@ -233,24 +253,50 @@ public class AutoCreateMealOrderTask {
233 .setClassName(gradeClass.getClassName()) 253 .setClassName(gradeClass.getClassName())
234 .setStudentNo(diner.getStudentNo()) 254 .setStudentNo(diner.getStudentNo())
235 .setReserveDate(Instant.now().toEpochMilli()) 255 .setReserveDate(Instant.now().toEpochMilli())
236 - .addAllMeals(buildNextWeekMeals(startOfNextWeek)) 256 + .addAllMeals(meals)
237 .build(); 257 .build();
238 } 258 }
239 259
240 - private LocalDate getThisWeekDay(LocalDate now, DayOfWeek target) { 260 + private List<MenuSchedule> buildNextWeekMeals(ZonedDateTime nextWeekStart,
241 - LocalDate monday = now.with(DayOfWeek.MONDAY); 261 + SingleDinerMealSuspensionRecordRpcResponse suspensionRecord,
242 - return monday.plusDays(target.getValue() - 1L); 262 + Map<String, Integer> holidayMap) {
243 - } 263 + return IntStream.range(0, 7)
244 -
245 - private List<MenuSchedule> buildNextWeekMeals(ZonedDateTime nextWeekStart) {
246 - return IntStream.range(0, 5)
247 .mapToObj(i -> { 264 .mapToObj(i -> {
248 final var date = nextWeekStart.plusDays(i); 265 final var date = nextWeekStart.plusDays(i);
266 + final var dateStr = date.format(DateUtil.YYYY_MM_DD);
267 +
268 + // 检查是否为节假日
269 + final var status = holidayMap.get(dateStr);
270 + if (status != null && status != 0 && status != 2) {
271 + // 如果不是工作日,返回null
272 + return null;
273 + }
274 +
275 + // 如果有停餐信息,检查当前循环的日期是否在停餐时间范围内
276 + if (suspensionRecord != null) {
277 + final var dateStart = date.with(LocalTime.MIN).toInstant().toEpochMilli();
278 + final var dateEnd = date.with(LocalTime.MAX).toInstant().toEpochMilli();
279 + final var suspensionStart = suspensionRecord.getStartAt();
280 + final var suspensionEnd = suspensionRecord.getEndAt();
281 +
282 + // 如果停餐时间范围与当前日期有重叠,返回null
283 + if (!(dateEnd < suspensionStart || dateStart > suspensionEnd)) {
284 + return null;
285 + }
286 + }
287 +
288 + // 如果是工作日且不在停餐时间内,返回正常菜单
249 return MenuSchedule.newBuilder() 289 return MenuSchedule.newBuilder()
250 .setDate(date.format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL)) 290 .setDate(date.format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL))
251 .setMenu("A") 291 .setMenu("A")
252 .build(); 292 .build();
253 }) 293 })
294 + .filter(Objects::nonNull) // 过滤掉null值
254 .toList(); 295 .toList();
255 } 296 }
297 +
298 + private LocalDate getThisWeekDay(LocalDate now, DayOfWeek target) {
299 + LocalDate monday = now.with(DayOfWeek.MONDAY);
300 + return monday.plusDays(target.getValue() - 1L);
301 + }
256 } 302 }
......