Jiaqi Xia

Merge branch 'feature/nongxinweixinnotice' into 'master'

Feature/nongxinweixinnotice



See merge request !7
1 +package com.tianting.infoloop.mapper;
2 +
3 +import com.tianting.infoloop.inject.MyBaseMapper;
4 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
5 +import org.apache.ibatis.annotations.Delete;
6 +import org.apache.ibatis.annotations.Param;
7 +
8 +import java.util.List;
9 +
10 +public interface OrderSubscriptionMessageMapper extends MyBaseMapper<OrderSubscriptionMessageDb> {
11 +
12 + /**
13 + * 批量物理删除(绕过逻辑删除)
14 + */
15 + @Delete("<script>" +
16 + "DELETE FROM order_subscription_message " +
17 + "WHERE enterpriseId = #{enterpriseId} " +
18 + "AND id IN " +
19 + "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
20 + "#{id}" +
21 + "</foreach>" +
22 + "</script>")
23 + int physicalDeleteByIds(@Param("ids") List<Long> ids, @Param("enterpriseId") int enterpriseId);
24 +}
25 +
1 +package com.tianting.infoloop.model.db;
2 +
3 +import com.baomidou.mybatisplus.annotation.FieldFill;
4 +import com.baomidou.mybatisplus.annotation.IdType;
5 +import com.baomidou.mybatisplus.annotation.TableField;
6 +import com.baomidou.mybatisplus.annotation.TableId;
7 +import com.baomidou.mybatisplus.annotation.TableLogic;
8 +import com.baomidou.mybatisplus.annotation.TableName;
9 +import com.baomidou.mybatisplus.extension.activerecord.Model;
10 +import lombok.Data;
11 +import lombok.EqualsAndHashCode;
12 +import lombok.experimental.Accessors;
13 +
14 +import java.time.LocalDateTime;
15 +
16 +/**
17 + * order subscription message DB
18 + * @TableName order_subscription_message
19 + */
20 +@Data
21 +@Accessors(chain = true)
22 +@EqualsAndHashCode(callSuper = true)
23 +@TableName(value = "meal_order_subscription_messages")
24 +public class OrderSubscriptionMessageDb extends Model<OrderSubscriptionMessageDb> {
25 + /**
26 + * 主键ID
27 + */
28 + @TableId(type = IdType.AUTO)
29 + private Long id;
30 + /**
31 + * 企业ID
32 + */
33 + private Integer enterpriseId;
34 + /**
35 + * 订餐用户ID(dinerId)
36 + */
37 + private Integer dinerId;
38 + /**
39 + * 微信用户OpenID
40 + */
41 + private String openId;
42 + /**
43 + * 订阅消息模板ID
44 + */
45 + private String templateId;
46 + /**
47 + * 跳转路径(小程序 path)
48 + */
49 + private String jumpPath;
50 + /**
51 + * 关联的订餐周期开始时间(精确到秒)
52 + */
53 + private LocalDateTime orderPeriodStartDate;
54 + /**
55 + * 关联的订餐周期结束时间(精确到秒)
56 + */
57 + private LocalDateTime orderPeriodEndDate;
58 + /**
59 + * 授权时间(创建时间)
60 + */
61 + @TableField(fill = FieldFill.INSERT)
62 + private LocalDateTime createdAt;
63 + /**
64 + * 更新时间
65 + */
66 + @TableField(fill = FieldFill.INSERT_UPDATE)
67 + private LocalDateTime updatedAt;
68 + /**
69 + * 授权状态,0-待使用(已授权但未发送),1-已使用(已发送,逻辑删除)
70 + */
71 + @TableLogic
72 + private Boolean isDeleted;
73 +}
74 +
1 +package com.tianting.infoloop.service;
2 +
3 +import com.baomidou.mybatisplus.extension.service.IService;
4 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcRequest;
5 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
6 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
7 +
8 +import java.util.List;
9 +
10 +public interface OrderSubscriptionMessageDbService extends IService<OrderSubscriptionMessageDb> {
11 +
12 + OrderSubscriptionMessageDb createOrderSubscriptionMessage(CreateOrderSubscriptionMessageRpcRequest request);
13 +
14 + List<OrderSubscriptionMessageDb> getUserOrderSubscriptionMessageHistory(GetUserOrderSubscriptionMessageHistoryRpcRequest request);
15 +
16 + /**
17 + * 批量逻辑删除授权记录(表示已使用)
18 + * @param ids 要删除的记录ID列表
19 + * @param enterpriseId 企业ID
20 + * @return 受影响的行数
21 + */
22 + int batchDeleteByIds(java.util.List<Long> ids, int enterpriseId);
23 +
24 + /**
25 + * 批量物理删除授权记录
26 + * @param ids 要删除的记录ID列表
27 + * @param enterpriseId 企业ID
28 + * @return 受影响的行数
29 + */
30 + int batchPhysicalDeleteByIds(java.util.List<Long> ids, int enterpriseId);
31 +
32 + /**
33 + * 查询待发送的订阅消息(未删除的记录)
34 + * @param enterpriseId 企业ID
35 + * @return 待发送的订阅消息列表
36 + */
37 + List<OrderSubscriptionMessageDb> queryPendingMessages(int enterpriseId);
38 +}
39 +
...@@ -7,6 +7,18 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; ...@@ -7,6 +7,18 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
7 import com.infoloop.tianting.mealorderservice.BatchCreateDinerMealSuspensionRecordsRpcRequest; 7 import com.infoloop.tianting.mealorderservice.BatchCreateDinerMealSuspensionRecordsRpcRequest;
8 import com.infoloop.tianting.mealorderservice.BatchCreateDinerMealSuspensionRecordsRpcResponse; 8 import com.infoloop.tianting.mealorderservice.BatchCreateDinerMealSuspensionRecordsRpcResponse;
9 import com.infoloop.tianting.mealorderservice.BatchCreateGradeClassesRpcRequest; 9 import com.infoloop.tianting.mealorderservice.BatchCreateGradeClassesRpcRequest;
10 +import com.infoloop.tianting.mealorderservice.BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest;
11 +import com.infoloop.tianting.mealorderservice.BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse;
12 +import com.infoloop.tianting.mealorderservice.BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest;
13 +import com.infoloop.tianting.mealorderservice.BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse;
14 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcRequest;
15 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcResponse;
16 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
17 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcResponse;
18 +import com.infoloop.tianting.mealorderservice.OrderSubscriptionMessageRpcResponse;
19 +import com.infoloop.tianting.mealorderservice.PendingOrderSubscriptionMessageRpcResponse;
20 +import com.infoloop.tianting.mealorderservice.QueryPendingOrderSubscriptionMessagesRpcRequest;
21 +import com.infoloop.tianting.mealorderservice.QueryPendingOrderSubscriptionMessagesRpcResponse;
10 import com.infoloop.tianting.mealorderservice.BatchCreateGradeClassesRpcResponse; 22 import com.infoloop.tianting.mealorderservice.BatchCreateGradeClassesRpcResponse;
11 import com.infoloop.tianting.mealorderservice.BatchCreateMealOrdersRpcRequest; 23 import com.infoloop.tianting.mealorderservice.BatchCreateMealOrdersRpcRequest;
12 import com.infoloop.tianting.mealorderservice.BatchCreateMealOrdersRpcResponse; 24 import com.infoloop.tianting.mealorderservice.BatchCreateMealOrdersRpcResponse;
...@@ -124,6 +136,8 @@ import com.tianting.infoloop.service.MealOrderService; ...@@ -124,6 +136,8 @@ import com.tianting.infoloop.service.MealOrderService;
124 import com.tianting.infoloop.service.MpAccountDinerRefService; 136 import com.tianting.infoloop.service.MpAccountDinerRefService;
125 import com.tianting.infoloop.service.MpAccountService; 137 import com.tianting.infoloop.service.MpAccountService;
126 import com.tianting.infoloop.service.DinerMealSuspensionRecordService; 138 import com.tianting.infoloop.service.DinerMealSuspensionRecordService;
139 +import com.tianting.infoloop.service.OrderSubscriptionMessageDbService;
140 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
127 import com.tianting.infoloop.utils.ProtoBeanUtil; 141 import com.tianting.infoloop.utils.ProtoBeanUtil;
128 import io.grpc.Status; 142 import io.grpc.Status;
129 import io.grpc.stub.StreamObserver; 143 import io.grpc.stub.StreamObserver;
...@@ -134,10 +148,10 @@ import org.springframework.stereotype.Service; ...@@ -134,10 +148,10 @@ import org.springframework.stereotype.Service;
134 import org.springframework.transaction.annotation.Transactional; 148 import org.springframework.transaction.annotation.Transactional;
135 149
136 import java.time.DayOfWeek; 150 import java.time.DayOfWeek;
137 -import java.time.Instant;
138 import java.time.LocalDate; 151 import java.time.LocalDate;
139 import java.time.LocalDateTime; 152 import java.time.LocalDateTime;
140 import java.time.LocalTime; 153 import java.time.LocalTime;
154 +import java.time.ZoneId;
141 import java.time.temporal.TemporalAdjusters; 155 import java.time.temporal.TemporalAdjusters;
142 import java.util.ArrayList; 156 import java.util.ArrayList;
143 import java.util.Collections; 157 import java.util.Collections;
...@@ -167,6 +181,8 @@ public class MealOrderGrpcService extends MealOrderServiceRpcGrpc.MealOrderServi ...@@ -167,6 +181,8 @@ public class MealOrderGrpcService extends MealOrderServiceRpcGrpc.MealOrderServi
167 181
168 private final DinerMealSuspensionRecordService dinerMealSuspensionRecordService; 182 private final DinerMealSuspensionRecordService dinerMealSuspensionRecordService;
169 183
184 + private final OrderSubscriptionMessageDbService orderSubscriptionMessageDbService;
185 +
170 @Override 186 @Override
171 @DS(DATA_SOURCE_SLAVE) 187 @DS(DATA_SOURCE_SLAVE)
172 public void getMealOrderById(final GetMealOrderByIdRpcRequest request, 188 public void getMealOrderById(final GetMealOrderByIdRpcRequest request,
...@@ -1417,4 +1433,149 @@ public class MealOrderGrpcService extends MealOrderServiceRpcGrpc.MealOrderServi ...@@ -1417,4 +1433,149 @@ public class MealOrderGrpcService extends MealOrderServiceRpcGrpc.MealOrderServi
1417 responseObserver.onNext(builder.build()); 1433 responseObserver.onNext(builder.build());
1418 responseObserver.onCompleted(); 1434 responseObserver.onCompleted();
1419 } 1435 }
1436 +
1437 + // 订餐订阅消息相关服务实现
1438 + @Override
1439 + @DS(DATA_SOURCE_MASTER)
1440 + public void createOrderSubscriptionMessage(final CreateOrderSubscriptionMessageRpcRequest request,
1441 + final StreamObserver<CreateOrderSubscriptionMessageRpcResponse> responseObserver) {
1442 + final var builder = CreateOrderSubscriptionMessageRpcResponse.newBuilder();
1443 + try {
1444 + final var data = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(request);
1445 + builder.setId(data.getId());
1446 + } catch (final Exception e) {
1447 + log.error("createOrderSubscriptionMessage error;", e);
1448 + responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
1449 + return;
1450 + }
1451 + responseObserver.onNext(builder.build());
1452 + responseObserver.onCompleted();
1453 + }
1454 +
1455 + @Override
1456 + @DS(DATA_SOURCE_MASTER)
1457 + public void getUserOrderSubscriptionMessageHistory(final GetUserOrderSubscriptionMessageHistoryRpcRequest request,
1458 + final StreamObserver<GetUserOrderSubscriptionMessageHistoryRpcResponse> responseObserver) {
1459 + final var builder = GetUserOrderSubscriptionMessageHistoryRpcResponse.newBuilder();
1460 + try {
1461 + final var list = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(request);
1462 + builder.addAllResponse(list.stream()
1463 + .map(this::convertToRpcResponse)
1464 + .collect(Collectors.toList()));
1465 + } catch (final Exception e) {
1466 + log.error("getUserOrderSubscriptionMessageHistory error;", e);
1467 + responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
1468 + return;
1469 + }
1470 + responseObserver.onNext(builder.build());
1471 + responseObserver.onCompleted();
1472 + }
1473 +
1474 + private OrderSubscriptionMessageRpcResponse convertToRpcResponse(OrderSubscriptionMessageDb db) {
1475 + OrderSubscriptionMessageRpcResponse.Builder builder = OrderSubscriptionMessageRpcResponse.newBuilder();
1476 + builder.setId(db.getId());
1477 +
1478 + if (db.getJumpPath() != null) {
1479 + builder.setJumpPath(db.getJumpPath());
1480 + }
1481 +
1482 + // 转换LocalDateTime为时间戳(毫秒),与项目中其他时间字段保持一致
1483 + if (db.getOrderPeriodStartDate() != null) {
1484 + long timestamp = db.getOrderPeriodStartDate().atZone(ZoneId.systemDefault())
1485 + .toInstant()
1486 + .toEpochMilli();
1487 + builder.setOrderPeriodStartDate(timestamp);
1488 + }
1489 +
1490 + if (db.getOrderPeriodEndDate() != null) {
1491 + long timestamp = db.getOrderPeriodEndDate().atZone(ZoneId.systemDefault())
1492 + .toInstant()
1493 + .toEpochMilli();
1494 + builder.setOrderPeriodEndDate(timestamp);
1495 + }
1496 +
1497 + // 转换LocalDateTime为时间戳(毫秒)
1498 + if (db.getCreatedAt() != null) {
1499 + long timestamp = db.getCreatedAt().atZone(ZoneId.systemDefault())
1500 + .toInstant()
1501 + .toEpochMilli();
1502 + builder.setCreatedAt(timestamp);
1503 + }
1504 +
1505 + builder.setIsDeleted(db.getIsDeleted() != null && db.getIsDeleted());
1506 + return builder.build();
1507 + }
1508 +
1509 + @Override
1510 + @DS(DATA_SOURCE_MASTER)
1511 + public void batchDeleteOrderSubscriptionMessagesByIds(final BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest request,
1512 + final StreamObserver<BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse> responseObserver) {
1513 + final var builder = BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse.newBuilder();
1514 + try {
1515 + final int affectedRows = orderSubscriptionMessageDbService.batchDeleteByIds(
1516 + request.getIdsList(),
1517 + request.getEnterpriseId());
1518 + builder.setAffectedRows(affectedRows);
1519 + } catch (final Exception e) {
1520 + log.error("batchDeleteOrderSubscriptionMessagesByIds error;", e);
1521 + responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
1522 + return;
1523 + }
1524 + responseObserver.onNext(builder.build());
1525 + responseObserver.onCompleted();
1526 + }
1527 +
1528 + @Override
1529 + @DS(DATA_SOURCE_MASTER)
1530 + public void batchPhysicalDeleteOrderSubscriptionMessagesByIds(
1531 + final BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest request,
1532 + final StreamObserver<BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse> responseObserver) {
1533 + final var builder = BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse.newBuilder();
1534 + try {
1535 + final int affectedRows = orderSubscriptionMessageDbService.batchPhysicalDeleteByIds(
1536 + request.getIdsList(),
1537 + request.getEnterpriseId());
1538 + builder.setAffectedRows(affectedRows);
1539 + } catch (final Exception e) {
1540 + log.error("batchPhysicalDeleteOrderSubscriptionMessagesByIds error;", e);
1541 + responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
1542 + return;
1543 + }
1544 + responseObserver.onNext(builder.build());
1545 + responseObserver.onCompleted();
1546 + }
1547 +
1548 + @Override
1549 + @DS(DATA_SOURCE_SLAVE)
1550 + public void queryPendingOrderSubscriptionMessages(
1551 + final QueryPendingOrderSubscriptionMessagesRpcRequest request,
1552 + final StreamObserver<QueryPendingOrderSubscriptionMessagesRpcResponse> responseObserver) {
1553 + final var builder = QueryPendingOrderSubscriptionMessagesRpcResponse.newBuilder();
1554 + try {
1555 + final var messages = orderSubscriptionMessageDbService.queryPendingMessages(
1556 + request.getEnterpriseId());
1557 + for (final var message : messages) {
1558 + builder.addResponses(PendingOrderSubscriptionMessageRpcResponse.newBuilder()
1559 + .setId(message.getId())
1560 + .setEnterpriseId(message.getEnterpriseId())
1561 + .setDinerId(message.getDinerId() != null ? message.getDinerId() : 0)
1562 + .setOpenId(message.getOpenId())
1563 + .setTemplateId(message.getTemplateId() != null ? message.getTemplateId() : "")
1564 + .setOrderPeriodStartDate(message.getOrderPeriodStartDate() != null ?
1565 + message.getOrderPeriodStartDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : 0)
1566 + .setJumpPath(message.getJumpPath() != null ? message.getJumpPath() : "")
1567 + .setOrderPeriodEndDate(message.getOrderPeriodEndDate() != null ?
1568 + message.getOrderPeriodEndDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : 0)
1569 + .setCreatedAt(message.getCreatedAt() != null ?
1570 + message.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : 0)
1571 + .build());
1572 + }
1573 + } catch (final Exception e) {
1574 + log.error("queryPendingOrderSubscriptionMessages error;", e);
1575 + responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
1576 + return;
1577 + }
1578 + responseObserver.onNext(builder.build());
1579 + responseObserver.onCompleted();
1580 + }
1420 } 1581 }
......
1 +package com.tianting.infoloop.service.impl;
2 +
3 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
5 +import com.infoloop.tianting.mealorderservice.CreateOrderSubscriptionMessageRpcRequest;
6 +import com.infoloop.tianting.mealorderservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
7 +import com.tianting.infoloop.mapper.OrderSubscriptionMessageMapper;
8 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
9 +import com.tianting.infoloop.service.OrderSubscriptionMessageDbService;
10 +import com.tianting.infoloop.utils.exception.ErrorCodeConstants;
11 +import com.tianting.infoloop.utils.exception.ServiceExceptionUtil;
12 +import lombok.RequiredArgsConstructor;
13 +import lombok.extern.slf4j.Slf4j;
14 +import org.springframework.beans.factory.annotation.Autowired;
15 +import org.springframework.stereotype.Service;
16 +
17 +import java.time.Instant;
18 +import java.time.LocalDateTime;
19 +import java.time.ZoneId;
20 +import java.util.List;
21 +
22 +@Slf4j
23 +@Service
24 +@RequiredArgsConstructor(onConstructor_ = @Autowired)
25 +public class OrderSubscriptionMessageDbServiceImpl extends ServiceImpl<OrderSubscriptionMessageMapper, OrderSubscriptionMessageDb> implements OrderSubscriptionMessageDbService {
26 +
27 + @Override
28 + public OrderSubscriptionMessageDb createOrderSubscriptionMessage(CreateOrderSubscriptionMessageRpcRequest request) {
29 + OrderSubscriptionMessageDb orderSubscriptionMessageDb = new OrderSubscriptionMessageDb();
30 + orderSubscriptionMessageDb.setEnterpriseId(request.getEnterpriseId());
31 + if (request.getDinerId() != 0) {
32 + orderSubscriptionMessageDb.setDinerId(request.getDinerId());
33 + }
34 + orderSubscriptionMessageDb.setOpenId(request.getOpenId());
35 + orderSubscriptionMessageDb.setTemplateId(request.getTemplateId());
36 + if (!request.getJumpPath().isEmpty()) {
37 + orderSubscriptionMessageDb.setJumpPath(request.getJumpPath());
38 + }
39 +
40 + // 转换时间戳为LocalDateTime(精确到秒),与项目中其他时间字段保持一致
41 + LocalDateTime orderPeriodStartDate = Instant.ofEpochMilli(request.getOrderPeriodStartDate())
42 + .atZone(ZoneId.systemDefault())
43 + .toLocalDateTime();
44 + orderSubscriptionMessageDb.setOrderPeriodStartDate(orderPeriodStartDate);
45 +
46 + if (request.getOrderPeriodEndDate() > 0) {
47 + LocalDateTime orderPeriodEndDate = Instant.ofEpochMilli(request.getOrderPeriodEndDate())
48 + .atZone(ZoneId.systemDefault())
49 + .toLocalDateTime();
50 + orderSubscriptionMessageDb.setOrderPeriodEndDate(orderPeriodEndDate);
51 + }
52 +
53 + boolean res = this.save(orderSubscriptionMessageDb);
54 + if (!res) {
55 + log.error("创建订阅消息授权记录失败, request: {}", request);
56 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_GEN_FAIL);
57 + }
58 + return orderSubscriptionMessageDb;
59 + }
60 +
61 + @Override
62 + public List<OrderSubscriptionMessageDb> getUserOrderSubscriptionMessageHistory(GetUserOrderSubscriptionMessageHistoryRpcRequest request) {
63 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
64 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, request.getEnterpriseId());
65 + queryWrapper.eq(OrderSubscriptionMessageDb::getOpenId, request.getOpenId());
66 +
67 + // 如果传入了 orderPeriodStartDate,查询大于等于该值的记录
68 + if (request.getOrderPeriodStartDate() > 0) {
69 + LocalDateTime orderPeriodStartDate = Instant.ofEpochMilli(request.getOrderPeriodStartDate())
70 + .atZone(ZoneId.systemDefault())
71 + .toLocalDateTime();
72 + queryWrapper.ge(OrderSubscriptionMessageDb::getOrderPeriodStartDate, orderPeriodStartDate);
73 + }
74 +
75 + queryWrapper.orderByDesc(OrderSubscriptionMessageDb::getCreatedAt);
76 + return this.list(queryWrapper);
77 + }
78 +
79 + @Override
80 + public int batchDeleteByIds(java.util.List<Long> ids, int enterpriseId) {
81 + if (ids == null || ids.isEmpty()) {
82 + return 0;
83 + }
84 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
85 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, enterpriseId);
86 + queryWrapper.in(OrderSubscriptionMessageDb::getId, ids);
87 + // 逻辑删除(使用 MyBatis-Plus 的 @TableLogic)
88 + return this.remove(queryWrapper) ? ids.size() : 0;
89 + }
90 +
91 + @Override
92 + public int batchPhysicalDeleteByIds(java.util.List<Long> ids, int enterpriseId) {
93 + if (ids == null || ids.isEmpty()) {
94 + return 0;
95 + }
96 + // 物理删除(使用 Mapper 中的 SQL,绕过逻辑删除)
97 + return this.baseMapper.physicalDeleteByIds(ids, enterpriseId);
98 + }
99 +
100 + @Override
101 + public List<OrderSubscriptionMessageDb> queryPendingMessages(int enterpriseId) {
102 + LambdaQueryWrapper<OrderSubscriptionMessageDb> queryWrapper = new LambdaQueryWrapper<>();
103 + queryWrapper.eq(OrderSubscriptionMessageDb::getEnterpriseId, enterpriseId)
104 + .eq(OrderSubscriptionMessageDb::getIsDeleted, false)
105 + .orderByAsc(OrderSubscriptionMessageDb::getCreatedAt);
106 + return this.list(queryWrapper);
107 + }
108 +}
109 +
...@@ -63,6 +63,13 @@ service MealOrderServiceRpc { ...@@ -63,6 +63,13 @@ service MealOrderServiceRpc {
63 rpc batchCreateDinerMealSuspensionRecords(BatchCreateDinerMealSuspensionRecordsRpcRequest) returns (BatchCreateDinerMealSuspensionRecordsRpcResponse); 63 rpc batchCreateDinerMealSuspensionRecords(BatchCreateDinerMealSuspensionRecordsRpcRequest) returns (BatchCreateDinerMealSuspensionRecordsRpcResponse);
64 rpc updateDinerMealSuspensionRecord(UpdateDinerMealSuspensionRecordRpcRequest) returns (UpdateDinerMealSuspensionRecordRpcResponse); 64 rpc updateDinerMealSuspensionRecord(UpdateDinerMealSuspensionRecordRpcRequest) returns (UpdateDinerMealSuspensionRecordRpcResponse);
65 rpc deleteDinerMealSuspensionRecordsByIds(DeleteDinerMealSuspensionRecordsByIdsRpcRequest) returns (DeleteDinerMealSuspensionRecordsRpcResponse); 65 rpc deleteDinerMealSuspensionRecordsByIds(DeleteDinerMealSuspensionRecordsByIdsRpcRequest) returns (DeleteDinerMealSuspensionRecordsRpcResponse);
66 +
67 + // 订餐订阅消息相关服务
68 + rpc CreateOrderSubscriptionMessage (CreateOrderSubscriptionMessageRpcRequest) returns (CreateOrderSubscriptionMessageRpcResponse) {}
69 + rpc GetUserOrderSubscriptionMessageHistory (GetUserOrderSubscriptionMessageHistoryRpcRequest) returns (GetUserOrderSubscriptionMessageHistoryRpcResponse) {}
70 + rpc BatchDeleteOrderSubscriptionMessagesByIds (BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest) returns (BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse) {}
71 + rpc BatchPhysicalDeleteOrderSubscriptionMessagesByIds (BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest) returns (BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse) {}
72 + rpc QueryPendingOrderSubscriptionMessages (QueryPendingOrderSubscriptionMessagesRpcRequest) returns (QueryPendingOrderSubscriptionMessagesRpcResponse) {}
66 } 73 }
67 74
68 enum MealOrderOrderMethodEnum { 75 enum MealOrderOrderMethodEnum {
...@@ -955,3 +962,76 @@ message BatchCreateDinerMealSuspensionRecordsRpcResponse { ...@@ -955,3 +962,76 @@ message BatchCreateDinerMealSuspensionRecordsRpcResponse {
955 bool isCreated = 1; 962 bool isCreated = 1;
956 repeated int32 ids = 2; 963 repeated int32 ids = 2;
957 } 964 }
965 +
966 +// 订餐订阅消息相关消息定义
967 +message CreateOrderSubscriptionMessageRpcRequest {
968 + int32 enterpriseId = 1;
969 + int32 dinerId = 2;
970 + string openId = 3;
971 + string templateId = 4;
972 + int64 orderPeriodStartDate = 5; // Unix 时间戳(毫秒),精确到秒
973 + string jumpPath = 6; // 跳转路径(小程序 path),可选
974 + int64 orderPeriodEndDate = 7; // Unix 时间戳(毫秒),精确到秒,可选
975 +}
976 +
977 +message CreateOrderSubscriptionMessageRpcResponse {
978 + int64 id = 1;
979 +}
980 +
981 +message GetUserOrderSubscriptionMessageHistoryRpcRequest {
982 + int32 enterpriseId = 1;
983 + string openId = 2;
984 + int64 orderPeriodStartDate = 3; // Unix 时间戳(毫秒),精确到秒,可选,如果传入则查询大于等于该值的记录
985 +}
986 +
987 +message OrderSubscriptionMessageRpcResponse {
988 + int64 id = 1;
989 + int64 orderPeriodStartDate = 2; // Unix 时间戳(毫秒),精确到秒
990 + int64 createdAt = 3; // Unix 时间戳(毫秒)
991 + bool isDeleted = 4;
992 + string jumpPath = 5; // 跳转路径(小程序 path),可选
993 + int64 orderPeriodEndDate = 6; // Unix 时间戳(毫秒),精确到秒,可选
994 +}
995 +
996 +message GetUserOrderSubscriptionMessageHistoryRpcResponse {
997 + repeated OrderSubscriptionMessageRpcResponse response = 1;
998 +}
999 +
1000 +message BatchDeleteOrderSubscriptionMessagesByIdsRpcRequest {
1001 + int32 enterpriseId = 1;
1002 + repeated int64 ids = 2; // 要删除的记录ID列表
1003 +}
1004 +
1005 +message BatchDeleteOrderSubscriptionMessagesByIdsRpcResponse {
1006 + int32 affectedRows = 1; // 受影响的行数
1007 +}
1008 +
1009 +message BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcRequest {
1010 + int32 enterpriseId = 1;
1011 + repeated int64 ids = 2; // 要删除的记录ID列表
1012 +}
1013 +
1014 +message BatchPhysicalDeleteOrderSubscriptionMessagesByIdsRpcResponse {
1015 + int32 affectedRows = 1; // 受影响的行数
1016 +}
1017 +
1018 +// 查询待发送的订阅消息(未删除的记录)
1019 +message QueryPendingOrderSubscriptionMessagesRpcRequest {
1020 + int32 enterpriseId = 1;
1021 +}
1022 +
1023 +message PendingOrderSubscriptionMessageRpcResponse {
1024 + int64 id = 1;
1025 + int32 enterpriseId = 2;
1026 + int32 dinerId = 3;
1027 + string openId = 4;
1028 + string templateId = 5;
1029 + int64 orderPeriodStartDate = 6;
1030 + string jumpPath = 7;
1031 + int64 orderPeriodEndDate = 8;
1032 + int64 createdAt = 9;
1033 +}
1034 +
1035 +message QueryPendingOrderSubscriptionMessagesRpcResponse {
1036 + repeated PendingOrderSubscriptionMessageRpcResponse responses = 1;
1037 +}
......
1 +package com.tianting.infoloop.service;
2 +
3 +import com.infoloop.tianting.ordersubscriptionmessageservice.CreateOrderSubscriptionMessageRpcRequest;
4 +import com.infoloop.tianting.ordersubscriptionmessageservice.GetUserOrderSubscriptionMessageHistoryRpcRequest;
5 +
6 +import java.util.Arrays;
7 +import java.util.List;
8 +import com.tianting.infoloop.App;
9 +import com.tianting.infoloop.model.db.OrderSubscriptionMessageDb;
10 +import org.junit.jupiter.api.BeforeAll;
11 +import org.junit.jupiter.api.Test;
12 +import org.junit.jupiter.api.TestInstance;
13 +import org.springframework.beans.factory.annotation.Autowired;
14 +import org.springframework.boot.test.context.SpringBootTest;
15 +import org.springframework.jdbc.core.JdbcTemplate;
16 +import org.springframework.test.context.ActiveProfiles;
17 +
18 +import java.util.List;
19 +
20 +import static org.assertj.core.api.Assertions.assertThat;
21 +
22 +@ActiveProfiles("dev")
23 +@SpringBootTest(classes = App.class)
24 +@TestInstance(TestInstance.Lifecycle.PER_CLASS)
25 +class OrderSubscriptionMessageDbServiceTest {
26 +
27 + @Autowired
28 + private JdbcTemplate jdbcTemplate;
29 +
30 + @Autowired
31 + private OrderSubscriptionMessageDbService orderSubscriptionMessageDbService;
32 +
33 + @BeforeAll
34 + void ensureTable() {
35 + jdbcTemplate.execute(
36 + "CREATE TABLE IF NOT EXISTS order_subscription_message ("
37 + + "id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',"
38 + + "enterpriseId INT NOT NULL COMMENT '企业ID',"
39 + + "dinerId INT DEFAULT NULL COMMENT '订餐用户ID(dinerId)',"
40 + + "openId VARCHAR(255) NOT NULL COMMENT '微信用户OpenID',"
41 + + "templateId VARCHAR(255) NOT NULL COMMENT '订阅消息模板ID',"
42 + + "jumpPath VARCHAR(255) DEFAULT NULL COMMENT '跳转路径(小程序 path)',"
43 + + "orderPeriodStartDate DATETIME DEFAULT NULL COMMENT '关联的订餐周期开始时间(精确到秒)',"
44 + + "orderPeriodEndDate DATETIME DEFAULT NULL COMMENT '关联的订餐周期结束时间(精确到秒)',"
45 + + "createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',"
46 + + "updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',"
47 + + "isDeleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除;0:未删除,1:已删除',"
48 + + "PRIMARY KEY (id),"
49 + + "KEY idx_enterprise_id (enterpriseId)"
50 + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订餐订阅消息授权表';");
51 +
52 + // 兼容本地已存在的旧表结构(修改字段类型为 DATETIME,精确到秒)
53 + Integer startDateType = jdbcTemplate.queryForObject(
54 + "SELECT COUNT(1) FROM information_schema.COLUMNS "
55 + + "WHERE table_schema = DATABASE() "
56 + + "AND table_name = 'order_subscription_message' "
57 + + "AND column_name = 'orderPeriodStartDate' "
58 + + "AND data_type IN ('date', 'bigint')",
59 + Integer.class);
60 + if (startDateType != null && startDateType > 0) {
61 + // 如果字段是 bigint,需要先清空数据或转换数据,这里先清空(测试环境)
62 + jdbcTemplate.update("UPDATE order_subscription_message SET orderPeriodStartDate = NULL WHERE orderPeriodStartDate IS NOT NULL");
63 + jdbcTemplate.execute(
64 + "ALTER TABLE order_subscription_message "
65 + + "MODIFY COLUMN orderPeriodStartDate DATETIME DEFAULT NULL COMMENT '关联的订餐周期开始时间(精确到秒)'");
66 + }
67 +
68 + Integer endDateExists = jdbcTemplate.queryForObject(
69 + "SELECT COUNT(1) FROM information_schema.COLUMNS "
70 + + "WHERE table_schema = DATABASE() "
71 + + "AND table_name = 'order_subscription_message' "
72 + + "AND column_name = 'orderPeriodEndDate'",
73 + Integer.class);
74 + if (endDateExists == null || endDateExists == 0) {
75 + jdbcTemplate.execute(
76 + "ALTER TABLE order_subscription_message "
77 + + "ADD COLUMN orderPeriodEndDate DATETIME DEFAULT NULL COMMENT '关联的订餐周期结束时间(精确到秒)' "
78 + + "AFTER orderPeriodStartDate");
79 + } else {
80 + Integer endDateType = jdbcTemplate.queryForObject(
81 + "SELECT COUNT(1) FROM information_schema.COLUMNS "
82 + + "WHERE table_schema = DATABASE() "
83 + + "AND table_name = 'order_subscription_message' "
84 + + "AND column_name = 'orderPeriodEndDate' "
85 + + "AND data_type IN ('date', 'bigint')",
86 + Integer.class);
87 + if (endDateType != null && endDateType > 0) {
88 + // 如果字段是 bigint,需要先清空数据或转换数据,这里先清空(测试环境)
89 + jdbcTemplate.update("UPDATE order_subscription_message SET orderPeriodEndDate = NULL WHERE orderPeriodEndDate IS NOT NULL");
90 + jdbcTemplate.execute(
91 + "ALTER TABLE order_subscription_message "
92 + + "MODIFY COLUMN orderPeriodEndDate DATETIME DEFAULT NULL COMMENT '关联的订餐周期结束时间(精确到秒)'");
93 + }
94 + }
95 + }
96 +
97 + @Test
98 + void shouldCreateAndQueryHistory() {
99 + final String openId = "openId_test_junit_001";
100 +
101 + // clean
102 + jdbcTemplate.update("DELETE FROM order_subscription_message WHERE enterpriseId=? AND openId=?", 1, openId);
103 +
104 + // create
105 + CreateOrderSubscriptionMessageRpcRequest createReq = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
106 + .setEnterpriseId(1)
107 + .setDinerId(100)
108 + .setOpenId(openId)
109 + .setTemplateId("template_test_junit_001")
110 + .setJumpPath("/pages/order/index")
111 + .setOrderPeriodStartDate(1738512000000L) // 2025-02-03 00:00:00 (毫秒时间戳,转换为 LocalDateTime)
112 + .setOrderPeriodEndDate(1739030400000L) // 2025-02-09 00:00:00 (毫秒时间戳,转换为 LocalDateTime)
113 + .build();
114 +
115 + OrderSubscriptionMessageDb created = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq);
116 + assertThat(created.getId()).isNotNull();
117 + assertThat(created.getEnterpriseId()).isEqualTo(1);
118 + assertThat(created.getDinerId()).isEqualTo(100);
119 + assertThat(created.getJumpPath()).isEqualTo("/pages/order/index");
120 + assertThat(created.getOrderPeriodEndDate()).isNotNull();
121 +
122 + // query history
123 + GetUserOrderSubscriptionMessageHistoryRpcRequest historyReq = GetUserOrderSubscriptionMessageHistoryRpcRequest.newBuilder()
124 + .setEnterpriseId(1)
125 + .setOpenId(openId)
126 + .setOrderPeriodStartDate(0)
127 + .build();
128 +
129 + List<OrderSubscriptionMessageDb> list = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(historyReq);
130 + assertThat(list).isNotEmpty();
131 + assertThat(list.get(0).getOpenId()).isEqualTo(openId);
132 + assertThat(list.get(0).getJumpPath()).isEqualTo("/pages/order/index");
133 + assertThat(list.get(0).getOrderPeriodEndDate()).isNotNull();
134 + }
135 +
136 + @Test
137 + void shouldQueryByOrderPeriodStartDateWithGreaterEqual() {
138 + final String openId = "openId_test_junit_date_query";
139 +
140 + // clean
141 + jdbcTemplate.update("DELETE FROM order_subscription_message WHERE enterpriseId=? AND openId=?", 1, openId);
142 +
143 + // 创建多条不同开始时间的记录
144 + // 记录1: 2025-02-03 00:00:00
145 + CreateOrderSubscriptionMessageRpcRequest createReq1 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
146 + .setEnterpriseId(1)
147 + .setDinerId(100)
148 + .setOpenId(openId)
149 + .setTemplateId("template_test_date_1")
150 + .setJumpPath("/pages/order/index")
151 + .setOrderPeriodStartDate(1738512000000L) // 2025-02-03 00:00:00
152 + .setOrderPeriodEndDate(1739030400000L) // 2025-02-09 00:00:00
153 + .build();
154 + OrderSubscriptionMessageDb created1 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq1);
155 +
156 + // 记录2: 2025-02-10 00:00:00 (晚于记录1)
157 + CreateOrderSubscriptionMessageRpcRequest createReq2 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
158 + .setEnterpriseId(1)
159 + .setDinerId(100)
160 + .setOpenId(openId)
161 + .setTemplateId("template_test_date_2")
162 + .setJumpPath("/pages/order/index")
163 + .setOrderPeriodStartDate(1739116800000L) // 2025-02-10 00:00:00
164 + .setOrderPeriodEndDate(1739635200000L) // 2025-02-16 00:00:00
165 + .build();
166 + OrderSubscriptionMessageDb created2 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq2);
167 +
168 + // 记录3: 2025-01-27 00:00:00 (早于记录1)
169 + CreateOrderSubscriptionMessageRpcRequest createReq3 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
170 + .setEnterpriseId(1)
171 + .setDinerId(100)
172 + .setOpenId(openId)
173 + .setTemplateId("template_test_date_3")
174 + .setJumpPath("/pages/order/index")
175 + .setOrderPeriodStartDate(1737907200000L) // 2025-01-27 00:00:00
176 + .setOrderPeriodEndDate(1738425600000L) // 2025-02-02 00:00:00
177 + .build();
178 + OrderSubscriptionMessageDb created3 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq3);
179 +
180 + // 记录4: 2025-02-03 12:00:00 (等于记录1的日期,但时间更晚)
181 + CreateOrderSubscriptionMessageRpcRequest createReq4 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
182 + .setEnterpriseId(1)
183 + .setDinerId(100)
184 + .setOpenId(openId)
185 + .setTemplateId("template_test_date_4")
186 + .setJumpPath("/pages/order/index")
187 + .setOrderPeriodStartDate(1738555200000L) // 2025-02-03 12:00:00
188 + .setOrderPeriodEndDate(1739073600000L) // 2025-02-09 12:00:00
189 + .build();
190 + OrderSubscriptionMessageDb created4 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq4);
191 +
192 + // 测试1: 查询 orderPeriodStartDate >= 2025-02-03 00:00:00
193 + // 应该返回: 记录1(等于), 记录2(大于), 记录4(大于)
194 + // 不应该返回: 记录3(小于)
195 + GetUserOrderSubscriptionMessageHistoryRpcRequest historyReq = GetUserOrderSubscriptionMessageHistoryRpcRequest.newBuilder()
196 + .setEnterpriseId(1)
197 + .setOpenId(openId)
198 + .setOrderPeriodStartDate(1738512000000L) // 2025-02-03 00:00:00
199 + .build();
200 +
201 + List<OrderSubscriptionMessageDb> list = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(historyReq);
202 +
203 + // 验证返回的记录数量:应该包含记录1、记录2、记录4,共3条
204 + assertThat(list.size()).isEqualTo(3);
205 +
206 + // 验证所有返回的记录的开始时间都 >= 2025-02-03 00:00:00
207 + java.time.LocalDateTime threshold = java.time.Instant.ofEpochMilli(1738512000000L)
208 + .atZone(java.time.ZoneId.systemDefault())
209 + .toLocalDateTime();
210 +
211 + for (OrderSubscriptionMessageDb db : list) {
212 + assertThat(db.getOrderPeriodStartDate()).isNotNull();
213 + assertThat(db.getOrderPeriodStartDate().isAfter(threshold) || db.getOrderPeriodStartDate().isEqual(threshold))
214 + .as("开始时间应该 >= 2025-02-03 00:00:00,实际: %s", db.getOrderPeriodStartDate())
215 + .isTrue();
216 + }
217 +
218 + // 验证包含记录1(等于)
219 + assertThat(list.stream().anyMatch(db -> db.getId().equals(created1.getId()))).isTrue();
220 +
221 + // 验证包含记录2(大于)
222 + assertThat(list.stream().anyMatch(db -> db.getId().equals(created2.getId()))).isTrue();
223 +
224 + // 验证包含记录4(大于,同一天但时间更晚)
225 + assertThat(list.stream().anyMatch(db -> db.getId().equals(created4.getId()))).isTrue();
226 +
227 + // 验证不包含记录3(小于)
228 + assertThat(list.stream().anyMatch(db -> db.getId().equals(created3.getId()))).isFalse();
229 +
230 + // 测试2: 查询 orderPeriodStartDate >= 2025-02-10 00:00:00
231 + // 应该只返回: 记录2(等于)
232 + GetUserOrderSubscriptionMessageHistoryRpcRequest historyReq2 = GetUserOrderSubscriptionMessageHistoryRpcRequest.newBuilder()
233 + .setEnterpriseId(1)
234 + .setOpenId(openId)
235 + .setOrderPeriodStartDate(1739116800000L) // 2025-02-10 00:00:00
236 + .build();
237 +
238 + List<OrderSubscriptionMessageDb> list2 = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(historyReq2);
239 +
240 + // 验证只返回记录2
241 + assertThat(list2.size()).isEqualTo(1);
242 + assertThat(list2.get(0).getId()).isEqualTo(created2.getId());
243 + }
244 +
245 + @Test
246 + void shouldBatchDeleteByIds() {
247 + final String openId = "openId_test_junit_delete";
248 +
249 + // clean
250 + jdbcTemplate.update("DELETE FROM order_subscription_message WHERE enterpriseId=? AND openId=?", 1, openId);
251 +
252 + // create multiple records
253 + CreateOrderSubscriptionMessageRpcRequest createReq1 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
254 + .setEnterpriseId(1)
255 + .setDinerId(100)
256 + .setOpenId(openId)
257 + .setTemplateId("template_test_junit_delete_1")
258 + .setJumpPath("/pages/order/index")
259 + .setOrderPeriodStartDate(1738512000000L)
260 + .setOrderPeriodEndDate(1739030400000L)
261 + .build();
262 +
263 + CreateOrderSubscriptionMessageRpcRequest createReq2 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
264 + .setEnterpriseId(1)
265 + .setDinerId(100)
266 + .setOpenId(openId)
267 + .setTemplateId("template_test_junit_delete_2")
268 + .setJumpPath("/pages/order/index")
269 + .setOrderPeriodStartDate(1738512000000L)
270 + .setOrderPeriodEndDate(1739030400000L)
271 + .build();
272 +
273 + OrderSubscriptionMessageDb created1 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq1);
274 + OrderSubscriptionMessageDb created2 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq2);
275 + List<Long> ids = Arrays.asList(created1.getId(), created2.getId());
276 +
277 + // verify records exist
278 + List<OrderSubscriptionMessageDb> beforeDelete = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(
279 + GetUserOrderSubscriptionMessageHistoryRpcRequest.newBuilder()
280 + .setEnterpriseId(1)
281 + .setOpenId(openId)
282 + .setOrderPeriodStartDate(0)
283 + .build());
284 + assertThat(beforeDelete.size()).isGreaterThanOrEqualTo(2);
285 +
286 + // batch delete (逻辑删除)
287 + int affectedRows = orderSubscriptionMessageDbService.batchDeleteByIds(ids, 1);
288 + assertThat(affectedRows).isEqualTo(2);
289 +
290 + // verify deleted - 逻辑删除后查询不到
291 + List<OrderSubscriptionMessageDb> afterDelete = orderSubscriptionMessageDbService.getUserOrderSubscriptionMessageHistory(
292 + GetUserOrderSubscriptionMessageHistoryRpcRequest.newBuilder()
293 + .setEnterpriseId(1)
294 + .setOpenId(openId)
295 + .setOrderPeriodStartDate(0)
296 + .build());
297 + assertThat(afterDelete.size()).isLessThan(beforeDelete.size());
298 +
299 + // verify deleted - 但数据库里还存在(isDeleted=1)
300 + Integer count = jdbcTemplate.queryForObject(
301 + "SELECT COUNT(1) FROM order_subscription_message WHERE id IN (?,?) AND isDeleted=1",
302 + Integer.class,
303 + created1.getId(), created2.getId());
304 + assertThat(count).isEqualTo(2);
305 + }
306 +
307 + @Test
308 + void shouldBatchPhysicalDeleteByIds() {
309 + final String openId = "openId_test_junit_physical_delete";
310 +
311 + // clean
312 + jdbcTemplate.update("DELETE FROM order_subscription_message WHERE enterpriseId=? AND openId=?", 1, openId);
313 +
314 + // create multiple records
315 + CreateOrderSubscriptionMessageRpcRequest createReq1 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
316 + .setEnterpriseId(1)
317 + .setDinerId(100)
318 + .setOpenId(openId)
319 + .setTemplateId("template_test_junit_physical_delete_1")
320 + .setJumpPath("/pages/order/index")
321 + .setOrderPeriodStartDate(1738512000000L)
322 + .setOrderPeriodEndDate(1739030400000L)
323 + .build();
324 +
325 + CreateOrderSubscriptionMessageRpcRequest createReq2 = CreateOrderSubscriptionMessageRpcRequest.newBuilder()
326 + .setEnterpriseId(1)
327 + .setDinerId(100)
328 + .setOpenId(openId)
329 + .setTemplateId("template_test_junit_physical_delete_2")
330 + .setJumpPath("/pages/order/index")
331 + .setOrderPeriodStartDate(1738512000000L)
332 + .setOrderPeriodEndDate(1739030400000L)
333 + .build();
334 +
335 + OrderSubscriptionMessageDb created1 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq1);
336 + OrderSubscriptionMessageDb created2 = orderSubscriptionMessageDbService.createOrderSubscriptionMessage(createReq2);
337 + List<Long> ids = Arrays.asList(created1.getId(), created2.getId());
338 +
339 + // batch physical delete
340 + int affectedRows = orderSubscriptionMessageDbService.batchPhysicalDeleteByIds(ids, 1);
341 + assertThat(affectedRows).isEqualTo(2);
342 +
343 + // verify deleted - 物理删除后数据库里也不存在
344 + Integer count = jdbcTemplate.queryForObject(
345 + "SELECT COUNT(1) FROM order_subscription_message WHERE id IN (?,?)",
346 + Integer.class,
347 + created1.getId(), created2.getId());
348 + assertThat(count).isEqualTo(0);
349 + }
350 +}
351 +