| Pass |
- 14:35:17 |
+ 0:26:02 |
Test passed
|
@@ -128,13 +128,13 @@
Started
-
ʮһÔÂ 10, 2026 14:35:16
+
ʮһÔÂ 11, 2026 00:26:01
Ended
-
ʮһÔÂ 10, 2026 14:35:17
+
ʮһÔÂ 11, 2026 00:26:02
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
index fe58f403..274c52d8 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
@@ -23,6 +23,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -239,15 +242,32 @@ public class MallOrderController {
*/
@PostMapping("/userRequireMake")
@ApiOperation(value = "用户点击出餐")
- public Result userRequireMake(@ApiParam("订单ID") @RequestParam String orderId) {
+ public Result userRequireMake(@ApiParam("订单ID") @RequestParam String orderId,
+ @ApiParam("预约用餐时间") @RequestParam(required = false) String userRequireMakeTime) {
try {
- mallOrderService.userRequireMake(orderId);
+ mallOrderService.userRequireMake(orderId, parseUserRequireMakeTime(userRequireMakeTime));
return ResultUtil.success("通知商家成功");
} catch (Exception e) {
log.error("出餐失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());
}
}
+
+ private Date parseUserRequireMakeTime(String value) {
+ if (value == null || value.trim().isEmpty()) {
+ return null;
+ }
+ String text = value.trim().replace(' ', 'T');
+ if (text.length() == 16) {
+ text = text + ":00";
+ }
+ try {
+ return Date.from(LocalDateTime.parse(text).atZone(ZoneId.systemDefault()).toInstant());
+ } catch (Exception e) {
+ throw new RuntimeException("用餐时间格式不正确");
+ }
+ }
+
/**
* 商家拒单
*/
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java
index 218a64ce..e04a540c 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java
@@ -275,7 +275,6 @@ public class OrderDelayConsumer {
MallOrder order = mallOrderMapper.selectById(orderId);
if (order == null
|| !Integer.valueOf(2).equals(order.getDeliveryType())
- || Integer.valueOf(1).equals(order.getUserRequireMake())
|| order.getUserRequireMakeTime() == null
|| order.getShopMakeTime() != null
|| order.getStatus() == null
@@ -288,6 +287,7 @@ public class OrderDelayConsumer {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔预约到店订单可以出餐啦!", orderId);
}
orderAsyncProducer.sendCloudPrint(orderId, "SHOP_APPOINTMENT_MAKE");
+ mallOrderService.scheduleStorePickupCookTimeout(orderId);
}
private void handleTransferArriveTimeout(String orderId) {
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
index 3f3df6d0..08439f1b 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
@@ -85,7 +85,12 @@ public interface MallOrderService extends IService {
/**
* 用户要求出餐
*/
- void userRequireMake(String orderId);
+ void userRequireMake(String orderId, java.util.Date userRequireMakeTime);
+
+ /**
+ * 到店订单通知商家出餐后,按取餐时间和商家出餐时长设置出餐超时提醒。
+ */
+ void scheduleStorePickupCookTimeout(String orderId);
void updateSaleCacheIncrementalViaMq(String shopId, String regionId, java.util.List items, Integer shopSaleCount);
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
index ddf5b78f..9fbc34c0 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
@@ -161,13 +161,19 @@ public class MallOrderGroupServiceImpl extends ServiceImpl orderIdList = Arrays.asList(group.getGroupOrderIds().split(","));
+ List orderIdList = parseGroupOrderIds(group);
List goodsList = new ArrayList<>();
LambdaQueryWrapper oqw = new LambdaQueryWrapper<>();
- oqw.eq(MallOrder::getShopId, group.getShopId())
- .eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
+ oqw.eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
.in(MallOrder::getId, orderIdList);
- List waitingOrders = mallOrderService.list(oqw);
+ List waitingOrders = orderIdList.isEmpty()
+ ? new ArrayList<>()
+ : mallOrderService.list(oqw);
+ if (waitingOrders.size() < orderIdList.size()) {
+ log.warn("成团时有订单未处于待成团,groupId={},groupOrderIds={},命中={}",
+ groupId, group.getGroupOrderIds(),
+ waitingOrders.stream().map(MallOrder::getId).collect(java.util.stream.Collectors.toList()));
+ }
boolean isFace2Face = group.getIsFace() != null && group.getIsFace() == 1;
List deliveryOrders = new ArrayList<>();
@@ -177,9 +183,10 @@ public class MallOrderGroupServiceImpl extends ServiceImpl ouw = new LambdaUpdateWrapper<>();
+ String latestSeq = null;
//代表该拼团子订单订单选择到店
if(targetStatus == 3){
- String latestSeq = String.format("%s-%s",
+ latestSeq = String.format("%s-%s",
LocalDate.now().format(DateTimeFormatter.ofPattern("MMdd")),
merchantOrderSeqUtil.generateOrderSequence(order.getShopId(), 2));
ouw.eq(MallOrder::getId, order.getId())
@@ -192,12 +199,21 @@ public class MallOrderGroupServiceImpl extends ServiceImpl 0) {
- cookTimeMins = cachedCookTime;
- }
- } catch (Exception e) {
- log.error("获取店铺出餐时间缓存异常: {}", e.getMessage());
+ if (order == null || StringUtils.isBlank(order.getId())) {
+ return;
+ }
+ long delayMillis = resolveStorePickupCookTimeoutDelay(order);
+ log.info("到店出餐超时提醒 orderId={} userRequireMakeTime={} delayMillis={}",
+ order.getId(), order.getUserRequireMakeTime(), delayMillis);
+ orderAsyncProducer.sendDelayMessage(order.getId(), "Shop_Cook_Timeout", delayMillis);
+ }
+
+ /**
+ * 超时提醒时刻 = 取餐时间 - 商家出餐时长。
+ * 这个时刻已经过了时,从当前起按商家出餐时长计时,避免立刻判超时。
+ * 若商家出餐时长长于通知后的剩余时间,则等通知后再给足出餐时长。
+ */
+ private long resolveStorePickupCookTimeoutDelay(MallOrder order) {
+ long cookMillis = 15L * 60 * 1000L;
+ try {
+ int cachedCookTime = safeMinutes(getCookingTime(order.getRegionId(), order.getShopId()));
+ if (cachedCookTime > 0) {
+ cookMillis = cachedCookTime * 60L * 1000L;
}
- orderAsyncProducer.sendDelayMessage(order.getId(), "Shop_Cook_Timeout", cookTimeMins * 60 * 1000L);
+ } catch (Exception e) {
+ log.error("获取店铺出餐时间缓存异常: {}", e.getMessage());
+ }
+ long now = System.currentTimeMillis();
+ Date pickupTime = order.getUserRequireMakeTime();
+ if (pickupTime == null) {
+ return cookMillis;
+ }
+ long pickupAt = pickupTime.getTime();
+ long startAt = Math.max(now, pickupAt - STORE_PICKUP_NOTIFY_BEFORE_MILLIS);
+ long timeoutAt = pickupAt - cookMillis;
+ if (timeoutAt <= now) {
+ timeoutAt = now + cookMillis;
+ } else {
+ timeoutAt = Math.max(timeoutAt, startAt + cookMillis);
}
+ return Math.max(1000L, timeoutAt - now);
}
/**
diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
index 2f655974..649df517 100644
--- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
+++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
@@ -805,7 +805,7 @@ public class MallOrderServiceImpl extends ServiceImpl guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getCurrentMembers, newMembers);
- mallOrderGroupMapper.update(group,guw);
+ mallOrderGroupMapper.update(null, guw);
//缓存更新
group.setCurrentMembers(newMembers);
shopGroupOrderCacheUtil.update(group.getShopId(), group);
@@ -816,7 +816,7 @@ public class MallOrderServiceImpl extends ServiceImpl guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getStatus, GROUP_STATUS_FORMING).set(MallOrderGroup::getCurrentMembers, newMembers);
- mallOrderGroupMapper.update(group,guw);
+ mallOrderGroupMapper.update(null, guw);
//普通拼团团长发起拼团进缓存
if(order.getOrderType() == ORDER_TYPE_GROUP){
group.setCurrentMembers(newMembers);
@@ -831,7 +831,7 @@ public class MallOrderServiceImpl extends ServiceImpl guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getCurrentMembers, newMembers);
- mallOrderGroupMapper.update(group,guw);
+ mallOrderGroupMapper.update(null, guw);
}
}
if (group != null) {
@@ -918,20 +918,51 @@ public class MallOrderServiceImpl extends ServiceImpl 0) {
- cookTimeMins = cachedCookTime;
- }
- } catch (Exception e) {
- log.error("获取店铺出餐时间缓存异常: {}", e.getMessage());
+ if (order == null) {
+ return;
+ }
+ long delayMillis = resolveStorePickupCookTimeoutDelay(order);
+ log.info("到店出餐超时提醒 orderId={} userRequireMakeTime={} delayMillis={}",
+ orderId, order.getUserRequireMakeTime(), delayMillis);
+ orderAsyncProducer.sendDelayMessage(orderId, "Shop_Cook_Timeout", delayMillis);
+ }
+
+ /**
+ * 超时提醒时刻 = 取餐时间 - 商家出餐时长。
+ * 这个时刻已经过了时,从当前起按商家出餐时长计时,避免立刻判超时。
+ * 若商家出餐时长长于通知后的剩余时间,则等通知后再给足出餐时长。
+ */
+ private long resolveStorePickupCookTimeoutDelay(MallOrder order) {
+ long cookMillis = 15L * 60 * 1000L;
+ try {
+ int cachedCookTime = safeMinutes(getCookingTime(order.getRegionId(), order.getShopId()));
+ if (cachedCookTime > 0) {
+ cookMillis = cachedCookTime * 60L * 1000L;
}
- orderAsyncProducer.sendDelayMessage(orderId, "Shop_Cook_Timeout", cookTimeMins * 60 * 1000L);
+ } catch (Exception e) {
+ log.error("获取店铺出餐时间缓存异常: {}", e.getMessage());
+ }
+ long now = System.currentTimeMillis();
+ Date pickupTime = order.getUserRequireMakeTime();
+ if (pickupTime == null) {
+ return cookMillis;
+ }
+ long pickupAt = pickupTime.getTime();
+ long startAt = Math.max(now, pickupAt - STORE_PICKUP_NOTIFY_BEFORE_MILLIS);
+ long timeoutAt = pickupAt - cookMillis;
+ if (timeoutAt <= now) {
+ timeoutAt = now + cookMillis;
+ } else {
+ timeoutAt = Math.max(timeoutAt, startAt + cookMillis);
}
+ return Math.max(1000L, timeoutAt - now);
}
@Override
@@ -1586,19 +1617,26 @@ public class MallOrderServiceImpl extends ServiceImpl uw = new LambdaUpdateWrapper<>();
- uw.eq(MallOrder::getId, orderId).set(MallOrder::getUserRequireMake,1);
- this.update(uw);
- Shop shop = getShopFromCache(order.getRegionId(), order.getShopId());
- if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
- jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单",orderId);
+ uw.eq(MallOrder::getId, orderId).set(MallOrder::getUserRequireMake, 1);
+ order.setUserRequireMake(1);
+ if (userRequireMakeTime != null) {
+ uw.set(MallOrder::getUserRequireMakeTime, userRequireMakeTime);
+ order.setUserRequireMakeTime(userRequireMakeTime);
}
- orderAsyncProducer.sendCloudPrint(orderId, "SHOP_INSTANT_MAKE");
-
- // 触发商家出餐超时监听
- triggerShopCookTimeoutEvent(orderId);
+ this.update(uw);
+ notifyOrScheduleStorePickupMake(order);
}
@Override
@@ -2146,6 +2184,7 @@ public class MallOrderServiceImpl extends ServiceImpl