Commit a73e078593b05c205c3c068ab0b66e87b8d8e73c
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
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 | 79 | /** |
| 80 | 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 | 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 | 4 | import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; |
| 4 | 5 | import lombok.Data; |
| 5 | 6 | |
| ... | ... | @@ -44,4 +45,71 @@ public class PayRefundRespDTO { |
| 44 | 45 | */ |
| 45 | 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 | 98 | try { |
| 99 | 99 | return doParseOrderNotify(params, body); |
| 100 | 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 | 103 | throw buildPayException(ex); |
| 103 | 104 | } |
| 104 | 105 | } |
| ... | ... | @@ -129,6 +130,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 129 | 130 | |
| 130 | 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 | 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 | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | 4 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | 5 | import cn.hutool.core.lang.Assert; |
| 6 | +import cn.hutool.core.map.MapUtil; | |
| 6 | 7 | import cn.hutool.core.util.StrUtil; |
| 7 | 8 | import cn.hutool.http.HttpUtil; |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | |
| 8 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 9 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 10 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| ... | ... | @@ -29,7 +31,6 @@ import java.util.Objects; |
| 29 | 31 | import java.util.function.Supplier; |
| 30 | 32 | |
| 31 | 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<AlipayPa |
| 74 | 75 | StandardCharsets.UTF_8.name(), config.getSignType()); |
| 75 | 76 | |
| 76 | 77 | // 2. 解析订单的状态 |
| 78 | + // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂 | |
| 77 | 79 | String tradeStatus = bodyObj.get("trade_status"); |
| 78 | 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 | 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 | 87 | Assert.notNull(status, (Supplier<Throwable>) () -> { |
| 82 | 88 | throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); |
| 83 | 89 | }); |
| ... | ... | @@ -94,7 +100,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 94 | 100 | * @return 退款请求 Response |
| 95 | 101 | */ |
| 96 | 102 | @Override |
| 97 | - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 103 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 98 | 104 | // 1.1 构建 AlipayTradeRefundModel 请求 |
| 99 | 105 | AlipayTradeRefundModel model = new AlipayTradeRefundModel(); |
| 100 | 106 | model.setOutTradeNo(reqDTO.getOutTradeNo()); |
| ... | ... | @@ -104,31 +110,22 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 104 | 110 | // 1.2 构建 AlipayTradePayRequest 请求 |
| 105 | 111 | AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); |
| 106 | 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 | 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 | 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 | 52 | if (!response.isSuccess()) { |
| 53 | 53 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| 54 | 54 | } |
| 55 | - return new PayOrderRespDTO(displayMode, "", | |
| 55 | + return PayOrderRespDTO.waitingOf(displayMode, "", | |
| 56 | 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 | 62 | if (!response.isSuccess()) { |
| 63 | 63 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| 64 | 64 | } |
| 65 | - return new PayOrderRespDTO(displayMode, "", | |
| 65 | + return PayOrderRespDTO.waitingOf(displayMode, "", | |
| 66 | 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 | 63 | if (!response.isSuccess()) { |
| 64 | 64 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| 65 | 65 | } |
| 66 | - return new PayOrderRespDTO(displayMode, response.getBody(), | |
| 66 | + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), | |
| 67 | 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 | 50 | if (!response.isSuccess()) { |
| 51 | 51 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| 52 | 52 | } |
| 53 | - return new PayOrderRespDTO(displayMode, response.getQrCode(), | |
| 53 | + return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(), | |
| 54 | 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 | 52 | if (!response.isSuccess()) { |
| 53 | 53 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| 54 | 54 | } |
| 55 | - return new PayOrderRespDTO(displayMode, response.getBody(), | |
| 55 | + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), | |
| 56 | 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 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 13 | 13 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 14 | 14 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 15 | -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | |
| 16 | 15 | import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; |
| 17 | 16 | import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; |
| 18 | 17 | import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; |
| ... | ... | @@ -131,6 +130,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 131 | 130 | // 1. 解析回调 |
| 132 | 131 | WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body); |
| 133 | 132 | // 2. 构建结果 |
| 133 | + // 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂 | |
| 134 | 134 | Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ? |
| 135 | 135 | PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); |
| 136 | 136 | return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), |
| ... | ... | @@ -142,6 +142,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 142 | 142 | WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); |
| 143 | 143 | WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult(); |
| 144 | 144 | // 2. 构建结果 |
| 145 | + // 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂 | |
| 145 | 146 | Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ? |
| 146 | 147 | PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); |
| 147 | 148 | String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null; |
| ... | ... | @@ -163,9 +164,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 163 | 164 | throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); |
| 164 | 165 | } |
| 165 | 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<WxPayClientC |
| 181 | 183 | // 2.1 执行请求 |
| 182 | 184 | WxPayRefundResult response = client.refundV2(request); |
| 183 | 185 | // 2.2 创建返回结果 |
| 184 | - PayRefundRespDTO refund = new PayRefundRespDTO() | |
| 185 | - .setOutRefundNo(reqDTO.getOutRefundNo()) | |
| 186 | - .setRawData(response); | |
| 187 | 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 | 193 | private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable { |
| ... | ... | @@ -206,78 +202,51 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 206 | 202 | // 2.1 执行请求 |
| 207 | 203 | WxPayRefundV3Result response = client.refundV3(request); |
| 208 | 204 | // 2.2 创建返回结果 |
| 209 | - PayRefundRespDTO refund = new PayRefundRespDTO() | |
| 210 | - .setOutRefundNo(reqDTO.getOutRefundNo()) | |
| 211 | - .setRawData(response); | |
| 212 | 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 | 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 | 229 | // 1. 解析回调 |
| 248 | 230 | WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body); |
| 249 | - WxPayRefundNotifyResult.ReqInfo responseResult = response.getReqInfo(); | |
| 231 | + WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo(); | |
| 250 | 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 | 240 | private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { |
| 266 | 241 | // 1. 解析回调 |
| 267 | 242 | WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); |
| 268 | - WxPayRefundNotifyV3Result.DecryptNotifyResult responseResult = response.getResult(); | |
| 243 | + WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult(); | |
| 269 | 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 | 67 | for (int i = 1; i < Byte.MAX_VALUE; i++) { |
| 68 | 68 | try { |
| 69 | 69 | WxPayMicropayResult response = client.micropay(request); |
| 70 | - // 支付成功,例如说:1)用户输入了密码;2) | |
| 70 | + // 支付成功,例如说:1)用户输入了密码;2)用户免密支付 | |
| 71 | 71 | return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), |
| 72 | 72 | response.getOutTradeNo(), response) |
| 73 | 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 | 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 | 52 | reqDTO.getOutTradeNo(), response); |
| 53 | 53 | } |
| 54 | 54 | |
| ... | ... | @@ -66,7 +66,7 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 66 | 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 | 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 | 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 | 62 | reqDTO.getOutTradeNo(), response); |
| 63 | 63 | } |
| 64 | 64 | |
| ... | ... | @@ -77,7 +77,7 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 77 | 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 | 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
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 | 14 | @AllArgsConstructor |
| 15 | 15 | public enum PayRefundStatusRespEnum { |
| 16 | 16 | |
| 17 | - WAITING(0, "未退款"), | |
| 17 | + WAITING(0, "等待退款"), | |
| 18 | 18 | SUCCESS(10, "退款成功"), |
| 19 | 19 | FAILURE(20, "退款失败"); |
| 20 | 20 | |
| ... | ... | @@ -25,4 +25,8 @@ public enum PayRefundStatusRespEnum { |
| 25 | 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 | 55 | } |
| 56 | 56 | return RandomUtil.randomInt(); |
| 57 | 57 | }); |
| 58 | + // LocalDateTime | |
| 59 | + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class, | |
| 60 | + (dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime()); | |
| 58 | 61 | // Boolean |
| 59 | 62 | PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { |
| 60 | 63 | // 如果是 deleted 的字段,返回非删除 |
| ... | ... | @@ -82,7 +85,8 @@ public class RandomUtils { |
| 82 | 85 | } |
| 83 | 86 | |
| 84 | 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 | 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 | 63 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; |
| 64 | 64 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 65 | 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 | 67 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 67 | 68 | |
| 68 | 69 | /** |
| ... | ... | @@ -344,7 +345,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { |
| 344 | 345 | PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); |
| 345 | 346 | if (payOrder == null) { |
| 346 | 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 | 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 | 7 | */ |
| 8 | 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 | 10 | public interface ErrorCodeConstants { |
| 11 | 11 | |
| 12 | 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 | 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 | 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 | 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 | 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 | 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 | 12 | @AllArgsConstructor |
| 13 | 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 | 1 | package cn.iocoder.yudao.module.pay.enums.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | |
| 4 | 5 | import lombok.AllArgsConstructor; |
| 5 | 6 | import lombok.Getter; |
| 6 | 7 | |
| ... | ... | @@ -17,7 +18,8 @@ public enum PayOrderStatusEnum implements IntArrayValuable { |
| 17 | 18 | |
| 18 | 19 | WAITING(0, "未支付"), |
| 19 | 20 | SUCCESS(10, "支付成功"), |
| 20 | - CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款 | |
| 21 | + REFUND(20, "已退款"), | |
| 22 | + CLOSED(30, "支付关闭"), // 注意:全部退款后,还是 REFUND 状态 | |
| 21 | 23 | ; |
| 22 | 24 | |
| 23 | 25 | private final Integer status; |
| ... | ... | @@ -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 | 57 | * @param status 状态 | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java
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 | 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 | 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 | 5 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 4 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 5 | 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 6 | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 7 | 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 | 19 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 9 | 20 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 10 | 21 | import io.swagger.v3.oas.annotations.Operation; |
| 22 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 11 | 23 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 12 | 24 | import lombok.extern.slf4j.Slf4j; |
| 25 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 13 | 26 | import org.springframework.validation.annotation.Validated; |
| 14 | 27 | import org.springframework.web.bind.annotation.*; |
| 15 | 28 | |
| 16 | 29 | import javax.annotation.Resource; |
| 17 | 30 | import javax.annotation.security.PermitAll; |
| 31 | +import javax.validation.Valid; | |
| 32 | +import java.util.List; | |
| 18 | 33 | import java.util.Map; |
| 19 | 34 | |
| 20 | 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 | 41 | @RestController |
| 25 | 42 | @RequestMapping("/pay/notify") |
| 26 | 43 | @Validated |
| ... | ... | @@ -31,6 +48,10 @@ public class PayNotifyController { |
| 31 | 48 | private PayOrderService orderService; |
| 32 | 49 | @Resource |
| 33 | 50 | private PayRefundService refundService; |
| 51 | + @Resource | |
| 52 | + private PayNotifyService notifyService; | |
| 53 | + @Resource | |
| 54 | + private PayAppService appService; | |
| 34 | 55 | |
| 35 | 56 | @Resource |
| 36 | 57 | private PayClientFactory payClientFactory; |
| ... | ... | @@ -47,7 +68,7 @@ public class PayNotifyController { |
| 47 | 68 | PayClient payClient = payClientFactory.getPayClient(channelId); |
| 48 | 69 | if (payClient == null) { |
| 49 | 70 | log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); |
| 50 | - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 71 | + throw exception(CHANNEL_NOT_FOUND); | |
| 51 | 72 | } |
| 52 | 73 | |
| 53 | 74 | // 2. 解析通知数据 |
| ... | ... | @@ -68,7 +89,7 @@ public class PayNotifyController { |
| 68 | 89 | PayClient payClient = payClientFactory.getPayClient(channelId); |
| 69 | 90 | if (payClient == null) { |
| 70 | 91 | log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); |
| 71 | - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 92 | + throw exception(CHANNEL_NOT_FOUND); | |
| 72 | 93 | } |
| 73 | 94 | |
| 74 | 95 | // 2. 解析通知数据 |
| ... | ... | @@ -77,4 +98,29 @@ public class PayNotifyController { |
| 77 | 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 | 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 | 5 | import java.time.LocalDateTime; |
| 9 | 6 | |
| 10 | -@Schema(description = "管理后台 - 退款订单 Response VO") | |
| 7 | +@Schema(description = "管理后台 - 回调通知 Response VO") | |
| 11 | 8 | @Data |
| 12 | 9 | @EqualsAndHashCode(callSuper = true) |
| 13 | 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 | 14 | private Long id; |
| 18 | 15 | |
| 19 | 16 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 20 | 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 | 1 | package cn.iocoder.yudao.module.pay.controller.admin.order; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollectionUtil; |
| 4 | -import cn.hutool.core.util.ObjectUtil; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | 6 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 10 | -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | |
| 11 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 12 | 9 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 13 | 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 14 | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 15 | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 16 | 13 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 17 | -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; | |
| 18 | 14 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 19 | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 20 | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| ... | ... | @@ -32,6 +28,7 @@ import java.util.List; |
| 32 | 28 | import java.util.Map; |
| 33 | 29 | |
| 34 | 30 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 31 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 35 | 32 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 36 | 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 | 39 | public class PayOrderController { |
| 43 | 40 | |
| 44 | 41 | @Resource |
| 45 | - private PayOrderService payOrderService; | |
| 46 | - @Resource | |
| 47 | - private PayOrderExtensionService orderExtensionService; | |
| 42 | + private PayOrderService orderService; | |
| 48 | 43 | @Resource |
| 49 | 44 | private PayAppService appService; |
| 50 | 45 | |
| ... | ... | @@ -53,40 +48,29 @@ public class PayOrderController { |
| 53 | 48 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 54 | 49 | @PreAuthorize("@ss.hasPermission('pay:order:query')") |
| 55 | 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 | 54 | @GetMapping("/get-detail") |
| 61 | 55 | @Operation(summary = "获得支付订单详情") |
| 62 | 56 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 63 | 57 | @PreAuthorize("@ss.hasPermission('pay:order:query')") |
| 64 | 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 | 70 | @PostMapping("/submit") |
| 87 | 71 | @Operation(summary = "提交支付订单") |
| 88 | 72 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { |
| 89 | - PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP()); | |
| 73 | + PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP()); | |
| 90 | 74 | return success(respVO); |
| 91 | 75 | } |
| 92 | 76 | |
| ... | ... | @@ -94,62 +78,34 @@ public class PayOrderController { |
| 94 | 78 | @Operation(summary = "获得支付订单分页") |
| 95 | 79 | @PreAuthorize("@ss.hasPermission('pay:order:query')") |
| 96 | 80 | public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) { |
| 97 | - PageResult<PayOrderDO> pageResult = payOrderService.getOrderPage(pageVO); | |
| 81 | + PageResult<PayOrderDO> pageResult = orderService.getOrderPage(pageVO); | |
| 98 | 82 | if (CollectionUtil.isEmpty(pageResult.getList())) { |
| 99 | 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 | 91 | @GetMapping("/export-excel") |
| 120 | - @Operation(summary = "导出支付订单Excel") | |
| 92 | + @Operation(summary = "导出支付订单 Excel") | |
| 121 | 93 | @PreAuthorize("@ss.hasPermission('pay:order:export')") |
| 122 | 94 | @OperateLog(type = EXPORT) |
| 123 | 95 | public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO, |
| 124 | 96 | HttpServletResponse response) throws IOException { |
| 125 | - List<PayOrderDO> list = payOrderService.getOrderList(exportReqVO); | |
| 97 | + List<PayOrderDO> list = orderService.getOrderList(exportReqVO); | |
| 126 | 98 | if (CollectionUtil.isEmpty(list)) { |
| 127 | 99 | ExcelUtils.write(response, "支付订单.xls", "数据", |
| 128 | 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 | 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 | 17 | @Data |
| 18 | 18 | public class PayOrderBaseVO { |
| 19 | 19 | |
| 20 | - @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 20 | + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 21 | 21 | @NotNull(message = "应用编号不能为空") |
| 22 | 22 | private Long appId; |
| 23 | 23 | |
| 24 | - @Schema(description = "渠道编号") | |
| 24 | + @Schema(description = "渠道编号", example = "2048") | |
| 25 | 25 | private Long channelId; |
| 26 | 26 | |
| 27 | - @Schema(description = "渠道编码") | |
| 27 | + @Schema(description = "渠道编码", example = "wx_app") | |
| 28 | 28 | private String channelCode; |
| 29 | 29 | |
| 30 | - @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 30 | + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") | |
| 31 | 31 | @NotNull(message = "商户订单编号不能为空") |
| 32 | 32 | private String merchantOrderId; |
| 33 | 33 | |
| 34 | - @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 34 | + @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") | |
| 35 | 35 | @NotNull(message = "商品标题不能为空") |
| 36 | 36 | private String subject; |
| 37 | 37 | |
| 38 | - @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 38 | + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是土豆") | |
| 39 | 39 | @NotNull(message = "商品描述不能为空") |
| 40 | 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 | 43 | @NotNull(message = "异步通知地址不能为空") |
| 44 | 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 | 47 | @NotNull(message = "支付金额,单位:分不能为空") |
| 52 | 48 | private Long price; |
| 53 | 49 | |
| 54 | - @Schema(description = "渠道手续费,单位:百分比") | |
| 50 | + @Schema(description = "渠道手续费,单位:百分比", example = "10") | |
| 55 | 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 | 57 | @NotNull(message = "支付状态不能为空") |
| 62 | 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 | 61 | @NotNull(message = "用户 IP不能为空") |
| 66 | 62 | private String userIp; |
| 67 | 63 | |
| ... | ... | @@ -74,29 +70,20 @@ public class PayOrderBaseVO { |
| 74 | 70 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 75 | 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 | 80 | @NotNull(message = "退款总金额,单位:分不能为空") |
| 94 | 81 | private Long refundPrice; |
| 95 | 82 | |
| 96 | - @Schema(description = "渠道用户编号") | |
| 83 | + @Schema(description = "渠道用户编号", example = "2048") | |
| 97 | 84 | private String channelUserId; |
| 98 | 85 | |
| 99 | - @Schema(description = "渠道订单号") | |
| 86 | + @Schema(description = "渠道订单号", example = "4096") | |
| 100 | 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 | 13 | @ToString(callSuper = true) |
| 14 | 14 | public class PayOrderDetailsRespVO extends PayOrderBaseVO { |
| 15 | 15 | |
| 16 | - @Schema(description = "支付订单编号") | |
| 16 | + @Schema(description = "支付订单编号", required = true, example = "1024") | |
| 17 | 17 | private Long id; |
| 18 | 18 | |
| 19 | - @Schema(description = "应用名称") | |
| 19 | + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") | |
| 20 | 20 | private String appName; |
| 21 | 21 | |
| 22 | - @Schema(description = "渠道编号名称") | |
| 23 | - private String channelCodeName; | |
| 24 | - | |
| 25 | - @Schema(description = "创建时间") | |
| 22 | + @Schema(description = "创建时间", required = true) | |
| 26 | 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 | 33 | @Data |
| 34 | 34 | @Schema(description = "支付订单扩展") |
| 35 | 35 | public static class PayOrderExtension { |
| 36 | 36 | |
| 37 | - @Schema(description = "支付订单号") | |
| 37 | + @Schema(description = "支付订单号", required = true, example = "1024") | |
| 38 | 38 | private String no; |
| 39 | 39 | |
| 40 | 40 | @Schema(description = "支付异步通知的内容") |
| 41 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; | |
| 5 | 6 | import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; |
| 6 | 7 | import com.alibaba.excel.annotation.ExcelProperty; |
| 7 | 8 | import lombok.Data; |
| ... | ... | @@ -9,53 +10,44 @@ import lombok.Data; |
| 9 | 10 | import java.time.LocalDateTime; |
| 10 | 11 | |
| 11 | 12 | /** |
| 12 | - * 支付订单Excel VO | |
| 13 | + * 支付订单 Excel VO | |
| 13 | 14 | * |
| 14 | 15 | * @author aquan |
| 15 | 16 | */ |
| 16 | 17 | @Data |
| 17 | 18 | public class PayOrderExcelVO { |
| 18 | 19 | |
| 19 | - @ExcelProperty("支付订单编号") | |
| 20 | + @ExcelProperty("编号") | |
| 20 | 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 | 44 | @ExcelProperty(value = "支付状态", converter = DictConvert.class) |
| 45 | + @DictFormat(DictTypeConstants.ORDER_STATUS) | |
| 48 | 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 | 52 | @ExcelProperty("订单支付成功时间") |
| 61 | 53 | private LocalDateTime successTime; |
| ... | ... | @@ -63,24 +55,11 @@ public class PayOrderExcelVO { |
| 63 | 55 | @ExcelProperty("订单失效时间") |
| 64 | 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 | 64 | @ExcelProperty("商品描述") |
| 86 | 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 | 12 | @Data |
| 13 | 13 | public class PayOrderExportReqVO { |
| 14 | 14 | |
| 15 | - @Schema(description = "应用编号") | |
| 15 | + @Schema(description = "应用编号", example = "1024") | |
| 16 | 16 | private Long appId; |
| 17 | 17 | |
| 18 | - @Schema(description = "渠道编号") | |
| 19 | - private Long channelId; | |
| 20 | - | |
| 21 | - @Schema(description = "渠道编码") | |
| 18 | + @Schema(description = "渠道编码", example = "wx_app") | |
| 22 | 19 | private String channelCode; |
| 23 | 20 | |
| 24 | - @Schema(description = "商户订单编号") | |
| 21 | + @Schema(description = "商户订单编号", example = "4096") | |
| 25 | 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 | 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 | 33 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 85 | 34 | @Schema(description = "创建时间") |
| 86 | 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 | 13 | @ToString(callSuper = true) |
| 14 | 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 | 17 | private Long id; |
| 18 | 18 | |
| 19 | 19 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 20 | 20 | private LocalDateTime createTime; |
| 21 | 21 | |
| 22 | - @Schema(description = "应用名称") | |
| 22 | + @Schema(description = "应用名称", example = "wx_pay") | |
| 23 | 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 | 17 | @ToString(callSuper = true) |
| 18 | 18 | public class PayOrderPageReqVO extends PageParam { |
| 19 | 19 | |
| 20 | - @Schema(description = "应用编号") | |
| 20 | + @Schema(description = "应用编号", example = "1024") | |
| 21 | 21 | private Long appId; |
| 22 | 22 | |
| 23 | - @Schema(description = "渠道编号") | |
| 24 | - private Long channelId; | |
| 25 | - | |
| 26 | - @Schema(description = "渠道编码") | |
| 23 | + @Schema(description = "渠道编码", example = "wx_app") | |
| 27 | 24 | private String channelCode; |
| 28 | 25 | |
| 29 | - @Schema(description = "商户订单编号") | |
| 26 | + @Schema(description = "商户订单编号", example = "4096") | |
| 30 | 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 | 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 | 38 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 90 | 39 | @Schema(description = "创建时间") |
| 91 | 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 | 1 | package cn.iocoder.yudao.module.pay.controller.admin.refund; |
| 2 | 2 | |
| 3 | 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 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*; |
| 6 | 9 | import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; |
| 7 | 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 8 | -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | |
| 9 | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 10 | 12 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 11 | 13 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 12 | 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 | 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 | 18 | import org.springframework.security.access.prepost.PreAuthorize; |
| 23 | 19 | import org.springframework.validation.annotation.Validated; |
| 24 | 20 | import org.springframework.web.bind.annotation.GetMapping; |
| ... | ... | @@ -35,6 +31,7 @@ import java.util.List; |
| 35 | 31 | import java.util.Map; |
| 36 | 32 | |
| 37 | 33 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 34 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 38 | 35 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 39 | 36 | |
| 40 | 37 | @Tag(name = "管理后台 - 退款订单") |
| ... | ... | @@ -56,20 +53,13 @@ public class PayRefundController { |
| 56 | 53 | @PreAuthorize("@ss.hasPermission('pay:refund:query')") |
| 57 | 54 | public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) { |
| 58 | 55 | PayRefundDO refund = refundService.getRefund(id); |
| 59 | - if (ObjectUtil.isNull(refund)) { | |
| 56 | + if (refund == null) { | |
| 60 | 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 | 65 | @GetMapping("/page") |
| ... | ... | @@ -82,21 +72,8 @@ public class PayRefundController { |
| 82 | 72 | } |
| 83 | 73 | |
| 84 | 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 | 79 | @GetMapping("/export-excel") |
| ... | ... | @@ -105,36 +82,18 @@ public class PayRefundController { |
| 105 | 82 | @OperateLog(type = EXPORT) |
| 106 | 83 | public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO, |
| 107 | 84 | HttpServletResponse response) throws IOException { |
| 108 | - | |
| 109 | 85 | List<PayRefundDO> list = refundService.getRefundList(exportReqVO); |
| 110 | 86 | if (CollectionUtil.isEmpty(list)) { |
| 111 | 87 | ExcelUtils.write(response, "退款订单.xls", "数据", |
| 112 | 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 | 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 | 1 | package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; |
| 2 | + | |
| 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 3 | 4 | import lombok.Data; |
| 4 | -import org.springframework.format.annotation.DateTimeFormat; | |
| 5 | 5 | |
| 6 | -import javax.validation.constraints.NotNull; | |
| 7 | 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 | 9 | * 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用 |
| 13 | 10 | * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 |
| ... | ... | @@ -15,91 +12,67 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ |
| 15 | 12 | @Data |
| 16 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 53 | private String reason; |
| 73 | 54 | |
| 74 | - @Schema(description = "用户 IP") | |
| 55 | + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") | |
| 75 | 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 | 61 | private String channelOrderNo; |
| 80 | 62 | |
| 81 | - @Schema(description = "渠道退款单号,渠道返回") | |
| 63 | + @Schema(description = "渠道退款单号", example = "2022") | |
| 82 | 64 | private String channelRefundNo; |
| 83 | 65 | |
| 84 | - @Schema(description = "渠道调用报错时,错误码") | |
| 66 | + @Schema(description = "退款成功时间") | |
| 67 | + private LocalDateTime successTime; | |
| 68 | + | |
| 69 | + @Schema(description = "调用渠道的错误码") | |
| 85 | 70 | private String channelErrorCode; |
| 86 | 71 | |
| 87 | - @Schema(description = "渠道调用报错时,错误信息") | |
| 72 | + @Schema(description = "调用渠道的错误提示") | |
| 88 | 73 | private String channelErrorMsg; |
| 89 | 74 | |
| 90 | 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 | 5 | import lombok.EqualsAndHashCode; |
| 6 | 6 | import lombok.ToString; |
| 7 | 7 | |
| 8 | -import javax.validation.constraints.NotNull; | |
| 9 | 8 | import java.time.LocalDateTime; |
| 10 | 9 | |
| 11 | 10 | @Schema(description = "管理后台 - 退款订单详情 Response VO") |
| ... | ... | @@ -17,14 +16,11 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO { |
| 17 | 16 | @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED) |
| 18 | 17 | private Long id; |
| 19 | 18 | |
| 20 | - @Schema(description = "应用名称") | |
| 19 | + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿") | |
| 21 | 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 | 25 | @Schema(description = "创建时间") |
| 30 | 26 | private LocalDateTime createTime; |
| ... | ... | @@ -32,4 +28,13 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO { |
| 32 | 28 | @Schema(description = "更新时间") |
| 33 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; | |
| 5 | 6 | import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; |
| 6 | 7 | import com.alibaba.excel.annotation.ExcelProperty; |
| 7 | 8 | import lombok.Data; |
| ... | ... | @@ -19,64 +20,42 @@ public class PayRefundExcelVO { |
| 19 | 20 | @ExcelProperty("支付退款编号") |
| 20 | 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 | 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 | 44 | @ExcelProperty(value = "退款状态", converter = DictConvert.class) |
| 45 | + @DictFormat(DictTypeConstants.REFUND_STATUS) | |
| 49 | 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 | 58 | @ExcelProperty("退款原因") |
| 62 | 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 | 12 | @Data |
| 13 | 13 | public class PayRefundExportReqVO { |
| 14 | 14 | |
| 15 | - @Schema(description = "应用编号") | |
| 15 | + @Schema(description = "应用编号", example = "1024") | |
| 16 | 16 | private Long appId; |
| 17 | 17 | |
| 18 | - @Schema(description = "渠道编号") | |
| 19 | - private Long channelId; | |
| 20 | - | |
| 21 | - @Schema(description = "渠道编码") | |
| 18 | + @Schema(description = "渠道编码", example = "wx_app") | |
| 22 | 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 | 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 | 28 | private String channelOrderNo; |
| 62 | 29 | |
| 63 | - @Schema(description = "渠道退款单号,渠道返回") | |
| 30 | + @Schema(description = "渠道退款单号", example = "40") | |
| 64 | 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 | 36 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 88 | 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 | 13 | @ToString(callSuper = true) |
| 14 | 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 | 17 | private Long id; |
| 18 | 18 | |
| 19 | - @Schema(description = "应用名称") | |
| 19 | + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿") | |
| 20 | 20 | private String appName; |
| 21 | 21 | |
| 22 | - @Schema(description = "渠道名称") | |
| 23 | - private String channelCodeName; | |
| 24 | - | |
| 25 | 22 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 26 | 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 | 17 | @ToString(callSuper = true) |
| 18 | 18 | public class PayRefundPageReqVO extends PageParam { |
| 19 | 19 | |
| 20 | - @Schema(description = "应用编号") | |
| 20 | + @Schema(description = "应用编号", example = "1024") | |
| 21 | 21 | private Long appId; |
| 22 | 22 | |
| 23 | - @Schema(description = "渠道编号") | |
| 24 | - private Long channelId; | |
| 25 | - | |
| 26 | - @Schema(description = "渠道编码") | |
| 23 | + @Schema(description = "渠道编码", example = "wx_app") | |
| 27 | 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 | 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 | 33 | private String channelOrderNo; |
| 67 | 34 | |
| 68 | - @Schema(description = "渠道退款单号,渠道返回") | |
| 35 | + @Schema(description = "渠道退款单号", example = "40") | |
| 69 | 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 | 41 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 93 | 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 | 1 | package cn.iocoder.yudao.module.pay.convert.order; |
| 2 | 2 | |
| 3 | 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 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | 7 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 6 | 8 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; |
| 7 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 8 | 10 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; |
| 11 | +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | |
| 9 | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 10 | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 11 | 14 | import org.mapstruct.Mapper; |
| 12 | 15 | import org.mapstruct.Mapping; |
| 13 | 16 | import org.mapstruct.factory.Mappers; |
| 14 | 17 | |
| 15 | -import java.math.BigDecimal; | |
| 16 | -import java.math.RoundingMode; | |
| 17 | 18 | import java.util.List; |
| 19 | +import java.util.Map; | |
| 18 | 20 | |
| 19 | 21 | /** |
| 20 | 22 | * 支付订单 Convert |
| ... | ... | @@ -30,60 +32,32 @@ public interface PayOrderConvert { |
| 30 | 32 | |
| 31 | 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 | 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 | 1 | package cn.iocoder.yudao.module.pay.convert.refund; |
| 2 | 2 | |
| 3 | 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 | 6 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; |
| 5 | 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 | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 8 | 14 | import org.mapstruct.Mapper; |
| 9 | 15 | import org.mapstruct.factory.Mappers; |
| 10 | 16 | |
| 11 | -import java.math.BigDecimal; | |
| 12 | -import java.math.RoundingMode; | |
| 13 | 17 | import java.util.List; |
| 18 | +import java.util.Map; | |
| 14 | 19 | |
| 15 | 20 | @Mapper |
| 16 | 21 | public interface PayRefundConvert { |
| 17 | 22 | |
| 18 | 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 | 43 | PayRefundDO convert(PayRefundCreateReqDTO bean); |
| 84 | 44 | |
| 85 | 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
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 | 4 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 7 | -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum; | |
| 8 | 7 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 9 | -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum; | |
| 10 | 8 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 11 | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
| 12 | 10 | import lombok.*; |
| ... | ... | @@ -71,12 +69,6 @@ public class PayOrderDO extends BaseDO { |
| 71 | 69 | * 异步通知地址 |
| 72 | 70 | */ |
| 73 | 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 | 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 | 105 | */ |
| 114 | 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
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 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 7 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 8 | 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 9 | -import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | |
| 10 | 9 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; |
| 11 | 10 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 12 | 11 | import com.baomidou.mybatisplus.annotation.TableId; |
| ... | ... | @@ -89,12 +88,6 @@ public class PayRefundDO extends BaseDO { |
| 89 | 88 | * 异步通知地址 |
| 90 | 89 | */ |
| 91 | 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 | 140 | */ |
| 148 | 141 | private String channelErrorCode; |
| 149 | 142 | /** |
| 150 | - * 调用渠道报错时,错误信息 | |
| 143 | + * 调用渠道的错误提示 | |
| 151 | 144 | */ |
| 152 | 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 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 6 | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 7 | 9 | @Mapper |
| 8 | 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 | 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 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; |
| 4 | 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 | 10 | import org.apache.ibatis.annotations.Mapper; |
| 8 | 11 | |
| 9 | 12 | import java.time.LocalDateTime; |
| ... | ... | @@ -21,10 +24,21 @@ public interface PayNotifyTaskMapper extends BaseMapperX<PayNotifyTaskDO> { |
| 21 | 24 | * @return PayTransactionNotifyTaskDO 数组 |
| 22 | 25 | */ |
| 23 | 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 | 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 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 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 | 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 9 | 9 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 10 | -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
| 11 | 10 | import org.apache.ibatis.annotations.Mapper; |
| 12 | 11 | |
| 13 | -import java.util.Collection; | |
| 14 | 12 | import java.util.List; |
| 15 | 13 | |
| 16 | 14 | @Mapper |
| 17 | 15 | public interface PayOrderMapper extends BaseMapperX<PayOrderDO> { |
| 18 | 16 | |
| 19 | 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 | 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 | 41 | default Long selectCountByAppId(Long appId) { |
| ... | ... | @@ -55,13 +43,13 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> { |
| 55 | 43 | } |
| 56 | 44 | |
| 57 | 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 | 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 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | |
| 7 | 6 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; |
| 8 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; |
| 9 | 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| ... | ... | @@ -44,27 +43,29 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { |
| 44 | 43 | } |
| 45 | 44 | |
| 46 | 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 | 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 | 14 | "pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类 |
| 15 | 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 | 3 | import lombok.Data; |
| 4 | 4 | import org.hibernate.validator.constraints.URL; |
| ... | ... | @@ -12,6 +12,9 @@ import javax.validation.constraints.NotEmpty; |
| 12 | 12 | @Data |
| 13 | 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 | 37 | @URL(message = "支付回调地址的格式必须是 URL") |
| 35 | 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
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 | 14 | import java.util.Map; |
| 15 | 15 | |
| 16 | 16 | /** |
| 17 | - * 支付应用信息 Service 接口 | |
| 17 | + * 支付应用 Service 接口 | |
| 18 | 18 | * |
| 19 | 19 | * @author 芋艿 |
| 20 | 20 | */ |
| 21 | 21 | public interface PayAppService { |
| 22 | 22 | |
| 23 | 23 | /** |
| 24 | - * 创建支付应用信息 | |
| 24 | + * 创建支付应用 | |
| 25 | 25 | * |
| 26 | - * @param createReqVO 创建信息 | |
| 26 | + * @param createReqVO 创建 | |
| 27 | 27 | * @return 编号 |
| 28 | 28 | */ |
| 29 | 29 | Long createApp(@Valid PayAppCreateReqVO createReqVO); |
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | - * 更新支付应用信息 | |
| 32 | + * 更新支付应用 | |
| 33 | 33 | * |
| 34 | - * @param updateReqVO 更新信息 | |
| 34 | + * @param updateReqVO 更新 | |
| 35 | 35 | */ |
| 36 | 36 | void updateApp(@Valid PayAppUpdateReqVO updateReqVO); |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | - * 修改应用信息状态 | |
| 39 | + * 修改应用状态 | |
| 40 | 40 | * |
| 41 | 41 | * @param id 应用编号 |
| 42 | 42 | * @param status 状态 |
| ... | ... | @@ -44,33 +44,40 @@ public interface PayAppService { |
| 44 | 44 | void updateAppStatus(Long id, Integer status); |
| 45 | 45 | |
| 46 | 46 | /** |
| 47 | - * 删除支付应用信息 | |
| 47 | + * 删除支付应用 | |
| 48 | 48 | * |
| 49 | 49 | * @param id 编号 |
| 50 | 50 | */ |
| 51 | 51 | void deleteApp(Long id); |
| 52 | 52 | |
| 53 | 53 | /** |
| 54 | - * 获得支付应用信息 | |
| 54 | + * 获得支付应用 | |
| 55 | 55 | * |
| 56 | 56 | * @param id 编号 |
| 57 | - * @return 支付应用信息 | |
| 57 | + * @return 支付应用 | |
| 58 | 58 | */ |
| 59 | 59 | PayAppDO getApp(Long id); |
| 60 | 60 | |
| 61 | 61 | /** |
| 62 | - * 获得支付应用信息列表 | |
| 62 | + * 获得支付应用列表 | |
| 63 | 63 | * |
| 64 | 64 | * @param ids 编号 |
| 65 | - * @return 支付应用信息列表 | |
| 65 | + * @return 支付应用列表 | |
| 66 | 66 | */ |
| 67 | 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 | 79 | * @param pageReqVO 分页查询 |
| 73 | - * @return 支付应用信息分页 | |
| 80 | + * @return 支付应用分页 | |
| 74 | 81 | */ |
| 75 | 82 | PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO); |
| 76 | 83 | |
| ... | ... | @@ -91,7 +98,7 @@ public interface PayAppService { |
| 91 | 98 | * 如果不合法,抛出 {@link ServiceException} 业务异常 |
| 92 | 99 | * |
| 93 | 100 | * @param id 应用编号 |
| 94 | - * @return 应用信息 | |
| 101 | + * @return 应用 | |
| 95 | 102 | */ |
| 96 | 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 | 1 | package cn.iocoder.yudao.module.pay.service.app; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 5 | import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; |
| 7 | 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 | 8 | import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert; |
| 10 | 9 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 11 | 10 | import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; |
| 12 | -import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; | |
| 13 | 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 | 12 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 17 | 13 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 18 | 14 | import org.springframework.context.annotation.Lazy; |
| ... | ... | @@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService { |
| 77 | 73 | validateAppExists(id); |
| 78 | 74 | // 校验关联数据是否存在 |
| 79 | 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 | 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 | 85 | |
| 90 | 86 | private void validateAppExists(Long id) { |
| 91 | 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 | 100 | } |
| 105 | 101 | |
| 106 | 102 | @Override |
| 103 | + public List<PayAppDO> getAppList() { | |
| 104 | + return appMapper.selectList(); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 107 | 108 | public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) { |
| 108 | 109 | return appMapper.selectPage(pageReqVO); |
| 109 | 110 | } |
| ... | ... | @@ -113,11 +114,11 @@ public class PayAppServiceImpl implements PayAppService { |
| 113 | 114 | PayAppDO app = appMapper.selectById(id); |
| 114 | 115 | // 校验是否存在 |
| 115 | 116 | if (app == null) { |
| 116 | - throw exception(ErrorCodeConstants.PAY_APP_NOT_FOUND); | |
| 117 | + throw exception(ErrorCodeConstants.APP_NOT_FOUND); | |
| 117 | 118 | } |
| 118 | 119 | // 校验是否禁用 |
| 119 | 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 | 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 | 32 | import java.util.concurrent.TimeUnit; |
| 33 | 33 | |
| 34 | 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 | 38 | * 支付渠道 Service 实现类 |
| ... | ... | @@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 142 | 141 | // 解析配置 |
| 143 | 142 | Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass(); |
| 144 | 143 | if (ObjectUtil.isNull(payClass)) { |
| 145 | - throw exception(CHANNEL_NOT_EXISTS); | |
| 144 | + throw exception(CHANNEL_NOT_FOUND); | |
| 146 | 145 | } |
| 147 | 146 | PayClientConfig config = JsonUtils.parseObject2(configStr, payClass); |
| 148 | 147 | Assert.notNull(config); |
| ... | ... | @@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 167 | 166 | private PayChannelDO validateChannelExists(Long id) { |
| 168 | 167 | PayChannelDO channel = channelMapper.selectById(id); |
| 169 | 168 | if (channel == null) { |
| 170 | - throw exception(CHANNEL_NOT_EXISTS); | |
| 169 | + throw exception(CHANNEL_NOT_FOUND); | |
| 171 | 170 | } |
| 172 | 171 | return channel; |
| 173 | 172 | } |
| ... | ... | @@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 203 | 202 | |
| 204 | 203 | private void validPayChannel(PayChannelDO channel) { |
| 205 | 204 | if (channel == null) { |
| 206 | - throw exception(ErrorCodeConstants.PAY_CHANNEL_NOT_FOUND); | |
| 205 | + throw exception(CHANNEL_NOT_FOUND); | |
| 207 | 206 | } |
| 208 | 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 | 119 | new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now()) |
| 120 | 120 | .setPayChannelCode(payOrder.getChannelCode())); |
| 121 | 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 | 137 | // 1.1 校验订单是否存在 |
| 138 | 138 | PayDemoOrderDO order = payDemoOrderMapper.selectById(id); |
| 139 | 139 | if (order == null) { |
| 140 | - throw exception(PAY_DEMO_ORDER_NOT_FOUND); | |
| 140 | + throw exception(DEMO_ORDER_NOT_FOUND); | |
| 141 | 141 | } |
| 142 | 142 | // 1.2 校验订单未支付 |
| 143 | 143 | if (order.getPayStatus()) { |
| 144 | 144 | log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]", |
| 145 | 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 | 148 | // 1.3 校验支付订单匹配 |
| 149 | 149 | if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 |
| 150 | 150 | log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]", |
| 151 | 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 | 155 | // 2.1 校验支付单是否存在 |
| 156 | 156 | PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); |
| 157 | 157 | if (payOrder == null) { |
| 158 | 158 | log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); |
| 159 | - throw exception(PAY_ORDER_NOT_FOUND); | |
| 159 | + throw exception(ORDER_NOT_FOUND); | |
| 160 | 160 | } |
| 161 | 161 | // 2.2 校验支付单已支付 |
| 162 | 162 | if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { |
| 163 | 163 | log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", |
| 164 | 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 | 167 | // 2.3 校验支付金额一致 |
| 168 | 168 | if (notEqual(payOrder.getPrice(), order.getPrice())) { |
| 169 | 169 | log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]", |
| 170 | 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 | 173 | // 2.4 校验支付订单匹配(二次) |
| 174 | 174 | if (notEqual(payOrder.getMerchantOrderId(), id.toString())) { |
| 175 | 175 | log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", |
| 176 | 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 | 179 | return payOrder; |
| 180 | 180 | } |
| ... | ... | @@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { |
| 203 | 203 | // 校验订单是否存在 |
| 204 | 204 | PayDemoOrderDO order = payDemoOrderMapper.selectById(id); |
| 205 | 205 | if (order == null) { |
| 206 | - throw exception(PAY_DEMO_ORDER_NOT_FOUND); | |
| 206 | + throw exception(DEMO_ORDER_NOT_FOUND); | |
| 207 | 207 | } |
| 208 | 208 | // 校验订单是否支付 |
| 209 | 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 | 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 | 216 | return order; |
| 217 | 217 | } |
| ... | ... | @@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { |
| 229 | 229 | // 1.1 校验示例订单 |
| 230 | 230 | PayDemoOrderDO order = payDemoOrderMapper.selectById(id); |
| 231 | 231 | if (order == null) { |
| 232 | - throw exception(PAY_DEMO_ORDER_NOT_FOUND); | |
| 232 | + throw exception(DEMO_ORDER_NOT_FOUND); | |
| 233 | 233 | } |
| 234 | 234 | // 1.2 校验退款订单匹配 |
| 235 | 235 | if (Objects.equals(order.getPayOrderId(), payRefundId)) { |
| 236 | 236 | log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]", |
| 237 | 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 | 241 | // 2.1 校验退款订单 |
| 242 | 242 | PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId); |
| 243 | 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 | 246 | // 2.2 |
| 247 | 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 | 250 | // 2.3 校验退款金额一致 |
| 251 | 251 | if (notEqual(payRefund.getRefundPrice(), order.getPrice())) { |
| 252 | 252 | log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]", |
| 253 | 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 | 256 | // 2.4 校验退款订单匹配(二次) |
| 257 | 257 | if (notEqual(payRefund.getMerchantOrderId(), id.toString())) { |
| 258 | 258 | log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]", |
| 259 | 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 | 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 | 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 | 7 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 4 | 8 | |
| 5 | 9 | import javax.validation.Valid; |
| 10 | +import java.util.List; | |
| 6 | 11 | |
| 7 | 12 | /** |
| 8 | - * 支付通知 Service 接口 | |
| 13 | + * 回调通知 Service 接口 | |
| 9 | 14 | * |
| 10 | 15 | * @author 芋道源码 |
| 11 | 16 | */ |
| 12 | 17 | public interface PayNotifyService { |
| 13 | 18 | |
| 14 | 19 | /** |
| 15 | - * 创建支付通知任务 | |
| 20 | + * 创建回调通知任务 | |
| 16 | 21 | * |
| 17 | 22 | * @param reqDTO 任务信息 |
| 18 | 23 | */ |
| 19 | 24 | void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO); |
| 20 | 25 | |
| 21 | 26 | /** |
| 22 | - * 执行支付通知 | |
| 27 | + * 执行回调通知 | |
| 23 | 28 | * |
| 24 | 29 | * 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用 |
| 25 | 30 | * @return 通知数量 |
| 26 | 31 | */ |
| 27 | 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 | 6 | import cn.hutool.http.HttpResponse; |
| 7 | 7 | import cn.hutool.http.HttpUtil; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 9 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 9 | 10 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 10 | 11 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 11 | 12 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 12 | 13 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; |
| 13 | 14 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; |
| 15 | +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; | |
| 14 | 16 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; |
| 15 | 17 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; |
| 16 | 18 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| ... | ... | @@ -72,15 +74,15 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 72 | 74 | private PayRefundService refundService; |
| 73 | 75 | |
| 74 | 76 | @Resource |
| 75 | - private PayNotifyTaskMapper payNotifyTaskMapper; | |
| 77 | + private PayNotifyTaskMapper notifyTaskMapper; | |
| 76 | 78 | @Resource |
| 77 | - private PayNotifyLogMapper payNotifyLogMapper; | |
| 79 | + private PayNotifyLogMapper notifyLogMapper; | |
| 78 | 80 | |
| 79 | 81 | @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR) |
| 80 | 82 | private ThreadPoolTaskExecutor threadPoolTaskExecutor; |
| 81 | 83 | |
| 82 | 84 | @Resource |
| 83 | - private PayNotifyLockRedisDAO payNotifyLockCoreRedisDAO; | |
| 85 | + private PayNotifyLockRedisDAO notifyLockCoreRedisDAO; | |
| 84 | 86 | |
| 85 | 87 | @Resource |
| 86 | 88 | @Lazy // 循环依赖(自己依赖自己),避免报错 |
| ... | ... | @@ -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 | 112 | // 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务 |
| 111 | 113 | TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
| ... | ... | @@ -119,7 +121,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 119 | 121 | @Override |
| 120 | 122 | public int executeNotify() throws InterruptedException { |
| 121 | 123 | // 获得需要通知的任务 |
| 122 | - List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify(); | |
| 124 | + List<PayNotifyTaskDO> tasks = notifyTaskMapper.selectListByNotify(); | |
| 123 | 125 | if (CollUtil.isEmpty(tasks)) { |
| 124 | 126 | return 0; |
| 125 | 127 | } |
| ... | ... | @@ -164,11 +166,11 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 164 | 166 | */ |
| 165 | 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 | 172 | // 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断 |
| 171 | - PayNotifyTaskDO dbTask = payNotifyTaskMapper.selectById(task.getId()); | |
| 173 | + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); | |
| 172 | 174 | if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) { |
| 173 | 175 | log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]", |
| 174 | 176 | JsonUtils.toJsonString(task), dbTask.getNotifyTimes()); |
| ... | ... | @@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 197 | 199 | // 记录 PayNotifyLog 日志 |
| 198 | 200 | String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : |
| 199 | 201 | JsonUtils.toJsonString(invokeResult); |
| 200 | - payNotifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) | |
| 202 | + notifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) | |
| 201 | 203 | .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); |
| 202 | 204 | } |
| 203 | 205 | |
| ... | ... | @@ -250,22 +252,37 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 250 | 252 | // 情况一:调用成功 |
| 251 | 253 | if (invokeResult != null && invokeResult.isSuccess()) { |
| 252 | 254 | updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); |
| 253 | - payNotifyTaskMapper.updateById(updateTask); | |
| 255 | + notifyTaskMapper.updateById(updateTask); | |
| 254 | 256 | return updateTask.getStatus(); |
| 255 | 257 | } |
| 256 | 258 | // 情况二:调用失败、调用异常 |
| 257 | 259 | // 2.1 超过最大回调次数 |
| 258 | 260 | if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { |
| 259 | 261 | updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); |
| 260 | - payNotifyTaskMapper.updateById(updateTask); | |
| 262 | + notifyTaskMapper.updateById(updateTask); | |
| 261 | 263 | return updateTask.getStatus(); |
| 262 | 264 | } |
| 263 | 265 | // 2.2 未超过最大回调次数 |
| 264 | 266 | updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()]))); |
| 265 | 267 | updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() |
| 266 | 268 | : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); |
| 267 | - payNotifyTaskMapper.updateById(updateTask); | |
| 269 | + notifyTaskMapper.updateById(updateTask); | |
| 268 | 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 | 1 | package cn.iocoder.yudao.module.pay.service.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 6 | 5 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 7 | 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 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; |
| 10 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; |
| 11 | 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 | 13 | import javax.validation.Valid; |
| 14 | 14 | import javax.validation.constraints.NotEmpty; |
| 15 | -import java.util.Collection; | |
| 16 | 15 | import java.util.List; |
| 17 | -import java.util.Map; | |
| 18 | 16 | |
| 19 | 17 | /** |
| 20 | 18 | * 支付订单 Service 接口 |
| ... | ... | @@ -49,45 +47,22 @@ public interface PayOrderService { |
| 49 | 47 | Long getOrderCountByAppId(Long appId); |
| 50 | 48 | |
| 51 | 49 | /** |
| 52 | - * 获得支付订单 | |
| 53 | - * 分页 | |
| 50 | + * 获得支付订单分页 | |
| 54 | 51 | * |
| 55 | 52 | * @param pageReqVO 分页查询 |
| 56 | - * @return 支付订单 | |
| 57 | - * 分页 | |
| 53 | + * @return 支付订单分页 | |
| 58 | 54 | */ |
| 59 | 55 | PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO); |
| 60 | 56 | |
| 61 | 57 | /** |
| 62 | - * 获得支付订单 | |
| 63 | - * 列表, 用于 Excel 导出 | |
| 58 | + * 获得支付订单列表, 用于 Excel 导出 | |
| 64 | 59 | * |
| 65 | 60 | * @param exportReqVO 查询条件 |
| 66 | - * @return 支付订单 | |
| 67 | - * 列表 | |
| 61 | + * @return 支付订单列表 | |
| 68 | 62 | */ |
| 69 | 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 | 68 | * @param reqDTO 创建请求 |
| ... | ... | @@ -122,4 +97,12 @@ public interface PayOrderService { |
| 122 | 97 | */ |
| 123 | 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 | 1 | package cn.iocoder.yudao.module.pay.service.order; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.date.DateUtil; | |
| 4 | 3 | import cn.hutool.core.lang.Pair; |
| 5 | 4 | import cn.hutool.core.util.ObjectUtil; |
| 6 | -import cn.hutool.core.util.RandomUtil; | |
| 7 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | +import cn.hutool.extra.spring.SpringUtil; | |
| 8 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 8 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 10 | -import cn.iocoder.yudao.framework.pay.config.PayProperties; | |
| 11 | 9 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 12 | 10 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 13 | 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 | 24 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 27 | 25 | import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper; |
| 28 | 26 | import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; |
| 27 | +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | |
| 29 | 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 | 29 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 30 | +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | |
| 33 | 31 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 34 | 32 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 35 | 33 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 36 | 34 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 35 | +import cn.iocoder.yudao.module.pay.util.MoneyUtils; | |
| 37 | 36 | import lombok.extern.slf4j.Slf4j; |
| 38 | 37 | import org.springframework.stereotype.Service; |
| 39 | 38 | import org.springframework.transaction.annotation.Transactional; |
| 40 | 39 | import org.springframework.validation.annotation.Validated; |
| 41 | 40 | |
| 42 | 41 | import javax.annotation.Resource; |
| 43 | -import java.time.LocalDateTime; | |
| 44 | -import java.util.Collection; | |
| 45 | 42 | import java.util.List; |
| 46 | 43 | import java.util.Objects; |
| 47 | 44 | |
| ... | ... | @@ -69,6 +66,8 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 69 | 66 | private PayOrderMapper orderMapper; |
| 70 | 67 | @Resource |
| 71 | 68 | private PayOrderExtensionMapper orderExtensionMapper; |
| 69 | + @Resource | |
| 70 | + private PayNoRedisDAO noRedisDAO; | |
| 72 | 71 | |
| 73 | 72 | @Resource |
| 74 | 73 | private PayAppService appService; |
| ... | ... | @@ -102,12 +101,6 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 102 | 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 | 104 | @Override |
| 112 | 105 | public Long createOrder(PayOrderCreateReqDTO reqDTO) { |
| 113 | 106 | // 校验 App |
| ... | ... | @@ -125,11 +118,11 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 125 | 118 | // 创建支付交易单 |
| 126 | 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 | 123 | .setStatus(PayOrderStatusEnum.WAITING.getStatus()) |
| 131 | 124 | // 退款相关字段 |
| 132 | - .setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0); | |
| 125 | + .setRefundPrice(0); | |
| 133 | 126 | orderMapper.insert(order); |
| 134 | 127 | return order.getId(); |
| 135 | 128 | } |
| ... | ... | @@ -143,8 +136,9 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 143 | 136 | PayClient client = payClientFactory.getPayClient(channel.getId()); |
| 144 | 137 | |
| 145 | 138 | // 2. 插入 PayOrderExtensionDO |
| 139 | + String no = noRedisDAO.generate(payProperties.getOrderNoPrefix()); | |
| 146 | 140 | PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp) |
| 147 | - .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) | |
| 141 | + .setOrderId(order.getId()).setNo(no) | |
| 148 | 142 | .setChannelId(channel.getId()).setChannelCode(channel.getCode()) |
| 149 | 143 | .setStatus(PayOrderStatusEnum.WAITING.getStatus()); |
| 150 | 144 | orderExtensionMapper.insert(orderExtension); |
| ... | ... | @@ -162,10 +156,10 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 162 | 156 | |
| 163 | 157 | // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功 |
| 164 | 158 | if (unifiedOrderResp != null) { |
| 165 | - notifyPayOrder(channel, unifiedOrderResp); | |
| 159 | + getSelf().notifyOrder(channel, unifiedOrderResp); | |
| 166 | 160 | // 如有渠道错误码,则抛出业务异常,提示用户 |
| 167 | 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 | 163 | unifiedOrderResp.getChannelErrorMsg()); |
| 170 | 164 | } |
| 171 | 165 | // 此处需要读取最新的状态 |
| ... | ... | @@ -177,13 +171,13 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 177 | 171 | private PayOrderDO validateOrderCanSubmit(Long id) { |
| 178 | 172 | PayOrderDO order = orderMapper.selectById(id); |
| 179 | 173 | if (order == null) { // 是否存在 |
| 180 | - throw exception(PAY_ORDER_NOT_FOUND); | |
| 174 | + throw exception(ORDER_NOT_FOUND); | |
| 181 | 175 | } |
| 182 | 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 | 179 | if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期 |
| 186 | - throw exception(PAY_ORDER_IS_EXPIRED); | |
| 180 | + throw exception(ORDER_IS_EXPIRED); | |
| 187 | 181 | } |
| 188 | 182 | return order; |
| 189 | 183 | } |
| ... | ... | @@ -196,7 +190,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 196 | 190 | PayClient client = payClientFactory.getPayClient(channel.getId()); |
| 197 | 191 | if (client == null) { |
| 198 | 192 | log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); |
| 199 | - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 193 | + throw exception(CHANNEL_NOT_FOUND); | |
| 200 | 194 | } |
| 201 | 195 | return channel; |
| 202 | 196 | } |
| ... | ... | @@ -211,61 +205,22 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 211 | 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 | 208 | @Override |
| 233 | - @Transactional(rollbackFor = Exception.class) | |
| 234 | 209 | public void notifyOrder(Long channelId, PayOrderRespDTO notify) { |
| 235 | 210 | // 校验支付渠道是否有效 |
| 236 | 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 | 225 | if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { |
| 271 | 226 | notifyOrderSuccess(channel, notify); |
| ... | ... | @@ -275,20 +230,22 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 275 | 230 | if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) { |
| 276 | 231 | notifyOrderClosed(channel, notify); |
| 277 | 232 | } |
| 233 | + // 情况三:WAITING:无需处理 | |
| 234 | + // 情况四:REFUND:通过退款回调处理 | |
| 278 | 235 | } |
| 279 | 236 | |
| 280 | 237 | private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) { |
| 281 | 238 | // 1. 更新 PayOrderExtensionDO 支付成功 |
| 282 | - PayOrderExtensionDO orderExtension = updateOrderExtensionSuccess(notify); | |
| 239 | + PayOrderExtensionDO orderExtension = updateOrderSuccess(notify); | |
| 283 | 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 | 243 | return; |
| 287 | 244 | } |
| 288 | 245 | |
| 289 | 246 | // 3. 插入支付通知记录 |
| 290 | 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 | 254 | * @param notify 通知 |
| 298 | 255 | * @return PayOrderExtensionDO 对象 |
| 299 | 256 | */ |
| 300 | - private PayOrderExtensionDO updateOrderExtensionSuccess(PayOrderRespDTO notify) { | |
| 257 | + private PayOrderExtensionDO updateOrderSuccess(PayOrderRespDTO notify) { | |
| 301 | 258 | // 1. 查询 PayOrderExtensionDO |
| 302 | 259 | PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); |
| 303 | 260 | if (orderExtension == null) { |
| 304 | - throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); | |
| 261 | + throw exception(ORDER_EXTENSION_NOT_FOUND); | |
| 305 | 262 | } |
| 306 | 263 | if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 |
| 307 | 264 | log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId()); |
| 308 | 265 | return orderExtension; |
| 309 | 266 | } |
| 310 | 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 | 271 | // 2. 更新 PayOrderExtensionDO |
| 315 | 272 | int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), |
| 316 | 273 | PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); |
| 317 | 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 | 277 | log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId()); |
| 321 | 278 | return orderExtension; |
| ... | ... | @@ -327,37 +284,37 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 327 | 284 | * @param channel 支付渠道 |
| 328 | 285 | * @param orderExtension 支付拓展单 |
| 329 | 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 | 291 | // 1. 判断 PayOrderDO 是否处于待支付 |
| 336 | 292 | PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); |
| 337 | 293 | if (order == null) { |
| 338 | - throw exception(PAY_ORDER_NOT_FOUND); | |
| 294 | + throw exception(ORDER_NOT_FOUND); | |
| 339 | 295 | } |
| 340 | 296 | if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新 |
| 341 | - && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) { | |
| 297 | + && Objects.equals(order.getExtensionId(), orderExtension.getId())) { | |
| 342 | 298 | log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId()); |
| 343 | - return Pair.of(true, order); | |
| 299 | + return true; | |
| 344 | 300 | } |
| 345 | 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 | 305 | // 2. 更新 PayOrderDO |
| 350 | 306 | int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(), |
| 351 | 307 | PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()) |
| 352 | 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 | 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 | 313 | if (updateCounts == 0) { // 校验状态,必须是待支付 |
| 357 | - throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); | |
| 314 | + throw exception(ORDER_STATUS_IS_NOT_WAITING); | |
| 358 | 315 | } |
| 359 | 316 | log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId()); |
| 360 | - return Pair.of(false, order); | |
| 317 | + return false; | |
| 361 | 318 | } |
| 362 | 319 | |
| 363 | 320 | private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) { |
| ... | ... | @@ -368,7 +325,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 368 | 325 | // 1. 查询 PayOrderExtensionDO |
| 369 | 326 | PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); |
| 370 | 327 | if (orderExtension == null) { |
| 371 | - throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); | |
| 328 | + throw exception(ORDER_EXTENSION_NOT_FOUND); | |
| 372 | 329 | } |
| 373 | 330 | if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新 |
| 374 | 331 | log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId()); |
| ... | ... | @@ -380,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 380 | 337 | return; |
| 381 | 338 | } |
| 382 | 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 | 343 | // 2. 更新 PayOrderExtensionDO |
| ... | ... | @@ -388,9 +345,46 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 388 | 345 | PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) |
| 389 | 346 | .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); |
| 390 | 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 | 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 | 3 | import cn.hutool.core.date.DateUtil; |
| 4 | 4 | import cn.hutool.core.util.RandomUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.pay.config.PayProperties; | |
| 7 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 8 | 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 9 | 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 | 20 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 22 | 21 | import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; |
| 23 | 22 | import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; |
| 24 | -import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | |
| 25 | 23 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 26 | -import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum; | |
| 27 | 24 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 28 | 25 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; |
| 26 | +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | |
| 29 | 27 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 30 | 28 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 31 | 29 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 32 | 30 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 33 | -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; | |
| 34 | 31 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 35 | 32 | import lombok.extern.slf4j.Slf4j; |
| 36 | 33 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -43,6 +40,7 @@ import java.util.List; |
| 43 | 40 | |
| 44 | 41 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 45 | 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 | 46 | * 退款订单 Service 实现类 |
| ... | ... | @@ -66,8 +64,6 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 66 | 64 | @Resource |
| 67 | 65 | private PayOrderService orderService; |
| 68 | 66 | @Resource |
| 69 | - private PayOrderExtensionService orderExtensionService; | |
| 70 | - @Resource | |
| 71 | 67 | private PayAppService appService; |
| 72 | 68 | @Resource |
| 73 | 69 | private PayChannelService channelService; |
| ... | ... | @@ -106,13 +102,13 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 106 | 102 | PayClient client = payClientFactory.getPayClient(channel.getId()); |
| 107 | 103 | if (client == null) { |
| 108 | 104 | log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); |
| 109 | - throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 105 | + throw exception(CHANNEL_NOT_FOUND); | |
| 110 | 106 | } |
| 111 | 107 | // 1.4 校验退款订单是否已经存在 |
| 112 | 108 | PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId( |
| 113 | 109 | app.getId(), reqDTO.getMerchantRefundId()); |
| 114 | 110 | if (refund != null) { |
| 115 | - throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS); | |
| 111 | + throw exception(ErrorCodeConstants.REFUND_EXISTS); | |
| 116 | 112 | } |
| 117 | 113 | |
| 118 | 114 | // 2.1 插入退款单 |
| ... | ... | @@ -120,7 +116,7 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 120 | 116 | .setNo(generateRefundNo()).setOrderId(order.getId()) |
| 121 | 117 | .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) |
| 122 | 118 | // 商户相关的字段 |
| 123 | - .setNotifyUrl(app.getRefundNotifyUrl()).setNotifyStatus(PayNotifyStatusEnum.WAITING.getStatus()) | |
| 119 | + .setNotifyUrl(app.getRefundNotifyUrl()) | |
| 124 | 120 | // 渠道相关字段 |
| 125 | 121 | .setChannelOrderNo(order.getChannelOrderNo()) |
| 126 | 122 | // 退款相关字段 |
| ... | ... | @@ -128,7 +124,7 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 128 | 124 | .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice()); |
| 129 | 125 | refundMapper.insert(refund); |
| 130 | 126 | // 2.2 向渠道发起退款申请 |
| 131 | - PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId()); | |
| 127 | + PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId()); | |
| 132 | 128 | PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO() |
| 133 | 129 | .setPayPrice(order.getPrice()) |
| 134 | 130 | .setRefundPrice(reqDTO.getPrice()) |
| ... | ... | @@ -136,7 +132,7 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 136 | 132 | .setOutRefundNo(refund.getNo()) |
| 137 | 133 | .setNotifyUrl(genChannelRefundNotifyUrl(channel)) |
| 138 | 134 | .setReason(reqDTO.getReason()); |
| 139 | - PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段 | |
| 135 | + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); | |
| 140 | 136 | // 2.3 处理退款返回 |
| 141 | 137 | notifyRefund(channel, refundRespDTO); |
| 142 | 138 | |
| ... | ... | @@ -153,25 +149,21 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 153 | 149 | private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { |
| 154 | 150 | PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); |
| 155 | 151 | if (order == null) { |
| 156 | - throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND); | |
| 152 | + throw exception(ErrorCodeConstants.ORDER_NOT_FOUND); | |
| 157 | 153 | } |
| 158 | 154 | // 校验状态,必须是支付状态 |
| 159 | 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 | 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 | 164 | if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(), |
| 173 | 165 | PayRefundStatusEnum.WAITING.getStatus()) > 0) { |
| 174 | - throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING); | |
| 166 | + throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING); | |
| 175 | 167 | } |
| 176 | 168 | return order; |
| 177 | 169 | } |
| ... | ... | @@ -205,7 +197,6 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 205 | 197 | } |
| 206 | 198 | |
| 207 | 199 | @Override |
| 208 | - @Transactional(rollbackFor = Exception.class) | |
| 209 | 200 | public void notifyRefund(Long channelId, PayRefundRespDTO notify) { |
| 210 | 201 | // 校验支付渠道是否有效 |
| 211 | 202 | channelService.validPayChannel(channelId); |
| ... | ... | @@ -217,28 +208,33 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 217 | 208 | TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify)); |
| 218 | 209 | } |
| 219 | 210 | |
| 211 | + // TODO 芋艿:事务问题 | |
| 220 | 212 | private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { |
| 213 | + // 情况一:退款成功 | |
| 221 | 214 | if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { |
| 222 | 215 | notifyRefundSuccess(channel, notify); |
| 223 | - } else { | |
| 216 | + return; | |
| 217 | + } | |
| 218 | + // 情况二:退款失败 | |
| 219 | + if (PayRefundStatusRespEnum.isFailure(notify.getStatus())) { | |
| 224 | 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 | 225 | // 1.1 查询 PayRefundDO |
| 230 | 226 | PayRefundDO refund = refundMapper.selectByAppIdAndNo( |
| 231 | 227 | channel.getAppId(), notify.getOutRefundNo()); |
| 232 | 228 | if (refund == null) { |
| 233 | - throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND); | |
| 229 | + throw exception(ErrorCodeConstants.REFUND_NOT_FOUND); | |
| 234 | 230 | } |
| 235 | 231 | if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 |
| 232 | + log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId()); | |
| 236 | 233 | return; |
| 237 | 234 | } |
| 238 | 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 | 238 | // 1.2 更新 PayRefundDO |
| 243 | 239 | PayRefundDO updateRefundObj = new PayRefundDO() |
| 244 | 240 | .setSuccessTime(notify.getSuccessTime()) |
| ... | ... | @@ -247,19 +243,48 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 247 | 243 | .setChannelNotifyData(toJsonString(notify)); |
| 248 | 244 | int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); |
| 249 | 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 | 250 | // 2. 更新订单 |
| 254 | 251 | orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice()); |
| 255 | 252 | |
| 256 | - // 3. 插入退款通知记录 | |
| 253 | + // 3. 插入退款通知记录 TODO 芋艿:退款成功 | |
| 257 | 254 | notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() |
| 258 | 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 | 90 | PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> |
| 91 | 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 | 96 | @Test |
| ... | ... | @@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { |
| 130 | 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 | 136 | @Test |
| ... | ... | @@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { |
| 144 | 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 | 150 | @Test |
| ... | ... | @@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { |
| 158 | 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 | 164 | @Test |
| ... | ... | @@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { |
| 239 | 239 | |
| 240 | 240 | @Test |
| 241 | 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 | 245 | @Test |
| ... | ... | @@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest { |
| 252 | 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 | 26 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 27 | 27 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; |
| 28 | 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 | 30 | import static org.junit.jupiter.api.Assertions.*; |
| 32 | 31 | |
| 33 | 32 | @Import({PayChannelServiceImpl.class}) |
| ... | ... | @@ -52,6 +51,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest { |
| 52 | 51 | } |
| 53 | 52 | |
| 54 | 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 | 88 | public void testCreateChannel_success() { |
| 56 | 89 | // 准备参数 |
| 57 | 90 | WxPayClientConfig config = randomWxPayClientConfig(); |
| ... | ... | @@ -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 | 164 | @Test |
| ... | ... | @@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { |
| 153 | 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 | 192 | @Test |
| ... | ... | @@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest { |
| 214 | 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 | 345 | public WxPayClientConfig randomWxPayClientConfig() { |
| 218 | 346 | return new WxPayClientConfig() |
| 219 | 347 | .setAppId(randomString()) | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
| 1 | 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 | 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 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 7 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 8 | 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 | 13 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; |
| 11 | 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 | 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 | 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 | 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 | 27 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 18 | 28 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 19 | 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 | 32 | import org.junit.jupiter.api.Test; |
| 33 | +import org.mockito.ArgumentMatcher; | |
| 34 | +import org.mockito.MockedStatic; | |
| 21 | 35 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 22 | 36 | import org.springframework.context.annotation.Import; |
| 23 | 37 | |
| 24 | 38 | import javax.annotation.Resource; |
| 25 | -import java.time.LocalDateTime; | |
| 39 | +import java.time.Duration; | |
| 26 | 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 | 44 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 29 | 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 | 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 | 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 | 57 | * {@link PayOrderServiceImpl} 的单元测试类 |
| 35 | 58 | * |
| 36 | 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 | 64 | @Resource |
| 42 | 65 | private PayOrderServiceImpl orderService; |
| 43 | 66 | |
| 44 | 67 | @Resource |
| 45 | 68 | private PayOrderMapper orderMapper; |
| 69 | + @Resource | |
| 70 | + private PayOrderExtensionMapper orderExtensionMapper; | |
| 46 | 71 | |
| 47 | 72 | @MockBean |
| 48 | 73 | private PayClientFactory payClientFactory; |
| ... | ... | @@ -55,140 +80,92 @@ public class PayOrderServiceTest extends BaseDbUnitTest { |
| 55 | 80 | @MockBean |
| 56 | 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 | 88 | @Test |
| 63 | 89 | public void testGetOrderPage() { |
| 64 | - | |
| 65 | - String merchantOrderId = generateNo(); | |
| 66 | - String channelOrderId = generateNo(); | |
| 67 | - | |
| 68 | 90 | // mock 数据 |
| 69 | 91 | PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 |
| 70 | 92 | o.setAppId(1L); |
| 71 | - o.setChannelId(1L); | |
| 72 | 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 | 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 | 100 | orderMapper.insert(dbOrder); |
| 96 | 101 | // 测试 appId 不匹配 |
| 97 | 102 | orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); |
| 98 | - // 测试 channelId 不匹配 | |
| 99 | - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L))); | |
| 100 | 103 | // 测试 channelCode 不匹配 |
| 101 | 104 | orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 102 | 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 | 111 | // 测试 status 不匹配 |
| 107 | 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 | 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 | 116 | PayOrderPageReqVO reqVO = new PayOrderPageReqVO(); |
| 115 | 117 | reqVO.setAppId(1L); |
| 116 | - reqVO.setChannelId(1L); | |
| 117 | 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 | 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 | 126 | PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO); |
| 125 | 127 | // 断言 |
| 126 | 128 | assertEquals(1, pageResult.getTotal()); |
| 127 | 129 | assertEquals(1, pageResult.getList().size()); |
| 128 | 130 | assertPojoEquals(dbOrder, pageResult.getList().get(0)); |
| 129 | - // assertEquals(0, dbOrder.getUpdateTime().compareTo(pageResult.getList().get(0).getUpdateTime())); | |
| 130 | 131 | } |
| 131 | 132 | |
| 132 | 133 | @Test |
| 133 | 134 | public void testGetOrderList() { |
| 134 | 135 | // mock 数据 |
| 135 | - String merchantOrderId = generateNo(); | |
| 136 | - String channelOrderId = generateNo(); | |
| 137 | 136 | PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 |
| 138 | 137 | o.setAppId(1L); |
| 139 | - o.setChannelId(1L); | |
| 140 | 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 | 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 | 145 | orderMapper.insert(dbOrder); |
| 165 | 146 | // 测试 appId 不匹配 |
| 166 | 147 | orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); |
| 167 | - // 测试 channelId 不匹配 | |
| 168 | - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L))); | |
| 169 | 148 | // 测试 channelCode 不匹配 |
| 170 | 149 | orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 171 | 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 | 156 | // 测试 status 不匹配 |
| 176 | 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 | 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 | 161 | PayOrderExportReqVO reqVO = new PayOrderExportReqVO(); |
| 184 | 162 | reqVO.setAppId(1L); |
| 185 | - reqVO.setChannelId(1L); | |
| 186 | 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 | 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 | 171 | List<PayOrderDO> list = orderService.getOrderList(reqVO); |
| ... | ... | @@ -197,4 +174,393 @@ public class PayOrderServiceTest extends BaseDbUnitTest { |
| 197 | 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 | 1 | package cn.iocoder.yudao.module.pay.service.refund; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.framework.pay.config.PayProperties; | |
| 5 | 4 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 6 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; | |
| 7 | 7 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 8 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 11 | 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 | 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 | 15 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 16 | 16 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 17 | 17 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 18 | -import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; | |
| 19 | 18 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 20 | 19 | import org.junit.jupiter.api.Test; |
| 21 | 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 | 30 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 32 | 31 | |
| 33 | 32 | @Import(PayRefundServiceImpl.class) |
| 34 | -public class PayRefundServiceTest extends BaseDbUnitTest { | |
| 33 | +public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | |
| 35 | 34 | |
| 36 | 35 | @Resource |
| 37 | 36 | private PayRefundServiceImpl refundService; |
| ... | ... | @@ -46,8 +45,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 46 | 45 | @MockBean |
| 47 | 46 | private PayOrderService orderService; |
| 48 | 47 | @MockBean |
| 49 | - private PayOrderExtensionService orderExtensionService; | |
| 50 | - @MockBean | |
| 51 | 48 | private PayAppService appService; |
| 52 | 49 | @MockBean |
| 53 | 50 | private PayChannelService channelService; |
| ... | ... | @@ -66,8 +63,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 66 | 63 | o.setMerchantOrderId("MOT0000001"); |
| 67 | 64 | o.setMerchantRefundId("MRF0000001"); |
| 68 | 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 | 67 | o.setPayPrice(100); |
| 72 | 68 | o.setRefundPrice(500); |
| 73 | 69 | o.setReason("就是想退款了,你有意见吗"); |
| ... | ... | @@ -87,11 +83,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 87 | 83 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 88 | 84 | // 测试 merchantRefundNo 不匹配 |
| 89 | 85 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); |
| 90 | - // 测试 notifyStatus 不匹配 | |
| 91 | - refundMapper.insert( | |
| 92 | - cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); | |
| 93 | 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 | 88 | // 测试 createTime 不匹配 |
| 96 | 89 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> |
| 97 | 90 | o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); |
| ... | ... | @@ -99,8 +92,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 99 | 92 | PayRefundPageReqVO reqVO = new PayRefundPageReqVO(); |
| 100 | 93 | reqVO.setAppId(1L); |
| 101 | 94 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 102 | - reqVO.setMerchantRefundNo("MRF0000001"); | |
| 103 | - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); | |
| 95 | + reqVO.setMerchantRefundId("MRF0000001"); | |
| 104 | 96 | reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); |
| 105 | 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 | 116 | o.setMerchantOrderId("MOT0000001"); |
| 125 | 117 | o.setMerchantRefundId("MRF0000001"); |
| 126 | 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 | 120 | o.setPayPrice(100); |
| 130 | 121 | o.setRefundPrice(500); |
| 131 | 122 | o.setReason("就是想退款了,你有意见吗"); |
| ... | ... | @@ -145,11 +136,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 145 | 136 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 146 | 137 | // 测试 merchantRefundNo 不匹配 |
| 147 | 138 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); |
| 148 | - // 测试 notifyStatus 不匹配 | |
| 149 | - refundMapper.insert( | |
| 150 | - cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); | |
| 151 | 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 | 141 | // 测试 createTime 不匹配 |
| 154 | 142 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> |
| 155 | 143 | o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); |
| ... | ... | @@ -158,10 +146,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 158 | 146 | PayRefundExportReqVO reqVO = new PayRefundExportReqVO(); |
| 159 | 147 | reqVO.setAppId(1L); |
| 160 | 148 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 161 | - reqVO.setMerchantRefundNo("MRF0000001"); | |
| 162 | - reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); | |
| 163 | 149 | reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); |
| 164 | - reqVO.setType(PayOrderRefundStatusEnum.PART.getStatus()); | |
| 165 | 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
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 | 39 | `subject` varchar(32) NOT NULL, |
| 40 | 40 | `body` varchar(128) NOT NULL, |
| 41 | 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 | 43 | `channel_fee_rate` double DEFAULT 0, |
| 45 | - `channel_fee_amount` bigint(20) DEFAULT 0, | |
| 44 | + `channel_fee_price` bigint(20) DEFAULT 0, | |
| 46 | 45 | `status` tinyint(4) NOT NULL, |
| 47 | 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 | 48 | `success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, |
| 50 | 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 | 53 | `channel_user_id` varchar(255) DEFAULT NULL, |
| 56 | 54 | `channel_order_no` varchar(64) DEFAULT NULL, |
| 57 | 55 | `creator` varchar(64) DEFAULT '', |
| ... | ... | @@ -62,6 +60,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` ( |
| 62 | 60 | PRIMARY KEY ("id") |
| 63 | 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 | 83 | CREATE TABLE IF NOT EXISTS `pay_refund` ( |
| 66 | 84 | "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, |
| 67 | 85 | `app_id` bigint(20) NOT NULL, | ... | ... |
yudao-ui-admin/src/api/pay/app.js
| 1 | 1 | import request from '@/utils/request' |
| 2 | 2 | |
| 3 | -// 创建支付应用信息 | |
| 3 | +// 创建支付应用 | |
| 4 | 4 | export function createApp(data) { |
| 5 | 5 | return request({ |
| 6 | 6 | url: '/pay/app/create', |
| ... | ... | @@ -9,7 +9,7 @@ export function createApp(data) { |
| 9 | 9 | }) |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | -// 更新支付应用信息 | |
| 12 | +// 更新支付应用 | |
| 13 | 13 | export function updateApp(data) { |
| 14 | 14 | return request({ |
| 15 | 15 | url: '/pay/app/update', |
| ... | ... | @@ -18,7 +18,7 @@ export function updateApp(data) { |
| 18 | 18 | }) |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | -// 支付应用信息状态修改 | |
| 21 | +// 支付应用状态修改 | |
| 22 | 22 | export function changeAppStatus(id, status) { |
| 23 | 23 | const data = { |
| 24 | 24 | id, |
| ... | ... | @@ -31,7 +31,7 @@ export function changeAppStatus(id, status) { |
| 31 | 31 | }) |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | -// 删除支付应用信息 | |
| 34 | +// 删除支付应用 | |
| 35 | 35 | export function deleteApp(id) { |
| 36 | 36 | return request({ |
| 37 | 37 | url: '/pay/app/delete?id=' + id, |
| ... | ... | @@ -39,7 +39,7 @@ export function deleteApp(id) { |
| 39 | 39 | }) |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | -// 获得支付应用信息 | |
| 42 | +// 获得支付应用 | |
| 43 | 43 | export function getApp(id) { |
| 44 | 44 | return request({ |
| 45 | 45 | url: '/pay/app/get?id=' + id, |
| ... | ... | @@ -47,7 +47,7 @@ export function getApp(id) { |
| 47 | 47 | }) |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | -// 获得支付应用信息分页 | |
| 50 | +// 获得支付应用分页 | |
| 51 | 51 | export function getAppPage(query) { |
| 52 | 52 | return request({ |
| 53 | 53 | url: '/pay/app/page', |
| ... | ... | @@ -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 | 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 | 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 | 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 | 212 | export const PayRefundStatusEnum = { | ... | ... |
yudao-ui-admin/src/utils/dict.js
| ... | ... | @@ -51,15 +51,12 @@ export const DICT_TYPE = { |
| 51 | 51 | |
| 52 | 52 | // ========== PAY 模块 ========== |
| 53 | 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 | 55 | PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型 |
| 58 | - PAY_ORDER_NOTIFY_STATUS: 'pay_order_notify_status', // 商户支付订单回调状态 | |
| 59 | 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 | 61 | // ========== MP 模块 ========== |
| 65 | 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 | 213 | <el-button @click="cancel">取 消</el-button> |
| 214 | 214 | </div> |
| 215 | 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 | 220 | </div> |
| 219 | 221 | </template> |
| 220 | 222 | |
| ... | ... | @@ -223,13 +225,13 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage } |
| 223 | 225 | import { DICT_TYPE, getDictDatas } from "@/utils/dict"; |
| 224 | 226 | import { PayType, PayChannelEnum, CommonStatusEnum } from "@/utils/constants"; |
| 225 | 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 | 230 | export default { |
| 229 | 231 | name: "PayApp", |
| 230 | 232 | components: { |
| 231 | 233 | "wechatChannelForm": wechatChannelForm, |
| 232 | - "aliPayChannelForm": aliPayChannelForm | |
| 234 | + "alipayChannelForm": alipayChannelForm | |
| 233 | 235 | }, |
| 234 | 236 | data() { |
| 235 | 237 | return { |
| ... | ... | @@ -283,13 +285,6 @@ export default { |
| 283 | 285 | "appId": null, |
| 284 | 286 | // 渠道编码 |
| 285 | 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 | 419 | this.channelParam.aliPayOpen = false; |
| 425 | 420 | } |
| 426 | 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 | 8 | <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> |
| 9 | 9 | </el-select> |
| 10 | 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 | 14 | </el-select> |
| 16 | 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 | 18 | @keyup.enter.native="handleQuery"/> |
| 20 | 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 | 26 | @keyup.enter.native="handleQuery"/> |
| 24 | 27 | </el-form-item> |
| 25 | 28 | <el-form-item label="支付状态" prop="status"> |
| 26 | 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 | 31 | :label="dict.label" :value="parseInt(dict.value)"/> |
| 41 | 32 | </el-select> |
| 42 | 33 | </el-form-item> |
| ... | ... | @@ -62,69 +53,64 @@ |
| 62 | 53 | |
| 63 | 54 | <!-- 列表 --> |
| 64 | 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 | 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 | 60 | </template> |
| 76 | 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 | 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 | 65 | </template> |
| 82 | 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 | 68 | <template v-slot="scope"> |
| 86 | - ¥{{ parseFloat(scope.row.price / 100).toFixed(2) }} | |
| 69 | + ¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }} | |
| 87 | 70 | </template> |
| 88 | 71 | </el-table-column> |
| 89 | 72 | <el-table-column label="手续金额" align="center" prop="channelFeePrice" width="100"> |
| 90 | 73 | <template v-slot="scope"> |
| 91 | - ¥{{ parseFloat(scope.row.channelFeePrice / 100).toFixed(2) }} | |
| 74 | + ¥{{ (scope.row.channelFeePrice / 100.0).toFixed(2) }} | |
| 92 | 75 | </template> |
| 93 | 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 | 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 | 88 | </template> |
| 98 | 89 | </el-table-column> |
| 99 | 90 | <el-table-column label="支付状态" align="center" prop="status"> |
| 100 | 91 | <template v-slot="scope"> |
| 101 | 92 | <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" /> |
| 102 | 93 | </template> |
| 103 | - | |
| 104 | 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 | 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 | 98 | </template> |
| 114 | 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 | 101 | <template v-slot="scope"> |
| 117 | - <span>{{ parseTime(scope.row.createTime) }}</span> | |
| 102 | + <span>{{ parseTime(scope.row.successTime) }}</span> | |
| 118 | 103 | </template> |
| 119 | 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 | 106 | <template v-slot="scope"> |
| 122 | - <span>{{ parseTime(scope.row.successTime) }}</span> | |
| 107 | + <span>{{ scope.row.appName }}</span> | |
| 123 | 108 | </template> |
| 124 | 109 | </el-table-column> |
| 110 | + <el-table-column label="商品标题" align="center" prop="subject" width="180" :show-overflow-tooltip="true"/> | |
| 125 | 111 | <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> |
| 126 | 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 | 114 | v-hasPermi="['pay:order:query']">查看详情 |
| 129 | 115 | </el-button> |
| 130 | 116 | </template> |
| ... | ... | @@ -134,67 +120,71 @@ |
| 134 | 120 | <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" |
| 135 | 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 | 125 | <el-descriptions :column="2" label-class-name="desc-label"> |
| 145 | - <el-descriptions-item label="商户订单号"> | |
| 126 | + <el-descriptions-item label="商户单号"> | |
| 146 | 127 | <el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag> |
| 147 | 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 | 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 | 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 | 143 | </el-descriptions-item> |
| 144 | + </el-descriptions> | |
| 145 | + <el-descriptions :column="2" label-class-name="desc-label"> | |
| 159 | 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 | 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 | 152 | <el-descriptions-item label="支付时间">{{ parseTime(orderDetail.successTime) }}</el-descriptions-item> |
| 174 | 153 | <el-descriptions-item label="失效时间">{{ parseTime(orderDetail.expireTime) }}</el-descriptions-item> |
| 175 | - <el-descriptions-item label="通知时间">{{ parseTime(orderDetail.notifyTime) }}</el-descriptions-item> | |
| 176 | 154 | </el-descriptions> |
| 177 | - <el-divider></el-divider> | |
| 178 | 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 | 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 | 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 | 180 | </el-descriptions-item> |
| 181 | + <el-descriptions-item label="通知 URL">{{ orderDetail.notifyUrl }}</el-descriptions-item> | |
| 190 | 182 | </el-descriptions> |
| 191 | - <el-divider></el-divider> | |
| 183 | + <!-- 分割线 --> | |
| 184 | + <el-divider /> | |
| 192 | 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 | 186 | <el-descriptions-item label="支付通道异步回调内容"> |
| 197 | - {{ orderDetail.payOrderExtension.channelNotifyData }} | |
| 187 | + {{ orderDetail.extension.channelNotifyData }} | |
| 198 | 188 | </el-descriptions-item> |
| 199 | 189 | </el-descriptions> |
| 200 | 190 | </el-dialog> |
| ... | ... | @@ -203,35 +193,7 @@ |
| 203 | 193 | |
| 204 | 194 | <script> |
| 205 | 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 | 198 | export default { |
| 237 | 199 | name: "PayOrder", |
| ... | ... | @@ -250,75 +212,37 @@ export default { |
| 250 | 212 | title: "", |
| 251 | 213 | // 是否显示弹出层 |
| 252 | 214 | open: false, |
| 253 | - // 查询参数 TODO 芋艿:多余字段的清理 | |
| 215 | + // 查询参数 | |
| 254 | 216 | queryParams: { |
| 255 | 217 | pageNo: 1, |
| 256 | 218 | pageSize: 10, |
| 257 | 219 | appId: null, |
| 258 | - channelId: null, | |
| 259 | 220 | channelCode: null, |
| 260 | 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 | 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 | 236 | created() { |
| 299 | - // 初始化默认时间 | |
| 300 | - this.initTime(); | |
| 301 | 237 | this.getList(); |
| 302 | - this.handleGetMerchantListByName(null); | |
| 238 | + // 获得筛选项 | |
| 239 | + getAppList().then(response => { | |
| 240 | + this.appList = response.data; | |
| 241 | + }) | |
| 303 | 242 | }, |
| 304 | 243 | methods: { |
| 305 | - initTime(){ | |
| 306 | - this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")]; | |
| 307 | - }, | |
| 308 | 244 | /** 查询列表 */ |
| 309 | 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 | 246 | this.loading = true; |
| 323 | 247 | // 执行查询 |
| 324 | 248 | getOrderPage(this.queryParams).then(response => { |
| ... | ... | @@ -339,22 +263,20 @@ export default { |
| 339 | 263 | /** 重置按钮操作 */ |
| 340 | 264 | resetQuery() { |
| 341 | 265 | this.resetForm("queryForm"); |
| 342 | - this.initTime(); | |
| 343 | 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 | 271 | getOrderDetail(row.id).then(response => { |
| 272 | + // 设置值 | |
| 351 | 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 | 278 | this.open = true; |
| 356 | 279 | }); |
| 357 | - | |
| 358 | 280 | }, |
| 359 | 281 | /** 导出按钮操作 */ |
| 360 | 282 | handleExport() { | ... | ... |
yudao-ui-admin/src/views/pay/refund/index.vue
| ... | ... | @@ -7,31 +7,30 @@ |
| 7 | 7 | <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> |
| 8 | 8 | </el-select> |
| 9 | 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 | 13 | </el-select> |
| 15 | 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 | 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 | 29 | @keyup.enter.native="handleQuery"/> |
| 25 | 30 | </el-form-item> |
| 26 | 31 | <el-form-item label="退款状态" prop="status"> |
| 27 | 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 | 34 | :label="dict.label" :value="parseInt(dict.value)"/> |
| 36 | 35 | </el-select> |
| 37 | 36 | </el-form-item> |
| ... | ... | @@ -58,77 +57,62 @@ |
| 58 | 57 | <!-- 列表 --> |
| 59 | 58 | <el-table v-loading="loading" :data="list"> |
| 60 | 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 | 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 | 68 | </template> |
| 71 | 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 | 76 | <template v-slot="scope"> |
| 76 | 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 | 79 | </p> |
| 80 | 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 | 85 | </p> |
| 84 | 86 | </template> |
| 85 | 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 | 89 | <template v-slot="scope"> |
| 88 | 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 | 92 | </p> |
| 92 | 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 | 95 | </p> |
| 96 | 96 | </template> |
| 97 | 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 | 98 | <el-table-column label="退款状态" align="center" prop="status"> |
| 114 | 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 | 101 | </template> |
| 117 | 102 | </el-table-column> |
| 118 | - <el-table-column label="回调状态" align="center" prop="notifyStatus"> | |
| 103 | + <el-table-column label="退款渠道" align="center" width="140"> | |
| 119 | 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 | 106 | </template> |
| 122 | 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 | 109 | <template v-slot="scope"> |
| 126 | - <span>{{ parseTime(scope.row.createTime) }}</span> | |
| 110 | + <span>{{ parseTime(scope.row.successTime) }}</span> | |
| 127 | 111 | </template> |
| 128 | 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 | 114 | <template v-slot="scope"> |
| 131 | - <span>{{ parseTime(scope.row.successTime) }}</span> | |
| 115 | + <span>{{ scope.row.appName }}</span> | |
| 132 | 116 | </template> |
| 133 | 117 | </el-table-column> |
| 134 | 118 | <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> |
| ... | ... | @@ -143,107 +127,76 @@ |
| 143 | 127 | <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" |
| 144 | 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 | 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 | 139 | </el-descriptions> |
| 152 | - <el-divider></el-divider> | |
| 153 | 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 | 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 | 151 | </el-descriptions> |
| 160 | - <el-divider></el-divider> | |
| 161 | 152 | <el-descriptions :column="2" label-class-name="desc-label"> |
| 162 | 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 | 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 | 158 | </el-descriptions-item> |
| 159 | + </el-descriptions> | |
| 160 | + <el-descriptions :column="2" label-class-name="desc-label"> | |
| 173 | 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 | 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 | 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 | 168 | <el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item> |
| 180 | 169 | </el-descriptions> |
| 181 | - <el-divider></el-divider> | |
| 170 | + <!-- 分割线 --> | |
| 171 | + <el-divider /> | |
| 182 | 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 | 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 | 181 | </el-descriptions> |
| 195 | - <el-divider></el-divider> | |
| 182 | + <!-- 分割线 --> | |
| 183 | + <el-divider /> | |
| 196 | 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 | 185 | <el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item> |
| 200 | 186 | <el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item> |
| 201 | 187 | </el-descriptions> |
| 202 | - <br> | |
| 203 | 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 | 192 | </el-descriptions> |
| 207 | 193 | </el-dialog> |
| 208 | 194 | </div> |
| 209 | 195 | </template> |
| 210 | 196 | |
| 211 | 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 | 201 | export default { |
| 249 | 202 | name: "PayRefund", |
| ... | ... | @@ -267,73 +220,30 @@ export default { |
| 267 | 220 | pageNo: 1, |
| 268 | 221 | pageSize: 10, |
| 269 | 222 | appId: null, |
| 270 | - channelId: null, | |
| 271 | 223 | channelCode: null, |
| 272 | - orderId: null, | |
| 273 | - tradeNo: null, | |
| 274 | 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 | 226 | channelOrderNo: null, |
| 285 | 227 | channelRefundNo: null, |
| 286 | - channelErrorCode: null, | |
| 287 | - channelErrorMsg: null, | |
| 288 | - channelExtras: null, | |
| 289 | - expireTime: [], | |
| 290 | - successTime: [], | |
| 291 | - notifyTime: [], | |
| 228 | + status: null, | |
| 292 | 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 | 237 | created() { |
| 315 | - this.initTime(); | |
| 316 | 238 | this.getList(); |
| 317 | - this.handleGetMerchantListByName(null); | |
| 239 | + // 获得筛选项 | |
| 240 | + getAppList().then(response => { | |
| 241 | + this.appList = response.data; | |
| 242 | + }) | |
| 318 | 243 | }, |
| 319 | 244 | methods: { |
| 320 | - initTime(){ | |
| 321 | - this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")]; | |
| 322 | - }, | |
| 323 | 245 | /** 查询列表 */ |
| 324 | 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 | 247 | this.loading = true; |
| 338 | 248 | // 执行查询 |
| 339 | 249 | getRefundPage(this.queryParams).then(response => { |
| ... | ... | @@ -369,60 +279,13 @@ export default { |
| 369 | 279 | this.$download.excel(response, '退款订单.xls'); |
| 370 | 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 | 283 | handleQueryDetails(row) { |
| 420 | - this.refundDetail = JSON.parse(JSON.stringify(defaultRefundDetail)); | |
| 284 | + this.refundDetail = {}; | |
| 421 | 285 | getRefund(row.id).then(response => { |
| 422 | 286 | this.refundDetail = response.data; |
| 423 | 287 | this.open = true; |
| 424 | 288 | }); |
| 425 | - | |
| 426 | 289 | }, |
| 427 | 290 | } |
| 428 | 291 | }; | ... | ... |