支付取消bug:
当用户支付后,订单处于等待回调状态,且在程序里此时没有任何方法可以判断订单此时的状态,如果此时定时取消任务启动,会认为订单还处于待支付中,就会将订单取消。
订单支付后,显示订单未支付bug:
用户第一次支付,订单此时关联的是第一次生成的外部订单,当用户完成支付后,订单处于等待回调状态,如果此时再次调用支付,订单就会关联第二次支付的外部订单,而用户实际支付的是第一次的外部订单。
以上解决办法就是加一个状态,考虑到多实例部署时的状态共享问题,可以使用redis实现:
多商户代码:
文件 :src/main/java/com/zbkj/service/service/impl/PayServiceImpl.java
@Resource//引入redis操作工具
private RedisUtil redisUtil;
@Override
public OrderPayResultResponse payment(OrderPayRequest orderPayRequest) {
//。。。
//源代码中的校验。。。
//改动==================
String KEY = "ORDER:PAID:" + order.getOrderNo();
Boolean setIfAbsent = redisUtil.getRedisTemplate().opsForValue().setIfAbsent(KEY, 1, Duration.ofMinutes(3));
//如果设置成功说明第一次支付,失败则是重复支付
if (!Boolean.TRUE.equals(setIfAbsent)) {
throw new CrmebException(OrderResultCode.ORDER_PAID);
}
try {
//支付处理。。。
return response;
} catch (Exception e) {
//失败删除
redisUtil.getRedisTemplate().delete(KEY);
throw new RuntimeException(e);
}
//改动==================
}
修改订单取消逻辑
文件:src/main/java/com/zbkj/service/service/impl/OrderTaskServiceImpl.java
/**
* 支付订单自动取消
*
* @param orderNo 订单编号
*/
private Boolean orderAutoCancel(String orderNo) {
Order order = orderService.getByOrderNo(orderNo);
if (ObjectUtil.isNull(order)) {
logger.error("自动取消支付订单,订单不存在,订单号为:{}", orderNo);
return Boolean.TRUE;
}
if (order.getPaid()) {
return Boolean.TRUE;
}
if (order.getStatus().equals(OrderConstants.ORDER_STATUS_CANCEL)) {
return Boolean.TRUE;
}
if (!order.getCancelStatus().equals(OrderConstants.ORDER_CANCEL_STATUS_NORMAL)) {
return Boolean.TRUE;
}
//改动==================
Boolean exists = redisUtil.exists("ORDER:PAID:" + order.getOrderNo());
//处于待支付状态 并且redis中有支付过的痕迹
if (Objects.equals(order.getStatus(), 0) && Boolean.TRUE.equals(exists)) {
//继续让其循环
return Boolean.FALSE;
}
//改动==================
// 获取过期时间
DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
long between = DateUtil.between(cancelTime, DateUtil.date(), DateUnit.SECOND, false);
if (between < 0) {// 未到过期时间继续循环
return Boolean.FALSE;
}
return commonOrderCancel(order, "auto");
}
单商户代码
文件:com.zbkj.service.service.impl.OrderPayServiceImpl.java
@Override
public OrderPayResultResponse payment(OrderPayRequest orderPayRequest, String ip){
//。。。。。。
if (user.getIntegral() < storeOrder.getUseIntegral()) {
throw new CrmebException("用户积分不足");
}
//改动==================
String KEY = "ORDER:PAID:" + storeOrder.getOrderId();
Boolean setIfAbsent = redisUtil.getRedisTemplate().opsForValue().setIfAbsent(KEY, 1, Duration.ofMinutes(3));
//如果设置成功说明第一次支付,失败则是重复支付
if (!Boolean.TRUE.equals(setIfAbsent)) {
throw new CrmebException(OrderResultCode.ORDER_PAID);
}
try{
//处理支付的代码。。。
return response;
}catch (Exception e) {
//失败删除
redisUtil.getRedisTemplate().delete(KEY);
throw new RuntimeException(e);
}
//改动==================
}
文件:com.zbkj.service.service.impl.StoreOrderTaskServiceImpl.java
/**
* 支付订单自动取消
*
* @param orderNo 订单编号
*/
private Boolean orderAutoCancel(String orderNo) {
Order order = orderService.getByOrderNo(orderNo);
if (ObjectUtil.isNull(order)) {
logger.error("自动取消支付订单,订单不存在,订单号为:{}", orderNo);
return Boolean.TRUE;
}
if (order.getPaid()) {
return Boolean.TRUE;
}
if (order.getStatus().equals(OrderConstants.ORDER_STATUS_CANCEL)) {
return Boolean.TRUE;
}
if (!order.getCancelStatus().equals(OrderConstants.ORDER_CANCEL_STATUS_NORMAL)) {
return Boolean.TRUE;
}
//改动==================
Boolean exists = redisUtil.exists("ORDER:PAY:" + order.getOrderNo());
//处于待支付状态 并且redis中有支付过的痕迹
if (Objects.equals(order.getStatus(), 0) && Boolean.TRUE.equals(exists)) {
return Boolean.FALSE;
}
//改动==================
// 获取过期时间
DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
long between = DateUtil.between(cancelTime, DateUtil.date(), DateUnit.SECOND, false);
if (between < 0) {// 未到过期时间继续循环
return Boolean.FALSE;
}
return commonOrderCancel(order, "auto");
}