zhuyifan

feat(task): 实现自动创建餐单的周任务

......@@ -6,6 +6,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.infoloop.tianting.server.StorageService;
import com.infoloop.tianting.server.StorageServiceFactory;
import com.infoloop.tianting.store.LoginCodeStore;
import com.infoloop.tianting.store.WeeklyTaskStore;
import com.infoloop.tianting.utils.SmsUtil;
import io.lettuce.core.api.StatefulRedisConnection;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -16,6 +17,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import java.time.Duration;
import static com.infoloop.tianting.constant.ConfigConstants.REDIS_CONNECTION;
@Configuration
......@@ -29,6 +32,13 @@ public class AppConfig {
return new LoginCodeStore(commands, 300);
}
@Bean
public WeeklyTaskStore weeklyTaskStore(@Autowired @Qualifier(REDIS_CONNECTION) final StatefulRedisConnection<String, String> connection) {
final var commands = connection.sync();
final var expireSeconds = Duration.ofDays(7).getSeconds();
return new WeeklyTaskStore(commands, expireSeconds);
}
// init bean
@Bean
public SmsUtil smsUtil(@Autowired SmsConfig smsConfig) {
......
......@@ -11,7 +11,9 @@ import com.infoloop.tianting.mealorderservice.SingleGradeClassRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleMealMenuRecordRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleMealOrderRpcResponse;
import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient;
import com.infoloop.tianting.service.client.DeliveryRuleServiceRpcClient;
import com.infoloop.tianting.service.client.MealOrderServiceRpcClient;
import com.infoloop.tianting.store.WeeklyTaskStore;
import com.infoloop.tianting.utils.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -21,9 +23,12 @@ import org.springframework.stereotype.Component;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
......@@ -40,10 +45,40 @@ public class AutoCreateMealOrderTask {
private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient;
@Scheduled(cron = "59 59 23 ? * SUN")
private final DeliveryRuleServiceRpcClient deliveryRuleServiceRpcClient;
private final WeeklyTaskStore weeklyTaskStore;
@Scheduled(cron = "0 * * ? * *")
public void executeTask() {
final int enterpriseId = 449;
final var today = LocalDate.now();
final var now = LocalDateTime.now();
final var today = now.toLocalDate();
// 判断是否本周已执行
final var keyPrefix = "create-meal-order-task";
if (weeklyTaskStore.isExecutedThisWeek(keyPrefix, enterpriseId, today)) return;
final var rules = deliveryRuleServiceRpcClient.getDefaultDeliveryTemplateAndRule(enterpriseId).getRule();
if (rules.getConfigJson().getRulesList().isEmpty()) {
return;
}
final var rule = rules.getConfigJson().getRules(0);
final var endTime = LocalTime.parse(rule.getEndTime(), DateUtil.HH_MM_SS);
final var enabledDays = new ArrayList<DayOfWeek>();
if (Boolean.TRUE.equals(rule.getMonday())) enabledDays.add(DayOfWeek.MONDAY);
if (Boolean.TRUE.equals(rule.getTuesday())) enabledDays.add(DayOfWeek.TUESDAY);
if (Boolean.TRUE.equals(rule.getWednesday())) enabledDays.add(DayOfWeek.WEDNESDAY);
if (Boolean.TRUE.equals(rule.getThursday())) enabledDays.add(DayOfWeek.THURSDAY);
if (Boolean.TRUE.equals(rule.getFriday())) enabledDays.add(DayOfWeek.FRIDAY);
if (Boolean.TRUE.equals(rule.getSaturday())) enabledDays.add(DayOfWeek.SATURDAY);
if (Boolean.TRUE.equals(rule.getSunday())) enabledDays.add(DayOfWeek.SUNDAY);
if (enabledDays.isEmpty()) {
return;
}
final var maxDay = Collections.max(enabledDays);
final var endDateTime = getThisWeekDay(today, maxDay).atTime(endTime);
if (now.isBefore(endDateTime)) return;
final var thisWeekStart = today.with(DayOfWeek.MONDAY).atStartOfDay().atZone(DateUtil.CHINA_ZONE);
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);
......@@ -78,6 +113,8 @@ public class AutoCreateMealOrderTask {
.build();
mealOrderServiceRpcClient.batchCreateMealOrders(loginInfo, creations);
log.info("本周未订餐学生已自动补单 {} 条", creations.size());
// 标记本周已执行
weeklyTaskStore.markExecuted(keyPrefix, enterpriseId, today);
}
private MealOrderCreation toMealOrderCreation(SingleDinerRpcResponse diner,
......@@ -105,6 +142,11 @@ public class AutoCreateMealOrderTask {
.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)
.mapToObj(i -> MenuSchedule.newBuilder()
......
......@@ -26,7 +26,6 @@ import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
......@@ -170,8 +169,13 @@ public class MealOrderServiceImpl implements MealOrderService {
final var minDay = Collections.min(enabledDays);
final var maxDay = Collections.max(enabledDays);
final var today = now.toLocalDate();
final var startDateTime = today.with(TemporalAdjusters.previousOrSame(minDay)).atTime(startTime);
final var endDateTime = today.with(TemporalAdjusters.nextOrSame(maxDay)).atTime(endTime);
final var startDateTime = getThisWeekDate(today, minDay).atTime(startTime);
final var endDateTime = getThisWeekDate(today,maxDay).atTime(endTime);
return !now.isBefore(startDateTime) && !now.isAfter(endDateTime);
}
private static LocalDate getThisWeekDate(LocalDate now, DayOfWeek day) {
LocalDate monday = now.with(DayOfWeek.MONDAY);
return monday.plusDays(day.getValue() - 1L); // MONDAY 是 1,SUNDAY 是 7
}
}
......
package com.infoloop.tianting.store;
import io.lettuce.core.SetArgs;
import io.lettuce.core.api.sync.RedisCommands;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
public class WeeklyTaskStore {
private final RedisCommands<String, String> commands;
private final long expire; // 过期时间(秒)
public WeeklyTaskStore(final RedisCommands<String, String> commands, final long expire) {
this.commands = commands;
this.expire = expire;
}
public boolean isExecutedThisWeek(String keyPrefix, int enterpriseId, LocalDate date) {
String key = getWeeklyKey(keyPrefix, enterpriseId, date);
return commands.exists(key) > 0;
}
public void markExecuted(String keyPrefix, int enterpriseId, LocalDate date) {
String key = getWeeklyKey(keyPrefix, enterpriseId, date);
commands.set(key, "1", new SetArgs().ex(expire));
}
private String getWeeklyKey(String keyPrefix, int enterpriseId, LocalDate date) {
WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 1);
int year = date.getYear();
int week = date.get(weekFields.weekOfWeekBasedYear());
return String.format("%s:%d:%d-W%d", keyPrefix, enterpriseId, year, week);
}
}