fix(cloud): 优化预约单过期处理和微信支付回调逻辑

- 添加费标准详情字段并实现相关查询逻辑
- 优化预约单过期处理逻辑,增加缓冲期和精确的时间判断
- 完善微信支付回调处理,增加参数校验和幂等性检查
- 添加支付成功通知功能
This commit is contained in:
tzy 2025-04-18 14:09:04 +08:00
parent a0fef83bf3
commit 90b805d0f4
5 changed files with 122 additions and 47 deletions

View File

@ -1,6 +1,7 @@
package com.evotech.hd.common.core.entity.cloud;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.evotech.hd.common.core.entity.BaseEntity;
@ -96,6 +97,9 @@ public class OrderSwapBattery extends BaseEntity implements Serializable {
@Schema(description = "费用标准")
private String feeStandardJson;
@Schema(description = "费用标准详情")
@TableField(exist = false)
private BatteryStationHdFeeStandard feeStandardDetail;
@Schema(description = "上次租赁电池时车辆里程")
private BigDecimal lastRentBatCarOdo;

View File

@ -53,6 +53,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
@ -87,6 +89,8 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
private BatteryStationDao batteryStationDao;
@Resource
private GZHTemplateMessageService gzhTemplateMessageService;
@Resource
private BatteryStationHdFeeStandardDao batteryStationHdFeeStandardDao;
@Override
@ -247,6 +251,15 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
if (page.getRecords().isEmpty()) {
return new Result<List<OrderSwapBattery>>().error(CodeMsg.DATABASE_RESULT_NULL);
}
page.getRecords().forEach(osb -> {
if (StringUtils.hasText(osb.getFeeStandardJson())){
String feeStandardJson = osb.getFeeStandardJson();
BatteryStationHdFeeStandard bean = JSONUtil.toBean(feeStandardJson, BatteryStationHdFeeStandard.class);
osb.setFeeStandardDetail(bean);
}
});
return new Result<List<OrderSwapBattery>>().success(page);
}

View File

@ -86,28 +86,59 @@ public class TradeServiceImpl implements TradeService {
}
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public Result<String> wechatPayNotifyHandle(TradeDetail tradeDetail) {
// 1. 添加交易
boolean b = tradeDetailDao.exists(new QueryWrapper<TradeDetail>()
try {
// 1. 参数校验
if (tradeDetail == null || !StringUtils.hasText(tradeDetail.getOutTradeNo())) {
log.error("微信支付回调参数异常: {}", JSONUtil.toJsonStr(tradeDetail));
return new Result<String>().error("参数异常");
}
// 2. 幂等性检查
boolean isProcessed = tradeDetailDao.exists(new QueryWrapper<TradeDetail>()
.eq("out_trade_no", tradeDetail.getOutTradeNo())
.eq("transaction_id", tradeDetail.getTransactionId())
.eq("pay_result", tradeDetail.getPayResult()));
if (b) {
log.info("\r\n===>>>已处理过此回调:" + tradeDetail);
return new Result<String>().error("重复消息!");
if (isProcessed) {
log.info("重复的微信支付回调, outTradeNo: {}", tradeDetail.getOutTradeNo());
return new Result<String>().error("重复消息");
}
// 添加交易
log.info("请求时间{} 是否存在交易{} 添加交易>>>>>{}" ,new Date() ,b, JSONUtil.toJsonStr(tradeDetail));
// 3. 记录交易
log.info("开始处理微信支付回调, outTradeNo: {}, 交易信息: {}",
tradeDetail.getOutTradeNo(),
JSONUtil.toJsonStr(tradeDetail));
add(tradeDetail);
// 2. 业务类型处理
// 4. 业务处理
payNotifyHandleService.payNotifyBussinessHandle(tradeDetail);
// 5. 发送支付成功通知
if (StringUtils.hasText(tradeDetail.getOrderNo())) {
OrderSwapBattery order = orderSwapBatteryDao.selectOne(
new LambdaQueryWrapper<OrderSwapBattery>()
.eq(OrderSwapBattery::getOrderNo, tradeDetail.getOrderNo())
);
if (order != null) {
gzhTemplateMessageService.orderMessageSend2(order.getPkId(), 3);
log.info("支付成功通知已发送, orderNo: {}", tradeDetail.getOrderNo());
} else {
log.warn("未找到对应的订单, orderNo: {}", tradeDetail.getOrderNo());
}
}
return new Result<String>().success("OK");
} catch (Exception e) {
log.error("处理微信支付回调异常, outTradeNo: {}, 异常信息: {}",
tradeDetail.getOutTradeNo(),
e.getMessage(),
e);
throw new RuntimeException("处理支付回调失败", e);
}
}
}

View File

@ -3,6 +3,7 @@ package com.evotech.hd.cloud.task;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
import com.evotech.hd.cloud.service.OrderSwapBatteryService;
@ -16,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Date;
@ -32,37 +34,62 @@ public class OrderSwapBatteryTask {
@Resource
private RedisUtil redisUtil;
@Scheduled(cron = "0 0 * * * ?") // 每小时执行一次
// @Scheduled(cron = "0 0 * * * ?") // 每小时执行一次
@Scheduled(cron = "0 */2 * * * ?")
@Transactional(rollbackFor = Exception.class)
public void orderSwapBatteryExpired() {
log.info("\r\n===>>> 开始查找预约单更新预约状态..");
// 查询条件排除已过期和无效状态
QueryWrapper<OrderSwapBatteryPre> queryWrapper = new QueryWrapper<>();
queryWrapper
.ne("status", 4)//无效
.ne("status", 3) //过期
.ne("status", 2); //过期
// 查询条件只查询未处理的预约单
LambdaQueryWrapper<OrderSwapBatteryPre> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq( OrderSwapBatteryPre::getStatus,1)
.le( OrderSwapBatteryPre::getReservationTime, new Date())
.select(OrderSwapBatteryPre::getPkId,
OrderSwapBatteryPre::getSourceId,
OrderSwapBatteryPre::getReservationTime,
OrderSwapBatteryPre::getSwapDuration,
OrderSwapBatteryPre::getStatus)
.orderByDesc(OrderSwapBatteryPre::getReservationTime)
.last("limit 1000");
List<OrderSwapBatteryPre> orderSwapBatteryPreList = orderSwapBatteryPreDao.selectList(queryWrapper);
// 获取当前时间
Date currentTime = new Date();
int expiredCount = 0; // 记录过期的预约单数量
int expiredCount = 0;
for (OrderSwapBatteryPre order : orderSwapBatteryPreList) {
// 检查预约时间是否已过期
if (order.getReservationTime() != null && order.getReservationTime().before(currentTime)) {
// 更新状态为过期
order.setStatus(4); // 设置为过期状态
try {
orderSwapBatteryPreDao.updateById(order);
//发送公众号过期提醒
//templateMessageService.orderMessageSend(order, 4);
expiredCount++;
log.info("预约单已过期订单ID: {}", order.getSourceId()); // 记录过期的订单ID
} catch (Exception e) {
log.error("更新预约单状态失败,预约人:{}订单ID: {}, 错误信息: {}", order.getUname(), order.getPkId(), e.getMessage());
// 1. 解析预约时间段
String[] timeRange = order.getSwapDuration().split("-");
if (timeRange.length != 2) {
log.error("预约时间段格式错误订单ID: {}", order.getPkId());
continue;
}
// 2. 计算预约结束时间
Date reservationDate = order.getReservationTime();
String endTimeStr = timeRange[1].trim();
Date endTime = DateUtil.parse(DateUtil.format(reservationDate, "yyyy-MM-dd") + " " + endTimeStr,
"yyyy-MM-dd HH:mm");
// 3. 添加30分钟缓冲期
Date expireTime = DateUtil.offsetMinute(endTime, 30);
// 4. 判断是否过期
if (currentTime.after(expireTime)) {
order.setStatus(4); // 设置为过期状态
orderSwapBatteryPreDao.updateById(order);
// 发送公众号过期提醒
// templateMessageService.preOrderMessageSend(order);
expiredCount++;
log.info("预约单已过期订单ID: {}, 预约时间: {}, 过期时间: {}",
order.getSourceId(),
DateUtil.format(order.getReservationTime(), "yyyy-MM-dd HH:mm:ss"),
DateUtil.format(expireTime, "yyyy-MM-dd HH:mm:ss"));
}
} catch (Exception e) {
log.error("处理预约单过期失败,预约人:{}订单ID: {}, 错误信息: {}",
order.getUname(), order.getPkId(), e.getMessage());
}
}

View File

@ -124,4 +124,4 @@ hbyt:
order_to_pay_template_id: IE0_RGuN5ufU4GFrCgM9JeUfvlWfbneEuUMDsn0RBQs
order_end_template_id: C5-AGh67aFXChQONqSwxaRrJgFrn_Z25VTlTk0jHSUY
wallet_recharge_template_id: 8JXsn_VkI0S0YZSbT2EKmV_zOxyudo4IsBLeU7V-SFk
order_to_pay_template_id2: K6cdaBOkxGJpah0vsz5rq5UBID04mk-eEWp2XM0KyA0