jin.shuai

农信停餐

......@@ -6,10 +6,12 @@ import com.infoloop.tianting.mealorderservice.SingleMealOrderRpcResponse;
import com.infoloop.tianting.model.common.CreatedResult;
import com.infoloop.tianting.model.dto.MealOrderDTO;
import com.infoloop.tianting.model.vo.DeliveryRuleVO;
import com.infoloop.tianting.model.vo.DinerMealSuspensionRecordVO;
import com.infoloop.tianting.model.vo.MealOrderVO;
import com.infoloop.tianting.service.MealOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -20,6 +22,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
......@@ -67,4 +70,11 @@ public class MealOrderController {
return mealOrderService.getDeliveryRule();
}
@ApiOperation(value = "查询停餐信息")
@GetMapping("/dinermealsuspensionrecord")
@ResponseStatus(HttpStatus.OK)
public List<DinerMealSuspensionRecordVO> queryDinerMealSuspensionRecordsByCondition() {
return mealOrderService.queryDinerMealSuspensionRecordsByCondition();
}
}
......
......@@ -62,7 +62,9 @@ public enum ErrorCodeEnum implements BaseEnum {
MEAL_ORDER_TIME_NOT_IN_RANGE(406000022, "当前时间不在选餐时间内"),
DINER_NAME_STUDENT_NO_NOT_MISMATCH(406000023, "该就餐人学号和名称不匹配")
DINER_NAME_STUDENT_NO_NOT_MISMATCH(406000023, "该就餐人学号和名称不匹配"),
DINER_MEAL_SUSPENDED(406000024, "当前就餐人处于停餐状态")
;
......
......@@ -3,14 +3,7 @@ package com.infoloop.tianting.logic.task;
import com.infoloop.tianting.clientinventoryservice.SingleClientRpcResponse;
import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.enums.LoginSourceEnum;
import com.infoloop.tianting.mealorderservice.MealOrderCreation;
import com.infoloop.tianting.mealorderservice.MealOrderOrderMethodEnum;
import com.infoloop.tianting.mealorderservice.MenuSchedule;
import com.infoloop.tianting.mealorderservice.SingleDinerRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleGradeClassRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleMealMenuRecordRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleMealOrderRpcResponse;
import com.infoloop.tianting.mealorderservice.SingleMpAccountDinerRefRpcResponse;
import com.infoloop.tianting.mealorderservice.*;
import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient;
import com.infoloop.tianting.service.client.DeliveryRuleServiceRpcClient;
import com.infoloop.tianting.service.client.MealOrderServiceRpcClient;
......@@ -31,6 +24,7 @@ import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
......@@ -109,8 +103,82 @@ public class AutoCreateMealOrderTask {
final var clientMap = clientInventoryServiceRpcClient.getClientsByIds(enterpriseId, clientIds).getClientsList().stream().collect(Collectors.toMap(SingleClientRpcResponse::getId, Function.identity()));
final var gradeClassMap = mealOrderServiceRpcClient.getGradeClassesByIds(enterpriseId, classIds).stream().collect(Collectors.toMap(SingleGradeClassRpcResponse::getId, Function.identity()));
final var latestMealMenuRecordMap = mealOrderServiceRpcClient.queryLatestMealMenuRecordsByClientIds(enterpriseId, clientIds).stream().collect(Collectors.toMap(SingleMealMenuRecordRpcResponse::getClientId, Function.identity()));
// 批量查询学校级别的停餐信息
final var schoolSuspensionMap = new HashMap<Integer, SingleDinerMealSuspensionRecordRpcResponse>();
var schoolSuspensionRecords = mealOrderServiceRpcClient.queryDinerMealSuspensionRecordsByCondition(
enterpriseId,
clientIds, // 使用0表示查询所有
null,
null
);
if (schoolSuspensionRecords != null) {
var currentTime = System.currentTimeMillis();
schoolSuspensionRecords.stream()
.filter(record -> clientIds.contains(record.getClientId()))
.filter(record -> currentTime >= record.getStartAt() && currentTime <= record.getEndAt())
.collect(Collectors.groupingBy(
SingleDinerMealSuspensionRecordRpcResponse::getClientId,
Collectors.collectingAndThen(
Collectors.maxBy((a, b) -> Long.compare(a.getCreatedAt(), b.getCreatedAt())),
opt -> opt.orElse(null)
)
))
.forEach((clientId, record) -> {
if (record != null) {
schoolSuspensionMap.put(clientId, record);
}
});
}
// 批量查询学生级别的停餐信息
final var studentSuspensionMap = new HashMap<Integer, SingleDinerMealSuspensionRecordRpcResponse>();
var studentSuspensionRecords = mealOrderServiceRpcClient.queryDinerMealSuspensionRecordsByCondition(
enterpriseId,
null, // 使用0表示查询所有
null,
notReservedDiners.stream().map(SingleDinerRpcResponse::getId).toList()
);
if (studentSuspensionRecords != null) {
var currentTime = System.currentTimeMillis();
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())
.collect(Collectors.groupingBy(
SingleDinerMealSuspensionRecordRpcResponse::getDinerId,
Collectors.collectingAndThen(
Collectors.maxBy((a, b) -> Long.compare(a.getCreatedAt(), b.getCreatedAt())),
opt -> opt.orElse(null)
)
))
.forEach((dinerId, record) -> {
if (record != null) {
studentSuspensionMap.put(dinerId, record);
}
});
}
// 构建创建请求
final var creations = notReservedDiners.stream().map(diner -> toMealOrderCreation(diner, clientMap, gradeClassMap, latestMealMenuRecordMap, mpAccountDinerRefMap, nextWeekStart)).filter(Objects::nonNull).toList();
final var creations = notReservedDiners.stream()
.map(diner -> toMealOrderCreation(
diner,
clientMap,
gradeClassMap,
latestMealMenuRecordMap,
mpAccountDinerRefMap,
nextWeekStart,
schoolSuspensionMap,
studentSuspensionMap
))
.filter(Objects::nonNull)
.toList();
if (creations.isEmpty()) {
return;
}
......@@ -132,12 +200,27 @@ public class AutoCreateMealOrderTask {
Map<Integer, SingleGradeClassRpcResponse> classMap,
Map<Integer, SingleMealMenuRecordRpcResponse> menuMap,
Map<Integer, SingleMpAccountDinerRefRpcResponse> mpAccountDinerRefMap,
ZonedDateTime startOfNextWeek) {
ZonedDateTime startOfNextWeek,
Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> schoolSuspensionMap,
Map<Integer, SingleDinerMealSuspensionRecordRpcResponse> studentSuspensionMap) {
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;
}
// 检查学生级别的停餐信息
if (studentSuspensionMap.containsKey(diner.getId())) {
log.info("学生 {} 当前处于停餐状态,跳过自动订餐", diner.getName());
return null;
}
return MealOrderCreation.newBuilder()
.setClientId(diner.getClientId())
.setMenuId(menu.getId())
......
package com.infoloop.tianting.model.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
@ApiModel("停餐记录VO")
public class DinerMealSuspensionRecordVO {
@ApiModelProperty("ID")
private Long id;
@ApiModelProperty("企业ID")
private Long enterpriseId;
@ApiModelProperty("客户ID")
private Long clientId;
@ApiModelProperty("班级ID")
private Long classId;
@ApiModelProperty("年级名称")
private String gradeName;
@ApiModelProperty("班级名称")
private String className;
@ApiModelProperty("用餐人ID")
private Long dinerId;
@ApiModelProperty("用餐人姓名")
private String dinerName;
@ApiModelProperty("学号")
private String studentNo;
@ApiModelProperty("开始时间")
private Date startAt;
@ApiModelProperty("结束时间")
private Date endAt;
@ApiModelProperty("备注")
private String comment;
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import com.infoloop.tianting.mealorderservice.SingleMealOrderRpcResponse;
import com.infoloop.tianting.model.common.CreatedResult;
import com.infoloop.tianting.model.dto.MealOrderDTO;
import com.infoloop.tianting.model.vo.DeliveryRuleVO;
import com.infoloop.tianting.model.vo.DinerMealSuspensionRecordVO;
import com.infoloop.tianting.model.vo.MealOrderVO;
import java.util.List;
......@@ -17,4 +18,16 @@ public interface MealOrderService {
MealOrderVO getMealOrderById(SingleMealOrderRpcResponse mealOrder);
DeliveryRuleVO getDeliveryRule();
/**
* 查询停餐信息
* 先查询学校的停餐信息,再查询学生的停餐信息,学校的停餐信息优先级高于学生停餐信息
*
* @param enterpriseId 企业ID
* @param clientId 客户ID
* @param classId 班级ID
* @param dinerId 用餐人ID
* @return 停餐信息列表
*/
List<DinerMealSuspensionRecordVO> queryDinerMealSuspensionRecordsByCondition();
}
......
......@@ -47,6 +47,8 @@ import com.infoloop.tianting.mealorderservice.UpdateDinerRpcRequest;
import com.infoloop.tianting.mealorderservice.UpdateDinerRpcResponse;
import com.infoloop.tianting.mealorderservice.UpdateMpAccountRpcRequest;
import com.infoloop.tianting.mealorderservice.UpdateMpAccountRpcResponse;
import com.infoloop.tianting.mealorderservice.QueryDinerMealSuspensionRecordsByConditionRpcRequest;
import com.infoloop.tianting.mealorderservice.SingleDinerMealSuspensionRecordRpcResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -274,4 +276,30 @@ public class MealOrderServiceRpcClient {
.setShouldFilterReserveDateEnd(reserveDateEnd != null).setReserveDateEnd(reserveDateEnd == null ? 0 : reserveDateEnd)
.build()).getResponsesList();
}
public List<SingleDinerMealSuspensionRecordRpcResponse> queryDinerMealSuspensionRecordsByCondition(
int enterpriseId,
@Nullable List<Integer> clientIds,
@Nullable List<Integer> classIds,
@Nullable List<Integer> dinerIds) {
var request = QueryDinerMealSuspensionRecordsByConditionRpcRequest.newBuilder()
.setEnterpriseId(enterpriseId);
if (clientIds != null) {
request.setShouldFilterClientIds(true)
.addAllClientIds(clientIds);
}
if (classIds != null) {
request.setShouldFilterClassIds(true)
.addAllClassIds(classIds);
}
if (dinerIds != null) {
request.setShouldFilterDinerIds(true)
.addAllDinerIds(dinerIds);
}
return mealOrderServiceRpcBlockingStub.queryDinerMealSuspensionRecordsByCondition(request.build())
.getResponsesList();
}
}
......
......@@ -31,6 +31,7 @@ service MealOrderServiceRpc {
rpc UpdateDiner (UpdateDinerRpcRequest) returns (UpdateDinerRpcResponse) {}
rpc BatchSaveOrUpdateDiners (BatchSaveOrUpdateDinersRpcRequest) returns (BatchSaveOrUpdateDinersRpcResponse) {}
rpc DeleteDinersByIds (DeleteDinersByIdsRpcRequest) returns (DeleteDinersRpcResponse) {}
rpc DeleteGraduationDinersByClassIds (DeleteGraduationDinersByClassIdsRpcRequest) returns (DeleteGraduationDinersByClassIdsRpcResponse) {}
rpc GetMpAccountDinerRefsByIds (GetMpAccountDinerRefsByIdsRpcRequest) returns (GetMpAccountDinerRefsByIdsRpcResponse) {}
rpc QueryMpAccountDinerRefsByCondition (QueryMpAccountDinerRefsByConditionRpcRequest) returns (QueryMpAccountDinerRefsByConditionRpcResponse) {}
......@@ -46,12 +47,22 @@ service MealOrderServiceRpc {
rpc BatchSaveOrUpdateGradeClasses (BatchSaveOrUpdateGradeClassesRpcRequest) returns (BatchSaveOrUpdateGradeClassesRpcResponse) {}
rpc DeleteGradeClassesByIds (DeleteGradeClassesByIdsRpcRequest) returns (DeleteGradeClassesRpcResponse) {}
rpc DeleteGradeClassesAndDinersByClientIds (DeleteGradeClassesAndDinersByClientIdsRpcRequest) returns (DeleteGradeClassesAndDinersByClientIdsRpcResponse) {}
rpc DeleteGradeClassesAndDinersByClassIds (DeleteGradeClassesAndDinersByClassIdsRpcRequest) returns (DeleteGradeClassesAndDinersByClassIdsRpcResponse) {}
rpc GetMealMenuRecordById (GetMealMenuRecordByIdRpcRequest) returns (GetMealMenuRecordByIdRpcResponse) {}
rpc GetMealMenuRecordsByIds (GetMealMenuRecordsByIdsRpcRequest) returns (GetMealMenuRecordsByIdsRpcResponse) {}
rpc QueryMealMenuRecordsByCondition (QueryMealMenuRecordsByConditionRpcRequest) returns (QueryMealMenuRecordsByConditionRpcResponse) {}
rpc CreateMealMenuRecord (CreateMealMenuRecordRpcRequest) returns (CreateMealMenuRecordRpcResponse) {}
rpc QueryLatestMealMenuRecordsByClientIds (QueryLatestMealMenuRecordsByClientIdsRpcRequest) returns (QueryLatestMealMenuRecordsByClientIdsRpcResponse) {}
// 停餐记录相关服务
rpc getDinerMealSuspensionRecordById(GetDinerMealSuspensionRecordByIdRpcRequest) returns (GetDinerMealSuspensionRecordByIdRpcResponse);
rpc getDinerMealSuspensionRecordsByIds(GetDinerMealSuspensionRecordsByIdsRpcRequest) returns (GetDinerMealSuspensionRecordsByIdsRpcResponse);
rpc queryDinerMealSuspensionRecordsByCondition(QueryDinerMealSuspensionRecordsByConditionRpcRequest) returns (QueryDinerMealSuspensionRecordsByConditionRpcResponse);
rpc createDinerMealSuspensionRecord(CreateDinerMealSuspensionRecordRpcRequest) returns (CreateDinerMealSuspensionRecordRpcResponse);
rpc batchCreateDinerMealSuspensionRecords(BatchCreateDinerMealSuspensionRecordsRpcRequest) returns (BatchCreateDinerMealSuspensionRecordsRpcResponse);
rpc updateDinerMealSuspensionRecord(UpdateDinerMealSuspensionRecordRpcRequest) returns (UpdateDinerMealSuspensionRecordRpcResponse);
rpc deleteDinerMealSuspensionRecordsByIds(DeleteDinerMealSuspensionRecordsByIdsRpcRequest) returns (DeleteDinerMealSuspensionRecordsRpcResponse);
}
enum MealOrderOrderMethodEnum {
......@@ -357,6 +368,17 @@ message DeleteDinersRpcResponse {
bool isDeleted = 1;
}
message DeleteGraduationDinersByClassIdsRpcRequest {
repeated int32 classIds = 1;
int32 enterpriseId = 2;
int32 updatedBy = 3;
int32 updateSource = 4;
}
message DeleteGraduationDinersByClassIdsRpcResponse {
bool isDeleted = 1;
}
enum MpAccountGenderEnum {
MP_ACCOUNT_GENDER_MAN = 0;
MP_ACCOUNT_GENDER_WOMAN = 1;
......@@ -613,8 +635,8 @@ message QueryGradeClassesByConditionRpcRequest {
int32 enterpriseId = 1;
bool shouldFilterClientIds = 2;
repeated int32 clientIds = 3;
bool shouldFilterGradeName = 4;
string gradeName = 5;
bool shouldFilterGradeNames = 4;
repeated string gradeName = 5;
bool includeDeleted = 6;
}
......@@ -721,6 +743,18 @@ message DeleteGradeClassesAndDinersByClientIdsRpcResponse {
bool isDeleted = 1;
}
message DeleteGradeClassesAndDinersByClassIdsRpcRequest {
repeated int32 classIds = 1;
int32 enterpriseId = 2;
int32 updatedBy = 3;
int32 updateSource = 4;
}
message DeleteGradeClassesAndDinersByClassIdsRpcResponse {
bool isDeleted = 1;
}
message SingleMealMenuRecordRpcResponse {
int32 id = 1;
int32 enterpriseId = 2;
......@@ -734,6 +768,7 @@ message SingleMealMenuRecordRpcResponse {
int64 updatedAt = 10;
int32 updateSource = 11;
bool isDeleted = 12;
string operatorName = 13;
}
message GetMealMenuRecordByIdRpcRequest {
......@@ -781,6 +816,7 @@ message CreateMealMenuRecordRpcRequest {
int32 enterpriseId = 2;
int32 createdBy = 3;
int32 creationSource = 4;
string operatorName = 5;
}
message CreateMealMenuRecordRpcResponse {
......@@ -796,3 +832,126 @@ message QueryLatestMealMenuRecordsByClientIdsRpcRequest {
message QueryLatestMealMenuRecordsByClientIdsRpcResponse {
repeated SingleMealMenuRecordRpcResponse responses = 1;
}
// 停餐记录相关消息定义
message SingleDinerMealSuspensionRecordRpcResponse {
int32 id = 1;
int32 enterpriseId = 2;
int32 clientId = 3;
int32 classId = 4;
int32 dinerId = 5;
int64 startAt = 6;
int64 endAt = 7;
string comment = 8;
int64 createdAt = 9;
int32 createdBy = 10;
int32 creationSource = 11;
int64 updatedAt = 12;
int32 updatedBy = 13;
int32 updateSource = 14;
}
message GetDinerMealSuspensionRecordByIdRpcRequest {
int64 id = 1;
}
message GetDinerMealSuspensionRecordByIdRpcResponse {
SingleDinerMealSuspensionRecordRpcResponse response = 1;
}
message GetDinerMealSuspensionRecordsByIdsRpcRequest {
repeated int32 ids = 1;
}
message GetDinerMealSuspensionRecordsByIdsRpcResponse {
repeated SingleDinerMealSuspensionRecordRpcResponse responses = 1;
}
message QueryDinerMealSuspensionRecordsByConditionRpcRequest {
int32 enterpriseId = 1;
bool shouldFilterClientIds = 2;
repeated int32 clientIds = 3;
bool shouldFilterClassIds = 4;
repeated int32 classIds = 5;
bool shouldFilterDinerIds = 6;
repeated int32 dinerIds = 7;
bool shouldFilterStartAt = 8;
int64 startAt = 9;
bool shouldFilterEndAt = 10;
int64 endAt = 11;
}
message QueryDinerMealSuspensionRecordsByConditionRpcResponse {
repeated SingleDinerMealSuspensionRecordRpcResponse responses = 1;
}
message CreateDinerMealSuspensionRecordRpcRequest {
int32 enterpriseId = 1;
int32 createdBy = 2;
int32 creationSource = 3;
DinerMealSuspensionRecordCreation creation = 4;
}
message DinerMealSuspensionRecordCreation {
int32 clientId = 1;
int32 classId = 2;
int32 dinerId = 3;
int64 startAt = 4;
int64 endAt = 5;
string comment = 6;
}
message CreateDinerMealSuspensionRecordRpcResponse {
bool isCreated = 1;
int32 id = 2;
}
message UpdateDinerMealSuspensionRecordRpcRequest {
int32 enterpriseId = 1;
int32 updatedBy = 2;
int32 updateSource = 3;
DinerMealSuspensionRecordModification modification = 4;
}
message DinerMealSuspensionRecordModification {
int32 id = 1;
bool shouldUpdateClientId = 2;
int32 clientId = 3;
bool shouldUpdateClassId = 4;
int32 classId = 5;
bool shouldUpdateDinerId = 6;
int32 dinerId = 7;
bool shouldUpdateStartAt = 8;
int64 startAt = 9;
bool shouldUpdateEndAt = 10;
int64 endAt = 11;
bool shouldUpdateComment = 12;
string comment = 13;
}
message UpdateDinerMealSuspensionRecordRpcResponse {
bool isUpdated = 1;
}
message DeleteDinerMealSuspensionRecordsByIdsRpcRequest {
repeated int32 ids = 1;
int32 enterpriseId = 2;
int32 updatedBy = 3;
int32 updateSource = 4;
}
message DeleteDinerMealSuspensionRecordsRpcResponse {
bool isDeleted = 1;
}
message BatchCreateDinerMealSuspensionRecordsRpcRequest {
int32 enterpriseId = 1;
int32 createdBy = 2;
int32 creationSource = 3;
repeated DinerMealSuspensionRecordCreation creations = 4;
}
message BatchCreateDinerMealSuspensionRecordsRpcResponse {
bool isCreated = 1;
repeated int32 ids = 2;
}
......