Commit a73e078593b05c205c3c068ab0b66e87b8d8e73c

Authored by puhui999
2 parents 25980760 29d61beb

Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product

# Conflicts:
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
Showing 94 changed files with 2583 additions and 2314 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java
@@ -12,7 +12,6 @@ import org.springframework.context.annotation.Bean; @@ -12,7 +12,6 @@ import org.springframework.context.annotation.Bean;
12 * @author 芋道源码 12 * @author 芋道源码
13 */ 13 */
14 @AutoConfiguration 14 @AutoConfiguration
15 -@EnableConfigurationProperties(PayProperties.class)  
16 public class YudaoPayAutoConfiguration { 15 public class YudaoPayAutoConfiguration {
17 16
18 @Bean 17 @Bean
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java
@@ -79,14 +79,16 @@ public class PayOrderRespDTO { @@ -79,14 +79,16 @@ public class PayOrderRespDTO {
79 /** 79 /**
80 * 创建【WAITING】状态的订单返回 80 * 创建【WAITING】状态的订单返回
81 */ 81 */
82 - public PayOrderRespDTO(String displayMode, String displayContent,  
83 - String outTradeNo, Object rawData) {  
84 - this.status = PayOrderStatusRespEnum.WAITING.getStatus();  
85 - this.displayMode = displayMode;  
86 - this.displayContent = displayContent; 82 + public static PayOrderRespDTO waitingOf(String displayMode, String displayContent,
  83 + String outTradeNo, Object rawData) {
  84 + PayOrderRespDTO respDTO = new PayOrderRespDTO();
  85 + respDTO.status = PayOrderStatusRespEnum.WAITING.getStatus();
  86 + respDTO.displayMode = displayMode;
  87 + respDTO.displayContent = displayContent;
87 // 相对通用的字段 88 // 相对通用的字段
88 - this.outTradeNo = outTradeNo;  
89 - this.rawData = rawData; 89 + respDTO.outTradeNo = outTradeNo;
  90 + respDTO.rawData = rawData;
  91 + return respDTO;
90 } 92 }
91 93
92 /** 94 /**
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java
1 package cn.iocoder.yudao.framework.pay.core.client.dto.refund; 1 package cn.iocoder.yudao.framework.pay.core.client.dto.refund;
2 2
  3 +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
3 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; 4 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
4 import lombok.Data; 5 import lombok.Data;
5 6
@@ -44,4 +45,71 @@ public class PayRefundRespDTO { @@ -44,4 +45,71 @@ public class PayRefundRespDTO {
44 */ 45 */
45 private Object rawData; 46 private Object rawData;
46 47
  48 + /**
  49 + * 调用渠道的错误码
  50 + *
  51 + * 注意:这里返回的是业务异常,而是不系统异常。
  52 + * 如果是系统异常,则会抛出 {@link PayException}
  53 + */
  54 + private String channelErrorCode;
  55 + /**
  56 + * 调用渠道报错时,错误信息
  57 + */
  58 + private String channelErrorMsg;
  59 +
  60 + private PayRefundRespDTO() {
  61 + }
  62 +
  63 + /**
  64 + * 创建【WAITING】状态的退款返回
  65 + */
  66 + public static PayRefundRespDTO waitingOf(String channelRefundNo,
  67 + String outRefundNo, Object rawData) {
  68 + PayRefundRespDTO respDTO = new PayRefundRespDTO();
  69 + respDTO.status = PayRefundStatusRespEnum.WAITING.getStatus();
  70 + respDTO.channelRefundNo = channelRefundNo;
  71 + // 相对通用的字段
  72 + respDTO.outRefundNo = outRefundNo;
  73 + respDTO.rawData = rawData;
  74 + return respDTO;
  75 + }
  76 +
  77 + /**
  78 + * 创建【SUCCESS】状态的退款返回
  79 + */
  80 + public static PayRefundRespDTO successOf(String channelRefundNo, LocalDateTime successTime,
  81 + String outRefundNo, Object rawData) {
  82 + PayRefundRespDTO respDTO = new PayRefundRespDTO();
  83 + respDTO.status = PayRefundStatusRespEnum.SUCCESS.getStatus();
  84 + respDTO.channelRefundNo = channelRefundNo;
  85 + respDTO.successTime = successTime;
  86 + // 相对通用的字段
  87 + respDTO.outRefundNo = outRefundNo;
  88 + respDTO.rawData = rawData;
  89 + return respDTO;
  90 + }
  91 +
  92 + /**
  93 + * 创建【FAILURE】状态的退款返回
  94 + */
  95 + public static PayRefundRespDTO failureOf(String outRefundNo, Object rawData) {
  96 + return failureOf(null, null,
  97 + outRefundNo, rawData);
  98 + }
  99 +
  100 + /**
  101 + * 创建【FAILURE】状态的退款返回
  102 + */
  103 + public static PayRefundRespDTO failureOf(String channelErrorCode, String channelErrorMsg,
  104 + String outRefundNo, Object rawData) {
  105 + PayRefundRespDTO respDTO = new PayRefundRespDTO();
  106 + respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus();
  107 + respDTO.channelErrorCode = channelErrorCode;
  108 + respDTO.channelErrorMsg = channelErrorMsg;
  109 + // 相对通用的字段
  110 + respDTO.outRefundNo = outRefundNo;
  111 + respDTO.rawData = rawData;
  112 + return respDTO;
  113 + }
  114 +
47 } 115 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -98,7 +98,8 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen @@ -98,7 +98,8 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
98 try { 98 try {
99 return doParseOrderNotify(params, body); 99 return doParseOrderNotify(params, body);
100 } catch (Throwable ex) { 100 } catch (Throwable ex) {
101 - log.error("[parseOrderNotify][params({}) body({}) 解析失败]", params, body, ex); 101 + log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]",
  102 + getId(), params, body, ex);
102 throw buildPayException(ex); 103 throw buildPayException(ex);
103 } 104 }
104 } 105 }
@@ -129,6 +130,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen @@ -129,6 +130,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
129 130
130 protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; 131 protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
131 132
  133 + @Override
  134 + public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
  135 + try {
  136 + return doParseRefundNotify(params, body);
  137 + } catch (Throwable ex) {
  138 + log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]",
  139 + getId(), params, body, ex);
  140 + throw buildPayException(ex);
  141 + }
  142 + }
  143 +
  144 + protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body)
  145 + throws Throwable;
  146 +
132 // ========== 各种工具方法 ========== 147 // ========== 各种工具方法 ==========
133 148
134 private PayException buildPayException(Throwable ex) { 149 private PayException buildPayException(Throwable ex) {
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -3,8 +3,10 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -3,8 +3,10 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
3 import cn.hutool.core.bean.BeanUtil; 3 import cn.hutool.core.bean.BeanUtil;
4 import cn.hutool.core.date.LocalDateTimeUtil; 4 import cn.hutool.core.date.LocalDateTimeUtil;
5 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
  6 +import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
7 import cn.hutool.http.HttpUtil; 8 import cn.hutool.http.HttpUtil;
  9 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 10 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
10 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 12 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@@ -29,7 +31,6 @@ import java.util.Objects; @@ -29,7 +31,6 @@ import java.util.Objects;
29 import java.util.function.Supplier; 31 import java.util.function.Supplier;
30 32
31 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; 33 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
32 -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;  
33 34
34 /** 35 /**
35 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) 36 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款)
@@ -74,10 +75,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -74,10 +75,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
74 StandardCharsets.UTF_8.name(), config.getSignType()); 75 StandardCharsets.UTF_8.name(), config.getSignType());
75 76
76 // 2. 解析订单的状态 77 // 2. 解析订单的状态
  78 + // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂
77 String tradeStatus = bodyObj.get("trade_status"); 79 String tradeStatus = bodyObj.get("trade_status");
78 Integer status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus() 80 Integer status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus()
79 - : Objects.equals("TRADE_SUCCESS", tradeStatus) ? PayOrderStatusRespEnum.SUCCESS.getStatus() 81 + : ObjectUtils.equalsAny(tradeStatus, "TRADE_FINISHED", "TRADE_SUCCESS") ? PayOrderStatusRespEnum.SUCCESS.getStatus()
80 : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null; 82 : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null;
  83 + // 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功
  84 + if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) {
  85 + status = PayOrderStatusRespEnum.REFUND.getStatus();
  86 + }
81 Assert.notNull(status, (Supplier<Throwable>) () -> { 87 Assert.notNull(status, (Supplier<Throwable>) () -> {
82 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); 88 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body));
83 }); 89 });
@@ -94,7 +100,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -94,7 +100,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
94 * @return 退款请求 Response 100 * @return 退款请求 Response
95 */ 101 */
96 @Override 102 @Override
97 - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { 103 + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws AlipayApiException {
98 // 1.1 构建 AlipayTradeRefundModel 请求 104 // 1.1 构建 AlipayTradeRefundModel 请求
99 AlipayTradeRefundModel model = new AlipayTradeRefundModel(); 105 AlipayTradeRefundModel model = new AlipayTradeRefundModel();
100 model.setOutTradeNo(reqDTO.getOutTradeNo()); 106 model.setOutTradeNo(reqDTO.getOutTradeNo());
@@ -104,31 +110,22 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -104,31 +110,22 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
104 // 1.2 构建 AlipayTradePayRequest 请求 110 // 1.2 构建 AlipayTradePayRequest 请求
105 AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); 111 AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
106 request.setBizModel(model); 112 request.setBizModel(model);
107 - try {  
108 - // 2.1 执行请求  
109 - AlipayTradeRefundResponse response = client.execute(request);  
110 - // 2.2 创建返回结果  
111 - PayRefundRespDTO refund = new PayRefundRespDTO()  
112 - .setOutRefundNo(reqDTO.getOutRefundNo())  
113 - .setRawData(response);  
114 - // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。  
115 - // 另外,支付宝没有退款单号,所以不用设置  
116 - if (response.isSuccess()) {  
117 - refund.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())  
118 - .setSuccessTime(LocalDateTimeUtil.of(response.getGmtRefundPay()));  
119 - Assert.notNull(refund.getSuccessTime(), "退款成功时间不能为空");  
120 - } else {  
121 - refund.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus());  
122 - }  
123 - return refund;  
124 - } catch (AlipayApiException e) {  
125 - log.error("[doUnifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), e);  
126 - return null; 113 +
  114 + // 2.1 执行请求
  115 + AlipayTradeRefundResponse response = client.execute(request);
  116 + // 2.2 创建返回结果
  117 + // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
  118 + // 另外,支付宝没有退款单号,所以不用设置
  119 + if (response.isSuccess()) {
  120 + return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()),
  121 + reqDTO.getOutRefundNo(), response);
  122 + } else {
  123 + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
127 } 124 }
128 } 125 }
129 126
130 @Override 127 @Override
131 - public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) { 128 + public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
132 // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 129 // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
133 // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 130 // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
134 // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 131 // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
@@ -52,7 +52,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { @@ -52,7 +52,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
52 if (!response.isSuccess()) { 52 if (!response.isSuccess()) {
53 return buildClosedPayOrderRespDTO(reqDTO, response); 53 return buildClosedPayOrderRespDTO(reqDTO, response);
54 } 54 }
55 - return new PayOrderRespDTO(displayMode, "", 55 + return PayOrderRespDTO.waitingOf(displayMode, "",
56 reqDTO.getOutTradeNo(), response); 56 reqDTO.getOutTradeNo(), response);
57 } 57 }
58 58
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
@@ -62,7 +62,7 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { @@ -62,7 +62,7 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
62 if (!response.isSuccess()) { 62 if (!response.isSuccess()) {
63 return buildClosedPayOrderRespDTO(reqDTO, response); 63 return buildClosedPayOrderRespDTO(reqDTO, response);
64 } 64 }
65 - return new PayOrderRespDTO(displayMode, "", 65 + return PayOrderRespDTO.waitingOf(displayMode, "",
66 reqDTO.getOutTradeNo(), response); 66 reqDTO.getOutTradeNo(), response);
67 } 67 }
68 68
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
@@ -63,7 +63,7 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { @@ -63,7 +63,7 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
63 if (!response.isSuccess()) { 63 if (!response.isSuccess()) {
64 return buildClosedPayOrderRespDTO(reqDTO, response); 64 return buildClosedPayOrderRespDTO(reqDTO, response);
65 } 65 }
66 - return new PayOrderRespDTO(displayMode, response.getBody(), 66 + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
67 reqDTO.getOutTradeNo(), response); 67 reqDTO.getOutTradeNo(), response);
68 } 68 }
69 69
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
@@ -50,7 +50,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { @@ -50,7 +50,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
50 if (!response.isSuccess()) { 50 if (!response.isSuccess()) {
51 return buildClosedPayOrderRespDTO(reqDTO, response); 51 return buildClosedPayOrderRespDTO(reqDTO, response);
52 } 52 }
53 - return new PayOrderRespDTO(displayMode, response.getQrCode(), 53 + return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(),
54 reqDTO.getOutTradeNo(), response); 54 reqDTO.getOutTradeNo(), response);
55 } 55 }
56 56
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
@@ -52,7 +52,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { @@ -52,7 +52,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
52 if (!response.isSuccess()) { 52 if (!response.isSuccess()) {
53 return buildClosedPayOrderRespDTO(reqDTO, response); 53 return buildClosedPayOrderRespDTO(reqDTO, response);
54 } 54 }
55 - return new PayOrderRespDTO(displayMode, response.getBody(), 55 + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
56 reqDTO.getOutTradeNo(), response); 56 reqDTO.getOutTradeNo(), response);
57 } 57 }
58 58
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -12,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; @@ -12,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
12 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 12 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
13 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 13 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
14 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; 14 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
15 -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;  
16 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; 15 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
17 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; 16 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
18 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; 17 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
@@ -131,6 +130,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -131,6 +130,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
131 // 1. 解析回调 130 // 1. 解析回调
132 WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body); 131 WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body);
133 // 2. 构建结果 132 // 2. 构建结果
  133 + // 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂
134 Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ? 134 Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ?
135 PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); 135 PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
136 return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), 136 return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
@@ -142,6 +142,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -142,6 +142,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
142 WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); 142 WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null);
143 WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult(); 143 WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult();
144 // 2. 构建结果 144 // 2. 构建结果
  145 + // 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂
145 Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ? 146 Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ?
146 PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); 147 PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
147 String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null; 148 String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null;
@@ -163,9 +164,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -163,9 +164,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
163 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); 164 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
164 } 165 }
165 } catch (WxPayException e) { 166 } catch (WxPayException e) {
166 - // todo 芋艿:异常的处理;  
167 -// throw buildUnifiedOrderException(null, e);  
168 - return null; 167 + String errorCode = getErrorCode(e);
  168 + String errorMessage = getErrorMessage(e);
  169 + return PayRefundRespDTO.failureOf(errorCode, errorMessage,
  170 + reqDTO.getOutTradeNo(), e.getXmlString());
169 } 171 }
170 } 172 }
171 173
@@ -181,17 +183,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -181,17 +183,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
181 // 2.1 执行请求 183 // 2.1 执行请求
182 WxPayRefundResult response = client.refundV2(request); 184 WxPayRefundResult response = client.refundV2(request);
183 // 2.2 创建返回结果 185 // 2.2 创建返回结果
184 - PayRefundRespDTO refund = new PayRefundRespDTO()  
185 - .setOutRefundNo(reqDTO.getOutRefundNo())  
186 - .setRawData(response);  
187 if (Objects.equals("SUCCESS", response.getResultCode())) { 186 if (Objects.equals("SUCCESS", response.getResultCode())) {
188 - refund.setStatus(PayRefundStatusRespEnum.WAITING.getStatus())  
189 - .setChannelRefundNo(response.getRefundId());  
190 - } else {  
191 - refund.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); 187 + return PayRefundRespDTO.waitingOf(response.getRefundId(),
  188 + reqDTO.getOutRefundNo(), response);
192 } 189 }
193 - // TODO 芋艿;异常的处理;  
194 - return refund; 190 + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
195 } 191 }
196 192
197 private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable { 193 private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
@@ -206,78 +202,51 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -206,78 +202,51 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
206 // 2.1 执行请求 202 // 2.1 执行请求
207 WxPayRefundV3Result response = client.refundV3(request); 203 WxPayRefundV3Result response = client.refundV3(request);
208 // 2.2 创建返回结果 204 // 2.2 创建返回结果
209 - PayRefundRespDTO refund = new PayRefundRespDTO()  
210 - .setOutRefundNo(reqDTO.getOutRefundNo())  
211 - .setRawData(response);  
212 if (Objects.equals("SUCCESS", response.getStatus())) { 205 if (Objects.equals("SUCCESS", response.getStatus())) {
213 - refund.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())  
214 - .setChannelRefundNo(response.getRefundId())  
215 - .setSuccessTime(parseDateV3(response.getSuccessTime()));  
216 - } else if (Objects.equals("PROCESSING", response.getStatus())) {  
217 - refund.setStatus(PayRefundStatusRespEnum.WAITING.getStatus())  
218 - .setChannelRefundNo(response.getRefundId());  
219 - } else {  
220 - refund.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); 206 + return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()),
  207 + reqDTO.getOutRefundNo(), response);
221 } 208 }
222 - // TODO 芋艿;异常的处理;  
223 - return refund; 209 + if (Objects.equals("PROCESSING", response.getStatus())) {
  210 + return PayRefundRespDTO.waitingOf(response.getRefundId(),
  211 + reqDTO.getOutRefundNo(), response);
  212 + }
  213 + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
224 } 214 }
225 215
226 @Override 216 @Override
227 - public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {  
228 - try {  
229 - // 微信支付 v2 回调结果处理  
230 - switch (config.getApiVersion()) {  
231 - case API_VERSION_V2:  
232 - return parseRefundNotifyV2(body);  
233 - case WxPayClientConfig.API_VERSION_V3:  
234 - return parseRefundNotifyV3(body);  
235 - default:  
236 - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));  
237 - }  
238 - } catch (WxPayException e) {  
239 - log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e);  
240 - throw new RuntimeException(e);  
241 - // TODO 芋艿:缺一个异常翻译 217 + public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) throws WxPayException {
  218 + switch (config.getApiVersion()) {
  219 + case API_VERSION_V2:
  220 + return doParseRefundNotifyV2(body);
  221 + case WxPayClientConfig.API_VERSION_V3:
  222 + return parseRefundNotifyV3(body);
  223 + default:
  224 + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
242 } 225 }
243 } 226 }
244 227
245 - @SuppressWarnings("DuplicatedCode")  
246 - private PayRefundRespDTO parseRefundNotifyV2(String body) throws WxPayException { 228 + private PayRefundRespDTO doParseRefundNotifyV2(String body) throws WxPayException {
247 // 1. 解析回调 229 // 1. 解析回调
248 WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body); 230 WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body);
249 - WxPayRefundNotifyResult.ReqInfo responseResult = response.getReqInfo(); 231 + WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo();
250 // 2. 构建结果 232 // 2. 构建结果
251 - PayRefundRespDTO notify = new PayRefundRespDTO()  
252 - .setChannelRefundNo(responseResult.getRefundId())  
253 - .setOutRefundNo(responseResult.getOutRefundNo())  
254 - .setRawData(response);  
255 - if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) {  
256 - notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())  
257 - .setSuccessTime(parseDateV2B(responseResult.getSuccessTime()));  
258 - } else {  
259 - notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); 233 + if (Objects.equals("SUCCESS", result.getRefundStatus())) {
  234 + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV2B(result.getSuccessTime()),
  235 + result.getOutRefundNo(), response);
260 } 236 }
261 - return notify; 237 + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
262 } 238 }
263 239
264 - @SuppressWarnings("DuplicatedCode")  
265 private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { 240 private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException {
266 // 1. 解析回调 241 // 1. 解析回调
267 WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); 242 WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null);
268 - WxPayRefundNotifyV3Result.DecryptNotifyResult responseResult = response.getResult(); 243 + WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
269 // 2. 构建结果 244 // 2. 构建结果
270 - PayRefundRespDTO notify = new PayRefundRespDTO()  
271 - .setChannelRefundNo(responseResult.getRefundId())  
272 - .setOutRefundNo(responseResult.getOutRefundNo())  
273 - .setRawData(response);  
274 - if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) {  
275 - notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())  
276 - .setSuccessTime(parseDateV3(responseResult.getSuccessTime()));  
277 - } else {  
278 - notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); 245 + if (Objects.equals("SUCCESS", result.getRefundStatus())) {
  246 + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV3(result.getSuccessTime()),
  247 + result.getOutRefundNo(), response);
279 } 248 }
280 - return notify; 249 + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
281 } 250 }
282 251
283 // ========== 各种工具方法 ========== 252 // ========== 各种工具方法 ==========
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java
@@ -67,7 +67,7 @@ public class WxBarPayClient extends AbstractWxPayClient { @@ -67,7 +67,7 @@ public class WxBarPayClient extends AbstractWxPayClient {
67 for (int i = 1; i < Byte.MAX_VALUE; i++) { 67 for (int i = 1; i < Byte.MAX_VALUE; i++) {
68 try { 68 try {
69 WxPayMicropayResult response = client.micropay(request); 69 WxPayMicropayResult response = client.micropay(request);
70 - // 支付成功,例如说:1)用户输入了密码;2) 70 + // 支付成功,例如说:1)用户输入了密码;2)用户免密支付
71 return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), 71 return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
72 response.getOutTradeNo(), response) 72 response.getOutTradeNo(), response)
73 .setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode()); 73 .setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode());
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java
@@ -48,7 +48,7 @@ public class WxNativePayClient extends AbstractWxPayClient { @@ -48,7 +48,7 @@ public class WxNativePayClient extends AbstractWxPayClient {
48 WxPayNativeOrderResult response = client.createOrder(request); 48 WxPayNativeOrderResult response = client.createOrder(request);
49 49
50 // 转换结果 50 // 转换结果
51 - return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(), 51 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(),
52 reqDTO.getOutTradeNo(), response); 52 reqDTO.getOutTradeNo(), response);
53 } 53 }
54 54
@@ -66,7 +66,7 @@ public class WxNativePayClient extends AbstractWxPayClient { @@ -66,7 +66,7 @@ public class WxNativePayClient extends AbstractWxPayClient {
66 String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); 66 String response = client.createOrderV3(TradeTypeEnum.NATIVE, request);
67 67
68 // 转换结果 68 // 转换结果
69 - return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response, 69 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response,
70 reqDTO.getOutTradeNo(), response); 70 reqDTO.getOutTradeNo(), response);
71 } 71 }
72 72
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
@@ -58,7 +58,7 @@ public class WxPubPayClient extends AbstractWxPayClient { @@ -58,7 +58,7 @@ public class WxPubPayClient extends AbstractWxPayClient {
58 WxPayMpOrderResult response = client.createOrder(request); 58 WxPayMpOrderResult response = client.createOrder(request);
59 59
60 // 转换结果 60 // 转换结果
61 - return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), 61 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
62 reqDTO.getOutTradeNo(), response); 62 reqDTO.getOutTradeNo(), response);
63 } 63 }
64 64
@@ -77,7 +77,7 @@ public class WxPubPayClient extends AbstractWxPayClient { @@ -77,7 +77,7 @@ public class WxPubPayClient extends AbstractWxPayClient {
77 WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request); 77 WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request);
78 78
79 // 转换结果 79 // 转换结果
80 - return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), 80 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
81 reqDTO.getOutTradeNo(), response); 81 reqDTO.getOutTradeNo(), response);
82 } 82 }
83 83
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java
@@ -16,7 +16,8 @@ public enum PayOrderStatusRespEnum { @@ -16,7 +16,8 @@ public enum PayOrderStatusRespEnum {
16 16
17 WAITING(0, "未支付"), 17 WAITING(0, "未支付"),
18 SUCCESS(10, "支付成功"), 18 SUCCESS(10, "支付成功"),
19 - CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款 19 + REFUND(20, "已退款"),
  20 + CLOSED(30, "支付关闭"),
20 ; 21 ;
21 22
22 private final Integer status; 23 private final Integer status;
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java
@@ -14,7 +14,7 @@ import java.util.Objects; @@ -14,7 +14,7 @@ import java.util.Objects;
14 @AllArgsConstructor 14 @AllArgsConstructor
15 public enum PayRefundStatusRespEnum { 15 public enum PayRefundStatusRespEnum {
16 16
17 - WAITING(0, "未退款"), 17 + WAITING(0, "等待退款"),
18 SUCCESS(10, "退款成功"), 18 SUCCESS(10, "退款成功"),
19 FAILURE(20, "退款失败"); 19 FAILURE(20, "退款失败");
20 20
@@ -25,4 +25,8 @@ public enum PayRefundStatusRespEnum { @@ -25,4 +25,8 @@ public enum PayRefundStatusRespEnum {
25 return Objects.equals(status, SUCCESS.getStatus()); 25 return Objects.equals(status, SUCCESS.getStatus());
26 } 26 }
27 27
  28 + public static boolean isFailure(Integer status) {
  29 + return Objects.equals(status, FAILURE.getStatus());
  30 + }
  31 +
28 } 32 }
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.excel.core.convert;
  2 +
  3 +import com.alibaba.excel.converters.Converter;
  4 +import com.alibaba.excel.enums.CellDataTypeEnum;
  5 +import com.alibaba.excel.metadata.GlobalConfiguration;
  6 +import com.alibaba.excel.metadata.data.WriteCellData;
  7 +import com.alibaba.excel.metadata.property.ExcelContentProperty;
  8 +
  9 +import java.math.BigDecimal;
  10 +import java.math.RoundingMode;
  11 +
  12 +/**
  13 + * 金额转换器
  14 + *
  15 + * 金额单位:分
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +public class MoneyConvert implements Converter<Integer> {
  20 +
  21 + @Override
  22 + public Class<?> supportJavaTypeKey() {
  23 + throw new UnsupportedOperationException("暂不支持,也不需要");
  24 + }
  25 +
  26 + @Override
  27 + public CellDataTypeEnum supportExcelTypeKey() {
  28 + throw new UnsupportedOperationException("暂不支持,也不需要");
  29 + }
  30 +
  31 + @Override
  32 + public WriteCellData<String> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
  33 + GlobalConfiguration globalConfiguration) {
  34 + BigDecimal result = BigDecimal.valueOf(value)
  35 + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
  36 + return new WriteCellData<>(result.toString());
  37 + }
  38 +
  39 +}
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 { @@ -55,6 +55,9 @@ public class RandomUtils {
55 } 55 }
56 return RandomUtil.randomInt(); 56 return RandomUtil.randomInt();
57 }); 57 });
  58 + // LocalDateTime
  59 + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class,
  60 + (dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime());
58 // Boolean 61 // Boolean
59 PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { 62 PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> {
60 // 如果是 deleted 的字段,返回非删除 63 // 如果是 deleted 的字段,返回非删除
@@ -82,7 +85,8 @@ public class RandomUtils { @@ -82,7 +85,8 @@ public class RandomUtils {
82 } 85 }
83 86
84 public static LocalDateTime randomLocalDateTime() { 87 public static LocalDateTime randomLocalDateTime() {
85 - return LocalDateTimeUtil.of(randomDate()); 88 + // 设置 Nano 为零的原因,避免 MySQL、H2 存储不到时间戳
  89 + return LocalDateTimeUtil.of(randomDate()).withNano(0);
86 } 90 }
87 91
88 public static Short randomShort() { 92 public static Short randomShort() {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
@@ -63,6 +63,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -63,6 +63,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
63 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; 63 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
64 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 64 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
65 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; 65 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
  66 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
66 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 67 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
67 68
68 /** 69 /**
@@ -344,7 +345,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -344,7 +345,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
344 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); 345 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
345 if (payOrder == null) { 346 if (payOrder == null) {
346 log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); 347 log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
347 - throw exception(PAY_ORDER_NOT_FOUND); 348 + throw exception(cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND);
348 } 349 }
349 // 校验支付单已支付 350 // 校验支付单已支付
350 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { 351 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/DictTypeConstants.java
@@ -7,13 +7,12 @@ package cn.iocoder.yudao.module.pay.enums; @@ -7,13 +7,12 @@ package cn.iocoder.yudao.module.pay.enums;
7 */ 7 */
8 public interface DictTypeConstants { 8 public interface DictTypeConstants {
9 9
10 - String CHANNEL_CODE = "pay_channel_code"; // 支付-渠道名 10 + String CHANNEL_CODE = "pay_channel_code"; // 支付渠道编码
11 11
12 - String ORDER_STATUS = "pay_order_status"; // 支付-订单-订单状态  
13 - String ORDER_NOTIFY_STATUS = "pay_order_notify_status"; // 支付-订单-订单回调商户状态 12 + String ORDER_STATUS = "pay_order_status"; // 支付渠道
14 13
15 - String ORDER_REFUND_STATUS = "pay_order_refund_status"; // 支付-订单-订单退款状态  
16 - String REFUND_ORDER_STATUS = "pay_refund_order_status"; // 支付-退款订单-退款状态  
17 - String REFUND_ORDER_TYPE = "pay_refund_order_type"; // 支付-退款订单-退款类别 14 + String REFUND_STATUS = "pay_order_status"; // 退款状态
  15 +
  16 + String NOTIFY_STATUS = "pay_notify_status"; // 回调状态
18 17
19 } 18 }
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; @@ -10,48 +10,46 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 // ========== APP 模块 1007000000 ========== 12 // ========== APP 模块 1007000000 ==========
13 - ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");  
14 - ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");  
15 - ErrorCode PAY_APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");  
16 - ErrorCode PAY_APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除"); 13 + ErrorCode APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
  14 + ErrorCode APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
  15 + ErrorCode APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
  16 + ErrorCode APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
17 17
18 // ========== CHANNEL 模块 1007001000 ========== 18 // ========== CHANNEL 模块 1007001000 ==========
19 - ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");  
20 - ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");  
21 - ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");  
22 - ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");  
23 - ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道"); 19 + ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
  20 + ErrorCode CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
  21 + ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
24 22
25 // ========== ORDER 模块 1007002000 ========== 23 // ========== ORDER 模块 1007002000 ==========
26 - ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");  
27 - ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");  
28 - ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");  
29 - ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");  
30 - ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}"); 24 + ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
  25 + ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
  26 + ErrorCode ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
  27 + ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
  28 + ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
  29 + ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
31 30
32 // ========== ORDER 模块(拓展单) 1007003000 ========== 31 // ========== ORDER 模块(拓展单) 1007003000 ==========
33 - ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");  
34 - ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付"); 32 + ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
  33 + ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
35 34
36 // ========== 支付模块(退款) 1007006000 ========== 35 // ========== 支付模块(退款) 1007006000 ==========
37 - ErrorCode PAY_REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");  
38 - ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");  
39 - ErrorCode PAY_REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");  
40 - ErrorCode PAY_REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");  
41 - ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");  
42 - ErrorCode PAY_REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款"); 36 + ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
  37 + ErrorCode REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
  38 + ErrorCode REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
  39 + ErrorCode REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
  40 + ErrorCode REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
43 41
44 // ========== 示例订单 1007900000 ========== 42 // ========== 示例订单 1007900000 ==========
45 - ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");  
46 - ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");  
47 - ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");  
48 - ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");  
49 - ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");  
50 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");  
51 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");  
52 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");  
53 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");  
54 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");  
55 - ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配"); 43 + ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
  44 + ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
  45 + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
  46 + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
  47 + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
  48 + ErrorCode DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
  49 + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
  50 + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
  51 + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
  52 + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
  53 + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
56 54
57 } 55 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyStatusEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyStatusEnum.java
@@ -12,11 +12,11 @@ import lombok.Getter; @@ -12,11 +12,11 @@ import lombok.Getter;
12 @AllArgsConstructor 12 @AllArgsConstructor
13 public enum PayNotifyStatusEnum { 13 public enum PayNotifyStatusEnum {
14 14
15 - WAITING(1, "等待通知"),  
16 - SUCCESS(2, "通知成功"),  
17 - FAILURE(3, "通知失败"), // 多次尝试,彻底失败  
18 - REQUEST_SUCCESS(4, "请求成功,但是结果失败"),  
19 - REQUEST_FAILURE(5, "请求失败"), 15 + WAITING(0, "等待通知"),
  16 + SUCCESS(10, "通知成功"),
  17 + FAILURE(20, "通知失败"), // 多次尝试,彻底失败
  18 + REQUEST_SUCCESS(21, "请求成功,但是结果失败"),
  19 + REQUEST_FAILURE(22, "请求失败"),
20 20
21 ; 21 ;
22 22
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java
1 package cn.iocoder.yudao.module.pay.enums.order; 1 package cn.iocoder.yudao.module.pay.enums.order;
2 2
3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
4 import lombok.AllArgsConstructor; 5 import lombok.AllArgsConstructor;
5 import lombok.Getter; 6 import lombok.Getter;
6 7
@@ -17,7 +18,8 @@ public enum PayOrderStatusEnum implements IntArrayValuable { @@ -17,7 +18,8 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
17 18
18 WAITING(0, "未支付"), 19 WAITING(0, "未支付"),
19 SUCCESS(10, "支付成功"), 20 SUCCESS(10, "支付成功"),
20 - CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款 21 + REFUND(20, "已退款"),
  22 + CLOSED(30, "支付关闭"), // 注意:全部退款后,还是 REFUND 状态
21 ; 23 ;
22 24
23 private final Integer status; 25 private final Integer status;
@@ -39,6 +41,17 @@ public enum PayOrderStatusEnum implements IntArrayValuable { @@ -39,6 +41,17 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
39 } 41 }
40 42
41 /** 43 /**
  44 + * 判断是否支付成功或者已退款
  45 + *
  46 + * @param status 状态
  47 + * @return 是否支付成功或者已退款
  48 + */
  49 + public static boolean isSuccessOrRefund(Integer status) {
  50 + return ObjectUtils.equalsAny(status,
  51 + SUCCESS.getStatus(), REFUND.getStatus());
  52 + }
  53 +
  54 + /**
42 * 判断是否支付关闭 55 * 判断是否支付关闭
43 * 56 *
44 * @param status 状态 57 * @param status 状态
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java
@@ -25,4 +25,8 @@ public enum PayRefundStatusEnum { @@ -25,4 +25,8 @@ public enum PayRefundStatusEnum {
25 return Objects.equals(status, SUCCESS.getStatus()); 25 return Objects.equals(status, SUCCESS.getStatus());
26 } 26 }
27 27
  28 + public static boolean isFailure(Integer status) {
  29 + return Objects.equals(status, FAILURE.getStatus());
  30 + }
  31 +
28 } 32 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/PayAppController.java
@@ -97,4 +97,12 @@ public class PayAppController { @@ -97,4 +97,12 @@ public class PayAppController {
97 return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels)); 97 return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels));
98 } 98 }
99 99
  100 + @GetMapping("/list")
  101 + @Operation(summary = "获得应用列表")
  102 + @PreAuthorize("@ss.hasPermission('pay:merchant:query')")
  103 + public CommonResult<List<PayAppRespVO>> getAppList() {
  104 + List<PayAppDO> appListDO = appService.getAppList();
  105 + return success(PayAppConvert.INSTANCE.convertList(appListDO));
  106 + }
  107 +
100 } 108 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
1 package cn.iocoder.yudao.module.pay.controller.admin.notify; 1 package cn.iocoder.yudao.module.pay.controller.admin.notify;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 5 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
4 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 6 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
5 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 7 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
  10 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
  11 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
  12 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
  13 +import cn.iocoder.yudao.module.pay.convert.notify.PayNotifyTaskConvert;
  14 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
  15 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
  16 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
  17 +import cn.iocoder.yudao.module.pay.service.app.PayAppService;
  18 +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
8 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 19 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
9 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 20 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
10 import io.swagger.v3.oas.annotations.Operation; 21 import io.swagger.v3.oas.annotations.Operation;
  22 +import io.swagger.v3.oas.annotations.Parameter;
11 import io.swagger.v3.oas.annotations.tags.Tag; 23 import io.swagger.v3.oas.annotations.tags.Tag;
12 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.springframework.security.access.prepost.PreAuthorize;
13 import org.springframework.validation.annotation.Validated; 26 import org.springframework.validation.annotation.Validated;
14 import org.springframework.web.bind.annotation.*; 27 import org.springframework.web.bind.annotation.*;
15 28
16 import javax.annotation.Resource; 29 import javax.annotation.Resource;
17 import javax.annotation.security.PermitAll; 30 import javax.annotation.security.PermitAll;
  31 +import javax.validation.Valid;
  32 +import java.util.List;
18 import java.util.Map; 33 import java.util.Map;
19 34
20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
21 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND; 36 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  37 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  38 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
22 39
23 -@Tag(name = "管理后台 - 支付通知") 40 +@Tag(name = "管理后台 - 回调通知")
24 @RestController 41 @RestController
25 @RequestMapping("/pay/notify") 42 @RequestMapping("/pay/notify")
26 @Validated 43 @Validated
@@ -31,6 +48,10 @@ public class PayNotifyController { @@ -31,6 +48,10 @@ public class PayNotifyController {
31 private PayOrderService orderService; 48 private PayOrderService orderService;
32 @Resource 49 @Resource
33 private PayRefundService refundService; 50 private PayRefundService refundService;
  51 + @Resource
  52 + private PayNotifyService notifyService;
  53 + @Resource
  54 + private PayAppService appService;
34 55
35 @Resource 56 @Resource
36 private PayClientFactory payClientFactory; 57 private PayClientFactory payClientFactory;
@@ -47,7 +68,7 @@ public class PayNotifyController { @@ -47,7 +68,7 @@ public class PayNotifyController {
47 PayClient payClient = payClientFactory.getPayClient(channelId); 68 PayClient payClient = payClientFactory.getPayClient(channelId);
48 if (payClient == null) { 69 if (payClient == null) {
49 log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); 70 log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
50 - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); 71 + throw exception(CHANNEL_NOT_FOUND);
51 } 72 }
52 73
53 // 2. 解析通知数据 74 // 2. 解析通知数据
@@ -68,7 +89,7 @@ public class PayNotifyController { @@ -68,7 +89,7 @@ public class PayNotifyController {
68 PayClient payClient = payClientFactory.getPayClient(channelId); 89 PayClient payClient = payClientFactory.getPayClient(channelId);
69 if (payClient == null) { 90 if (payClient == null) {
70 log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); 91 log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
71 - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); 92 + throw exception(CHANNEL_NOT_FOUND);
72 } 93 }
73 94
74 // 2. 解析通知数据 95 // 2. 解析通知数据
@@ -77,4 +98,29 @@ public class PayNotifyController { @@ -77,4 +98,29 @@ public class PayNotifyController {
77 return "success"; 98 return "success";
78 } 99 }
79 100
  101 + @GetMapping("/get-detail")
  102 + @Operation(summary = "获得回调通知的明细")
  103 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  104 + @PreAuthorize("@ss.hasPermission('pay:notify:query')")
  105 + public CommonResult<PayNotifyTaskDetailRespVO> getNotifyTaskDetail(@RequestParam("id") Long id) {
  106 + PayNotifyTaskDO task = notifyService.getNotifyTask(id);
  107 + if (task == null) {
  108 + return success(null);
  109 + }
  110 + // 拼接返回
  111 + PayAppDO app = appService.getApp(task.getAppId());
  112 + List<PayNotifyLogDO> logs = notifyService.getNotifyLogList(id);
  113 + return success(PayNotifyTaskConvert.INSTANCE.convert(task, app, logs));
  114 + }
  115 +
  116 + @GetMapping("/page")
  117 + @Operation(summary = "获得回调通知分页")
  118 + @PreAuthorize("@ss.hasPermission('pay:notify:query')")
  119 + public CommonResult<PageResult<PayNotifyTaskRespVO>> getNotifyTaskPage(@Valid PayNotifyTaskPageReqVO pageVO) {
  120 + PageResult<PayNotifyTaskDO> pageResult = notifyService.getNotifyTaskPage(pageVO);
  121 + // 拼接返回
  122 + Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayNotifyTaskDO::getAppId));
  123 + return success(PayNotifyTaskConvert.INSTANCE.convertPage(pageResult, appMap));
  124 + }
  125 +
80 } 126 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +/**
  9 + * 回调通知 Base VO,提供给添加、修改、详细的子 VO 使用
  10 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  11 + */
  12 +@Data
  13 +public class PayNotifyTaskBaseVO {
  14 +
  15 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10636")
  16 + private Long appId;
  17 +
  18 + @Schema(description = "通知类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  19 + private Byte type;
  20 +
  21 + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6722")
  22 + private Long dataId;
  23 +
  24 + @Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Byte status;
  26 +
  27 + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26697")
  28 + private String merchantOrderId;
  29 +
  30 + @Schema(description = "下一次通知时间", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private LocalDateTime nextNotifyTime;
  32 +
  33 + @Schema(description = "最后一次执行时间", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private LocalDateTime lastExecuteTime;
  35 +
  36 + @Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private Byte notifyTimes;
  38 +
  39 + @Schema(description = "最大可通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
  40 + private Byte maxNotifyTimes;
  41 +
  42 + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
  43 + private String notifyUrl;
  44 +
  45 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskDetailRespVO.java 0 → 100644
  1 +
  2 +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
  3 +
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.time.LocalDateTime;
  10 +import java.util.List;
  11 +
  12 +@Schema(description = "管理后台 - 回调通知的明细 Response VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class PayNotifyTaskDetailRespVO extends PayNotifyTaskBaseVO {
  17 +
  18 + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380")
  19 + private Long id;
  20 +
  21 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private LocalDateTime createTime;
  23 +
  24 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private LocalDateTime updateTime;
  26 +
  27 + @Schema(description = "应用名称", example = "wx_pay")
  28 + private String appName;
  29 +
  30 + @Schema(description = "回调日志列表")
  31 + private List<Log> logs;
  32 +
  33 + @Schema(description = "管理后台 - 回调日志")
  34 + @Data
  35 + public static class Log {
  36 +
  37 + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8848")
  38 + private Long id;
  39 +
  40 + @Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  41 + private Byte status;
  42 +
  43 + @Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
  44 + private Byte notifyTimes;
  45 +
  46 + @Schema(description = "HTTP 响应结果", requiredMode = Schema.RequiredMode.REQUIRED)
  47 + private String response;
  48 +
  49 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  50 + private LocalDateTime createTime;
  51 +
  52 + }
  53 +
  54 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - 回调通知分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class PayNotifyTaskPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "应用编号", example = "10636")
  21 + private Long appId;
  22 +
  23 + @Schema(description = "通知类型", example = "2")
  24 + private Byte type;
  25 +
  26 + @Schema(description = "数据编号", example = "6722")
  27 + private Long dataId;
  28 +
  29 + @Schema(description = "通知状态", example = "1")
  30 + private Byte status;
  31 +
  32 + @Schema(description = "商户订单编号", example = "26697")
  33 + private String merchantOrderId;
  34 +
  35 + @Schema(description = "创建时间")
  36 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + private LocalDateTime[] createTime;
  38 +
  39 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundRespVO.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskRespVO.java 100755 → 100644
1 -package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; 1 +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -import lombok.ToString;  
7 - 4 +import lombok.*;
8 import java.time.LocalDateTime; 5 import java.time.LocalDateTime;
9 6
10 -@Schema(description = "管理后台 - 退款订单 Response VO") 7 +@Schema(description = "管理后台 - 回调通知 Response VO")
11 @Data 8 @Data
12 @EqualsAndHashCode(callSuper = true) 9 @EqualsAndHashCode(callSuper = true)
13 @ToString(callSuper = true) 10 @ToString(callSuper = true)
14 -public class PayRefundRespVO extends PayRefundBaseVO { 11 +public class PayNotifyTaskRespVO extends PayNotifyTaskBaseVO {
15 12
16 - @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED) 13 + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380")
17 private Long id; 14 private Long id;
18 15
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 16 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 17 private LocalDateTime createTime;
21 18
  19 + @Schema(description = "应用名称", example = "wx_pay")
  20 + private String appName;
  21 +
22 } 22 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
1 package cn.iocoder.yudao.module.pay.controller.admin.order; 1 package cn.iocoder.yudao.module.pay.controller.admin.order;
2 2
3 import cn.hutool.core.collection.CollectionUtil; 3 import cn.hutool.core.collection.CollectionUtil;
4 -import cn.hutool.core.util.ObjectUtil;  
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
8 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 6 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
9 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
10 -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;  
11 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; 8 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
12 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; 9 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
13 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
14 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
15 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; 12 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
16 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 13 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
17 -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;  
18 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 14 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
19 import io.swagger.v3.oas.annotations.Operation; 15 import io.swagger.v3.oas.annotations.Operation;
20 import io.swagger.v3.oas.annotations.Parameter; 16 import io.swagger.v3.oas.annotations.Parameter;
@@ -32,6 +28,7 @@ import java.util.List; @@ -32,6 +28,7 @@ import java.util.List;
32 import java.util.Map; 28 import java.util.Map;
33 29
34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
35 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; 32 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
36 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; 33 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
37 34
@@ -42,9 +39,7 @@ import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.E @@ -42,9 +39,7 @@ import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.E
42 public class PayOrderController { 39 public class PayOrderController {
43 40
44 @Resource 41 @Resource
45 - private PayOrderService payOrderService;  
46 - @Resource  
47 - private PayOrderExtensionService orderExtensionService; 42 + private PayOrderService orderService;
48 @Resource 43 @Resource
49 private PayAppService appService; 44 private PayAppService appService;
50 45
@@ -53,40 +48,29 @@ public class PayOrderController { @@ -53,40 +48,29 @@ public class PayOrderController {
53 @Parameter(name = "id", description = "编号", required = true, example = "1024") 48 @Parameter(name = "id", description = "编号", required = true, example = "1024")
54 @PreAuthorize("@ss.hasPermission('pay:order:query')") 49 @PreAuthorize("@ss.hasPermission('pay:order:query')")
55 public CommonResult<PayOrderRespVO> getOrder(@RequestParam("id") Long id) { 50 public CommonResult<PayOrderRespVO> getOrder(@RequestParam("id") Long id) {
56 - return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id))); 51 + return success(PayOrderConvert.INSTANCE.convert(orderService.getOrder(id)));
57 } 52 }
58 53
59 - // TODO 芋艿:看看怎么优化下;  
60 @GetMapping("/get-detail") 54 @GetMapping("/get-detail")
61 @Operation(summary = "获得支付订单详情") 55 @Operation(summary = "获得支付订单详情")
62 @Parameter(name = "id", description = "编号", required = true, example = "1024") 56 @Parameter(name = "id", description = "编号", required = true, example = "1024")
63 @PreAuthorize("@ss.hasPermission('pay:order:query')") 57 @PreAuthorize("@ss.hasPermission('pay:order:query')")
64 public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) { 58 public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) {
65 - PayOrderDO order = payOrderService.getOrder(id);  
66 - if (ObjectUtil.isNull(order)) {  
67 - return success(new PayOrderDetailsRespVO());  
68 - }  
69 -  
70 - PayAppDO appDO = appService.getApp(order.getAppId());  
71 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(order.getChannelCode());  
72 -  
73 - // TODO @aquan:文案,都是前端 format;  
74 - PayOrderDetailsRespVO respVO = PayOrderConvert.INSTANCE.orderDetailConvert(order);  
75 - respVO.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
76 - respVO.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
77 -  
78 - PayOrderExtensionDO extensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());  
79 - if (ObjectUtil.isNotNull(extensionDO)) {  
80 - respVO.setPayOrderExtension(PayOrderConvert.INSTANCE.orderDetailExtensionConvert(extensionDO)); 59 + PayOrderDO order = orderService.getOrder(id);
  60 + if (order == null) {
  61 + return success(null);
81 } 62 }
82 63
83 - return success(respVO); 64 + // 拼接返回
  65 + PayAppDO app = appService.getApp(order.getAppId());
  66 + PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId());
  67 + return success(PayOrderConvert.INSTANCE.convert(order, orderExtension, app));
84 } 68 }
85 69
86 @PostMapping("/submit") 70 @PostMapping("/submit")
87 @Operation(summary = "提交支付订单") 71 @Operation(summary = "提交支付订单")
88 public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { 72 public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
89 - PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP()); 73 + PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP());
90 return success(respVO); 74 return success(respVO);
91 } 75 }
92 76
@@ -94,62 +78,34 @@ public class PayOrderController { @@ -94,62 +78,34 @@ public class PayOrderController {
94 @Operation(summary = "获得支付订单分页") 78 @Operation(summary = "获得支付订单分页")
95 @PreAuthorize("@ss.hasPermission('pay:order:query')") 79 @PreAuthorize("@ss.hasPermission('pay:order:query')")
96 public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) { 80 public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) {
97 - PageResult<PayOrderDO> pageResult = payOrderService.getOrderPage(pageVO); 81 + PageResult<PayOrderDO> pageResult = orderService.getOrderPage(pageVO);
98 if (CollectionUtil.isEmpty(pageResult.getList())) { 82 if (CollectionUtil.isEmpty(pageResult.getList())) {
99 return success(new PageResult<>(pageResult.getTotal())); 83 return success(new PageResult<>(pageResult.getTotal()));
100 } 84 }
101 85
102 - // 处理应用ID数据  
103 - Map<Long, PayAppDO> appMap = appService.getAppMap(  
104 - CollectionUtils.convertList(pageResult.getList(), PayOrderDO::getAppId));  
105 -  
106 - List<PayOrderPageItemRespVO> pageList = new ArrayList<>(pageResult.getList().size());  
107 - pageResult.getList().forEach(c -> {  
108 - PayAppDO appDO = appMap.get(c.getAppId());  
109 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());  
110 -  
111 - PayOrderPageItemRespVO orderItem = PayOrderConvert.INSTANCE.pageConvertItemPage(c);  
112 - orderItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
113 - orderItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
114 - pageList.add(orderItem);  
115 - });  
116 - return success(new PageResult<>(pageList, pageResult.getTotal())); 86 + // 拼接返回
  87 + Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayOrderDO::getAppId));
  88 + return success(PayOrderConvert.INSTANCE.convertPage(pageResult, appMap));
117 } 89 }
118 90
119 @GetMapping("/export-excel") 91 @GetMapping("/export-excel")
120 - @Operation(summary = "导出支付订单Excel") 92 + @Operation(summary = "导出支付订单 Excel")
121 @PreAuthorize("@ss.hasPermission('pay:order:export')") 93 @PreAuthorize("@ss.hasPermission('pay:order:export')")
122 @OperateLog(type = EXPORT) 94 @OperateLog(type = EXPORT)
123 public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO, 95 public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO,
124 HttpServletResponse response) throws IOException { 96 HttpServletResponse response) throws IOException {
125 - List<PayOrderDO> list = payOrderService.getOrderList(exportReqVO); 97 + List<PayOrderDO> list = orderService.getOrderList(exportReqVO);
126 if (CollectionUtil.isEmpty(list)) { 98 if (CollectionUtil.isEmpty(list)) {
127 ExcelUtils.write(response, "支付订单.xls", "数据", 99 ExcelUtils.write(response, "支付订单.xls", "数据",
128 PayOrderExcelVO.class, new ArrayList<>()); 100 PayOrderExcelVO.class, new ArrayList<>());
  101 + return;
129 } 102 }
130 103
131 - // 处理应用ID数据  
132 - Map<Long, PayAppDO> appMap = appService.getAppMap(  
133 - CollectionUtils.convertList(list, PayOrderDO::getAppId));  
134 - // 处理扩展订单数据  
135 - Map<Long, PayOrderExtensionDO> orderExtensionMap = orderExtensionService  
136 - .getOrderExtensionMap(CollectionUtils.convertList(list, PayOrderDO::getSuccessExtensionId));  
137 -  
138 - List<PayOrderExcelVO> excelDatum = new ArrayList<>(list.size());  
139 - list.forEach(c -> {  
140 - PayAppDO appDO = appMap.get(c.getAppId());  
141 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());  
142 - PayOrderExtensionDO orderExtensionDO = orderExtensionMap.get(c.getSuccessExtensionId());  
143 -  
144 - PayOrderExcelVO excelItem = PayOrderConvert.INSTANCE.excelConvert(c);  
145 - excelItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
146 - excelItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
147 - excelItem.setNo(ObjectUtil.isNotNull(orderExtensionDO) ? orderExtensionDO.getNo() : "");  
148 - excelDatum.add(excelItem);  
149 - });  
150 - 104 + // 拼接返回
  105 + Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(list, PayOrderDO::getAppId));
  106 + List<PayOrderExcelVO> excelList = PayOrderConvert.INSTANCE.convertList(list, appMap);
151 // 导出 Excel 107 // 导出 Excel
152 - ExcelUtils.write(response, "支付订单.xls", "数据", PayOrderExcelVO.class, excelDatum); 108 + ExcelUtils.write(response, "支付订单.xls", "数据", PayOrderExcelVO.class, excelList);
153 } 109 }
154 110
155 } 111 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderBaseVO.java
@@ -17,51 +17,47 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -17,51 +17,47 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 @Data 17 @Data
18 public class PayOrderBaseVO { 18 public class PayOrderBaseVO {
19 19
20 - @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) 20 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
21 @NotNull(message = "应用编号不能为空") 21 @NotNull(message = "应用编号不能为空")
22 private Long appId; 22 private Long appId;
23 23
24 - @Schema(description = "渠道编号") 24 + @Schema(description = "渠道编号", example = "2048")
25 private Long channelId; 25 private Long channelId;
26 26
27 - @Schema(description = "渠道编码") 27 + @Schema(description = "渠道编码", example = "wx_app")
28 private String channelCode; 28 private String channelCode;
29 29
30 - @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED) 30 + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
31 @NotNull(message = "商户订单编号不能为空") 31 @NotNull(message = "商户订单编号不能为空")
32 private String merchantOrderId; 32 private String merchantOrderId;
33 33
34 - @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED) 34 + @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
35 @NotNull(message = "商品标题不能为空") 35 @NotNull(message = "商品标题不能为空")
36 private String subject; 36 private String subject;
37 37
38 - @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED) 38 + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是土豆")
39 @NotNull(message = "商品描述不能为空") 39 @NotNull(message = "商品描述不能为空")
40 private String body; 40 private String body;
41 41
42 - @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED) 42 + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay/notify")
43 @NotNull(message = "异步通知地址不能为空") 43 @NotNull(message = "异步通知地址不能为空")
44 private String notifyUrl; 44 private String notifyUrl;
45 45
46 - @Schema(description = "通知商户支付结果的回调状态", requiredMode = Schema.RequiredMode.REQUIRED)  
47 - @NotNull(message = "通知商户支付结果的回调状态不能为空")  
48 - private Integer notifyStatus;  
49 -  
50 - @Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED) 46 + @Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
51 @NotNull(message = "支付金额,单位:分不能为空") 47 @NotNull(message = "支付金额,单位:分不能为空")
52 private Long price; 48 private Long price;
53 49
54 - @Schema(description = "渠道手续费,单位:百分比") 50 + @Schema(description = "渠道手续费,单位:百分比", example = "10")
55 private Double channelFeeRate; 51 private Double channelFeeRate;
56 52
57 - @Schema(description = "渠道手续金额,单位:分")  
58 - private Long channelFeePrice; 53 + @Schema(description = "渠道手续金额,单位:分", example = "100")
  54 + private Integer channelFeePrice;
59 55
60 - @Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED) 56 + @Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
61 @NotNull(message = "支付状态不能为空") 57 @NotNull(message = "支付状态不能为空")
62 private Integer status; 58 private Integer status;
63 59
64 - @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED) 60 + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
65 @NotNull(message = "用户 IP不能为空") 61 @NotNull(message = "用户 IP不能为空")
66 private String userIp; 62 private String userIp;
67 63
@@ -74,29 +70,20 @@ public class PayOrderBaseVO { @@ -74,29 +70,20 @@ public class PayOrderBaseVO {
74 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 70 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
75 private LocalDateTime successTime; 71 private LocalDateTime successTime;
76 72
77 - @Schema(description = "订单支付通知时间")  
78 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
79 - private LocalDateTime notifyTime;  
80 -  
81 - @Schema(description = "支付成功的订单拓展单编号")  
82 - private Long successExtensionId;  
83 -  
84 - @Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED)  
85 - @NotNull(message = "退款状态不能为空")  
86 - private Integer refundStatus; 73 + @Schema(description = "支付成功的订单拓展单编号", example = "50")
  74 + private Long extensionId;
87 75
88 - @Schema(description = "退款次数", requiredMode = Schema.RequiredMode.REQUIRED)  
89 - @NotNull(message = "退款次数不能为空")  
90 - private Integer refundTimes; 76 + @Schema(description = "支付订单号", example = "2048888")
  77 + private String no;
91 78
92 - @Schema(description = "退款总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED) 79 + @Schema(description = "退款总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
93 @NotNull(message = "退款总金额,单位:分不能为空") 80 @NotNull(message = "退款总金额,单位:分不能为空")
94 private Long refundPrice; 81 private Long refundPrice;
95 82
96 - @Schema(description = "渠道用户编号") 83 + @Schema(description = "渠道用户编号", example = "2048")
97 private String channelUserId; 84 private String channelUserId;
98 85
99 - @Schema(description = "渠道订单号") 86 + @Schema(description = "渠道订单号", example = "4096")
100 private String channelOrderNo; 87 private String channelOrderNo;
101 88
102 } 89 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderDetailsRespVO.java
@@ -13,32 +13,33 @@ import java.time.LocalDateTime; @@ -13,32 +13,33 @@ import java.time.LocalDateTime;
13 @ToString(callSuper = true) 13 @ToString(callSuper = true)
14 public class PayOrderDetailsRespVO extends PayOrderBaseVO { 14 public class PayOrderDetailsRespVO extends PayOrderBaseVO {
15 15
16 - @Schema(description = "支付订单编号") 16 + @Schema(description = "支付订单编号", required = true, example = "1024")
17 private Long id; 17 private Long id;
18 18
19 - @Schema(description = "应用名称") 19 + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
20 private String appName; 20 private String appName;
21 21
22 - @Schema(description = "渠道编号名称")  
23 - private String channelCodeName;  
24 -  
25 - @Schema(description = "创建时间") 22 + @Schema(description = "创建时间", required = true)
26 private LocalDateTime createTime; 23 private LocalDateTime createTime;
27 24
  25 + @Schema(description = "更新时间", required = true)
  26 + private LocalDateTime updateTime;
  27 +
28 /** 28 /**
29 * 支付订单扩展 29 * 支付订单扩展
30 */ 30 */
31 - private PayOrderExtension payOrderExtension; 31 + private PayOrderExtension extension;
32 32
33 @Data 33 @Data
34 @Schema(description = "支付订单扩展") 34 @Schema(description = "支付订单扩展")
35 public static class PayOrderExtension { 35 public static class PayOrderExtension {
36 36
37 - @Schema(description = "支付订单号") 37 + @Schema(description = "支付订单号", required = true, example = "1024")
38 private String no; 38 private String no;
39 39
40 @Schema(description = "支付异步通知的内容") 40 @Schema(description = "支付异步通知的内容")
41 private String channelNotifyData; 41 private String channelNotifyData;
  42 +
42 } 43 }
43 44
44 } 45 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExcelVO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.order.vo; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.order.vo;
2 2
3 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; 3 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
4 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; 4 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  5 +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
5 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; 6 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
6 import com.alibaba.excel.annotation.ExcelProperty; 7 import com.alibaba.excel.annotation.ExcelProperty;
7 import lombok.Data; 8 import lombok.Data;
@@ -9,53 +10,44 @@ import lombok.Data; @@ -9,53 +10,44 @@ import lombok.Data;
9 import java.time.LocalDateTime; 10 import java.time.LocalDateTime;
10 11
11 /** 12 /**
12 - * 支付订单Excel VO 13 + * 支付订单 Excel VO
13 * 14 *
14 * @author aquan 15 * @author aquan
15 */ 16 */
16 @Data 17 @Data
17 public class PayOrderExcelVO { 18 public class PayOrderExcelVO {
18 19
19 - @ExcelProperty("支付订单编号") 20 + @ExcelProperty("编号")
20 private Long id; 21 private Long id;
21 22
22 - @ExcelProperty(value = "应用名称")  
23 - private String appName;  
24 -  
25 - @ExcelProperty("商品标题")  
26 - private String subject; 23 + @ExcelProperty("创建时间")
  24 + private LocalDateTime createTime;
27 25
28 - @ExcelProperty("商户订单编号")  
29 - private String merchantOrderId; 26 + @ExcelProperty(value = "支付金额", converter = MoneyConvert.class)
  27 + private Integer price;
30 28
31 - @ExcelProperty("渠道订单号")  
32 - private String channelOrderNo; 29 + @ExcelProperty(value = "退款金额", converter = MoneyConvert.class)
  30 + private Integer refundPrice;
33 31
34 - @ExcelProperty(value = "支付订单号")  
35 - private String no; 32 + @ExcelProperty(value = "手续金额", converter = MoneyConvert.class)
  33 + private Integer channelFeePrice;
36 34
37 - @ExcelProperty("支付金额,单位:元")  
38 - private String price; 35 + @ExcelProperty("商户单号")
  36 + private String merchantOrderId;
39 37
40 - @ExcelProperty("渠道手续金额,单位:元")  
41 - private String channelFeePrice; 38 + @ExcelProperty(value = "支付单号")
  39 + private String no;
42 40
43 - @ExcelProperty("渠道手续费,单位:百分比")  
44 - private String channelFeeRate; 41 + @ExcelProperty("渠道单号")
  42 + private String channelOrderNo;
45 43
46 - @DictFormat(DictTypeConstants.ORDER_STATUS)  
47 @ExcelProperty(value = "支付状态", converter = DictConvert.class) 44 @ExcelProperty(value = "支付状态", converter = DictConvert.class)
  45 + @DictFormat(DictTypeConstants.ORDER_STATUS)
48 private Integer status; 46 private Integer status;
49 47
50 - @DictFormat(DictTypeConstants.ORDER_NOTIFY_STATUS)  
51 - @ExcelProperty(value = "通知商户支付结果的回调状态", converter = DictConvert.class)  
52 - private Integer notifyStatus;  
53 -  
54 - @ExcelProperty("异步通知地址")  
55 - private String notifyUrl;  
56 -  
57 - @ExcelProperty("创建时间")  
58 - private LocalDateTime createTime; 48 + @ExcelProperty(value = "渠道编号名称", converter = DictConvert.class)
  49 + @DictFormat(DictTypeConstants.CHANNEL_CODE)
  50 + private String channelCode;
59 51
60 @ExcelProperty("订单支付成功时间") 52 @ExcelProperty("订单支付成功时间")
61 private LocalDateTime successTime; 53 private LocalDateTime successTime;
@@ -63,24 +55,11 @@ public class PayOrderExcelVO { @@ -63,24 +55,11 @@ public class PayOrderExcelVO {
63 @ExcelProperty("订单失效时间") 55 @ExcelProperty("订单失效时间")
64 private LocalDateTime expireTime; 56 private LocalDateTime expireTime;
65 57
66 - @ExcelProperty("订单支付通知时间")  
67 - private LocalDateTime notifyTime;  
68 -  
69 - @ExcelProperty(value = "渠道编号名称")  
70 - private String channelCodeName;  
71 -  
72 - @ExcelProperty("用户 IP")  
73 - private String userIp;  
74 -  
75 - @DictFormat(DictTypeConstants.ORDER_REFUND_STATUS)  
76 - @ExcelProperty(value = "退款状态", converter = DictConvert.class)  
77 - private Integer refundStatus;  
78 -  
79 - @ExcelProperty("退款次数")  
80 - private Integer refundTimes; 58 + @ExcelProperty(value = "应用名称")
  59 + private String appName;
81 60
82 - @ExcelProperty("退款总金额,单位:元")  
83 - private String refundPrice; 61 + @ExcelProperty("商品标题")
  62 + private String subject;
84 63
85 @ExcelProperty("商品描述") 64 @ExcelProperty("商品描述")
86 private String body; 65 private String body;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExportReqVO.java
@@ -12,75 +12,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -12,75 +12,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
12 @Data 12 @Data
13 public class PayOrderExportReqVO { 13 public class PayOrderExportReqVO {
14 14
15 - @Schema(description = "应用编号") 15 + @Schema(description = "应用编号", example = "1024")
16 private Long appId; 16 private Long appId;
17 17
18 - @Schema(description = "渠道编号")  
19 - private Long channelId;  
20 -  
21 - @Schema(description = "渠道编码") 18 + @Schema(description = "渠道编码", example = "wx_app")
22 private String channelCode; 19 private String channelCode;
23 20
24 - @Schema(description = "商户订单编号") 21 + @Schema(description = "商户订单编号", example = "4096")
25 private String merchantOrderId; 22 private String merchantOrderId;
26 23
27 - @Schema(description = "商品标题")  
28 - private String subject;  
29 -  
30 - @Schema(description = "商品描述")  
31 - private String body;  
32 -  
33 - @Schema(description = "异步通知地址")  
34 - private String notifyUrl;  
35 -  
36 - @Schema(description = "通知商户支付结果的回调状态")  
37 - private Integer notifyStatus;  
38 -  
39 - @Schema(description = "支付金额,单位:分")  
40 - private Long price;  
41 -  
42 - @Schema(description = "渠道手续费,单位:百分比")  
43 - private Double channelFeeRate; 24 + @Schema(description = "渠道编号", example = "1888")
  25 + private String channelOrderNo;
44 26
45 - @Schema(description = "渠道手续金额,单位:分")  
46 - private Long channelFeePrice; 27 + @Schema(description = "支付单号", example = "2014888")
  28 + private String no;
47 29
48 - @Schema(description = "支付状态") 30 + @Schema(description = "支付状态", example = "0")
49 private Integer status; 31 private Integer status;
50 32
51 - @Schema(description = "用户 IP")  
52 - private String userIp;  
53 -  
54 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
55 - @Schema(description = "订单失效时间")  
56 - private LocalDateTime[] expireTime;  
57 -  
58 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
59 - @Schema(description = "开始订单支付成功时间")  
60 - private LocalDateTime[] successTime;  
61 -  
62 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
63 - @Schema(description = "开始订单支付通知时间")  
64 - private LocalDateTime[] notifyTime;  
65 -  
66 - @Schema(description = "支付成功的订单拓展单编号")  
67 - private Long successExtensionId;  
68 -  
69 - @Schema(description = "退款状态")  
70 - private Integer refundStatus;  
71 -  
72 - @Schema(description = "退款次数")  
73 - private Integer refundTimes;  
74 -  
75 - @Schema(description = "退款总金额,单位:分")  
76 - private Long refundPrice;  
77 -  
78 - @Schema(description = "渠道用户编号")  
79 - private String channelUserId;  
80 -  
81 - @Schema(description = "渠道订单号")  
82 - private String channelOrderNo;  
83 -  
84 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 33 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
85 @Schema(description = "创建时间") 34 @Schema(description = "创建时间")
86 private LocalDateTime[] createTime; 35 private LocalDateTime[] createTime;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageItemRespVO.java
@@ -13,20 +13,13 @@ import java.time.LocalDateTime; @@ -13,20 +13,13 @@ import java.time.LocalDateTime;
13 @ToString(callSuper = true) 13 @ToString(callSuper = true)
14 public class PayOrderPageItemRespVO extends PayOrderBaseVO { 14 public class PayOrderPageItemRespVO extends PayOrderBaseVO {
15 15
16 - @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED) 16 + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
17 private Long id; 17 private Long id;
18 18
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 20 private LocalDateTime createTime;
21 21
22 - @Schema(description = "应用名称") 22 + @Schema(description = "应用名称", example = "wx_pay")
23 private String appName; 23 private String appName;
24 24
25 - @Schema(description = "渠道名称")  
26 - private String channelCodeName;  
27 -  
28 - @Schema(description = "支付订单号")  
29 - private String no;  
30 -  
31 -  
32 } 25 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageReqVO.java
@@ -17,75 +17,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -17,75 +17,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 @ToString(callSuper = true) 17 @ToString(callSuper = true)
18 public class PayOrderPageReqVO extends PageParam { 18 public class PayOrderPageReqVO extends PageParam {
19 19
20 - @Schema(description = "应用编号") 20 + @Schema(description = "应用编号", example = "1024")
21 private Long appId; 21 private Long appId;
22 22
23 - @Schema(description = "渠道编号")  
24 - private Long channelId;  
25 -  
26 - @Schema(description = "渠道编码") 23 + @Schema(description = "渠道编码", example = "wx_app")
27 private String channelCode; 24 private String channelCode;
28 25
29 - @Schema(description = "商户订单编号") 26 + @Schema(description = "商户订单编号", example = "4096")
30 private String merchantOrderId; 27 private String merchantOrderId;
31 28
32 - @Schema(description = "商品标题")  
33 - private String subject;  
34 -  
35 - @Schema(description = "商品描述")  
36 - private String body;  
37 -  
38 - @Schema(description = "异步通知地址")  
39 - private String notifyUrl;  
40 -  
41 - @Schema(description = "通知商户支付结果的回调状态")  
42 - private Integer notifyStatus;  
43 -  
44 - @Schema(description = "支付金额,单位:分")  
45 - private Long price;  
46 -  
47 - @Schema(description = "渠道手续费,单位:百分比")  
48 - private Double channelFeeRate; 29 + @Schema(description = "渠道编号", example = "1888")
  30 + private String channelOrderNo;
49 31
50 - @Schema(description = "渠道手续金额,单位:分")  
51 - private Long channelFeePrice; 32 + @Schema(description = "支付单号", example = "2014888")
  33 + private String no;
52 34
53 - @Schema(description = "支付状态") 35 + @Schema(description = "支付状态", example = "0")
54 private Integer status; 36 private Integer status;
55 37
56 - @Schema(description = "用户 IP")  
57 - private String userIp;  
58 -  
59 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
60 - @Schema(description = "订单失效时间")  
61 - private LocalDateTime[] expireTime;  
62 -  
63 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
64 - @Schema(description = "订单支付成功时间")  
65 - private LocalDateTime[] successTime;  
66 -  
67 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
68 - @Schema(description = "订单支付通知时间")  
69 - private LocalDateTime[] notifyTime;  
70 -  
71 - @Schema(description = "支付成功的订单拓展单编号")  
72 - private Long successExtensionId;  
73 -  
74 - @Schema(description = "退款状态")  
75 - private Integer refundStatus;  
76 -  
77 - @Schema(description = "退款次数")  
78 - private Integer refundTimes;  
79 -  
80 - @Schema(description = "退款总金额,单位:分")  
81 - private Long refundPrice;  
82 -  
83 - @Schema(description = "渠道用户编号")  
84 - private String channelUserId;  
85 -  
86 - @Schema(description = "渠道订单号")  
87 - private String channelOrderNo;  
88 -  
89 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 38 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
90 @Schema(description = "创建时间") 39 @Schema(description = "创建时间")
91 private LocalDateTime[] createTime; 40 private LocalDateTime[] createTime;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java 100755 → 100644
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java
1 package cn.iocoder.yudao.module.pay.controller.admin.refund; 1 package cn.iocoder.yudao.module.pay.controller.admin.refund;
2 2
3 import cn.hutool.core.collection.CollectionUtil; 3 import cn.hutool.core.collection.CollectionUtil;
4 -import cn.hutool.core.util.ObjectUtil; 4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  7 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
5 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*; 8 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
6 import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; 9 import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
8 -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;  
9 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
10 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 12 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
11 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 13 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
12 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 14 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
13 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
14 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
15 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
16 -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;  
17 -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;  
18 -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;  
19 -import io.swagger.v3.oas.annotations.tags.Tag;  
20 -import io.swagger.v3.oas.annotations.Parameter;  
21 import io.swagger.v3.oas.annotations.Operation; 15 import io.swagger.v3.oas.annotations.Operation;
  16 +import io.swagger.v3.oas.annotations.Parameter;
  17 +import io.swagger.v3.oas.annotations.tags.Tag;
22 import org.springframework.security.access.prepost.PreAuthorize; 18 import org.springframework.security.access.prepost.PreAuthorize;
23 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
24 import org.springframework.web.bind.annotation.GetMapping; 20 import org.springframework.web.bind.annotation.GetMapping;
@@ -35,6 +31,7 @@ import java.util.List; @@ -35,6 +31,7 @@ import java.util.List;
35 import java.util.Map; 31 import java.util.Map;
36 32
37 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 33 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
38 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; 35 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
39 36
40 @Tag(name = "管理后台 - 退款订单") 37 @Tag(name = "管理后台 - 退款订单")
@@ -56,20 +53,13 @@ public class PayRefundController { @@ -56,20 +53,13 @@ public class PayRefundController {
56 @PreAuthorize("@ss.hasPermission('pay:refund:query')") 53 @PreAuthorize("@ss.hasPermission('pay:refund:query')")
57 public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) { 54 public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) {
58 PayRefundDO refund = refundService.getRefund(id); 55 PayRefundDO refund = refundService.getRefund(id);
59 - if (ObjectUtil.isNull(refund)) { 56 + if (refund == null) {
60 return success(new PayRefundDetailsRespVO()); 57 return success(new PayRefundDetailsRespVO());
61 } 58 }
62 59
63 - PayAppDO appDO = appService.getApp(refund.getAppId());  
64 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(refund.getChannelCode());  
65 - PayOrderDO orderDO = orderService.getOrder(refund.getOrderId());  
66 -  
67 - PayRefundDetailsRespVO refundDetail = PayRefundConvert.INSTANCE.refundDetailConvert(refund);  
68 - refundDetail.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
69 - refundDetail.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
70 - refundDetail.setSubject(orderDO.getSubject());  
71 -  
72 - return success(refundDetail); 60 + // 拼接数据
  61 + PayAppDO app = appService.getApp(refund.getAppId());
  62 + return success(PayRefundConvert.INSTANCE.convert(refund, app));
73 } 63 }
74 64
75 @GetMapping("/page") 65 @GetMapping("/page")
@@ -82,21 +72,8 @@ public class PayRefundController { @@ -82,21 +72,8 @@ public class PayRefundController {
82 } 72 }
83 73
84 // 处理应用ID数据 74 // 处理应用ID数据
85 - Map<Long, PayAppDO> appMap = appService.getAppMap(  
86 - CollectionUtils.convertList(pageResult.getList(), PayRefundDO::getAppId));  
87 - List<PayRefundPageItemRespVO> list = new ArrayList<>(pageResult.getList().size());  
88 - pageResult.getList().forEach(c -> {  
89 - PayAppDO appDO = appMap.get(c.getAppId());  
90 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());  
91 -  
92 - PayRefundPageItemRespVO item = PayRefundConvert.INSTANCE.pageItemConvert(c);  
93 -  
94 - item.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
95 - item.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
96 - list.add(item);  
97 - });  
98 -  
99 - return success(new PageResult<>(list, pageResult.getTotal())); 75 + Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayRefundDO::getAppId));
  76 + return success(PayRefundConvert.INSTANCE.convertPage(pageResult, appMap));
100 } 77 }
101 78
102 @GetMapping("/export-excel") 79 @GetMapping("/export-excel")
@@ -105,36 +82,18 @@ public class PayRefundController { @@ -105,36 +82,18 @@ public class PayRefundController {
105 @OperateLog(type = EXPORT) 82 @OperateLog(type = EXPORT)
106 public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO, 83 public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO,
107 HttpServletResponse response) throws IOException { 84 HttpServletResponse response) throws IOException {
108 -  
109 List<PayRefundDO> list = refundService.getRefundList(exportReqVO); 85 List<PayRefundDO> list = refundService.getRefundList(exportReqVO);
110 if (CollectionUtil.isEmpty(list)) { 86 if (CollectionUtil.isEmpty(list)) {
111 ExcelUtils.write(response, "退款订单.xls", "数据", 87 ExcelUtils.write(response, "退款订单.xls", "数据",
112 PayRefundExcelVO.class, new ArrayList<>()); 88 PayRefundExcelVO.class, new ArrayList<>());
  89 + return;
113 } 90 }
114 91
115 - // 处理应用ID数据  
116 - Map<Long, PayAppDO> appMap = appService.getAppMap(  
117 - CollectionUtils.convertList(list, PayRefundDO::getAppId));  
118 -  
119 - List<PayRefundExcelVO> excelDatum = new ArrayList<>(list.size());  
120 - // 处理商品名称数据  
121 - Map<Long, PayOrderDO> orderMap = orderService.getOrderSubjectMap(  
122 - CollectionUtils.convertList(list, PayRefundDO::getOrderId));  
123 -  
124 - list.forEach(c -> {  
125 - PayAppDO appDO = appMap.get(c.getAppId());  
126 - PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());  
127 -  
128 - PayRefundExcelVO excelItem = PayRefundConvert.INSTANCE.excelConvert(c);  
129 - excelItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");  
130 - excelItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");  
131 - excelItem.setSubject(orderMap.get(c.getOrderId()).getSubject());  
132 -  
133 - excelDatum.add(excelItem);  
134 - });  
135 - 92 + // 拼接返回
  93 + Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(list, PayRefundDO::getAppId));
  94 + List<PayRefundExcelVO> excelList = PayRefundConvert.INSTANCE.convertList(list, appMap);
136 // 导出 Excel 95 // 导出 Excel
137 - ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelDatum); 96 + ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelList);
138 } 97 }
139 98
140 } 99 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundBaseVO.java
1 package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; 1 package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
  2 +
2 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
3 import lombok.Data; 4 import lombok.Data;
4 -import org.springframework.format.annotation.DateTimeFormat;  
5 5
6 -import javax.validation.constraints.NotNull;  
7 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
8 7
9 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;  
10 -  
11 /** 8 /**
12 * 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用 9 * 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用
13 * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 10 * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
@@ -15,91 +12,67 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -15,91 +12,67 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
15 @Data 12 @Data
16 public class PayRefundBaseVO { 13 public class PayRefundBaseVO {
17 14
18 - @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED)  
19 - @NotNull(message = "应用编号不能为空") 15 + @Schema(description = "外部退款号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110")
  16 + private String no;
  17 +
  18 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
20 private Long appId; 19 private Long appId;
21 20
22 - @Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED)  
23 - @NotNull(message = "渠道编号不能为空") 21 + @Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
24 private Long channelId; 22 private Long channelId;
25 23
26 - @Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED)  
27 - @NotNull(message = "渠道编码不能为空") 24 + @Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_app")
28 private String channelCode; 25 private String channelCode;
29 26
30 - @Schema(description = "支付订单编号 pay_order 表id", requiredMode = Schema.RequiredMode.REQUIRED)  
31 - @NotNull(message = "支付订单编号 pay_order 表id不能为空") 27 + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
32 private Long orderId; 28 private Long orderId;
33 29
34 - @Schema(description = "交易订单号 pay_extension 表no 字段", requiredMode = Schema.RequiredMode.REQUIRED)  
35 - @NotNull(message = "交易订单号 pay_extension 表no 字段不能为空")  
36 - private String tradeNo; 30 + // ========== 商户相关字段 ==========
37 31
38 - @Schema(description = "商户订单编号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)  
39 - @NotNull(message = "商户订单编号(商户系统生成)不能为空") 32 + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "225")
40 private String merchantOrderId; 33 private String merchantOrderId;
41 34
42 - @Schema(description = "商户退款订单号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)  
43 - @NotNull(message = "商户退款订单号(商户系统生成)不能为空")  
44 - private String merchantRefundNo; 35 + @Schema(description = "商户退款订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
  36 + private String merchantRefundId;
45 37
46 - @Schema(description = "异步通知商户地址", requiredMode = Schema.RequiredMode.REQUIRED)  
47 - @NotNull(message = "异步通知商户地址不能为空") 38 + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED)
48 private String notifyUrl; 39 private String notifyUrl;
49 40
50 - @Schema(description = "通知商户退款结果的回调状态", requiredMode = Schema.RequiredMode.REQUIRED)  
51 - @NotNull(message = "通知商户退款结果的回调状态不能为空")  
52 - private Integer notifyStatus; 41 + // ========== 退款相关字段 ==========
53 42
54 - @Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED)  
55 - @NotNull(message = "退款状态不能为空") 43 + @Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
56 private Integer status; 44 private Integer status;
57 45
58 - @Schema(description = "退款类型(部分退款,全部退款)", requiredMode = Schema.RequiredMode.REQUIRED)  
59 - @NotNull(message = "退款类型(部分退款,全部退款)不能为空")  
60 - private Integer type;  
61 -  
62 - @Schema(description = "支付金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)  
63 - @NotNull(message = "支付金额,单位分不能为空")  
64 - private Long payAmount; 46 + @Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  47 + private Long payPrice;
65 48
66 - @Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)  
67 - @NotNull(message = "退款金额,单位分不能为空")  
68 - private Long refundAmount; 49 + @Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
  50 + private Long refundPrice;
69 51
70 - @Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED)  
71 - @NotNull(message = "退款原因不能为空") 52 + @Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要退了")
72 private String reason; 53 private String reason;
73 54
74 - @Schema(description = "用户 IP") 55 + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
75 private String userIp; 56 private String userIp;
76 57
77 - @Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应", requiredMode = Schema.RequiredMode.REQUIRED)  
78 - @NotNull(message = "渠道订单号,pay_order 中的channel_order_no 对应不能为空") 58 + // ========== 渠道相关字段 ==========
  59 +
  60 + @Schema(description = "渠道订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "233")
79 private String channelOrderNo; 61 private String channelOrderNo;
80 62
81 - @Schema(description = "渠道退款单号,渠道返回") 63 + @Schema(description = "渠道退款单号", example = "2022")
82 private String channelRefundNo; 64 private String channelRefundNo;
83 65
84 - @Schema(description = "渠道调用报错时,错误码") 66 + @Schema(description = "退款成功时间")
  67 + private LocalDateTime successTime;
  68 +
  69 + @Schema(description = "调用渠道的错误码")
85 private String channelErrorCode; 70 private String channelErrorCode;
86 71
87 - @Schema(description = "渠道调用报错时,错误信息") 72 + @Schema(description = "调用渠道的错误提示")
88 private String channelErrorMsg; 73 private String channelErrorMsg;
89 74
90 @Schema(description = "支付渠道的额外参数") 75 @Schema(description = "支付渠道的额外参数")
91 - private String channelExtras;  
92 -  
93 - @Schema(description = "退款失效时间")  
94 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
95 - private LocalDateTime expireTime;  
96 -  
97 - @Schema(description = "退款成功时间")  
98 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
99 - private LocalDateTime successTime;  
100 -  
101 - @Schema(description = "退款通知时间")  
102 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
103 - private LocalDateTime notifyTime; 76 + private String channelNotifyData;
104 77
105 } 78 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundCreateReqVO.java deleted
1 -package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;  
2 -import io.swagger.v3.oas.annotations.media.Schema;  
3 -import lombok.*;  
4 -  
5 -@Schema(description = "管理后台 - 退款订单创建 Request VO")  
6 -@Data  
7 -@EqualsAndHashCode(callSuper = true)  
8 -@ToString(callSuper = true)  
9 -public class PayRefundCreateReqVO extends PayRefundBaseVO {  
10 -  
11 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundDetailsRespVO.java
@@ -5,7 +5,6 @@ import lombok.Data; @@ -5,7 +5,6 @@ import lombok.Data;
5 import lombok.EqualsAndHashCode; 5 import lombok.EqualsAndHashCode;
6 import lombok.ToString; 6 import lombok.ToString;
7 7
8 -import javax.validation.constraints.NotNull;  
9 import java.time.LocalDateTime; 8 import java.time.LocalDateTime;
10 9
11 @Schema(description = "管理后台 - 退款订单详情 Response VO") 10 @Schema(description = "管理后台 - 退款订单详情 Response VO")
@@ -17,14 +16,11 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO { @@ -17,14 +16,11 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
17 @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED) 16 @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
18 private Long id; 17 private Long id;
19 18
20 - @Schema(description = "应用名称") 19 + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
21 private String appName; 20 private String appName;
22 21
23 - @Schema(description = "渠道编号名称")  
24 - private String channelCodeName;  
25 -  
26 - @NotNull(message = "商品标题不能为空")  
27 - private String subject; 22 + @Schema(description = "支付订单", requiredMode = Schema.RequiredMode.REQUIRED)
  23 + private Order order;
28 24
29 @Schema(description = "创建时间") 25 @Schema(description = "创建时间")
30 private LocalDateTime createTime; 26 private LocalDateTime createTime;
@@ -32,4 +28,13 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO { @@ -32,4 +28,13 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
32 @Schema(description = "更新时间") 28 @Schema(description = "更新时间")
33 private LocalDateTime updateTime; 29 private LocalDateTime updateTime;
34 30
  31 + @Schema(description = "管理后台 - 支付订单")
  32 + @Data
  33 + public static class Order {
  34 +
  35 + @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
  36 + private String subject;
  37 +
  38 + }
  39 +
35 } 40 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
2 2
3 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; 3 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
4 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; 4 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  5 +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
5 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; 6 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
6 import com.alibaba.excel.annotation.ExcelProperty; 7 import com.alibaba.excel.annotation.ExcelProperty;
7 import lombok.Data; 8 import lombok.Data;
@@ -19,64 +20,42 @@ public class PayRefundExcelVO { @@ -19,64 +20,42 @@ public class PayRefundExcelVO {
19 @ExcelProperty("支付退款编号") 20 @ExcelProperty("支付退款编号")
20 private Long id; 21 private Long id;
21 22
22 - @ExcelProperty("商品名称")  
23 - private String subject; 23 + @ExcelProperty("创建时间")
  24 + private LocalDateTime createTime;
24 25
25 - @ExcelProperty(value = "应用名称")  
26 - private String appName; 26 + @ExcelProperty(value = "支付金额", converter = MoneyConvert.class)
  27 + private Integer payPrice;
27 28
28 - @ExcelProperty(value = "渠道编号名称")  
29 - private String channelCodeName; 29 + @ExcelProperty(value = "退款金额", converter = MoneyConvert.class)
  30 + private Integer refundPrice;
30 31
31 - @ExcelProperty("交易订单号")  
32 - private String tradeNo; 32 + @ExcelProperty("商户退款单号")
  33 + private String merchantRefundId;
  34 + @ExcelProperty("退款单号")
  35 + private String no;
  36 + @ExcelProperty("渠道退款单号")
  37 + private String channelRefundNo;
33 38
34 - @ExcelProperty("商户订单编号") 39 + @ExcelProperty("商户支付单号")
35 private String merchantOrderId; 40 private String merchantOrderId;
  41 + @ExcelProperty("渠道支付单号")
  42 + private String channelOrderNo;
36 43
37 - @ExcelProperty("商户退款订单号")  
38 - private String merchantRefundNo;  
39 -  
40 - @ExcelProperty("异步通知商户地址")  
41 - private String notifyUrl;  
42 -  
43 - @DictFormat(DictTypeConstants.ORDER_NOTIFY_STATUS)  
44 - @ExcelProperty(value = "商户退款结果回调状态", converter = DictConvert.class)  
45 - private Integer notifyStatus;  
46 -  
47 - @DictFormat(DictTypeConstants.REFUND_ORDER_STATUS)  
48 @ExcelProperty(value = "退款状态", converter = DictConvert.class) 44 @ExcelProperty(value = "退款状态", converter = DictConvert.class)
  45 + @DictFormat(DictTypeConstants.REFUND_STATUS)
49 private Integer status; 46 private Integer status;
50 47
51 - @DictFormat(DictTypeConstants.REFUND_ORDER_TYPE)  
52 - @ExcelProperty(value = "退款类型", converter = DictConvert.class)  
53 - private Integer type; 48 + @ExcelProperty(value = "退款渠道", converter = DictConvert.class)
  49 + @DictFormat(DictTypeConstants.CHANNEL_CODE)
  50 + private String channelCode;
54 51
55 - @ExcelProperty("支付金额,单位:元")  
56 - private String payPrice; 52 + @ExcelProperty("成功时间")
  53 + private LocalDateTime successTime;
57 54
58 - @ExcelProperty("退款金额,单位:元")  
59 - private String refundPrice; 55 + @ExcelProperty(value = "支付应用")
  56 + private String appName;
60 57
61 @ExcelProperty("退款原因") 58 @ExcelProperty("退款原因")
62 private String reason; 59 private String reason;
63 60
64 - @ExcelProperty("用户付款 IP")  
65 - private String userIp;  
66 -  
67 - @ExcelProperty("渠道订单号")  
68 - private String channelOrderNo;  
69 -  
70 - @ExcelProperty("渠道退款单号")  
71 - private String channelRefundNo;  
72 -  
73 - @ExcelProperty("创建时间")  
74 - private LocalDateTime createTime;  
75 -  
76 - @ExcelProperty("退款成功时间")  
77 - private LocalDateTime successTime;  
78 -  
79 - @ExcelProperty("退款失效时间")  
80 - private LocalDateTime expireTime;  
81 -  
82 } 61 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExportReqVO.java
@@ -12,77 +12,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -12,77 +12,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
12 @Data 12 @Data
13 public class PayRefundExportReqVO { 13 public class PayRefundExportReqVO {
14 14
15 - @Schema(description = "应用编号") 15 + @Schema(description = "应用编号", example = "1024")
16 private Long appId; 16 private Long appId;
17 17
18 - @Schema(description = "渠道编号")  
19 - private Long channelId;  
20 -  
21 - @Schema(description = "渠道编码") 18 + @Schema(description = "渠道编码", example = "wx_app")
22 private String channelCode; 19 private String channelCode;
23 20
24 - @Schema(description = "支付订单编号 pay_order 表id")  
25 - private Long orderId;  
26 -  
27 - @Schema(description = "交易订单号 pay_extension 表no 字段")  
28 - private String tradeNo;  
29 -  
30 - @Schema(description = "商户订单编号(商户系统生成)") 21 + @Schema(description = "商户支付单号", example = "10")
31 private String merchantOrderId; 22 private String merchantOrderId;
32 23
33 - @Schema(description = "商户退款订单号(商户系统生成)")  
34 - private String merchantRefundNo;  
35 -  
36 - @Schema(description = "异步通知商户地址")  
37 - private String notifyUrl;  
38 -  
39 - @Schema(description = "通知商户退款结果的回调状态")  
40 - private Integer notifyStatus;  
41 -  
42 - @Schema(description = "退款状态")  
43 - private Integer status;  
44 -  
45 - @Schema(description = "退款类型(部分退款,全部退款)")  
46 - private Integer type;  
47 -  
48 - @Schema(description = "支付金额,单位分")  
49 - private Long payPrice;  
50 -  
51 - @Schema(description = "退款金额,单位分")  
52 - private Long refundPrice;  
53 -  
54 - @Schema(description = "退款原因")  
55 - private String reason; 24 + @Schema(description = "商户退款单号", example = "20")
  25 + private String merchantRefundId;
56 26
57 - @Schema(description = "用户 IP")  
58 - private String userIp;  
59 -  
60 - @Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应") 27 + @Schema(description = "渠道支付单号", example = "30")
61 private String channelOrderNo; 28 private String channelOrderNo;
62 29
63 - @Schema(description = "渠道退款单号,渠道返回") 30 + @Schema(description = "渠道退款单号", example = "40")
64 private String channelRefundNo; 31 private String channelRefundNo;
65 32
66 - @Schema(description = "渠道调用报错时,错误码")  
67 - private String channelErrorCode;  
68 -  
69 - @Schema(description = "渠道调用报错时,错误信息")  
70 - private String channelErrorMsg;  
71 -  
72 - @Schema(description = "支付渠道的额外参数")  
73 - private String channelExtras;  
74 -  
75 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
76 - @Schema(description = "退款失效时间")  
77 - private LocalDateTime[] expireTime;  
78 -  
79 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
80 - @Schema(description = "退款成功时间")  
81 - private LocalDateTime[] successTime;  
82 -  
83 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
84 - @Schema(description = "退款通知时间")  
85 - private LocalDateTime[] notifyTime; 33 + @Schema(description = "退款状态", example = "0")
  34 + private Integer status;
86 35
87 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 36 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
88 @Schema(description = "创建时间") 37 @Schema(description = "创建时间")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageItemRespVO.java
@@ -13,15 +13,12 @@ import java.time.LocalDateTime; @@ -13,15 +13,12 @@ import java.time.LocalDateTime;
13 @ToString(callSuper = true) 13 @ToString(callSuper = true)
14 public class PayRefundPageItemRespVO extends PayRefundBaseVO { 14 public class PayRefundPageItemRespVO extends PayRefundBaseVO {
15 15
16 - @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED) 16 + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
17 private Long id; 17 private Long id;
18 18
19 - @Schema(description = "应用名称") 19 + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
20 private String appName; 20 private String appName;
21 21
22 - @Schema(description = "渠道名称")  
23 - private String channelCodeName;  
24 -  
25 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 22 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
26 private LocalDateTime createTime; 23 private LocalDateTime createTime;
27 24
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageReqVO.java
@@ -17,77 +17,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -17,77 +17,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 @ToString(callSuper = true) 17 @ToString(callSuper = true)
18 public class PayRefundPageReqVO extends PageParam { 18 public class PayRefundPageReqVO extends PageParam {
19 19
20 - @Schema(description = "应用编号") 20 + @Schema(description = "应用编号", example = "1024")
21 private Long appId; 21 private Long appId;
22 22
23 - @Schema(description = "渠道编号")  
24 - private Long channelId;  
25 -  
26 - @Schema(description = "渠道编码") 23 + @Schema(description = "渠道编码", example = "wx_app")
27 private String channelCode; 24 private String channelCode;
28 25
29 - @Schema(description = "支付订单编号 pay_order 表id")  
30 - private Long orderId;  
31 -  
32 - @Schema(description = "交易订单号 pay_extension 表no 字段")  
33 - private String tradeNo;  
34 -  
35 - @Schema(description = "商户订单编号(商户系统生成)") 26 + @Schema(description = "商户支付单号", example = "10")
36 private String merchantOrderId; 27 private String merchantOrderId;
37 28
38 - @Schema(description = "商户退款订单号(商户系统生成)")  
39 - private String merchantRefundNo;  
40 -  
41 - @Schema(description = "异步通知商户地址")  
42 - private String notifyUrl;  
43 -  
44 - @Schema(description = "通知商户退款结果的回调状态")  
45 - private Integer notifyStatus;  
46 -  
47 - @Schema(description = "退款状态")  
48 - private Integer status;  
49 -  
50 - @Schema(description = "退款类型(部分退款,全部退款)")  
51 - private Integer type;  
52 -  
53 - @Schema(description = "支付金额,单位分")  
54 - private Long payPrice;  
55 -  
56 - @Schema(description = "退款金额,单位分")  
57 - private Long refundPrice;  
58 -  
59 - @Schema(description = "退款原因")  
60 - private String reason; 29 + @Schema(description = "商户退款单号", example = "20")
  30 + private String merchantRefundId;
61 31
62 - @Schema(description = "用户 IP")  
63 - private String userIp;  
64 -  
65 - @Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应") 32 + @Schema(description = "渠道支付单号", example = "30")
66 private String channelOrderNo; 33 private String channelOrderNo;
67 34
68 - @Schema(description = "渠道退款单号,渠道返回") 35 + @Schema(description = "渠道退款单号", example = "40")
69 private String channelRefundNo; 36 private String channelRefundNo;
70 37
71 - @Schema(description = "渠道调用报错时,错误码")  
72 - private String channelErrorCode;  
73 -  
74 - @Schema(description = "渠道调用报错时,错误信息")  
75 - private String channelErrorMsg;  
76 -  
77 - @Schema(description = "支付渠道的额外参数")  
78 - private String channelExtras;  
79 -  
80 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
81 - @Schema(description = "退款失效时间")  
82 - private LocalDateTime[] expireTime;  
83 -  
84 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
85 - @Schema(description = "退款成功时间")  
86 - private LocalDateTime[] successTime;  
87 -  
88 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
89 - @Schema(description = "退款通知时间")  
90 - private LocalDateTime[] notifyTime; 38 + @Schema(description = "退款状态", example = "0")
  39 + private Integer status;
91 40
92 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 41 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
93 @Schema(description = "创建时间") 42 @Schema(description = "创建时间")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundUpdateReqVO.java deleted
1 -package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;  
2 -import io.swagger.v3.oas.annotations.media.Schema;  
3 -import lombok.*;  
4 -import javax.validation.constraints.*;  
5 -  
6 -@Schema(description = "管理后台 - 退款订单更新 Request VO")  
7 -@Data  
8 -@EqualsAndHashCode(callSuper = true)  
9 -@ToString(callSuper = true)  
10 -public class PayRefundUpdateReqVO extends PayRefundBaseVO {  
11 -  
12 - @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)  
13 - @NotNull(message = "支付退款编号不能为空")  
14 - private Long id;  
15 -  
16 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/notify/PayNotifyTaskConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.convert.notify;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  5 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
  6 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
  7 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
  8 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
  9 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
  10 +import org.mapstruct.Mapper;
  11 +import org.mapstruct.factory.Mappers;
  12 +
  13 +import java.util.List;
  14 +import java.util.Map;
  15 +
  16 +/**
  17 + * 支付通知 Convert
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@Mapper
  22 +public interface PayNotifyTaskConvert {
  23 +
  24 + PayNotifyTaskConvert INSTANCE = Mappers.getMapper(PayNotifyTaskConvert.class);
  25 +
  26 + PayNotifyTaskRespVO convert(PayNotifyTaskDO bean);
  27 +
  28 + default PageResult<PayNotifyTaskRespVO> convertPage(PageResult<PayNotifyTaskDO> page, Map<Long, PayAppDO> appMap){
  29 + PageResult<PayNotifyTaskRespVO> result = convertPage(page);
  30 + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
  31 + return result;
  32 + }
  33 + PageResult<PayNotifyTaskRespVO> convertPage(PageResult<PayNotifyTaskDO> page);
  34 +
  35 + default PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, PayAppDO app, List<PayNotifyLogDO> logs) {
  36 + PayNotifyTaskDetailRespVO respVO = convert(task, logs);
  37 + if (app != null) {
  38 + respVO.setAppName(app.getName());
  39 + }
  40 + return respVO;
  41 + }
  42 + PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, List<PayNotifyLogDO> logs);
  43 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
1 package cn.iocoder.yudao.module.pay.convert.order; 1 package cn.iocoder.yudao.module.pay.convert.order;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
5 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 7 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
6 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; 8 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
7 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; 9 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
8 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; 10 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
  11 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
9 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 12 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
10 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; 13 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
11 import org.mapstruct.Mapper; 14 import org.mapstruct.Mapper;
12 import org.mapstruct.Mapping; 15 import org.mapstruct.Mapping;
13 import org.mapstruct.factory.Mappers; 16 import org.mapstruct.factory.Mappers;
14 17
15 -import java.math.BigDecimal;  
16 -import java.math.RoundingMode;  
17 import java.util.List; 18 import java.util.List;
  19 +import java.util.Map;
18 20
19 /** 21 /**
20 * 支付订单 Convert 22 * 支付订单 Convert
@@ -30,60 +32,32 @@ public interface PayOrderConvert { @@ -30,60 +32,32 @@ public interface PayOrderConvert {
30 32
31 PayOrderRespDTO convert2(PayOrderDO order); 33 PayOrderRespDTO convert2(PayOrderDO order);
32 34
33 - PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);  
34 -  
35 - PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);  
36 -  
37 - List<PayOrderRespVO> convertList(List<PayOrderDO> list);  
38 -  
39 - PageResult<PayOrderRespVO> convertPage(PageResult<PayOrderDO> page);  
40 -  
41 - /**  
42 - * 订单 DO 转自定义分页对象  
43 - *  
44 - * @param bean 订单DO  
45 - * @return 分页对象  
46 - */  
47 - PayOrderPageItemRespVO pageConvertItemPage(PayOrderDO bean);  
48 -  
49 - // TODO 芋艿:优化下 convert 逻辑  
50 - default PayOrderExcelVO excelConvert(PayOrderDO bean) {  
51 - if (bean == null) {  
52 - return null; 35 + default PayOrderDetailsRespVO convert(PayOrderDO order, PayOrderExtensionDO orderExtension, PayAppDO app) {
  36 + PayOrderDetailsRespVO respVO = convertDetail(order);
  37 + respVO.setExtension(convert(orderExtension));
  38 + if (app != null) {
  39 + respVO.setAppName(app.getName());
53 } 40 }
  41 + return respVO;
  42 + }
  43 + PayOrderDetailsRespVO convertDetail(PayOrderDO bean);
  44 + PayOrderDetailsRespVO.PayOrderExtension convert(PayOrderExtensionDO bean);
54 45
55 - PayOrderExcelVO payOrderExcelVO = new PayOrderExcelVO();  
56 -  
57 - payOrderExcelVO.setId(bean.getId());  
58 - payOrderExcelVO.setSubject(bean.getSubject());  
59 - payOrderExcelVO.setMerchantOrderId(bean.getMerchantOrderId());  
60 - payOrderExcelVO.setChannelOrderNo(bean.getChannelOrderNo());  
61 - payOrderExcelVO.setStatus(bean.getStatus());  
62 - payOrderExcelVO.setNotifyStatus(bean.getNotifyStatus());  
63 - payOrderExcelVO.setNotifyUrl(bean.getNotifyUrl());  
64 - payOrderExcelVO.setCreateTime(bean.getCreateTime());  
65 - payOrderExcelVO.setSuccessTime(bean.getSuccessTime());  
66 - payOrderExcelVO.setExpireTime(bean.getExpireTime());  
67 - payOrderExcelVO.setNotifyTime(bean.getNotifyTime());  
68 - payOrderExcelVO.setUserIp(bean.getUserIp());  
69 - payOrderExcelVO.setRefundStatus(bean.getRefundStatus());  
70 - payOrderExcelVO.setRefundTimes(bean.getRefundTimes());  
71 - payOrderExcelVO.setBody(bean.getBody());  
72 -  
73 - BigDecimal multiple = new BigDecimal(100);  
74 -  
75 - payOrderExcelVO.setPrice(BigDecimal.valueOf(bean.getPrice())  
76 - .divide(multiple, 2, RoundingMode.HALF_UP).toString());  
77 -  
78 - payOrderExcelVO.setChannelFeePrice(BigDecimal.valueOf(bean.getChannelFeePrice())  
79 - .divide(multiple, 2, RoundingMode.HALF_UP).toString());  
80 - payOrderExcelVO.setChannelFeeRate(java.math.BigDecimal.valueOf(bean.getChannelFeeRate())  
81 - .multiply(multiple).toString());  
82 - payOrderExcelVO.setRefundPrice(BigDecimal.valueOf(bean.getRefundPrice())  
83 - .divide(multiple, 2, RoundingMode.HALF_UP).toString());  
84 -  
85 - return payOrderExcelVO; 46 + default PageResult<PayOrderPageItemRespVO> convertPage(PageResult<PayOrderDO> page, Map<Long, PayAppDO> appMap) {
  47 + PageResult<PayOrderPageItemRespVO> result = convertPage(page);
  48 + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
  49 + return result;
  50 + }
  51 + PageResult<PayOrderPageItemRespVO> convertPage(PageResult<PayOrderDO> page);
  52 +
  53 + default List<PayOrderExcelVO> convertList(List<PayOrderDO> list, Map<Long, PayAppDO> appMap) {
  54 + return CollectionUtils.convertList(list, order -> {
  55 + PayOrderExcelVO excelVO = convertExcel(order);
  56 + MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName()));
  57 + return excelVO;
  58 + });
86 } 59 }
  60 + PayOrderExcelVO convertExcel(PayOrderDO bean);
87 61
88 PayOrderDO convert(PayOrderCreateReqDTO bean); 62 PayOrderDO convert(PayOrderCreateReqDTO bean);
89 63
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java
1 package cn.iocoder.yudao.module.pay.convert.refund; 1 package cn.iocoder.yudao.module.pay.convert.refund;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
4 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; 6 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
5 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; 7 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
6 -import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*; 8 +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundDetailsRespVO;
  9 +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExcelVO;
  10 +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageItemRespVO;
  11 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
  12 +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 13 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
8 import org.mapstruct.Mapper; 14 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 15 import org.mapstruct.factory.Mappers;
10 16
11 -import java.math.BigDecimal;  
12 -import java.math.RoundingMode;  
13 import java.util.List; 17 import java.util.List;
  18 +import java.util.Map;
14 19
15 @Mapper 20 @Mapper
16 public interface PayRefundConvert { 21 public interface PayRefundConvert {
17 22
18 PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class); 23 PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class);
19 24
20 - PayRefundDO convert(PayRefundCreateReqVO bean);  
21 25
22 - PayRefundDO convert(PayRefundUpdateReqVO bean);  
23 -  
24 - PayRefundRespVO convert(PayRefundDO bean);  
25 -  
26 - /**  
27 - * 退款订单 DO 转 退款详情订单 VO  
28 - *  
29 - * @param bean 退款订单 DO  
30 - * @return 退款详情订单 VO  
31 - */  
32 - PayRefundDetailsRespVO refundDetailConvert(PayRefundDO bean);  
33 -  
34 - /**  
35 - * 退款订单DO 转 分页退款条目VO  
36 - *  
37 - * @param bean 退款订单DO  
38 - * @return 分页退款条目VO  
39 - */  
40 - PayRefundPageItemRespVO pageItemConvert(PayRefundDO bean);  
41 -  
42 - List<PayRefundRespVO> convertList(List<PayRefundDO> list);  
43 -  
44 - PageResult<PayRefundRespVO> convertPage(PageResult<PayRefundDO> page);  
45 -  
46 - /**  
47 - * 退款订单DO 转 导出excel VO  
48 - *  
49 - * @param bean 退款订单DO  
50 - * @return 导出 excel VO  
51 - */  
52 - default PayRefundExcelVO excelConvert(PayRefundDO bean) {  
53 - if (bean == null) {  
54 - return null; 26 + default PayRefundDetailsRespVO convert(PayRefundDO refund, PayAppDO app) {
  27 + PayRefundDetailsRespVO respVO = convert(refund);
  28 + if (app != null) {
  29 + respVO.setAppName(app.getName());
55 } 30 }
  31 + return respVO;
  32 + }
  33 + PayRefundDetailsRespVO convert(PayRefundDO bean);
  34 + PayRefundDetailsRespVO.Order convert(PayOrderDO bean);
56 35
57 - PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();  
58 -  
59 - payRefundExcelVO.setId(bean.getId());  
60 - payRefundExcelVO.setTradeNo(bean.getNo());  
61 - payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());  
62 - // TODO 芋艿:晚点在改  
63 -// payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());  
64 - payRefundExcelVO.setNotifyUrl(bean.getNotifyUrl());  
65 - payRefundExcelVO.setNotifyStatus(bean.getNotifyStatus());  
66 - payRefundExcelVO.setStatus(bean.getStatus());  
67 - payRefundExcelVO.setReason(bean.getReason());  
68 - payRefundExcelVO.setUserIp(bean.getUserIp());  
69 - payRefundExcelVO.setChannelOrderNo(bean.getChannelOrderNo());  
70 - payRefundExcelVO.setChannelRefundNo(bean.getChannelRefundNo());  
71 - payRefundExcelVO.setSuccessTime(bean.getSuccessTime());  
72 - payRefundExcelVO.setCreateTime(bean.getCreateTime());  
73 -  
74 - BigDecimal multiple = new BigDecimal(100);  
75 - payRefundExcelVO.setPayPrice(BigDecimal.valueOf(bean.getPayPrice())  
76 - .divide(multiple, 2, RoundingMode.HALF_UP).toString());  
77 - payRefundExcelVO.setRefundPrice(BigDecimal.valueOf(bean.getRefundPrice())  
78 - .divide(multiple, 2, RoundingMode.HALF_UP).toString());  
79 -  
80 - return payRefundExcelVO; 36 + default PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page, Map<Long, PayAppDO> appMap) {
  37 + PageResult<PayRefundPageItemRespVO> result = convertPage(page);
  38 + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
  39 + return result;
81 } 40 }
  41 + PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page);
82 42
83 PayRefundDO convert(PayRefundCreateReqDTO bean); 43 PayRefundDO convert(PayRefundCreateReqDTO bean);
84 44
85 PayRefundRespDTO convert02(PayRefundDO bean); 45 PayRefundRespDTO convert02(PayRefundDO bean);
86 46
  47 + default List<PayRefundExcelVO> convertList(List<PayRefundDO> list, Map<Long, PayAppDO> appMap) {
  48 + return CollectionUtils.convertList(list, order -> {
  49 + PayRefundExcelVO excelVO = convertExcel(order);
  50 + MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName()));
  51 + return excelVO;
  52 + });
  53 + }
  54 + PayRefundExcelVO convertExcel(PayRefundDO bean);
  55 +
87 } 56 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java
@@ -15,7 +15,7 @@ import lombok.experimental.Accessors; @@ -15,7 +15,7 @@ import lombok.experimental.Accessors;
15 import java.time.LocalDateTime; 15 import java.time.LocalDateTime;
16 16
17 /** 17 /**
18 - * 商户支付、退款等的通知 18 + * 支付通知
19 * 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。 19 * 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。
20 * 20 *
21 * @author 芋道源码 21 * @author 芋道源码
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java
@@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 4 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
5 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; 5 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
7 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;  
8 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 7 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
9 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;  
10 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
11 import com.baomidou.mybatisplus.annotation.TableName; 9 import com.baomidou.mybatisplus.annotation.TableName;
12 import lombok.*; 10 import lombok.*;
@@ -71,12 +69,6 @@ public class PayOrderDO extends BaseDO { @@ -71,12 +69,6 @@ public class PayOrderDO extends BaseDO {
71 * 异步通知地址 69 * 异步通知地址
72 */ 70 */
73 private String notifyUrl; 71 private String notifyUrl;
74 - /**  
75 - * 通知商户支付结果的回调状态  
76 - *  
77 - * 枚举 {@link PayOrderNotifyStatusEnum}  
78 - */  
79 - private Integer notifyStatus;  
80 72
81 // ========== 订单相关字段 ========== 73 // ========== 订单相关字段 ==========
82 74
@@ -93,7 +85,7 @@ public class PayOrderDO extends BaseDO { @@ -93,7 +85,7 @@ public class PayOrderDO extends BaseDO {
93 /** 85 /**
94 * 渠道手续金额,单位:分 86 * 渠道手续金额,单位:分
95 */ 87 */
96 - private Long channelFeePrice; 88 + private Integer channelFeePrice;
97 /** 89 /**
98 * 支付状态 90 * 支付状态
99 * 91 *
@@ -113,27 +105,19 @@ public class PayOrderDO extends BaseDO { @@ -113,27 +105,19 @@ public class PayOrderDO extends BaseDO {
113 */ 105 */
114 private LocalDateTime successTime; 106 private LocalDateTime successTime;
115 /** 107 /**
116 - * 订单支付通知时间,即支付渠道的通知时间  
117 - */  
118 - private LocalDateTime notifyTime;  
119 - /**  
120 * 支付成功的订单拓展单编号 108 * 支付成功的订单拓展单编号
121 * 109 *
122 - * 关联 {@link PayOrderDO#getId()} 110 + * 关联 {@link PayOrderExtensionDO#getId()}
123 */ 111 */
124 - private Long successExtensionId;  
125 -  
126 - // ========== 退款相关字段 ========== 112 + private Long extensionId;
127 /** 113 /**
128 - * 退款状态 114 + * 支付成功的外部订单号
129 * 115 *
130 - * 枚举 {@link PayOrderRefundStatusEnum}  
131 - */  
132 - private Integer refundStatus;  
133 - /**  
134 - * 退款次数 116 + * 关联 {@link PayOrderExtensionDO#getNo()}
135 */ 117 */
136 - private Integer refundTimes; 118 + private String no;
  119 +
  120 + // ========== 退款相关字段 ==========
137 /** 121 /**
138 * 退款总金额,单位:分 122 * 退款总金额,单位:分
139 */ 123 */
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; @@ -15,6 +15,7 @@ import java.util.Map;
15 /** 15 /**
16 * 支付订单拓展 DO 16 * 支付订单拓展 DO
17 * 17 *
  18 + * 每次调用支付渠道,都会生成一条对应记录
18 * 19 *
19 * @author 芋道源码 20 * @author 芋道源码
20 */ 21 */
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; 6 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; 7 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
8 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
9 -import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;  
10 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 9 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
11 import com.baomidou.mybatisplus.annotation.KeySequence; 10 import com.baomidou.mybatisplus.annotation.KeySequence;
12 import com.baomidou.mybatisplus.annotation.TableId; 11 import com.baomidou.mybatisplus.annotation.TableId;
@@ -89,12 +88,6 @@ public class PayRefundDO extends BaseDO { @@ -89,12 +88,6 @@ public class PayRefundDO extends BaseDO {
89 * 异步通知地址 88 * 异步通知地址
90 */ 89 */
91 private String notifyUrl; 90 private String notifyUrl;
92 - /**  
93 - * 通知商户退款结果的回调状态  
94 - *  
95 - * 枚举 {@link PayNotifyStatusEnum}  
96 - */  
97 - private Integer notifyStatus;  
98 91
99 // ========== 退款相关字段 ========== 92 // ========== 退款相关字段 ==========
100 /** 93 /**
@@ -147,7 +140,7 @@ public class PayRefundDO extends BaseDO { @@ -147,7 +140,7 @@ public class PayRefundDO extends BaseDO {
147 */ 140 */
148 private String channelErrorCode; 141 private String channelErrorCode;
149 /** 142 /**
150 - * 调用渠道报错时,错误信息 143 + * 调用渠道的错误提示
151 */ 144 */
152 private String channelErrorMsg; 145 private String channelErrorMsg;
153 146
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogMapper.java
@@ -4,6 +4,13 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; @@ -4,6 +4,13 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import org.apache.ibatis.annotations.Mapper; 5 import org.apache.ibatis.annotations.Mapper;
6 6
  7 +import java.util.List;
  8 +
7 @Mapper 9 @Mapper
8 public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> { 10 public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> {
  11 +
  12 + default List<PayNotifyLogDO> selectListByTaskId(Long taskId) {
  13 + return selectList(PayNotifyLogDO::getTaskId, taskId);
  14 + }
  15 +
9 } 16 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskMapper.java
1 package cn.iocoder.yudao.module.pay.dal.mysql.notify; 1 package cn.iocoder.yudao.module.pay.dal.mysql.notify;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
3 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; 7 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
4 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; 8 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
5 -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;  
6 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 9 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
7 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
8 11
9 import java.time.LocalDateTime; 12 import java.time.LocalDateTime;
@@ -21,10 +24,21 @@ public interface PayNotifyTaskMapper extends BaseMapperX&lt;PayNotifyTaskDO&gt; { @@ -21,10 +24,21 @@ public interface PayNotifyTaskMapper extends BaseMapperX&lt;PayNotifyTaskDO&gt; {
21 * @return PayTransactionNotifyTaskDO 数组 24 * @return PayTransactionNotifyTaskDO 数组
22 */ 25 */
23 default List<PayNotifyTaskDO> selectListByNotify() { 26 default List<PayNotifyTaskDO> selectListByNotify() {
24 - return selectList(new QueryWrapper<PayNotifyTaskDO>()  
25 - .in("status", PayNotifyStatusEnum.WAITING.getStatus(), PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus(),  
26 - PayNotifyStatusEnum.REQUEST_FAILURE.getStatus())  
27 - .le("next_notify_time", LocalDateTime.now())); 27 + return selectList(new LambdaQueryWrapper<PayNotifyTaskDO>()
  28 + .in(PayNotifyTaskDO::getStatus, PayNotifyStatusEnum.WAITING.getStatus(),
  29 + PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus())
  30 + .le(PayNotifyTaskDO::getNextNotifyTime, LocalDateTime.now()));
  31 + }
  32 +
  33 + default PageResult<PayNotifyTaskDO> selectPage(PayNotifyTaskPageReqVO reqVO) {
  34 + return selectPage(reqVO, new LambdaQueryWrapperX<PayNotifyTaskDO>()
  35 + .eqIfPresent(PayNotifyTaskDO::getAppId, reqVO.getAppId())
  36 + .eqIfPresent(PayNotifyTaskDO::getType, reqVO.getType())
  37 + .eqIfPresent(PayNotifyTaskDO::getDataId, reqVO.getDataId())
  38 + .eqIfPresent(PayNotifyTaskDO::getStatus, reqVO.getStatus())
  39 + .eqIfPresent(PayNotifyTaskDO::getMerchantOrderId, reqVO.getMerchantOrderId())
  40 + .betweenIfPresent(PayNotifyTaskDO::getCreateTime, reqVO.getCreateTime())
  41 + .orderByDesc(PayNotifyTaskDO::getId));
28 } 42 }
29 43
30 } 44 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java
1 package cn.iocoder.yudao.module.pay.dal.mysql.order; 1 package cn.iocoder.yudao.module.pay.dal.mysql.order;
2 2
3 -import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;  
4 -import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;  
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
7 -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
  7 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
8 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
10 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;  
11 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
12 11
13 -import java.util.Collection;  
14 import java.util.List; 12 import java.util.List;
15 13
16 @Mapper 14 @Mapper
17 public interface PayOrderMapper extends BaseMapperX<PayOrderDO> { 15 public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
18 16
19 default PageResult<PayOrderDO> selectPage(PayOrderPageReqVO reqVO) { 17 default PageResult<PayOrderDO> selectPage(PayOrderPageReqVO reqVO) {
20 - return selectPage(reqVO, new QueryWrapperX<PayOrderDO>()  
21 - .eqIfPresent("app_id", reqVO.getAppId())  
22 - .eqIfPresent("channel_id", reqVO.getChannelId())  
23 - .eqIfPresent("channel_code", reqVO.getChannelCode())  
24 - .likeIfPresent("merchant_order_id", reqVO.getMerchantOrderId())  
25 - .eqIfPresent("notify_status", reqVO.getNotifyStatus())  
26 - .eqIfPresent("status", reqVO.getStatus())  
27 - .eqIfPresent("refund_status", reqVO.getRefundStatus())  
28 - .likeIfPresent("channel_order_no", reqVO.getChannelOrderNo())  
29 - .betweenIfPresent("create_time", reqVO.getCreateTime())  
30 - .orderByDesc("id")); 18 + return selectPage(reqVO, new LambdaQueryWrapperX<PayOrderDO>()
  19 + .eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId())
  20 + .eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode())
  21 + .likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId())
  22 + .likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo())
  23 + .likeIfPresent(PayOrderDO::getNo, reqVO.getNo())
  24 + .eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus())
  25 + .betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime())
  26 + .orderByDesc(PayOrderDO::getId));
31 } 27 }
32 28
33 default List<PayOrderDO> selectList(PayOrderExportReqVO reqVO) { 29 default List<PayOrderDO> selectList(PayOrderExportReqVO reqVO) {
34 - return selectList(new QueryWrapperX<PayOrderDO>()  
35 - .eqIfPresent("app_id", reqVO.getAppId())  
36 - .eqIfPresent("channel_id", reqVO.getChannelId())  
37 - .eqIfPresent("channel_code", reqVO.getChannelCode())  
38 - .likeIfPresent("merchant_order_id", reqVO.getMerchantOrderId())  
39 - .eqIfPresent("notify_status", reqVO.getNotifyStatus())  
40 - .eqIfPresent("status", reqVO.getStatus())  
41 - .eqIfPresent("refund_status", reqVO.getRefundStatus())  
42 - .likeIfPresent("channel_order_no", reqVO.getChannelOrderNo())  
43 - .betweenIfPresent("create_time", reqVO.getCreateTime())  
44 - .orderByDesc("id"));  
45 - }  
46 -  
47 - default List<PayOrderDO> findByIdListQueryOrderSubject(Collection<Long> idList) {  
48 - return selectList(new LambdaQueryWrapper<PayOrderDO>()  
49 - .select(PayOrderDO::getId, PayOrderDO::getSubject)  
50 - .in(PayOrderDO::getId, idList)); 30 + return selectList(new LambdaQueryWrapperX<PayOrderDO>()
  31 + .eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId())
  32 + .eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode())
  33 + .likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId())
  34 + .likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo())
  35 + .likeIfPresent(PayOrderDO::getNo, reqVO.getNo())
  36 + .eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus())
  37 + .betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime())
  38 + .orderByDesc(PayOrderDO::getId));
51 } 39 }
52 40
53 default Long selectCountByAppId(Long appId) { 41 default Long selectCountByAppId(Long appId) {
@@ -55,13 +43,13 @@ public interface PayOrderMapper extends BaseMapperX&lt;PayOrderDO&gt; { @@ -55,13 +43,13 @@ public interface PayOrderMapper extends BaseMapperX&lt;PayOrderDO&gt; {
55 } 43 }
56 44
57 default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) { 45 default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {
58 - return selectOne(new QueryWrapper<PayOrderDO>().eq("app_id", appId)  
59 - .eq("merchant_order_id", merchantOrderId)); 46 + return selectOne(PayOrderDO::getAppId, appId,
  47 + PayOrderDO::getMerchantOrderId, merchantOrderId);
60 } 48 }
61 49
62 default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) { 50 default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) {
63 - return update(update, new QueryWrapper<PayOrderDO>()  
64 - .eq("id", id).eq("status", status)); 51 + return update(update, new LambdaQueryWrapper<PayOrderDO>()
  52 + .eq(PayOrderDO::getId, id).eq(PayOrderDO::getStatus, status));
65 } 53 }
66 54
67 } 55 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.refund; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.refund;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;  
7 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
8 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; 7 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
9 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
@@ -44,27 +43,29 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; { @@ -44,27 +43,29 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; {
44 } 43 }
45 44
46 default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) { 45 default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
47 - return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()  
48 - .eqIfPresent("app_id", reqVO.getAppId())  
49 - .eqIfPresent("channel_code", reqVO.getChannelCode())  
50 - .likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())  
51 - .eqIfPresent("type", reqVO.getType())  
52 - .eqIfPresent("status", reqVO.getStatus())  
53 - .eqIfPresent("notify_status", reqVO.getNotifyStatus())  
54 - .betweenIfPresent("create_time", reqVO.getCreateTime())  
55 - .orderByDesc("id")); 46 + return selectPage(reqVO, new LambdaQueryWrapperX<PayRefundDO>()
  47 + .eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
  48 + .eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
  49 + .likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
  50 + .likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
  51 + .likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
  52 + .likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
  53 + .eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
  54 + .betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
  55 + .orderByDesc(PayRefundDO::getId));
56 } 56 }
57 57
58 default List<PayRefundDO> selectList(PayRefundExportReqVO reqVO) { 58 default List<PayRefundDO> selectList(PayRefundExportReqVO reqVO) {
59 - return selectList(new QueryWrapperX<PayRefundDO>()  
60 - .eqIfPresent("app_id", reqVO.getAppId())  
61 - .eqIfPresent("channel_code", reqVO.getChannelCode())  
62 - .likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())  
63 - .eqIfPresent("type", reqVO.getType())  
64 - .eqIfPresent("status", reqVO.getStatus())  
65 - .eqIfPresent("notify_status", reqVO.getNotifyStatus())  
66 - .betweenIfPresent("create_time", reqVO.getCreateTime())  
67 - .orderByDesc("id")); 59 + return selectList(new LambdaQueryWrapperX<PayRefundDO>()
  60 + .eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
  61 + .eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
  62 + .likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
  63 + .likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
  64 + .likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
  65 + .likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
  66 + .eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
  67 + .betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
  68 + .orderByDesc(PayRefundDO::getId));
68 } 69 }
69 70
70 } 71 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java
@@ -14,4 +14,12 @@ public interface RedisKeyConstants { @@ -14,4 +14,12 @@ public interface RedisKeyConstants {
14 "pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类 14 "pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类
15 RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 15 RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
16 16
  17 + /**
  18 + * 支付序号的缓存
  19 + *
  20 + * KEY 格式:pay_no:{prefix}
  21 + * VALUE 数据格式:编号自增
  22 + */
  23 + String PAY_NO = "pay_no";
  24 +
17 } 25 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/no/PayNoRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.dal.redis.no;
  2 +
  3 +import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil;import org.springframework.data.redis.core.StringRedisTemplate;
  4 +import org.springframework.stereotype.Repository;
  5 +
  6 +import javax.annotation.Resource;import java.time.LocalDateTime;
  7 +
  8 +/**
  9 + * 支付序号的 Redis DAO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Repository
  14 +public class PayNoRedisDAO {
  15 +
  16 + @Resource
  17 + private StringRedisTemplate stringRedisTemplate;
  18 +
  19 + /**
  20 + * 生成序号
  21 + *
  22 + * @param prefix 前缀
  23 + * @return 序号
  24 + */
  25 + public String generate(String prefix) {
  26 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
  27 + Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
  28 + return noPrefix + no;
  29 + }
  30 +
  31 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderNotifyStatusEnum.java deleted
1 -package cn.iocoder.yudao.module.pay.enums.order;  
2 -  
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Getter;  
6 -  
7 -/**  
8 - * 支付订单的通知状态枚举  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Getter  
13 -@AllArgsConstructor  
14 -public enum PayOrderNotifyStatusEnum implements IntArrayValuable {  
15 -  
16 - NO(0, "未通知"),  
17 - SUCCESS(10, "通知成功"),  
18 - FAILURE(20, "通知失败")  
19 - ;  
20 -  
21 - private final Integer status;  
22 - private final String name;  
23 -  
24 - @Override  
25 - public int[] array() {  
26 - return new int[0];  
27 - }  
28 -  
29 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderRefundStatusEnum.java deleted
1 -package cn.iocoder.yudao.module.pay.enums.order;  
2 -  
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Getter;  
6 -  
7 -/**  
8 - * 支付订单的退款状态枚举  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Getter  
13 -@AllArgsConstructor  
14 -public enum PayOrderRefundStatusEnum implements IntArrayValuable {  
15 -  
16 - NO(0, "未退款"),  
17 - PART(10, "部分退款"),  
18 - ALL(20, "全部退款")  
19 - ;  
20 -  
21 - private final Integer status;  
22 - private final String name;  
23 -  
24 - @Override  
25 - public int[] array() {  
26 - return new int[0];  
27 - }  
28 -  
29 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.framework.pay.config;
  2 +
  3 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  4 +import org.springframework.context.annotation.Configuration;
  5 +
  6 +@Configuration(proxyBeanMethods = false)
  7 +@EnableConfigurationProperties(PayProperties.class)
  8 +public class PayConfiguration {
  9 +}
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java
1 -package cn.iocoder.yudao.framework.pay.config; 1 +package cn.iocoder.yudao.module.pay.framework.pay.config;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 import org.hibernate.validator.constraints.URL; 4 import org.hibernate.validator.constraints.URL;
@@ -12,6 +12,9 @@ import javax.validation.constraints.NotEmpty; @@ -12,6 +12,9 @@ import javax.validation.constraints.NotEmpty;
12 @Data 12 @Data
13 public class PayProperties { 13 public class PayProperties {
14 14
  15 + private static final String ORDER_NO_PREFIX = "P";
  16 + private static final String REFUND_NO_PREFIX = "R";
  17 +
15 /** 18 /**
16 * 支付回调地址 19 * 支付回调地址
17 * 20 *
@@ -34,4 +37,16 @@ public class PayProperties { @@ -34,4 +37,16 @@ public class PayProperties {
34 @URL(message = "支付回调地址的格式必须是 URL") 37 @URL(message = "支付回调地址的格式必须是 URL")
35 private String refundNotifyUrl; 38 private String refundNotifyUrl;
36 39
  40 + /**
  41 + * 支付订单 no 的前缀
  42 + */
  43 + @NotEmpty(message = "支付订单 no 的前缀不能为空")
  44 + private String orderNoPrefix = ORDER_NO_PREFIX;
  45 +
  46 + /**
  47 + * 退款订单 no 的前缀
  48 + */
  49 + @NotEmpty(message = "退款订单 no 的前缀不能为空")
  50 + private String refundNoPrefix = REFUND_NO_PREFIX;
  51 +
37 } 52 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/package-info.java 0 → 100644
  1 +/**
  2 + * 占位,无实际作用
  3 + */
  4 +package cn.iocoder.yudao.module.pay.framework.pay.core;
0 \ No newline at end of file 5 \ No newline at end of file
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppService.java
@@ -14,29 +14,29 @@ import java.util.List; @@ -14,29 +14,29 @@ import java.util.List;
14 import java.util.Map; 14 import java.util.Map;
15 15
16 /** 16 /**
17 - * 支付应用信息 Service 接口 17 + * 支付应用 Service 接口
18 * 18 *
19 * @author 芋艿 19 * @author 芋艿
20 */ 20 */
21 public interface PayAppService { 21 public interface PayAppService {
22 22
23 /** 23 /**
24 - * 创建支付应用信息 24 + * 创建支付应用
25 * 25 *
26 - * @param createReqVO 创建信息 26 + * @param createReqVO 创建
27 * @return 编号 27 * @return 编号
28 */ 28 */
29 Long createApp(@Valid PayAppCreateReqVO createReqVO); 29 Long createApp(@Valid PayAppCreateReqVO createReqVO);
30 30
31 /** 31 /**
32 - * 更新支付应用信息 32 + * 更新支付应用
33 * 33 *
34 - * @param updateReqVO 更新信息 34 + * @param updateReqVO 更新
35 */ 35 */
36 void updateApp(@Valid PayAppUpdateReqVO updateReqVO); 36 void updateApp(@Valid PayAppUpdateReqVO updateReqVO);
37 37
38 /** 38 /**
39 - * 修改应用信息状态 39 + * 修改应用状态
40 * 40 *
41 * @param id 应用编号 41 * @param id 应用编号
42 * @param status 状态 42 * @param status 状态
@@ -44,33 +44,40 @@ public interface PayAppService { @@ -44,33 +44,40 @@ public interface PayAppService {
44 void updateAppStatus(Long id, Integer status); 44 void updateAppStatus(Long id, Integer status);
45 45
46 /** 46 /**
47 - * 删除支付应用信息 47 + * 删除支付应用
48 * 48 *
49 * @param id 编号 49 * @param id 编号
50 */ 50 */
51 void deleteApp(Long id); 51 void deleteApp(Long id);
52 52
53 /** 53 /**
54 - * 获得支付应用信息 54 + * 获得支付应用
55 * 55 *
56 * @param id 编号 56 * @param id 编号
57 - * @return 支付应用信息 57 + * @return 支付应用
58 */ 58 */
59 PayAppDO getApp(Long id); 59 PayAppDO getApp(Long id);
60 60
61 /** 61 /**
62 - * 获得支付应用信息列表 62 + * 获得支付应用列表
63 * 63 *
64 * @param ids 编号 64 * @param ids 编号
65 - * @return 支付应用信息列表 65 + * @return 支付应用列表
66 */ 66 */
67 List<PayAppDO> getAppList(Collection<Long> ids); 67 List<PayAppDO> getAppList(Collection<Long> ids);
68 68
69 /** 69 /**
70 - * 获得支付应用信息分页 70 + * 获得支付应用列表
  71 + *
  72 + * @return 支付应用列表
  73 + */
  74 + List<PayAppDO> getAppList();
  75 +
  76 + /**
  77 + * 获得支付应用分页
71 * 78 *
72 * @param pageReqVO 分页查询 79 * @param pageReqVO 分页查询
73 - * @return 支付应用信息分页 80 + * @return 支付应用分页
74 */ 81 */
75 PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO); 82 PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO);
76 83
@@ -91,7 +98,7 @@ public interface PayAppService { @@ -91,7 +98,7 @@ public interface PayAppService {
91 * 如果不合法,抛出 {@link ServiceException} 业务异常 98 * 如果不合法,抛出 {@link ServiceException} 业务异常
92 * 99 *
93 * @param id 应用编号 100 * @param id 应用编号
94 - * @return 应用信息 101 + * @return 应用
95 */ 102 */
96 PayAppDO validPayApp(Long id); 103 PayAppDO validPayApp(Long id);
97 104
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.app; 1 package cn.iocoder.yudao.module.pay.service.app;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;  
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; 5 import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
7 import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; 6 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; @@ -9,10 +8,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
9 import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert; 8 import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert;
10 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; 9 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
11 import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; 10 import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
12 -import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;  
13 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; 11 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
14 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;  
15 -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;  
16 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 12 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
17 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 13 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
18 import org.springframework.context.annotation.Lazy; 14 import org.springframework.context.annotation.Lazy;
@@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService { @@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService {
77 validateAppExists(id); 73 validateAppExists(id);
78 // 校验关联数据是否存在 74 // 校验关联数据是否存在
79 if (orderService.getOrderCountByAppId(id) > 0) { 75 if (orderService.getOrderCountByAppId(id) > 0) {
80 - throw exception(PAY_APP_EXIST_ORDER_CANT_DELETE); 76 + throw exception(APP_EXIST_ORDER_CANT_DELETE);
81 } 77 }
82 if (refundService.getRefundCountByAppId(id) > 0) { 78 if (refundService.getRefundCountByAppId(id) > 0) {
83 - throw exception(PAY_APP_EXIST_REFUND_CANT_DELETE); 79 + throw exception(APP_EXIST_REFUND_CANT_DELETE);
84 } 80 }
85 81
86 // 删除 82 // 删除
@@ -89,7 +85,7 @@ public class PayAppServiceImpl implements PayAppService { @@ -89,7 +85,7 @@ public class PayAppServiceImpl implements PayAppService {
89 85
90 private void validateAppExists(Long id) { 86 private void validateAppExists(Long id) {
91 if (appMapper.selectById(id) == null) { 87 if (appMapper.selectById(id) == null) {
92 - throw exception(PAY_APP_NOT_FOUND); 88 + throw exception(APP_NOT_FOUND);
93 } 89 }
94 } 90 }
95 91
@@ -104,6 +100,11 @@ public class PayAppServiceImpl implements PayAppService { @@ -104,6 +100,11 @@ public class PayAppServiceImpl implements PayAppService {
104 } 100 }
105 101
106 @Override 102 @Override
  103 + public List<PayAppDO> getAppList() {
  104 + return appMapper.selectList();
  105 + }
  106 +
  107 + @Override
107 public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) { 108 public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) {
108 return appMapper.selectPage(pageReqVO); 109 return appMapper.selectPage(pageReqVO);
109 } 110 }
@@ -113,11 +114,11 @@ public class PayAppServiceImpl implements PayAppService { @@ -113,11 +114,11 @@ public class PayAppServiceImpl implements PayAppService {
113 PayAppDO app = appMapper.selectById(id); 114 PayAppDO app = appMapper.selectById(id);
114 // 校验是否存在 115 // 校验是否存在
115 if (app == null) { 116 if (app == null) {
116 - throw exception(ErrorCodeConstants.PAY_APP_NOT_FOUND); 117 + throw exception(ErrorCodeConstants.APP_NOT_FOUND);
117 } 118 }
118 // 校验是否禁用 119 // 校验是否禁用
119 if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) { 120 if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
120 - throw exception(ErrorCodeConstants.PAY_APP_IS_DISABLE); 121 + throw exception(ErrorCodeConstants.APP_IS_DISABLE);
121 } 122 }
122 return app; 123 return app;
123 } 124 }
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; @@ -32,8 +32,7 @@ import java.util.List;
32 import java.util.concurrent.TimeUnit; 32 import java.util.concurrent.TimeUnit;
33 33
34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;  
36 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS; 35 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
37 36
38 /** 37 /**
39 * 支付渠道 Service 实现类 38 * 支付渠道 Service 实现类
@@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService {
142 // 解析配置 141 // 解析配置
143 Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass(); 142 Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass();
144 if (ObjectUtil.isNull(payClass)) { 143 if (ObjectUtil.isNull(payClass)) {
145 - throw exception(CHANNEL_NOT_EXISTS); 144 + throw exception(CHANNEL_NOT_FOUND);
146 } 145 }
147 PayClientConfig config = JsonUtils.parseObject2(configStr, payClass); 146 PayClientConfig config = JsonUtils.parseObject2(configStr, payClass);
148 Assert.notNull(config); 147 Assert.notNull(config);
@@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService {
167 private PayChannelDO validateChannelExists(Long id) { 166 private PayChannelDO validateChannelExists(Long id) {
168 PayChannelDO channel = channelMapper.selectById(id); 167 PayChannelDO channel = channelMapper.selectById(id);
169 if (channel == null) { 168 if (channel == null) {
170 - throw exception(CHANNEL_NOT_EXISTS); 169 + throw exception(CHANNEL_NOT_FOUND);
171 } 170 }
172 return channel; 171 return channel;
173 } 172 }
@@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService {
203 202
204 private void validPayChannel(PayChannelDO channel) { 203 private void validPayChannel(PayChannelDO channel) {
205 if (channel == null) { 204 if (channel == null) {
206 - throw exception(ErrorCodeConstants.PAY_CHANNEL_NOT_FOUND); 205 + throw exception(CHANNEL_NOT_FOUND);
207 } 206 }
208 if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) { 207 if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
209 - throw exception(ErrorCodeConstants.PAY_CHANNEL_IS_DISABLE); 208 + throw exception(CHANNEL_IS_DISABLE);
210 } 209 }
211 } 210 }
212 211
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 { @@ -119,7 +119,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
119 new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now()) 119 new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
120 .setPayChannelCode(payOrder.getChannelCode())); 120 .setPayChannelCode(payOrder.getChannelCode()));
121 if (updateCount == 0) { 121 if (updateCount == 0) {
122 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); 122 + throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
123 } 123 }
124 } 124 }
125 125
@@ -137,44 +137,44 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { @@ -137,44 +137,44 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
137 // 1.1 校验订单是否存在 137 // 1.1 校验订单是否存在
138 PayDemoOrderDO order = payDemoOrderMapper.selectById(id); 138 PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
139 if (order == null) { 139 if (order == null) {
140 - throw exception(PAY_DEMO_ORDER_NOT_FOUND); 140 + throw exception(DEMO_ORDER_NOT_FOUND);
141 } 141 }
142 // 1.2 校验订单未支付 142 // 1.2 校验订单未支付
143 if (order.getPayStatus()) { 143 if (order.getPayStatus()) {
144 log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]", 144 log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
145 id, toJsonString(order)); 145 id, toJsonString(order));
146 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); 146 + throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
147 } 147 }
148 // 1.3 校验支付订单匹配 148 // 1.3 校验支付订单匹配
149 if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 149 if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
150 log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]", 150 log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
151 id, payOrderId, toJsonString(order)); 151 id, payOrderId, toJsonString(order));
152 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); 152 + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
153 } 153 }
154 154
155 // 2.1 校验支付单是否存在 155 // 2.1 校验支付单是否存在
156 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); 156 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
157 if (payOrder == null) { 157 if (payOrder == null) {
158 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); 158 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
159 - throw exception(PAY_ORDER_NOT_FOUND); 159 + throw exception(ORDER_NOT_FOUND);
160 } 160 }
161 // 2.2 校验支付单已支付 161 // 2.2 校验支付单已支付
162 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { 162 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
163 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", 163 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
164 id, payOrderId, toJsonString(payOrder)); 164 id, payOrderId, toJsonString(payOrder));
165 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS); 165 + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
166 } 166 }
167 // 2.3 校验支付金额一致 167 // 2.3 校验支付金额一致
168 if (notEqual(payOrder.getPrice(), order.getPrice())) { 168 if (notEqual(payOrder.getPrice(), order.getPrice())) {
169 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]", 169 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
170 id, payOrderId, toJsonString(order), toJsonString(payOrder)); 170 id, payOrderId, toJsonString(order), toJsonString(payOrder));
171 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH); 171 + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
172 } 172 }
173 // 2.4 校验支付订单匹配(二次) 173 // 2.4 校验支付订单匹配(二次)
174 if (notEqual(payOrder.getMerchantOrderId(), id.toString())) { 174 if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
175 log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", 175 log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
176 id, payOrderId, toJsonString(payOrder)); 176 id, payOrderId, toJsonString(payOrder));
177 - throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); 177 + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
178 } 178 }
179 return payOrder; 179 return payOrder;
180 } 180 }
@@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { @@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
203 // 校验订单是否存在 203 // 校验订单是否存在
204 PayDemoOrderDO order = payDemoOrderMapper.selectById(id); 204 PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
205 if (order == null) { 205 if (order == null) {
206 - throw exception(PAY_DEMO_ORDER_NOT_FOUND); 206 + throw exception(DEMO_ORDER_NOT_FOUND);
207 } 207 }
208 // 校验订单是否支付 208 // 校验订单是否支付
209 if (!order.getPayStatus()) { 209 if (!order.getPayStatus()) {
210 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID); 210 + throw exception(DEMO_ORDER_REFUND_FAIL_NOT_PAID);
211 } 211 }
212 // 校验订单是否已退款 212 // 校验订单是否已退款
213 if (order.getPayRefundId() != null) { 213 if (order.getPayRefundId() != null) {
214 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED); 214 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUNDED);
215 } 215 }
216 return order; 216 return order;
217 } 217 }
@@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { @@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
229 // 1.1 校验示例订单 229 // 1.1 校验示例订单
230 PayDemoOrderDO order = payDemoOrderMapper.selectById(id); 230 PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
231 if (order == null) { 231 if (order == null) {
232 - throw exception(PAY_DEMO_ORDER_NOT_FOUND); 232 + throw exception(DEMO_ORDER_NOT_FOUND);
233 } 233 }
234 // 1.2 校验退款订单匹配 234 // 1.2 校验退款订单匹配
235 if (Objects.equals(order.getPayOrderId(), payRefundId)) { 235 if (Objects.equals(order.getPayOrderId(), payRefundId)) {
236 log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]", 236 log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
237 id, payRefundId, toJsonString(order)); 237 id, payRefundId, toJsonString(order));
238 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); 238 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
239 } 239 }
240 240
241 // 2.1 校验退款订单 241 // 2.1 校验退款订单
242 PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId); 242 PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
243 if (payRefund == null) { 243 if (payRefund == null) {
244 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND); 244 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
245 } 245 }
246 // 2.2 246 // 2.2
247 if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) { 247 if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
248 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS); 248 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
249 } 249 }
250 // 2.3 校验退款金额一致 250 // 2.3 校验退款金额一致
251 if (notEqual(payRefund.getRefundPrice(), order.getPrice())) { 251 if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
252 log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]", 252 log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
253 id, payRefundId, toJsonString(order), toJsonString(payRefund)); 253 id, payRefundId, toJsonString(order), toJsonString(payRefund));
254 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH); 254 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
255 } 255 }
256 // 2.4 校验退款订单匹配(二次) 256 // 2.4 校验退款订单匹配(二次)
257 if (notEqual(payRefund.getMerchantOrderId(), id.toString())) { 257 if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
258 log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]", 258 log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
259 id, payRefundId, toJsonString(payRefund)); 259 id, payRefundId, toJsonString(payRefund));
260 - throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); 260 + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
261 } 261 }
262 return payRefund; 262 return payRefund;
263 } 263 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyService.java
1 package cn.iocoder.yudao.module.pay.service.notify; 1 package cn.iocoder.yudao.module.pay.service.notify;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
  5 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
  6 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
3 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; 7 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
4 8
5 import javax.validation.Valid; 9 import javax.validation.Valid;
  10 +import java.util.List;
6 11
7 /** 12 /**
8 - * 支付通知 Service 接口 13 + * 回调通知 Service 接口
9 * 14 *
10 * @author 芋道源码 15 * @author 芋道源码
11 */ 16 */
12 public interface PayNotifyService { 17 public interface PayNotifyService {
13 18
14 /** 19 /**
15 - * 创建支付通知任务 20 + * 创建回调通知任务
16 * 21 *
17 * @param reqDTO 任务信息 22 * @param reqDTO 任务信息
18 */ 23 */
19 void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO); 24 void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO);
20 25
21 /** 26 /**
22 - * 执行支付通知 27 + * 执行回调通知
23 * 28 *
24 * 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用 29 * 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用
25 * @return 通知数量 30 * @return 通知数量
26 */ 31 */
27 int executeNotify() throws InterruptedException; 32 int executeNotify() throws InterruptedException;
28 33
  34 + /**
  35 + * 获得回调通知
  36 + *
  37 + * @param id 编号
  38 + * @return 回调通知
  39 + */
  40 + PayNotifyTaskDO getNotifyTask(Long id);
  41 +
  42 + /**
  43 + * 获得回调通知分页
  44 + *
  45 + * @param pageReqVO 分页查询
  46 + * @return 回调通知分页
  47 + */
  48 + PageResult<PayNotifyTaskDO> getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO);
  49 +
  50 + /**
  51 + * 获得回调日志列表
  52 + *
  53 + * @param taskId 任务编号
  54 + * @return 日志列表
  55 + */
  56 + List<PayNotifyLogDO> getNotifyLogList(Long taskId);
  57 +
29 } 58 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
@@ -6,11 +6,13 @@ import cn.hutool.core.util.ObjectUtil; @@ -6,11 +6,13 @@ import cn.hutool.core.util.ObjectUtil;
6 import cn.hutool.http.HttpResponse; 6 import cn.hutool.http.HttpResponse;
7 import cn.hutool.http.HttpUtil; 7 import cn.hutool.http.HttpUtil;
8 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  9 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 10 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
10 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 11 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
11 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 12 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
12 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; 13 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
13 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; 14 import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
  15 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
14 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; 16 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
15 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; 17 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
16 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 18 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
@@ -72,15 +74,15 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -72,15 +74,15 @@ public class PayNotifyServiceImpl implements PayNotifyService {
72 private PayRefundService refundService; 74 private PayRefundService refundService;
73 75
74 @Resource 76 @Resource
75 - private PayNotifyTaskMapper payNotifyTaskMapper; 77 + private PayNotifyTaskMapper notifyTaskMapper;
76 @Resource 78 @Resource
77 - private PayNotifyLogMapper payNotifyLogMapper; 79 + private PayNotifyLogMapper notifyLogMapper;
78 80
79 @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR) 81 @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR)
80 private ThreadPoolTaskExecutor threadPoolTaskExecutor; 82 private ThreadPoolTaskExecutor threadPoolTaskExecutor;
81 83
82 @Resource 84 @Resource
83 - private PayNotifyLockRedisDAO payNotifyLockCoreRedisDAO; 85 + private PayNotifyLockRedisDAO notifyLockCoreRedisDAO;
84 86
85 @Resource 87 @Resource
86 @Lazy // 循环依赖(自己依赖自己),避免报错 88 @Lazy // 循环依赖(自己依赖自己),避免报错
@@ -105,7 +107,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -105,7 +107,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
105 } 107 }
106 108
107 // 执行插入 109 // 执行插入
108 - payNotifyTaskMapper.insert(task); 110 + notifyTaskMapper.insert(task);
109 111
110 // 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务 112 // 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务
111 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { 113 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@@ -119,7 +121,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -119,7 +121,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
119 @Override 121 @Override
120 public int executeNotify() throws InterruptedException { 122 public int executeNotify() throws InterruptedException {
121 // 获得需要通知的任务 123 // 获得需要通知的任务
122 - List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify(); 124 + List<PayNotifyTaskDO> tasks = notifyTaskMapper.selectListByNotify();
123 if (CollUtil.isEmpty(tasks)) { 125 if (CollUtil.isEmpty(tasks)) {
124 return 0; 126 return 0;
125 } 127 }
@@ -164,11 +166,11 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -164,11 +166,11 @@ public class PayNotifyServiceImpl implements PayNotifyService {
164 */ 166 */
165 public void executeNotify(PayNotifyTaskDO task) { 167 public void executeNotify(PayNotifyTaskDO task) {
166 // 分布式锁,避免并发问题 168 // 分布式锁,避免并发问题
167 - payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { 169 + notifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
168 // 校验,当前任务是否已经被通知过 170 // 校验,当前任务是否已经被通知过
169 // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。 171 // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。
170 // 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断 172 // 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断
171 - PayNotifyTaskDO dbTask = payNotifyTaskMapper.selectById(task.getId()); 173 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
172 if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) { 174 if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) {
173 log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]", 175 log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]",
174 JsonUtils.toJsonString(task), dbTask.getNotifyTimes()); 176 JsonUtils.toJsonString(task), dbTask.getNotifyTimes());
@@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
197 // 记录 PayNotifyLog 日志 199 // 记录 PayNotifyLog 日志
198 String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : 200 String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
199 JsonUtils.toJsonString(invokeResult); 201 JsonUtils.toJsonString(invokeResult);
200 - payNotifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) 202 + notifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
201 .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); 203 .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
202 } 204 }
203 205
@@ -250,22 +252,37 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -250,22 +252,37 @@ public class PayNotifyServiceImpl implements PayNotifyService {
250 // 情况一:调用成功 252 // 情况一:调用成功
251 if (invokeResult != null && invokeResult.isSuccess()) { 253 if (invokeResult != null && invokeResult.isSuccess()) {
252 updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); 254 updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
253 - payNotifyTaskMapper.updateById(updateTask); 255 + notifyTaskMapper.updateById(updateTask);
254 return updateTask.getStatus(); 256 return updateTask.getStatus();
255 } 257 }
256 // 情况二:调用失败、调用异常 258 // 情况二:调用失败、调用异常
257 // 2.1 超过最大回调次数 259 // 2.1 超过最大回调次数
258 if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { 260 if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
259 updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); 261 updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
260 - payNotifyTaskMapper.updateById(updateTask); 262 + notifyTaskMapper.updateById(updateTask);
261 return updateTask.getStatus(); 263 return updateTask.getStatus();
262 } 264 }
263 // 2.2 未超过最大回调次数 265 // 2.2 未超过最大回调次数
264 updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()]))); 266 updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])));
265 updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() 267 updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
266 : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); 268 : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
267 - payNotifyTaskMapper.updateById(updateTask); 269 + notifyTaskMapper.updateById(updateTask);
268 return updateTask.getStatus(); 270 return updateTask.getStatus();
269 } 271 }
270 272
  273 + @Override
  274 + public PayNotifyTaskDO getNotifyTask(Long id) {
  275 + return notifyTaskMapper.selectById(id);
  276 + }
  277 +
  278 + @Override
  279 + public PageResult<PayNotifyTaskDO> getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO) {
  280 + return notifyTaskMapper.selectPage(pageReqVO);
  281 + }
  282 +
  283 + @Override
  284 + public List<PayNotifyLogDO> getNotifyLogList(Long taskId) {
  285 + return notifyLogMapper.selectListByTaskId(taskId);
  286 + }
  287 +
271 } 288 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderExtensionService.java deleted
1 -package cn.iocoder.yudao.module.pay.service.order;  
2 -  
3 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
4 -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;  
5 -  
6 -import java.util.Collection;  
7 -import java.util.List;  
8 -import java.util.Map;  
9 -  
10 -// TODO 芋艿:合并到 PayOrder 里;  
11 -/**  
12 - * 支付订单 Service 接口  
13 - *  
14 - * @author aquan  
15 - */  
16 -public interface PayOrderExtensionService {  
17 -  
18 - /**  
19 - * 获得支付订单  
20 - *  
21 - * @param id 编号  
22 - * @return 支付订单  
23 - */  
24 - PayOrderExtensionDO getOrderExtension(Long id);  
25 -  
26 - /**  
27 - * 获得支付订单  
28 - * 列表  
29 - *  
30 - * @param ids 编号  
31 - * @return 支付订单  
32 - * 列表  
33 - */  
34 - List<PayOrderExtensionDO> getOrderExtensionList(Collection<Long> ids);  
35 -  
36 - /**  
37 - * 根据订单成功的 扩展订单ID 查询所有的扩展订单转 成 map 返回  
38 - *  
39 - * @param successExtensionIdList 订单 ID 集合  
40 - * @return 订单扩展 map 集合  
41 - */  
42 - default Map<Long, PayOrderExtensionDO> getOrderExtensionMap(Collection<Long> successExtensionIdList) {  
43 - List<PayOrderExtensionDO> list = getOrderExtensionList(successExtensionIdList);  
44 - return CollectionUtils.convertMap(list, PayOrderExtensionDO::getId);  
45 - }  
46 -  
47 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderExtensionServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.pay.service.order;  
2 -  
3 -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;  
4 -import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;  
5 -import org.springframework.stereotype.Service;  
6 -import org.springframework.validation.annotation.Validated;  
7 -  
8 -import javax.annotation.Resource;  
9 -import java.util.Collection;  
10 -import java.util.List;  
11 -  
12 -/**  
13 - * 支付订单 Service 实现类  
14 - *  
15 - * @author aquan  
16 - */  
17 -@Service  
18 -@Validated  
19 -public class PayOrderExtensionServiceImpl implements PayOrderExtensionService {  
20 -  
21 - @Resource  
22 - private PayOrderExtensionMapper orderExtensionMapper;  
23 -  
24 - @Override  
25 - public PayOrderExtensionDO getOrderExtension(Long id) {  
26 - return orderExtensionMapper.selectById(id);  
27 - }  
28 -  
29 - @Override  
30 - public List<PayOrderExtensionDO> getOrderExtensionList(Collection<Long> ids) {  
31 - return orderExtensionMapper.selectBatchIds(ids);  
32 - }  
33 -  
34 -}  
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
1 package cn.iocoder.yudao.module.pay.service.order; 1 package cn.iocoder.yudao.module.pay.service.order;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
6 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 5 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
7 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
@@ -9,12 +8,11 @@ import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; @@ -9,12 +8,11 @@ import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
9 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; 8 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
10 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; 9 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
11 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
  11 +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
12 12
13 import javax.validation.Valid; 13 import javax.validation.Valid;
14 import javax.validation.constraints.NotEmpty; 14 import javax.validation.constraints.NotEmpty;
15 -import java.util.Collection;  
16 import java.util.List; 15 import java.util.List;
17 -import java.util.Map;  
18 16
19 /** 17 /**
20 * 支付订单 Service 接口 18 * 支付订单 Service 接口
@@ -49,45 +47,22 @@ public interface PayOrderService { @@ -49,45 +47,22 @@ public interface PayOrderService {
49 Long getOrderCountByAppId(Long appId); 47 Long getOrderCountByAppId(Long appId);
50 48
51 /** 49 /**
52 - * 获得支付订单  
53 - * 分页 50 + * 获得支付订单分页
54 * 51 *
55 * @param pageReqVO 分页查询 52 * @param pageReqVO 分页查询
56 - * @return 支付订单  
57 - * 分页 53 + * @return 支付订单分页
58 */ 54 */
59 PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO); 55 PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO);
60 56
61 /** 57 /**
62 - * 获得支付订单  
63 - * 列表, 用于 Excel 导出 58 + * 获得支付订单列表, 用于 Excel 导出
64 * 59 *
65 * @param exportReqVO 查询条件 60 * @param exportReqVO 查询条件
66 - * @return 支付订单  
67 - * 列表 61 + * @return 支付订单列表
68 */ 62 */
69 List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO); 63 List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
70 64
71 /** 65 /**
72 - * 根据 ID 集合获取只包含商品名称的订单集合  
73 - *  
74 - * @param idList 订单 ID 集合  
75 - * @return 只包含商品名称的订单集合  
76 - */  
77 - List<PayOrderDO> getOrderSubjectList(Collection<Long> idList);  
78 -  
79 - /**  
80 - * 根据订单 ID 集合获取订单商品名称Map集合  
81 - *  
82 - * @param ids 订单 ID 集合  
83 - * @return 订单商品 map 集合  
84 - */  
85 - default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {  
86 - List<PayOrderDO> list = getOrderSubjectList(ids);  
87 - return CollectionUtils.convertMap(list, PayOrderDO::getId);  
88 - }  
89 -  
90 - /**  
91 * 创建支付单 66 * 创建支付单
92 * 67 *
93 * @param reqDTO 创建请求 68 * @param reqDTO 创建请求
@@ -122,4 +97,12 @@ public interface PayOrderService { @@ -122,4 +97,12 @@ public interface PayOrderService {
122 */ 97 */
123 void updateOrderRefundPrice(Long id, Integer incrRefundPrice); 98 void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
124 99
  100 + /**
  101 + * 获得支付订单
  102 + *
  103 + * @param id 编号
  104 + * @return 支付订单
  105 + */
  106 + PayOrderExtensionDO getOrderExtension(Long id);
  107 +
125 } 108 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.order; 1 package cn.iocoder.yudao.module.pay.service.order;
2 2
3 -import cn.hutool.core.date.DateUtil;  
4 import cn.hutool.core.lang.Pair; 3 import cn.hutool.core.lang.Pair;
5 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
6 -import cn.hutool.core.util.RandomUtil;  
7 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.hutool.extra.spring.SpringUtil;
8 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 8 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
10 -import cn.iocoder.yudao.framework.pay.config.PayProperties;  
11 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 9 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
12 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 10 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
13 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@@ -26,22 +24,21 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; @@ -26,22 +24,21 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
26 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; 24 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
27 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper; 25 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
28 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; 26 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
  27 +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
29 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 28 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
30 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;  
31 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;  
32 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 29 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
  30 +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
33 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 31 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
34 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 32 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
35 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 33 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
36 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; 34 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
  35 +import cn.iocoder.yudao.module.pay.util.MoneyUtils;
37 import lombok.extern.slf4j.Slf4j; 36 import lombok.extern.slf4j.Slf4j;
38 import org.springframework.stereotype.Service; 37 import org.springframework.stereotype.Service;
39 import org.springframework.transaction.annotation.Transactional; 38 import org.springframework.transaction.annotation.Transactional;
40 import org.springframework.validation.annotation.Validated; 39 import org.springframework.validation.annotation.Validated;
41 40
42 import javax.annotation.Resource; 41 import javax.annotation.Resource;
43 -import java.time.LocalDateTime;  
44 -import java.util.Collection;  
45 import java.util.List; 42 import java.util.List;
46 import java.util.Objects; 43 import java.util.Objects;
47 44
@@ -69,6 +66,8 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -69,6 +66,8 @@ public class PayOrderServiceImpl implements PayOrderService {
69 private PayOrderMapper orderMapper; 66 private PayOrderMapper orderMapper;
70 @Resource 67 @Resource
71 private PayOrderExtensionMapper orderExtensionMapper; 68 private PayOrderExtensionMapper orderExtensionMapper;
  69 + @Resource
  70 + private PayNoRedisDAO noRedisDAO;
72 71
73 @Resource 72 @Resource
74 private PayAppService appService; 73 private PayAppService appService;
@@ -102,12 +101,6 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -102,12 +101,6 @@ public class PayOrderServiceImpl implements PayOrderService {
102 return orderMapper.selectList(exportReqVO); 101 return orderMapper.selectList(exportReqVO);
103 } 102 }
104 103
105 - // TODO @艿艿:需要优化。不确定这个方法的作用  
106 - @Override  
107 - public List<PayOrderDO> getOrderSubjectList(Collection<Long> idList) {  
108 - return orderMapper.findByIdListQueryOrderSubject(idList);  
109 - }  
110 -  
111 @Override 104 @Override
112 public Long createOrder(PayOrderCreateReqDTO reqDTO) { 105 public Long createOrder(PayOrderCreateReqDTO reqDTO) {
113 // 校验 App 106 // 校验 App
@@ -125,11 +118,11 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -125,11 +118,11 @@ public class PayOrderServiceImpl implements PayOrderService {
125 // 创建支付交易单 118 // 创建支付交易单
126 order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId()) 119 order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId())
127 // 商户相关字段 120 // 商户相关字段
128 - .setNotifyUrl(app.getOrderNotifyUrl()).setNotifyStatus(PayOrderNotifyStatusEnum.NO.getStatus()) 121 + .setNotifyUrl(app.getOrderNotifyUrl())
129 // 订单相关字段 122 // 订单相关字段
130 .setStatus(PayOrderStatusEnum.WAITING.getStatus()) 123 .setStatus(PayOrderStatusEnum.WAITING.getStatus())
131 // 退款相关字段 124 // 退款相关字段
132 - .setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0); 125 + .setRefundPrice(0);
133 orderMapper.insert(order); 126 orderMapper.insert(order);
134 return order.getId(); 127 return order.getId();
135 } 128 }
@@ -143,8 +136,9 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -143,8 +136,9 @@ public class PayOrderServiceImpl implements PayOrderService {
143 PayClient client = payClientFactory.getPayClient(channel.getId()); 136 PayClient client = payClientFactory.getPayClient(channel.getId());
144 137
145 // 2. 插入 PayOrderExtensionDO 138 // 2. 插入 PayOrderExtensionDO
  139 + String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
146 PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp) 140 PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
147 - .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) 141 + .setOrderId(order.getId()).setNo(no)
148 .setChannelId(channel.getId()).setChannelCode(channel.getCode()) 142 .setChannelId(channel.getId()).setChannelCode(channel.getCode())
149 .setStatus(PayOrderStatusEnum.WAITING.getStatus()); 143 .setStatus(PayOrderStatusEnum.WAITING.getStatus());
150 orderExtensionMapper.insert(orderExtension); 144 orderExtensionMapper.insert(orderExtension);
@@ -162,10 +156,10 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -162,10 +156,10 @@ public class PayOrderServiceImpl implements PayOrderService {
162 156
163 // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功 157 // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
164 if (unifiedOrderResp != null) { 158 if (unifiedOrderResp != null) {
165 - notifyPayOrder(channel, unifiedOrderResp); 159 + getSelf().notifyOrder(channel, unifiedOrderResp);
166 // 如有渠道错误码,则抛出业务异常,提示用户 160 // 如有渠道错误码,则抛出业务异常,提示用户
167 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) { 161 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
168 - throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(), 162 + throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
169 unifiedOrderResp.getChannelErrorMsg()); 163 unifiedOrderResp.getChannelErrorMsg());
170 } 164 }
171 // 此处需要读取最新的状态 165 // 此处需要读取最新的状态
@@ -177,13 +171,13 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -177,13 +171,13 @@ public class PayOrderServiceImpl implements PayOrderService {
177 private PayOrderDO validateOrderCanSubmit(Long id) { 171 private PayOrderDO validateOrderCanSubmit(Long id) {
178 PayOrderDO order = orderMapper.selectById(id); 172 PayOrderDO order = orderMapper.selectById(id);
179 if (order == null) { // 是否存在 173 if (order == null) { // 是否存在
180 - throw exception(PAY_ORDER_NOT_FOUND); 174 + throw exception(ORDER_NOT_FOUND);
181 } 175 }
182 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 176 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
183 - throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); 177 + throw exception(ORDER_STATUS_IS_NOT_WAITING);
184 } 178 }
185 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期 179 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
186 - throw exception(PAY_ORDER_IS_EXPIRED); 180 + throw exception(ORDER_IS_EXPIRED);
187 } 181 }
188 return order; 182 return order;
189 } 183 }
@@ -196,7 +190,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -196,7 +190,7 @@ public class PayOrderServiceImpl implements PayOrderService {
196 PayClient client = payClientFactory.getPayClient(channel.getId()); 190 PayClient client = payClientFactory.getPayClient(channel.getId());
197 if (client == null) { 191 if (client == null) {
198 log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); 192 log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
199 - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); 193 + throw exception(CHANNEL_NOT_FOUND);
200 } 194 }
201 return channel; 195 return channel;
202 } 196 }
@@ -211,61 +205,22 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -211,61 +205,22 @@ public class PayOrderServiceImpl implements PayOrderService {
211 return payProperties.getOrderNotifyUrl() + "/" + channel.getId(); 205 return payProperties.getOrderNotifyUrl() + "/" + channel.getId();
212 } 206 }
213 207
214 - private String generateOrderExtensionNo() {  
215 -// wx  
216 -// 2014  
217 -// 10  
218 -// 27  
219 -// 20  
220 -// 09  
221 -// 39  
222 -// 5522657  
223 -// a690389285100  
224 - // 目前的算法  
225 - // 时间序列,年月日时分秒 14 位  
226 - // 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整  
227 - return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + // 时间序列  
228 - RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒  
229 - ;  
230 - }  
231 -  
232 @Override 208 @Override
233 - @Transactional(rollbackFor = Exception.class)  
234 public void notifyOrder(Long channelId, PayOrderRespDTO notify) { 209 public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
235 // 校验支付渠道是否有效 210 // 校验支付渠道是否有效
236 PayChannelDO channel = channelService.validPayChannel(channelId); 211 PayChannelDO channel = channelService.validPayChannel(channelId);
237 // 更新支付订单为已支付 212 // 更新支付订单为已支付
238 - TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify)); 213 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyOrder(channel, notify));
239 } 214 }
240 215
241 - @Override  
242 - public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {  
243 - PayOrderDO order = orderMapper.selectById(id);  
244 - if (order == null) {  
245 - throw exception(PAY_ORDER_NOT_FOUND);  
246 - }  
247 - if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {  
248 - throw exception(PAY_REFUND_PRICE_EXCEED);  
249 - }  
250 - if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {  
251 - throw exception(PAY_REFUND_PRICE_EXCEED);  
252 - }  
253 -  
254 - // 更新订单  
255 - PayOrderDO updateObj = new PayOrderDO()  
256 - .setRefundPrice(order.getRefundPrice() + incrRefundPrice)  
257 - .setRefundTimes(order.getRefundTimes() + 1);  
258 - if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {  
259 - updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())  
260 - .setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());  
261 - } else {  
262 - updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())  
263 - .setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());  
264 - }  
265 - orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);  
266 - }  
267 -  
268 - private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) { 216 + /**
  217 + * 通知并更新订单的支付结果
  218 + *
  219 + * @param channel 支付渠道
  220 + * @param notify 通知
  221 + */
  222 + @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
  223 + public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
269 // 情况一:支付成功的回调 224 // 情况一:支付成功的回调
270 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { 225 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
271 notifyOrderSuccess(channel, notify); 226 notifyOrderSuccess(channel, notify);
@@ -275,20 +230,22 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -275,20 +230,22 @@ public class PayOrderServiceImpl implements PayOrderService {
275 if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) { 230 if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
276 notifyOrderClosed(channel, notify); 231 notifyOrderClosed(channel, notify);
277 } 232 }
  233 + // 情况三:WAITING:无需处理
  234 + // 情况四:REFUND:通过退款回调处理
278 } 235 }
279 236
280 private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) { 237 private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
281 // 1. 更新 PayOrderExtensionDO 支付成功 238 // 1. 更新 PayOrderExtensionDO 支付成功
282 - PayOrderExtensionDO orderExtension = updateOrderExtensionSuccess(notify); 239 + PayOrderExtensionDO orderExtension = updateOrderSuccess(notify);
283 // 2. 更新 PayOrderDO 支付成功 240 // 2. 更新 PayOrderDO 支付成功
284 - Pair<Boolean, PayOrderDO> order = updateOrderExtensionSuccess(channel, orderExtension, notify);  
285 - if (order.getKey()) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调 241 + Boolean paid = updateOrderSuccess(channel, orderExtension, notify);
  242 + if (paid) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调
286 return; 243 return;
287 } 244 }
288 245
289 // 3. 插入支付通知记录 246 // 3. 插入支付通知记录
290 notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() 247 notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
291 - .type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getValue().getId()).build()); 248 + .type(PayNotifyTypeEnum.ORDER.getType()).dataId(orderExtension.getOrderId()).build());
292 } 249 }
293 250
294 /** 251 /**
@@ -297,25 +254,25 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -297,25 +254,25 @@ public class PayOrderServiceImpl implements PayOrderService {
297 * @param notify 通知 254 * @param notify 通知
298 * @return PayOrderExtensionDO 对象 255 * @return PayOrderExtensionDO 对象
299 */ 256 */
300 - private PayOrderExtensionDO updateOrderExtensionSuccess(PayOrderRespDTO notify) { 257 + private PayOrderExtensionDO updateOrderSuccess(PayOrderRespDTO notify) {
301 // 1. 查询 PayOrderExtensionDO 258 // 1. 查询 PayOrderExtensionDO
302 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); 259 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
303 if (orderExtension == null) { 260 if (orderExtension == null) {
304 - throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); 261 + throw exception(ORDER_EXTENSION_NOT_FOUND);
305 } 262 }
306 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 263 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
307 log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId()); 264 log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
308 return orderExtension; 265 return orderExtension;
309 } 266 }
310 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 267 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
311 - throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 268 + throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
312 } 269 }
313 270
314 // 2. 更新 PayOrderExtensionDO 271 // 2. 更新 PayOrderExtensionDO
315 int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), 272 int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
316 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); 273 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
317 if (updateCounts == 0) { // 校验状态,必须是待支付 274 if (updateCounts == 0) { // 校验状态,必须是待支付
318 - throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 275 + throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
319 } 276 }
320 log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId()); 277 log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
321 return orderExtension; 278 return orderExtension;
@@ -327,37 +284,37 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -327,37 +284,37 @@ public class PayOrderServiceImpl implements PayOrderService {
327 * @param channel 支付渠道 284 * @param channel 支付渠道
328 * @param orderExtension 支付拓展单 285 * @param orderExtension 支付拓展单
329 * @param notify 通知回调 286 * @param notify 通知回调
330 - * @return key:是否之前已经成功回调  
331 - * value:PayOrderDO 对象 287 + * @return 是否之前已经成功回调
332 */ 288 */
333 - private Pair<Boolean, PayOrderDO> updateOrderExtensionSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,  
334 - PayOrderRespDTO notify) { 289 + private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
  290 + PayOrderRespDTO notify) {
335 // 1. 判断 PayOrderDO 是否处于待支付 291 // 1. 判断 PayOrderDO 是否处于待支付
336 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); 292 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
337 if (order == null) { 293 if (order == null) {
338 - throw exception(PAY_ORDER_NOT_FOUND); 294 + throw exception(ORDER_NOT_FOUND);
339 } 295 }
340 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新 296 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
341 - && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) { 297 + && Objects.equals(order.getExtensionId(), orderExtension.getId())) {
342 log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId()); 298 log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId());
343 - return Pair.of(true, order); 299 + return true;
344 } 300 }
345 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 301 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
346 - throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); 302 + throw exception(ORDER_STATUS_IS_NOT_WAITING);
347 } 303 }
348 304
349 // 2. 更新 PayOrderDO 305 // 2. 更新 PayOrderDO
350 int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(), 306 int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
351 PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()) 307 PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
352 .channelId(channel.getId()).channelCode(channel.getCode()) 308 .channelId(channel.getId()).channelCode(channel.getCode())
353 - .successTime(notify.getSuccessTime()).successExtensionId(orderExtension.getId()) 309 + .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
354 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId()) 310 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
355 - .notifyTime(LocalDateTime.now()).build()); 311 + .channelFeeRate(channel.getFeeRate()).channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
  312 + .build());
356 if (updateCounts == 0) { // 校验状态,必须是待支付 313 if (updateCounts == 0) { // 校验状态,必须是待支付
357 - throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); 314 + throw exception(ORDER_STATUS_IS_NOT_WAITING);
358 } 315 }
359 log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId()); 316 log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
360 - return Pair.of(false, order); 317 + return false;
361 } 318 }
362 319
363 private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) { 320 private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) {
@@ -368,7 +325,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -368,7 +325,7 @@ public class PayOrderServiceImpl implements PayOrderService {
368 // 1. 查询 PayOrderExtensionDO 325 // 1. 查询 PayOrderExtensionDO
369 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); 326 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
370 if (orderExtension == null) { 327 if (orderExtension == null) {
371 - throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); 328 + throw exception(ORDER_EXTENSION_NOT_FOUND);
372 } 329 }
373 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新 330 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
374 log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId()); 331 log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
@@ -380,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -380,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
380 return; 337 return;
381 } 338 }
382 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 339 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
383 - throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 340 + throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
384 } 341 }
385 342
386 // 2. 更新 PayOrderExtensionDO 343 // 2. 更新 PayOrderExtensionDO
@@ -388,9 +345,46 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -388,9 +345,46 @@ public class PayOrderServiceImpl implements PayOrderService {
388 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) 345 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
389 .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); 346 .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
390 if (updateCounts == 0) { // 校验状态,必须是待支付 347 if (updateCounts == 0) { // 校验状态,必须是待支付
391 - throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); 348 + throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
392 } 349 }
393 log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId()); 350 log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
394 } 351 }
395 352
  353 + @Override
  354 + public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
  355 + PayOrderDO order = orderMapper.selectById(id);
  356 + if (order == null) {
  357 + throw exception(ORDER_NOT_FOUND);
  358 + }
  359 + if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
  360 + throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
  361 + }
  362 + if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
  363 + throw exception(REFUND_PRICE_EXCEED);
  364 + }
  365 +
  366 + // 更新订单
  367 + PayOrderDO updateObj = new PayOrderDO()
  368 + .setRefundPrice(order.getRefundPrice() + incrRefundPrice)
  369 + .setStatus(PayOrderStatusEnum.REFUND.getStatus());
  370 + int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
  371 + if (updateCount == 0) {
  372 + throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
  373 + }
  374 + }
  375 +
  376 + @Override
  377 + public PayOrderExtensionDO getOrderExtension(Long id) {
  378 + return orderExtensionMapper.selectById(id);
  379 + }
  380 +
  381 + /**
  382 + * 获得自身的代理对象,解决 AOP 生效问题
  383 + *
  384 + * @return 自己
  385 + */
  386 + private PayOrderServiceImpl getSelf() {
  387 + return SpringUtil.getBean(getClass());
  388 + }
  389 +
396 } 390 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund;
3 import cn.hutool.core.date.DateUtil; 3 import cn.hutool.core.date.DateUtil;
4 import cn.hutool.core.util.RandomUtil; 4 import cn.hutool.core.util.RandomUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.pay.config.PayProperties;  
7 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 6 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
8 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 7 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@@ -21,16 +20,14 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; @@ -21,16 +20,14 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
21 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 20 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
22 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; 21 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
23 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; 22 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
24 -import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;  
25 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 23 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
26 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;  
27 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 24 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
28 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 25 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
  26 +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
29 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 27 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
30 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 28 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
31 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 29 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
32 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; 30 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
33 -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;  
34 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 31 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
35 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
36 import org.springframework.stereotype.Service; 33 import org.springframework.stereotype.Service;
@@ -43,6 +40,7 @@ import java.util.List; @@ -43,6 +40,7 @@ import java.util.List;
43 40
44 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 41 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
45 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 42 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  43 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
46 44
47 /** 45 /**
48 * 退款订单 Service 实现类 46 * 退款订单 Service 实现类
@@ -66,8 +64,6 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -66,8 +64,6 @@ public class PayRefundServiceImpl implements PayRefundService {
66 @Resource 64 @Resource
67 private PayOrderService orderService; 65 private PayOrderService orderService;
68 @Resource 66 @Resource
69 - private PayOrderExtensionService orderExtensionService;  
70 - @Resource  
71 private PayAppService appService; 67 private PayAppService appService;
72 @Resource 68 @Resource
73 private PayChannelService channelService; 69 private PayChannelService channelService;
@@ -106,13 +102,13 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -106,13 +102,13 @@ public class PayRefundServiceImpl implements PayRefundService {
106 PayClient client = payClientFactory.getPayClient(channel.getId()); 102 PayClient client = payClientFactory.getPayClient(channel.getId());
107 if (client == null) { 103 if (client == null) {
108 log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); 104 log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
109 - throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND); 105 + throw exception(CHANNEL_NOT_FOUND);
110 } 106 }
111 // 1.4 校验退款订单是否已经存在 107 // 1.4 校验退款订单是否已经存在
112 PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId( 108 PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
113 app.getId(), reqDTO.getMerchantRefundId()); 109 app.getId(), reqDTO.getMerchantRefundId());
114 if (refund != null) { 110 if (refund != null) {
115 - throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS); 111 + throw exception(ErrorCodeConstants.REFUND_EXISTS);
116 } 112 }
117 113
118 // 2.1 插入退款单 114 // 2.1 插入退款单
@@ -120,7 +116,7 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -120,7 +116,7 @@ public class PayRefundServiceImpl implements PayRefundService {
120 .setNo(generateRefundNo()).setOrderId(order.getId()) 116 .setNo(generateRefundNo()).setOrderId(order.getId())
121 .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) 117 .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
122 // 商户相关的字段 118 // 商户相关的字段
123 - .setNotifyUrl(app.getRefundNotifyUrl()).setNotifyStatus(PayNotifyStatusEnum.WAITING.getStatus()) 119 + .setNotifyUrl(app.getRefundNotifyUrl())
124 // 渠道相关字段 120 // 渠道相关字段
125 .setChannelOrderNo(order.getChannelOrderNo()) 121 .setChannelOrderNo(order.getChannelOrderNo())
126 // 退款相关字段 122 // 退款相关字段
@@ -128,7 +124,7 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -128,7 +124,7 @@ public class PayRefundServiceImpl implements PayRefundService {
128 .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice()); 124 .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
129 refundMapper.insert(refund); 125 refundMapper.insert(refund);
130 // 2.2 向渠道发起退款申请 126 // 2.2 向渠道发起退款申请
131 - PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId()); 127 + PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId());
132 PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO() 128 PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO()
133 .setPayPrice(order.getPrice()) 129 .setPayPrice(order.getPrice())
134 .setRefundPrice(reqDTO.getPrice()) 130 .setRefundPrice(reqDTO.getPrice())
@@ -136,7 +132,7 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -136,7 +132,7 @@ public class PayRefundServiceImpl implements PayRefundService {
136 .setOutRefundNo(refund.getNo()) 132 .setOutRefundNo(refund.getNo())
137 .setNotifyUrl(genChannelRefundNotifyUrl(channel)) 133 .setNotifyUrl(genChannelRefundNotifyUrl(channel))
138 .setReason(reqDTO.getReason()); 134 .setReason(reqDTO.getReason());
139 - PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段 135 + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
140 // 2.3 处理退款返回 136 // 2.3 处理退款返回
141 notifyRefund(channel, refundRespDTO); 137 notifyRefund(channel, refundRespDTO);
142 138
@@ -153,25 +149,21 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -153,25 +149,21 @@ public class PayRefundServiceImpl implements PayRefundService {
153 private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { 149 private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
154 PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); 150 PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
155 if (order == null) { 151 if (order == null) {
156 - throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND); 152 + throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
157 } 153 }
158 // 校验状态,必须是支付状态 154 // 校验状态,必须是支付状态
159 if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) { 155 if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
160 - throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS); 156 + throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS);
161 } 157 }
162 158
163 - // 是否已经全额退款  
164 - if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) {  
165 - throw exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);  
166 - }  
167 // 校验金额 退款金额不能大于原定的金额 159 // 校验金额 退款金额不能大于原定的金额
168 if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ 160 if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
169 - throw exception(ErrorCodeConstants.PAY_REFUND_PRICE_EXCEED); 161 + throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
170 } 162 }
171 // 是否有退款中的订单 163 // 是否有退款中的订单
172 if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(), 164 if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
173 PayRefundStatusEnum.WAITING.getStatus()) > 0) { 165 PayRefundStatusEnum.WAITING.getStatus()) > 0) {
174 - throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING); 166 + throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING);
175 } 167 }
176 return order; 168 return order;
177 } 169 }
@@ -205,7 +197,6 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -205,7 +197,6 @@ public class PayRefundServiceImpl implements PayRefundService {
205 } 197 }
206 198
207 @Override 199 @Override
208 - @Transactional(rollbackFor = Exception.class)  
209 public void notifyRefund(Long channelId, PayRefundRespDTO notify) { 200 public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
210 // 校验支付渠道是否有效 201 // 校验支付渠道是否有效
211 channelService.validPayChannel(channelId); 202 channelService.validPayChannel(channelId);
@@ -217,28 +208,33 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -217,28 +208,33 @@ public class PayRefundServiceImpl implements PayRefundService {
217 TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify)); 208 TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify));
218 } 209 }
219 210
  211 + // TODO 芋艿:事务问题
220 private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { 212 private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
  213 + // 情况一:退款成功
221 if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { 214 if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
222 notifyRefundSuccess(channel, notify); 215 notifyRefundSuccess(channel, notify);
223 - } else { 216 + return;
  217 + }
  218 + // 情况二:退款失败
  219 + if (PayRefundStatusRespEnum.isFailure(notify.getStatus())) {
224 notifyRefundFailure(channel, notify); 220 notifyRefundFailure(channel, notify);
225 } 221 }
226 } 222 }
227 223
228 - private void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) { 224 + public void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) {
229 // 1.1 查询 PayRefundDO 225 // 1.1 查询 PayRefundDO
230 PayRefundDO refund = refundMapper.selectByAppIdAndNo( 226 PayRefundDO refund = refundMapper.selectByAppIdAndNo(
231 channel.getAppId(), notify.getOutRefundNo()); 227 channel.getAppId(), notify.getOutRefundNo());
232 if (refund == null) { 228 if (refund == null) {
233 - throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND); 229 + throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
234 } 230 }
235 if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 231 if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
  232 + log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId());
236 return; 233 return;
237 } 234 }
238 if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { 235 if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
239 - throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING); 236 + throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
240 } 237 }
241 -  
242 // 1.2 更新 PayRefundDO 238 // 1.2 更新 PayRefundDO
243 PayRefundDO updateRefundObj = new PayRefundDO() 239 PayRefundDO updateRefundObj = new PayRefundDO()
244 .setSuccessTime(notify.getSuccessTime()) 240 .setSuccessTime(notify.getSuccessTime())
@@ -247,19 +243,48 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -247,19 +243,48 @@ public class PayRefundServiceImpl implements PayRefundService {
247 .setChannelNotifyData(toJsonString(notify)); 243 .setChannelNotifyData(toJsonString(notify));
248 int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); 244 int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
249 if (updateCounts == 0) { // 校验状态,必须是等待状态 245 if (updateCounts == 0) { // 校验状态,必须是等待状态
250 - throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING); 246 + throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
251 } 247 }
  248 + log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId());
252 249
253 // 2. 更新订单 250 // 2. 更新订单
254 orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice()); 251 orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice());
255 252
256 - // 3. 插入退款通知记录 253 + // 3. 插入退款通知记录 TODO 芋艿:退款成功
257 notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() 254 notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
258 .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()); 255 .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
259 } 256 }
260 257
261 - private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) {  
262 - // TODO 芋艿:未实现 258 + @Transactional(rollbackFor = Exception.class)
  259 + public void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) {
  260 + // 1.1 查询 PayRefundDO
  261 + PayRefundDO refund = refundMapper.selectByAppIdAndNo(
  262 + channel.getAppId(), notify.getOutRefundNo());
  263 + if (refund == null) {
  264 + throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
  265 + }
  266 + if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
  267 + log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId());
  268 + return;
  269 + }
  270 + if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
  271 + throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
  272 + }
  273 + // 1.2 更新 PayRefundDO
  274 + PayRefundDO updateRefundObj = new PayRefundDO()
  275 + .setChannelRefundNo(notify.getChannelRefundNo())
  276 + .setStatus(PayRefundStatusEnum.FAILURE.getStatus())
  277 + .setChannelNotifyData(toJsonString(notify))
  278 + .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg());
  279 + int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
  280 + if (updateCounts == 0) { // 校验状态,必须是等待状态
  281 + throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
  282 + }
  283 + log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId());
  284 +
  285 + // 2. 插入退款通知记录 TODO 芋艿:退款失败
  286 + notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
  287 + .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
263 } 288 }
264 289
265 } 290 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/util/MoneyUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.util;
  2 +
  3 +import java.math.BigDecimal;
  4 +import java.math.RoundingMode;
  5 +
  6 +/**
  7 + * 金额工具类
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +public class MoneyUtils {
  12 +
  13 + /**
  14 + * 计算百分比金额,四舍五入
  15 + *
  16 + * @param price 金额
  17 + * @param rate 百分比,例如说 56.77% 则传入 56.77
  18 + * @return 百分比金额
  19 + */
  20 + public static Integer calculateRatePrice(Integer price, Double rate) {
  21 + return new BigDecimal(price)
  22 + .multiply(BigDecimal.valueOf(rate)) // 乘以
  23 + .setScale(0, RoundingMode.HALF_UP) // 四舍五入
  24 + .intValue();
  25 + }
  26 +
  27 +}
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 { @@ -90,7 +90,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
90 PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> 90 PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
91 o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); 91 o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
92 // 调用, 并断言异常 92 // 调用, 并断言异常
93 - assertServiceException(() -> appService.updateApp(reqVO), PAY_APP_NOT_FOUND); 93 + assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_FOUND);
94 } 94 }
95 95
96 @Test 96 @Test
@@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
130 Long id = randomLongId(); 130 Long id = randomLongId();
131 131
132 // 调用, 并断言异常 132 // 调用, 并断言异常
133 - assertServiceException(() -> appService.deleteApp(id), PAY_APP_NOT_FOUND); 133 + assertServiceException(() -> appService.deleteApp(id), APP_NOT_FOUND);
134 } 134 }
135 135
136 @Test 136 @Test
@@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
144 when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L); 144 when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L);
145 145
146 // 调用, 并断言异常 146 // 调用, 并断言异常
147 - assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_ORDER_CANT_DELETE); 147 + assertServiceException(() -> appService.deleteApp(id), APP_EXIST_ORDER_CANT_DELETE);
148 } 148 }
149 149
150 @Test 150 @Test
@@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
158 when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L); 158 when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L);
159 159
160 // 调用, 并断言异常 160 // 调用, 并断言异常
161 - assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_REFUND_CANT_DELETE); 161 + assertServiceException(() -> appService.deleteApp(id), APP_EXIST_REFUND_CANT_DELETE);
162 } 162 }
163 163
164 @Test 164 @Test
@@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
239 239
240 @Test 240 @Test
241 public void testValidPayApp_notFound() { 241 public void testValidPayApp_notFound() {
242 - assertServiceException(() -> appService.validPayApp(randomLongId()), PAY_APP_NOT_FOUND); 242 + assertServiceException(() -> appService.validPayApp(randomLongId()), APP_NOT_FOUND);
243 } 243 }
244 244
245 @Test 245 @Test
@@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
252 Long id = dbApp.getId(); 252 Long id = dbApp.getId();
253 253
254 // 调用,并断言异常 254 // 调用,并断言异常
255 - assertServiceException(() -> appService.validPayApp(id), PAY_APP_IS_DISABLE); 255 + assertServiceException(() -> appService.validPayApp(id), APP_IS_DISABLE);
256 } 256 }
257 257
258 } 258 }
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; @@ -26,8 +26,7 @@ import java.util.List;
26 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 26 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
29 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;  
30 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS; 29 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
31 import static org.junit.jupiter.api.Assertions.*; 30 import static org.junit.jupiter.api.Assertions.*;
32 31
33 @Import({PayChannelServiceImpl.class}) 32 @Import({PayChannelServiceImpl.class})
@@ -52,6 +51,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @@ -52,6 +51,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
52 } 51 }
53 52
54 @Test 53 @Test
  54 + public void testInitLocalCache() {
  55 + // mock 数据
  56 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
  57 + o -> o.setConfig(randomWxPayClientConfig()));
  58 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  59 +
  60 + // 调用
  61 + channelService.initLocalCache();
  62 + // 校验缓存
  63 + assertEquals(1, channelService.getChannelCache().size());
  64 + assertEquals(dbChannel, channelService.getChannelCache().get(0));
  65 + }
  66 +
  67 + @Test
  68 + public void testRefreshLocalCache() {
  69 + // mock 数据 01
  70 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
  71 + o -> o.setConfig(randomWxPayClientConfig()));
  72 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  73 + channelService.initLocalCache();
  74 + // mock 数据 02
  75 + PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class,
  76 + o -> o.setConfig(randomWxPayClientConfig()));
  77 + channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
  78 +
  79 + // 调用
  80 + channelService.refreshLocalCache();
  81 + // 校验缓存
  82 + assertEquals(2, channelService.getChannelCache().size());
  83 + assertEquals(dbChannel, channelService.getChannelCache().get(0));
  84 + assertEquals(dbChannel02, channelService.getChannelCache().get(1));
  85 + }
  86 +
  87 + @Test
55 public void testCreateChannel_success() { 88 public void testCreateChannel_success() {
56 // 准备参数 89 // 准备参数
57 WxPayClientConfig config = randomWxPayClientConfig(); 90 WxPayClientConfig config = randomWxPayClientConfig();
@@ -125,7 +158,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @@ -125,7 +158,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
125 }); 158 });
126 159
127 // 调用, 并断言异常 160 // 调用, 并断言异常
128 - assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS); 161 + assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_FOUND);
129 } 162 }
130 163
131 @Test 164 @Test
@@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
153 Long id = randomLongId(); 186 Long id = randomLongId();
154 187
155 // 调用, 并断言异常 188 // 调用, 并断言异常
156 - assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS); 189 + assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_FOUND);
157 } 190 }
158 191
159 @Test 192 @Test
@@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
214 assertPojoEquals(channel, dbChannel); 247 assertPojoEquals(channel, dbChannel);
215 } 248 }
216 249
  250 + @Test
  251 + public void testValidPayChannel_notExists() {
  252 + // 准备参数
  253 + Long id = randomLongId();
  254 +
  255 + // 调用, 并断言异常
  256 + assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_NOT_FOUND);
  257 + }
  258 +
  259 + @Test
  260 + public void testValidPayChannel_isDisable() {
  261 + // mock 数据
  262 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
  263 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  264 + o.setConfig(randomAlipayPayClientConfig());
  265 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  266 + });
  267 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  268 + // 准备参数
  269 + Long id = dbChannel.getId();
  270 +
  271 + // 调用, 并断言异常
  272 + assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_IS_DISABLE);
  273 + }
  274 +
  275 + @Test
  276 + public void testValidPayChannel_success() {
  277 + // mock 数据
  278 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
  279 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  280 + o.setConfig(randomAlipayPayClientConfig());
  281 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  282 + });
  283 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  284 + // 准备参数
  285 + Long id = dbChannel.getId();
  286 +
  287 + // 调用
  288 + PayChannelDO channel = channelService.validPayChannel(id);
  289 + // 断言异常
  290 + assertPojoEquals(channel, dbChannel);
  291 + }
  292 +
  293 + @Test
  294 + public void testValidPayChannel_appIdAndCode() {
  295 + // mock 数据
  296 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
  297 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  298 + o.setConfig(randomAlipayPayClientConfig());
  299 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  300 + });
  301 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  302 + // 准备参数
  303 + Long appId = dbChannel.getAppId();
  304 + String code = dbChannel.getCode();
  305 +
  306 + // 调用
  307 + PayChannelDO channel = channelService.validPayChannel(appId, code);
  308 + // 断言异常
  309 + assertPojoEquals(channel, dbChannel);
  310 + }
  311 +
  312 + @Test
  313 + public void testGetEnableChannelList() {
  314 + // 准备参数
  315 + Long appId = randomLongId();
  316 + // mock 数据 01(enable 不匹配)
  317 + PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> {
  318 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  319 + o.setConfig(randomAlipayPayClientConfig());
  320 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  321 + });
  322 + channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据
  323 + // mock 数据 02(appId 不匹配)
  324 + PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> {
  325 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  326 + o.setConfig(randomAlipayPayClientConfig());
  327 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  328 + });
  329 + channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
  330 + // mock 数据 03
  331 + PayChannelDO dbChannel03 = randomPojo(PayChannelDO.class, o -> {
  332 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  333 + o.setConfig(randomAlipayPayClientConfig());
  334 + o.setAppId(appId);
  335 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  336 + });
  337 + channelMapper.insert(dbChannel03);// @Sql: 先插入出一条存在的数据
  338 +
  339 + // 调用
  340 + List<PayChannelDO> channel = channelService.getEnableChannelList(appId);
  341 + // 断言异常
  342 + assertPojoEquals(channel, dbChannel03);
  343 + }
  344 +
217 public WxPayClientConfig randomWxPayClientConfig() { 345 public WxPayClientConfig randomWxPayClientConfig() {
218 return new WxPayClientConfig() 346 return new WxPayClientConfig()
219 .setAppId(randomString()) 347 .setAppId(randomString())
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
1 package cn.iocoder.yudao.module.pay.service.order; 1 package cn.iocoder.yudao.module.pay.service.order;
2 2
3 -import cn.hutool.core.date.DateUtil;  
4 -import cn.hutool.core.util.RandomUtil; 3 +import cn.hutool.extra.spring.SpringUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.pay.config.PayProperties; 5 +import cn.iocoder.yudao.framework.pay.core.client.PayClient;
7 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 6 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
  7 +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 9 +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
  10 +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
  11 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
  12 +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
10 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; 13 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
11 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; 14 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
  15 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
  16 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
  17 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
  18 +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
12 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 19 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
  20 +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
  21 +import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
13 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; 22 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
14 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum; 23 +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
  24 +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; 25 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
16 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum; 26 +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
17 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 27 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
18 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 28 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
19 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 29 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
  30 +import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
  31 +import org.junit.jupiter.api.BeforeEach;
20 import org.junit.jupiter.api.Test; 32 import org.junit.jupiter.api.Test;
  33 +import org.mockito.ArgumentMatcher;
  34 +import org.mockito.MockedStatic;
21 import org.springframework.boot.test.mock.mockito.MockBean; 35 import org.springframework.boot.test.mock.mockito.MockBean;
22 import org.springframework.context.annotation.Import; 36 import org.springframework.context.annotation.Import;
23 37
24 import javax.annotation.Resource; 38 import javax.annotation.Resource;
25 -import java.time.LocalDateTime; 39 +import java.time.Duration;
26 import java.util.List; 40 import java.util.List;
27 41
  42 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  43 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
28 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 44 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 45 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  46 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 47 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  48 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
  49 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
  50 +import static org.assertj.core.api.Assertions.assertThat;
31 import static org.junit.jupiter.api.Assertions.assertEquals; 51 import static org.junit.jupiter.api.Assertions.assertEquals;
  52 +import static org.junit.jupiter.api.Assertions.assertNotNull;
  53 +import static org.mockito.ArgumentMatchers.*;
  54 +import static org.mockito.Mockito.*;
32 55
33 /** 56 /**
34 * {@link PayOrderServiceImpl} 的单元测试类 57 * {@link PayOrderServiceImpl} 的单元测试类
35 * 58 *
36 * @author 芋艿 59 * @author 芋艿
37 */ 60 */
38 -@Import({PayOrderServiceImpl.class})  
39 -public class PayOrderServiceTest extends BaseDbUnitTest { 61 +@Import({PayOrderServiceImpl.class, PayNoRedisDAO.class})
  62 +public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
40 63
41 @Resource 64 @Resource
42 private PayOrderServiceImpl orderService; 65 private PayOrderServiceImpl orderService;
43 66
44 @Resource 67 @Resource
45 private PayOrderMapper orderMapper; 68 private PayOrderMapper orderMapper;
  69 + @Resource
  70 + private PayOrderExtensionMapper orderExtensionMapper;
46 71
47 @MockBean 72 @MockBean
48 private PayClientFactory payClientFactory; 73 private PayClientFactory payClientFactory;
@@ -55,140 +80,92 @@ public class PayOrderServiceTest extends BaseDbUnitTest { @@ -55,140 +80,92 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
55 @MockBean 80 @MockBean
56 private PayNotifyService notifyService; 81 private PayNotifyService notifyService;
57 82
58 - public String generateNo() {  
59 - return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); 83 + @BeforeEach
  84 + public void setUp() {
  85 + when(properties.getOrderNotifyUrl()).thenReturn("http://127.0.0.1");
60 } 86 }
61 87
62 @Test 88 @Test
63 public void testGetOrderPage() { 89 public void testGetOrderPage() {
64 -  
65 - String merchantOrderId = generateNo();  
66 - String channelOrderId = generateNo();  
67 -  
68 // mock 数据 90 // mock 数据
69 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 91 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
70 o.setAppId(1L); 92 o.setAppId(1L);
71 - o.setChannelId(1L);  
72 o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 93 o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
73 - o.setMerchantOrderId(merchantOrderId);  
74 - o.setSubject("灿灿子的炸弹猫");  
75 - o.setBody("斌斌子送给灿灿子的炸弹猫");  
76 - o.setNotifyUrl("https://hc.com/lbh");  
77 - o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());  
78 - o.setPrice(10000);  
79 - o.setChannelFeeRate(0.01);  
80 - o.setChannelFeePrice(1L); 94 + o.setMerchantOrderId("110");
  95 + o.setChannelOrderNo("220");
  96 + o.setNo("330");
81 o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); 97 o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
82 - o.setUserIp("127.0.0.1");  
83 - o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));  
84 - o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));  
85 - o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));  
86 - o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));  
87 - o.setSuccessExtensionId(1L);  
88 - o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());  
89 - o.setRefundTimes(0);  
90 - o.setRefundPrice(0);  
91 - o.setChannelUserId("1008611");  
92 - o.setChannelOrderNo(channelOrderId);  
93 - o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15)); 98 + o.setCreateTime(buildTime(2018, 1, 15));
94 }); 99 });
95 orderMapper.insert(dbOrder); 100 orderMapper.insert(dbOrder);
96 // 测试 appId 不匹配 101 // 测试 appId 不匹配
97 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); 102 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
98 - // 测试 channelId 不匹配  
99 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L)));  
100 // 测试 channelCode 不匹配 103 // 测试 channelCode 不匹配
101 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); 104 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
102 // 测试 merchantOrderId 不匹配 105 // 测试 merchantOrderId 不匹配
103 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));  
104 - // 测试 notifyStatus 不匹配  
105 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); 106 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
  107 + // 测试 channelOrderNo 不匹配
  108 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString())));
  109 + // 测试 no 不匹配
  110 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString())));
106 // 测试 status 不匹配 111 // 测试 status 不匹配
107 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()))); 112 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
108 - // 测试 refundStatus 不匹配  
109 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));  
110 // 测试 createTime 不匹配 113 // 测试 createTime 不匹配
111 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,  
112 - 1)))); 114 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
113 // 准备参数 115 // 准备参数
114 PayOrderPageReqVO reqVO = new PayOrderPageReqVO(); 116 PayOrderPageReqVO reqVO = new PayOrderPageReqVO();
115 reqVO.setAppId(1L); 117 reqVO.setAppId(1L);
116 - reqVO.setChannelId(1L);  
117 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 118 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
118 - reqVO.setMerchantOrderId(merchantOrderId);  
119 - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); 119 + reqVO.setMerchantOrderId("11");
  120 + reqVO.setChannelOrderNo("22");
  121 + reqVO.setNo("33");
120 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); 122 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
121 - reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());  
122 - reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)})); 123 + reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
  124 +
123 // 调用 125 // 调用
124 PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO); 126 PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
125 // 断言 127 // 断言
126 assertEquals(1, pageResult.getTotal()); 128 assertEquals(1, pageResult.getTotal());
127 assertEquals(1, pageResult.getList().size()); 129 assertEquals(1, pageResult.getList().size());
128 assertPojoEquals(dbOrder, pageResult.getList().get(0)); 130 assertPojoEquals(dbOrder, pageResult.getList().get(0));
129 - // assertEquals(0, dbOrder.getUpdateTime().compareTo(pageResult.getList().get(0).getUpdateTime()));  
130 } 131 }
131 132
132 @Test 133 @Test
133 public void testGetOrderList() { 134 public void testGetOrderList() {
134 // mock 数据 135 // mock 数据
135 - String merchantOrderId = generateNo();  
136 - String channelOrderId = generateNo();  
137 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 136 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
138 o.setAppId(1L); 137 o.setAppId(1L);
139 - o.setChannelId(1L);  
140 o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 138 o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
141 - o.setMerchantOrderId(merchantOrderId);  
142 - o.setSubject("灿灿子的炸弹猫");  
143 - o.setBody("斌斌子送给灿灿子的炸弹猫");  
144 - o.setNotifyUrl("https://hc.com/lbh");  
145 - o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());  
146 - o.setPrice(10000);  
147 - o.setChannelFeeRate(0.01);  
148 - o.setChannelFeePrice(1L); 139 + o.setMerchantOrderId("110");
  140 + o.setChannelOrderNo("220");
  141 + o.setNo("330");
149 o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); 142 o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
150 - o.setUserIp("127.0.0.1");  
151 - o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));  
152 - o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));  
153 - o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));  
154 - o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));  
155 - o.setSuccessExtensionId(1L);  
156 - o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());  
157 - o.setRefundTimes(0);  
158 - o.setRefundPrice(0);  
159 - o.setChannelUserId("1008611");  
160 - o.setChannelOrderNo(channelOrderId);  
161 - o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));  
162 - 143 + o.setCreateTime(buildTime(2018, 1, 15));
163 }); 144 });
164 orderMapper.insert(dbOrder); 145 orderMapper.insert(dbOrder);
165 // 测试 appId 不匹配 146 // 测试 appId 不匹配
166 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); 147 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
167 - // 测试 channelId 不匹配  
168 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L)));  
169 // 测试 channelCode 不匹配 148 // 测试 channelCode 不匹配
170 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); 149 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
171 // 测试 merchantOrderId 不匹配 150 // 测试 merchantOrderId 不匹配
172 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));  
173 - // 测试 notifyStatus 不匹配  
174 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); 151 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
  152 + // 测试 channelOrderNo 不匹配
  153 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString())));
  154 + // 测试 no 不匹配
  155 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString())));
175 // 测试 status 不匹配 156 // 测试 status 不匹配
176 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()))); 157 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
177 - // 测试 refundStatus 不匹配  
178 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));  
179 // 测试 createTime 不匹配 158 // 测试 createTime 不匹配
180 - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,  
181 - 1)))); 159 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
182 // 准备参数 160 // 准备参数
183 PayOrderExportReqVO reqVO = new PayOrderExportReqVO(); 161 PayOrderExportReqVO reqVO = new PayOrderExportReqVO();
184 reqVO.setAppId(1L); 162 reqVO.setAppId(1L);
185 - reqVO.setChannelId(1L);  
186 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 163 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
187 - reqVO.setMerchantOrderId(merchantOrderId);  
188 - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); 164 + reqVO.setMerchantOrderId("11");
  165 + reqVO.setChannelOrderNo("22");
  166 + reqVO.setNo("33");
189 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); 167 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
190 - reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());  
191 - reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)})); 168 + reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
192 169
193 // 调用 170 // 调用
194 List<PayOrderDO> list = orderService.getOrderList(reqVO); 171 List<PayOrderDO> list = orderService.getOrderList(reqVO);
@@ -197,4 +174,393 @@ public class PayOrderServiceTest extends BaseDbUnitTest { @@ -197,4 +174,393 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
197 assertPojoEquals(dbOrder, list.get(0)); 174 assertPojoEquals(dbOrder, list.get(0));
198 } 175 }
199 176
  177 + @Test
  178 + public void testCreateOrder_success() {
  179 + // mock 参数
  180 + PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
  181 + o -> o.setAppId(1L).setMerchantOrderId("10")
  182 + .setSubject(randomString()).setBody(randomString()));
  183 + // mock 方法
  184 + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
  185 + when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app);
  186 +
  187 + // 调用
  188 + Long orderId = orderService.createOrder(reqDTO);
  189 + // 断言
  190 + PayOrderDO order = orderMapper.selectById(orderId);
  191 + assertPojoEquals(order, reqDTO);
  192 + assertEquals(order.getAppId(), 1L);
  193 + assertEquals(order.getNotifyUrl(), "http://127.0.0.1");
  194 + assertEquals(order.getStatus(), PayOrderStatusEnum.WAITING.getStatus());
  195 + assertEquals(order.getRefundPrice(), 0);
  196 + }
  197 +
  198 + @Test
  199 + public void testCreateOrder_exists() {
  200 + // mock 参数
  201 + PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
  202 + o -> o.setAppId(1L).setMerchantOrderId("10"));
  203 + // mock 数据
  204 + PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> o.setAppId(1L).setMerchantOrderId("10"));
  205 + orderMapper.insert(dbOrder);
  206 +
  207 + // 调用
  208 + Long orderId = orderService.createOrder(reqDTO);
  209 + // 断言
  210 + PayOrderDO order = orderMapper.selectById(orderId);
  211 + assertPojoEquals(dbOrder, order);
  212 + }
  213 +
  214 + @Test
  215 + public void testSubmitOrder_notFound() {
  216 + // 准备参数
  217 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class);
  218 + String userIp = randomString();
  219 +
  220 + // 调用, 并断言异常
  221 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
  222 + }
  223 +
  224 + @Test
  225 + public void testSubmitOrder_notWaiting() {
  226 + // mock 数据(order)
  227 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
  228 + orderMapper.insert(order);
  229 + // 准备参数
  230 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
  231 + String userIp = randomString();
  232 +
  233 + // 调用, 并断言异常
  234 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
  235 + }
  236 +
  237 + @Test
  238 + public void testSubmitOrder_expired() {
  239 + // mock 数据(order)
  240 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  241 + .setExpireTime(addTime(Duration.ofDays(-1))));
  242 + orderMapper.insert(order);
  243 + // 准备参数
  244 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
  245 + String userIp = randomString();
  246 +
  247 + // 调用, 并断言异常
  248 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
  249 + }
  250 +
  251 + @Test
  252 + public void testSubmitOrder_channelNotFound() {
  253 + // mock 数据(order)
  254 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  255 + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
  256 + orderMapper.insert(order);
  257 + // 准备参数
  258 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
  259 + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
  260 + String userIp = randomString();
  261 + // mock 方法(app)
  262 + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
  263 + when(appService.validPayApp(eq(1L))).thenReturn(app);
  264 + // mock 方法(channel)
  265 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
  266 + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
  267 + .thenReturn(channel);
  268 +
  269 + // 调用, 并断言异常
  270 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), CHANNEL_NOT_FOUND);
  271 + }
  272 +
  273 + @Test // 调用 unifiedOrder 接口,返回存在渠道错误
  274 + public void testSubmitOrder_channelError() {
  275 + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
  276 + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
  277 + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
  278 + .thenReturn(payOrderServiceImpl);
  279 +
  280 + // mock 数据(order)
  281 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  282 + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
  283 + orderMapper.insert(order);
  284 + // 准备参数
  285 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
  286 + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
  287 + String userIp = randomString();
  288 + // mock 方法(app)
  289 + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
  290 + when(appService.validPayApp(eq(1L))).thenReturn(app);
  291 + // mock 方法(channel)
  292 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
  293 + .setCode(PayChannelEnum.ALIPAY_APP.getCode()));
  294 + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
  295 + .thenReturn(channel);
  296 + // mock 方法(client)
  297 + PayClient client = mock(PayClient.class);
  298 + when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  299 + // mock 方法()
  300 + PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o ->
  301 + o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常"));
  302 + when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
  303 + assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo());
  304 + assertThat(payOrderUnifiedReqDTO)
  305 + .extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime")
  306 + .containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10",
  307 + reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime());
  308 + return true;
  309 + }))).thenReturn(unifiedOrderResp);
  310 +
  311 + // 调用,并断言异常
  312 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
  313 + ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
  314 + // 断言,数据记录(PayOrderExtensionDO)
  315 + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
  316 + assertNotNull(orderExtension);
  317 + assertThat(orderExtension).extracting("no", "orderId").isNotNull();
  318 + assertThat(orderExtension)
  319 + .extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
  320 + "channelErrorCode", "channelErrorMsg", "channelNotifyData")
  321 + .containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
  322 + PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
  323 + null, null, null);
  324 + }
  325 + }
  326 +
  327 + @Test
  328 + public void testSubmitOrder_success() {
  329 + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
  330 + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
  331 + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
  332 + .thenReturn(payOrderServiceImpl);
  333 +
  334 + // mock 数据(order)
  335 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  336 + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
  337 + orderMapper.insert(order);
  338 + // 准备参数
  339 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
  340 + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
  341 + String userIp = randomString();
  342 + // mock 方法(app)
  343 + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
  344 + when(appService.validPayApp(eq(1L))).thenReturn(app);
  345 + // mock 方法(channel)
  346 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
  347 + .setCode(PayChannelEnum.ALIPAY_APP.getCode()));
  348 + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
  349 + .thenReturn(channel);
  350 + // mock 方法(client)
  351 + PayClient client = mock(PayClient.class);
  352 + when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  353 + // mock 方法()
  354 + PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
  355 + .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
  356 + when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
  357 + assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo());
  358 + assertThat(payOrderUnifiedReqDTO)
  359 + .extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime")
  360 + .containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10",
  361 + reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime());
  362 + return true;
  363 + }))).thenReturn(unifiedOrderResp);
  364 +
  365 + // 调用
  366 + PayOrderSubmitRespVO result = orderService.submitOrder(reqVO, userIp);
  367 + // 断言,数据记录(PayOrderExtensionDO)
  368 + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
  369 + assertNotNull(orderExtension);
  370 + assertThat(orderExtension).extracting("no", "orderId").isNotNull();
  371 + assertThat(orderExtension)
  372 + .extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
  373 + "channelErrorCode", "channelErrorMsg", "channelNotifyData")
  374 + .containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
  375 + PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
  376 + null, null, null);
  377 + // 断言,返回(PayOrderSubmitRespVO)
  378 + assertThat(result)
  379 + .extracting("status", "displayMode", "displayContent")
  380 + .containsExactly(PayOrderStatusEnum.WAITING.getStatus(), PayOrderDisplayModeEnum.URL.getMode(), "tudou");
  381 + // 断言,调用
  382 + verify(payOrderServiceImpl).notifyOrder(same(channel), same(unifiedOrderResp));
  383 + }
  384 + }
  385 +
  386 + @Test
  387 + public void testNotifyOrder_channelId() {
  388 + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
  389 + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
  390 + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
  391 + .thenReturn(payOrderServiceImpl);
  392 + // 准备参数
  393 + Long channelId = 10L;
  394 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class);
  395 + // mock 方法(channel)
  396 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  397 + when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
  398 +
  399 + // 调用
  400 + orderService.notifyOrder(channelId, notify);
  401 + // 断言
  402 + verify(payOrderServiceImpl).notifyOrder(same(channel), same(notify));
  403 + }
  404 + }
  405 +
  406 + @Test
  407 + public void testNotifyOrderSuccess_orderExtension_notFound() {
  408 + // 准备参数
  409 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  410 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  411 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()));
  412 +
  413 + // 调用,并断言异常
  414 + assertServiceException(() -> orderService.notifyOrder(channel, notify),
  415 + ORDER_EXTENSION_NOT_FOUND);
  416 + }
  417 +
  418 + @Test
  419 + public void testNotifyOrderSuccess_orderExtension_closed() {
  420 + // mock 数据(PayOrderExtensionDO)
  421 + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
  422 + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
  423 + .setNo("P110"));
  424 + orderExtensionMapper.insert(orderExtension);
  425 + // 准备参数
  426 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  427 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  428 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
  429 + .setOutTradeNo("P110"));
  430 +
  431 + // 调用,并断言异常
  432 + assertServiceException(() -> orderService.notifyOrder(channel, notify),
  433 + ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  434 + }
  435 +
  436 + @Test
  437 + public void testNotifyOrderSuccess_order_notFound() {
  438 + // mock 数据(PayOrderExtensionDO)
  439 + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
  440 + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
  441 + .setNo("P110"));
  442 + orderExtensionMapper.insert(orderExtension);
  443 + // 准备参数
  444 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  445 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  446 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
  447 + .setOutTradeNo("P110"));
  448 +
  449 + // 调用,并断言异常
  450 + assertServiceException(() -> orderService.notifyOrder(channel, notify),
  451 + ORDER_NOT_FOUND);
  452 + // 断言 PayOrderExtensionDO :数据更新被回滚
  453 + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
  454 + }
  455 +
  456 + @Test
  457 + public void testNotifyOrderSuccess_order_closed() {
  458 + testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.CLOSED.getStatus());
  459 + }
  460 +
  461 + @Test
  462 + public void testNotifyOrderSuccess_order_refund() {
  463 + testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.REFUND.getStatus());
  464 + }
  465 +
  466 + private void testNotifyOrderSuccess_order_closedOrRefund(Integer status) {
  467 + // mock 数据(PayOrderDO)
  468 + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status));
  469 + orderMapper.insert(order);
  470 + // mock 数据(PayOrderExtensionDO)
  471 + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
  472 + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
  473 + .setNo("P110")
  474 + .setOrderId(order.getId()));
  475 + orderExtensionMapper.insert(orderExtension);
  476 + // 准备参数
  477 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  478 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  479 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
  480 + .setOutTradeNo("P110"));
  481 +
  482 + // 调用,并断言异常
  483 + assertServiceException(() -> orderService.notifyOrder(channel, notify),
  484 + ORDER_STATUS_IS_NOT_WAITING);
  485 + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
  486 + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
  487 + }
  488 +
  489 + @Test
  490 + public void testNotifyOrderSuccess_order_paid() {
  491 + // mock 数据(PayOrderDO)
  492 + PayOrderDO order = randomPojo(PayOrderDO.class,
  493 + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
  494 + orderMapper.insert(order);
  495 + // mock 数据(PayOrderExtensionDO)
  496 + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
  497 + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
  498 + .setNo("P110")
  499 + .setOrderId(order.getId()));
  500 + orderExtensionMapper.insert(orderExtension);
  501 + // 重要:需要将 order 的 extensionId 更新下
  502 + order.setExtensionId(orderExtension.getId());
  503 + orderMapper.updateById(order);
  504 + // 准备参数
  505 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
  506 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  507 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
  508 + .setOutTradeNo("P110"));
  509 +
  510 + // 调用,并断言异常
  511 + orderService.notifyOrder(channel, notify);
  512 + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
  513 + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
  514 + // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS
  515 + assertPojoEquals(order, orderMapper.selectOne(null));
  516 + // 断言,调用
  517 + verify(notifyService, never()).createPayNotifyTask(any(PayNotifyTaskCreateReqDTO.class));
  518 + }
  519 +
  520 + @Test
  521 + public void testNotifyOrderSuccess_order_waiting() {
  522 + // mock 数据(PayOrderDO)
  523 + PayOrderDO order = randomPojo(PayOrderDO.class,
  524 + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  525 + .setPrice(10));
  526 + orderMapper.insert(order);
  527 + // mock 数据(PayOrderExtensionDO)
  528 + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
  529 + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
  530 + .setNo("P110")
  531 + .setOrderId(order.getId()));
  532 + orderExtensionMapper.insert(orderExtension);
  533 + // 准备参数
  534 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
  535 + .setFeeRate(0.1D));
  536 + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
  537 + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
  538 + .setOutTradeNo("P110"));
  539 +
  540 + // 调用,并断言异常
  541 + orderService.notifyOrder(channel, notify);
  542 + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
  543 + orderExtension.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
  544 + .setChannelNotifyData(toJsonString(notify));
  545 + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null),
  546 + "updateTime", "updater");
  547 + // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS
  548 + order.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
  549 + .setChannelId(10L).setChannelCode(channel.getCode())
  550 + .setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo())
  551 + .setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId())
  552 + .setChannelFeeRate(0.1D).setChannelFeePrice(1);
  553 + assertPojoEquals(order, orderMapper.selectOne(null),
  554 + "updateTime", "updater");
  555 + // 断言,调用
  556 + verify(notifyService).createPayNotifyTask(argThat(new ArgumentMatcher<PayNotifyTaskCreateReqDTO>() {
  557 + @Override
  558 + public boolean matches(PayNotifyTaskCreateReqDTO reqDTO) {
  559 + assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType());
  560 + assertEquals(reqDTO.getDataId(), orderExtension.getOrderId());
  561 + return true;
  562 + }
  563 + }));
  564 + }
  565 +
200 } 566 }
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
1 package cn.iocoder.yudao.module.pay.service.refund; 1 package cn.iocoder.yudao.module.pay.service.refund;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.framework.pay.config.PayProperties;  
5 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 4 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
6 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 5 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
7 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 7 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
8 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; 8 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
9 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; 9 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
10 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
11 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; 11 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
12 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum; 12 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
13 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 13 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
14 -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum; 14 +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
15 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 15 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
16 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 16 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
17 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 17 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
18 -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;  
19 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 18 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
20 import org.junit.jupiter.api.Test; 19 import org.junit.jupiter.api.Test;
21 import org.springframework.boot.test.mock.mockito.MockBean; 20 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -31,7 +30,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; @@ -31,7 +30,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
31 import static org.junit.jupiter.api.Assertions.assertEquals; 30 import static org.junit.jupiter.api.Assertions.assertEquals;
32 31
33 @Import(PayRefundServiceImpl.class) 32 @Import(PayRefundServiceImpl.class)
34 -public class PayRefundServiceTest extends BaseDbUnitTest { 33 +public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
35 34
36 @Resource 35 @Resource
37 private PayRefundServiceImpl refundService; 36 private PayRefundServiceImpl refundService;
@@ -46,8 +45,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -46,8 +45,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
46 @MockBean 45 @MockBean
47 private PayOrderService orderService; 46 private PayOrderService orderService;
48 @MockBean 47 @MockBean
49 - private PayOrderExtensionService orderExtensionService;  
50 - @MockBean  
51 private PayAppService appService; 48 private PayAppService appService;
52 @MockBean 49 @MockBean
53 private PayChannelService channelService; 50 private PayChannelService channelService;
@@ -66,8 +63,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -66,8 +63,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
66 o.setMerchantOrderId("MOT0000001"); 63 o.setMerchantOrderId("MOT0000001");
67 o.setMerchantRefundId("MRF0000001"); 64 o.setMerchantRefundId("MRF0000001");
68 o.setNotifyUrl("https://www.cancanzi.com"); 65 o.setNotifyUrl("https://www.cancanzi.com");
69 - o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());  
70 - o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); 66 + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
71 o.setPayPrice(100); 67 o.setPayPrice(100);
72 o.setRefundPrice(500); 68 o.setRefundPrice(500);
73 o.setReason("就是想退款了,你有意见吗"); 69 o.setReason("就是想退款了,你有意见吗");
@@ -87,11 +83,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -87,11 +83,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
87 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); 83 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
88 // 测试 merchantRefundNo 不匹配 84 // 测试 merchantRefundNo 不匹配
89 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); 85 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
90 - // 测试 notifyStatus 不匹配  
91 - refundMapper.insert(  
92 - cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));  
93 // 测试 status 不匹配 86 // 测试 status 不匹配
94 - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus()))); 87 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
95 // 测试 createTime 不匹配 88 // 测试 createTime 不匹配
96 refundMapper.insert(cloneIgnoreId(dbRefund, o -> 89 refundMapper.insert(cloneIgnoreId(dbRefund, o ->
97 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); 90 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
@@ -99,8 +92,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -99,8 +92,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
99 PayRefundPageReqVO reqVO = new PayRefundPageReqVO(); 92 PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
100 reqVO.setAppId(1L); 93 reqVO.setAppId(1L);
101 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 94 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
102 - reqVO.setMerchantRefundNo("MRF0000001");  
103 - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); 95 + reqVO.setMerchantRefundId("MRF0000001");
104 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); 96 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
105 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)})); 97 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
106 98
@@ -124,8 +116,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -124,8 +116,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
124 o.setMerchantOrderId("MOT0000001"); 116 o.setMerchantOrderId("MOT0000001");
125 o.setMerchantRefundId("MRF0000001"); 117 o.setMerchantRefundId("MRF0000001");
126 o.setNotifyUrl("https://www.cancanzi.com"); 118 o.setNotifyUrl("https://www.cancanzi.com");
127 - o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());  
128 - o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); 119 + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
129 o.setPayPrice(100); 120 o.setPayPrice(100);
130 o.setRefundPrice(500); 121 o.setRefundPrice(500);
131 o.setReason("就是想退款了,你有意见吗"); 122 o.setReason("就是想退款了,你有意见吗");
@@ -145,11 +136,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -145,11 +136,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
145 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); 136 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
146 // 测试 merchantRefundNo 不匹配 137 // 测试 merchantRefundNo 不匹配
147 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); 138 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
148 - // 测试 notifyStatus 不匹配  
149 - refundMapper.insert(  
150 - cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));  
151 // 测试 status 不匹配 139 // 测试 status 不匹配
152 - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus()))); 140 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
153 // 测试 createTime 不匹配 141 // 测试 createTime 不匹配
154 refundMapper.insert(cloneIgnoreId(dbRefund, o -> 142 refundMapper.insert(cloneIgnoreId(dbRefund, o ->
155 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); 143 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
@@ -158,10 +146,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { @@ -158,10 +146,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
158 PayRefundExportReqVO reqVO = new PayRefundExportReqVO(); 146 PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
159 reqVO.setAppId(1L); 147 reqVO.setAppId(1L);
160 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); 148 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
161 - reqVO.setMerchantRefundNo("MRF0000001");  
162 - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());  
163 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); 149 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
164 - reqVO.setType(PayOrderRefundStatusEnum.PART.getStatus());  
165 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)})); 150 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
166 151
167 // 调用 152 // 调用
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql
1 DELETE FROM pay_app; 1 DELETE FROM pay_app;
2 DELETE FROM pay_channel; 2 DELETE FROM pay_channel;
3 DELETE FROM pay_order; 3 DELETE FROM pay_order;
  4 +DELETE FROM pay_order_extension;
4 DELETE FROM pay_refund; 5 DELETE FROM pay_refund;
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql
@@ -39,19 +39,17 @@ CREATE TABLE IF NOT EXISTS `pay_order` ( @@ -39,19 +39,17 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
39 `subject` varchar(32) NOT NULL, 39 `subject` varchar(32) NOT NULL,
40 `body` varchar(128) NOT NULL, 40 `body` varchar(128) NOT NULL,
41 `notify_url` varchar(1024) NOT NULL, 41 `notify_url` varchar(1024) NOT NULL,
42 - `notify_status` tinyint(4) NOT NULL,  
43 - `amount` bigint(20) NOT NULL, 42 + `price` bigint(20) NOT NULL,
44 `channel_fee_rate` double DEFAULT 0, 43 `channel_fee_rate` double DEFAULT 0,
45 - `channel_fee_amount` bigint(20) DEFAULT 0, 44 + `channel_fee_price` bigint(20) DEFAULT 0,
46 `status` tinyint(4) NOT NULL, 45 `status` tinyint(4) NOT NULL,
47 `user_ip` varchar(50) NOT NULL, 46 `user_ip` varchar(50) NOT NULL,
48 - `expire_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, 47 + `expire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
49 `success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, 48 `success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
50 `notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, 49 `notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
51 - `success_extension_id` bigint(20) DEFAULT NULL COMMENT '支付成功的订单拓展单编号',  
52 - `refund_status` tinyint(4) NOT NULL,  
53 - `refund_times` tinyint(4) NOT NULL,  
54 - `refund_amount` bigint(20) NOT NULL, 50 + `extension_id` bigint(20) DEFAULT NULL,
  51 + `no` varchar(64) NULL,
  52 + `refund_price` bigint(20) NOT NULL,
55 `channel_user_id` varchar(255) DEFAULT NULL, 53 `channel_user_id` varchar(255) DEFAULT NULL,
56 `channel_order_no` varchar(64) DEFAULT NULL, 54 `channel_order_no` varchar(64) DEFAULT NULL,
57 `creator` varchar(64) DEFAULT '', 55 `creator` varchar(64) DEFAULT '',
@@ -62,6 +60,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` ( @@ -62,6 +60,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
62 PRIMARY KEY ("id") 60 PRIMARY KEY ("id")
63 ) COMMENT = '支付订单'; 61 ) COMMENT = '支付订单';
64 62
  63 +CREATE TABLE IF NOT EXISTS `pay_order_extension` (
  64 + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  65 + `no` varchar(64) NOT NULL,
  66 + `order_id` bigint(20) NOT NULL,
  67 + `channel_id` bigint(20) NOT NULL,
  68 + `channel_code` varchar(32) NOT NULL,
  69 + `user_ip` varchar(50) NULL DEFAULT NULL,
  70 + `status` tinyint(4) NOT NULL,
  71 + `channel_extras` varchar(1024) NULL DEFAULT NULL,
  72 + `channel_error_code` varchar(64) NULL,
  73 + `channel_error_msg` varchar(64) NULL,
  74 + `channel_notify_data` varchar(1024) NULL,
  75 + `creator` varchar(64) NULL DEFAULT '',
  76 + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  77 + `updater` varchar(64) NULL DEFAULT '',
  78 + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  79 + `deleted` bit(1) NOT NULL DEFAULT FALSE,
  80 + PRIMARY KEY ("id")
  81 +) COMMENT = '支付订单拓展';
  82 +
65 CREATE TABLE IF NOT EXISTS `pay_refund` ( 83 CREATE TABLE IF NOT EXISTS `pay_refund` (
66 "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, 84 "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
67 `app_id` bigint(20) NOT NULL, 85 `app_id` bigint(20) NOT NULL,
yudao-ui-admin/src/api/pay/app.js
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 -// 创建支付应用信息 3 +// 创建支付应用
4 export function createApp(data) { 4 export function createApp(data) {
5 return request({ 5 return request({
6 url: '/pay/app/create', 6 url: '/pay/app/create',
@@ -9,7 +9,7 @@ export function createApp(data) { @@ -9,7 +9,7 @@ export function createApp(data) {
9 }) 9 })
10 } 10 }
11 11
12 -// 更新支付应用信息 12 +// 更新支付应用
13 export function updateApp(data) { 13 export function updateApp(data) {
14 return request({ 14 return request({
15 url: '/pay/app/update', 15 url: '/pay/app/update',
@@ -18,7 +18,7 @@ export function updateApp(data) { @@ -18,7 +18,7 @@ export function updateApp(data) {
18 }) 18 })
19 } 19 }
20 20
21 -// 支付应用信息状态修改 21 +// 支付应用状态修改
22 export function changeAppStatus(id, status) { 22 export function changeAppStatus(id, status) {
23 const data = { 23 const data = {
24 id, 24 id,
@@ -31,7 +31,7 @@ export function changeAppStatus(id, status) { @@ -31,7 +31,7 @@ export function changeAppStatus(id, status) {
31 }) 31 })
32 } 32 }
33 33
34 -// 删除支付应用信息 34 +// 删除支付应用
35 export function deleteApp(id) { 35 export function deleteApp(id) {
36 return request({ 36 return request({
37 url: '/pay/app/delete?id=' + id, 37 url: '/pay/app/delete?id=' + id,
@@ -39,7 +39,7 @@ export function deleteApp(id) { @@ -39,7 +39,7 @@ export function deleteApp(id) {
39 }) 39 })
40 } 40 }
41 41
42 -// 获得支付应用信息 42 +// 获得支付应用
43 export function getApp(id) { 43 export function getApp(id) {
44 return request({ 44 return request({
45 url: '/pay/app/get?id=' + id, 45 url: '/pay/app/get?id=' + id,
@@ -47,7 +47,7 @@ export function getApp(id) { @@ -47,7 +47,7 @@ export function getApp(id) {
47 }) 47 })
48 } 48 }
49 49
50 -// 获得支付应用信息分页 50 +// 获得支付应用分页
51 export function getAppPage(query) { 51 export function getAppPage(query) {
52 return request({ 52 return request({
53 url: '/pay/app/page', 53 url: '/pay/app/page',
@@ -56,23 +56,10 @@ export function getAppPage(query) { @@ -56,23 +56,10 @@ export function getAppPage(query) {
56 }) 56 })
57 } 57 }
58 58
59 -// 导出支付应用信息 Excel  
60 -export function exportAppExcel(query) { 59 +// 获得支付应用列表
  60 +export function getAppList() {
61 return request({ 61 return request({
62 - url: '/pay/app/export-excel',  
63 - method: 'get',  
64 - params: query,  
65 - responseType: 'blob'  
66 - })  
67 -}  
68 -  
69 -// 根据商ID称搜索应用列表  
70 -export function getAppListByMerchantId(merchantId) {  
71 - return request({  
72 - url: '/pay/app/list-merchant-id',  
73 - params:{  
74 - merchantId:merchantId  
75 - }, 62 + url: '/pay/app/list',
76 method: 'get' 63 method: 'get'
77 }) 64 })
78 } 65 }
yudao-ui-admin/src/api/pay/notify.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得支付通知明细
  4 +export function getNotifyTaskDetail(id) {
  5 + return request({
  6 + url: '/pay/notify/get-detail?id=' + id,
  7 + method: 'get'
  8 + })
  9 +}
  10 +
  11 +// 获得支付通知分页
  12 +export function getNotifyTaskPage(query) {
  13 + return request({
  14 + url: '/pay/notify/page',
  15 + method: 'get',
  16 + params: query
  17 + })
  18 +}
yudao-ui-admin/src/utils/constants.js
@@ -207,42 +207,6 @@ export const PayOrderStatusEnum = { @@ -207,42 +207,6 @@ export const PayOrderStatusEnum = {
207 } 207 }
208 208
209 /** 209 /**
210 - * 支付订单回调状态枚举  
211 - */  
212 -export const PayOrderNotifyStatusEnum = {  
213 - NO: {  
214 - status: 0,  
215 - name: '未通知'  
216 - },  
217 - SUCCESS: {  
218 - status: 10,  
219 - name: '通知成功'  
220 - },  
221 - FAILURE: {  
222 - status: 20,  
223 - name: '通知失败'  
224 - }  
225 -}  
226 -  
227 -/**  
228 - * 支付订单退款状态枚举  
229 - */  
230 -export const PayOrderRefundStatusEnum = {  
231 - NO: {  
232 - status: 0,  
233 - name: '未退款'  
234 - },  
235 - SOME: {  
236 - status: 10,  
237 - name: '部分退款'  
238 - },  
239 - ALL: {  
240 - status: 20,  
241 - name: '全部退款'  
242 - }  
243 -}  
244 -  
245 -/**  
246 * 支付退款订单状态枚举 210 * 支付退款订单状态枚举
247 */ 211 */
248 export const PayRefundStatusEnum = { 212 export const PayRefundStatusEnum = {
yudao-ui-admin/src/utils/dict.js
@@ -51,15 +51,12 @@ export const DICT_TYPE = { @@ -51,15 +51,12 @@ export const DICT_TYPE = {
51 51
52 // ========== PAY 模块 ========== 52 // ========== PAY 模块 ==========
53 PAY_CHANNEL_WECHAT_VERSION: 'pay_channel_wechat_version', // 微信渠道版本 53 PAY_CHANNEL_WECHAT_VERSION: 'pay_channel_wechat_version', // 微信渠道版本
54 - PAY_CHANNEL_ALIPAY_SIGN_TYPE: 'pay_channel_alipay_sign_type', // 支付渠道支付宝算法类型  
55 - PAY_CHANNEL_ALIPAY_MODE: 'pay_channel_alipay_mode', // 支付宝公钥类型  
56 - PAY_CHANNEL_ALIPAY_SERVER_TYPE: 'pay_channel_alipay_server_type', // 支付宝网关地址 54 +
57 PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型 55 PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型
58 - PAY_ORDER_NOTIFY_STATUS: 'pay_order_notify_status', // 商户支付订单回调状态  
59 PAY_ORDER_STATUS: 'pay_order_status', // 商户支付订单状态 56 PAY_ORDER_STATUS: 'pay_order_status', // 商户支付订单状态
60 - PAY_ORDER_REFUND_STATUS: 'pay_order_refund_status', // 商户支付订单退款状态  
61 - PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态  
62 - PAY_REFUND_ORDER_TYPE: 'pay_refund_order_type', // 退款订单类别 57 + PAY_REFUND_STATUS: 'pay_refund_status', // 退款订单状态
  58 + PAY_NOTIFY_STATUS: 'pay_notify_status', // 商户支付回调状态
  59 + PAY_NOTIFY_TYPE: 'pay_notify_type', // 商户支付回调状态
63 60
64 // ========== MP 模块 ========== 61 // ========== MP 模块 ==========
65 MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型 62 MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
yudao-ui-admin/src/views/pay/app/components/aliPayChannelForm.vue deleted
1 -<template>  
2 - <div>  
3 - <el-dialog :visible.sync="transferParam.aliPayOpen" :title="title" @closed="close" append-to-body width="800px">  
4 - <el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"  
5 - v-loading="transferParam.loading">  
6 - <el-form-item label-width="180px" label="渠道费率" prop="feeRate">  
7 - <el-input v-model="form.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">  
8 - <template slot="append">%</template>  
9 - </el-input>  
10 - </el-form-item>  
11 - <el-form-item label-width="180px" label="开放平台APPID" prop="aliPayConfig.appId">  
12 - <el-input v-model="form.aliPayConfig.appId" placeholder="请输入开放平台APPID" clearable :style="{width: '100%'}">  
13 - </el-input>  
14 - </el-form-item>  
15 - <el-form-item label-width="180px" label="渠道状态" prop="status">  
16 - <el-radio-group v-model="form.status" size="medium">  
17 - <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">  
18 - {{ dict.label }}  
19 - </el-radio>  
20 - </el-radio-group>  
21 - </el-form-item>  
22 - <el-form-item label-width="180px" label="网关地址" prop="aliPayConfig.serverUrl">  
23 - <el-radio-group v-model="form.aliPayConfig.serverUrl" size="medium">  
24 - <el-radio v-for="dict in aliPayServerDatas" :key="dict.value" :label="dict.value">  
25 - {{ dict.label }}  
26 - </el-radio>  
27 - </el-radio-group>  
28 - </el-form-item>  
29 - <el-form-item label-width="180px" label="算法类型" prop="aliPayConfig.signType">  
30 - <el-radio-group v-model="form.aliPayConfig.signType" size="medium">  
31 - <el-radio v-for="dict in aliPaySignTypeDatas" :key="dict.value" :label="dict.value">  
32 - {{ dict.label }}  
33 - </el-radio>  
34 - </el-radio-group>  
35 - </el-form-item>  
36 - <el-form-item label-width="180px" label="公钥类型" prop="aliPayConfig.mode">  
37 - <el-radio-group v-model="form.aliPayConfig.mode" size="medium">  
38 - <el-radio v-for="dict in aliPayModeDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">  
39 - {{ dict.label }}  
40 - </el-radio>  
41 - </el-radio-group>  
42 - </el-form-item>  
43 - <div v-if="form.aliPayConfig.mode === 1">  
44 - <el-form-item label-width="180px" label="应用私钥" prop="aliPayConfig.privateKey">  
45 - <el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey"  
46 - placeholder="请输入应用私钥" clearable :style="{width: '100%'}">  
47 - </el-input>  
48 - </el-form-item>  
49 - <el-form-item label-width="180px" label="支付宝公钥" prop="aliPayConfig.alipayPublicKey">  
50 - <el-input  
51 - type="textarea"  
52 - :autosize="{minRows: 8, maxRows: 8}"  
53 - v-model="form.aliPayConfig.alipayPublicKey"  
54 - placeholder="请输入支付宝公钥" clearable  
55 - :style="{width: '100%'}">  
56 - </el-input>  
57 - </el-form-item>  
58 - </div>  
59 - <div v-if="form.aliPayConfig.mode === 2">  
60 - <el-form-item label-width="180px" label="商户公钥应用证书" prop="aliPayConfig.appCertContent">  
61 - <el-input v-model="form.aliPayConfig.appCertContent" type="textarea"  
62 - placeholder="请上传商户公钥应用证书"  
63 - readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>  
64 - </el-form-item>  
65 - <el-form-item label-width="180px" label="">  
66 - <el-upload  
67 - action=""  
68 - ref="privateKeyContentFile"  
69 - :limit="1"  
70 - :accept="fileAccept"  
71 - :http-request="appCertUpload"  
72 - :before-upload="fileBeforeUpload">  
73 - <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>  
74 - </el-upload>  
75 - </el-form-item>  
76 - <el-form-item label-width="180px" label="支付宝公钥证书" prop="aliPayConfig.alipayPublicCertContent">  
77 - <el-input v-model="form.aliPayConfig.alipayPublicCertContent" type="textarea"  
78 - placeholder="请上传支付宝公钥证书"  
79 - readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>  
80 - </el-form-item>  
81 - <el-form-item label-width="180px" label="">  
82 - <el-upload  
83 - ref="privateCertContentFile"  
84 - action=""  
85 - :limit="1"  
86 - :accept="fileAccept"  
87 - :before-upload="fileBeforeUpload"  
88 - :http-request="alipayPublicCertUpload">  
89 - <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>  
90 - </el-upload>  
91 - </el-form-item>  
92 - <el-form-item label-width="180px" label="根证书" prop="aliPayConfig.rootCertContent">  
93 - <el-input  
94 - v-model="form.aliPayConfig.rootCertContent"  
95 - type="textarea"  
96 - placeholder="请上传根证书"  
97 - readonly :autosize="{minRows: 8, maxRows: 8}"  
98 - :style="{width: '100%'}">  
99 - </el-input>  
100 - </el-form-item>  
101 - <el-form-item label-width="180px" label="">  
102 - <el-upload  
103 - ref="privateCertContentFile"  
104 - :limit="1"  
105 - :accept="fileAccept"  
106 - action=""  
107 - :before-upload="fileBeforeUpload"  
108 - :http-request="rootCertUpload">  
109 - <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>  
110 - </el-upload>  
111 - </el-form-item>  
112 - </div>  
113 - <el-form-item label-width="180px" label="备注" prop="remark">  
114 - <el-input v-model="form.remark" :style="{width: '100%'}"></el-input>  
115 - </el-form-item>  
116 - </el-form>  
117 - <div slot="footer" class="dialog-footer">  
118 - <el-button @click="close">取消</el-button>  
119 - <el-button type="primary" @click="handleConfirm">确定</el-button>  
120 - </div>  
121 - </el-dialog>  
122 - </div>  
123 -</template>  
124 -<script>  
125 -import {DICT_TYPE, getDictDatas} from "@/utils/dict";  
126 -import {createChannel, getChannel, updateChannel} from "@/api/pay/channel";  
127 -  
128 -const defaultForm = {  
129 - code: '',  
130 - status: null,  
131 - remark: '',  
132 - feeRate: null,  
133 - appId: '',  
134 - aliPayConfig: {  
135 - appId: '',  
136 - serverUrl: null,  
137 - signType: '',  
138 - mode: null,  
139 - privateKey: '',  
140 - alipayPublicKey: '',  
141 - appCertContent: '',  
142 - alipayPublicCertContent: '',  
143 - rootCertContent: ''  
144 - }  
145 -};  
146 -  
147 -export default {  
148 - name: "aliPayChannelForm",  
149 - components: {},  
150 - props: {  
151 - // 传输的参数  
152 - transferParam: {  
153 - // 加载动画  
154 - "loading": false,  
155 - // 是否修改  
156 - "edit": false,  
157 - // 是否显示  
158 - "aliPayOpen": false,  
159 - // 应用ID  
160 - "appId": null,  
161 - // 渠道编码  
162 - "payCode": null,  
163 - }  
164 - },  
165 - data() {  
166 - return {  
167 - title:'',  
168 - form: JSON.parse(JSON.stringify(defaultForm)),  
169 - rules: {  
170 - feeRate: [{  
171 - required: true,  
172 - message: '请输入渠道费率',  
173 - trigger: 'blur'  
174 - }],  
175 - 'aliPayConfig.appId': [{  
176 - required: true,  
177 - message: '请输入开放平台上创建的应用的 ID',  
178 - trigger: 'blur'  
179 - }],  
180 - status: [{  
181 - required: true,  
182 - message: '渠道状态不能为空',  
183 - trigger: 'blur'  
184 - }],  
185 - 'aliPayConfig.serverUrl': [{  
186 - required: true,  
187 - message: '请传入网关地址',  
188 - trigger: 'blur'  
189 - }],  
190 - 'aliPayConfig.signType': [{  
191 - required: true,  
192 - message: '请传入签名算法类型',  
193 - trigger: 'blur'  
194 - }],  
195 - 'aliPayConfig.mode': [{  
196 - required: true,  
197 - message: '公钥类型不能为空',  
198 - trigger: 'blur'  
199 - }],  
200 - 'aliPayConfig.privateKey': [{  
201 - required: true,  
202 - message: '请输入商户私钥',  
203 - trigger: 'blur'  
204 - }],  
205 - 'aliPayConfig.alipayPublicKey': [{  
206 - required: true,  
207 - message: '请输入支付宝公钥字符串',  
208 - trigger: 'blur'  
209 - }],  
210 - 'aliPayConfig.appCertContent': [{  
211 - required: true,  
212 - message: '请上传商户公钥应用证书',  
213 - trigger: 'blur'  
214 - }],  
215 - 'aliPayConfig.alipayPublicCertContent': [{  
216 - required: true,  
217 - message: '请上传支付宝公钥证书',  
218 - trigger: 'blur'  
219 - }],  
220 - 'aliPayConfig.rootCertContent': [{  
221 - required: true,  
222 - message: '请上传指定根证书',  
223 - trigger: 'blur'  
224 - }],  
225 - },  
226 - fileAccept: ".crt",  
227 - // 渠道状态 数据字典  
228 - statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS),  
229 - // 支付宝加密方式  
230 - aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),  
231 - // 版本状态 数据字典  
232 - aliPayModeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_MODE),  
233 - // 支付宝网关地址  
234 - aliPayServerDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SERVER_TYPE),  
235 - }  
236 - },  
237 - watch: {  
238 - transferParam: {  
239 - deep: true, // 深度监听  
240 - handler(newVal) {  
241 - if (newVal.aliPayOpen) {  
242 - this.form.code = newVal.payCode;  
243 - this.form.appId = newVal.appId;  
244 - // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据  
245 - if (newVal.edit === true && newVal.loading) {  
246 - this.title = "编辑支付渠道";  
247 - this.init();  
248 - } else {  
249 - this.title = "创建支付渠道";  
250 - }  
251 - }  
252 - }  
253 - }  
254 - },  
255 -  
256 - methods: {  
257 - init() {  
258 - getChannel(this.transferParam.appId, this.transferParam.payCode)  
259 - .then(response => {  
260 - this.form.id = response.data.id;  
261 - this.form.feeRate = response.data.feeRate;  
262 - this.form.status = response.data.status;  
263 - this.form.remark = response.data.remark;  
264 -  
265 - let config = JSON.parse(response.data.config);  
266 - this.form.aliPayConfig.appId = config.appId;  
267 - this.form.aliPayConfig.serverUrl = config.serverUrl;  
268 - this.form.aliPayConfig.signType = config.signType;  
269 - this.form.aliPayConfig.mode = config.mode;  
270 - this.form.aliPayConfig.privateKey = config.privateKey;  
271 - this.form.aliPayConfig.alipayPublicKey = config.alipayPublicKey;  
272 - this.form.aliPayConfig.appCertContent = config.appCertContent;  
273 - this.form.aliPayConfig.alipayPublicCertContent = config.alipayPublicCertContent;  
274 - this.form.aliPayConfig.rootCertContent = config.rootCertContent;  
275 - this.transferParam.loading = false;  
276 - })  
277 - },  
278 - close() {  
279 - this.transferParam.aliPayOpen = false;  
280 - this.form = JSON.parse(JSON.stringify(defaultForm));  
281 - },  
282 - handleConfirm() {  
283 - this.$refs['aliPayForm'].validate(valid => {  
284 - if (!valid) {  
285 - return  
286 - }  
287 - let data = this.form;  
288 - data.config = JSON.stringify(this.form.aliPayConfig);  
289 - if (this.transferParam.edit) {  
290 - updateChannel(data).then(response => {  
291 - if (response.code === 0) {  
292 - this.$modal.msgSuccess("修改成功");  
293 - this.close();  
294 - }  
295 -  
296 - })  
297 - } else {  
298 -  
299 - createChannel(data).then(response => {  
300 - if (response.code === 0) {  
301 - this.$modal.msgSuccess("新增成功");  
302 - this.$parent.refreshTable();  
303 - this.close();  
304 - }  
305 - });  
306 - }  
307 - });  
308 - },  
309 - fileBeforeUpload(file) {  
310 - let format = '.' + file.name.split(".")[1];  
311 - if (format !== this.fileAccept) {  
312 - this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');  
313 - return false;  
314 - }  
315 - let isRightSize = file.size / 1024 / 1024 < 2  
316 - if (!isRightSize) {  
317 - this.$message.error('文件大小超过 2MB')  
318 - }  
319 - return isRightSize  
320 - },  
321 - appCertUpload(event) {  
322 - const readFile = new FileReader()  
323 - readFile.onload = (e) => {  
324 - this.form.aliPayConfig.appCertContent = e.target.result  
325 - }  
326 - readFile.readAsText(event.file);  
327 - },  
328 - alipayPublicCertUpload(event) {  
329 - const readFile = new FileReader()  
330 - readFile.onload = (e) => {  
331 - this.form.aliPayConfig.alipayPublicCertContent = e.target.result  
332 - }  
333 - readFile.readAsText(event.file);  
334 - },  
335 - rootCertUpload(event) {  
336 - const readFile = new FileReader()  
337 - readFile.onload = (e) => {  
338 - this.form.aliPayConfig.rootCertContent = e.target.result  
339 - }  
340 - readFile.readAsText(event.file);  
341 - },  
342 -  
343 - }  
344 -}  
345 -  
346 -</script>  
347 -<style scoped>  
348 -  
349 -</style>  
yudao-ui-admin/src/views/pay/app/components/alipayChannelForm.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-dialog :visible.sync="dialogVisible" :title="title" @closed="close" append-to-body width="800px">
  4 + <el-form ref="form" :model="formData" :rules="rules" size="medium" label-width="100px" v-loading="formLoading">
  5 + <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
  6 + <el-input v-model="formData.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
  7 + <template slot="append">%</template>
  8 + </el-input>
  9 + </el-form-item>
  10 + <el-form-item label-width="180px" label="开放平台 APPID" prop="config.appId">
  11 + <el-input v-model="formData.config.appId" placeholder="请输入开放平台 APPID" clearable :style="{width: '100%'}">
  12 + </el-input>
  13 + </el-form-item>
  14 + <el-form-item label-width="180px" label="渠道状态" prop="status">
  15 + <el-radio-group v-model="formData.status" size="medium">
  16 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)"
  17 + :label="parseInt(dict.value)">
  18 + {{ dict.label }}
  19 + </el-radio>
  20 + </el-radio-group>
  21 + </el-form-item>
  22 + <el-form-item label-width="180px" label="网关地址" prop="config.serverUrl">
  23 + <el-radio-group v-model="formData.config.serverUrl" size="medium">
  24 + <el-radio label="https://openapi.alipay.com/gateway.do">线上环境</el-radio>
  25 + <el-radio label="https://openapi-sandbox.dl.alipaydev.com/gateway.do">沙箱环境</el-radio>
  26 + </el-radio-group>
  27 + </el-form-item>
  28 + <el-form-item label-width="180px" label="算法类型" prop="config.signType">
  29 + <el-radio-group v-model="formData.config.signType" size="medium">
  30 + <el-radio key="RSA2" label="RSA2">RSA2</el-radio>
  31 + </el-radio-group>
  32 + </el-form-item>
  33 + <el-form-item label-width="180px" label="公钥类型" prop="config.mode">
  34 + <el-radio-group v-model="formData.config.mode" size="medium">
  35 + <el-radio key="公钥模式" :label="1">公钥模式</el-radio>
  36 + <el-radio key="证书模式" :label="2">证书模式</el-radio>
  37 + </el-radio-group>
  38 + </el-form-item>
  39 + <div v-if="formData.config.mode === 1">
  40 + <el-form-item label-width="180px" label="应用私钥" prop="config.privateKey">
  41 + <el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="formData.config.privateKey"
  42 + placeholder="请输入应用私钥" clearable :style="{width: '100%'}">
  43 + </el-input>
  44 + </el-form-item>
  45 + <el-form-item label-width="180px" label="支付宝公钥" prop="config.alipayPublicKey">
  46 + <el-input
  47 + type="textarea"
  48 + :autosize="{minRows: 8, maxRows: 8}"
  49 + v-model="formData.config.alipayPublicKey"
  50 + placeholder="请输入支付宝公钥" clearable
  51 + :style="{width: '100%'}">
  52 + </el-input>
  53 + </el-form-item>
  54 + </div>
  55 + <div v-if="formData.config.mode === 2">
  56 + <el-form-item label-width="180px" label="商户公钥应用证书" prop="config.appCertContent">
  57 + <el-input v-model="formData.config.appCertContent" type="textarea"
  58 + placeholder="请上传商户公钥应用证书"
  59 + readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  60 + </el-form-item>
  61 + <el-form-item label-width="180px" label="">
  62 + <el-upload
  63 + action=""
  64 + ref="privateKeyContentFile"
  65 + :limit="1"
  66 + :accept="fileAccept"
  67 + :http-request="appCertUpload"
  68 + :before-upload="fileBeforeUpload">
  69 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  70 + </el-upload>
  71 + </el-form-item>
  72 + <el-form-item label-width="180px" label="支付宝公钥证书" prop="config.alipayPublicCertContent">
  73 + <el-input v-model="formData.config.alipayPublicCertContent" type="textarea"
  74 + placeholder="请上传支付宝公钥证书"
  75 + readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  76 + </el-form-item>
  77 + <el-form-item label-width="180px" label="">
  78 + <el-upload
  79 + ref="privateCertContentFile"
  80 + action=""
  81 + :limit="1"
  82 + :accept="fileAccept"
  83 + :before-upload="fileBeforeUpload"
  84 + :http-request="alipayPublicCertUpload">
  85 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  86 + </el-upload>
  87 + </el-form-item>
  88 + <el-form-item label-width="180px" label="根证书" prop="config.rootCertContent">
  89 + <el-input
  90 + v-model="formData.config.rootCertContent"
  91 + type="textarea"
  92 + placeholder="请上传根证书"
  93 + readonly :autosize="{minRows: 8, maxRows: 8}"
  94 + :style="{width: '100%'}">
  95 + </el-input>
  96 + </el-form-item>
  97 + <el-form-item label-width="180px" label="">
  98 + <el-upload
  99 + ref="privateCertContentFile"
  100 + :limit="1"
  101 + :accept="fileAccept"
  102 + action=""
  103 + :before-upload="fileBeforeUpload"
  104 + :http-request="rootCertUpload">
  105 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  106 + </el-upload>
  107 + </el-form-item>
  108 + </div>
  109 + <el-form-item label-width="180px" label="备注" prop="remark">
  110 + <el-input v-model="formData.remark" :style="{width: '100%'}"></el-input>
  111 + </el-form-item>
  112 + </el-form>
  113 + <div slot="footer" class="dialog-footer">
  114 + <el-button @click="close">取消</el-button>
  115 + <el-button type="primary" @click="submitForm">确定</el-button>
  116 + </div>
  117 + </el-dialog>
  118 + </div>
  119 +</template>
  120 +<script>
  121 +import { createChannel, getChannel, updateChannel } from "@/api/pay/channel";
  122 +import { CommonStatusEnum } from "@/utils/constants";
  123 +
  124 +export default {
  125 + name: "alipayChannelForm",
  126 + data() {
  127 + return {
  128 + dialogVisible: false,
  129 + formLoading: false,
  130 + title:'',
  131 + formData: {
  132 + appId: '',
  133 + code: '',
  134 + status: undefined,
  135 + feeRate: undefined,
  136 + remark: '',
  137 + config: {
  138 + appId: '',
  139 + serverUrl: null,
  140 + signType: '',
  141 + mode: null,
  142 + privateKey: '',
  143 + alipayPublicKey: '',
  144 + appCertContent: '',
  145 + alipayPublicCertContent: '',
  146 + rootCertContent: ''
  147 + }
  148 + },
  149 + rules: {
  150 + feeRate: [{ required: true, message: '请输入渠道费率', trigger: 'blur' }],
  151 + status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }],
  152 + 'config.appId': [{ required: true, message: '请输入开放平台上创建的应用的 ID', trigger: 'blur' }],
  153 + 'config.serverUrl': [{ required: true, message: '请传入网关地址', trigger: 'blur' }],
  154 + 'config.signType': [{ required: true, message: '请传入签名算法类型', trigger: 'blur' }],
  155 + 'config.mode': [{ required: true, message: '公钥类型不能为空', trigger: 'blur'}],
  156 + 'config.privateKey': [{ required: true, message: '请输入商户私钥', trigger: 'blur' }],
  157 + 'config.alipayPublicKey': [{ required: true, message: '请输入支付宝公钥字符串', trigger: 'blur' }],
  158 + 'config.appCertContent': [{ required: true, message: '请上传商户公钥应用证书', trigger: 'blur' }],
  159 + 'config.alipayPublicCertContent': [{ required: true, message: '请上传支付宝公钥证书', trigger: 'blur'}],
  160 + 'config.rootCertContent': [{ required: true, message: '请上传指定根证书', trigger: 'blur' }],
  161 + },
  162 + fileAccept: ".crt",
  163 + }
  164 + },
  165 + methods: {
  166 + open(appId, code) {
  167 + this.dialogVisible = true;
  168 + this.formLoading = true;
  169 + this.reset(appId, code);
  170 + getChannel(appId, code).then(response => {
  171 + if (response.data && response.data.id) {
  172 + this.formData = response.data;
  173 + this.formData.config = JSON.parse(response.data.config);
  174 + }
  175 + this.title = this.formData.id ? '创建支付渠道' : '编辑支付渠道'
  176 + }).finally(() => {
  177 + this.formLoading = false;
  178 + });
  179 + },
  180 + close() {
  181 + this.dialogVisible = false;
  182 + this.reset(undefined, undefined);
  183 + },
  184 + submitForm() {
  185 + this.$refs['form'].validate(valid => {
  186 + if (!valid) {
  187 + return
  188 + }
  189 + const data = { ...this.formData };
  190 + data.config = JSON.stringify(this.formData.config);
  191 + if (!data.id) {
  192 + createChannel(data).then(response => {
  193 + this.$modal.msgSuccess("新增成功");
  194 + this.$emit('success')
  195 + this.close();
  196 + });
  197 + } else {
  198 + updateChannel(data).then(response => {
  199 + this.$modal.msgSuccess("修改成功");
  200 + this.$emit('success')
  201 + this.close();
  202 + })
  203 + }
  204 + });
  205 + },
  206 + /** 重置表单 */
  207 + reset(appId, code) {
  208 + this.formData = {
  209 + appId: appId,
  210 + code: code,
  211 + status: CommonStatusEnum.ENABLE,
  212 + remark: '',
  213 + feeRate: null,
  214 + config: {
  215 + appId: '',
  216 + serverUrl: null,
  217 + signType: 'RSA2',
  218 + mode: null,
  219 + privateKey: '',
  220 + alipayPublicKey: '',
  221 + appCertContent: '',
  222 + alipayPublicCertContent: '',
  223 + rootCertContent: ''
  224 + }
  225 + }
  226 + this.resetForm('form')
  227 + },
  228 + fileBeforeUpload(file) {
  229 + let format = '.' + file.name.split(".")[1];
  230 + if (format !== this.fileAccept) {
  231 + this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');
  232 + return false;
  233 + }
  234 + let isRightSize = file.size / 1024 / 1024 < 2
  235 + if (!isRightSize) {
  236 + this.$message.error('文件大小超过 2MB')
  237 + }
  238 + return isRightSize
  239 + },
  240 + appCertUpload(event) {
  241 + const readFile = new FileReader()
  242 + readFile.onload = (e) => {
  243 + this.formData.config.appCertContent = e.target.result
  244 + }
  245 + readFile.readAsText(event.file);
  246 + },
  247 + alipayPublicCertUpload(event) {
  248 + const readFile = new FileReader()
  249 + readFile.onload = (e) => {
  250 + this.formData.config.alipayPublicCertContent = e.target.result
  251 + }
  252 + readFile.readAsText(event.file);
  253 + },
  254 + rootCertUpload(event) {
  255 + const readFile = new FileReader()
  256 + readFile.onload = (e) => {
  257 + this.formData.config.rootCertContent = e.target.result
  258 + }
  259 + readFile.readAsText(event.file);
  260 + },
  261 +
  262 + }
  263 +}
  264 +
  265 +</script>
  266 +<style scoped>
  267 +
  268 +</style>
yudao-ui-admin/src/views/pay/app/index.vue
@@ -213,8 +213,10 @@ @@ -213,8 +213,10 @@
213 <el-button @click="cancel">取 消</el-button> 213 <el-button @click="cancel">取 消</el-button>
214 </div> 214 </div>
215 </el-dialog> 215 </el-dialog>
216 - <wechat-channel-form :transferParam="channelParam"></wechat-channel-form>  
217 - <ali-pay-channel-form :transferParam="channelParam"></ali-pay-channel-form> 216 +
  217 + <!-- 弹窗 -->
  218 + <wechat-channel-form :transferParam="channelParam" />
  219 + <alipay-channel-form ref="alipayChannelFormRef" @success="getList" />
218 </div> 220 </div>
219 </template> 221 </template>
220 222
@@ -223,13 +225,13 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage } @@ -223,13 +225,13 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage }
223 import { DICT_TYPE, getDictDatas } from "@/utils/dict"; 225 import { DICT_TYPE, getDictDatas } from "@/utils/dict";
224 import { PayType, PayChannelEnum, CommonStatusEnum } from "@/utils/constants"; 226 import { PayType, PayChannelEnum, CommonStatusEnum } from "@/utils/constants";
225 import wechatChannelForm from "@/views/pay/app/components/wechatChannelForm"; 227 import wechatChannelForm from "@/views/pay/app/components/wechatChannelForm";
226 -import aliPayChannelForm from "@/views/pay/app/components/aliPayChannelForm"; 228 +import alipayChannelForm from "@/views/pay/app/components/alipayChannelForm";
227 229
228 export default { 230 export default {
229 name: "PayApp", 231 name: "PayApp",
230 components: { 232 components: {
231 "wechatChannelForm": wechatChannelForm, 233 "wechatChannelForm": wechatChannelForm,
232 - "aliPayChannelForm": aliPayChannelForm 234 + "alipayChannelForm": alipayChannelForm
233 }, 235 },
234 data() { 236 data() {
235 return { 237 return {
@@ -283,13 +285,6 @@ export default { @@ -283,13 +285,6 @@ export default {
283 "appId": null, 285 "appId": null,
284 // 渠道编码 286 // 渠道编码
285 "payCode": null, 287 "payCode": null,
286 - // 商户对象  
287 - "payMerchant": {  
288 - // 编号  
289 - "id": null,  
290 - // 名称  
291 - "name": null  
292 - },  
293 } 288 }
294 }; 289 };
295 }, 290 },
@@ -424,14 +419,12 @@ export default { @@ -424,14 +419,12 @@ export default {
424 this.channelParam.aliPayOpen = false; 419 this.channelParam.aliPayOpen = false;
425 } 420 }
426 if (type === PayType.ALIPAY) { 421 if (type === PayType.ALIPAY) {
427 - this.channelParam.aliPayOpen = true;  
428 - this.channelParam.wechatOpen = false; 422 + console.log(this.$refs['alipayChannelFormRef'])
  423 + this.$refs['alipayChannelFormRef'].open(row.id, payCode);
  424 + return;
  425 + // this.channelParam.aliPayOpen = true;
  426 + // this.channelParam.wechatOpen = false;
429 } 427 }
430 - this.channelParam.edit = false;  
431 - this.channelParam.loading = false;  
432 - this.channelParam.appId = row.id;  
433 - this.channelParam.payCode = payCode;  
434 - this.channelParam.payMerchant = row.payMerchant;  
435 }, 428 },
436 /** 429 /**
437 * 根据渠道编码判断渠道列表中是否存在 430 * 根据渠道编码判断渠道列表中是否存在
yudao-ui-admin/src/views/pay/notify/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
  6 + <el-form-item label="应用编号" prop="appId">
  7 + <el-select clearable v-model="queryParams.appId" filterable placeholder="请选择应用信息">
  8 + <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
  9 + </el-select>
  10 + </el-form-item>
  11 + <el-form-item label="通知类型" prop="type">
  12 + <el-select v-model="queryParams.type" placeholder="请选择通知类型" clearable size="small">
  13 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_NOTIFY_TYPE)"
  14 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item label="关联编号" prop="dataId">
  18 + <el-input v-model="queryParams.dataId" placeholder="请输入关联编号" clearable @keyup.enter.native="handleQuery"/>
  19 + </el-form-item>
  20 + <el-form-item label="通知状态" prop="status">
  21 + <el-select v-model="queryParams.status" placeholder="请选择通知状态" clearable size="small">
  22 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_NOTIFY_STATUS)"
  23 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  24 + </el-select>
  25 + </el-form-item>
  26 + <el-form-item label="商户订单编号" prop="merchantOrderId">
  27 + <el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户订单编号" clearable @keyup.enter.native="handleQuery"/>
  28 + </el-form-item>
  29 + <el-form-item label="创建时间" prop="createTime">
  30 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  31 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
  32 + </el-form-item>
  33 + <el-form-item>
  34 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  35 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  36 + </el-form-item>
  37 + </el-form>
  38 +
  39 + <!-- 列表 -->
  40 + <el-table v-loading="loading" :data="list">
  41 + <el-table-column label="任务编号" align="center" prop="id" />
  42 + <el-table-column label="应用编号" align="center" prop="appName" />
  43 + <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" />
  44 + <el-table-column label="通知类型" align="center" prop="type">
  45 + <template v-slot="scope">
  46 + <dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="scope.row.type" />
  47 + </template>
  48 + </el-table-column>
  49 + <el-table-column label="关联编号" align="center" prop="dataId" />
  50 + <el-table-column label="通知状态" align="center" prop="status">
  51 + <template v-slot="scope">
  52 + <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" />
  53 + </template>
  54 + </el-table-column>
  55 + <el-table-column label="最后通知时间" align="center" prop="lastExecuteTime" width="180">
  56 + <template v-slot="scope">
  57 + <span>{{ parseTime(scope.row.lastExecuteTime) }}</span>
  58 + </template>
  59 + </el-table-column>
  60 + <el-table-column label="下次通知时间" align="center" prop="nextNotifyTime" width="180">
  61 + <template v-slot="scope">
  62 + <span>{{ parseTime(scope.row.nextNotifyTime) }}</span>
  63 + </template>
  64 + </el-table-column>
  65 + <el-table-column label="通知次数" align="center" prop="notifyTimes">
  66 + <template v-slot="scope">
  67 + <el-tag size="mini" type="success">
  68 + {{ scope.row.notifyTimes }} / {{ scope.row.maxNotifyTimes }}
  69 + </el-tag>
  70 + </template>
  71 + </el-table-column>
  72 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  73 + <template v-slot="scope">
  74 + <el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
  75 + v-hasPermi="['pay:notify:query']">查看详情
  76 + </el-button>
  77 + </template>
  78 + </el-table-column>
  79 + </el-table>
  80 + <!-- 分页组件 -->
  81 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  82 + @pagination="getList"/>
  83 +
  84 + <!-- 对话框(详情) -->
  85 + <el-dialog title="通知详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
  86 + <el-descriptions :column="2" label-class-name="desc-label">
  87 + <el-descriptions-item label="商户订单编号">
  88 + <el-tag size="small">{{ notifyDetail.merchantOrderId }}</el-tag>
  89 + </el-descriptions-item>
  90 + <el-descriptions-item label="通知状态">
  91 + <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="notifyDetail.status" size="small" />
  92 + </el-descriptions-item>
  93 + </el-descriptions>
  94 + <el-descriptions :column="2" label-class-name="desc-label">
  95 + <el-descriptions-item label="应用编号">{{ notifyDetail.appId }}</el-descriptions-item>
  96 + <el-descriptions-item label="应用名称">{{ notifyDetail.appName }}</el-descriptions-item>
  97 + </el-descriptions>
  98 + <el-descriptions :column="2" label-class-name="desc-label">
  99 + <el-descriptions-item label="关联编号">{{ notifyDetail.dataId }}</el-descriptions-item>
  100 + <el-descriptions-item label="通知类型">
  101 + <dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="notifyDetail.type" />
  102 + </el-descriptions-item>
  103 + </el-descriptions>
  104 + <el-descriptions :column="2" label-class-name="desc-label">
  105 + <el-descriptions-item label="通知次数">{{ notifyDetail.notifyTimes }}</el-descriptions-item>
  106 + <el-descriptions-item label="最大通知次数">{{ notifyDetail.maxNotifyTimes }}</el-descriptions-item>
  107 + </el-descriptions>
  108 + <el-descriptions :column="2" label-class-name="desc-label">
  109 + <el-descriptions-item label="最后通知时间">{{ parseTime(notifyDetail.lastExecuteTime) }}</el-descriptions-item>
  110 + <el-descriptions-item label="下次通知时间">{{ parseTime(notifyDetail.nextNotifyTime) }}</el-descriptions-item>
  111 + </el-descriptions>
  112 + <el-descriptions :column="2" label-class-name="desc-label">
  113 + <el-descriptions-item label="创建时间">{{ parseTime(notifyDetail.createTime) }}</el-descriptions-item>
  114 + <el-descriptions-item label="更新时间">{{ parseTime(notifyDetail.updateTime) }}</el-descriptions-item>
  115 + </el-descriptions>
  116 + <!-- 分割线 -->
  117 + <el-divider />
  118 + <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
  119 + <el-descriptions-item label="回调日志">
  120 + <el-table :data="notifyDetail.logs">
  121 + <el-table-column label="日志编号" align="center" prop="id" />
  122 + <el-table-column label="通知状态" align="center" prop="status">
  123 + <template v-slot="scope">
  124 + <dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" />
  125 + </template>
  126 + </el-table-column>
  127 + <el-table-column label="通知次数" align="center" prop="notifyTimes" />
  128 + <el-table-column label="通知时间" align="center" prop="lastExecuteTime" width="180">
  129 + <template v-slot="scope">
  130 + <span>{{ parseTime(scope.row.createTime) }}</span>
  131 + </template>
  132 + </el-table-column>
  133 + <el-table-column label="响应结果" align="center" prop="response" />
  134 + </el-table>
  135 + </el-descriptions-item>
  136 + </el-descriptions>
  137 + </el-dialog>
  138 + </div>
  139 +</template>
  140 +
  141 +<script>
  142 +import { getNotifyTaskPage, getNotifyTaskDetail } from "@/api/pay/notify";
  143 +import { getAppList } from "@/api/pay/app";
  144 +
  145 +export default {
  146 + name: "PayNotify",
  147 + data() {
  148 + return {
  149 + // 遮罩层
  150 + loading: true,
  151 + // 导出遮罩层
  152 + exportLoading: false,
  153 + // 显示搜索条件
  154 + showSearch: true,
  155 + // 总条数
  156 + total: 0,
  157 + // 支付通知列表
  158 + list: [],
  159 + // 是否显示弹出层
  160 + open: false,
  161 + // 查询参数
  162 + queryParams: {
  163 + pageNo: 1,
  164 + pageSize: 10,
  165 + appId: null,
  166 + type: null,
  167 + dataId: null,
  168 + status: null,
  169 + merchantOrderId: null,
  170 + createTime: [],
  171 + },
  172 +
  173 + // 支付应用列表集合
  174 + appList: [],
  175 + // 通知详情
  176 + notifyDetail: {
  177 + logs: []
  178 + },
  179 + };
  180 + },
  181 + created() {
  182 + this.getList();
  183 + // 获得筛选项
  184 + getAppList().then(response => {
  185 + this.appList = response.data;
  186 + })
  187 + },
  188 + methods: {
  189 + /** 查询列表 */
  190 + getList() {
  191 + this.loading = true;
  192 + // 执行查询
  193 + getNotifyTaskPage(this.queryParams).then(response => {
  194 + this.list = response.data.list;
  195 + this.total = response.data.total;
  196 + this.loading = false;
  197 + });
  198 + },
  199 + /** 搜索按钮操作 */
  200 + handleQuery() {
  201 + this.queryParams.pageNo = 1;
  202 + this.getList();
  203 + },
  204 + /** 重置按钮操作 */
  205 + resetQuery() {
  206 + this.resetForm("queryForm");
  207 + this.handleQuery();
  208 + },
  209 + /** 详情按钮操作 */
  210 + handleDetail(row) {
  211 + this.notifyDetail = {};
  212 + getNotifyTaskDetail(row.id).then(response => {
  213 + // 设置值
  214 + this.notifyDetail = response.data;
  215 + // 弹窗打开
  216 + this.open = true;
  217 + });
  218 + },
  219 + }
  220 +};
  221 +</script>
yudao-ui-admin/src/views/pay/order/index.vue
@@ -8,35 +8,26 @@ @@ -8,35 +8,26 @@
8 <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> 8 <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
9 </el-select> 9 </el-select>
10 </el-form-item> 10 </el-form-item>
11 - <el-form-item label="渠道编码" prop="channelCode">  
12 - <el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable  
13 - @clear="()=>{queryParams.channelCode = null}">  
14 - <el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/> 11 + <el-form-item label="支付渠道" prop="channelCode">
  12 + <el-select v-model="queryParams.channelCode" placeholder="请选择支付渠道" clearable>
  13 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
15 </el-select> 14 </el-select>
16 </el-form-item> 15 </el-form-item>
17 - <el-form-item label="商户订单编号" prop="merchantOrderId">  
18 - <el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户订单编号" clearable 16 + <el-form-item label="商户单号" prop="merchantOrderId">
  17 + <el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户单号" clearable
19 @keyup.enter.native="handleQuery"/> 18 @keyup.enter.native="handleQuery"/>
20 </el-form-item> 19 </el-form-item>
21 - <el-form-item label="渠道订单号" prop="channelOrderNo">  
22 - <el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道订单号" clearable 20 + <el-form-item label="支付单号" prop="no">
  21 + <el-input v-model="queryParams.no" placeholder="请输入支付单号" clearable
  22 + @keyup.enter.native="handleQuery"/>
  23 + </el-form-item>
  24 + <el-form-item label="渠道单号" prop="channelOrderNo">
  25 + <el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道单号" clearable
23 @keyup.enter.native="handleQuery"/> 26 @keyup.enter.native="handleQuery"/>
24 </el-form-item> 27 </el-form-item>
25 <el-form-item label="支付状态" prop="status"> 28 <el-form-item label="支付状态" prop="status">
26 <el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small"> 29 <el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small">
27 - <el-option v-for="dict in payOrderDictDatum" :key="parseInt(dict.value)"  
28 - :label="dict.label" :value="parseInt(dict.value)"/>  
29 - </el-select>  
30 - </el-form-item>  
31 - <el-form-item label="退款状态" prop="refundStatus">  
32 - <el-select v-model="queryParams.refundStatus" placeholder="请选择退款状态" clearable>  
33 - <el-option v-for="dict in payOrderRefundDictDatum" :key="parseInt(dict.value)"  
34 - :label="dict.label" :value="parseInt(dict.value)"/>  
35 - </el-select>  
36 - </el-form-item>  
37 - <el-form-item label="回调商户状态" prop="notifyStatus">  
38 - <el-select v-model="queryParams.notifyStatus" placeholder="请选择订单回调商户状态" clearable>  
39 - <el-option v-for="dict in payOrderNotifyDictDatum" :key="parseInt(dict.value)" 30 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_STATUS)" :key="parseInt(dict.value)"
40 :label="dict.label" :value="parseInt(dict.value)"/> 31 :label="dict.label" :value="parseInt(dict.value)"/>
41 </el-select> 32 </el-select>
42 </el-form-item> 33 </el-form-item>
@@ -62,69 +53,64 @@ @@ -62,69 +53,64 @@
62 53
63 <!-- 列表 --> 54 <!-- 列表 -->
64 <el-table v-loading="loading" :data="list"> 55 <el-table v-loading="loading" :data="list">
65 - <el-table-column label="订单编号" align="center" prop="id" width="80"/>  
66 - <el-table-column label="支付渠道" align="center" width="130"> 56 + <el-table-column label="编号" align="center" prop="id" width="80"/>
  57 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
67 <template v-slot="scope"> 58 <template v-slot="scope">
68 - <el-popover trigger="hover" placement="top">  
69 - <p>应用名称: {{ scope.row.appName }}</p>  
70 - <p>渠道名称: {{ scope.row.channelCodeName }}</p>  
71 - <div slot="reference" class="name-wrapper">  
72 - {{ scope.row.channelCodeName }}  
73 - </div>  
74 - </el-popover> 59 + <span>{{ parseTime(scope.row.createTime) }}</span>
75 </template> 60 </template>
76 </el-table-column> 61 </el-table-column>
77 - <el-table-column label="支付订单" align="left" width="280"> 62 + <el-table-column label="支付金额" align="center" prop="price" width="100">
78 <template v-slot="scope"> 63 <template v-slot="scope">
79 - <p class="order-font"><el-tag size="mini">商户单号</el-tag> {{scope.row.merchantOrderId}}</p>  
80 - <p class="order-font"><el-tag size="mini" type="warning">支付单号</el-tag> {{scope.row.channelOrderNo}}</p> 64 + ¥{{ (scope.row.price / 100.0).toFixed(2) }}
81 </template> 65 </template>
82 </el-table-column> 66 </el-table-column>
83 - <el-table-column label="商品标题" align="center" prop="subject" width="180" :show-overflow-tooltip="true"/>  
84 - <el-table-column label="支付金额" align="center" prop="price" width="100"> 67 + <el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
85 <template v-slot="scope"> 68 <template v-slot="scope">
86 - ¥{{ parseFloat(scope.row.price / 100).toFixed(2) }} 69 + ¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}
87 </template> 70 </template>
88 </el-table-column> 71 </el-table-column>
89 <el-table-column label="手续金额" align="center" prop="channelFeePrice" width="100"> 72 <el-table-column label="手续金额" align="center" prop="channelFeePrice" width="100">
90 <template v-slot="scope"> 73 <template v-slot="scope">
91 - ¥{{ parseFloat(scope.row.channelFeePrice / 100).toFixed(2) }} 74 + ¥{{ (scope.row.channelFeePrice / 100.0).toFixed(2) }}
92 </template> 75 </template>
93 </el-table-column> 76 </el-table-column>
94 - <el-table-column label="退款金额" align="center" prop="refundPrice" width="100"> 77 + <el-table-column label="订单号" align="left" width="300">
95 <template v-slot="scope"> 78 <template v-slot="scope">
96 - ¥{{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }} 79 + <p class="order-font"><el-tag size="mini">
  80 + 商户</el-tag> {{scope.row.merchantOrderId}}
  81 + </p>
  82 + <p class="order-font" v-if="scope.row.no">
  83 + <el-tag size="mini" type="warning">支付</el-tag> {{scope.row.no}}
  84 + </p>
  85 + <p class="order-font" v-if="scope.row.channelOrderNo">
  86 + <el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
  87 + </p>
97 </template> 88 </template>
98 </el-table-column> 89 </el-table-column>
99 <el-table-column label="支付状态" align="center" prop="status"> 90 <el-table-column label="支付状态" align="center" prop="status">
100 <template v-slot="scope"> 91 <template v-slot="scope">
101 <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" /> 92 <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" />
102 </template> 93 </template>
103 -  
104 </el-table-column> 94 </el-table-column>
105 -<!-- <el-table-column label="退款状态" align="center" prop="refundStatus">-->  
106 -<!-- <template v-slot="scope">-->  
107 -<!-- <span>{{ getDictDataLabel(DICT_TYPE.PAY_ORDER_REFUND_STATUS, scope.row.refundStatus) }}</span>-->  
108 -<!-- </template>-->  
109 -<!-- </el-table-column>-->  
110 - <el-table-column label="回调状态" align="center" prop="notifyStatus" width="100"> 95 + <el-table-column label="支付渠道" align="center" width="140">
111 <template v-slot="scope"> 96 <template v-slot="scope">
112 - <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" /> 97 + <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" />
113 </template> 98 </template>
114 </el-table-column> 99 </el-table-column>
115 - <el-table-column label="创建时间" align="center" prop="createTime" width="100"> 100 + <el-table-column label="支付时间" align="center" prop="successTime" width="180">
116 <template v-slot="scope"> 101 <template v-slot="scope">
117 - <span>{{ parseTime(scope.row.createTime) }}</span> 102 + <span>{{ parseTime(scope.row.successTime) }}</span>
118 </template> 103 </template>
119 </el-table-column> 104 </el-table-column>
120 - <el-table-column label="支付时间" align="center" prop="successTime" width="100"> 105 + <el-table-column label="支付应用" align="center" prop="successTime" width="100">
121 <template v-slot="scope"> 106 <template v-slot="scope">
122 - <span>{{ parseTime(scope.row.successTime) }}</span> 107 + <span>{{ scope.row.appName }}</span>
123 </template> 108 </template>
124 </el-table-column> 109 </el-table-column>
  110 + <el-table-column label="商品标题" align="center" prop="subject" width="180" :show-overflow-tooltip="true"/>
125 <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> 111 <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
126 <template v-slot="scope"> 112 <template v-slot="scope">
127 - <el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)" 113 + <el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
128 v-hasPermi="['pay:order:query']">查看详情 114 v-hasPermi="['pay:order:query']">查看详情
129 </el-button> 115 </el-button>
130 </template> 116 </template>
@@ -134,67 +120,71 @@ @@ -134,67 +120,71 @@
134 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" 120 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
135 @pagination="getList"/> 121 @pagination="getList"/>
136 122
137 - <!-- 对话框(添加 / 修改) -->  
138 - <el-dialog title="订单详情" :visible.sync="open" width="50%">  
139 - <el-descriptions :column="2" label-class-name="desc-label">  
140 - <el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>  
141 - <el-descriptions-item label="商品名称">{{ orderDetail.subject }}</el-descriptions-item>  
142 - </el-descriptions>  
143 - <el-divider></el-divider> 123 + <!-- 对话框(详情) -->
  124 + <el-dialog title="订单详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
144 <el-descriptions :column="2" label-class-name="desc-label"> 125 <el-descriptions :column="2" label-class-name="desc-label">
145 - <el-descriptions-item label="商户订单号"> 126 + <el-descriptions-item label="商户单号">
146 <el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag> 127 <el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag>
147 </el-descriptions-item> 128 </el-descriptions-item>
148 - <el-descriptions-item label="渠道订单号">  
149 - <el-tag class="tag-purple" size="small">{{ orderDetail.channelOrderNo }}</el-tag> 129 + <el-descriptions-item label="支付单号">
  130 + <el-tag type="warning" size="small" v-if="orderDetail.no">{{ orderDetail.no }}</el-tag>
150 </el-descriptions-item> 131 </el-descriptions-item>
151 - <el-descriptions-item label="支付订单号">  
152 - <el-tag v-if="orderDetail.payOrderExtension.no !== ''" class="tag-pink" size="small">  
153 - {{ orderDetail.payOrderExtension.no }}  
154 - </el-tag> 132 + </el-descriptions>
  133 + <el-descriptions :column="2" label-class-name="desc-label">
  134 + <el-descriptions-item label="应用编号">{{ orderDetail.appId }}</el-descriptions-item>
  135 + <el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>
  136 + </el-descriptions>
  137 + <el-descriptions :column="2" label-class-name="desc-label">
  138 + <el-descriptions-item label="支付状态">
  139 + <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="orderDetail.status" size="small" />
155 </el-descriptions-item> 140 </el-descriptions-item>
156 - <el-descriptions-item label="金额">  
157 - <el-tag type="success" size="small">{{ parseFloat(orderDetail.price / 100, 2) }}</el-tag> 141 + <el-descriptions-item label="支付金额">
  142 + <el-tag type="success" size="small">¥{{ (orderDetail.price / 100.0).toFixed(2) }}</el-tag>
158 </el-descriptions-item> 143 </el-descriptions-item>
  144 + </el-descriptions>
  145 + <el-descriptions :column="2" label-class-name="desc-label">
159 <el-descriptions-item label="手续费"> 146 <el-descriptions-item label="手续费">
160 - <el-tag type="warning" size="small">{{ parseFloat(orderDetail.channelFeePrice / 100, 2) }}</el-tag>  
161 - </el-descriptions-item>  
162 - <el-descriptions-item label="手续费比例">  
163 - {{ parseFloat(orderDetail.channelFeeRate / 100, 2) }}%  
164 - </el-descriptions-item>  
165 - <el-descriptions-item label="支付状态">  
166 - <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="orderDetail.status" /> 147 + <el-tag type="warning" size="small">¥{{ (orderDetail.channelFeePrice / 100.0).toFixed(2) }}</el-tag>
167 </el-descriptions-item> 148 </el-descriptions-item>
168 - <el-descriptions-item label="回调状态">  
169 - <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="orderDetail.notifyStatus" />  
170 - </el-descriptions-item>  
171 - <el-descriptions-item label="回调地址">{{ orderDetail.notifyUrl }}</el-descriptions-item>  
172 - <el-descriptions-item label="创建时间">{{ parseTime(orderDetail.createTime) }}</el-descriptions-item> 149 + <el-descriptions-item label="手续费比例">{{ (orderDetail.channelFeeRate / 100.0).toFixed(2) }}%</el-descriptions-item>
  150 + </el-descriptions>
  151 + <el-descriptions :column="2" label-class-name="desc-label">
173 <el-descriptions-item label="支付时间">{{ parseTime(orderDetail.successTime) }}</el-descriptions-item> 152 <el-descriptions-item label="支付时间">{{ parseTime(orderDetail.successTime) }}</el-descriptions-item>
174 <el-descriptions-item label="失效时间">{{ parseTime(orderDetail.expireTime) }}</el-descriptions-item> 153 <el-descriptions-item label="失效时间">{{ parseTime(orderDetail.expireTime) }}</el-descriptions-item>
175 - <el-descriptions-item label="通知时间">{{ parseTime(orderDetail.notifyTime) }}</el-descriptions-item>  
176 </el-descriptions> 154 </el-descriptions>
177 - <el-divider></el-divider>  
178 <el-descriptions :column="2" label-class-name="desc-label"> 155 <el-descriptions :column="2" label-class-name="desc-label">
179 - <el-descriptions-item label="支付渠道">{{ orderDetail.channelCodeName }}</el-descriptions-item>  
180 - <el-descriptions-item label="支付IP">{{ orderDetail.userIp }}</el-descriptions-item>  
181 - <el-descriptions-item label="退款状态">  
182 - <dict-tag :type="DICT_TYPE.PAY_ORDER_REFUND_STATUS" :value="orderDetail.refundStatus" /> 156 + <el-descriptions-item label="创建时间">{{ parseTime(orderDetail.createTime) }}</el-descriptions-item>
  157 + <el-descriptions-item label="更新时间">{{ parseTime(orderDetail.updateTime) }}</el-descriptions-item>
  158 + </el-descriptions>
  159 + <!-- 分割线 -->
  160 + <el-divider/>
  161 + <el-descriptions :column="2" label-class-name="desc-label">
  162 + <el-descriptions-item label="商品标题">{{ orderDetail.subject }}</el-descriptions-item>
  163 + <el-descriptions-item label="商品描述">{{ orderDetail.body }}</el-descriptions-item>
  164 + </el-descriptions>
  165 + <el-descriptions :column="2" label-class-name="desc-label">
  166 + <el-descriptions-item label="支付渠道">
  167 + <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="orderDetail.channelCode" />
183 </el-descriptions-item> 168 </el-descriptions-item>
184 - <el-descriptions-item label="退款次数">{{ orderDetail.refundTimes }}</el-descriptions-item> 169 + <el-descriptions-item label="支付 IP">{{ orderDetail.userIp }}</el-descriptions-item>
  170 + </el-descriptions>
  171 + <el-descriptions :column="2" label-class-name="desc-label">
  172 + <el-descriptions-item label="渠道单号">
  173 + <el-tag size="mini" type="success" v-if="orderDetail.channelOrderNo">{{ orderDetail.channelOrderNo }}</el-tag>
  174 + </el-descriptions-item>
  175 + <el-descriptions-item label="渠道用户">{{ orderDetail.channelUserId }}</el-descriptions-item>
  176 + </el-descriptions>
  177 + <el-descriptions :column="2" label-class-name="desc-label">
185 <el-descriptions-item label="退款金额"> 178 <el-descriptions-item label="退款金额">
186 - <el-tag type="warning">  
187 - {{ parseFloat(orderDetail.refundPrice / 100, 2) }}  
188 - </el-tag> 179 + <el-tag size="mini" type="danger">¥{{ (orderDetail.refundPrice / 100.0).toFixed(2) }}</el-tag>
189 </el-descriptions-item> 180 </el-descriptions-item>
  181 + <el-descriptions-item label="通知 URL">{{ orderDetail.notifyUrl }}</el-descriptions-item>
190 </el-descriptions> 182 </el-descriptions>
191 - <el-divider></el-divider> 183 + <!-- 分割线 -->
  184 + <el-divider />
192 <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> 185 <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
193 - <el-descriptions-item label="商品描述">  
194 - {{ orderDetail.body }}  
195 - </el-descriptions-item>  
196 <el-descriptions-item label="支付通道异步回调内容"> 186 <el-descriptions-item label="支付通道异步回调内容">
197 - {{ orderDetail.payOrderExtension.channelNotifyData }} 187 + {{ orderDetail.extension.channelNotifyData }}
198 </el-descriptions-item> 188 </el-descriptions-item>
199 </el-descriptions> 189 </el-descriptions>
200 </el-dialog> 190 </el-dialog>
@@ -203,35 +193,7 @@ @@ -203,35 +193,7 @@
203 193
204 <script> 194 <script>
205 import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order"; 195 import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order";
206 -import { DICT_TYPE, getDictDatas } from "@/utils/dict";  
207 -import { getNowDateTime} from "@/utils/ruoyi";  
208 -  
209 -const defaultOrderDetail = {  
210 - appName: '',  
211 - channelCodeName: '',  
212 - subject: '',  
213 - merchantOrderId: null,  
214 - channelOrderNo: '',  
215 - body: '',  
216 - price: null,  
217 - channelFeeRate: null,  
218 - channelFeePrice: null,  
219 - userIp: '',  
220 - status: null,  
221 - notifyUrl: '',  
222 - notifyStatus: null,  
223 - refundStatus: null,  
224 - refundTimes: '',  
225 - refundPrice: null,  
226 - createTime: '',  
227 - successTime: '',  
228 - notifyTime: '',  
229 - expireTime: '',  
230 - payOrderExtension: {  
231 - channelNotifyData: '',  
232 - no: ''  
233 - }  
234 -}; 196 +import { getAppList } from "@/api/pay/app";
235 197
236 export default { 198 export default {
237 name: "PayOrder", 199 name: "PayOrder",
@@ -250,75 +212,37 @@ export default { @@ -250,75 +212,37 @@ export default {
250 title: "", 212 title: "",
251 // 是否显示弹出层 213 // 是否显示弹出层
252 open: false, 214 open: false,
253 - // 查询参数 TODO 芋艿:多余字段的清理 215 + // 查询参数
254 queryParams: { 216 queryParams: {
255 pageNo: 1, 217 pageNo: 1,
256 pageSize: 10, 218 pageSize: 10,
257 appId: null, 219 appId: null,
258 - channelId: null,  
259 channelCode: null, 220 channelCode: null,
260 merchantOrderId: null, 221 merchantOrderId: null,
261 - subject: null,  
262 - body: null,  
263 - notifyUrl: null,  
264 - notifyStatus: null,  
265 - price: null,  
266 - channelFeeRate: null,  
267 - channelFeePrice: null,  
268 - status: null,  
269 - userIp: null,  
270 - successExtensionId: null,  
271 - refundStatus: null,  
272 - refundTimes: null,  
273 - refundPrice: null,  
274 - channelUserId: null,  
275 channelOrderNo: null, 222 channelOrderNo: null,
276 - expireTime: [],  
277 - successTime: [],  
278 - notifyTime: [],  
279 - createTime: [] 223 + no: null,
  224 + status: null,
  225 + createTime: [],
280 }, 226 },
281 - // 商户加载遮罩层  
282 - merchantLoading: false,  
283 - // 商户列表集合  
284 - merchantList: null, 227 +
285 // 支付应用列表集合 228 // 支付应用列表集合
286 - appList: null,  
287 - // 支付渠道编码字典数据集合  
288 - payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),  
289 - // 订单回调商户状态字典数据集合  
290 - payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),  
291 - // 订单状态字典数据集合  
292 - payOrderDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_STATUS),  
293 - // 订单退款状态字典数据集合  
294 - payOrderRefundDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS),  
295 - orderDetail: JSON.parse(JSON.stringify(defaultOrderDetail)), 229 + appList: [],
  230 + // 订单详情
  231 + orderDetail: {
  232 + extension: {}
  233 + },
296 }; 234 };
297 }, 235 },
298 created() { 236 created() {
299 - // 初始化默认时间  
300 - this.initTime();  
301 this.getList(); 237 this.getList();
302 - this.handleGetMerchantListByName(null); 238 + // 获得筛选项
  239 + getAppList().then(response => {
  240 + this.appList = response.data;
  241 + })
303 }, 242 },
304 methods: { 243 methods: {
305 - initTime(){  
306 - this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];  
307 - },  
308 /** 查询列表 */ 244 /** 查询列表 */
309 getList() { 245 getList() {
310 - // 判断选择的日期是否超过了一个月  
311 - let oneMonthTime = 31 * 24 * 3600 * 1000;  
312 - if (this.queryParams.createTime == null){  
313 - this.initTime();  
314 - } else {  
315 - let minDateTime = new Date(this.queryParams.createTime[0]).getTime();  
316 - let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()  
317 - if (maxDateTime - minDateTime > oneMonthTime) {  
318 - this.$message.error('时间范围最大为 31 天!');  
319 - return false;  
320 - }  
321 - }  
322 this.loading = true; 246 this.loading = true;
323 // 执行查询 247 // 执行查询
324 getOrderPage(this.queryParams).then(response => { 248 getOrderPage(this.queryParams).then(response => {
@@ -339,22 +263,20 @@ export default { @@ -339,22 +263,20 @@ export default {
339 /** 重置按钮操作 */ 263 /** 重置按钮操作 */
340 resetQuery() { 264 resetQuery() {
341 this.resetForm("queryForm"); 265 this.resetForm("queryForm");
342 - this.initTime();  
343 this.handleQuery(); 266 this.handleQuery();
344 }, 267 },
345 - /**  
346 - * 查看订单详情  
347 - */  
348 - handleQueryDetails(row) {  
349 - this.orderDetail = JSON.parse(JSON.stringify(defaultOrderDetail)); 268 + /** 详情按钮操作 */
  269 + handleDetail(row) {
  270 + this.orderDetail = {};
350 getOrderDetail(row.id).then(response => { 271 getOrderDetail(row.id).then(response => {
  272 + // 设置值
351 this.orderDetail = response.data; 273 this.orderDetail = response.data;
352 - if (response.data.payOrderExtension === null) {  
353 - this.orderDetail.payOrderExtension = Object.assign(defaultOrderDetail.payOrderExtension, {}); 274 + if (!this.orderDetail.extension) {
  275 + this.orderDetail.extension = {}
354 } 276 }
  277 + // 弹窗打开
355 this.open = true; 278 this.open = true;
356 }); 279 });
357 -  
358 }, 280 },
359 /** 导出按钮操作 */ 281 /** 导出按钮操作 */
360 handleExport() { 282 handleExport() {
yudao-ui-admin/src/views/pay/refund/index.vue
@@ -7,31 +7,30 @@ @@ -7,31 +7,30 @@
7 <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> 7 <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
8 </el-select> 8 </el-select>
9 </el-form-item> 9 </el-form-item>
10 - <el-form-item label="渠道编码" prop="channelCode">  
11 - <el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable  
12 - @clear="()=>{queryParams.channelCode = null}">  
13 - <el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/> 10 + <el-form-item label="退款渠道" prop="channelCode">
  11 + <el-select v-model="queryParams.channelCode" placeholder="请选择退款渠道" clearable>
  12 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
14 </el-select> 13 </el-select>
15 </el-form-item> 14 </el-form-item>
16 - <el-form-item label="退款类型" prop="type">  
17 - <el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable>  
18 - <el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"  
19 - :label="dict.label" :value="parseInt(dict.value)"/>  
20 - </el-select> 15 + <el-form-item label="商户支付单号" prop="merchantOrderId">
  16 + <el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户支付单号" clearable
  17 + @keyup.enter.native="handleQuery"/>
  18 + </el-form-item>
  19 + <el-form-item label="商户退款单号" prop="merchantRefundId">
  20 + <el-input v-model="queryParams.merchantRefundId" placeholder="请输入商户退款单号" clearable
  21 + @keyup.enter.native="handleQuery"/>
  22 + </el-form-item>
  23 + <el-form-item label="渠道支付单号" prop="channelOrderNo">
  24 + <el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道支付单号" clearable
  25 + @keyup.enter.native="handleQuery"/>
21 </el-form-item> 26 </el-form-item>
22 - <el-form-item label="商户退款订单号" prop="merchantRefundNo">  
23 - <el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable 27 + <el-form-item label="渠道退款单号" prop="channelRefundNo">
  28 + <el-input v-model="queryParams.channelRefundNo" placeholder="请输入渠道退款单号" clearable
24 @keyup.enter.native="handleQuery"/> 29 @keyup.enter.native="handleQuery"/>
25 </el-form-item> 30 </el-form-item>
26 <el-form-item label="退款状态" prop="status"> 31 <el-form-item label="退款状态" prop="status">
27 <el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable> 32 <el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable>
28 - <el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"  
29 - :label="dict.label" :value="parseInt(dict.value)"/>  
30 - </el-select>  
31 - </el-form-item>  
32 - <el-form-item label="退款回调状态" prop="notifyStatus">  
33 - <el-select v-model="queryParams.notifyStatus" placeholder="请选择通知商户退款结果的回调状态" clearable>  
34 - <el-option v-for="dict in payOrderNotifyDictDatum" :key="parseInt(dict.value)" 33 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_REFUND_STATUS)" :key="parseInt(dict.value)"
35 :label="dict.label" :value="parseInt(dict.value)"/> 34 :label="dict.label" :value="parseInt(dict.value)"/>
36 </el-select> 35 </el-select>
37 </el-form-item> 36 </el-form-item>
@@ -58,77 +57,62 @@ @@ -58,77 +57,62 @@
58 <!-- 列表 --> 57 <!-- 列表 -->
59 <el-table v-loading="loading" :data="list"> 58 <el-table v-loading="loading" :data="list">
60 <el-table-column label="编号" align="center" prop="id"/> 59 <el-table-column label="编号" align="center" prop="id"/>
61 - <el-table-column label="支付渠道" align="center" width="130"> 60 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
62 <template v-slot="scope"> 61 <template v-slot="scope">
63 - <el-popover trigger="hover" placement="top">  
64 - <p>应用名称: {{ scope.row.appName }}</p>  
65 - <p>渠道名称: {{ scope.row.channelCodeName }}</p>  
66 - <div slot="reference" class="name-wrapper">  
67 - {{ scope.row.channelCodeName }}  
68 - </div>  
69 - </el-popover> 62 + <span>{{ parseTime(scope.row.createTime) }}</span>
  63 + </template>
  64 + </el-table-column>
  65 + <el-table-column label="支付金额" align="center" prop="payPrice" width="100">
  66 + <template v-slot="scope" class="">
  67 + ¥{{ (scope.row.payPrice / 100.0).toFixed(2) }}
70 </template> 68 </template>
71 </el-table-column> 69 </el-table-column>
72 - <!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->  
73 - <!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->  
74 - <el-table-column label="商户订单号" align="left" width="230"> 70 + <el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
  71 + <template v-slot="scope">
  72 + ¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}
  73 + </template>
  74 + </el-table-column>
  75 + <el-table-column label="退款订单号" align="left" width="300">
75 <template v-slot="scope"> 76 <template v-slot="scope">
76 <p class="order-font"> 77 <p class="order-font">
77 - <el-tag size="mini">退款</el-tag>  
78 - {{ scope.row.merchantRefundNo }} 78 + <el-tag size="mini">商户</el-tag> {{scope.row.merchantRefundId}}
79 </p> 79 </p>
80 <p class="order-font"> 80 <p class="order-font">
81 - <el-tag type="success">交易</el-tag>  
82 - {{ scope.row.merchantOrderId }} 81 + <el-tag size="mini" type="warning">退款</el-tag> {{scope.row.no}}
  82 + </p>
  83 + <p class="order-font" v-if="scope.row.channelRefundNo">
  84 + <el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelRefundNo}}
83 </p> 85 </p>
84 </template> 86 </template>
85 </el-table-column> 87 </el-table-column>
86 - <el-table-column label="支付订单号" align="center" prop="merchantRefundNo" width="250"> 88 + <el-table-column label="支付订单号" align="left" width="300">
87 <template v-slot="scope"> 89 <template v-slot="scope">
88 <p class="order-font"> 90 <p class="order-font">
89 - <el-tag size="mini">交易</el-tag>  
90 - {{ scope.row.tradeNo }} 91 + <el-tag size="mini">商户</el-tag> {{scope.row.merchantOrderId}}
91 </p> 92 </p>
92 <p class="order-font"> 93 <p class="order-font">
93 - <el-tag size="mini" type="warning">渠道</el-tag>  
94 - {{ scope.row.channelOrderNo }} 94 + <el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
95 </p> 95 </p>
96 </template> 96 </template>
97 </el-table-column> 97 </el-table-column>
98 - <el-table-column label="支付金额(元)" align="center" prop="payPrice" width="100">  
99 - <template v-slot="scope" class="">  
100 - ¥{{ parseFloat(scope.row.payPrice / 100).toFixed(2) }}  
101 - </template>  
102 - </el-table-column>  
103 - <el-table-column label="退款金额(元)" align="center" prop="refundPrice" width="100">  
104 - <template v-slot="scope">  
105 - ¥{{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }}  
106 - </template>  
107 - </el-table-column>  
108 - <el-table-column label="退款类型" align="center" prop="type" width="80">  
109 - <template v-slot="scope">  
110 - <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="scope.row.type" />  
111 - </template>  
112 - </el-table-column>  
113 <el-table-column label="退款状态" align="center" prop="status"> 98 <el-table-column label="退款状态" align="center" prop="status">
114 <template v-slot="scope"> 99 <template v-slot="scope">
115 - <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="scope.row.status" /> 100 + <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
116 </template> 101 </template>
117 </el-table-column> 102 </el-table-column>
118 - <el-table-column label="回调状态" align="center" prop="notifyStatus"> 103 + <el-table-column label="退款渠道" align="center" width="140">
119 <template v-slot="scope"> 104 <template v-slot="scope">
120 - <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" /> 105 + <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" />
121 </template> 106 </template>
122 </el-table-column> 107 </el-table-column>
123 - <el-table-column label="退款原因" align="center" prop="reason" width="140" :show-overflow-tooltip="true"/>  
124 - <el-table-column label="创建时间" align="center" prop="createTime" width="100"> 108 + <el-table-column label="成功时间" align="center" prop="successTime" width="180">
125 <template v-slot="scope"> 109 <template v-slot="scope">
126 - <span>{{ parseTime(scope.row.createTime) }}</span> 110 + <span>{{ parseTime(scope.row.successTime) }}</span>
127 </template> 111 </template>
128 </el-table-column> 112 </el-table-column>
129 - <el-table-column label="退款成功时间" align="center" prop="successTime" width="100"> 113 + <el-table-column label="支付应用" align="center" prop="successTime" width="100">
130 <template v-slot="scope"> 114 <template v-slot="scope">
131 - <span>{{ parseTime(scope.row.successTime) }}</span> 115 + <span>{{ scope.row.appName }}</span>
132 </template> 116 </template>
133 </el-table-column> 117 </el-table-column>
134 <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> 118 <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
@@ -143,107 +127,76 @@ @@ -143,107 +127,76 @@
143 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" 127 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
144 @pagination="getList"/> 128 @pagination="getList"/>
145 129
146 - <!-- 对话框(添加 / 修改) -->  
147 - <el-dialog title="退款订单详情" :visible.sync="open" width="700px" append-to-body> 130 + <!-- 对话框(详情) -->
  131 + <el-dialog title="退款订单详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
148 <el-descriptions :column="2" label-class-name="desc-label"> 132 <el-descriptions :column="2" label-class-name="desc-label">
149 - <el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>  
150 - <el-descriptions-item label="商品名称">{{ refundDetail.subject }}</el-descriptions-item> 133 + <el-descriptions-item label="商户退款单号">
  134 + <el-tag size="small">{{ refundDetail.merchantRefundId }}</el-tag>
  135 + </el-descriptions-item>
  136 + <el-descriptions-item label="渠道退款单号">
  137 + <el-tag type="success" size="small" v-if="refundDetail.channelRefundNo">{{ refundDetail.channelRefundNo }}</el-tag>
  138 + </el-descriptions-item>
151 </el-descriptions> 139 </el-descriptions>
152 - <el-divider></el-divider>  
153 <el-descriptions :column="2" label-class-name="desc-label"> 140 <el-descriptions :column="2" label-class-name="desc-label">
154 - <el-descriptions-item label="商户退款单号">  
155 - <el-tag size="mini">{{ refundDetail.merchantRefundNo }}</el-tag> 141 + <el-descriptions-item label="商户支付单号">
  142 + <el-tag size="small">{{ refundDetail.merchantOrderId }}</el-tag>
156 </el-descriptions-item> 143 </el-descriptions-item>
157 - <el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>  
158 - <el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item> 144 + <el-descriptions-item label="渠道支付单号">
  145 + <el-tag type="success" size="small">{{ refundDetail.channelOrderNo }}</el-tag>
  146 + </el-descriptions-item>
  147 + </el-descriptions>
  148 + <el-descriptions :column="2" label-class-name="desc-label">
  149 + <el-descriptions-item label="应用编号">{{ refundDetail.appId }}</el-descriptions-item>
  150 + <el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>
159 </el-descriptions> 151 </el-descriptions>
160 - <el-divider></el-divider>  
161 <el-descriptions :column="2" label-class-name="desc-label"> 152 <el-descriptions :column="2" label-class-name="desc-label">
162 <el-descriptions-item label="支付金额"> 153 <el-descriptions-item label="支付金额">
163 - {{ parseFloat(refundDetail.payPrice / 100).toFixed(2) }} 154 + <el-tag type="success" size="small">¥{{ (refundDetail.payPrice / 100.0).toFixed(2) }}</el-tag>
164 </el-descriptions-item> 155 </el-descriptions-item>
165 - <el-descriptions-item label="退款金额" size="mini">  
166 - <el-tag class="tag-purple" size="mini">{{ parseFloat(refundDetail.refundPrice / 100).toFixed(2) }}</el-tag>  
167 - </el-descriptions-item>  
168 - <el-descriptions-item label="退款类型">  
169 - <template v-slot="scope">  
170 - <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="refundDetail.type" />  
171 - </template> 156 + <el-descriptions-item label="退款金额">
  157 + <el-tag size="mini" type="danger">¥{{ (refundDetail.refundPrice / 100.0).toFixed(2) }}</el-tag>
172 </el-descriptions-item> 158 </el-descriptions-item>
  159 + </el-descriptions>
  160 + <el-descriptions :column="2" label-class-name="desc-label">
173 <el-descriptions-item label="退款状态"> 161 <el-descriptions-item label="退款状态">
174 - <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="refundDetail.status" /> 162 + <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="refundDetail.status" />
175 </el-descriptions-item> 163 </el-descriptions-item>
  164 + <el-descriptions-item label="退款时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
  165 + </el-descriptions>
  166 + <el-descriptions :column="2" label-class-name="desc-label">
176 <el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item> 167 <el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item>
177 - <el-descriptions-item label="退款成功时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>  
178 - <el-descriptions-item label="退款失效时间">{{ parseTime(refundDetail.expireTime) }}</el-descriptions-item>  
179 <el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item> 168 <el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item>
180 </el-descriptions> 169 </el-descriptions>
181 - <el-divider></el-divider> 170 + <!-- 分割线 -->
  171 + <el-divider />
182 <el-descriptions :column="2" label-class-name="desc-label"> 172 <el-descriptions :column="2" label-class-name="desc-label">
183 - <el-descriptions-item label="支付渠道">  
184 - {{ refundDetail.channelCodeName }}  
185 - </el-descriptions-item>  
186 - <el-descriptions-item label="支付IP" size="mini">  
187 - {{refundDetail.userIp}}  
188 - </el-descriptions-item>  
189 - <el-descriptions-item label="回调地址">{{ refundDetail.notifyUrl }}</el-descriptions-item>  
190 - <el-descriptions-item label="回调状态">  
191 - <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="refundDetail.notifyStatus" /> 173 + <el-descriptions-item label="退款渠道">
  174 + <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="refundDetail.channelCode" />
192 </el-descriptions-item> 175 </el-descriptions-item>
193 - <el-descriptions-item label="回调时间">{{ parseTime(refundDetail.notifyTime) }}</el-descriptions-item> 176 + <el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item>
  177 + </el-descriptions>
  178 + <el-descriptions :column="2" label-class-name="desc-label">
  179 + <el-descriptions-item label="退款 IP">{{ refundDetail.userIp }}</el-descriptions-item>
  180 + <el-descriptions-item label="通知 URL">{{ refundDetail.notifyUrl }}</el-descriptions-item>
194 </el-descriptions> 181 </el-descriptions>
195 - <el-divider></el-divider> 182 + <!-- 分割线 -->
  183 + <el-divider />
196 <el-descriptions :column="2" label-class-name="desc-label"> 184 <el-descriptions :column="2" label-class-name="desc-label">
197 - <el-descriptions-item label="渠道订单号">{{ refundDetail.channelOrderNo }}</el-descriptions-item>  
198 - <el-descriptions-item label="渠道退款单号">{{ refundDetail.channelRefundNo }}</el-descriptions-item>  
199 <el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item> 185 <el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item>
200 <el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item> 186 <el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item>
201 </el-descriptions> 187 </el-descriptions>
202 - <br>  
203 <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> 188 <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
204 - <el-descriptions-item label="渠道额外参数">{{ refundDetail.channelExtras }}</el-descriptions-item>  
205 - <el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item> 189 + <el-descriptions-item label="支付通道异步回调内容">
  190 + {{ refundDetail.channelNotifyData }}
  191 + </el-descriptions-item>
206 </el-descriptions> 192 </el-descriptions>
207 </el-dialog> 193 </el-dialog>
208 </div> 194 </div>
209 </template> 195 </template>
210 196
211 <script> 197 <script>
212 -import {getRefundPage, exportRefundExcel, getRefund} from "@/api/pay/refund";  
213 -import { DICT_TYPE, getDictDatas } from "@/utils/dict";  
214 -import { PayOrderRefundStatusEnum, PayRefundStatusEnum } from "@/utils/constants";  
215 -import { getNowDateTime } from "@/utils/ruoyi";  
216 -  
217 -const defaultRefundDetail = {  
218 - id: null,  
219 - appId: null,  
220 - appName: '',  
221 - channelCode: '',  
222 - channelCodeName: '',  
223 - channelErrorCode: '',  
224 - channelErrorMsg: '',  
225 - channelExtras: '',  
226 - channelId: null,  
227 - channelOrderNo: '',  
228 - channelRefundNo: '',  
229 - createTime: null,  
230 - expireTime: null,  
231 - merchantOrderId: '',  
232 - merchantRefundNo: '',  
233 - notifyStatus: null,  
234 - notifyTime: null,  
235 - notifyUrl: '',  
236 - orderId: null,  
237 - payPrice: null,  
238 - reason: '',  
239 - refundPrice: null,  
240 - status: null,  
241 - subject: '',  
242 - successTime: null,  
243 - tradeNo: '',  
244 - type: null,  
245 - userIp: ''  
246 -} 198 +import { getRefundPage, exportRefundExcel, getRefund } from "@/api/pay/refund";
  199 +import { getAppList } from "@/api/pay/app";
247 200
248 export default { 201 export default {
249 name: "PayRefund", 202 name: "PayRefund",
@@ -267,73 +220,30 @@ export default { @@ -267,73 +220,30 @@ export default {
267 pageNo: 1, 220 pageNo: 1,
268 pageSize: 10, 221 pageSize: 10,
269 appId: null, 222 appId: null,
270 - channelId: null,  
271 channelCode: null, 223 channelCode: null,
272 - orderId: null,  
273 - tradeNo: null,  
274 merchantOrderId: null, 224 merchantOrderId: null,
275 - merchantRefundNo: null,  
276 - notifyUrl: null,  
277 - notifyStatus: null,  
278 - status: null,  
279 - type: null,  
280 - payPrice: null,  
281 - refundPrice: null,  
282 - reason: null,  
283 - userIp: null, 225 + merchantRefundId: null,
284 channelOrderNo: null, 226 channelOrderNo: null,
285 channelRefundNo: null, 227 channelRefundNo: null,
286 - channelErrorCode: null,  
287 - channelErrorMsg: null,  
288 - channelExtras: null,  
289 - expireTime: [],  
290 - successTime: [],  
291 - notifyTime: [], 228 + status: null,
292 createTime: [] 229 createTime: []
293 }, 230 },
294 - // 商户加载遮罩层  
295 - merchantLoading: false,  
296 - // 商户列表集合  
297 - merchantList: null,  
298 // 支付应用列表集合 231 // 支付应用列表集合
299 - appList: null,  
300 - // 支付渠道编码字典数据集合  
301 - payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),  
302 - // 订单退款状态字典数据集合  
303 - payRefundOrderDictDatum: getDictDatas(DICT_TYPE.PAY_REFUND_ORDER_STATUS),  
304 - // 退款订单类别字典数据集合  
305 - payRefundOrderTypeDictDatum: getDictDatas(DICT_TYPE.PAY_REFUND_ORDER_TYPE),  
306 - // 订单回调商户状态字典数据集合  
307 - payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),  
308 - // el-tag订单退款状态type值  
309 - refundStatusType: '', 232 + appList: [],
310 // 退款订单详情 233 // 退款订单详情
311 - refundDetail: JSON.parse(JSON.stringify(defaultRefundDetail)), 234 + refundDetail: {},
312 }; 235 };
313 }, 236 },
314 created() { 237 created() {
315 - this.initTime();  
316 this.getList(); 238 this.getList();
317 - this.handleGetMerchantListByName(null); 239 + // 获得筛选项
  240 + getAppList().then(response => {
  241 + this.appList = response.data;
  242 + })
318 }, 243 },
319 methods: { 244 methods: {
320 - initTime(){  
321 - this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];  
322 - },  
323 /** 查询列表 */ 245 /** 查询列表 */
324 getList() { 246 getList() {
325 - // 判断选择的日期是否超过了一个月  
326 - let oneMonthTime = 31 * 24 * 3600 * 1000;  
327 - if (this.queryParams.createTime == null){  
328 - this.initTime();  
329 - } else {  
330 - let minDateTime = new Date(this.queryParams.createTime[0]).getTime();  
331 - let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()  
332 - if (maxDateTime - minDateTime > oneMonthTime) {  
333 - this.$message.error('时间范围最大为 31 天!');  
334 - return false;  
335 - }  
336 - }  
337 this.loading = true; 247 this.loading = true;
338 // 执行查询 248 // 执行查询
339 getRefundPage(this.queryParams).then(response => { 249 getRefundPage(this.queryParams).then(response => {
@@ -369,60 +279,13 @@ export default { @@ -369,60 +279,13 @@ export default {
369 this.$download.excel(response, '退款订单.xls'); 279 this.$download.excel(response, '退款订单.xls');
370 }).catch(() => {}); 280 }).catch(() => {});
371 }, 281 },
372 - /**  
373 - * 根据商户名称模糊匹配商户信息  
374 - * @param name 商户名称  
375 - */  
376 - handleGetMerchantListByName(name) {  
377 - getMerchantListByName(name).then(response => {  
378 - this.merchantList = response.data;  
379 - this.merchantLoading = false;  
380 - });  
381 - },  
382 - /**  
383 - * 根据退款类别得到样式名称  
384 - * @param refundType 退款类别  
385 - */  
386 - findByRefundTypeGetStyle(refundType) {  
387 - switch (refundType) {  
388 - case PayOrderRefundStatusEnum.NO.status:  
389 - return "success";  
390 - case PayOrderRefundStatusEnum.SOME.status:  
391 - return "warning";  
392 - case PayOrderRefundStatusEnum.ALL.status:  
393 - return "danger";  
394 - }  
395 - },  
396 - /**  
397 - * 根据退款状态得到样式名称  
398 - * @param refundStatus 退款状态  
399 - */  
400 - findByRefundStatusGetStyle(refundStatus) {  
401 - switch (refundStatus) {  
402 - case PayRefundStatusEnum.CREATE.status:  
403 - return "info";  
404 - case PayRefundStatusEnum.SUCCESS.status:  
405 - return "success";  
406 - case PayRefundStatusEnum.FAILURE.status:  
407 - case PayRefundStatusEnum.CLOSE.status:  
408 - return "danger";  
409 - case PayRefundStatusEnum.PROCESSING_NOTIFY.status:  
410 - case PayRefundStatusEnum.PROCESSING_QUERY.status:  
411 - case PayRefundStatusEnum.UNKNOWN_RETRY.status:  
412 - case PayRefundStatusEnum.UNKNOWN_QUERY.status:  
413 - return "warning";  
414 - }  
415 - },  
416 - /**  
417 - * 查看订单详情  
418 - */ 282 + /** 详情按钮操作 */
419 handleQueryDetails(row) { 283 handleQueryDetails(row) {
420 - this.refundDetail = JSON.parse(JSON.stringify(defaultRefundDetail)); 284 + this.refundDetail = {};
421 getRefund(row.id).then(response => { 285 getRefund(row.id).then(response => {
422 this.refundDetail = response.data; 286 this.refundDetail = response.data;
423 this.open = true; 287 this.open = true;
424 }); 288 });
425 -  
426 }, 289 },
427 } 290 }
428 }; 291 };