ソースを参照

mall + pay:
1. bar 扫码支付成功后,额外返回 notify
2. notify 在支付回调时,增加幂等处理

YunaiV 2 年 前
コミット
cad508def6

+ 5 - 9
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedRespDTO.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.framework.pay.core.client.dto.order;
 package cn.iocoder.yudao.framework.pay.core.client.dto.order;
 
 
+import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
-import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
 import lombok.Data;
 import lombok.Data;
 
 
 /**
 /**
@@ -24,19 +24,15 @@ public class PayOrderUnifiedRespDTO {
     private String displayContent;
     private String displayContent;
 
 
     /**
     /**
-     * 支付状态
+     * 同步的通知信息
      *
      *
-     * 枚举 {@link PayOrderStatusRespEnum} 类
+     * 目前只有 bar 条码支付才会出现,它是支付发起时,直接返回是否支付成功的,而其它支付还是异步通知
      */
      */
-    private Integer status;
+    private PayOrderNotifyRespDTO notify;
 
 
     public PayOrderUnifiedRespDTO(String displayMode, String displayContent) {
     public PayOrderUnifiedRespDTO(String displayMode, String displayContent) {
-        this(displayMode, displayContent, PayOrderStatusRespEnum.WAITING.getStatus());
-    }
-
-    public PayOrderUnifiedRespDTO(String displayMode, String displayContent, Integer status) {
         this.displayMode = displayMode;
         this.displayMode = displayMode;
         this.displayContent = displayContent;
         this.displayContent = displayContent;
-        this.status = status;
     }
     }
+
 }
 }

+ 9 - 3
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java

@@ -5,13 +5,13 @@ import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
-import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
 import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
 import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
 import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
 import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
 import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.constant.WxPayConstants;
@@ -70,9 +70,15 @@ public class WxBarPayClient extends AbstractWxPayClient {
             try {
             try {
                 WxPayMicropayResult response = client.micropay(request);
                 WxPayMicropayResult response = client.micropay(request);
                 // 支付成功(例如说,用户输入了密码)
                 // 支付成功(例如说,用户输入了密码)
+                PayOrderNotifyRespDTO notify = PayOrderNotifyRespDTO.builder()
+                        .orderExtensionNo(response.getOutTradeNo())
+                        .channelOrderNo(response.getTransactionId())
+                        .channelUserId(response.getOpenid())
+                        .successTime(parseDateV2(response.getTimeEnd()))
+                        .build();
                 return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.BAR_CODE.getMode(),
                 return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.BAR_CODE.getMode(),
-                        JsonUtils.toJsonString(response),
-                        PayOrderStatusRespEnum.SUCCESS.getStatus());
+                        JsonUtils.toJsonString(response))
+                        .setNotify(notify);
             } catch (WxPayException ex) {
             } catch (WxPayException ex) {
                 // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理
                 // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理
                 // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。
                 // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。

+ 1 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java

@@ -25,6 +25,7 @@ public interface ErrorCodeConstants {
     ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
     ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
     ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
     ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
     ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
     ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
+    ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
 
 
     // ========== ORDER 模块(拓展单) 1007003000 ==========
     // ========== ORDER 模块(拓展单) 1007003000 ==========
     ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
     ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");

+ 3 - 5
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java

@@ -1,19 +1,17 @@
 package cn.iocoder.yudao.module.pay.controller.admin.order.vo;
 package cn.iocoder.yudao.module.pay.controller.admin.order.vo;
 
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
 
 
 @Schema(description = "管理后台 - 支付订单提交 Response VO")
 @Schema(description = "管理后台 - 支付订单提交 Response VO")
 @Data
 @Data
 public class PayOrderSubmitRespVO {
 public class PayOrderSubmitRespVO {
 
 
+    @Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") // 参见 PayOrderStatusEnum 枚举
+    private Integer status;
+
     @Schema(description = "展示模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "url") // 参见 PayDisplayModeEnum 枚举
     @Schema(description = "展示模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "url") // 参见 PayDisplayModeEnum 枚举
     private String displayMode;
     private String displayMode;
-
     @Schema(description = "展示内容", requiredMode = Schema.RequiredMode.REQUIRED)
     @Schema(description = "展示内容", requiredMode = Schema.RequiredMode.REQUIRED)
     private String displayContent;
     private String displayContent;
 
 

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http

@@ -19,7 +19,7 @@ tenant-id: {{appTenentId}}
   "id": 202,
   "id": 202,
   "channelCode": "wx_bar",
   "channelCode": "wx_bar",
   "channelExtras": {
   "channelExtras": {
-    "authCode": "132990241553789274"
+    "authCode": "134042110834344848"
   }
   }
 }
 }
 
 

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java

@@ -93,7 +93,7 @@ public interface PayOrderConvert {
 
 
     PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO, String userIp);
     PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO, String userIp);
 
 
-    PayOrderSubmitRespVO convert(PayOrderUnifiedRespDTO bean);
+    PayOrderSubmitRespVO convert(PayOrderDO order, PayOrderUnifiedRespDTO unifiedRespDTO);
 
 
     AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean);
     AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean);
 
 

+ 59 - 32
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.pay.service.order;
 package cn.iocoder.yudao.module.pay.service.order;
 
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Pair;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.pay.config.PayProperties;
 import cn.iocoder.yudao.framework.pay.config.PayProperties;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
@@ -28,6 +30,7 @@ import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
+import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
@@ -41,6 +44,7 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.List;
 import java.util.List;
+import java.util.Objects;
 
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
@@ -109,22 +113,19 @@ public class PayOrderServiceImpl implements PayOrderService {
         }
         }
 
 
         // 创建支付交易单
         // 创建支付交易单
-        order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId());
-        // 商户相关字段
-        order.setNotifyUrl(app.getPayNotifyUrl())
-                .setNotifyStatus(PayOrderNotifyStatusEnum.NO.getStatus());
-        // 订单相关字段
-        order.setStatus(PayOrderStatusEnum.WAITING.getStatus());
-        // 退款相关字段
-        // todo @芋艿 创建支付的订单的退款状态枚举是不是有问题,应该是 PayRefundTypeEnum 吧 您这填写的是 PayOrderNotifyStatusEnum 回调状态枚举
-        order.setRefundStatus(PayOrderNotifyStatusEnum.NO.getStatus())
-                .setRefundTimes(0).setRefundPrice(0L);
+        order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId())
+                // 商户相关字段
+                .setNotifyUrl(app.getPayNotifyUrl()).setNotifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
+                // 订单相关字段
+                .setStatus(PayOrderStatusEnum.WAITING.getStatus())
+                // 退款相关字段
+                .setRefundStatus(PayRefundTypeEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0L);
         orderMapper.insert(order);
         orderMapper.insert(order);
-        // 最终返回
         return order.getId();
         return order.getId();
     }
     }
 
 
     @Override
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) {
     public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) {
         // 1. 获得 PayOrderDO ,并校验其是否存在
         // 1. 获得 PayOrderDO ,并校验其是否存在
         PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId());
         PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId());
@@ -150,9 +151,15 @@ public class PayOrderServiceImpl implements PayOrderService {
                 .setAmount(order.getPrice()).setExpireTime(order.getExpireTime());
                 .setAmount(order.getPrice()).setExpireTime(order.getExpireTime());
         PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO);
         PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO);
 
 
-        // TODO 轮询三方接口,是否已经支付的任务
+        // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
+        if (unifiedOrderRespDTO.getNotify() != null) {
+            notifyPayOrderSuccess(channel, unifiedOrderRespDTO.getNotify(), null);
+            // 此处需要读取最新的状态
+            order = orderMapper.selectById(order.getId());
+        }
+
         // 返回成功
         // 返回成功
-        return PayOrderConvert.INSTANCE.convert(unifiedOrderRespDTO);
+        return PayOrderConvert.INSTANCE.convert(order, unifiedOrderRespDTO);
     }
     }
 
 
     private PayOrderDO validatePayOrderCanSubmit(Long id) {
     private PayOrderDO validatePayOrderCanSubmit(Long id) {
@@ -163,6 +170,9 @@ public class PayOrderServiceImpl implements PayOrderService {
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         }
+        if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
+            throw exception(ErrorCodeConstants.PAY_ORDER_IS_EXPIRED);
+        }
         return order;
         return order;
     }
     }
 
 
@@ -214,17 +224,22 @@ public class PayOrderServiceImpl implements PayOrderService {
     public void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) {
     public void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) {
         // 校验支付渠道是否有效
         // 校验支付渠道是否有效
         PayChannelDO channel = channelService.validPayChannel(channelId);
         PayChannelDO channel = channelService.validPayChannel(channelId);
-        TenantUtils.execute(channel.getTenantId(), () -> {
-            // 1. 更新 PayOrderExtensionDO 支付成功
-            PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify.getOrderExtensionNo(),
-                    rawNotify);
-            // 2. 更新 PayOrderDO 支付成功
-            PayOrderDO order = updatePayOrderSuccess(channel, orderExtension, notify);
-
-            // 3. 插入支付通知记录
-            notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
-                    .type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getId()).build());
-        });
+        // 更新支付订单为已支付
+        TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrderSuccess(channel, notify, rawNotify));
+    }
+
+    private void notifyPayOrderSuccess(PayChannelDO channel, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) {
+        // 1. 更新 PayOrderExtensionDO 支付成功
+        PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify.getOrderExtensionNo(), rawNotify);
+        // 2. 更新 PayOrderDO 支付成功
+        Pair<Boolean, PayOrderDO> order = updatePayOrderSuccess(channel, orderExtension, notify);
+        if (order.getKey()) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调
+            return;
+        }
+
+        // 3. 插入支付通知记录
+        notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
+                .type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getValue().getId()).build());
     }
     }
 
 
     /**
     /**
@@ -235,15 +250,20 @@ public class PayOrderServiceImpl implements PayOrderService {
      * @return PayOrderExtensionDO 对象
      * @return PayOrderExtensionDO 对象
      */
      */
     private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, PayNotifyReqDTO rawNotify) {
     private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, PayNotifyReqDTO rawNotify) {
-        // 1.1 查询 PayOrderExtensionDO
+        // 1. 查询 PayOrderExtensionDO
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(no);
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(no);
         if (orderExtension == null) {
         if (orderExtension == null) {
             throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND);
             throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND);
         }
         }
+        if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
+            log.info("[updatePayOrderSuccess][支付拓展单({}) 已经是已支付,无需更新为已支付]", orderExtension.getId());
+            return orderExtension;
+        }
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
             throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
             throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         }
-        // 1.2 更新 PayOrderExtensionDO
+
+        // 2. 更新 PayOrderExtensionDO
         int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(),
         int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(),
                 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
                 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
                         .status(PayOrderStatusEnum.SUCCESS.getStatus())
                         .status(PayOrderStatusEnum.SUCCESS.getStatus())
@@ -261,19 +281,26 @@ public class PayOrderServiceImpl implements PayOrderService {
      * @param channel 支付渠道
      * @param channel 支付渠道
      * @param orderExtension 支付拓展单
      * @param orderExtension 支付拓展单
      * @param notify 通知回调
      * @param notify 通知回调
-     * @return PayOrderDO 对象
+     * @return key:是否之前已经成功回调
+     *         value:PayOrderDO 对象
      */
      */
-    private PayOrderDO updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
-                                             PayOrderNotifyRespDTO notify) {
-        // 2.1 判断 PayOrderDO 是否处于待支付
+    private Pair<Boolean, PayOrderDO> updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
+                                                            PayOrderNotifyRespDTO notify) {
+        // 1. 判断 PayOrderDO 是否处于待支付
         PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
         PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
         if (order == null) {
         if (order == null) {
             throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
             throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
         }
         }
+        if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
+                && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
+            log.info("[updatePayOrderSuccess][支付订单({}) 已经是已支付,无需更新为已支付]", order.getId());
+            return Pair.of(true, order);
+        }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         }
-        // 2.2 更新 PayOrderDO
+
+        // 2. 更新 PayOrderDO
         int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
         int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
                 PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
                 PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
                         .channelId(channel.getId()).channelCode(channel.getCode())
                         .channelId(channel.getId()).channelCode(channel.getCode())
@@ -284,7 +311,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
             throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         }
         log.info("[updatePayOrderSuccess][支付订单({}) 更新为已支付]", order.getId());
         log.info("[updatePayOrderSuccess][支付订单({}) 更新为已支付]", order.getId());
-        return order;
+        return Pair.of(false, order);
     }
     }
 
 
 }
 }

+ 3 - 3
yudao-ui-admin/src/views/pay/cashier/index.vue

@@ -27,7 +27,7 @@
       <el-descriptions title="选择微信支付" style="margin-top: 20px;" />
       <el-descriptions title="选择微信支付" style="margin-top: 20px;" />
       <div class="pay-channel-container">
       <div class="pay-channel-container">
         <div class="box" v-for="channel in channels" v-if="channel.code.indexOf('wx_') === 0" :key="channel.code">
         <div class="box" v-for="channel in channels" v-if="channel.code.indexOf('wx_') === 0" :key="channel.code">
-          <img :src="icons[channel.code]">
+          <img :src="channel.icon">
           <div class="title">{{ channel.name }}</div>
           <div class="title">{{ channel.name }}</div>
         </div>
         </div>
       </div>
       </div>
@@ -36,7 +36,7 @@
       <div class="pay-channel-container">
       <div class="pay-channel-container">
         <div class="box" v-for="channel in channels" :key="channel.code"
         <div class="box" v-for="channel in channels" :key="channel.code"
              v-if="channel.code.indexOf('alipay_') === -1 && channel.code.indexOf('wx_') === -1">
              v-if="channel.code.indexOf('alipay_') === -1 && channel.code.indexOf('wx_') === -1">
-          <img :src="icons[channel.code]">
+          <img :src="channel.icon">
           <div class="title">{{ channel.name }}</div>
           <div class="title">{{ channel.name }}</div>
         </div>
         </div>
       </div>
       </div>
@@ -132,7 +132,7 @@ export default {
         code: "wx_lite"
         code: "wx_lite"
       }, {
       }, {
         name: '微信 App 支付',
         name: '微信 App 支付',
-        icon: require("@/assets/images/pay/icon/wx_lite.svg"),
+        icon: require("@/assets/images/pay/icon/wx_app.svg"),
         code: "wx_app"
         code: "wx_app"
       }, {
       }, {
         name: '模拟支付',
         name: '模拟支付',