|
|
|
@ -161,13 +161,19 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper, |
|
|
|
// 通过 head_order_id 找到团长订单,再通过 groupUserIds 关联
|
|
|
|
// 策略:查所有 orderId 在 groupOrderIds 中、shopId 相同、status=待成团的订单
|
|
|
|
// 更简洁:直接查 mall_order 中 id in (groupOrderIds split) AND shop_id = ? AND status = 10
|
|
|
|
List<String> orderIdList = Arrays.asList(group.getGroupOrderIds().split(",")); |
|
|
|
List<String> orderIdList = parseGroupOrderIds(group); |
|
|
|
List<MallOrderGoods> goodsList = new ArrayList<>(); |
|
|
|
LambdaQueryWrapper<MallOrder> 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<MallOrder> waitingOrders = mallOrderService.list(oqw); |
|
|
|
List<MallOrder> 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<MallOrder> deliveryOrders = new ArrayList<>(); |
|
|
|
@ -177,9 +183,10 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper, |
|
|
|
for (MallOrder order : waitingOrders) { |
|
|
|
int targetStatus = (order.getDeliveryType() != null && order.getDeliveryType() == 1) ? 2 : 3; |
|
|
|
LambdaUpdateWrapper<MallOrder> 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<MallOrderGroupMapper, |
|
|
|
.set(MallOrder::getStatus, targetStatus); |
|
|
|
} |
|
|
|
if (!mallOrderService.update(ouw)) { |
|
|
|
log.warn("成团激活订单失败,状态已变化 groupId={} orderId={}", groupId, order.getId()); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (targetStatus == 2) { |
|
|
|
notifyShopDeliveryOrder(order); |
|
|
|
} else if (targetStatus == 3) { |
|
|
|
notifyOrScheduleStorePickupMake(order); |
|
|
|
order.setStatus(targetStatus); |
|
|
|
if (latestSeq != null) { |
|
|
|
order.setNumberCode(latestSeq); |
|
|
|
} |
|
|
|
try { |
|
|
|
if (targetStatus == 2) { |
|
|
|
notifyShopDeliveryOrder(order); |
|
|
|
} else if (targetStatus == 3) { |
|
|
|
notifyOrScheduleStorePickupMake(order); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("成团通知或打印失败 groupId={} orderId={}", groupId, order.getId(), e); |
|
|
|
} |
|
|
|
MallOrderVO orderVO = buildVO(order, null, null, null); |
|
|
|
orderVO.setStatus(targetStatus); |
|
|
|
@ -362,30 +378,44 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper, |
|
|
|
if (order == null || !Integer.valueOf(DELIVERY_TYPE_SELF).equals(order.getDeliveryType())) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (Integer.valueOf(1).equals(order.getUserRequireMake())) { |
|
|
|
notifyAndPrintStorePickupMake(order, "SHOP_INSTANT_MAKE"); |
|
|
|
triggerShopCookTimeoutEvent(order); |
|
|
|
log.info("到店成团出餐判断 orderId={} deliveryType={} userRequireMake={} userRequireMakeTime={}", |
|
|
|
order.getId(), order.getDeliveryType(), order.getUserRequireMake(), order.getUserRequireMakeTime()); |
|
|
|
if (order.getUserRequireMakeTime() != null) { |
|
|
|
Date now = new Date(); |
|
|
|
boolean alreadyDue = !order.getUserRequireMakeTime().after(now); |
|
|
|
long delayMillis = order.getUserRequireMakeTime().getTime() |
|
|
|
- STORE_PICKUP_NOTIFY_BEFORE_MILLIS |
|
|
|
- now.getTime(); |
|
|
|
if (alreadyDue || delayMillis <= 0) { |
|
|
|
notifyAndPrintStorePickupMake(order, "SHOP_APPOINTMENT_MAKE"); |
|
|
|
triggerShopCookTimeoutQuietly(order); |
|
|
|
} else { |
|
|
|
orderAsyncProducer.sendDelayMessage(order.getId(), DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY, delayMillis); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
if (order.getUserRequireMakeTime() == null) { |
|
|
|
return; |
|
|
|
if (Integer.valueOf(1).equals(order.getUserRequireMake())) { |
|
|
|
notifyAndPrintStorePickupMake(order, "SHOP_INSTANT_MAKE"); |
|
|
|
triggerShopCookTimeoutQuietly(order); |
|
|
|
} |
|
|
|
long delayMillis = order.getUserRequireMakeTime().getTime() |
|
|
|
- STORE_PICKUP_NOTIFY_BEFORE_MILLIS |
|
|
|
- System.currentTimeMillis(); |
|
|
|
if (delayMillis <= 0) { |
|
|
|
notifyAndPrintStorePickupMake(order, "SHOP_APPOINTMENT_MAKE"); |
|
|
|
} |
|
|
|
|
|
|
|
private void triggerShopCookTimeoutQuietly(MallOrder order) { |
|
|
|
try { |
|
|
|
triggerShopCookTimeoutEvent(order); |
|
|
|
return; |
|
|
|
} catch (Exception e) { |
|
|
|
log.warn("到店出餐超时监听发送失败 orderId={}: {}", order == null ? null : order.getId(), e.getMessage()); |
|
|
|
} |
|
|
|
orderAsyncProducer.sendDelayMessage(order.getId(), DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY, delayMillis); |
|
|
|
} |
|
|
|
|
|
|
|
private void notifyAndPrintStorePickupMake(MallOrder order, String printReason) { |
|
|
|
try { |
|
|
|
Shop shop = getShopFromCache(order.getRegionId(), order.getShopId()); |
|
|
|
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) { |
|
|
|
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单", order.getId()); |
|
|
|
String message = StringUtils.isNotBlank(order.getNumberCode()) |
|
|
|
? "您有一笔新的到店订单 " + order.getNumberCode() |
|
|
|
: "您有一笔新的到店订单"; |
|
|
|
jPushService.sendPushNotification(shop.getClientId(), message, order.getId()); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.warn("到店订单推送失败 orderId={}: {}", order.getId(), e.getMessage()); |
|
|
|
@ -474,18 +504,44 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper, |
|
|
|
} |
|
|
|
|
|
|
|
private void triggerShopCookTimeoutEvent(MallOrder order) { |
|
|
|
if (order != null) { |
|
|
|
long cookTimeMins = 15; // default
|
|
|
|
try { |
|
|
|
int cachedCookTime = safeMinutes(getCookingTime(order.getRegionId(), order.getShopId())); |
|
|
|
if (cachedCookTime > 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); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
|