Browse Source

by gateway:
1. 补全 channel 单元测试
2. 完善部分 order 单元测试

zhijiantianya@gmail.com 1 year ago
parent
commit
3f410c2735
16 changed files with 489 additions and 226 deletions
  1. 5 1
      yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java
  2. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
  3. 31 33
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  4. 3 4
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
  5. 1 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java
  6. 0 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java
  7. 5 9
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java
  8. 5 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
  9. 17 17
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
  10. 12 16
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
  11. 43 44
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
  12. 11 10
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
  13. 6 6
      yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java
  14. 132 4
      yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java
  15. 192 64
      yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
  16. 24 4
      yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql

+ 5 - 1
yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java

@@ -55,6 +55,9 @@ public class RandomUtils {
             }
             return RandomUtil.randomInt();
         });
+        // LocalDateTime
+        PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class,
+                (dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime());
         // Boolean
         PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> {
             // 如果是 deleted 的字段,返回非删除
@@ -82,7 +85,8 @@ public class RandomUtils {
     }
 
     public static LocalDateTime randomLocalDateTime() {
-        return LocalDateTimeUtil.of(randomDate());
+        // 设置 Nano 为零的原因,避免 MySQL、H2 存储不到时间戳
+        return LocalDateTimeUtil.of(randomDate()).withNano(0);
     }
 
     public static Short randomShort() {

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java

@@ -57,7 +57,7 @@ import java.util.*;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
 /**
@@ -308,7 +308,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
         if (payOrder == null) {
             log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
-            throw exception(PAY_ORDER_NOT_FOUND);
+            throw exception(cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND);
         }
         // 校验支付单已支付
         if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {

+ 31 - 33
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java

@@ -10,48 +10,46 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 public interface ErrorCodeConstants {
 
     // ========== APP 模块 1007000000 ==========
-    ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
-    ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
-    ErrorCode PAY_APP_EXIST_ORDER_CANT_DELETE =  new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
-    ErrorCode PAY_APP_EXIST_REFUND_CANT_DELETE =  new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
+    ErrorCode APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
+    ErrorCode APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
+    ErrorCode APP_EXIST_ORDER_CANT_DELETE =  new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
+    ErrorCode APP_EXIST_REFUND_CANT_DELETE =  new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
 
     // ========== CHANNEL 模块 1007001000 ==========
-    ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
-    ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
-    ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");
-    ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");
-    ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");
+    ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
+    ErrorCode CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
+    ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
 
     // ========== ORDER 模块 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_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
-    ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
-    ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
+    ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
+    ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
+    ErrorCode ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
+    ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
+    ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
 
     // ========== ORDER 模块(拓展单) 1007003000 ==========
-    ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
-    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
+    ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
+    ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
 
     // ========== 支付模块(退款) 1007006000 ==========
-    ErrorCode PAY_REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
-    ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
-    ErrorCode PAY_REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
-    ErrorCode PAY_REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
-    ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
-    ErrorCode PAY_REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
+    ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
+    ErrorCode REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
+    ErrorCode REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
+    ErrorCode REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
+    ErrorCode REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
+    ErrorCode REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
 
     // ========== 示例订单 1007900000 ==========
-    ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
-    ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
-    ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
-    ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
-    ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
+    ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
+    ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
+    ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
+    ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
+    ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
+    ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
 
 }

+ 3 - 4
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java

@@ -17,8 +17,7 @@ import javax.annotation.Resource;
 import javax.annotation.security.PermitAll;
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
 
 @Tag(name = "管理后台 - 支付通知")
 @RestController
@@ -47,7 +46,7 @@ public class PayNotifyController {
         PayClient payClient = payClientFactory.getPayClient(channelId);
         if (payClient == null) {
             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
-            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(CHANNEL_NOT_FOUND);
         }
 
         // 2. 解析通知数据
@@ -68,7 +67,7 @@ public class PayNotifyController {
         PayClient payClient = payClientFactory.getPayClient(channelId);
         if (payClient == null) {
             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
-            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(CHANNEL_NOT_FOUND);
         }
 
         // 2. 解析通知数据

+ 1 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java

@@ -15,6 +15,7 @@ import java.util.Map;
 /**
  * 支付订单拓展 DO
  *
+ * 每次调用支付渠道,都会生成一条对应记录
  *
  * @author 芋道源码
  */

+ 0 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java

@@ -44,12 +44,6 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
                 .orderByDesc("id"));
     }
 
-    default List<PayOrderDO> findByIdListQueryOrderSubject(Collection<Long> idList) {
-        return selectList(new LambdaQueryWrapper<PayOrderDO>()
-                .select(PayOrderDO::getId, PayOrderDO::getSubject)
-                .in(PayOrderDO::getId, idList));
-    }
-
     default Long selectCountByAppId(Long appId) {
         return selectCount(PayOrderDO::getAppId, appId);
     }

+ 5 - 9
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.pay.service.app;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
@@ -9,10 +8,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
 import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
-import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
-import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
-import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 import org.springframework.context.annotation.Lazy;
@@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService {
         validateAppExists(id);
         // 校验关联数据是否存在
         if (orderService.getOrderCountByAppId(id) > 0) {
-            throw exception(PAY_APP_EXIST_ORDER_CANT_DELETE);
+            throw exception(APP_EXIST_ORDER_CANT_DELETE);
         }
         if (refundService.getRefundCountByAppId(id) > 0) {
-            throw exception(PAY_APP_EXIST_REFUND_CANT_DELETE);
+            throw exception(APP_EXIST_REFUND_CANT_DELETE);
         }
 
         // 删除
@@ -89,7 +85,7 @@ public class PayAppServiceImpl implements PayAppService {
 
     private void validateAppExists(Long id) {
         if (appMapper.selectById(id) == null) {
-            throw exception(PAY_APP_NOT_FOUND);
+            throw exception(APP_NOT_FOUND);
         }
     }
 
@@ -113,11 +109,11 @@ public class PayAppServiceImpl implements PayAppService {
         PayAppDO app = appMapper.selectById(id);
         // 校验是否存在
         if (app == null) {
-            throw exception(ErrorCodeConstants.PAY_APP_NOT_FOUND);
+            throw exception(ErrorCodeConstants.APP_NOT_FOUND);
         }
         // 校验是否禁用
         if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
-            throw exception(ErrorCodeConstants.PAY_APP_IS_DISABLE);
+            throw exception(ErrorCodeConstants.APP_IS_DISABLE);
         }
         return app;
     }

+ 5 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java

@@ -32,8 +32,7 @@ import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 
 /**
  * 支付渠道 Service 实现类
@@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService {
         // 解析配置
         Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass();
         if (ObjectUtil.isNull(payClass)) {
-            throw exception(CHANNEL_NOT_EXISTS);
+            throw exception(CHANNEL_NOT_FOUND);
         }
         PayClientConfig config = JsonUtils.parseObject2(configStr, payClass);
         Assert.notNull(config);
@@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService {
     private PayChannelDO validateChannelExists(Long id) {
         PayChannelDO channel = channelMapper.selectById(id);
         if (channel == null) {
-            throw exception(CHANNEL_NOT_EXISTS);
+            throw exception(CHANNEL_NOT_FOUND);
         }
         return channel;
     }
@@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService {
 
     private void validPayChannel(PayChannelDO channel) {
         if (channel == null) {
-            throw exception(ErrorCodeConstants.PAY_CHANNEL_NOT_FOUND);
+            throw exception(CHANNEL_NOT_FOUND);
         }
         if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
-            throw exception(ErrorCodeConstants.PAY_CHANNEL_IS_DISABLE);
+            throw exception(CHANNEL_IS_DISABLE);
         }
     }
 

+ 17 - 17
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java

@@ -119,7 +119,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
                 new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
                         .setPayChannelCode(payOrder.getChannelCode()));
         if (updateCount == 0) {
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
+            throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
         }
     }
 
@@ -137,44 +137,44 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         // 1.1 校验订单是否存在
         PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
         if (order == null) {
-            throw exception(PAY_DEMO_ORDER_NOT_FOUND);
+            throw exception(DEMO_ORDER_NOT_FOUND);
         }
         // 1.2 校验订单未支付
         if (order.getPayStatus()) {
             log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
                     id, toJsonString(order));
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
+            throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
         }
         // 1.3 校验支付订单匹配
         if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
             log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
                     id, payOrderId, toJsonString(order));
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
+            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
         }
 
         // 2.1 校验支付单是否存在
         PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
         if (payOrder == null) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
-            throw exception(PAY_ORDER_NOT_FOUND);
+            throw exception(ORDER_NOT_FOUND);
         }
         // 2.2 校验支付单已支付
         if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
                     id, payOrderId, toJsonString(payOrder));
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
+            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
         }
         // 2.3 校验支付金额一致
         if (notEqual(payOrder.getPrice(), order.getPrice())) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
                     id, payOrderId, toJsonString(order), toJsonString(payOrder));
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
+            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
         }
         // 2.4 校验支付订单匹配(二次)
         if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
             log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
                     id, payOrderId, toJsonString(payOrder));
-            throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
+            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
         }
         return payOrder;
     }
@@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         // 校验订单是否存在
         PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
         if (order == null) {
-            throw exception(PAY_DEMO_ORDER_NOT_FOUND);
+            throw exception(DEMO_ORDER_NOT_FOUND);
         }
         // 校验订单是否支付
         if (!order.getPayStatus()) {
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID);
+            throw exception(DEMO_ORDER_REFUND_FAIL_NOT_PAID);
         }
         // 校验订单是否已退款
         if (order.getPayRefundId() != null) {
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUNDED);
         }
         return order;
     }
@@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         // 1.1 校验示例订单
         PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
         if (order == null) {
-            throw exception(PAY_DEMO_ORDER_NOT_FOUND);
+            throw exception(DEMO_ORDER_NOT_FOUND);
         }
         // 1.2 校验退款订单匹配
         if (Objects.equals(order.getPayOrderId(), payRefundId)) {
             log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
                     id, payRefundId, toJsonString(order));
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
         }
 
         // 2.1 校验退款订单
         PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
         if (payRefund == null) {
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
         }
         // 2.2
         if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
         }
         // 2.3 校验退款金额一致
         if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
             log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
                     id, payRefundId, toJsonString(order), toJsonString(payRefund));
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
         }
         // 2.4 校验退款订单匹配(二次)
         if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
             log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
                     id, payRefundId, toJsonString(payRefund));
-            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
+            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
         }
         return payRefund;
     }

+ 12 - 16
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java

@@ -49,41 +49,37 @@ public interface PayOrderService {
     Long getOrderCountByAppId(Long appId);
 
     /**
-     * 获得支付订单
-     * 分页
+     * 获得支付订单分页
      *
      * @param pageReqVO 分页查询
-     * @return 支付订单
-     * 分页
+     * @return 支付订单分页
      */
     PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO);
 
     /**
-     * 获得支付订单
-     * 列表, 用于 Excel 导出
+     * 获得支付订单列表, 用于 Excel 导出
      *
      * @param exportReqVO 查询条件
-     * @return 支付订单
-     * 列表
+     * @return 支付订单列表
      */
     List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
 
     /**
-     * 根据 ID 集合获取只包含商品名称的订单集合
+     * 获得支付订单列表
      *
-     * @param idList 订单 ID 集合
-     * @return 只包含商品名称的订单集合
+     * @param ids 订单 ID 集合
+     * @return 支付订单列表
      */
-    List<PayOrderDO> getOrderSubjectList(Collection<Long> idList);
+    List<PayOrderDO> getOrderList(Collection<Long> ids);
 
     /**
-     * 根据订单 ID 集合获取订单商品名称Map集合
+     * 获得支付订单 Map
      *
      * @param ids 订单 ID 集合
-     * @return 订单商品 map 集合
+     * @return 支付订单 Map 集合
      */
     default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {
-        List<PayOrderDO> list = getOrderSubjectList(ids);
+        List<PayOrderDO> list = getOrderList(ids);
         return CollectionUtils.convertMap(list, PayOrderDO::getId);
     }
 
@@ -122,4 +118,4 @@ public interface PayOrderService {
      */
     void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
 
-}
+}

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

@@ -102,10 +102,9 @@ public class PayOrderServiceImpl implements PayOrderService {
         return orderMapper.selectList(exportReqVO);
     }
 
-    // TODO @艿艿:需要优化。不确定这个方法的作用
     @Override
-    public List<PayOrderDO> getOrderSubjectList(Collection<Long> idList) {
-        return orderMapper.findByIdListQueryOrderSubject(idList);
+    public List<PayOrderDO> getOrderList(Collection<Long> ids) {
+        return orderMapper.selectBatchIds(ids);
     }
 
     @Override
@@ -165,7 +164,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             notifyPayOrder(channel, unifiedOrderResp);
             // 如有渠道错误码,则抛出业务异常,提示用户
             if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
-                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
+                throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
                         unifiedOrderResp.getChannelErrorMsg());
             }
             // 此处需要读取最新的状态
@@ -177,13 +176,13 @@ public class PayOrderServiceImpl implements PayOrderService {
     private PayOrderDO validateOrderCanSubmit(Long id) {
         PayOrderDO order = orderMapper.selectById(id);
         if (order == null) { // 是否存在
-            throw exception(PAY_ORDER_NOT_FOUND);
+            throw exception(ORDER_NOT_FOUND);
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_STATUS_IS_NOT_WAITING);
         }
         if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
-            throw exception(PAY_ORDER_IS_EXPIRED);
+            throw exception(ORDER_IS_EXPIRED);
         }
         return order;
     }
@@ -196,7 +195,7 @@ public class PayOrderServiceImpl implements PayOrderService {
         PayClient client = payClientFactory.getPayClient(channel.getId());
         if (client == null) {
             log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
-            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(CHANNEL_NOT_FOUND);
         }
         return channel;
     }
@@ -238,33 +237,6 @@ public class PayOrderServiceImpl implements PayOrderService {
         TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
     }
 
-    @Override
-    public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
-        PayOrderDO order = orderMapper.selectById(id);
-        if (order == null) {
-            throw exception(PAY_ORDER_NOT_FOUND);
-        }
-        if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
-            throw exception(PAY_REFUND_PRICE_EXCEED);
-        }
-        if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
-            throw exception(PAY_REFUND_PRICE_EXCEED);
-        }
-
-        // 更新订单
-        PayOrderDO updateObj = new PayOrderDO()
-                .setRefundPrice(order.getRefundPrice() + incrRefundPrice)
-                .setRefundTimes(order.getRefundTimes() + 1);
-        if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
-            updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
-                    .setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
-        } else {
-            updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
-                    .setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
-        }
-        orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
-    }
-
     private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
         // 情况一:支付成功的回调
         if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
@@ -301,21 +273,21 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 1. 查询 PayOrderExtensionDO
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
         if (orderExtension == null) {
-            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
+            throw exception(ORDER_EXTENSION_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
             log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
             return orderExtension;
         }
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderExtensionDO
         int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
                 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
         return orderExtension;
@@ -335,7 +307,7 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 1. 判断 PayOrderDO 是否处于待支付
         PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
         if (order == null) {
-            throw exception(PAY_ORDER_NOT_FOUND);
+            throw exception(ORDER_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
                 && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
@@ -343,7 +315,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             return Pair.of(true, order);
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderDO
@@ -354,7 +326,7 @@ public class PayOrderServiceImpl implements PayOrderService {
                         .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
                         .notifyTime(LocalDateTime.now()).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
         return Pair.of(false, order);
@@ -368,7 +340,7 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 1. 查询 PayOrderExtensionDO
         PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
         if (orderExtension == null) {
-            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
+            throw exception(ORDER_EXTENSION_NOT_FOUND);
         }
         if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
             log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
@@ -380,7 +352,7 @@ public class PayOrderServiceImpl implements PayOrderService {
             return;
         }
         if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新 PayOrderExtensionDO
@@ -388,9 +360,36 @@ public class PayOrderServiceImpl implements PayOrderService {
                 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
                         .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
     }
 
+    @Override
+    public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
+        PayOrderDO order = orderMapper.selectById(id);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+        if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
+            throw exception(REFUND_PRICE_EXCEED);
+        }
+        if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
+            throw exception(REFUND_PRICE_EXCEED);
+        }
+
+        // 更新订单
+        PayOrderDO updateObj = new PayOrderDO()
+                .setRefundPrice(order.getRefundPrice() + incrRefundPrice)
+                .setRefundTimes(order.getRefundTimes() + 1);
+        if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
+            updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
+                    .setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
+        } else {
+            updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
+                    .setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
+        }
+        orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
+    }
+
 }

+ 11 - 10
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java

@@ -43,6 +43,7 @@ import java.util.List;
 
 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.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
 
 /**
  * 退款订单 Service 实现类
@@ -106,13 +107,13 @@ public class PayRefundServiceImpl implements PayRefundService {
         PayClient client = payClientFactory.getPayClient(channel.getId());
         if (client == null) {
             log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
-            throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(CHANNEL_NOT_FOUND);
         }
         // 1.4 校验退款订单是否已经存在
         PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
                 app.getId(), reqDTO.getMerchantRefundId());
         if (refund != null) {
-            throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS);
+            throw exception(ErrorCodeConstants.REFUND_EXISTS);
         }
 
         // 2.1 插入退款单
@@ -153,25 +154,25 @@ public class PayRefundServiceImpl implements PayRefundService {
     private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
         PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
         if (order == null) {
-            throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
+            throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
         }
         // 校验状态,必须是支付状态
         if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
-            throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
+            throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS);
         }
 
         // 是否已经全额退款
         if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) {
-            throw exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
+            throw exception(ErrorCodeConstants.REFUND_ALL_REFUNDED);
         }
         // 校验金额 退款金额不能大于原定的金额
         if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
-            throw exception(ErrorCodeConstants.PAY_REFUND_PRICE_EXCEED);
+            throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
         }
         // 是否有退款中的订单
         if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
                 PayRefundStatusEnum.WAITING.getStatus()) > 0) {
-            throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING);
+            throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING);
         }
         return order;
     }
@@ -230,13 +231,13 @@ public class PayRefundServiceImpl implements PayRefundService {
         PayRefundDO refund = refundMapper.selectByAppIdAndNo(
                 channel.getAppId(), notify.getOutRefundNo());
         if (refund == null) {
-            throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND);
+            throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
         }
         if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
             return;
         }
         if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
-            throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
         }
 
         // 1.2 更新 PayRefundDO
@@ -247,7 +248,7 @@ public class PayRefundServiceImpl implements PayRefundService {
                 .setChannelNotifyData(toJsonString(notify));
         int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
         if (updateCounts == 0) { // 校验状态,必须是等待状态
-            throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
         }
 
         // 2. 更新订单

+ 6 - 6
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java

@@ -90,7 +90,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
         PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
                 o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
         // 调用, 并断言异常
-        assertServiceException(() -> appService.updateApp(reqVO), PAY_APP_NOT_FOUND);
+        assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_FOUND);
     }
 
     @Test
@@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> appService.deleteApp(id), PAY_APP_NOT_FOUND);
+        assertServiceException(() -> appService.deleteApp(id), APP_NOT_FOUND);
     }
 
     @Test
@@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
         when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L);
 
         // 调用, 并断言异常
-        assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_ORDER_CANT_DELETE);
+        assertServiceException(() -> appService.deleteApp(id), APP_EXIST_ORDER_CANT_DELETE);
     }
 
     @Test
@@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
         when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L);
 
         // 调用, 并断言异常
-        assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_REFUND_CANT_DELETE);
+        assertServiceException(() -> appService.deleteApp(id), APP_EXIST_REFUND_CANT_DELETE);
     }
 
     @Test
@@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
 
     @Test
     public void testValidPayApp_notFound() {
-        assertServiceException(() -> appService.validPayApp(randomLongId()), PAY_APP_NOT_FOUND);
+        assertServiceException(() -> appService.validPayApp(randomLongId()), APP_NOT_FOUND);
     }
 
     @Test
@@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
         Long id = dbApp.getId();
 
         // 调用,并断言异常
-        assertServiceException(() -> appService.validPayApp(id), PAY_APP_IS_DISABLE);
+        assertServiceException(() -> appService.validPayApp(id), APP_IS_DISABLE);
     }
 
 }

+ 132 - 4
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java

@@ -26,8 +26,7 @@ import java.util.List;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 @Import({PayChannelServiceImpl.class})
@@ -51,6 +50,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
         channelService.setChannelCache(null);
     }
 
+    @Test
+    public void testInitLocalCache() {
+        // mock 数据
+        PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
+                o -> o.setConfig(randomWxPayClientConfig()));
+        channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
+
+        // 调用
+        channelService.initLocalCache();
+        // 校验缓存
+        assertEquals(1, channelService.getChannelCache().size());
+        assertEquals(dbChannel, channelService.getChannelCache().get(0));
+    }
+
+    @Test
+    public void testRefreshLocalCache() {
+        // mock 数据 01
+        PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
+                o -> o.setConfig(randomWxPayClientConfig()));
+        channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
+        channelService.initLocalCache();
+        // mock 数据 02
+        PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class,
+                o -> o.setConfig(randomWxPayClientConfig()));
+        channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
+
+        // 调用
+        channelService.refreshLocalCache();
+        // 校验缓存
+        assertEquals(2, channelService.getChannelCache().size());
+        assertEquals(dbChannel, channelService.getChannelCache().get(0));
+        assertEquals(dbChannel02, channelService.getChannelCache().get(1));
+    }
+
     @Test
     public void testCreateChannel_success() {
         // 准备参数
@@ -125,7 +158,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
         });
 
         // 调用, 并断言异常
-        assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS);
+        assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_FOUND);
     }
 
     @Test
@@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS);
+        assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_FOUND);
     }
 
     @Test
@@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
         assertPojoEquals(channel, dbChannel);
     }
 
+    @Test
+    public void testValidPayChannel_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_NOT_FOUND);
+    }
+
+    @Test
+    public void testValidPayChannel_isDisable() {
+        // mock 数据
+        PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setStatus(CommonStatusEnum.DISABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbChannel.getId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_IS_DISABLE);
+    }
+
+    @Test
+    public void testValidPayChannel_success() {
+        // mock 数据
+        PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbChannel.getId();
+
+        // 调用
+        PayChannelDO channel = channelService.validPayChannel(id);
+        // 断言异常
+        assertPojoEquals(channel, dbChannel);
+    }
+
+    @Test
+    public void testValidPayChannel_appIdAndCode() {
+        // mock 数据
+        PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long appId = dbChannel.getAppId();
+        String code = dbChannel.getCode();
+
+        // 调用
+        PayChannelDO channel = channelService.validPayChannel(appId, code);
+        // 断言异常
+        assertPojoEquals(channel, dbChannel);
+    }
+
+    @Test
+    public void testGetEnableChannelList() {
+        // 准备参数
+        Long appId = randomLongId();
+        // mock 数据 01(enable 不匹配)
+        PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setStatus(CommonStatusEnum.DISABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据
+        // mock 数据 02(appId 不匹配)
+        PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
+        // mock 数据 03
+        PayChannelDO dbChannel03 = randomPojo(PayChannelDO.class, o -> {
+            o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
+            o.setConfig(randomAlipayPayClientConfig());
+            o.setAppId(appId);
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        channelMapper.insert(dbChannel03);// @Sql: 先插入出一条存在的数据
+
+        // 调用
+        List<PayChannelDO> channel = channelService.getEnableChannelList(appId);
+        // 断言异常
+        assertPojoEquals(channel, dbChannel03);
+    }
+
     public WxPayClientConfig randomWxPayClientConfig() {
         return new WxPayClientConfig()
                 .setAppId(randomString())

+ 192 - 64
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java

@@ -3,32 +3,53 @@ package cn.iocoder.yudao.module.pay.service.order;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.RandomUtil;
 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.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
+import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
+import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
+import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
 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.PayOrderRefundStatusEnum;
+import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 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.notify.PayNotifyService;
 import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
+import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.List;
 
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.equalsAny;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
  * {@link PayOrderServiceImpl} 的单元测试类
@@ -43,6 +64,8 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
 
     @Resource
     private PayOrderMapper orderMapper;
+    @Resource
+    private PayOrderExtensionMapper orderExtensionMapper;
 
     @MockBean
     private PayClientFactory payClientFactory;
@@ -55,42 +78,18 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
     @MockBean
     private PayNotifyService notifyService;
 
-    public String generateNo() {
-        return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999);
-    }
-
     @Test
     public void testGetOrderPage() {
-
-        String merchantOrderId = generateNo();
-        String channelOrderId = generateNo();
-
         // mock 数据
         PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
             o.setAppId(1L);
-            o.setChannelId(1L);
+            o.setChannelId(10L);
             o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
-            o.setMerchantOrderId(merchantOrderId);
-            o.setSubject("灿灿子的炸弹猫");
-            o.setBody("斌斌子送给灿灿子的炸弹猫");
-            o.setNotifyUrl("https://hc.com/lbh");
+            o.setMerchantOrderId("110");
             o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
-            o.setPrice(10000);
-            o.setChannelFeeRate(0.01);
-            o.setChannelFeePrice(1L);
             o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
-            o.setUserIp("127.0.0.1");
-            o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
-            o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
-            o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
-            o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
-            o.setSuccessExtensionId(1L);
+            o.setCreateTime(buildTime(2018, 1, 15));
             o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
-            o.setRefundTimes(0);
-            o.setRefundPrice(0);
-            o.setChannelUserId("1008611");
-            o.setChannelOrderNo(channelOrderId);
-            o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
         });
         orderMapper.insert(dbOrder);
         // 测试 appId 不匹配
@@ -100,7 +99,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
         // 测试 channelCode 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
         // 测试 merchantOrderId 不匹配
-        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));
+        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
         // 测试 notifyStatus 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
         // 测试 status 不匹配
@@ -108,58 +107,38 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
         // 测试 refundStatus 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
         // 测试 createTime 不匹配
-        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
-                1))));
+        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
         // 准备参数
         PayOrderPageReqVO reqVO = new PayOrderPageReqVO();
         reqVO.setAppId(1L);
-        reqVO.setChannelId(1L);
+        reqVO.setChannelId(10L);
         reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
-        reqVO.setMerchantOrderId(merchantOrderId);
+        reqVO.setMerchantOrderId("110");
         reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
         reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
         reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
-        reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
+        reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
+
         // 调用
         PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
         // 断言
         assertEquals(1, pageResult.getTotal());
         assertEquals(1, pageResult.getList().size());
         assertPojoEquals(dbOrder, pageResult.getList().get(0));
-        // assertEquals(0, dbOrder.getUpdateTime().compareTo(pageResult.getList().get(0).getUpdateTime()));
     }
 
     @Test
     public void testGetOrderList() {
         // mock 数据
-        String merchantOrderId = generateNo();
-        String channelOrderId = generateNo();
         PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
             o.setAppId(1L);
-            o.setChannelId(1L);
+            o.setChannelId(10L);
             o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
-            o.setMerchantOrderId(merchantOrderId);
-            o.setSubject("灿灿子的炸弹猫");
-            o.setBody("斌斌子送给灿灿子的炸弹猫");
-            o.setNotifyUrl("https://hc.com/lbh");
+            o.setMerchantOrderId("110");
             o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
-            o.setPrice(10000);
-            o.setChannelFeeRate(0.01);
-            o.setChannelFeePrice(1L);
             o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
-            o.setUserIp("127.0.0.1");
-            o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
-            o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
-            o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
-            o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
-            o.setSuccessExtensionId(1L);
+            o.setCreateTime(buildTime(2018, 1, 15));
             o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
-            o.setRefundTimes(0);
-            o.setRefundPrice(0);
-            o.setChannelUserId("1008611");
-            o.setChannelOrderNo(channelOrderId);
-            o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
-
         });
         orderMapper.insert(dbOrder);
         // 测试 appId 不匹配
@@ -169,7 +148,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
         // 测试 channelCode 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
         // 测试 merchantOrderId 不匹配
-        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));
+        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
         // 测试 notifyStatus 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
         // 测试 status 不匹配
@@ -177,18 +156,17 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
         // 测试 refundStatus 不匹配
         orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
         // 测试 createTime 不匹配
-        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
-                1))));
+        orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
         // 准备参数
         PayOrderExportReqVO reqVO = new PayOrderExportReqVO();
         reqVO.setAppId(1L);
-        reqVO.setChannelId(1L);
+        reqVO.setChannelId(10L);
         reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
-        reqVO.setMerchantOrderId(merchantOrderId);
+        reqVO.setMerchantOrderId("110");
         reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
         reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
         reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
-        reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
+        reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
 
         // 调用
         List<PayOrderDO> list = orderService.getOrderList(reqVO);
@@ -197,4 +175,154 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
         assertPojoEquals(dbOrder, list.get(0));
     }
 
+    @Test
+    public void testCreateOrder_success() {
+        // mock 参数
+        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
+                o -> o.setAppId(1L).setMerchantOrderId("10")
+                        .setSubject(randomString()).setBody(randomString()));
+        // mock 方法
+        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
+        when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app);
+
+        // 调用
+        Long orderId = orderService.createOrder(reqDTO);
+        // 断言
+        PayOrderDO order = orderMapper.selectById(orderId);
+        assertPojoEquals(order, reqDTO);
+        assertEquals(order.getAppId(), 1L);
+        assertEquals(order.getNotifyUrl(), "http://127.0.0.1");
+        assertEquals(order.getStatus(), PayOrderStatusEnum.WAITING.getStatus());
+        assertEquals(order.getRefundStatus(), PayOrderRefundStatusEnum.NO.getStatus());
+        assertEquals(order.getRefundTimes(), 0);
+        assertEquals(order.getRefundPrice(), 0);
+    }
+    
+    @Test
+    public void testCreateOrder_exists() {
+        // mock 参数
+        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
+                o -> o.setAppId(1L).setMerchantOrderId("10"));
+        // mock 数据
+        PayOrderDO dbOrder = randomPojo(PayOrderDO.class,  o -> o.setAppId(1L).setMerchantOrderId("10"));
+        orderMapper.insert(dbOrder);
+
+        // 调用
+        Long orderId = orderService.createOrder(reqDTO);
+        // 断言
+        PayOrderDO order = orderMapper.selectById(orderId);
+        assertPojoEquals(dbOrder, order);
+    }
+
+    @Test
+    public void testSubmitOrder_notFound() {
+        // 准备参数
+        PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class);
+        String userIp = randomString();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
+    }
+
+    @Test
+    public void testSubmitOrder_notWaiting() {
+        // mock 数据(order)
+        PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
+        orderMapper.insert(order);
+        // 准备参数
+        PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
+        String userIp = randomString();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
+    }
+
+    @Test
+    public void testSubmitOrder_expired() {
+        // mock 数据(order)
+        PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
+                .setExpireTime(addTime(Duration.ofDays(-1))));
+        orderMapper.insert(order);
+        // 准备参数
+        PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
+        String userIp = randomString();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
+    }
+
+    @Test
+    public void testSubmitOrder_channelNotFound() {
+        // mock 数据(order)
+        PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
+                .setAppId(1L));
+        orderMapper.insert(order);
+        // 准备参数
+        PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
+                .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
+        String userIp = randomString();
+        // mock 方法(app)
+        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
+        when(appService.validPayApp(eq(1L))).thenReturn(app);
+        // mock 方法(channel)
+        PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
+        when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
+                .thenReturn(channel);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> orderService.submitOrder(reqVO, userIp), CHANNEL_NOT_FOUND);
+    }
+
+    @Test // 调用 unifiedOrder 接口,返回存在渠道错误
+    public void testSubmitOrder_channelError() {
+        // mock 数据(order)
+        PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
+                .setAppId(1L));
+        orderMapper.insert(order);
+        // 准备参数
+        PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
+                .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
+        String userIp = randomString();
+        // mock 方法(app)
+        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
+        when(appService.validPayApp(eq(1L))).thenReturn(app);
+        // mock 方法(channel)
+        PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
+                .setCode(PayChannelEnum.ALIPAY_APP.getCode()));
+        when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
+                .thenReturn(channel);
+        // mock 方法(client)
+        PayClient client = mock(PayClient.class);
+        when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
+        when(client.unifiedOrder(any(PayOrderUnifiedReqDTO.class))).thenThrow(new NullPointerException());
+
+        // 调用,并断言异常
+        assertThrows(NullPointerException.class, () -> orderService.submitOrder(reqVO, userIp));
+        // 断言,数据记录(PayOrderExtensionDO)
+        PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
+        assertNotNull(orderExtension);
+        assertThat(orderExtension).extracting("no", "orderId").isNotNull();
+        assertThat(orderExtension)
+                .extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
+                        "channelErrorCode", "channelErrorMsg", "channelNotifyData")
+                .containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
+                        PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
+                        null, null, null);
+    }
+
+    @Test // 【成功】支付结果为等待中
+    public void testSubmitOrder_waitingResult() {
+
+    }
+
+    @Test // 【成功】支付结果为已完成
+    public void testSubmitOrder_successResult() {
+
+    }
+
+    @Test // 【成功】支付结果为已关闭
+    public void testSubmitOrder_closedResult() {
+
+    }
+
 }

+ 24 - 4
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql

@@ -40,9 +40,9 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
     `body`                 varchar(128)  NOT NULL,
     `notify_url`           varchar(1024) NOT NULL,
     `notify_status`        tinyint(4)    NOT NULL,
-    `amount`               bigint(20)    NOT NULL,
+    `price`                bigint(20)    NOT NULL,
     `channel_fee_rate`     double                 DEFAULT 0,
-    `channel_fee_amount`   bigint(20)             DEFAULT 0,
+    `channel_fee_price`    bigint(20)             DEFAULT 0,
     `status`               tinyint(4)    NOT NULL,
     `user_ip`              varchar(50)   NOT NULL,
     `expire_time`          datetime(0)   NOT NULL DEFAULT CURRENT_TIMESTAMP,
@@ -50,8 +50,8 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
     `notify_time`          datetime(0)            DEFAULT CURRENT_TIMESTAMP,
     `success_extension_id` bigint(20)             DEFAULT NULL COMMENT '支付成功的订单拓展单编号',
     `refund_status`        tinyint(4)    NOT NULL,
-    `refund_times`         tinyint(4)    NOT NULL,
-    `refund_amount`        bigint(20)    NOT NULL,
+    `refund_times`         int           NOT NULL,
+    `refund_price`         bigint(20)    NOT NULL,
     `channel_user_id`      varchar(255)           DEFAULT NULL,
     `channel_order_no`     varchar(64)            DEFAULT NULL,
     `creator`              varchar(64)            DEFAULT '',
@@ -62,6 +62,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
     PRIMARY KEY ("id")
 ) COMMENT = '支付订单';
 
+CREATE TABLE IF NOT EXISTS `pay_order_extension` (
+    "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    `no`           varchar(64)         NOT NULL,
+    `order_id`           bigint(20)    NOT NULL,
+    `channel_id`         bigint(20)    NOT NULL,
+    `channel_code`       varchar(32)   NOT NULL,
+    `user_ip`            varchar(50)   NULL     DEFAULT NULL,
+    `status`             tinyint(4)    NOT NULL,
+    `channel_extras`     varchar(1024) NULL     DEFAULT NULL,
+    `channel_error_code`  varchar(64)  NULL,
+    `channel_error_msg` varchar(64)    NULL,
+    `channel_notify_data` varchar(64)  NULL,
+    `creator`            varchar(64)   NULL     DEFAULT '',
+    `create_time`        datetime(0)   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `updater`            varchar(64)   NULL     DEFAULT '',
+    `update_time`        datetime(0)   NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    `deleted`            bit(1)        NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
+) COMMENT = '支付订单拓展';
+
 CREATE TABLE IF NOT EXISTS `pay_refund` (
     "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     `app_id`             bigint(20)    NOT NULL,