jin.shuai

农信停餐

......@@ -84,6 +84,24 @@ public class AutoCreateMealOrderTask {
final var thisWeekEnd = today.with(DayOfWeek.SUNDAY).atTime(LocalTime.MAX).atZone(DateUtil.CHINA_ZONE);
final var nextWeekStart = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).atStartOfDay().atZone(DateUtil.CHINA_ZONE);
// 获取下周每天的节假日信息
final var holidayMap = new HashMap<String, Integer>();
for (int i = 0; i < 7; i++) {
final var date = nextWeekStart.plusDays(i);
final var dateStr = date.format(DateUtil.YYYY_MM_DD);
try {
final var url = String.format("https://api.haoshenqi.top/holiday?date=%s", dateStr);
final var response = new java.net.URL(url).openConnection();
final var reader = new java.io.BufferedReader(new java.io.InputStreamReader(response.getInputStream()));
final var jsonResponse = reader.readLine();
final var jsonNode = new com.fasterxml.jackson.databind.ObjectMapper().readTree(jsonResponse);
final var status = jsonNode.get(0).get("status").asInt();
holidayMap.put(dateStr, status);
} catch (Exception e) {
log.error("检查节假日失败: {}", dateStr, e);
}
}
// 查询本周已订餐学生 ID
final var mealOrders = mealOrderServiceRpcClient.queryMealOrdersByCondition(enterpriseId, null, thisWeekStart.toInstant().toEpochMilli(), thisWeekEnd.toInstant().toEpochMilli());
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 {
enterpriseId,
clientIds, // 使用0表示查询所有
null,
null
List.of(0)
);
if (schoolSuspensionRecords != null) {
var currentTime = System.currentTimeMillis();
final var nextWeekStartTime = nextWeekStart.toInstant().toEpochMilli();
final var nextWeekEndTime = nextWeekStart.plusDays(6).with(LocalTime.MAX).toInstant().toEpochMilli();
schoolSuspensionRecords.stream()
.filter(record -> clientIds.contains(record.getClientId()))
.filter(record -> currentTime >= record.getStartAt() && currentTime <= record.getEndAt())
.filter(record -> !(record.getEndAt() < nextWeekStartTime || record.getStartAt() > nextWeekEndTime))
.collect(Collectors.groupingBy(
SingleDinerMealSuspensionRecordRpcResponse::getClientId,
Collectors.collectingAndThen(
......@@ -142,14 +162,15 @@ public class AutoCreateMealOrderTask {
);
if (studentSuspensionRecords != null) {
var currentTime = System.currentTimeMillis();
final var nextWeekStartTime = nextWeekStart.toInstant().toEpochMilli();
final var nextWeekEndTime = nextWeekStart.plusDays(6).with(LocalTime.MAX).toInstant().toEpochMilli();
var dinerIdSet = notReservedDiners.stream()
.map(SingleDinerRpcResponse::getId)
.collect(Collectors.toSet());
studentSuspensionRecords.stream()
.filter(record -> dinerIdSet.contains(record.getDinerId()))
.filter(record -> currentTime >= record.getStartAt() && currentTime <= record.getEndAt())
.filter(record -> !(record.getEndAt() < nextWeekStartTime || record.getStartAt() > nextWeekEndTime))
.collect(Collectors.groupingBy(
SingleDinerMealSuspensionRecordRpcResponse::getDinerId,
Collectors.collectingAndThen(
......@@ -174,7 +195,8 @@ public class AutoCreateMealOrderTask {
mpAccountDinerRefMap,
nextWeekStart,
schoolSuspensionMap,
studentSuspensionMap
studentSuspensionMap,
holidayMap
))
.filter(Objects::nonNull)
.toList();
......@@ -202,24 +224,22 @@ public class AutoCreateMealOrderTask {
Map<Integer, SingleMpAccountDinerRefRpcResponse> mpAccountDinerRefMap,
ZonedDateTime startOfNextWeek,
Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> schoolSuspensionMap,
Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> studentSuspensionMap) {
Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> studentSuspensionMap,
Map<String, Integer> holidayMap) {
final var menu = menuMap.get(diner.getClientId());
final var client = clientMap.get(diner.getClientId());
final var gradeClass = classMap.get(diner.getClassId());
final var mpAccountDinerRef = mpAccountDinerRefMap.get(diner.getId());
if (menu == null || client == null || gradeClass == null) return null;
// 检查学校级别的停餐信息
if (schoolSuspensionMap.containsKey(diner.getClientId())) {
log.info("学校 {} 当前处于停餐状态,跳过自动订餐", client.getName());
return null;
// 获取停餐信息,优先使用学校级别的
SingleDinerMealSuspensionRecordRpcResponse suspensionRecord = schoolSuspensionMap.get(diner.getClientId());
if (suspensionRecord == null) {
suspensionRecord = studentSuspensionMap.get(diner.getId());
}
// 检查学生级别的停餐信息
if (studentSuspensionMap.containsKey(diner.getId())) {
log.info("学生 {} 当前处于停餐状态,跳过自动订餐", diner.getName());
return null;
}
// 构建下周的餐食安排
List<MenuSchedule> meals = buildNextWeekMeals(startOfNextWeek, suspensionRecord, holidayMap);
return MealOrderCreation.newBuilder()
.setClientId(diner.getClientId())
......@@ -233,24 +253,50 @@ public class AutoCreateMealOrderTask {
.setClassName(gradeClass.getClassName())
.setStudentNo(diner.getStudentNo())
.setReserveDate(Instant.now().toEpochMilli())
.addAllMeals(buildNextWeekMeals(startOfNextWeek))
.addAllMeals(meals)
.build();
}
private LocalDate getThisWeekDay(LocalDate now, DayOfWeek target) {
LocalDate monday = now.with(DayOfWeek.MONDAY);
return monday.plusDays(target.getValue() - 1L);
}
private List<MenuSchedule> buildNextWeekMeals(ZonedDateTime nextWeekStart) {
return IntStream.range(0, 5)
private List<MenuSchedule> buildNextWeekMeals(ZonedDateTime nextWeekStart,
SingleDinerMealSuspensionRecordRpcResponse suspensionRecord,
Map<String, Integer> holidayMap) {
return IntStream.range(0, 7)
.mapToObj(i -> {
final var date = nextWeekStart.plusDays(i);
final var dateStr = date.format(DateUtil.YYYY_MM_DD);
// 检查是否为节假日
final var status = holidayMap.get(dateStr);
if (status != null && status != 0 && status != 2) {
// 如果不是工作日,返回null
return null;
}
// 如果有停餐信息,检查当前循环的日期是否在停餐时间范围内
if (suspensionRecord != null) {
final var dateStart = date.with(LocalTime.MIN).toInstant().toEpochMilli();
final var dateEnd = date.with(LocalTime.MAX).toInstant().toEpochMilli();
final var suspensionStart = suspensionRecord.getStartAt();
final var suspensionEnd = suspensionRecord.getEndAt();
// 如果停餐时间范围与当前日期有重叠,返回null
if (!(dateEnd < suspensionStart || dateStart > suspensionEnd)) {
return null;
}
}
// 如果是工作日且不在停餐时间内,返回正常菜单
return MenuSchedule.newBuilder()
.setDate(date.format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL))
.setMenu("A")
.build();
})
.filter(Objects::nonNull) // 过滤掉null值
.toList();
}
private LocalDate getThisWeekDay(LocalDate now, DayOfWeek target) {
LocalDate monday = now.with(DayOfWeek.MONDAY);
return monday.plusDays(target.getValue() - 1L);
}
}
......