预订单逻辑优化

This commit is contained in:
Jack 2025-10-31 21:58:43 +08:00
parent c91fc181c9
commit eb268d35b3
7 changed files with 99 additions and 48 deletions

View File

@ -125,4 +125,11 @@ public class CommonConstant {
public static final Integer Order_Booking_State_LJ = 1;
public static final Integer Order_Booking_State_YY = 2;
// 预约下单从当前时间延迟的最小分钟数单位分钟不能低于35分钟
public final static Integer MIN_DELAY_MINUTES_FOR_BOOKING_ORDER = 46;
// 预约订单创建提前分钟数用于提前创建顺丰订单
// public final static Integer MIN_DELAY_MINUTES_FOR_SF_EXPRESS_ORDER = 35;
}

View File

@ -96,6 +96,7 @@ public class RedisKeyExpiredListener implements MessageListener {
// orderId
String orderId = expiredKey.replace(RedisConstant.Order_Booking_Task_Key, "");
log.info("[预约订单顺丰同城下单Redis过期监听] 处理预约订单顺丰同城下单超时消息. 订单号: {}", orderId);
if (StrUtil.isBlank(orderId)) {
log.error("[预约订单顺丰同城下单Redis过期监听] 键: {} 不符合预期格式,无法解析订单号", expiredKey);
return;

View File

@ -607,4 +607,13 @@ public interface ShopOrderBaseService extends IBaseService<ShopOrderBase> {
* @return
*/
Long sameCityOrderExpireSeconds(Long defaultValue);
/**
* 更新订单下单时间
*
* @param orderId
* @param orderTime
* @return
*/
Boolean updateOrderTime(String orderId, Date orderTime);
}

View File

@ -8,7 +8,6 @@
package com.suisung.mall.shop.order.service;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.suisung.mall.common.modules.order.ShopOrderBooking;
import com.suisung.mall.core.web.service.IBaseService;
@ -40,15 +39,7 @@ public interface ShopOrderBookingService extends IBaseService<ShopOrderBooking>
* @return 分页结果
*/
Page<ShopOrderBooking> findValidBookingList(Integer pageNum, Integer pageSize);
/**
* 更新预约订单任务
*
* @param updateWrapper 更新条件包装器
* @return 是否更新成功
*/
Boolean update(UpdateWrapper<ShopOrderBooking> updateWrapper);
/**
* 更改预约订单任务下单完成状态同时删除 redis 的定时任务
*

View File

@ -6675,15 +6675,22 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
bookingAt = bookingBeginTime.getTime() / 1000; // 预订单到达时间戳
}
// 计算订单下单时间预约开始时间前35分钟
Date scheduledOrderTime = DateUtil.offsetSecond(bookingBeginTime, -Convert.toInt(sameCityOrderExpireSeconds(2100L))); // 35分钟超时60秒*35分钟 = 2100秒
info_row.setBooking_state(bookingState);
info_row.setBooking_at(bookingAt);
info_row.setBooking_begin_time(bookingBeginTime);
info_row.setBooking_end_time(bookingEndTime);
info_row.setOrder_time(scheduledOrderTime.getTime());
// 重要预约订单任务创建处理
if (!shopOrderBookingService.setupRedisBookingTask(info_row.getOrder_id(), info_row.getBooking_at())) {
throw new ApiException(I18nUtil._("保存预约订单任务失败!"));
}
// 更新订单的下单时间
updateOrderTime(order_id, scheduledOrderTime);
}
@ -8759,7 +8766,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
// 支付渠道处理
m.put("payment_channel_name", m.getOrDefault("payment_channel_name", "线上支付").toString());
// 配送时间= 支付时间+35分钟
// 配送到达时间= 支付时间+35分钟
Long mchOrderExpireSeconds = shopOrderBaseService.sameCityOrderExpireSeconds(2100L);
// 配送时间
Date paymentTime = Convert.toDate(m.get("payment_time"));
@ -9271,6 +9278,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
*/
@Override
public Long sameCityOrderExpireSeconds(Long defaultValue) {
if (CheckUtil.isEmpty(defaultValue)) {
defaultValue = 2100L;
}
try {
String value = accountService.getAccountBaseConfigValue(CommonConstant.CONF_KEY_SAME_CITY_ORDER_EXPIRE_SECONDS);
if (StringUtils.isBlank(value)) {
@ -9284,4 +9295,48 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
return defaultValue;
}
}
/**
* 更新订单下单时间
*
* @param orderId 订单ID
* @param orderTime 新的订单时间
* @return Boolean 更新是否成功
*/
@Override
public Boolean updateOrderTime(String orderId, Date orderTime) {
// 1. 参数校验
if (StrUtil.isBlank(orderId)) {
log.warn("[更新订单时间] 订单ID不能为空");
return false;
}
if (orderTime == null) {
log.warn("[更新订单时间] 订单时间不能为空, orderId={}", orderId);
return false;
}
try {
// 2. 构建更新条件
UpdateWrapper<ShopOrderBase> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("order_id", orderId)
.set("order_time", orderTime);
// 3. 执行更新操作
boolean result = update(updateWrapper);
if (result) {
log.info("[更新订单时间] 订单时间更新成功, orderId={}, orderTime={}", orderId, orderTime);
} else {
log.warn("[更新订单时间] 订单时间更新失败, 可能订单不存在, orderId={}", orderId);
}
return result;
} catch (Exception e) {
// 4. 异常处理
log.error("[更新订单时间] 更新订单时间时发生异常, orderId={}, orderTime={}", orderId, orderTime, e);
return false;
}
}
}

View File

@ -21,6 +21,7 @@ import com.suisung.mall.common.utils.CheckUtil;
import com.suisung.mall.core.web.service.RedisService;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.order.mapper.ShopOrderBookingMapper;
import com.suisung.mall.shop.order.service.ShopOrderBaseService;
import com.suisung.mall.shop.order.service.ShopOrderBookingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,17 +31,18 @@ import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookingMapper, ShopOrderBooking> implements ShopOrderBookingService {
private static final Long MINUTES_BEFORE_BOOKING = 35L;
@Resource
private ShopOrderBookingMapper shopOrderBookingMapper;
@Lazy
@Resource
private ShopOrderBaseService shopOrderBaseService;
@Lazy
@Autowired
private RedisService redisService;
@ -64,7 +66,8 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
try {
// 计算执行时间预约时间前35分钟
long runAt = bookingAt - TimeUnit.MINUTES.toSeconds(MINUTES_BEFORE_BOOKING);
// long runAt = bookingAt - TimeUnit.MINUTES.toSeconds(CommonConstant.MIN_DELAY_MINUTES_FOR_SF_EXPRESS_ORDER);
long runAt = bookingAt - shopOrderBaseService.sameCityOrderExpireSeconds(2100L); // 35分钟超时60秒*35分钟 = 2100秒
ShopOrderBooking shopOrderBooking = new ShopOrderBooking();
shopOrderBooking.setOrder_id(orderId);
@ -77,9 +80,10 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
// 如果保存成功设置Redis过期键
if (shopOrderBooking != null) {
String redisKey = RedisConstant.Order_Booking_Task_Key + orderId;
long remainingSeconds = runAt - System.currentTimeMillis() / 1000;
// 设置过期时间为runAt时间点相对于当前时间的秒数
if (runAt > 0) {
redisService.set(redisKey, Convert.toStr(shopOrderBooking.getRun_at()), runAt);
if (remainingSeconds > 0) {
redisService.set(redisKey, Convert.toStr(shopOrderBooking.getRun_at()), remainingSeconds);
log.debug("Redis键设置成功: key={}, bookingAt={}, runAt={}", redisKey, bookingAt, runAt);
} else {
log.warn("过期时间无效未设置Redis键: key={}, bookingAt={}, runAt={}", redisKey, bookingAt, runAt);
@ -111,7 +115,7 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
try {
if (CheckUtil.isEmpty(shopOrderBooking.getRun_at())) {
long runAt = shopOrderBooking.getBooking_at() - TimeUnit.MINUTES.toSeconds(MINUTES_BEFORE_BOOKING);
long runAt = shopOrderBooking.getBooking_at() - shopOrderBaseService.sameCityOrderExpireSeconds(2100L); // 35分钟超时60秒*35分钟 = 2100秒
shopOrderBooking.setRun_at(runAt);
}
@ -166,22 +170,6 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
return this.page(page, queryWrapper);
}
@Override
public Boolean update(UpdateWrapper<ShopOrderBooking> updateWrapper) {
log.debug("更新预约订单任务");
if (updateWrapper == null) {
log.warn("更新条件不能为空");
return false;
}
try {
return this.update(updateWrapper);
} catch (Exception e) {
log.error("更新预约订单任务时发生异常", e);
return false;
}
}
/**
* 更改预约订单任务下单完成状态同时删除 redis 的定时任务
*
@ -205,7 +193,7 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
updateWrapper.set("status", CommonConstant.Disable2);
// 执行更新操作
boolean result = this.update(updateWrapper);
boolean result = update(updateWrapper);
if (result) {
log.debug("成功完成预约订单任务的同城配送下单: orderId={}", orderId);
@ -246,9 +234,16 @@ public class ShopOrderBookingServiceImpl extends BaseServiceImpl<ShopOrderBookin
continue;
}
redisService.set(redisKey, Convert.toStr(shopOrderBooking.getRun_at()), shopOrderBooking.getRun_at());
if (shopOrderBooking == null || shopOrderBooking.getRun_at() == null) {
log.debug("run_at 参数空不能同步到 Redis");
continue;
}
count++;
long remainingSeconds = shopOrderBooking.getRun_at() - System.currentTimeMillis() / 1000;
if (remainingSeconds > 0) {
redisService.set(redisKey, Convert.toStr(shopOrderBooking.getRun_at()), remainingSeconds);
count++;
}
}
return count;

View File

@ -119,27 +119,21 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
private ShopStorePrinterService shopStorePrinterService;
@Autowired
private ShopOrderInfoMapper shopOrderInfoMapper;
@Lazy
@Autowired
private ShopStoreSfOrderService shopStoreSfOrderService;
@Lazy
@Autowired
private ShopOrderBookingService shopOrderBookingService;
@Lazy
@Autowired
private SFExpressApiService sfExpressApiService;
@Lazy
@Autowired
private PushMessageService pushMessageService;
@Autowired
private ThreadPoolExecutor executor;
@Override
public Map dashboard() {
@ -914,9 +908,9 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
}
// 7. 预约时间范围检查 - 仅能预约50分钟后的订单防止用户在下单页面停留太长45分钟也是可以通过的
Date fortyFiveMinutesLater = DateUtil.offsetMinute(new Date(), 45);
if (!bookingBeginTime.after(fortyFiveMinutesLater)) {
return Pair.of(false, "[预约订单校验] 请预约50分后的订单");
Date fortyFiveMinutesLater = DateUtil.offsetMinute(new Date(), CommonConstant.MIN_DELAY_MINUTES_FOR_BOOKING_ORDER - 5);
if (bookingBeginTime.before(fortyFiveMinutesLater)) {
return Pair.of(false, String.format("[预约订单校验] 请预约%d分后的订单", CommonConstant.MIN_DELAY_MINUTES_FOR_BOOKING_ORDER));
}
return Pair.of(true, "[预约订单校验] 成功");
@ -975,7 +969,6 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
return Pair.of(false, "预约订单已下过单,请勿重复操作");
}
// 调用顺丰接口创建订单
Pair<Boolean, String> sfResult = sfExpressApiService.innerCreateSfExpressOrder(orderId, 0L);
if (sfResult == null) {
@ -1161,7 +1154,7 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
Date startTime = openTime;
if (isToday) {
// 当前时间+50分钟作为第二个时间槽的开始时间
Date nowPlusFifty = DateUtil.offsetMinute(new Date(), 35);
Date nowPlusFifty = DateUtil.offsetMinute(new Date(), CommonConstant.MIN_DELAY_MINUTES_FOR_BOOKING_ORDER);
// 如果当前时间+50分钟在营业时间范围内则从该时间开始
if (nowPlusFifty.after(openTime) && nowPlusFifty.before(closeTime)) {