mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-02-01 01:50:04 +08:00
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
This commit is contained in:
commit
a73e078593
@ -12,7 +12,6 @@ import org.springframework.context.annotation.Bean;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@EnableConfigurationProperties(PayProperties.class)
|
|
||||||
public class YudaoPayAutoConfiguration {
|
public class YudaoPayAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -79,14 +79,16 @@ public class PayOrderRespDTO {
|
|||||||
/**
|
/**
|
||||||
* 创建【WAITING】状态的订单返回
|
* 创建【WAITING】状态的订单返回
|
||||||
*/
|
*/
|
||||||
public PayOrderRespDTO(String displayMode, String displayContent,
|
public static PayOrderRespDTO waitingOf(String displayMode, String displayContent,
|
||||||
String outTradeNo, Object rawData) {
|
String outTradeNo, Object rawData) {
|
||||||
this.status = PayOrderStatusRespEnum.WAITING.getStatus();
|
PayOrderRespDTO respDTO = new PayOrderRespDTO();
|
||||||
this.displayMode = displayMode;
|
respDTO.status = PayOrderStatusRespEnum.WAITING.getStatus();
|
||||||
this.displayContent = displayContent;
|
respDTO.displayMode = displayMode;
|
||||||
|
respDTO.displayContent = displayContent;
|
||||||
// 相对通用的字段
|
// 相对通用的字段
|
||||||
this.outTradeNo = outTradeNo;
|
respDTO.outTradeNo = outTradeNo;
|
||||||
this.rawData = rawData;
|
respDTO.rawData = rawData;
|
||||||
|
return respDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.framework.pay.core.client.dto.refund;
|
package cn.iocoder.yudao.framework.pay.core.client.dto.refund;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -44,4 +45,71 @@ public class PayRefundRespDTO {
|
|||||||
*/
|
*/
|
||||||
private Object rawData;
|
private Object rawData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用渠道的错误码
|
||||||
|
*
|
||||||
|
* 注意:这里返回的是业务异常,而是不系统异常。
|
||||||
|
* 如果是系统异常,则会抛出 {@link PayException}
|
||||||
|
*/
|
||||||
|
private String channelErrorCode;
|
||||||
|
/**
|
||||||
|
* 调用渠道报错时,错误信息
|
||||||
|
*/
|
||||||
|
private String channelErrorMsg;
|
||||||
|
|
||||||
|
private PayRefundRespDTO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建【WAITING】状态的退款返回
|
||||||
|
*/
|
||||||
|
public static PayRefundRespDTO waitingOf(String channelRefundNo,
|
||||||
|
String outRefundNo, Object rawData) {
|
||||||
|
PayRefundRespDTO respDTO = new PayRefundRespDTO();
|
||||||
|
respDTO.status = PayRefundStatusRespEnum.WAITING.getStatus();
|
||||||
|
respDTO.channelRefundNo = channelRefundNo;
|
||||||
|
// 相对通用的字段
|
||||||
|
respDTO.outRefundNo = outRefundNo;
|
||||||
|
respDTO.rawData = rawData;
|
||||||
|
return respDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建【SUCCESS】状态的退款返回
|
||||||
|
*/
|
||||||
|
public static PayRefundRespDTO successOf(String channelRefundNo, LocalDateTime successTime,
|
||||||
|
String outRefundNo, Object rawData) {
|
||||||
|
PayRefundRespDTO respDTO = new PayRefundRespDTO();
|
||||||
|
respDTO.status = PayRefundStatusRespEnum.SUCCESS.getStatus();
|
||||||
|
respDTO.channelRefundNo = channelRefundNo;
|
||||||
|
respDTO.successTime = successTime;
|
||||||
|
// 相对通用的字段
|
||||||
|
respDTO.outRefundNo = outRefundNo;
|
||||||
|
respDTO.rawData = rawData;
|
||||||
|
return respDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建【FAILURE】状态的退款返回
|
||||||
|
*/
|
||||||
|
public static PayRefundRespDTO failureOf(String outRefundNo, Object rawData) {
|
||||||
|
return failureOf(null, null,
|
||||||
|
outRefundNo, rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建【FAILURE】状态的退款返回
|
||||||
|
*/
|
||||||
|
public static PayRefundRespDTO failureOf(String channelErrorCode, String channelErrorMsg,
|
||||||
|
String outRefundNo, Object rawData) {
|
||||||
|
PayRefundRespDTO respDTO = new PayRefundRespDTO();
|
||||||
|
respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus();
|
||||||
|
respDTO.channelErrorCode = channelErrorCode;
|
||||||
|
respDTO.channelErrorMsg = channelErrorMsg;
|
||||||
|
// 相对通用的字段
|
||||||
|
respDTO.outRefundNo = outRefundNo;
|
||||||
|
respDTO.rawData = rawData;
|
||||||
|
return respDTO;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,8 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
|||||||
try {
|
try {
|
||||||
return doParseOrderNotify(params, body);
|
return doParseOrderNotify(params, body);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("[parseOrderNotify][params({}) body({}) 解析失败]", params, body, ex);
|
log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]",
|
||||||
|
getId(), params, body, ex);
|
||||||
throw buildPayException(ex);
|
throw buildPayException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,6 +130,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
|||||||
|
|
||||||
protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
|
protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
|
||||||
|
try {
|
||||||
|
return doParseRefundNotify(params, body);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]",
|
||||||
|
getId(), params, body, ex);
|
||||||
|
throw buildPayException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body)
|
||||||
|
throws Throwable;
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
|
||||||
private PayException buildPayException(Throwable ex) {
|
private PayException buildPayException(Throwable ex) {
|
||||||
|
@ -3,8 +3,10 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
|||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
||||||
@ -29,7 +31,6 @@ import java.util.Objects;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
|
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款)
|
* 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款)
|
||||||
@ -74,10 +75,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
StandardCharsets.UTF_8.name(), config.getSignType());
|
StandardCharsets.UTF_8.name(), config.getSignType());
|
||||||
|
|
||||||
// 2. 解析订单的状态
|
// 2. 解析订单的状态
|
||||||
|
// 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂
|
||||||
String tradeStatus = bodyObj.get("trade_status");
|
String tradeStatus = bodyObj.get("trade_status");
|
||||||
Integer status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus()
|
Integer status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus()
|
||||||
: Objects.equals("TRADE_SUCCESS", tradeStatus) ? PayOrderStatusRespEnum.SUCCESS.getStatus()
|
: ObjectUtils.equalsAny(tradeStatus, "TRADE_FINISHED", "TRADE_SUCCESS") ? PayOrderStatusRespEnum.SUCCESS.getStatus()
|
||||||
: Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null;
|
: Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null;
|
||||||
|
// 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功
|
||||||
|
if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) {
|
||||||
|
status = PayOrderStatusRespEnum.REFUND.getStatus();
|
||||||
|
}
|
||||||
Assert.notNull(status, (Supplier<Throwable>) () -> {
|
Assert.notNull(status, (Supplier<Throwable>) () -> {
|
||||||
throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body));
|
throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body));
|
||||||
});
|
});
|
||||||
@ -94,7 +100,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
* @return 退款请求 Response
|
* @return 退款请求 Response
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
|
protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws AlipayApiException {
|
||||||
// 1.1 构建 AlipayTradeRefundModel 请求
|
// 1.1 构建 AlipayTradeRefundModel 请求
|
||||||
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
|
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
|
||||||
model.setOutTradeNo(reqDTO.getOutTradeNo());
|
model.setOutTradeNo(reqDTO.getOutTradeNo());
|
||||||
@ -104,31 +110,22 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
// 1.2 构建 AlipayTradePayRequest 请求
|
// 1.2 构建 AlipayTradePayRequest 请求
|
||||||
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
||||||
request.setBizModel(model);
|
request.setBizModel(model);
|
||||||
try {
|
|
||||||
// 2.1 执行请求
|
// 2.1 执行请求
|
||||||
AlipayTradeRefundResponse response = client.execute(request);
|
AlipayTradeRefundResponse response = client.execute(request);
|
||||||
// 2.2 创建返回结果
|
// 2.2 创建返回结果
|
||||||
PayRefundRespDTO refund = new PayRefundRespDTO()
|
// 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
|
||||||
.setOutRefundNo(reqDTO.getOutRefundNo())
|
// 另外,支付宝没有退款单号,所以不用设置
|
||||||
.setRawData(response);
|
if (response.isSuccess()) {
|
||||||
// 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
|
return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()),
|
||||||
// 另外,支付宝没有退款单号,所以不用设置
|
reqDTO.getOutRefundNo(), response);
|
||||||
if (response.isSuccess()) {
|
} else {
|
||||||
refund.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
|
||||||
.setSuccessTime(LocalDateTimeUtil.of(response.getGmtRefundPay()));
|
|
||||||
Assert.notNull(refund.getSuccessTime(), "退款成功时间不能为空");
|
|
||||||
} else {
|
|
||||||
refund.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus());
|
|
||||||
}
|
|
||||||
return refund;
|
|
||||||
} catch (AlipayApiException e) {
|
|
||||||
log.error("[doUnifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), e);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
|
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
|
||||||
// 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
|
// 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
|
||||||
// ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
|
// ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
|
||||||
// ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
|
// ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
|
||||||
|
@ -52,7 +52,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||||
}
|
}
|
||||||
return new PayOrderRespDTO(displayMode, "",
|
return PayOrderRespDTO.waitingOf(displayMode, "",
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||||
}
|
}
|
||||||
return new PayOrderRespDTO(displayMode, "",
|
return PayOrderRespDTO.waitingOf(displayMode, "",
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||||
}
|
}
|
||||||
return new PayOrderRespDTO(displayMode, response.getBody(),
|
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||||
}
|
}
|
||||||
return new PayOrderRespDTO(displayMode, response.getQrCode(),
|
return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return buildClosedPayOrderRespDTO(reqDTO, response);
|
return buildClosedPayOrderRespDTO(reqDTO, response);
|
||||||
}
|
}
|
||||||
return new PayOrderRespDTO(displayMode, response.getBody(),
|
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
|||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
|
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
|
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
|
||||||
@ -131,6 +130,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body);
|
WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body);
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
|
// 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂
|
||||||
Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ?
|
Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ?
|
||||||
PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
|
PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
|
||||||
return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
|
return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
|
||||||
@ -142,6 +142,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null);
|
WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null);
|
||||||
WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
|
// 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂
|
||||||
Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ?
|
Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ?
|
||||||
PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
|
PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus();
|
||||||
String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null;
|
String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null;
|
||||||
@ -163,9 +164,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
||||||
}
|
}
|
||||||
} catch (WxPayException e) {
|
} catch (WxPayException e) {
|
||||||
// todo 芋艿:异常的处理;
|
String errorCode = getErrorCode(e);
|
||||||
// throw buildUnifiedOrderException(null, e);
|
String errorMessage = getErrorMessage(e);
|
||||||
return null;
|
return PayRefundRespDTO.failureOf(errorCode, errorMessage,
|
||||||
|
reqDTO.getOutTradeNo(), e.getXmlString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,17 +183,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
// 2.1 执行请求
|
// 2.1 执行请求
|
||||||
WxPayRefundResult response = client.refundV2(request);
|
WxPayRefundResult response = client.refundV2(request);
|
||||||
// 2.2 创建返回结果
|
// 2.2 创建返回结果
|
||||||
PayRefundRespDTO refund = new PayRefundRespDTO()
|
|
||||||
.setOutRefundNo(reqDTO.getOutRefundNo())
|
|
||||||
.setRawData(response);
|
|
||||||
if (Objects.equals("SUCCESS", response.getResultCode())) {
|
if (Objects.equals("SUCCESS", response.getResultCode())) {
|
||||||
refund.setStatus(PayRefundStatusRespEnum.WAITING.getStatus())
|
return PayRefundRespDTO.waitingOf(response.getRefundId(),
|
||||||
.setChannelRefundNo(response.getRefundId());
|
reqDTO.getOutRefundNo(), response);
|
||||||
} else {
|
|
||||||
refund.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus());
|
|
||||||
}
|
}
|
||||||
// TODO 芋艿;异常的处理;
|
return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
|
||||||
return refund;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
||||||
@ -206,78 +202,51 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
// 2.1 执行请求
|
// 2.1 执行请求
|
||||||
WxPayRefundV3Result response = client.refundV3(request);
|
WxPayRefundV3Result response = client.refundV3(request);
|
||||||
// 2.2 创建返回结果
|
// 2.2 创建返回结果
|
||||||
PayRefundRespDTO refund = new PayRefundRespDTO()
|
|
||||||
.setOutRefundNo(reqDTO.getOutRefundNo())
|
|
||||||
.setRawData(response);
|
|
||||||
if (Objects.equals("SUCCESS", response.getStatus())) {
|
if (Objects.equals("SUCCESS", response.getStatus())) {
|
||||||
refund.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())
|
return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()),
|
||||||
.setChannelRefundNo(response.getRefundId())
|
reqDTO.getOutRefundNo(), response);
|
||||||
.setSuccessTime(parseDateV3(response.getSuccessTime()));
|
|
||||||
} else if (Objects.equals("PROCESSING", response.getStatus())) {
|
|
||||||
refund.setStatus(PayRefundStatusRespEnum.WAITING.getStatus())
|
|
||||||
.setChannelRefundNo(response.getRefundId());
|
|
||||||
} else {
|
|
||||||
refund.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus());
|
|
||||||
}
|
}
|
||||||
// TODO 芋艿;异常的处理;
|
if (Objects.equals("PROCESSING", response.getStatus())) {
|
||||||
return refund;
|
return PayRefundRespDTO.waitingOf(response.getRefundId(),
|
||||||
|
reqDTO.getOutRefundNo(), response);
|
||||||
|
}
|
||||||
|
return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
|
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) throws WxPayException {
|
||||||
try {
|
switch (config.getApiVersion()) {
|
||||||
// 微信支付 v2 回调结果处理
|
case API_VERSION_V2:
|
||||||
switch (config.getApiVersion()) {
|
return doParseRefundNotifyV2(body);
|
||||||
case API_VERSION_V2:
|
case WxPayClientConfig.API_VERSION_V3:
|
||||||
return parseRefundNotifyV2(body);
|
return parseRefundNotifyV3(body);
|
||||||
case WxPayClientConfig.API_VERSION_V3:
|
default:
|
||||||
return parseRefundNotifyV3(body);
|
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
|
||||||
}
|
|
||||||
} catch (WxPayException e) {
|
|
||||||
log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
// TODO 芋艿:缺一个异常翻译
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("DuplicatedCode")
|
private PayRefundRespDTO doParseRefundNotifyV2(String body) throws WxPayException {
|
||||||
private PayRefundRespDTO parseRefundNotifyV2(String body) throws WxPayException {
|
|
||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body);
|
WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body);
|
||||||
WxPayRefundNotifyResult.ReqInfo responseResult = response.getReqInfo();
|
WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
PayRefundRespDTO notify = new PayRefundRespDTO()
|
if (Objects.equals("SUCCESS", result.getRefundStatus())) {
|
||||||
.setChannelRefundNo(responseResult.getRefundId())
|
return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV2B(result.getSuccessTime()),
|
||||||
.setOutRefundNo(responseResult.getOutRefundNo())
|
result.getOutRefundNo(), response);
|
||||||
.setRawData(response);
|
|
||||||
if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) {
|
|
||||||
notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())
|
|
||||||
.setSuccessTime(parseDateV2B(responseResult.getSuccessTime()));
|
|
||||||
} else {
|
|
||||||
notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus());
|
|
||||||
}
|
}
|
||||||
return notify;
|
return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("DuplicatedCode")
|
|
||||||
private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException {
|
private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException {
|
||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null);
|
WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null);
|
||||||
WxPayRefundNotifyV3Result.DecryptNotifyResult responseResult = response.getResult();
|
WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
PayRefundRespDTO notify = new PayRefundRespDTO()
|
if (Objects.equals("SUCCESS", result.getRefundStatus())) {
|
||||||
.setChannelRefundNo(responseResult.getRefundId())
|
return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV3(result.getSuccessTime()),
|
||||||
.setOutRefundNo(responseResult.getOutRefundNo())
|
result.getOutRefundNo(), response);
|
||||||
.setRawData(response);
|
|
||||||
if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) {
|
|
||||||
notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus())
|
|
||||||
.setSuccessTime(parseDateV3(responseResult.getSuccessTime()));
|
|
||||||
} else {
|
|
||||||
notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus());
|
|
||||||
}
|
}
|
||||||
return notify;
|
return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
@ -67,7 +67,7 @@ public class WxBarPayClient extends AbstractWxPayClient {
|
|||||||
for (int i = 1; i < Byte.MAX_VALUE; i++) {
|
for (int i = 1; i < Byte.MAX_VALUE; i++) {
|
||||||
try {
|
try {
|
||||||
WxPayMicropayResult response = client.micropay(request);
|
WxPayMicropayResult response = client.micropay(request);
|
||||||
// 支付成功,例如说:1)用户输入了密码;2)
|
// 支付成功,例如说:1)用户输入了密码;2)用户免密支付
|
||||||
return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
|
return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
|
||||||
response.getOutTradeNo(), response)
|
response.getOutTradeNo(), response)
|
||||||
.setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode());
|
.setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode());
|
||||||
|
@ -48,7 +48,7 @@ public class WxNativePayClient extends AbstractWxPayClient {
|
|||||||
WxPayNativeOrderResult response = client.createOrder(request);
|
WxPayNativeOrderResult response = client.createOrder(request);
|
||||||
|
|
||||||
// 转换结果
|
// 转换结果
|
||||||
return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(),
|
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public class WxNativePayClient extends AbstractWxPayClient {
|
|||||||
String response = client.createOrderV3(TradeTypeEnum.NATIVE, request);
|
String response = client.createOrderV3(TradeTypeEnum.NATIVE, request);
|
||||||
|
|
||||||
// 转换结果
|
// 转换结果
|
||||||
return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response,
|
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response,
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class WxPubPayClient extends AbstractWxPayClient {
|
|||||||
WxPayMpOrderResult response = client.createOrder(request);
|
WxPayMpOrderResult response = client.createOrder(request);
|
||||||
|
|
||||||
// 转换结果
|
// 转换结果
|
||||||
return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
|
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ public class WxPubPayClient extends AbstractWxPayClient {
|
|||||||
WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request);
|
WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request);
|
||||||
|
|
||||||
// 转换结果
|
// 转换结果
|
||||||
return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
|
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response),
|
||||||
reqDTO.getOutTradeNo(), response);
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@ public enum PayOrderStatusRespEnum {
|
|||||||
|
|
||||||
WAITING(0, "未支付"),
|
WAITING(0, "未支付"),
|
||||||
SUCCESS(10, "支付成功"),
|
SUCCESS(10, "支付成功"),
|
||||||
CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款
|
REFUND(20, "已退款"),
|
||||||
|
CLOSED(30, "支付关闭"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Integer status;
|
private final Integer status;
|
||||||
|
@ -14,7 +14,7 @@ import java.util.Objects;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum PayRefundStatusRespEnum {
|
public enum PayRefundStatusRespEnum {
|
||||||
|
|
||||||
WAITING(0, "未退款"),
|
WAITING(0, "等待退款"),
|
||||||
SUCCESS(10, "退款成功"),
|
SUCCESS(10, "退款成功"),
|
||||||
FAILURE(20, "退款失败");
|
FAILURE(20, "退款失败");
|
||||||
|
|
||||||
@ -25,4 +25,8 @@ public enum PayRefundStatusRespEnum {
|
|||||||
return Objects.equals(status, SUCCESS.getStatus());
|
return Objects.equals(status, SUCCESS.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isFailure(Integer status) {
|
||||||
|
return Objects.equals(status, FAILURE.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.framework.excel.core.convert;
|
||||||
|
|
||||||
|
import com.alibaba.excel.converters.Converter;
|
||||||
|
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||||
|
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||||
|
import com.alibaba.excel.metadata.data.WriteCellData;
|
||||||
|
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额转换器
|
||||||
|
*
|
||||||
|
* 金额单位:分
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class MoneyConvert implements Converter<Integer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> supportJavaTypeKey() {
|
||||||
|
throw new UnsupportedOperationException("暂不支持,也不需要");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CellDataTypeEnum supportExcelTypeKey() {
|
||||||
|
throw new UnsupportedOperationException("暂不支持,也不需要");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WriteCellData<String> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
|
||||||
|
GlobalConfiguration globalConfiguration) {
|
||||||
|
BigDecimal result = BigDecimal.valueOf(value)
|
||||||
|
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
||||||
|
return new WriteCellData<>(result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,6 +55,9 @@ public class RandomUtils {
|
|||||||
}
|
}
|
||||||
return RandomUtil.randomInt();
|
return RandomUtil.randomInt();
|
||||||
});
|
});
|
||||||
|
// LocalDateTime
|
||||||
|
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class,
|
||||||
|
(dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime());
|
||||||
// Boolean
|
// Boolean
|
||||||
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> {
|
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> {
|
||||||
// 如果是 deleted 的字段,返回非删除
|
// 如果是 deleted 的字段,返回非删除
|
||||||
@ -82,7 +85,8 @@ public class RandomUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static LocalDateTime randomLocalDateTime() {
|
public static LocalDateTime randomLocalDateTime() {
|
||||||
return LocalDateTimeUtil.of(randomDate());
|
// 设置 Nano 为零的原因,避免 MySQL、H2 存储不到时间戳
|
||||||
|
return LocalDateTimeUtil.of(randomDate()).withNano(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Short randomShort() {
|
public static Short randomShort() {
|
||||||
|
@ -63,6 +63,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
|
|||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
|
||||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -344,7 +345,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
|||||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
||||||
if (payOrder == null) {
|
if (payOrder == null) {
|
||||||
log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
throw exception(cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验支付单已支付
|
// 校验支付单已支付
|
||||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||||
|
@ -7,13 +7,12 @@ package cn.iocoder.yudao.module.pay.enums;
|
|||||||
*/
|
*/
|
||||||
public interface DictTypeConstants {
|
public interface DictTypeConstants {
|
||||||
|
|
||||||
String CHANNEL_CODE = "pay_channel_code"; // 支付-渠道名
|
String CHANNEL_CODE = "pay_channel_code"; // 支付渠道编码
|
||||||
|
|
||||||
String ORDER_STATUS = "pay_order_status"; // 支付-订单-订单状态
|
String ORDER_STATUS = "pay_order_status"; // 支付渠道
|
||||||
String ORDER_NOTIFY_STATUS = "pay_order_notify_status"; // 支付-订单-订单回调商户状态
|
|
||||||
|
|
||||||
String ORDER_REFUND_STATUS = "pay_order_refund_status"; // 支付-订单-订单退款状态
|
String REFUND_STATUS = "pay_order_status"; // 退款状态
|
||||||
String REFUND_ORDER_STATUS = "pay_refund_order_status"; // 支付-退款订单-退款状态
|
|
||||||
String REFUND_ORDER_TYPE = "pay_refund_order_type"; // 支付-退款订单-退款类别
|
String NOTIFY_STATUS = "pay_notify_status"; // 回调状态
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,48 +10,46 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|||||||
public interface ErrorCodeConstants {
|
public interface ErrorCodeConstants {
|
||||||
|
|
||||||
// ========== APP 模块 1007000000 ==========
|
// ========== APP 模块 1007000000 ==========
|
||||||
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
|
ErrorCode APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
|
||||||
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
|
ErrorCode APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
|
||||||
ErrorCode PAY_APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
|
ErrorCode APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
|
||||||
ErrorCode PAY_APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
|
ErrorCode APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
|
||||||
|
|
||||||
// ========== CHANNEL 模块 1007001000 ==========
|
// ========== CHANNEL 模块 1007001000 ==========
|
||||||
ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
|
ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
|
||||||
ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
|
ErrorCode CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
|
||||||
ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");
|
ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
|
||||||
ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");
|
|
||||||
ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");
|
|
||||||
|
|
||||||
// ========== ORDER 模块 1007002000 ==========
|
// ========== ORDER 模块 1007002000 ==========
|
||||||
ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
|
ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
|
||||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
|
ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
|
||||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
|
ErrorCode ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
|
||||||
ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
|
ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
|
||||||
ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
|
ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
|
||||||
|
ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
|
||||||
|
|
||||||
// ========== ORDER 模块(拓展单) 1007003000 ==========
|
// ========== ORDER 模块(拓展单) 1007003000 ==========
|
||||||
ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
|
ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
|
||||||
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
|
ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
|
||||||
|
|
||||||
// ========== 支付模块(退款) 1007006000 ==========
|
// ========== 支付模块(退款) 1007006000 ==========
|
||||||
ErrorCode PAY_REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
||||||
ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
|
ErrorCode REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
|
||||||
ErrorCode PAY_REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
|
ErrorCode REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
|
||||||
ErrorCode PAY_REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
|
ErrorCode REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
|
||||||
ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
|
ErrorCode REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
|
||||||
ErrorCode PAY_REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
|
|
||||||
|
|
||||||
// ========== 示例订单 1007900000 ==========
|
// ========== 示例订单 1007900000 ==========
|
||||||
ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
|
ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
|
ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
|
ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
|
ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
|
ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
|
ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum PayNotifyStatusEnum {
|
public enum PayNotifyStatusEnum {
|
||||||
|
|
||||||
WAITING(1, "等待通知"),
|
WAITING(0, "等待通知"),
|
||||||
SUCCESS(2, "通知成功"),
|
SUCCESS(10, "通知成功"),
|
||||||
FAILURE(3, "通知失败"), // 多次尝试,彻底失败
|
FAILURE(20, "通知失败"), // 多次尝试,彻底失败
|
||||||
REQUEST_SUCCESS(4, "请求成功,但是结果失败"),
|
REQUEST_SUCCESS(21, "请求成功,但是结果失败"),
|
||||||
REQUEST_FAILURE(5, "请求失败"),
|
REQUEST_FAILURE(22, "请求失败"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.pay.enums.order;
|
package cn.iocoder.yudao.module.pay.enums.order;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -17,7 +18,8 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
|
|||||||
|
|
||||||
WAITING(0, "未支付"),
|
WAITING(0, "未支付"),
|
||||||
SUCCESS(10, "支付成功"),
|
SUCCESS(10, "支付成功"),
|
||||||
CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款
|
REFUND(20, "已退款"),
|
||||||
|
CLOSED(30, "支付关闭"), // 注意:全部退款后,还是 REFUND 状态
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Integer status;
|
private final Integer status;
|
||||||
@ -38,6 +40,17 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
|
|||||||
return Objects.equals(status, SUCCESS.getStatus());
|
return Objects.equals(status, SUCCESS.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否支付成功或者已退款
|
||||||
|
*
|
||||||
|
* @param status 状态
|
||||||
|
* @return 是否支付成功或者已退款
|
||||||
|
*/
|
||||||
|
public static boolean isSuccessOrRefund(Integer status) {
|
||||||
|
return ObjectUtils.equalsAny(status,
|
||||||
|
SUCCESS.getStatus(), REFUND.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否支付关闭
|
* 判断是否支付关闭
|
||||||
*
|
*
|
||||||
|
@ -25,4 +25,8 @@ public enum PayRefundStatusEnum {
|
|||||||
return Objects.equals(status, SUCCESS.getStatus());
|
return Objects.equals(status, SUCCESS.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isFailure(Integer status) {
|
||||||
|
return Objects.equals(status, FAILURE.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -97,4 +97,12 @@ public class PayAppController {
|
|||||||
return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels));
|
return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
@Operation(summary = "获得应用列表")
|
||||||
|
@PreAuthorize("@ss.hasPermission('pay:merchant:query')")
|
||||||
|
public CommonResult<List<PayAppRespVO>> getAppList() {
|
||||||
|
List<PayAppDO> appListDO = appService.getAppList();
|
||||||
|
return success(PayAppConvert.INSTANCE.convertList(appListDO));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,43 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.notify;
|
package cn.iocoder.yudao.module.pay.controller.admin.notify;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.convert.notify.PayNotifyTaskConvert;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.annotation.security.PermitAll;
|
import javax.annotation.security.PermitAll;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 支付通知")
|
@Tag(name = "管理后台 - 回调通知")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/pay/notify")
|
@RequestMapping("/pay/notify")
|
||||||
@Validated
|
@Validated
|
||||||
@ -31,6 +48,10 @@ public class PayNotifyController {
|
|||||||
private PayOrderService orderService;
|
private PayOrderService orderService;
|
||||||
@Resource
|
@Resource
|
||||||
private PayRefundService refundService;
|
private PayRefundService refundService;
|
||||||
|
@Resource
|
||||||
|
private PayNotifyService notifyService;
|
||||||
|
@Resource
|
||||||
|
private PayAppService appService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayClientFactory payClientFactory;
|
private PayClientFactory payClientFactory;
|
||||||
@ -47,7 +68,7 @@ public class PayNotifyController {
|
|||||||
PayClient payClient = payClientFactory.getPayClient(channelId);
|
PayClient payClient = payClientFactory.getPayClient(channelId);
|
||||||
if (payClient == null) {
|
if (payClient == null) {
|
||||||
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 解析通知数据
|
// 2. 解析通知数据
|
||||||
@ -68,7 +89,7 @@ public class PayNotifyController {
|
|||||||
PayClient payClient = payClientFactory.getPayClient(channelId);
|
PayClient payClient = payClientFactory.getPayClient(channelId);
|
||||||
if (payClient == null) {
|
if (payClient == null) {
|
||||||
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 解析通知数据
|
// 2. 解析通知数据
|
||||||
@ -77,4 +98,29 @@ public class PayNotifyController {
|
|||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-detail")
|
||||||
|
@Operation(summary = "获得回调通知的明细")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('pay:notify:query')")
|
||||||
|
public CommonResult<PayNotifyTaskDetailRespVO> getNotifyTaskDetail(@RequestParam("id") Long id) {
|
||||||
|
PayNotifyTaskDO task = notifyService.getNotifyTask(id);
|
||||||
|
if (task == null) {
|
||||||
|
return success(null);
|
||||||
|
}
|
||||||
|
// 拼接返回
|
||||||
|
PayAppDO app = appService.getApp(task.getAppId());
|
||||||
|
List<PayNotifyLogDO> logs = notifyService.getNotifyLogList(id);
|
||||||
|
return success(PayNotifyTaskConvert.INSTANCE.convert(task, app, logs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得回调通知分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('pay:notify:query')")
|
||||||
|
public CommonResult<PageResult<PayNotifyTaskRespVO>> getNotifyTaskPage(@Valid PayNotifyTaskPageReqVO pageVO) {
|
||||||
|
PageResult<PayNotifyTaskDO> pageResult = notifyService.getNotifyTaskPage(pageVO);
|
||||||
|
// 拼接返回
|
||||||
|
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayNotifyTaskDO::getAppId));
|
||||||
|
return success(PayNotifyTaskConvert.INSTANCE.convertPage(pageResult, appMap));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调通知 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||||
|
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PayNotifyTaskBaseVO {
|
||||||
|
|
||||||
|
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10636")
|
||||||
|
private Long appId;
|
||||||
|
|
||||||
|
@Schema(description = "通知类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||||
|
private Byte type;
|
||||||
|
|
||||||
|
@Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6722")
|
||||||
|
private Long dataId;
|
||||||
|
|
||||||
|
@Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Byte status;
|
||||||
|
|
||||||
|
@Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26697")
|
||||||
|
private String merchantOrderId;
|
||||||
|
|
||||||
|
@Schema(description = "下一次通知时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime nextNotifyTime;
|
||||||
|
|
||||||
|
@Schema(description = "最后一次执行时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime lastExecuteTime;
|
||||||
|
|
||||||
|
@Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Byte notifyTimes;
|
||||||
|
|
||||||
|
@Schema(description = "最大可通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Byte maxNotifyTimes;
|
||||||
|
|
||||||
|
@Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
|
||||||
|
private String notifyUrl;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 回调通知的明细 Response VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class PayNotifyTaskDetailRespVO extends PayNotifyTaskBaseVO {
|
||||||
|
|
||||||
|
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
@Schema(description = "应用名称", example = "wx_pay")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
@Schema(description = "回调日志列表")
|
||||||
|
private List<Log> logs;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 回调日志")
|
||||||
|
@Data
|
||||||
|
public static class Log {
|
||||||
|
|
||||||
|
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8848")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Byte status;
|
||||||
|
|
||||||
|
@Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Byte notifyTimes;
|
||||||
|
|
||||||
|
@Schema(description = "HTTP 响应结果", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String response;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 回调通知分页 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class PayNotifyTaskPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "应用编号", example = "10636")
|
||||||
|
private Long appId;
|
||||||
|
|
||||||
|
@Schema(description = "通知类型", example = "2")
|
||||||
|
private Byte type;
|
||||||
|
|
||||||
|
@Schema(description = "数据编号", example = "6722")
|
||||||
|
private Long dataId;
|
||||||
|
|
||||||
|
@Schema(description = "通知状态", example = "1")
|
||||||
|
private Byte status;
|
||||||
|
|
||||||
|
@Schema(description = "商户订单编号", example = "26697")
|
||||||
|
private String merchantOrderId;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.controller.admin.notify.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 回调通知 Response VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class PayNotifyTaskRespVO extends PayNotifyTaskBaseVO {
|
||||||
|
|
||||||
|
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "应用名称", example = "wx_pay")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
}
|
@ -1,20 +1,16 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.order;
|
package cn.iocoder.yudao.module.pay.controller.admin.order;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
|
||||||
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
|
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
@ -32,6 +28,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
|
|
||||||
@ -42,9 +39,7 @@ import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.E
|
|||||||
public class PayOrderController {
|
public class PayOrderController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderService payOrderService;
|
private PayOrderService orderService;
|
||||||
@Resource
|
|
||||||
private PayOrderExtensionService orderExtensionService;
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayAppService appService;
|
private PayAppService appService;
|
||||||
|
|
||||||
@ -53,40 +48,29 @@ public class PayOrderController {
|
|||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
||||||
public CommonResult<PayOrderRespVO> getOrder(@RequestParam("id") Long id) {
|
public CommonResult<PayOrderRespVO> getOrder(@RequestParam("id") Long id) {
|
||||||
return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id)));
|
return success(PayOrderConvert.INSTANCE.convert(orderService.getOrder(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 芋艿:看看怎么优化下;
|
|
||||||
@GetMapping("/get-detail")
|
@GetMapping("/get-detail")
|
||||||
@Operation(summary = "获得支付订单详情")
|
@Operation(summary = "获得支付订单详情")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
||||||
public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) {
|
||||||
PayOrderDO order = payOrderService.getOrder(id);
|
PayOrderDO order = orderService.getOrder(id);
|
||||||
if (ObjectUtil.isNull(order)) {
|
if (order == null) {
|
||||||
return success(new PayOrderDetailsRespVO());
|
return success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
PayAppDO appDO = appService.getApp(order.getAppId());
|
// 拼接返回
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(order.getChannelCode());
|
PayAppDO app = appService.getApp(order.getAppId());
|
||||||
|
PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId());
|
||||||
// TODO @aquan:文案,都是前端 format;
|
return success(PayOrderConvert.INSTANCE.convert(order, orderExtension, app));
|
||||||
PayOrderDetailsRespVO respVO = PayOrderConvert.INSTANCE.orderDetailConvert(order);
|
|
||||||
respVO.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
respVO.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
|
|
||||||
PayOrderExtensionDO extensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
|
|
||||||
if (ObjectUtil.isNotNull(extensionDO)) {
|
|
||||||
respVO.setPayOrderExtension(PayOrderConvert.INSTANCE.orderDetailExtensionConvert(extensionDO));
|
|
||||||
}
|
|
||||||
|
|
||||||
return success(respVO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/submit")
|
@PostMapping("/submit")
|
||||||
@Operation(summary = "提交支付订单")
|
@Operation(summary = "提交支付订单")
|
||||||
public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
|
public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
|
||||||
PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP());
|
PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP());
|
||||||
return success(respVO);
|
return success(respVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,62 +78,34 @@ public class PayOrderController {
|
|||||||
@Operation(summary = "获得支付订单分页")
|
@Operation(summary = "获得支付订单分页")
|
||||||
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
@PreAuthorize("@ss.hasPermission('pay:order:query')")
|
||||||
public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) {
|
public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) {
|
||||||
PageResult<PayOrderDO> pageResult = payOrderService.getOrderPage(pageVO);
|
PageResult<PayOrderDO> pageResult = orderService.getOrderPage(pageVO);
|
||||||
if (CollectionUtil.isEmpty(pageResult.getList())) {
|
if (CollectionUtil.isEmpty(pageResult.getList())) {
|
||||||
return success(new PageResult<>(pageResult.getTotal()));
|
return success(new PageResult<>(pageResult.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理应用ID数据
|
// 拼接返回
|
||||||
Map<Long, PayAppDO> appMap = appService.getAppMap(
|
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayOrderDO::getAppId));
|
||||||
CollectionUtils.convertList(pageResult.getList(), PayOrderDO::getAppId));
|
return success(PayOrderConvert.INSTANCE.convertPage(pageResult, appMap));
|
||||||
|
|
||||||
List<PayOrderPageItemRespVO> pageList = new ArrayList<>(pageResult.getList().size());
|
|
||||||
pageResult.getList().forEach(c -> {
|
|
||||||
PayAppDO appDO = appMap.get(c.getAppId());
|
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
|
|
||||||
|
|
||||||
PayOrderPageItemRespVO orderItem = PayOrderConvert.INSTANCE.pageConvertItemPage(c);
|
|
||||||
orderItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
orderItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
pageList.add(orderItem);
|
|
||||||
});
|
|
||||||
return success(new PageResult<>(pageList, pageResult.getTotal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
@GetMapping("/export-excel")
|
||||||
@Operation(summary = "导出支付订单Excel")
|
@Operation(summary = "导出支付订单 Excel")
|
||||||
@PreAuthorize("@ss.hasPermission('pay:order:export')")
|
@PreAuthorize("@ss.hasPermission('pay:order:export')")
|
||||||
@OperateLog(type = EXPORT)
|
@OperateLog(type = EXPORT)
|
||||||
public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO,
|
public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO,
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
List<PayOrderDO> list = payOrderService.getOrderList(exportReqVO);
|
List<PayOrderDO> list = orderService.getOrderList(exportReqVO);
|
||||||
if (CollectionUtil.isEmpty(list)) {
|
if (CollectionUtil.isEmpty(list)) {
|
||||||
ExcelUtils.write(response, "支付订单.xls", "数据",
|
ExcelUtils.write(response, "支付订单.xls", "数据",
|
||||||
PayOrderExcelVO.class, new ArrayList<>());
|
PayOrderExcelVO.class, new ArrayList<>());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理应用ID数据
|
// 拼接返回
|
||||||
Map<Long, PayAppDO> appMap = appService.getAppMap(
|
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(list, PayOrderDO::getAppId));
|
||||||
CollectionUtils.convertList(list, PayOrderDO::getAppId));
|
List<PayOrderExcelVO> excelList = PayOrderConvert.INSTANCE.convertList(list, appMap);
|
||||||
// 处理扩展订单数据
|
|
||||||
Map<Long, PayOrderExtensionDO> orderExtensionMap = orderExtensionService
|
|
||||||
.getOrderExtensionMap(CollectionUtils.convertList(list, PayOrderDO::getSuccessExtensionId));
|
|
||||||
|
|
||||||
List<PayOrderExcelVO> excelDatum = new ArrayList<>(list.size());
|
|
||||||
list.forEach(c -> {
|
|
||||||
PayAppDO appDO = appMap.get(c.getAppId());
|
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
|
|
||||||
PayOrderExtensionDO orderExtensionDO = orderExtensionMap.get(c.getSuccessExtensionId());
|
|
||||||
|
|
||||||
PayOrderExcelVO excelItem = PayOrderConvert.INSTANCE.excelConvert(c);
|
|
||||||
excelItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
excelItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
excelItem.setNo(ObjectUtil.isNotNull(orderExtensionDO) ? orderExtensionDO.getNo() : "");
|
|
||||||
excelDatum.add(excelItem);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "支付订单.xls", "数据", PayOrderExcelVO.class, excelDatum);
|
ExcelUtils.write(response, "支付订单.xls", "数据", PayOrderExcelVO.class, excelList);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,51 +17,47 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayOrderBaseVO {
|
public class PayOrderBaseVO {
|
||||||
|
|
||||||
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
@NotNull(message = "应用编号不能为空")
|
@NotNull(message = "应用编号不能为空")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号")
|
@Schema(description = "渠道编号", example = "2048")
|
||||||
private Long channelId;
|
private Long channelId;
|
||||||
|
|
||||||
@Schema(description = "渠道编码")
|
@Schema(description = "渠道编码", example = "wx_app")
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
|
||||||
@NotNull(message = "商户订单编号不能为空")
|
@NotNull(message = "商户订单编号不能为空")
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||||
@NotNull(message = "商品标题不能为空")
|
@NotNull(message = "商品标题不能为空")
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
@Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是土豆")
|
||||||
@NotNull(message = "商品描述不能为空")
|
@NotNull(message = "商品描述不能为空")
|
||||||
private String body;
|
private String body;
|
||||||
|
|
||||||
@Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay/notify")
|
||||||
@NotNull(message = "异步通知地址不能为空")
|
@NotNull(message = "异步通知地址不能为空")
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
|
|
||||||
@Schema(description = "通知商户支付结果的回调状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||||
@NotNull(message = "通知商户支付结果的回调状态不能为空")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "支付金额,单位:分不能为空")
|
@NotNull(message = "支付金额,单位:分不能为空")
|
||||||
private Long price;
|
private Long price;
|
||||||
|
|
||||||
@Schema(description = "渠道手续费,单位:百分比")
|
@Schema(description = "渠道手续费,单位:百分比", example = "10")
|
||||||
private Double channelFeeRate;
|
private Double channelFeeRate;
|
||||||
|
|
||||||
@Schema(description = "渠道手续金额,单位:分")
|
@Schema(description = "渠道手续金额,单位:分", example = "100")
|
||||||
private Long channelFeePrice;
|
private Integer channelFeePrice;
|
||||||
|
|
||||||
@Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotNull(message = "支付状态不能为空")
|
@NotNull(message = "支付状态不能为空")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||||
@NotNull(message = "用户 IP不能为空")
|
@NotNull(message = "用户 IP不能为空")
|
||||||
private String userIp;
|
private String userIp;
|
||||||
|
|
||||||
@ -74,29 +70,20 @@ public class PayOrderBaseVO {
|
|||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private LocalDateTime successTime;
|
private LocalDateTime successTime;
|
||||||
|
|
||||||
@Schema(description = "订单支付通知时间")
|
@Schema(description = "支付成功的订单拓展单编号", example = "50")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
private Long extensionId;
|
||||||
private LocalDateTime notifyTime;
|
|
||||||
|
|
||||||
@Schema(description = "支付成功的订单拓展单编号")
|
@Schema(description = "支付订单号", example = "2048888")
|
||||||
private Long successExtensionId;
|
private String no;
|
||||||
|
|
||||||
@Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "退款总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||||
@NotNull(message = "退款状态不能为空")
|
|
||||||
private Integer refundStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款次数", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "退款次数不能为空")
|
|
||||||
private Integer refundTimes;
|
|
||||||
|
|
||||||
@Schema(description = "退款总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "退款总金额,单位:分不能为空")
|
@NotNull(message = "退款总金额,单位:分不能为空")
|
||||||
private Long refundPrice;
|
private Long refundPrice;
|
||||||
|
|
||||||
@Schema(description = "渠道用户编号")
|
@Schema(description = "渠道用户编号", example = "2048")
|
||||||
private String channelUserId;
|
private String channelUserId;
|
||||||
|
|
||||||
@Schema(description = "渠道订单号")
|
@Schema(description = "渠道订单号", example = "4096")
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,32 +13,33 @@ import java.time.LocalDateTime;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayOrderDetailsRespVO extends PayOrderBaseVO {
|
public class PayOrderDetailsRespVO extends PayOrderBaseVO {
|
||||||
|
|
||||||
@Schema(description = "支付订单编号")
|
@Schema(description = "支付订单编号", required = true, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "应用名称")
|
@Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
|
||||||
private String appName;
|
private String appName;
|
||||||
|
|
||||||
@Schema(description = "渠道编号名称")
|
@Schema(description = "创建时间", required = true)
|
||||||
private String channelCodeName;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间", required = true)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单扩展
|
* 支付订单扩展
|
||||||
*/
|
*/
|
||||||
private PayOrderExtension payOrderExtension;
|
private PayOrderExtension extension;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "支付订单扩展")
|
@Schema(description = "支付订单扩展")
|
||||||
public static class PayOrderExtension {
|
public static class PayOrderExtension {
|
||||||
|
|
||||||
@Schema(description = "支付订单号")
|
@Schema(description = "支付订单号", required = true, example = "1024")
|
||||||
private String no;
|
private String no;
|
||||||
|
|
||||||
@Schema(description = "支付异步通知的内容")
|
@Schema(description = "支付异步通知的内容")
|
||||||
private String channelNotifyData;
|
private String channelNotifyData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.order.vo;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
|
||||||
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
|
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -9,78 +10,56 @@ import lombok.Data;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单Excel VO
|
* 支付订单 Excel VO
|
||||||
*
|
*
|
||||||
* @author aquan
|
* @author aquan
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PayOrderExcelVO {
|
public class PayOrderExcelVO {
|
||||||
|
|
||||||
@ExcelProperty("支付订单编号")
|
@ExcelProperty("编号")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ExcelProperty(value = "应用名称")
|
|
||||||
private String appName;
|
|
||||||
|
|
||||||
@ExcelProperty("商品标题")
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
@ExcelProperty("商户订单编号")
|
|
||||||
private String merchantOrderId;
|
|
||||||
|
|
||||||
@ExcelProperty("渠道订单号")
|
|
||||||
private String channelOrderNo;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "支付订单号")
|
|
||||||
private String no;
|
|
||||||
|
|
||||||
@ExcelProperty("支付金额,单位:元")
|
|
||||||
private String price;
|
|
||||||
|
|
||||||
@ExcelProperty("渠道手续金额,单位:元")
|
|
||||||
private String channelFeePrice;
|
|
||||||
|
|
||||||
@ExcelProperty("渠道手续费,单位:百分比")
|
|
||||||
private String channelFeeRate;
|
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.ORDER_STATUS)
|
|
||||||
@ExcelProperty(value = "支付状态", converter = DictConvert.class)
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.ORDER_NOTIFY_STATUS)
|
|
||||||
@ExcelProperty(value = "通知商户支付结果的回调状态", converter = DictConvert.class)
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@ExcelProperty("异步通知地址")
|
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "支付金额", converter = MoneyConvert.class)
|
||||||
|
private Integer price;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "退款金额", converter = MoneyConvert.class)
|
||||||
|
private Integer refundPrice;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "手续金额", converter = MoneyConvert.class)
|
||||||
|
private Integer channelFeePrice;
|
||||||
|
|
||||||
|
@ExcelProperty("商户单号")
|
||||||
|
private String merchantOrderId;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "支付单号")
|
||||||
|
private String no;
|
||||||
|
|
||||||
|
@ExcelProperty("渠道单号")
|
||||||
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "支付状态", converter = DictConvert.class)
|
||||||
|
@DictFormat(DictTypeConstants.ORDER_STATUS)
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "渠道编号名称", converter = DictConvert.class)
|
||||||
|
@DictFormat(DictTypeConstants.CHANNEL_CODE)
|
||||||
|
private String channelCode;
|
||||||
|
|
||||||
@ExcelProperty("订单支付成功时间")
|
@ExcelProperty("订单支付成功时间")
|
||||||
private LocalDateTime successTime;
|
private LocalDateTime successTime;
|
||||||
|
|
||||||
@ExcelProperty("订单失效时间")
|
@ExcelProperty("订单失效时间")
|
||||||
private LocalDateTime expireTime;
|
private LocalDateTime expireTime;
|
||||||
|
|
||||||
@ExcelProperty("订单支付通知时间")
|
@ExcelProperty(value = "应用名称")
|
||||||
private LocalDateTime notifyTime;
|
private String appName;
|
||||||
|
|
||||||
@ExcelProperty(value = "渠道编号名称")
|
@ExcelProperty("商品标题")
|
||||||
private String channelCodeName;
|
private String subject;
|
||||||
|
|
||||||
@ExcelProperty("用户 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.ORDER_REFUND_STATUS)
|
|
||||||
@ExcelProperty(value = "退款状态", converter = DictConvert.class)
|
|
||||||
private Integer refundStatus;
|
|
||||||
|
|
||||||
@ExcelProperty("退款次数")
|
|
||||||
private Integer refundTimes;
|
|
||||||
|
|
||||||
@ExcelProperty("退款总金额,单位:元")
|
|
||||||
private String refundPrice;
|
|
||||||
|
|
||||||
@ExcelProperty("商品描述")
|
@ExcelProperty("商品描述")
|
||||||
private String body;
|
private String body;
|
||||||
|
@ -12,75 +12,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayOrderExportReqVO {
|
public class PayOrderExportReqVO {
|
||||||
|
|
||||||
@Schema(description = "应用编号")
|
@Schema(description = "应用编号", example = "1024")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号")
|
@Schema(description = "渠道编码", example = "wx_app")
|
||||||
private Long channelId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道编码")
|
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "商户订单编号")
|
@Schema(description = "商户订单编号", example = "4096")
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商品标题")
|
@Schema(description = "渠道编号", example = "1888")
|
||||||
private String subject;
|
|
||||||
|
|
||||||
@Schema(description = "商品描述")
|
|
||||||
private String body;
|
|
||||||
|
|
||||||
@Schema(description = "异步通知地址")
|
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@Schema(description = "通知商户支付结果的回调状态")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位:分")
|
|
||||||
private Long price;
|
|
||||||
|
|
||||||
@Schema(description = "渠道手续费,单位:百分比")
|
|
||||||
private Double channelFeeRate;
|
|
||||||
|
|
||||||
@Schema(description = "渠道手续金额,单位:分")
|
|
||||||
private Long channelFeePrice;
|
|
||||||
|
|
||||||
@Schema(description = "支付状态")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "用户 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "订单失效时间")
|
|
||||||
private LocalDateTime[] expireTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "开始订单支付成功时间")
|
|
||||||
private LocalDateTime[] successTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "开始订单支付通知时间")
|
|
||||||
private LocalDateTime[] notifyTime;
|
|
||||||
|
|
||||||
@Schema(description = "支付成功的订单拓展单编号")
|
|
||||||
private Long successExtensionId;
|
|
||||||
|
|
||||||
@Schema(description = "退款状态")
|
|
||||||
private Integer refundStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款次数")
|
|
||||||
private Integer refundTimes;
|
|
||||||
|
|
||||||
@Schema(description = "退款总金额,单位:分")
|
|
||||||
private Long refundPrice;
|
|
||||||
|
|
||||||
@Schema(description = "渠道用户编号")
|
|
||||||
private String channelUserId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道订单号")
|
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
@Schema(description = "支付单号", example = "2014888")
|
||||||
|
private String no;
|
||||||
|
|
||||||
|
@Schema(description = "支付状态", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private LocalDateTime[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
@ -13,20 +13,13 @@ import java.time.LocalDateTime;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayOrderPageItemRespVO extends PayOrderBaseVO {
|
public class PayOrderPageItemRespVO extends PayOrderBaseVO {
|
||||||
|
|
||||||
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@Schema(description = "应用名称")
|
@Schema(description = "应用名称", example = "wx_pay")
|
||||||
private String appName;
|
private String appName;
|
||||||
|
|
||||||
@Schema(description = "渠道名称")
|
|
||||||
private String channelCodeName;
|
|
||||||
|
|
||||||
@Schema(description = "支付订单号")
|
|
||||||
private String no;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,75 +17,24 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayOrderPageReqVO extends PageParam {
|
public class PayOrderPageReqVO extends PageParam {
|
||||||
|
|
||||||
@Schema(description = "应用编号")
|
@Schema(description = "应用编号", example = "1024")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号")
|
@Schema(description = "渠道编码", example = "wx_app")
|
||||||
private Long channelId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道编码")
|
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "商户订单编号")
|
@Schema(description = "商户订单编号", example = "4096")
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商品标题")
|
@Schema(description = "渠道编号", example = "1888")
|
||||||
private String subject;
|
|
||||||
|
|
||||||
@Schema(description = "商品描述")
|
|
||||||
private String body;
|
|
||||||
|
|
||||||
@Schema(description = "异步通知地址")
|
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@Schema(description = "通知商户支付结果的回调状态")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位:分")
|
|
||||||
private Long price;
|
|
||||||
|
|
||||||
@Schema(description = "渠道手续费,单位:百分比")
|
|
||||||
private Double channelFeeRate;
|
|
||||||
|
|
||||||
@Schema(description = "渠道手续金额,单位:分")
|
|
||||||
private Long channelFeePrice;
|
|
||||||
|
|
||||||
@Schema(description = "支付状态")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "用户 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "订单失效时间")
|
|
||||||
private LocalDateTime[] expireTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "订单支付成功时间")
|
|
||||||
private LocalDateTime[] successTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "订单支付通知时间")
|
|
||||||
private LocalDateTime[] notifyTime;
|
|
||||||
|
|
||||||
@Schema(description = "支付成功的订单拓展单编号")
|
|
||||||
private Long successExtensionId;
|
|
||||||
|
|
||||||
@Schema(description = "退款状态")
|
|
||||||
private Integer refundStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款次数")
|
|
||||||
private Integer refundTimes;
|
|
||||||
|
|
||||||
@Schema(description = "退款总金额,单位:分")
|
|
||||||
private Long refundPrice;
|
|
||||||
|
|
||||||
@Schema(description = "渠道用户编号")
|
|
||||||
private String channelUserId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道订单号")
|
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
@Schema(description = "支付单号", example = "2014888")
|
||||||
|
private String no;
|
||||||
|
|
||||||
|
@Schema(description = "支付状态", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private LocalDateTime[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java
Executable file → Normal file
0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java
Executable file → Normal file
@ -1,24 +1,20 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.refund;
|
package cn.iocoder.yudao.module.pay.controller.admin.refund;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
|
||||||
import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
|
import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -35,6 +31,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 退款订单")
|
@Tag(name = "管理后台 - 退款订单")
|
||||||
@ -56,20 +53,13 @@ public class PayRefundController {
|
|||||||
@PreAuthorize("@ss.hasPermission('pay:refund:query')")
|
@PreAuthorize("@ss.hasPermission('pay:refund:query')")
|
||||||
public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) {
|
public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) {
|
||||||
PayRefundDO refund = refundService.getRefund(id);
|
PayRefundDO refund = refundService.getRefund(id);
|
||||||
if (ObjectUtil.isNull(refund)) {
|
if (refund == null) {
|
||||||
return success(new PayRefundDetailsRespVO());
|
return success(new PayRefundDetailsRespVO());
|
||||||
}
|
}
|
||||||
|
|
||||||
PayAppDO appDO = appService.getApp(refund.getAppId());
|
// 拼接数据
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(refund.getChannelCode());
|
PayAppDO app = appService.getApp(refund.getAppId());
|
||||||
PayOrderDO orderDO = orderService.getOrder(refund.getOrderId());
|
return success(PayRefundConvert.INSTANCE.convert(refund, app));
|
||||||
|
|
||||||
PayRefundDetailsRespVO refundDetail = PayRefundConvert.INSTANCE.refundDetailConvert(refund);
|
|
||||||
refundDetail.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
refundDetail.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
refundDetail.setSubject(orderDO.getSubject());
|
|
||||||
|
|
||||||
return success(refundDetail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@ -82,21 +72,8 @@ public class PayRefundController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理应用ID数据
|
// 处理应用ID数据
|
||||||
Map<Long, PayAppDO> appMap = appService.getAppMap(
|
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayRefundDO::getAppId));
|
||||||
CollectionUtils.convertList(pageResult.getList(), PayRefundDO::getAppId));
|
return success(PayRefundConvert.INSTANCE.convertPage(pageResult, appMap));
|
||||||
List<PayRefundPageItemRespVO> list = new ArrayList<>(pageResult.getList().size());
|
|
||||||
pageResult.getList().forEach(c -> {
|
|
||||||
PayAppDO appDO = appMap.get(c.getAppId());
|
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
|
|
||||||
|
|
||||||
PayRefundPageItemRespVO item = PayRefundConvert.INSTANCE.pageItemConvert(c);
|
|
||||||
|
|
||||||
item.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
item.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
list.add(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
return success(new PageResult<>(list, pageResult.getTotal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
@GetMapping("/export-excel")
|
||||||
@ -105,36 +82,18 @@ public class PayRefundController {
|
|||||||
@OperateLog(type = EXPORT)
|
@OperateLog(type = EXPORT)
|
||||||
public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO,
|
public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO,
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
|
|
||||||
List<PayRefundDO> list = refundService.getRefundList(exportReqVO);
|
List<PayRefundDO> list = refundService.getRefundList(exportReqVO);
|
||||||
if (CollectionUtil.isEmpty(list)) {
|
if (CollectionUtil.isEmpty(list)) {
|
||||||
ExcelUtils.write(response, "退款订单.xls", "数据",
|
ExcelUtils.write(response, "退款订单.xls", "数据",
|
||||||
PayRefundExcelVO.class, new ArrayList<>());
|
PayRefundExcelVO.class, new ArrayList<>());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理应用ID数据
|
// 拼接返回
|
||||||
Map<Long, PayAppDO> appMap = appService.getAppMap(
|
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(list, PayRefundDO::getAppId));
|
||||||
CollectionUtils.convertList(list, PayRefundDO::getAppId));
|
List<PayRefundExcelVO> excelList = PayRefundConvert.INSTANCE.convertList(list, appMap);
|
||||||
|
|
||||||
List<PayRefundExcelVO> excelDatum = new ArrayList<>(list.size());
|
|
||||||
// 处理商品名称数据
|
|
||||||
Map<Long, PayOrderDO> orderMap = orderService.getOrderSubjectMap(
|
|
||||||
CollectionUtils.convertList(list, PayRefundDO::getOrderId));
|
|
||||||
|
|
||||||
list.forEach(c -> {
|
|
||||||
PayAppDO appDO = appMap.get(c.getAppId());
|
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
|
|
||||||
|
|
||||||
PayRefundExcelVO excelItem = PayRefundConvert.INSTANCE.excelConvert(c);
|
|
||||||
excelItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
|
|
||||||
excelItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
|
|
||||||
excelItem.setSubject(orderMap.get(c.getOrderId()).getSubject());
|
|
||||||
|
|
||||||
excelDatum.add(excelItem);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelDatum);
|
ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelList);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用
|
* 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||||
@ -15,91 +12,67 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayRefundBaseVO {
|
public class PayRefundBaseVO {
|
||||||
|
|
||||||
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "外部退款号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110")
|
||||||
@NotNull(message = "应用编号不能为空")
|
private String no;
|
||||||
|
|
||||||
|
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||||
@NotNull(message = "渠道编号不能为空")
|
|
||||||
private Long channelId;
|
private Long channelId;
|
||||||
|
|
||||||
@Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_app")
|
||||||
@NotNull(message = "渠道编码不能为空")
|
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "支付订单编号 pay_order 表id", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
@NotNull(message = "支付订单编号 pay_order 表id不能为空")
|
|
||||||
private Long orderId;
|
private Long orderId;
|
||||||
|
|
||||||
@Schema(description = "交易订单号 pay_extension 表no 字段", requiredMode = Schema.RequiredMode.REQUIRED)
|
// ========== 商户相关字段 ==========
|
||||||
@NotNull(message = "交易订单号 pay_extension 表no 字段不能为空")
|
|
||||||
private String tradeNo;
|
|
||||||
|
|
||||||
@Schema(description = "商户订单编号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "225")
|
||||||
@NotNull(message = "商户订单编号(商户系统生成)不能为空")
|
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商户退款订单号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "商户退款订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
|
||||||
@NotNull(message = "商户退款订单号(商户系统生成)不能为空")
|
private String merchantRefundId;
|
||||||
private String merchantRefundNo;
|
|
||||||
|
|
||||||
@Schema(description = "异步通知商户地址", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotNull(message = "异步通知商户地址不能为空")
|
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
|
|
||||||
@Schema(description = "通知商户退款结果的回调状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
// ========== 退款相关字段 ==========
|
||||||
@NotNull(message = "通知商户退款结果的回调状态不能为空")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||||
@NotNull(message = "退款状态不能为空")
|
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "退款类型(部分退款,全部退款)", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||||
@NotNull(message = "退款类型(部分退款,全部退款)不能为空")
|
private Long payPrice;
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||||
@NotNull(message = "支付金额,单位分不能为空")
|
private Long refundPrice;
|
||||||
private Long payAmount;
|
|
||||||
|
|
||||||
@Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要退了")
|
||||||
@NotNull(message = "退款金额,单位分不能为空")
|
|
||||||
private Long refundAmount;
|
|
||||||
|
|
||||||
@Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "退款原因不能为空")
|
|
||||||
private String reason;
|
private String reason;
|
||||||
|
|
||||||
@Schema(description = "用户 IP")
|
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||||
private String userIp;
|
private String userIp;
|
||||||
|
|
||||||
@Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应", requiredMode = Schema.RequiredMode.REQUIRED)
|
// ========== 渠道相关字段 ==========
|
||||||
@NotNull(message = "渠道订单号,pay_order 中的channel_order_no 对应不能为空")
|
|
||||||
|
@Schema(description = "渠道订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "233")
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
@Schema(description = "渠道退款单号,渠道返回")
|
@Schema(description = "渠道退款单号", example = "2022")
|
||||||
private String channelRefundNo;
|
private String channelRefundNo;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误码")
|
@Schema(description = "退款成功时间")
|
||||||
|
private LocalDateTime successTime;
|
||||||
|
|
||||||
|
@Schema(description = "调用渠道的错误码")
|
||||||
private String channelErrorCode;
|
private String channelErrorCode;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误信息")
|
@Schema(description = "调用渠道的错误提示")
|
||||||
private String channelErrorMsg;
|
private String channelErrorMsg;
|
||||||
|
|
||||||
@Schema(description = "支付渠道的额外参数")
|
@Schema(description = "支付渠道的额外参数")
|
||||||
private String channelExtras;
|
private String channelNotifyData;
|
||||||
|
|
||||||
@Schema(description = "退款失效时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime expireTime;
|
|
||||||
|
|
||||||
@Schema(description = "退款成功时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime successTime;
|
|
||||||
|
|
||||||
@Schema(description = "退款通知时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime notifyTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 退款订单创建 Request VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class PayRefundCreateReqVO extends PayRefundBaseVO {
|
|
||||||
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 退款订单详情 Response VO")
|
@Schema(description = "管理后台 - 退款订单详情 Response VO")
|
||||||
@ -17,14 +16,11 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
|
|||||||
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "应用名称")
|
@Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
|
||||||
private String appName;
|
private String appName;
|
||||||
|
|
||||||
@Schema(description = "渠道编号名称")
|
@Schema(description = "支付订单", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String channelCodeName;
|
private Order order;
|
||||||
|
|
||||||
@NotNull(message = "商品标题不能为空")
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
@ -32,4 +28,13 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
|
|||||||
@Schema(description = "更新时间")
|
@Schema(description = "更新时间")
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 支付订单")
|
||||||
|
@Data
|
||||||
|
public static class Order {
|
||||||
|
|
||||||
|
@Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
|
||||||
|
private String subject;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
|
||||||
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
|
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -19,64 +20,42 @@ public class PayRefundExcelVO {
|
|||||||
@ExcelProperty("支付退款编号")
|
@ExcelProperty("支付退款编号")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ExcelProperty("商品名称")
|
@ExcelProperty("创建时间")
|
||||||
private String subject;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty(value = "应用名称")
|
@ExcelProperty(value = "支付金额", converter = MoneyConvert.class)
|
||||||
private String appName;
|
private Integer payPrice;
|
||||||
|
|
||||||
@ExcelProperty(value = "渠道编号名称")
|
@ExcelProperty(value = "退款金额", converter = MoneyConvert.class)
|
||||||
private String channelCodeName;
|
private Integer refundPrice;
|
||||||
|
|
||||||
@ExcelProperty("交易订单号")
|
@ExcelProperty("商户退款单号")
|
||||||
private String tradeNo;
|
private String merchantRefundId;
|
||||||
|
@ExcelProperty("退款单号")
|
||||||
|
private String no;
|
||||||
|
@ExcelProperty("渠道退款单号")
|
||||||
|
private String channelRefundNo;
|
||||||
|
|
||||||
@ExcelProperty("商户订单编号")
|
@ExcelProperty("商户支付单号")
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
@ExcelProperty("渠道支付单号")
|
||||||
|
private String channelOrderNo;
|
||||||
|
|
||||||
@ExcelProperty("商户退款订单号")
|
|
||||||
private String merchantRefundNo;
|
|
||||||
|
|
||||||
@ExcelProperty("异步通知商户地址")
|
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.ORDER_NOTIFY_STATUS)
|
|
||||||
@ExcelProperty(value = "商户退款结果回调状态", converter = DictConvert.class)
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.REFUND_ORDER_STATUS)
|
|
||||||
@ExcelProperty(value = "退款状态", converter = DictConvert.class)
|
@ExcelProperty(value = "退款状态", converter = DictConvert.class)
|
||||||
|
@DictFormat(DictTypeConstants.REFUND_STATUS)
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@DictFormat(DictTypeConstants.REFUND_ORDER_TYPE)
|
@ExcelProperty(value = "退款渠道", converter = DictConvert.class)
|
||||||
@ExcelProperty(value = "退款类型", converter = DictConvert.class)
|
@DictFormat(DictTypeConstants.CHANNEL_CODE)
|
||||||
private Integer type;
|
private String channelCode;
|
||||||
|
|
||||||
@ExcelProperty("支付金额,单位:元")
|
@ExcelProperty("成功时间")
|
||||||
private String payPrice;
|
private LocalDateTime successTime;
|
||||||
|
|
||||||
@ExcelProperty("退款金额,单位:元")
|
@ExcelProperty(value = "支付应用")
|
||||||
private String refundPrice;
|
private String appName;
|
||||||
|
|
||||||
@ExcelProperty("退款原因")
|
@ExcelProperty("退款原因")
|
||||||
private String reason;
|
private String reason;
|
||||||
|
|
||||||
@ExcelProperty("用户付款 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@ExcelProperty("渠道订单号")
|
|
||||||
private String channelOrderNo;
|
|
||||||
|
|
||||||
@ExcelProperty("渠道退款单号")
|
|
||||||
private String channelRefundNo;
|
|
||||||
|
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
@ExcelProperty("退款成功时间")
|
|
||||||
private LocalDateTime successTime;
|
|
||||||
|
|
||||||
@ExcelProperty("退款失效时间")
|
|
||||||
private LocalDateTime expireTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,77 +12,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayRefundExportReqVO {
|
public class PayRefundExportReqVO {
|
||||||
|
|
||||||
@Schema(description = "应用编号")
|
@Schema(description = "应用编号", example = "1024")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号")
|
@Schema(description = "渠道编码", example = "wx_app")
|
||||||
private Long channelId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道编码")
|
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "支付订单编号 pay_order 表id")
|
@Schema(description = "商户支付单号", example = "10")
|
||||||
private Long orderId;
|
|
||||||
|
|
||||||
@Schema(description = "交易订单号 pay_extension 表no 字段")
|
|
||||||
private String tradeNo;
|
|
||||||
|
|
||||||
@Schema(description = "商户订单编号(商户系统生成)")
|
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商户退款订单号(商户系统生成)")
|
@Schema(description = "商户退款单号", example = "20")
|
||||||
private String merchantRefundNo;
|
private String merchantRefundId;
|
||||||
|
|
||||||
@Schema(description = "异步通知商户地址")
|
@Schema(description = "渠道支付单号", example = "30")
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@Schema(description = "通知商户退款结果的回调状态")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款状态")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "退款类型(部分退款,全部退款)")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位分")
|
|
||||||
private Long payPrice;
|
|
||||||
|
|
||||||
@Schema(description = "退款金额,单位分")
|
|
||||||
private Long refundPrice;
|
|
||||||
|
|
||||||
@Schema(description = "退款原因")
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
@Schema(description = "用户 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应")
|
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
@Schema(description = "渠道退款单号,渠道返回")
|
@Schema(description = "渠道退款单号", example = "40")
|
||||||
private String channelRefundNo;
|
private String channelRefundNo;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误码")
|
@Schema(description = "退款状态", example = "0")
|
||||||
private String channelErrorCode;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误信息")
|
|
||||||
private String channelErrorMsg;
|
|
||||||
|
|
||||||
@Schema(description = "支付渠道的额外参数")
|
|
||||||
private String channelExtras;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款失效时间")
|
|
||||||
private LocalDateTime[] expireTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款成功时间")
|
|
||||||
private LocalDateTime[] successTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款通知时间")
|
|
||||||
private LocalDateTime[] notifyTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
|
@ -13,15 +13,12 @@ import java.time.LocalDateTime;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayRefundPageItemRespVO extends PayRefundBaseVO {
|
public class PayRefundPageItemRespVO extends PayRefundBaseVO {
|
||||||
|
|
||||||
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "应用名称")
|
@Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
|
||||||
private String appName;
|
private String appName;
|
||||||
|
|
||||||
@Schema(description = "渠道名称")
|
|
||||||
private String channelCodeName;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@ -17,77 +17,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayRefundPageReqVO extends PageParam {
|
public class PayRefundPageReqVO extends PageParam {
|
||||||
|
|
||||||
@Schema(description = "应用编号")
|
@Schema(description = "应用编号", example = "1024")
|
||||||
private Long appId;
|
private Long appId;
|
||||||
|
|
||||||
@Schema(description = "渠道编号")
|
@Schema(description = "渠道编码", example = "wx_app")
|
||||||
private Long channelId;
|
|
||||||
|
|
||||||
@Schema(description = "渠道编码")
|
|
||||||
private String channelCode;
|
private String channelCode;
|
||||||
|
|
||||||
@Schema(description = "支付订单编号 pay_order 表id")
|
@Schema(description = "商户支付单号", example = "10")
|
||||||
private Long orderId;
|
|
||||||
|
|
||||||
@Schema(description = "交易订单号 pay_extension 表no 字段")
|
|
||||||
private String tradeNo;
|
|
||||||
|
|
||||||
@Schema(description = "商户订单编号(商户系统生成)")
|
|
||||||
private String merchantOrderId;
|
private String merchantOrderId;
|
||||||
|
|
||||||
@Schema(description = "商户退款订单号(商户系统生成)")
|
@Schema(description = "商户退款单号", example = "20")
|
||||||
private String merchantRefundNo;
|
private String merchantRefundId;
|
||||||
|
|
||||||
@Schema(description = "异步通知商户地址")
|
@Schema(description = "渠道支付单号", example = "30")
|
||||||
private String notifyUrl;
|
|
||||||
|
|
||||||
@Schema(description = "通知商户退款结果的回调状态")
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
@Schema(description = "退款状态")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "退款类型(部分退款,全部退款)")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "支付金额,单位分")
|
|
||||||
private Long payPrice;
|
|
||||||
|
|
||||||
@Schema(description = "退款金额,单位分")
|
|
||||||
private Long refundPrice;
|
|
||||||
|
|
||||||
@Schema(description = "退款原因")
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
@Schema(description = "用户 IP")
|
|
||||||
private String userIp;
|
|
||||||
|
|
||||||
@Schema(description = "渠道订单号,pay_order 中的channel_order_no 对应")
|
|
||||||
private String channelOrderNo;
|
private String channelOrderNo;
|
||||||
|
|
||||||
@Schema(description = "渠道退款单号,渠道返回")
|
@Schema(description = "渠道退款单号", example = "40")
|
||||||
private String channelRefundNo;
|
private String channelRefundNo;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误码")
|
@Schema(description = "退款状态", example = "0")
|
||||||
private String channelErrorCode;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "渠道调用报错时,错误信息")
|
|
||||||
private String channelErrorMsg;
|
|
||||||
|
|
||||||
@Schema(description = "支付渠道的额外参数")
|
|
||||||
private String channelExtras;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款失效时间")
|
|
||||||
private LocalDateTime[] expireTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款成功时间")
|
|
||||||
private LocalDateTime[] successTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
@Schema(description = "退款通知时间")
|
|
||||||
private LocalDateTime[] notifyTime;
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 退款订单 Response VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class PayRefundRespVO extends PayRefundBaseVO {
|
|
||||||
|
|
||||||
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.*;
|
|
||||||
import javax.validation.constraints.*;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 退款订单更新 Request VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class PayRefundUpdateReqVO extends PayRefundBaseVO {
|
|
||||||
|
|
||||||
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "支付退款编号不能为空")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.convert.notify;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付通知 Convert
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PayNotifyTaskConvert {
|
||||||
|
|
||||||
|
PayNotifyTaskConvert INSTANCE = Mappers.getMapper(PayNotifyTaskConvert.class);
|
||||||
|
|
||||||
|
PayNotifyTaskRespVO convert(PayNotifyTaskDO bean);
|
||||||
|
|
||||||
|
default PageResult<PayNotifyTaskRespVO> convertPage(PageResult<PayNotifyTaskDO> page, Map<Long, PayAppDO> appMap){
|
||||||
|
PageResult<PayNotifyTaskRespVO> result = convertPage(page);
|
||||||
|
result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
PageResult<PayNotifyTaskRespVO> convertPage(PageResult<PayNotifyTaskDO> page);
|
||||||
|
|
||||||
|
default PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, PayAppDO app, List<PayNotifyLogDO> logs) {
|
||||||
|
PayNotifyTaskDetailRespVO respVO = convert(task, logs);
|
||||||
|
if (app != null) {
|
||||||
|
respVO.setAppName(app.getName());
|
||||||
|
}
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, List<PayNotifyLogDO> logs);
|
||||||
|
}
|
@ -1,20 +1,22 @@
|
|||||||
package cn.iocoder.yudao.module.pay.convert.order;
|
package cn.iocoder.yudao.module.pay.convert.order;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
|
||||||
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
|
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单 Convert
|
* 支付订单 Convert
|
||||||
@ -30,60 +32,32 @@ public interface PayOrderConvert {
|
|||||||
|
|
||||||
PayOrderRespDTO convert2(PayOrderDO order);
|
PayOrderRespDTO convert2(PayOrderDO order);
|
||||||
|
|
||||||
PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);
|
default PayOrderDetailsRespVO convert(PayOrderDO order, PayOrderExtensionDO orderExtension, PayAppDO app) {
|
||||||
|
PayOrderDetailsRespVO respVO = convertDetail(order);
|
||||||
PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
|
respVO.setExtension(convert(orderExtension));
|
||||||
|
if (app != null) {
|
||||||
List<PayOrderRespVO> convertList(List<PayOrderDO> list);
|
respVO.setAppName(app.getName());
|
||||||
|
|
||||||
PageResult<PayOrderRespVO> convertPage(PageResult<PayOrderDO> page);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单 DO 转自定义分页对象
|
|
||||||
*
|
|
||||||
* @param bean 订单DO
|
|
||||||
* @return 分页对象
|
|
||||||
*/
|
|
||||||
PayOrderPageItemRespVO pageConvertItemPage(PayOrderDO bean);
|
|
||||||
|
|
||||||
// TODO 芋艿:优化下 convert 逻辑
|
|
||||||
default PayOrderExcelVO excelConvert(PayOrderDO bean) {
|
|
||||||
if (bean == null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return respVO;
|
||||||
PayOrderExcelVO payOrderExcelVO = new PayOrderExcelVO();
|
|
||||||
|
|
||||||
payOrderExcelVO.setId(bean.getId());
|
|
||||||
payOrderExcelVO.setSubject(bean.getSubject());
|
|
||||||
payOrderExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
|
|
||||||
payOrderExcelVO.setChannelOrderNo(bean.getChannelOrderNo());
|
|
||||||
payOrderExcelVO.setStatus(bean.getStatus());
|
|
||||||
payOrderExcelVO.setNotifyStatus(bean.getNotifyStatus());
|
|
||||||
payOrderExcelVO.setNotifyUrl(bean.getNotifyUrl());
|
|
||||||
payOrderExcelVO.setCreateTime(bean.getCreateTime());
|
|
||||||
payOrderExcelVO.setSuccessTime(bean.getSuccessTime());
|
|
||||||
payOrderExcelVO.setExpireTime(bean.getExpireTime());
|
|
||||||
payOrderExcelVO.setNotifyTime(bean.getNotifyTime());
|
|
||||||
payOrderExcelVO.setUserIp(bean.getUserIp());
|
|
||||||
payOrderExcelVO.setRefundStatus(bean.getRefundStatus());
|
|
||||||
payOrderExcelVO.setRefundTimes(bean.getRefundTimes());
|
|
||||||
payOrderExcelVO.setBody(bean.getBody());
|
|
||||||
|
|
||||||
BigDecimal multiple = new BigDecimal(100);
|
|
||||||
|
|
||||||
payOrderExcelVO.setPrice(BigDecimal.valueOf(bean.getPrice())
|
|
||||||
.divide(multiple, 2, RoundingMode.HALF_UP).toString());
|
|
||||||
|
|
||||||
payOrderExcelVO.setChannelFeePrice(BigDecimal.valueOf(bean.getChannelFeePrice())
|
|
||||||
.divide(multiple, 2, RoundingMode.HALF_UP).toString());
|
|
||||||
payOrderExcelVO.setChannelFeeRate(java.math.BigDecimal.valueOf(bean.getChannelFeeRate())
|
|
||||||
.multiply(multiple).toString());
|
|
||||||
payOrderExcelVO.setRefundPrice(BigDecimal.valueOf(bean.getRefundPrice())
|
|
||||||
.divide(multiple, 2, RoundingMode.HALF_UP).toString());
|
|
||||||
|
|
||||||
return payOrderExcelVO;
|
|
||||||
}
|
}
|
||||||
|
PayOrderDetailsRespVO convertDetail(PayOrderDO bean);
|
||||||
|
PayOrderDetailsRespVO.PayOrderExtension convert(PayOrderExtensionDO bean);
|
||||||
|
|
||||||
|
default PageResult<PayOrderPageItemRespVO> convertPage(PageResult<PayOrderDO> page, Map<Long, PayAppDO> appMap) {
|
||||||
|
PageResult<PayOrderPageItemRespVO> result = convertPage(page);
|
||||||
|
result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
PageResult<PayOrderPageItemRespVO> convertPage(PageResult<PayOrderDO> page);
|
||||||
|
|
||||||
|
default List<PayOrderExcelVO> convertList(List<PayOrderDO> list, Map<Long, PayAppDO> appMap) {
|
||||||
|
return CollectionUtils.convertList(list, order -> {
|
||||||
|
PayOrderExcelVO excelVO = convertExcel(order);
|
||||||
|
MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName()));
|
||||||
|
return excelVO;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PayOrderExcelVO convertExcel(PayOrderDO bean);
|
||||||
|
|
||||||
PayOrderDO convert(PayOrderCreateReqDTO bean);
|
PayOrderDO convert(PayOrderCreateReqDTO bean);
|
||||||
|
|
||||||
|
@ -1,87 +1,56 @@
|
|||||||
package cn.iocoder.yudao.module.pay.convert.refund;
|
package cn.iocoder.yudao.module.pay.convert.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundDetailsRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExcelVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageItemRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PayRefundConvert {
|
public interface PayRefundConvert {
|
||||||
|
|
||||||
PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class);
|
PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class);
|
||||||
|
|
||||||
PayRefundDO convert(PayRefundCreateReqVO bean);
|
|
||||||
|
|
||||||
PayRefundDO convert(PayRefundUpdateReqVO bean);
|
default PayRefundDetailsRespVO convert(PayRefundDO refund, PayAppDO app) {
|
||||||
|
PayRefundDetailsRespVO respVO = convert(refund);
|
||||||
PayRefundRespVO convert(PayRefundDO bean);
|
if (app != null) {
|
||||||
|
respVO.setAppName(app.getName());
|
||||||
/**
|
|
||||||
* 退款订单 DO 转 退款详情订单 VO
|
|
||||||
*
|
|
||||||
* @param bean 退款订单 DO
|
|
||||||
* @return 退款详情订单 VO
|
|
||||||
*/
|
|
||||||
PayRefundDetailsRespVO refundDetailConvert(PayRefundDO bean);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款订单DO 转 分页退款条目VO
|
|
||||||
*
|
|
||||||
* @param bean 退款订单DO
|
|
||||||
* @return 分页退款条目VO
|
|
||||||
*/
|
|
||||||
PayRefundPageItemRespVO pageItemConvert(PayRefundDO bean);
|
|
||||||
|
|
||||||
List<PayRefundRespVO> convertList(List<PayRefundDO> list);
|
|
||||||
|
|
||||||
PageResult<PayRefundRespVO> convertPage(PageResult<PayRefundDO> page);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款订单DO 转 导出excel VO
|
|
||||||
*
|
|
||||||
* @param bean 退款订单DO
|
|
||||||
* @return 导出 excel VO
|
|
||||||
*/
|
|
||||||
default PayRefundExcelVO excelConvert(PayRefundDO bean) {
|
|
||||||
if (bean == null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return respVO;
|
||||||
PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();
|
|
||||||
|
|
||||||
payRefundExcelVO.setId(bean.getId());
|
|
||||||
payRefundExcelVO.setTradeNo(bean.getNo());
|
|
||||||
payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
|
|
||||||
// TODO 芋艿:晚点在改
|
|
||||||
// payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());
|
|
||||||
payRefundExcelVO.setNotifyUrl(bean.getNotifyUrl());
|
|
||||||
payRefundExcelVO.setNotifyStatus(bean.getNotifyStatus());
|
|
||||||
payRefundExcelVO.setStatus(bean.getStatus());
|
|
||||||
payRefundExcelVO.setReason(bean.getReason());
|
|
||||||
payRefundExcelVO.setUserIp(bean.getUserIp());
|
|
||||||
payRefundExcelVO.setChannelOrderNo(bean.getChannelOrderNo());
|
|
||||||
payRefundExcelVO.setChannelRefundNo(bean.getChannelRefundNo());
|
|
||||||
payRefundExcelVO.setSuccessTime(bean.getSuccessTime());
|
|
||||||
payRefundExcelVO.setCreateTime(bean.getCreateTime());
|
|
||||||
|
|
||||||
BigDecimal multiple = new BigDecimal(100);
|
|
||||||
payRefundExcelVO.setPayPrice(BigDecimal.valueOf(bean.getPayPrice())
|
|
||||||
.divide(multiple, 2, RoundingMode.HALF_UP).toString());
|
|
||||||
payRefundExcelVO.setRefundPrice(BigDecimal.valueOf(bean.getRefundPrice())
|
|
||||||
.divide(multiple, 2, RoundingMode.HALF_UP).toString());
|
|
||||||
|
|
||||||
return payRefundExcelVO;
|
|
||||||
}
|
}
|
||||||
|
PayRefundDetailsRespVO convert(PayRefundDO bean);
|
||||||
|
PayRefundDetailsRespVO.Order convert(PayOrderDO bean);
|
||||||
|
|
||||||
|
default PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page, Map<Long, PayAppDO> appMap) {
|
||||||
|
PageResult<PayRefundPageItemRespVO> result = convertPage(page);
|
||||||
|
result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page);
|
||||||
|
|
||||||
PayRefundDO convert(PayRefundCreateReqDTO bean);
|
PayRefundDO convert(PayRefundCreateReqDTO bean);
|
||||||
|
|
||||||
PayRefundRespDTO convert02(PayRefundDO bean);
|
PayRefundRespDTO convert02(PayRefundDO bean);
|
||||||
|
|
||||||
|
default List<PayRefundExcelVO> convertList(List<PayRefundDO> list, Map<Long, PayAppDO> appMap) {
|
||||||
|
return CollectionUtils.convertList(list, order -> {
|
||||||
|
PayRefundExcelVO excelVO = convertExcel(order);
|
||||||
|
MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName()));
|
||||||
|
return excelVO;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PayRefundExcelVO convertExcel(PayRefundDO bean);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import lombok.experimental.Accessors;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商户支付、退款等的通知
|
* 支付通知
|
||||||
* 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。
|
* 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
|
@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
|
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -71,12 +69,6 @@ public class PayOrderDO extends BaseDO {
|
|||||||
* 异步通知地址
|
* 异步通知地址
|
||||||
*/
|
*/
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
/**
|
|
||||||
* 通知商户支付结果的回调状态
|
|
||||||
*
|
|
||||||
* 枚举 {@link PayOrderNotifyStatusEnum}
|
|
||||||
*/
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
// ========== 订单相关字段 ==========
|
// ========== 订单相关字段 ==========
|
||||||
|
|
||||||
@ -93,7 +85,7 @@ public class PayOrderDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 渠道手续金额,单位:分
|
* 渠道手续金额,单位:分
|
||||||
*/
|
*/
|
||||||
private Long channelFeePrice;
|
private Integer channelFeePrice;
|
||||||
/**
|
/**
|
||||||
* 支付状态
|
* 支付状态
|
||||||
*
|
*
|
||||||
@ -112,28 +104,20 @@ public class PayOrderDO extends BaseDO {
|
|||||||
* 订单支付成功时间
|
* 订单支付成功时间
|
||||||
*/
|
*/
|
||||||
private LocalDateTime successTime;
|
private LocalDateTime successTime;
|
||||||
/**
|
|
||||||
* 订单支付通知时间,即支付渠道的通知时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime notifyTime;
|
|
||||||
/**
|
/**
|
||||||
* 支付成功的订单拓展单编号
|
* 支付成功的订单拓展单编号
|
||||||
*
|
*
|
||||||
* 关联 {@link PayOrderDO#getId()}
|
* 关联 {@link PayOrderExtensionDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long successExtensionId;
|
private Long extensionId;
|
||||||
|
/**
|
||||||
|
* 支付成功的外部订单号
|
||||||
|
*
|
||||||
|
* 关联 {@link PayOrderExtensionDO#getNo()}
|
||||||
|
*/
|
||||||
|
private String no;
|
||||||
|
|
||||||
// ========== 退款相关字段 ==========
|
// ========== 退款相关字段 ==========
|
||||||
/**
|
|
||||||
* 退款状态
|
|
||||||
*
|
|
||||||
* 枚举 {@link PayOrderRefundStatusEnum}
|
|
||||||
*/
|
|
||||||
private Integer refundStatus;
|
|
||||||
/**
|
|
||||||
* 退款次数
|
|
||||||
*/
|
|
||||||
private Integer refundTimes;
|
|
||||||
/**
|
/**
|
||||||
* 退款总金额,单位:分
|
* 退款总金额,单位:分
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +15,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* 支付订单拓展 DO
|
* 支付订单拓展 DO
|
||||||
*
|
*
|
||||||
|
* 每次调用支付渠道,都会生成一条对应记录
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
@ -89,12 +88,6 @@ public class PayRefundDO extends BaseDO {
|
|||||||
* 异步通知地址
|
* 异步通知地址
|
||||||
*/
|
*/
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
/**
|
|
||||||
* 通知商户退款结果的回调状态
|
|
||||||
*
|
|
||||||
* 枚举 {@link PayNotifyStatusEnum}
|
|
||||||
*/
|
|
||||||
private Integer notifyStatus;
|
|
||||||
|
|
||||||
// ========== 退款相关字段 ==========
|
// ========== 退款相关字段 ==========
|
||||||
/**
|
/**
|
||||||
@ -147,7 +140,7 @@ public class PayRefundDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private String channelErrorCode;
|
private String channelErrorCode;
|
||||||
/**
|
/**
|
||||||
* 调用渠道报错时,错误信息
|
* 调用渠道的错误提示
|
||||||
*/
|
*/
|
||||||
private String channelErrorMsg;
|
private String channelErrorMsg;
|
||||||
|
|
||||||
|
@ -4,6 +4,13 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> {
|
public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> {
|
||||||
|
|
||||||
|
default List<PayNotifyLogDO> selectListByTaskId(Long taskId) {
|
||||||
|
return selectList(PayNotifyLogDO::getTaskId, taskId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package cn.iocoder.yudao.module.pay.dal.mysql.notify;
|
package cn.iocoder.yudao.module.pay.dal.mysql.notify;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -21,10 +24,21 @@ public interface PayNotifyTaskMapper extends BaseMapperX<PayNotifyTaskDO> {
|
|||||||
* @return PayTransactionNotifyTaskDO 数组
|
* @return PayTransactionNotifyTaskDO 数组
|
||||||
*/
|
*/
|
||||||
default List<PayNotifyTaskDO> selectListByNotify() {
|
default List<PayNotifyTaskDO> selectListByNotify() {
|
||||||
return selectList(new QueryWrapper<PayNotifyTaskDO>()
|
return selectList(new LambdaQueryWrapper<PayNotifyTaskDO>()
|
||||||
.in("status", PayNotifyStatusEnum.WAITING.getStatus(), PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus(),
|
.in(PayNotifyTaskDO::getStatus, PayNotifyStatusEnum.WAITING.getStatus(),
|
||||||
PayNotifyStatusEnum.REQUEST_FAILURE.getStatus())
|
PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus())
|
||||||
.le("next_notify_time", LocalDateTime.now()));
|
.le(PayNotifyTaskDO::getNextNotifyTime, LocalDateTime.now()));
|
||||||
|
}
|
||||||
|
|
||||||
|
default PageResult<PayNotifyTaskDO> selectPage(PayNotifyTaskPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<PayNotifyTaskDO>()
|
||||||
|
.eqIfPresent(PayNotifyTaskDO::getAppId, reqVO.getAppId())
|
||||||
|
.eqIfPresent(PayNotifyTaskDO::getType, reqVO.getType())
|
||||||
|
.eqIfPresent(PayNotifyTaskDO::getDataId, reqVO.getDataId())
|
||||||
|
.eqIfPresent(PayNotifyTaskDO::getStatus, reqVO.getStatus())
|
||||||
|
.eqIfPresent(PayNotifyTaskDO::getMerchantOrderId, reqVO.getMerchantOrderId())
|
||||||
|
.betweenIfPresent(PayNotifyTaskDO::getCreateTime, reqVO.getCreateTime())
|
||||||
|
.orderByDesc(PayNotifyTaskDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,41 @@
|
|||||||
package cn.iocoder.yudao.module.pay.dal.mysql.order;
|
package cn.iocoder.yudao.module.pay.dal.mysql.order;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
|
public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
|
||||||
|
|
||||||
default PageResult<PayOrderDO> selectPage(PayOrderPageReqVO reqVO) {
|
default PageResult<PayOrderDO> selectPage(PayOrderPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new QueryWrapperX<PayOrderDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<PayOrderDO>()
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId())
|
||||||
.eqIfPresent("channel_id", reqVO.getChannelId())
|
.eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId())
|
||||||
.likeIfPresent("merchant_order_id", reqVO.getMerchantOrderId())
|
.likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo())
|
||||||
.eqIfPresent("notify_status", reqVO.getNotifyStatus())
|
.likeIfPresent(PayOrderDO::getNo, reqVO.getNo())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus())
|
||||||
.eqIfPresent("refund_status", reqVO.getRefundStatus())
|
.betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.likeIfPresent("channel_order_no", reqVO.getChannelOrderNo())
|
.orderByDesc(PayOrderDO::getId));
|
||||||
.betweenIfPresent("create_time", reqVO.getCreateTime())
|
|
||||||
.orderByDesc("id"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<PayOrderDO> selectList(PayOrderExportReqVO reqVO) {
|
default List<PayOrderDO> selectList(PayOrderExportReqVO reqVO) {
|
||||||
return selectList(new QueryWrapperX<PayOrderDO>()
|
return selectList(new LambdaQueryWrapperX<PayOrderDO>()
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId())
|
||||||
.eqIfPresent("channel_id", reqVO.getChannelId())
|
.eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId())
|
||||||
.likeIfPresent("merchant_order_id", reqVO.getMerchantOrderId())
|
.likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo())
|
||||||
.eqIfPresent("notify_status", reqVO.getNotifyStatus())
|
.likeIfPresent(PayOrderDO::getNo, reqVO.getNo())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus())
|
||||||
.eqIfPresent("refund_status", reqVO.getRefundStatus())
|
.betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.likeIfPresent("channel_order_no", reqVO.getChannelOrderNo())
|
.orderByDesc(PayOrderDO::getId));
|
||||||
.betweenIfPresent("create_time", reqVO.getCreateTime())
|
|
||||||
.orderByDesc("id"));
|
|
||||||
}
|
|
||||||
|
|
||||||
default List<PayOrderDO> findByIdListQueryOrderSubject(Collection<Long> idList) {
|
|
||||||
return selectList(new LambdaQueryWrapper<PayOrderDO>()
|
|
||||||
.select(PayOrderDO::getId, PayOrderDO::getSubject)
|
|
||||||
.in(PayOrderDO::getId, idList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default Long selectCountByAppId(Long appId) {
|
default Long selectCountByAppId(Long appId) {
|
||||||
@ -55,13 +43,13 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {
|
default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {
|
||||||
return selectOne(new QueryWrapper<PayOrderDO>().eq("app_id", appId)
|
return selectOne(PayOrderDO::getAppId, appId,
|
||||||
.eq("merchant_order_id", merchantOrderId));
|
PayOrderDO::getMerchantOrderId, merchantOrderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) {
|
default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) {
|
||||||
return update(update, new QueryWrapper<PayOrderDO>()
|
return update(update, new LambdaQueryWrapper<PayOrderDO>()
|
||||||
.eq("id", id).eq("status", status));
|
.eq(PayOrderDO::getId, id).eq(PayOrderDO::getStatus, status));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.refund;
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
@ -44,27 +43,29 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
|
default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<PayRefundDO>()
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
|
||||||
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
|
.likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
|
||||||
.eqIfPresent("type", reqVO.getType())
|
.likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
|
||||||
.eqIfPresent("notify_status", reqVO.getNotifyStatus())
|
.likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
|
||||||
.betweenIfPresent("create_time", reqVO.getCreateTime())
|
.eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
|
||||||
.orderByDesc("id"));
|
.betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
|
||||||
|
.orderByDesc(PayRefundDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<PayRefundDO> selectList(PayRefundExportReqVO reqVO) {
|
default List<PayRefundDO> selectList(PayRefundExportReqVO reqVO) {
|
||||||
return selectList(new QueryWrapperX<PayRefundDO>()
|
return selectList(new LambdaQueryWrapperX<PayRefundDO>()
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
|
||||||
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
|
.likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
|
||||||
.eqIfPresent("type", reqVO.getType())
|
.likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
|
||||||
.eqIfPresent("notify_status", reqVO.getNotifyStatus())
|
.likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
|
||||||
.betweenIfPresent("create_time", reqVO.getCreateTime())
|
.eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
|
||||||
.orderByDesc("id"));
|
.betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
|
||||||
|
.orderByDesc(PayRefundDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,12 @@ public interface RedisKeyConstants {
|
|||||||
"pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类
|
"pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类
|
||||||
RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
|
RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付序号的缓存
|
||||||
|
*
|
||||||
|
* KEY 格式:pay_no:{prefix}
|
||||||
|
* VALUE 数据格式:编号自增
|
||||||
|
*/
|
||||||
|
String PAY_NO = "pay_no";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.dal.redis.no;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil;import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付序号的 Redis DAO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public class PayNoRedisDAO {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成序号
|
||||||
|
*
|
||||||
|
* @param prefix 前缀
|
||||||
|
* @return 序号
|
||||||
|
*/
|
||||||
|
public String generate(String prefix) {
|
||||||
|
String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
|
||||||
|
Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
|
||||||
|
return noPrefix + no;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,29 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.enums.order;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单的通知状态枚举
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum PayOrderNotifyStatusEnum implements IntArrayValuable {
|
|
||||||
|
|
||||||
NO(0, "未通知"),
|
|
||||||
SUCCESS(10, "通知成功"),
|
|
||||||
FAILURE(20, "通知失败")
|
|
||||||
;
|
|
||||||
|
|
||||||
private final Integer status;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] array() {
|
|
||||||
return new int[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.enums.order;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单的退款状态枚举
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum PayOrderRefundStatusEnum implements IntArrayValuable {
|
|
||||||
|
|
||||||
NO(0, "未退款"),
|
|
||||||
PART(10, "部分退款"),
|
|
||||||
ALL(20, "全部退款")
|
|
||||||
;
|
|
||||||
|
|
||||||
private final Integer status;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] array() {
|
|
||||||
return new int[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,9 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.framework.pay.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableConfigurationProperties(PayProperties.class)
|
||||||
|
public class PayConfiguration {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.framework.pay.config;
|
package cn.iocoder.yudao.module.pay.framework.pay.config;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.hibernate.validator.constraints.URL;
|
import org.hibernate.validator.constraints.URL;
|
||||||
@ -12,6 +12,9 @@ import javax.validation.constraints.NotEmpty;
|
|||||||
@Data
|
@Data
|
||||||
public class PayProperties {
|
public class PayProperties {
|
||||||
|
|
||||||
|
private static final String ORDER_NO_PREFIX = "P";
|
||||||
|
private static final String REFUND_NO_PREFIX = "R";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付回调地址
|
* 支付回调地址
|
||||||
*
|
*
|
||||||
@ -34,4 +37,16 @@ public class PayProperties {
|
|||||||
@URL(message = "支付回调地址的格式必须是 URL")
|
@URL(message = "支付回调地址的格式必须是 URL")
|
||||||
private String refundNotifyUrl;
|
private String refundNotifyUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付订单 no 的前缀
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "支付订单 no 的前缀不能为空")
|
||||||
|
private String orderNoPrefix = ORDER_NO_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款订单 no 的前缀
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "退款订单 no 的前缀不能为空")
|
||||||
|
private String refundNoPrefix = REFUND_NO_PREFIX;
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 占位,无实际作用
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.pay.framework.pay.core;
|
@ -14,29 +14,29 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付应用信息 Service 接口
|
* 支付应用 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋艿
|
* @author 芋艿
|
||||||
*/
|
*/
|
||||||
public interface PayAppService {
|
public interface PayAppService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建支付应用信息
|
* 创建支付应用
|
||||||
*
|
*
|
||||||
* @param createReqVO 创建信息
|
* @param createReqVO 创建
|
||||||
* @return 编号
|
* @return 编号
|
||||||
*/
|
*/
|
||||||
Long createApp(@Valid PayAppCreateReqVO createReqVO);
|
Long createApp(@Valid PayAppCreateReqVO createReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新支付应用信息
|
* 更新支付应用
|
||||||
*
|
*
|
||||||
* @param updateReqVO 更新信息
|
* @param updateReqVO 更新
|
||||||
*/
|
*/
|
||||||
void updateApp(@Valid PayAppUpdateReqVO updateReqVO);
|
void updateApp(@Valid PayAppUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改应用信息状态
|
* 修改应用状态
|
||||||
*
|
*
|
||||||
* @param id 应用编号
|
* @param id 应用编号
|
||||||
* @param status 状态
|
* @param status 状态
|
||||||
@ -44,33 +44,40 @@ public interface PayAppService {
|
|||||||
void updateAppStatus(Long id, Integer status);
|
void updateAppStatus(Long id, Integer status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除支付应用信息
|
* 删除支付应用
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 编号
|
||||||
*/
|
*/
|
||||||
void deleteApp(Long id);
|
void deleteApp(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付应用信息
|
* 获得支付应用
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 编号
|
||||||
* @return 支付应用信息
|
* @return 支付应用
|
||||||
*/
|
*/
|
||||||
PayAppDO getApp(Long id);
|
PayAppDO getApp(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付应用信息列表
|
* 获得支付应用列表
|
||||||
*
|
*
|
||||||
* @param ids 编号
|
* @param ids 编号
|
||||||
* @return 支付应用信息列表
|
* @return 支付应用列表
|
||||||
*/
|
*/
|
||||||
List<PayAppDO> getAppList(Collection<Long> ids);
|
List<PayAppDO> getAppList(Collection<Long> ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付应用信息分页
|
* 获得支付应用列表
|
||||||
|
*
|
||||||
|
* @return 支付应用列表
|
||||||
|
*/
|
||||||
|
List<PayAppDO> getAppList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得支付应用分页
|
||||||
*
|
*
|
||||||
* @param pageReqVO 分页查询
|
* @param pageReqVO 分页查询
|
||||||
* @return 支付应用信息分页
|
* @return 支付应用分页
|
||||||
*/
|
*/
|
||||||
PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO);
|
PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO);
|
||||||
|
|
||||||
@ -91,7 +98,7 @@ public interface PayAppService {
|
|||||||
* 如果不合法,抛出 {@link ServiceException} 业务异常
|
* 如果不合法,抛出 {@link ServiceException} 业务异常
|
||||||
*
|
*
|
||||||
* @param id 应用编号
|
* @param id 应用编号
|
||||||
* @return 应用信息
|
* @return 应用
|
||||||
*/
|
*/
|
||||||
PayAppDO validPayApp(Long id);
|
PayAppDO validPayApp(Long id);
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.app;
|
package cn.iocoder.yudao.module.pay.service.app;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
|
||||||
@ -9,10 +8,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
|
|||||||
import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert;
|
import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
validateAppExists(id);
|
validateAppExists(id);
|
||||||
// 校验关联数据是否存在
|
// 校验关联数据是否存在
|
||||||
if (orderService.getOrderCountByAppId(id) > 0) {
|
if (orderService.getOrderCountByAppId(id) > 0) {
|
||||||
throw exception(PAY_APP_EXIST_ORDER_CANT_DELETE);
|
throw exception(APP_EXIST_ORDER_CANT_DELETE);
|
||||||
}
|
}
|
||||||
if (refundService.getRefundCountByAppId(id) > 0) {
|
if (refundService.getRefundCountByAppId(id) > 0) {
|
||||||
throw exception(PAY_APP_EXIST_REFUND_CANT_DELETE);
|
throw exception(APP_EXIST_REFUND_CANT_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
@ -89,7 +85,7 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
|
|
||||||
private void validateAppExists(Long id) {
|
private void validateAppExists(Long id) {
|
||||||
if (appMapper.selectById(id) == null) {
|
if (appMapper.selectById(id) == null) {
|
||||||
throw exception(PAY_APP_NOT_FOUND);
|
throw exception(APP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +99,11 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
return appMapper.selectBatchIds(ids);
|
return appMapper.selectBatchIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PayAppDO> getAppList() {
|
||||||
|
return appMapper.selectList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) {
|
public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) {
|
||||||
return appMapper.selectPage(pageReqVO);
|
return appMapper.selectPage(pageReqVO);
|
||||||
@ -113,11 +114,11 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
PayAppDO app = appMapper.selectById(id);
|
PayAppDO app = appMapper.selectById(id);
|
||||||
// 校验是否存在
|
// 校验是否存在
|
||||||
if (app == null) {
|
if (app == null) {
|
||||||
throw exception(ErrorCodeConstants.PAY_APP_NOT_FOUND);
|
throw exception(ErrorCodeConstants.APP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验是否禁用
|
// 校验是否禁用
|
||||||
if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
|
if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.PAY_APP_IS_DISABLE);
|
throw exception(ErrorCodeConstants.APP_IS_DISABLE);
|
||||||
}
|
}
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付渠道 Service 实现类
|
* 支付渠道 Service 实现类
|
||||||
@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
// 解析配置
|
// 解析配置
|
||||||
Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass();
|
Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass();
|
||||||
if (ObjectUtil.isNull(payClass)) {
|
if (ObjectUtil.isNull(payClass)) {
|
||||||
throw exception(CHANNEL_NOT_EXISTS);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
PayClientConfig config = JsonUtils.parseObject2(configStr, payClass);
|
PayClientConfig config = JsonUtils.parseObject2(configStr, payClass);
|
||||||
Assert.notNull(config);
|
Assert.notNull(config);
|
||||||
@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
private PayChannelDO validateChannelExists(Long id) {
|
private PayChannelDO validateChannelExists(Long id) {
|
||||||
PayChannelDO channel = channelMapper.selectById(id);
|
PayChannelDO channel = channelMapper.selectById(id);
|
||||||
if (channel == null) {
|
if (channel == null) {
|
||||||
throw exception(CHANNEL_NOT_EXISTS);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
|
|
||||||
private void validPayChannel(PayChannelDO channel) {
|
private void validPayChannel(PayChannelDO channel) {
|
||||||
if (channel == null) {
|
if (channel == null) {
|
||||||
throw exception(ErrorCodeConstants.PAY_CHANNEL_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
|
if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.PAY_CHANNEL_IS_DISABLE);
|
throw exception(CHANNEL_IS_DISABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
|||||||
new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
|
new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
|
||||||
.setPayChannelCode(payOrder.getChannelCode()));
|
.setPayChannelCode(payOrder.getChannelCode()));
|
||||||
if (updateCount == 0) {
|
if (updateCount == 0) {
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,44 +137,44 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
|||||||
// 1.1 校验订单是否存在
|
// 1.1 校验订单是否存在
|
||||||
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
throw exception(DEMO_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 1.2 校验订单未支付
|
// 1.2 校验订单未支付
|
||||||
if (order.getPayStatus()) {
|
if (order.getPayStatus()) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
|
||||||
id, toJsonString(order));
|
id, toJsonString(order));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||||
}
|
}
|
||||||
// 1.3 校验支付订单匹配
|
// 1.3 校验支付订单匹配
|
||||||
if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
|
if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
||||||
id, payOrderId, toJsonString(order));
|
id, payOrderId, toJsonString(order));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 校验支付单是否存在
|
// 2.1 校验支付单是否存在
|
||||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
||||||
if (payOrder == null) {
|
if (payOrder == null) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
throw exception(ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 2.2 校验支付单已支付
|
// 2.2 校验支付单已支付
|
||||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
||||||
id, payOrderId, toJsonString(payOrder));
|
id, payOrderId, toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
|
throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
|
||||||
}
|
}
|
||||||
// 2.3 校验支付金额一致
|
// 2.3 校验支付金额一致
|
||||||
if (notEqual(payOrder.getPrice(), order.getPrice())) {
|
if (notEqual(payOrder.getPrice(), order.getPrice())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
||||||
id, payOrderId, toJsonString(order), toJsonString(payOrder));
|
id, payOrderId, toJsonString(order), toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
|
throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
|
||||||
}
|
}
|
||||||
// 2.4 校验支付订单匹配(二次)
|
// 2.4 校验支付订单匹配(二次)
|
||||||
if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
|
if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
||||||
id, payOrderId, toJsonString(payOrder));
|
id, payOrderId, toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
return payOrder;
|
return payOrder;
|
||||||
}
|
}
|
||||||
@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
|||||||
// 校验订单是否存在
|
// 校验订单是否存在
|
||||||
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
throw exception(DEMO_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验订单是否支付
|
// 校验订单是否支付
|
||||||
if (!order.getPayStatus()) {
|
if (!order.getPayStatus()) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID);
|
throw exception(DEMO_ORDER_REFUND_FAIL_NOT_PAID);
|
||||||
}
|
}
|
||||||
// 校验订单是否已退款
|
// 校验订单是否已退款
|
||||||
if (order.getPayRefundId() != null) {
|
if (order.getPayRefundId() != null) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUNDED);
|
||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
|||||||
// 1.1 校验示例订单
|
// 1.1 校验示例订单
|
||||||
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
throw exception(DEMO_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 1.2 校验退款订单匹配
|
// 1.2 校验退款订单匹配
|
||||||
if (Objects.equals(order.getPayOrderId(), payRefundId)) {
|
if (Objects.equals(order.getPayOrderId(), payRefundId)) {
|
||||||
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
|
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
|
||||||
id, payRefundId, toJsonString(order));
|
id, payRefundId, toJsonString(order));
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 校验退款订单
|
// 2.1 校验退款订单
|
||||||
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
|
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
|
||||||
if (payRefund == null) {
|
if (payRefund == null) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 2.2
|
// 2.2
|
||||||
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
|
||||||
}
|
}
|
||||||
// 2.3 校验退款金额一致
|
// 2.3 校验退款金额一致
|
||||||
if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
|
if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
|
||||||
log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
|
log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
|
||||||
id, payRefundId, toJsonString(order), toJsonString(payRefund));
|
id, payRefundId, toJsonString(order), toJsonString(payRefund));
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
|
||||||
}
|
}
|
||||||
// 2.4 校验退款订单匹配(二次)
|
// 2.4 校验退款订单匹配(二次)
|
||||||
if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
|
if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
|
||||||
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
|
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
|
||||||
id, payRefundId, toJsonString(payRefund));
|
id, payRefundId, toJsonString(payRefund));
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
return payRefund;
|
return payRefund;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,58 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.notify;
|
package cn.iocoder.yudao.module.pay.service.notify;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付通知 Service 接口
|
* 回调通知 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public interface PayNotifyService {
|
public interface PayNotifyService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建支付通知任务
|
* 创建回调通知任务
|
||||||
*
|
*
|
||||||
* @param reqDTO 任务信息
|
* @param reqDTO 任务信息
|
||||||
*/
|
*/
|
||||||
void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO);
|
void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行支付通知
|
* 执行回调通知
|
||||||
*
|
*
|
||||||
* 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用
|
* 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用
|
||||||
* @return 通知数量
|
* @return 通知数量
|
||||||
*/
|
*/
|
||||||
int executeNotify() throws InterruptedException;
|
int executeNotify() throws InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得回调通知
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 回调通知
|
||||||
|
*/
|
||||||
|
PayNotifyTaskDO getNotifyTask(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得回调通知分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 回调通知分页
|
||||||
|
*/
|
||||||
|
PageResult<PayNotifyTaskDO> getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得回调日志列表
|
||||||
|
*
|
||||||
|
* @param taskId 任务编号
|
||||||
|
* @return 日志列表
|
||||||
|
*/
|
||||||
|
List<PayNotifyLogDO> getNotifyLogList(Long taskId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,13 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
@ -72,15 +74,15 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
private PayRefundService refundService;
|
private PayRefundService refundService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayNotifyTaskMapper payNotifyTaskMapper;
|
private PayNotifyTaskMapper notifyTaskMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private PayNotifyLogMapper payNotifyLogMapper;
|
private PayNotifyLogMapper notifyLogMapper;
|
||||||
|
|
||||||
@Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR)
|
@Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR)
|
||||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayNotifyLockRedisDAO payNotifyLockCoreRedisDAO;
|
private PayNotifyLockRedisDAO notifyLockCoreRedisDAO;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy // 循环依赖(自己依赖自己),避免报错
|
@Lazy // 循环依赖(自己依赖自己),避免报错
|
||||||
@ -105,7 +107,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 执行插入
|
// 执行插入
|
||||||
payNotifyTaskMapper.insert(task);
|
notifyTaskMapper.insert(task);
|
||||||
|
|
||||||
// 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务
|
// 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||||
@ -119,7 +121,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
@Override
|
@Override
|
||||||
public int executeNotify() throws InterruptedException {
|
public int executeNotify() throws InterruptedException {
|
||||||
// 获得需要通知的任务
|
// 获得需要通知的任务
|
||||||
List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify();
|
List<PayNotifyTaskDO> tasks = notifyTaskMapper.selectListByNotify();
|
||||||
if (CollUtil.isEmpty(tasks)) {
|
if (CollUtil.isEmpty(tasks)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -164,11 +166,11 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
*/
|
*/
|
||||||
public void executeNotify(PayNotifyTaskDO task) {
|
public void executeNotify(PayNotifyTaskDO task) {
|
||||||
// 分布式锁,避免并发问题
|
// 分布式锁,避免并发问题
|
||||||
payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
|
notifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
|
||||||
// 校验,当前任务是否已经被通知过
|
// 校验,当前任务是否已经被通知过
|
||||||
// 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。
|
// 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。
|
||||||
// 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断
|
// 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断
|
||||||
PayNotifyTaskDO dbTask = payNotifyTaskMapper.selectById(task.getId());
|
PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
|
||||||
if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) {
|
if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) {
|
||||||
log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]",
|
log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]",
|
||||||
JsonUtils.toJsonString(task), dbTask.getNotifyTimes());
|
JsonUtils.toJsonString(task), dbTask.getNotifyTimes());
|
||||||
@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
// 记录 PayNotifyLog 日志
|
// 记录 PayNotifyLog 日志
|
||||||
String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
|
String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
|
||||||
JsonUtils.toJsonString(invokeResult);
|
JsonUtils.toJsonString(invokeResult);
|
||||||
payNotifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
|
notifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
|
||||||
.notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
|
.notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,22 +252,37 @@ public class PayNotifyServiceImpl implements PayNotifyService {
|
|||||||
// 情况一:调用成功
|
// 情况一:调用成功
|
||||||
if (invokeResult != null && invokeResult.isSuccess()) {
|
if (invokeResult != null && invokeResult.isSuccess()) {
|
||||||
updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
|
updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
|
||||||
payNotifyTaskMapper.updateById(updateTask);
|
notifyTaskMapper.updateById(updateTask);
|
||||||
return updateTask.getStatus();
|
return updateTask.getStatus();
|
||||||
}
|
}
|
||||||
// 情况二:调用失败、调用异常
|
// 情况二:调用失败、调用异常
|
||||||
// 2.1 超过最大回调次数
|
// 2.1 超过最大回调次数
|
||||||
if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
|
if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
|
||||||
updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
|
updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
|
||||||
payNotifyTaskMapper.updateById(updateTask);
|
notifyTaskMapper.updateById(updateTask);
|
||||||
return updateTask.getStatus();
|
return updateTask.getStatus();
|
||||||
}
|
}
|
||||||
// 2.2 未超过最大回调次数
|
// 2.2 未超过最大回调次数
|
||||||
updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])));
|
updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])));
|
||||||
updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
|
updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
|
||||||
: PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
|
: PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
|
||||||
payNotifyTaskMapper.updateById(updateTask);
|
notifyTaskMapper.updateById(updateTask);
|
||||||
return updateTask.getStatus();
|
return updateTask.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayNotifyTaskDO getNotifyTask(Long id) {
|
||||||
|
return notifyTaskMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<PayNotifyTaskDO> getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO) {
|
||||||
|
return notifyTaskMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PayNotifyLogDO> getNotifyLogList(Long taskId) {
|
||||||
|
return notifyLogMapper.selectListByTaskId(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.order;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
// TODO 芋艿:合并到 PayOrder 里;
|
|
||||||
/**
|
|
||||||
* 支付订单 Service 接口
|
|
||||||
*
|
|
||||||
* @author aquan
|
|
||||||
*/
|
|
||||||
public interface PayOrderExtensionService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得支付订单
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 支付订单
|
|
||||||
*/
|
|
||||||
PayOrderExtensionDO getOrderExtension(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得支付订单
|
|
||||||
* 列表
|
|
||||||
*
|
|
||||||
* @param ids 编号
|
|
||||||
* @return 支付订单
|
|
||||||
* 列表
|
|
||||||
*/
|
|
||||||
List<PayOrderExtensionDO> getOrderExtensionList(Collection<Long> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据订单成功的 扩展订单ID 查询所有的扩展订单转 成 map 返回
|
|
||||||
*
|
|
||||||
* @param successExtensionIdList 订单 ID 集合
|
|
||||||
* @return 订单扩展 map 集合
|
|
||||||
*/
|
|
||||||
default Map<Long, PayOrderExtensionDO> getOrderExtensionMap(Collection<Long> successExtensionIdList) {
|
|
||||||
List<PayOrderExtensionDO> list = getOrderExtensionList(successExtensionIdList);
|
|
||||||
return CollectionUtils.convertMap(list, PayOrderExtensionDO::getId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.order;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单 Service 实现类
|
|
||||||
*
|
|
||||||
* @author aquan
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class PayOrderExtensionServiceImpl implements PayOrderExtensionService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PayOrderExtensionMapper orderExtensionMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PayOrderExtensionDO getOrderExtension(Long id) {
|
|
||||||
return orderExtensionMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<PayOrderExtensionDO> getOrderExtensionList(Collection<Long> ids) {
|
|
||||||
return orderExtensionMapper.selectBatchIds(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.order;
|
package cn.iocoder.yudao.module.pay.service.order;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
||||||
@ -9,12 +8,11 @@ import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
|||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单 Service 接口
|
* 支付订单 Service 接口
|
||||||
@ -49,44 +47,21 @@ public interface PayOrderService {
|
|||||||
Long getOrderCountByAppId(Long appId);
|
Long getOrderCountByAppId(Long appId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付订单
|
* 获得支付订单分页
|
||||||
* 分页
|
|
||||||
*
|
*
|
||||||
* @param pageReqVO 分页查询
|
* @param pageReqVO 分页查询
|
||||||
* @return 支付订单
|
* @return 支付订单分页
|
||||||
* 分页
|
|
||||||
*/
|
*/
|
||||||
PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO);
|
PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付订单
|
* 获得支付订单列表, 用于 Excel 导出
|
||||||
* 列表, 用于 Excel 导出
|
|
||||||
*
|
*
|
||||||
* @param exportReqVO 查询条件
|
* @param exportReqVO 查询条件
|
||||||
* @return 支付订单
|
* @return 支付订单列表
|
||||||
* 列表
|
|
||||||
*/
|
*/
|
||||||
List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
|
List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 ID 集合获取只包含商品名称的订单集合
|
|
||||||
*
|
|
||||||
* @param idList 订单 ID 集合
|
|
||||||
* @return 只包含商品名称的订单集合
|
|
||||||
*/
|
|
||||||
List<PayOrderDO> getOrderSubjectList(Collection<Long> idList);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据订单 ID 集合获取订单商品名称Map集合
|
|
||||||
*
|
|
||||||
* @param ids 订单 ID 集合
|
|
||||||
* @return 订单商品 map 集合
|
|
||||||
*/
|
|
||||||
default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {
|
|
||||||
List<PayOrderDO> list = getOrderSubjectList(ids);
|
|
||||||
return CollectionUtils.convertMap(list, PayOrderDO::getId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建支付单
|
* 创建支付单
|
||||||
*
|
*
|
||||||
@ -122,4 +97,12 @@ public interface PayOrderService {
|
|||||||
*/
|
*/
|
||||||
void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
|
void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得支付订单
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 支付订单
|
||||||
|
*/
|
||||||
|
PayOrderExtensionDO getOrderExtension(Long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.order;
|
package cn.iocoder.yudao.module.pay.service.order;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.lang.Pair;
|
import cn.hutool.core.lang.Pair;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
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;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.util.MoneyUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -69,6 +66,8 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
private PayOrderMapper orderMapper;
|
private PayOrderMapper orderMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderExtensionMapper orderExtensionMapper;
|
private PayOrderExtensionMapper orderExtensionMapper;
|
||||||
|
@Resource
|
||||||
|
private PayNoRedisDAO noRedisDAO;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayAppService appService;
|
private PayAppService appService;
|
||||||
@ -102,12 +101,6 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
return orderMapper.selectList(exportReqVO);
|
return orderMapper.selectList(exportReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @艿艿:需要优化。不确定这个方法的作用
|
|
||||||
@Override
|
|
||||||
public List<PayOrderDO> getOrderSubjectList(Collection<Long> idList) {
|
|
||||||
return orderMapper.findByIdListQueryOrderSubject(idList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createOrder(PayOrderCreateReqDTO reqDTO) {
|
public Long createOrder(PayOrderCreateReqDTO reqDTO) {
|
||||||
// 校验 App
|
// 校验 App
|
||||||
@ -125,11 +118,11 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
// 创建支付交易单
|
// 创建支付交易单
|
||||||
order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId())
|
order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId())
|
||||||
// 商户相关字段
|
// 商户相关字段
|
||||||
.setNotifyUrl(app.getOrderNotifyUrl()).setNotifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
|
.setNotifyUrl(app.getOrderNotifyUrl())
|
||||||
// 订单相关字段
|
// 订单相关字段
|
||||||
.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
// 退款相关字段
|
// 退款相关字段
|
||||||
.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0);
|
.setRefundPrice(0);
|
||||||
orderMapper.insert(order);
|
orderMapper.insert(order);
|
||||||
return order.getId();
|
return order.getId();
|
||||||
}
|
}
|
||||||
@ -143,8 +136,9 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||||
|
|
||||||
// 2. 插入 PayOrderExtensionDO
|
// 2. 插入 PayOrderExtensionDO
|
||||||
|
String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
|
||||||
PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
|
PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
|
||||||
.setOrderId(order.getId()).setNo(generateOrderExtensionNo())
|
.setOrderId(order.getId()).setNo(no)
|
||||||
.setChannelId(channel.getId()).setChannelCode(channel.getCode())
|
.setChannelId(channel.getId()).setChannelCode(channel.getCode())
|
||||||
.setStatus(PayOrderStatusEnum.WAITING.getStatus());
|
.setStatus(PayOrderStatusEnum.WAITING.getStatus());
|
||||||
orderExtensionMapper.insert(orderExtension);
|
orderExtensionMapper.insert(orderExtension);
|
||||||
@ -162,10 +156,10 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
|
|
||||||
// 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
|
// 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
|
||||||
if (unifiedOrderResp != null) {
|
if (unifiedOrderResp != null) {
|
||||||
notifyPayOrder(channel, unifiedOrderResp);
|
getSelf().notifyOrder(channel, unifiedOrderResp);
|
||||||
// 如有渠道错误码,则抛出业务异常,提示用户
|
// 如有渠道错误码,则抛出业务异常,提示用户
|
||||||
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
|
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
|
||||||
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
|
throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
|
||||||
unifiedOrderResp.getChannelErrorMsg());
|
unifiedOrderResp.getChannelErrorMsg());
|
||||||
}
|
}
|
||||||
// 此处需要读取最新的状态
|
// 此处需要读取最新的状态
|
||||||
@ -177,13 +171,13 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
private PayOrderDO validateOrderCanSubmit(Long id) {
|
private PayOrderDO validateOrderCanSubmit(Long id) {
|
||||||
PayOrderDO order = orderMapper.selectById(id);
|
PayOrderDO order = orderMapper.selectById(id);
|
||||||
if (order == null) { // 是否存在
|
if (order == null) { // 是否存在
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
throw exception(ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
|
if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
|
||||||
throw exception(PAY_ORDER_IS_EXPIRED);
|
throw exception(ORDER_IS_EXPIRED);
|
||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
@ -196,7 +190,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -211,61 +205,22 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
return payProperties.getOrderNotifyUrl() + "/" + channel.getId();
|
return payProperties.getOrderNotifyUrl() + "/" + channel.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateOrderExtensionNo() {
|
|
||||||
// wx
|
|
||||||
// 2014
|
|
||||||
// 10
|
|
||||||
// 27
|
|
||||||
// 20
|
|
||||||
// 09
|
|
||||||
// 39
|
|
||||||
// 5522657
|
|
||||||
// a690389285100
|
|
||||||
// 目前的算法
|
|
||||||
// 时间序列,年月日时分秒 14 位
|
|
||||||
// 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整
|
|
||||||
return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + // 时间序列
|
|
||||||
RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
|
public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
|
||||||
// 校验支付渠道是否有效
|
// 校验支付渠道是否有效
|
||||||
PayChannelDO channel = channelService.validPayChannel(channelId);
|
PayChannelDO channel = channelService.validPayChannel(channelId);
|
||||||
// 更新支付订单为已支付
|
// 更新支付订单为已支付
|
||||||
TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
|
TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyOrder(channel, notify));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
|
* 通知并更新订单的支付结果
|
||||||
PayOrderDO order = orderMapper.selectById(id);
|
*
|
||||||
if (order == null) {
|
* @param channel 支付渠道
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
* @param notify 通知
|
||||||
}
|
*/
|
||||||
if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
|
@Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
|
||||||
throw exception(PAY_REFUND_PRICE_EXCEED);
|
public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||||
}
|
|
||||||
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
|
|
||||||
throw exception(PAY_REFUND_PRICE_EXCEED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新订单
|
|
||||||
PayOrderDO updateObj = new PayOrderDO()
|
|
||||||
.setRefundPrice(order.getRefundPrice() + incrRefundPrice)
|
|
||||||
.setRefundTimes(order.getRefundTimes() + 1);
|
|
||||||
if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
|
|
||||||
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
|
|
||||||
.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
|
|
||||||
} else {
|
|
||||||
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
|
|
||||||
.setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
|
|
||||||
}
|
|
||||||
orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
|
|
||||||
// 情况一:支付成功的回调
|
// 情况一:支付成功的回调
|
||||||
if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
|
if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
|
||||||
notifyOrderSuccess(channel, notify);
|
notifyOrderSuccess(channel, notify);
|
||||||
@ -275,20 +230,22 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
|
if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) {
|
||||||
notifyOrderClosed(channel, notify);
|
notifyOrderClosed(channel, notify);
|
||||||
}
|
}
|
||||||
|
// 情况三:WAITING:无需处理
|
||||||
|
// 情况四:REFUND:通过退款回调处理
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
|
private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||||
// 1. 更新 PayOrderExtensionDO 支付成功
|
// 1. 更新 PayOrderExtensionDO 支付成功
|
||||||
PayOrderExtensionDO orderExtension = updateOrderExtensionSuccess(notify);
|
PayOrderExtensionDO orderExtension = updateOrderSuccess(notify);
|
||||||
// 2. 更新 PayOrderDO 支付成功
|
// 2. 更新 PayOrderDO 支付成功
|
||||||
Pair<Boolean, PayOrderDO> order = updateOrderExtensionSuccess(channel, orderExtension, notify);
|
Boolean paid = updateOrderSuccess(channel, orderExtension, notify);
|
||||||
if (order.getKey()) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调
|
if (paid) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 插入支付通知记录
|
// 3. 插入支付通知记录
|
||||||
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||||
.type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getValue().getId()).build());
|
.type(PayNotifyTypeEnum.ORDER.getType()).dataId(orderExtension.getOrderId()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -297,25 +254,25 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
* @param notify 通知
|
* @param notify 通知
|
||||||
* @return PayOrderExtensionDO 对象
|
* @return PayOrderExtensionDO 对象
|
||||||
*/
|
*/
|
||||||
private PayOrderExtensionDO updateOrderExtensionSuccess(PayOrderRespDTO notify) {
|
private PayOrderExtensionDO updateOrderSuccess(PayOrderRespDTO notify) {
|
||||||
// 1. 查询 PayOrderExtensionDO
|
// 1. 查询 PayOrderExtensionDO
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
throw exception(ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
|
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
|
||||||
return orderExtension;
|
return orderExtension;
|
||||||
}
|
}
|
||||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderExtensionDO
|
// 2. 更新 PayOrderExtensionDO
|
||||||
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
|
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
|
||||||
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
|
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
|
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
|
||||||
return orderExtension;
|
return orderExtension;
|
||||||
@ -327,37 +284,37 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
* @param channel 支付渠道
|
* @param channel 支付渠道
|
||||||
* @param orderExtension 支付拓展单
|
* @param orderExtension 支付拓展单
|
||||||
* @param notify 通知回调
|
* @param notify 通知回调
|
||||||
* @return key:是否之前已经成功回调
|
* @return 是否之前已经成功回调
|
||||||
* value:PayOrderDO 对象
|
|
||||||
*/
|
*/
|
||||||
private Pair<Boolean, PayOrderDO> updateOrderExtensionSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
||||||
PayOrderRespDTO notify) {
|
PayOrderRespDTO notify) {
|
||||||
// 1. 判断 PayOrderDO 是否处于待支付
|
// 1. 判断 PayOrderDO 是否处于待支付
|
||||||
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
throw exception(ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
|
||||||
&& Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
|
&& Objects.equals(order.getExtensionId(), orderExtension.getId())) {
|
||||||
log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId());
|
log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId());
|
||||||
return Pair.of(true, order);
|
return true;
|
||||||
}
|
}
|
||||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderDO
|
// 2. 更新 PayOrderDO
|
||||||
int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
|
int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
|
||||||
PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
|
PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
.channelId(channel.getId()).channelCode(channel.getCode())
|
.channelId(channel.getId()).channelCode(channel.getCode())
|
||||||
.successTime(notify.getSuccessTime()).successExtensionId(orderExtension.getId())
|
.successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
|
||||||
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
|
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
|
||||||
.notifyTime(LocalDateTime.now()).build());
|
.channelFeeRate(channel.getFeeRate()).channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
|
||||||
|
.build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
|
log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
|
||||||
return Pair.of(false, order);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) {
|
private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) {
|
||||||
@ -368,7 +325,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
// 1. 查询 PayOrderExtensionDO
|
// 1. 查询 PayOrderExtensionDO
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
|
||||||
if (orderExtension == null) {
|
if (orderExtension == null) {
|
||||||
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
throw exception(ORDER_EXTENSION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
|
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
|
||||||
log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
|
log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
|
||||||
@ -380,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新 PayOrderExtensionDO
|
// 2. 更新 PayOrderExtensionDO
|
||||||
@ -388,9 +345,46 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
|
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
|
||||||
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
|
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
|
||||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
|
log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
|
||||||
|
PayOrderDO order = orderMapper.selectById(id);
|
||||||
|
if (order == null) {
|
||||||
|
throw exception(ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
||||||
|
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
|
||||||
|
throw exception(REFUND_PRICE_EXCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新订单
|
||||||
|
PayOrderDO updateObj = new PayOrderDO()
|
||||||
|
.setRefundPrice(order.getRefundPrice() + incrRefundPrice)
|
||||||
|
.setStatus(PayOrderStatusEnum.REFUND.getStatus());
|
||||||
|
int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
|
||||||
|
if (updateCount == 0) {
|
||||||
|
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayOrderExtensionDO getOrderExtension(Long id) {
|
||||||
|
return orderExtensionMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得自身的代理对象,解决 AOP 生效问题
|
||||||
|
*
|
||||||
|
* @return 自己
|
||||||
|
*/
|
||||||
|
private PayOrderServiceImpl getSelf() {
|
||||||
|
return SpringUtil.getBean(getClass());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund;
|
|||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
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;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
||||||
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -43,6 +40,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款订单 Service 实现类
|
* 退款订单 Service 实现类
|
||||||
@ -66,8 +64,6 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
@Resource
|
@Resource
|
||||||
private PayOrderService orderService;
|
private PayOrderService orderService;
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderExtensionService orderExtensionService;
|
|
||||||
@Resource
|
|
||||||
private PayAppService appService;
|
private PayAppService appService;
|
||||||
@Resource
|
@Resource
|
||||||
private PayChannelService channelService;
|
private PayChannelService channelService;
|
||||||
@ -106,13 +102,13 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||||
throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 1.4 校验退款订单是否已经存在
|
// 1.4 校验退款订单是否已经存在
|
||||||
PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
|
PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
|
||||||
app.getId(), reqDTO.getMerchantRefundId());
|
app.getId(), reqDTO.getMerchantRefundId());
|
||||||
if (refund != null) {
|
if (refund != null) {
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS);
|
throw exception(ErrorCodeConstants.REFUND_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 插入退款单
|
// 2.1 插入退款单
|
||||||
@ -120,7 +116,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setNo(generateRefundNo()).setOrderId(order.getId())
|
.setNo(generateRefundNo()).setOrderId(order.getId())
|
||||||
.setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
|
.setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
|
||||||
// 商户相关的字段
|
// 商户相关的字段
|
||||||
.setNotifyUrl(app.getRefundNotifyUrl()).setNotifyStatus(PayNotifyStatusEnum.WAITING.getStatus())
|
.setNotifyUrl(app.getRefundNotifyUrl())
|
||||||
// 渠道相关字段
|
// 渠道相关字段
|
||||||
.setChannelOrderNo(order.getChannelOrderNo())
|
.setChannelOrderNo(order.getChannelOrderNo())
|
||||||
// 退款相关字段
|
// 退款相关字段
|
||||||
@ -128,7 +124,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
|
.setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
|
||||||
refundMapper.insert(refund);
|
refundMapper.insert(refund);
|
||||||
// 2.2 向渠道发起退款申请
|
// 2.2 向渠道发起退款申请
|
||||||
PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
|
PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId());
|
||||||
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO()
|
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO()
|
||||||
.setPayPrice(order.getPrice())
|
.setPayPrice(order.getPrice())
|
||||||
.setRefundPrice(reqDTO.getPrice())
|
.setRefundPrice(reqDTO.getPrice())
|
||||||
@ -136,7 +132,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setOutRefundNo(refund.getNo())
|
.setOutRefundNo(refund.getNo())
|
||||||
.setNotifyUrl(genChannelRefundNotifyUrl(channel))
|
.setNotifyUrl(genChannelRefundNotifyUrl(channel))
|
||||||
.setReason(reqDTO.getReason());
|
.setReason(reqDTO.getReason());
|
||||||
PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段
|
PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
|
||||||
// 2.3 处理退款返回
|
// 2.3 处理退款返回
|
||||||
notifyRefund(channel, refundRespDTO);
|
notifyRefund(channel, refundRespDTO);
|
||||||
|
|
||||||
@ -153,25 +149,21 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
|
throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验状态,必须是支付状态
|
// 校验状态,必须是支付状态
|
||||||
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否已经全额退款
|
|
||||||
if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) {
|
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
|
|
||||||
}
|
|
||||||
// 校验金额 退款金额不能大于原定的金额
|
// 校验金额 退款金额不能大于原定的金额
|
||||||
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_PRICE_EXCEED);
|
throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
|
||||||
}
|
}
|
||||||
// 是否有退款中的订单
|
// 是否有退款中的订单
|
||||||
if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
|
if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
|
||||||
PayRefundStatusEnum.WAITING.getStatus()) > 0) {
|
PayRefundStatusEnum.WAITING.getStatus()) > 0) {
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING);
|
throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING);
|
||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
@ -205,7 +197,6 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
|
public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
|
||||||
// 校验支付渠道是否有效
|
// 校验支付渠道是否有效
|
||||||
channelService.validPayChannel(channelId);
|
channelService.validPayChannel(channelId);
|
||||||
@ -217,28 +208,33 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify));
|
TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿:事务问题
|
||||||
private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
|
private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
|
||||||
|
// 情况一:退款成功
|
||||||
if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
|
if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
|
||||||
notifyRefundSuccess(channel, notify);
|
notifyRefundSuccess(channel, notify);
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
// 情况二:退款失败
|
||||||
|
if (PayRefundStatusRespEnum.isFailure(notify.getStatus())) {
|
||||||
notifyRefundFailure(channel, notify);
|
notifyRefundFailure(channel, notify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) {
|
public void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) {
|
||||||
// 1.1 查询 PayRefundDO
|
// 1.1 查询 PayRefundDO
|
||||||
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
||||||
channel.getAppId(), notify.getOutRefundNo());
|
channel.getAppId(), notify.getOutRefundNo());
|
||||||
if (refund == null) {
|
if (refund == null) {
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND);
|
throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
|
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.2 更新 PayRefundDO
|
// 1.2 更新 PayRefundDO
|
||||||
PayRefundDO updateRefundObj = new PayRefundDO()
|
PayRefundDO updateRefundObj = new PayRefundDO()
|
||||||
.setSuccessTime(notify.getSuccessTime())
|
.setSuccessTime(notify.getSuccessTime())
|
||||||
@ -247,19 +243,48 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setChannelNotifyData(toJsonString(notify));
|
.setChannelNotifyData(toJsonString(notify));
|
||||||
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
||||||
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
||||||
throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
|
log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId());
|
||||||
|
|
||||||
// 2. 更新订单
|
// 2. 更新订单
|
||||||
orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice());
|
orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice());
|
||||||
|
|
||||||
// 3. 插入退款通知记录
|
// 3. 插入退款通知记录 TODO 芋艿:退款成功
|
||||||
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||||
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
// TODO 芋艿:未实现
|
public void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) {
|
||||||
|
// 1.1 查询 PayRefundDO
|
||||||
|
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
||||||
|
channel.getAppId(), notify.getOutRefundNo());
|
||||||
|
if (refund == null) {
|
||||||
|
throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
|
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
||||||
|
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
// 1.2 更新 PayRefundDO
|
||||||
|
PayRefundDO updateRefundObj = new PayRefundDO()
|
||||||
|
.setChannelRefundNo(notify.getChannelRefundNo())
|
||||||
|
.setStatus(PayRefundStatusEnum.FAILURE.getStatus())
|
||||||
|
.setChannelNotifyData(toJsonString(notify))
|
||||||
|
.setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg());
|
||||||
|
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
||||||
|
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
||||||
|
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId());
|
||||||
|
|
||||||
|
// 2. 插入退款通知记录 TODO 芋艿:退款失败
|
||||||
|
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||||
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.util;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class MoneyUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算百分比金额,四舍五入
|
||||||
|
*
|
||||||
|
* @param price 金额
|
||||||
|
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||||
|
* @return 百分比金额
|
||||||
|
*/
|
||||||
|
public static Integer calculateRatePrice(Integer price, Double rate) {
|
||||||
|
return new BigDecimal(price)
|
||||||
|
.multiply(BigDecimal.valueOf(rate)) // 乘以
|
||||||
|
.setScale(0, RoundingMode.HALF_UP) // 四舍五入
|
||||||
|
.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -90,7 +90,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
|
PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
|
||||||
o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
|
o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> appService.updateApp(reqVO), PAY_APP_NOT_FOUND);
|
assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
Long id = randomLongId();
|
Long id = randomLongId();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> appService.deleteApp(id), PAY_APP_NOT_FOUND);
|
assertServiceException(() -> appService.deleteApp(id), APP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L);
|
when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L);
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_ORDER_CANT_DELETE);
|
assertServiceException(() -> appService.deleteApp(id), APP_EXIST_ORDER_CANT_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L);
|
when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L);
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_REFUND_CANT_DELETE);
|
assertServiceException(() -> appService.deleteApp(id), APP_EXIST_REFUND_CANT_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidPayApp_notFound() {
|
public void testValidPayApp_notFound() {
|
||||||
assertServiceException(() -> appService.validPayApp(randomLongId()), PAY_APP_NOT_FOUND);
|
assertServiceException(() -> appService.validPayApp(randomLongId()), APP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
|
|||||||
Long id = dbApp.getId();
|
Long id = dbApp.getId();
|
||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
assertServiceException(() -> appService.validPayApp(id), PAY_APP_IS_DISABLE);
|
assertServiceException(() -> appService.validPayApp(id), APP_IS_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,7 @@ import java.util.List;
|
|||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@Import({PayChannelServiceImpl.class})
|
@Import({PayChannelServiceImpl.class})
|
||||||
@ -51,6 +50,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
|
|||||||
channelService.setChannelCache(null);
|
channelService.setChannelCache(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitLocalCache() {
|
||||||
|
// mock 数据
|
||||||
|
PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
|
||||||
|
o -> o.setConfig(randomWxPayClientConfig()));
|
||||||
|
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
channelService.initLocalCache();
|
||||||
|
// 校验缓存
|
||||||
|
assertEquals(1, channelService.getChannelCache().size());
|
||||||
|
assertEquals(dbChannel, channelService.getChannelCache().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefreshLocalCache() {
|
||||||
|
// mock 数据 01
|
||||||
|
PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
|
||||||
|
o -> o.setConfig(randomWxPayClientConfig()));
|
||||||
|
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
|
||||||
|
channelService.initLocalCache();
|
||||||
|
// mock 数据 02
|
||||||
|
PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class,
|
||||||
|
o -> o.setConfig(randomWxPayClientConfig()));
|
||||||
|
channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
channelService.refreshLocalCache();
|
||||||
|
// 校验缓存
|
||||||
|
assertEquals(2, channelService.getChannelCache().size());
|
||||||
|
assertEquals(dbChannel, channelService.getChannelCache().get(0));
|
||||||
|
assertEquals(dbChannel02, channelService.getChannelCache().get(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateChannel_success() {
|
public void testCreateChannel_success() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
@ -125,7 +158,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS);
|
assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
|
|||||||
Long id = randomLongId();
|
Long id = randomLongId();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS);
|
assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
|
|||||||
assertPojoEquals(channel, dbChannel);
|
assertPojoEquals(channel, dbChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPayChannel_notExists() {
|
||||||
|
// 准备参数
|
||||||
|
Long id = randomLongId();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPayChannel_isDisable() {
|
||||||
|
// mock 数据
|
||||||
|
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
|
||||||
|
// 准备参数
|
||||||
|
Long id = dbChannel.getId();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_IS_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPayChannel_success() {
|
||||||
|
// mock 数据
|
||||||
|
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
|
||||||
|
// 准备参数
|
||||||
|
Long id = dbChannel.getId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayChannelDO channel = channelService.validPayChannel(id);
|
||||||
|
// 断言异常
|
||||||
|
assertPojoEquals(channel, dbChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPayChannel_appIdAndCode() {
|
||||||
|
// mock 数据
|
||||||
|
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
|
||||||
|
// 准备参数
|
||||||
|
Long appId = dbChannel.getAppId();
|
||||||
|
String code = dbChannel.getCode();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayChannelDO channel = channelService.validPayChannel(appId, code);
|
||||||
|
// 断言异常
|
||||||
|
assertPojoEquals(channel, dbChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetEnableChannelList() {
|
||||||
|
// 准备参数
|
||||||
|
Long appId = randomLongId();
|
||||||
|
// mock 数据 01(enable 不匹配)
|
||||||
|
PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据
|
||||||
|
// mock 数据 02(appId 不匹配)
|
||||||
|
PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
|
||||||
|
// mock 数据 03
|
||||||
|
PayChannelDO dbChannel03 = randomPojo(PayChannelDO.class, o -> {
|
||||||
|
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
|
||||||
|
o.setConfig(randomAlipayPayClientConfig());
|
||||||
|
o.setAppId(appId);
|
||||||
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
});
|
||||||
|
channelMapper.insert(dbChannel03);// @Sql: 先插入出一条存在的数据
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
List<PayChannelDO> channel = channelService.getEnableChannelList(appId);
|
||||||
|
// 断言异常
|
||||||
|
assertPojoEquals(channel, dbChannel03);
|
||||||
|
}
|
||||||
|
|
||||||
public WxPayClientConfig randomWxPayClientConfig() {
|
public WxPayClientConfig randomWxPayClientConfig() {
|
||||||
return new WxPayClientConfig()
|
return new WxPayClientConfig()
|
||||||
.setAppId(randomString())
|
.setAppId(randomString())
|
||||||
|
@ -1,48 +1,73 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.order;
|
package cn.iocoder.yudao.module.pay.service.order;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||||
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentMatcher;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link PayOrderServiceImpl} 的单元测试类
|
* {@link PayOrderServiceImpl} 的单元测试类
|
||||||
*
|
*
|
||||||
* @author 芋艿
|
* @author 芋艿
|
||||||
*/
|
*/
|
||||||
@Import({PayOrderServiceImpl.class})
|
@Import({PayOrderServiceImpl.class, PayNoRedisDAO.class})
|
||||||
public class PayOrderServiceTest extends BaseDbUnitTest {
|
public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderServiceImpl orderService;
|
private PayOrderServiceImpl orderService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderMapper orderMapper;
|
private PayOrderMapper orderMapper;
|
||||||
|
@Resource
|
||||||
|
private PayOrderExtensionMapper orderExtensionMapper;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private PayClientFactory payClientFactory;
|
private PayClientFactory payClientFactory;
|
||||||
@ -55,140 +80,92 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private PayNotifyService notifyService;
|
private PayNotifyService notifyService;
|
||||||
|
|
||||||
public String generateNo() {
|
@BeforeEach
|
||||||
return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999);
|
public void setUp() {
|
||||||
|
when(properties.getOrderNotifyUrl()).thenReturn("http://127.0.0.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOrderPage() {
|
public void testGetOrderPage() {
|
||||||
|
|
||||||
String merchantOrderId = generateNo();
|
|
||||||
String channelOrderId = generateNo();
|
|
||||||
|
|
||||||
// mock 数据
|
// mock 数据
|
||||||
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
|
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
|
||||||
o.setAppId(1L);
|
o.setAppId(1L);
|
||||||
o.setChannelId(1L);
|
|
||||||
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
o.setMerchantOrderId(merchantOrderId);
|
o.setMerchantOrderId("110");
|
||||||
o.setSubject("灿灿子的炸弹猫");
|
o.setChannelOrderNo("220");
|
||||||
o.setBody("斌斌子送给灿灿子的炸弹猫");
|
o.setNo("330");
|
||||||
o.setNotifyUrl("https://hc.com/lbh");
|
|
||||||
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
|
||||||
o.setPrice(10000);
|
|
||||||
o.setChannelFeeRate(0.01);
|
|
||||||
o.setChannelFeePrice(1L);
|
|
||||||
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setUserIp("127.0.0.1");
|
o.setCreateTime(buildTime(2018, 1, 15));
|
||||||
o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
|
|
||||||
o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
|
|
||||||
o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
|
|
||||||
o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
|
|
||||||
o.setSuccessExtensionId(1L);
|
|
||||||
o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
|
|
||||||
o.setRefundTimes(0);
|
|
||||||
o.setRefundPrice(0);
|
|
||||||
o.setChannelUserId("1008611");
|
|
||||||
o.setChannelOrderNo(channelOrderId);
|
|
||||||
o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
|
|
||||||
});
|
});
|
||||||
orderMapper.insert(dbOrder);
|
orderMapper.insert(dbOrder);
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
|
||||||
// 测试 channelId 不匹配
|
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L)));
|
|
||||||
// 测试 channelCode 不匹配
|
// 测试 channelCode 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantOrderId 不匹配
|
// 测试 merchantOrderId 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
|
||||||
// 测试 notifyStatus 不匹配
|
// 测试 channelOrderNo 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString())));
|
||||||
|
// 测试 no 不匹配
|
||||||
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString())));
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
|
||||||
// 测试 refundStatus 不匹配
|
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
|
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
|
||||||
1))));
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayOrderPageReqVO reqVO = new PayOrderPageReqVO();
|
PayOrderPageReqVO reqVO = new PayOrderPageReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelId(1L);
|
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
reqVO.setMerchantOrderId(merchantOrderId);
|
reqVO.setMerchantOrderId("11");
|
||||||
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
reqVO.setChannelOrderNo("22");
|
||||||
|
reqVO.setNo("33");
|
||||||
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
|
reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
|
|
||||||
// 调用
|
// 调用
|
||||||
PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
|
PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(1, pageResult.getTotal());
|
assertEquals(1, pageResult.getTotal());
|
||||||
assertEquals(1, pageResult.getList().size());
|
assertEquals(1, pageResult.getList().size());
|
||||||
assertPojoEquals(dbOrder, pageResult.getList().get(0));
|
assertPojoEquals(dbOrder, pageResult.getList().get(0));
|
||||||
// assertEquals(0, dbOrder.getUpdateTime().compareTo(pageResult.getList().get(0).getUpdateTime()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOrderList() {
|
public void testGetOrderList() {
|
||||||
// mock 数据
|
// mock 数据
|
||||||
String merchantOrderId = generateNo();
|
|
||||||
String channelOrderId = generateNo();
|
|
||||||
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
|
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
|
||||||
o.setAppId(1L);
|
o.setAppId(1L);
|
||||||
o.setChannelId(1L);
|
|
||||||
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
o.setMerchantOrderId(merchantOrderId);
|
o.setMerchantOrderId("110");
|
||||||
o.setSubject("灿灿子的炸弹猫");
|
o.setChannelOrderNo("220");
|
||||||
o.setBody("斌斌子送给灿灿子的炸弹猫");
|
o.setNo("330");
|
||||||
o.setNotifyUrl("https://hc.com/lbh");
|
|
||||||
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
|
||||||
o.setPrice(10000);
|
|
||||||
o.setChannelFeeRate(0.01);
|
|
||||||
o.setChannelFeePrice(1L);
|
|
||||||
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setUserIp("127.0.0.1");
|
o.setCreateTime(buildTime(2018, 1, 15));
|
||||||
o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
|
|
||||||
o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
|
|
||||||
o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
|
|
||||||
o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
|
|
||||||
o.setSuccessExtensionId(1L);
|
|
||||||
o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
|
|
||||||
o.setRefundTimes(0);
|
|
||||||
o.setRefundPrice(0);
|
|
||||||
o.setChannelUserId("1008611");
|
|
||||||
o.setChannelOrderNo(channelOrderId);
|
|
||||||
o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
|
|
||||||
|
|
||||||
});
|
});
|
||||||
orderMapper.insert(dbOrder);
|
orderMapper.insert(dbOrder);
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L)));
|
||||||
// 测试 channelId 不匹配
|
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelId(2L)));
|
|
||||||
// 测试 channelCode 不匹配
|
// 测试 channelCode 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantOrderId 不匹配
|
// 测试 merchantOrderId 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
|
||||||
// 测试 notifyStatus 不匹配
|
// 测试 channelOrderNo 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString())));
|
||||||
|
// 测试 no 不匹配
|
||||||
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString())));
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
|
||||||
// 测试 refundStatus 不匹配
|
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
|
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
|
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
|
||||||
1))));
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayOrderExportReqVO reqVO = new PayOrderExportReqVO();
|
PayOrderExportReqVO reqVO = new PayOrderExportReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelId(1L);
|
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
reqVO.setMerchantOrderId(merchantOrderId);
|
reqVO.setMerchantOrderId("11");
|
||||||
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
reqVO.setChannelOrderNo("22");
|
||||||
|
reqVO.setNo("33");
|
||||||
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
|
reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
|
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
List<PayOrderDO> list = orderService.getOrderList(reqVO);
|
List<PayOrderDO> list = orderService.getOrderList(reqVO);
|
||||||
@ -197,4 +174,393 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
|
|||||||
assertPojoEquals(dbOrder, list.get(0));
|
assertPojoEquals(dbOrder, list.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateOrder_success() {
|
||||||
|
// mock 参数
|
||||||
|
PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("10")
|
||||||
|
.setSubject(randomString()).setBody(randomString()));
|
||||||
|
// mock 方法
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
|
||||||
|
when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long orderId = orderService.createOrder(reqDTO);
|
||||||
|
// 断言
|
||||||
|
PayOrderDO order = orderMapper.selectById(orderId);
|
||||||
|
assertPojoEquals(order, reqDTO);
|
||||||
|
assertEquals(order.getAppId(), 1L);
|
||||||
|
assertEquals(order.getNotifyUrl(), "http://127.0.0.1");
|
||||||
|
assertEquals(order.getStatus(), PayOrderStatusEnum.WAITING.getStatus());
|
||||||
|
assertEquals(order.getRefundPrice(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateOrder_exists() {
|
||||||
|
// mock 参数
|
||||||
|
PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("10"));
|
||||||
|
// mock 数据
|
||||||
|
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> o.setAppId(1L).setMerchantOrderId("10"));
|
||||||
|
orderMapper.insert(dbOrder);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long orderId = orderService.createOrder(reqDTO);
|
||||||
|
// 断言
|
||||||
|
PayOrderDO order = orderMapper.selectById(orderId);
|
||||||
|
assertPojoEquals(dbOrder, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubmitOrder_notFound() {
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class);
|
||||||
|
String userIp = randomString();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubmitOrder_notWaiting() {
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
|
||||||
|
String userIp = randomString();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubmitOrder_expired() {
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setExpireTime(addTime(Duration.ofDays(-1))));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
|
||||||
|
String userIp = randomString();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubmitOrder_channelNotFound() {
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
|
||||||
|
.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
String userIp = randomString();
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
|
||||||
|
.thenReturn(channel);
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), CHANNEL_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // 调用 unifiedOrder 接口,返回存在渠道错误
|
||||||
|
public void testSubmitOrder_channelError() {
|
||||||
|
PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
|
||||||
|
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
|
||||||
|
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
|
||||||
|
.thenReturn(payOrderServiceImpl);
|
||||||
|
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
|
||||||
|
.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
String userIp = randomString();
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
|
||||||
|
.thenReturn(channel);
|
||||||
|
// mock 方法(client)
|
||||||
|
PayClient client = mock(PayClient.class);
|
||||||
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
|
// mock 方法()
|
||||||
|
PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o ->
|
||||||
|
o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常"));
|
||||||
|
when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
|
||||||
|
assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo());
|
||||||
|
assertThat(payOrderUnifiedReqDTO)
|
||||||
|
.extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime")
|
||||||
|
.containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10",
|
||||||
|
reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(unifiedOrderResp);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
|
||||||
|
ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
|
||||||
|
// 断言,数据记录(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
|
||||||
|
assertNotNull(orderExtension);
|
||||||
|
assertThat(orderExtension).extracting("no", "orderId").isNotNull();
|
||||||
|
assertThat(orderExtension)
|
||||||
|
.extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
|
||||||
|
"channelErrorCode", "channelErrorMsg", "channelNotifyData")
|
||||||
|
.containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
|
||||||
|
PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
|
||||||
|
null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubmitOrder_success() {
|
||||||
|
PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
|
||||||
|
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
|
||||||
|
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
|
||||||
|
.thenReturn(payOrderServiceImpl);
|
||||||
|
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setAppId(1L).setExpireTime(addTime(Duration.ofDays(1))));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
|
||||||
|
.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
String userIp = randomString();
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
|
||||||
|
.thenReturn(channel);
|
||||||
|
// mock 方法(client)
|
||||||
|
PayClient client = mock(PayClient.class);
|
||||||
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
|
// mock 方法()
|
||||||
|
PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
|
||||||
|
.setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
|
||||||
|
when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
|
||||||
|
assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo());
|
||||||
|
assertThat(payOrderUnifiedReqDTO)
|
||||||
|
.extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime")
|
||||||
|
.containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10",
|
||||||
|
reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(unifiedOrderResp);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayOrderSubmitRespVO result = orderService.submitOrder(reqVO, userIp);
|
||||||
|
// 断言,数据记录(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
|
||||||
|
assertNotNull(orderExtension);
|
||||||
|
assertThat(orderExtension).extracting("no", "orderId").isNotNull();
|
||||||
|
assertThat(orderExtension)
|
||||||
|
.extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
|
||||||
|
"channelErrorCode", "channelErrorMsg", "channelNotifyData")
|
||||||
|
.containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
|
||||||
|
PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
|
||||||
|
null, null, null);
|
||||||
|
// 断言,返回(PayOrderSubmitRespVO)
|
||||||
|
assertThat(result)
|
||||||
|
.extracting("status", "displayMode", "displayContent")
|
||||||
|
.containsExactly(PayOrderStatusEnum.WAITING.getStatus(), PayOrderDisplayModeEnum.URL.getMode(), "tudou");
|
||||||
|
// 断言,调用
|
||||||
|
verify(payOrderServiceImpl).notifyOrder(same(channel), same(unifiedOrderResp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrder_channelId() {
|
||||||
|
PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class);
|
||||||
|
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
|
||||||
|
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class)))
|
||||||
|
.thenReturn(payOrderServiceImpl);
|
||||||
|
// 准备参数
|
||||||
|
Long channelId = 10L;
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
orderService.notifyOrder(channelId, notify);
|
||||||
|
// 断言
|
||||||
|
verify(payOrderServiceImpl).notifyOrder(same(channel), same(notify));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_orderExtension_notFound() {
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_EXTENSION_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_orderExtension_closed() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_order_notFound() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_NOT_FOUND);
|
||||||
|
// 断言 PayOrderExtensionDO :数据更新被回滚
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_order_closed() {
|
||||||
|
testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.CLOSED.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_order_refund() {
|
||||||
|
testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.REFUND.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testNotifyOrderSuccess_order_closedOrRefund(Integer status) {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setNo("P110")
|
||||||
|
.setOrderId(order.getId()));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_STATUS_IS_NOT_WAITING);
|
||||||
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_order_paid() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setNo("P110")
|
||||||
|
.setOrderId(order.getId()));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 重要:需要将 order 的 extensionId 更新下
|
||||||
|
order.setExtensionId(orderExtension.getId());
|
||||||
|
orderMapper.updateById(order);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
orderService.notifyOrder(channel, notify);
|
||||||
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
|
// 断言 PayOrderDO :数据未更新,因为它是 SUCCESS
|
||||||
|
assertPojoEquals(order, orderMapper.selectOne(null));
|
||||||
|
// 断言,调用
|
||||||
|
verify(notifyService, never()).createPayNotifyTask(any(PayNotifyTaskCreateReqDTO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderSuccess_order_waiting() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setPrice(10));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setNo("P110")
|
||||||
|
.setOrderId(order.getId()));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setFeeRate(0.1D));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
orderService.notifyOrder(channel, notify);
|
||||||
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
||||||
|
orderExtension.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setChannelNotifyData(toJsonString(notify));
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null),
|
||||||
|
"updateTime", "updater");
|
||||||
|
// 断言 PayOrderDO :数据未更新,因为它是 SUCCESS
|
||||||
|
order.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setChannelId(10L).setChannelCode(channel.getCode())
|
||||||
|
.setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo())
|
||||||
|
.setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId())
|
||||||
|
.setChannelFeeRate(0.1D).setChannelFeePrice(1);
|
||||||
|
assertPojoEquals(order, orderMapper.selectOne(null),
|
||||||
|
"updateTime", "updater");
|
||||||
|
// 断言,调用
|
||||||
|
verify(notifyService).createPayNotifyTask(argThat(new ArgumentMatcher<PayNotifyTaskCreateReqDTO>() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(PayNotifyTaskCreateReqDTO reqDTO) {
|
||||||
|
assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType());
|
||||||
|
assertEquals(reqDTO.getDataId(), orderExtension.getOrderId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
@ -31,7 +30,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
@Import(PayRefundServiceImpl.class)
|
@Import(PayRefundServiceImpl.class)
|
||||||
public class PayRefundServiceTest extends BaseDbUnitTest {
|
public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayRefundServiceImpl refundService;
|
private PayRefundServiceImpl refundService;
|
||||||
@ -46,8 +45,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private PayOrderService orderService;
|
private PayOrderService orderService;
|
||||||
@MockBean
|
@MockBean
|
||||||
private PayOrderExtensionService orderExtensionService;
|
|
||||||
@MockBean
|
|
||||||
private PayAppService appService;
|
private PayAppService appService;
|
||||||
@MockBean
|
@MockBean
|
||||||
private PayChannelService channelService;
|
private PayChannelService channelService;
|
||||||
@ -66,8 +63,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
o.setMerchantOrderId("MOT0000001");
|
o.setMerchantOrderId("MOT0000001");
|
||||||
o.setMerchantRefundId("MRF0000001");
|
o.setMerchantRefundId("MRF0000001");
|
||||||
o.setNotifyUrl("https://www.cancanzi.com");
|
o.setNotifyUrl("https://www.cancanzi.com");
|
||||||
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
|
||||||
o.setPayPrice(100);
|
o.setPayPrice(100);
|
||||||
o.setRefundPrice(500);
|
o.setRefundPrice(500);
|
||||||
o.setReason("就是想退款了,你有意见吗");
|
o.setReason("就是想退款了,你有意见吗");
|
||||||
@ -87,11 +83,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantRefundNo 不匹配
|
// 测试 merchantRefundNo 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
||||||
// 测试 notifyStatus 不匹配
|
|
||||||
refundMapper.insert(
|
|
||||||
cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
|
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
||||||
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
||||||
@ -99,8 +92,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
reqVO.setMerchantRefundNo("MRF0000001");
|
reqVO.setMerchantRefundId("MRF0000001");
|
||||||
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
|
||||||
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
||||||
|
|
||||||
@ -124,8 +116,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
o.setMerchantOrderId("MOT0000001");
|
o.setMerchantOrderId("MOT0000001");
|
||||||
o.setMerchantRefundId("MRF0000001");
|
o.setMerchantRefundId("MRF0000001");
|
||||||
o.setNotifyUrl("https://www.cancanzi.com");
|
o.setNotifyUrl("https://www.cancanzi.com");
|
||||||
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
|
||||||
o.setPayPrice(100);
|
o.setPayPrice(100);
|
||||||
o.setRefundPrice(500);
|
o.setRefundPrice(500);
|
||||||
o.setReason("就是想退款了,你有意见吗");
|
o.setReason("就是想退款了,你有意见吗");
|
||||||
@ -145,11 +136,8 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantRefundNo 不匹配
|
// 测试 merchantRefundNo 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
||||||
// 测试 notifyStatus 不匹配
|
|
||||||
refundMapper.insert(
|
|
||||||
cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
|
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
||||||
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
||||||
@ -158,10 +146,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
reqVO.setMerchantRefundNo("MRF0000001");
|
|
||||||
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
|
|
||||||
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
||||||
reqVO.setType(PayOrderRefundStatusEnum.PART.getStatus());
|
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
DELETE FROM pay_app;
|
DELETE FROM pay_app;
|
||||||
DELETE FROM pay_channel;
|
DELETE FROM pay_channel;
|
||||||
DELETE FROM pay_order;
|
DELETE FROM pay_order;
|
||||||
|
DELETE FROM pay_order_extension;
|
||||||
DELETE FROM pay_refund;
|
DELETE FROM pay_refund;
|
||||||
|
@ -39,19 +39,17 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
|
|||||||
`subject` varchar(32) NOT NULL,
|
`subject` varchar(32) NOT NULL,
|
||||||
`body` varchar(128) NOT NULL,
|
`body` varchar(128) NOT NULL,
|
||||||
`notify_url` varchar(1024) NOT NULL,
|
`notify_url` varchar(1024) NOT NULL,
|
||||||
`notify_status` tinyint(4) NOT NULL,
|
`price` bigint(20) NOT NULL,
|
||||||
`amount` bigint(20) NOT NULL,
|
|
||||||
`channel_fee_rate` double DEFAULT 0,
|
`channel_fee_rate` double DEFAULT 0,
|
||||||
`channel_fee_amount` bigint(20) DEFAULT 0,
|
`channel_fee_price` bigint(20) DEFAULT 0,
|
||||||
`status` tinyint(4) NOT NULL,
|
`status` tinyint(4) NOT NULL,
|
||||||
`user_ip` varchar(50) NOT NULL,
|
`user_ip` varchar(50) NOT NULL,
|
||||||
`expire_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`expire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
|
`success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
|
||||||
`notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
|
`notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
|
||||||
`success_extension_id` bigint(20) DEFAULT NULL COMMENT '支付成功的订单拓展单编号',
|
`extension_id` bigint(20) DEFAULT NULL,
|
||||||
`refund_status` tinyint(4) NOT NULL,
|
`no` varchar(64) NULL,
|
||||||
`refund_times` tinyint(4) NOT NULL,
|
`refund_price` bigint(20) NOT NULL,
|
||||||
`refund_amount` bigint(20) NOT NULL,
|
|
||||||
`channel_user_id` varchar(255) DEFAULT NULL,
|
`channel_user_id` varchar(255) DEFAULT NULL,
|
||||||
`channel_order_no` varchar(64) DEFAULT NULL,
|
`channel_order_no` varchar(64) DEFAULT NULL,
|
||||||
`creator` varchar(64) DEFAULT '',
|
`creator` varchar(64) DEFAULT '',
|
||||||
@ -62,6 +60,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
|
|||||||
PRIMARY KEY ("id")
|
PRIMARY KEY ("id")
|
||||||
) COMMENT = '支付订单';
|
) COMMENT = '支付订单';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pay_order_extension` (
|
||||||
|
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
`no` varchar(64) NOT NULL,
|
||||||
|
`order_id` bigint(20) NOT NULL,
|
||||||
|
`channel_id` bigint(20) NOT NULL,
|
||||||
|
`channel_code` varchar(32) NOT NULL,
|
||||||
|
`user_ip` varchar(50) NULL DEFAULT NULL,
|
||||||
|
`status` tinyint(4) NOT NULL,
|
||||||
|
`channel_extras` varchar(1024) NULL DEFAULT NULL,
|
||||||
|
`channel_error_code` varchar(64) NULL,
|
||||||
|
`channel_error_msg` varchar(64) NULL,
|
||||||
|
`channel_notify_data` varchar(1024) NULL,
|
||||||
|
`creator` varchar(64) NULL DEFAULT '',
|
||||||
|
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updater` varchar(64) NULL DEFAULT '',
|
||||||
|
`update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT FALSE,
|
||||||
|
PRIMARY KEY ("id")
|
||||||
|
) COMMENT = '支付订单拓展';
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `pay_refund` (
|
CREATE TABLE IF NOT EXISTS `pay_refund` (
|
||||||
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||||
`app_id` bigint(20) NOT NULL,
|
`app_id` bigint(20) NOT NULL,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 创建支付应用信息
|
// 创建支付应用
|
||||||
export function createApp(data) {
|
export function createApp(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/create',
|
url: '/pay/app/create',
|
||||||
@ -9,7 +9,7 @@ export function createApp(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新支付应用信息
|
// 更新支付应用
|
||||||
export function updateApp(data) {
|
export function updateApp(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/update',
|
url: '/pay/app/update',
|
||||||
@ -18,7 +18,7 @@ export function updateApp(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 支付应用信息状态修改
|
// 支付应用状态修改
|
||||||
export function changeAppStatus(id, status) {
|
export function changeAppStatus(id, status) {
|
||||||
const data = {
|
const data = {
|
||||||
id,
|
id,
|
||||||
@ -31,7 +31,7 @@ export function changeAppStatus(id, status) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除支付应用信息
|
// 删除支付应用
|
||||||
export function deleteApp(id) {
|
export function deleteApp(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/delete?id=' + id,
|
url: '/pay/app/delete?id=' + id,
|
||||||
@ -39,7 +39,7 @@ export function deleteApp(id) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得支付应用信息
|
// 获得支付应用
|
||||||
export function getApp(id) {
|
export function getApp(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/get?id=' + id,
|
url: '/pay/app/get?id=' + id,
|
||||||
@ -47,7 +47,7 @@ export function getApp(id) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得支付应用信息分页
|
// 获得支付应用分页
|
||||||
export function getAppPage(query) {
|
export function getAppPage(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/page',
|
url: '/pay/app/page',
|
||||||
@ -56,23 +56,10 @@ export function getAppPage(query) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出支付应用信息 Excel
|
// 获得支付应用列表
|
||||||
export function exportAppExcel(query) {
|
export function getAppList() {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/app/export-excel',
|
url: '/pay/app/list',
|
||||||
method: 'get',
|
|
||||||
params: query,
|
|
||||||
responseType: 'blob'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据商ID称搜索应用列表
|
|
||||||
export function getAppListByMerchantId(merchantId) {
|
|
||||||
return request({
|
|
||||||
url: '/pay/app/list-merchant-id',
|
|
||||||
params:{
|
|
||||||
merchantId:merchantId
|
|
||||||
},
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
18
yudao-ui-admin/src/api/pay/notify.js
Normal file
18
yudao-ui-admin/src/api/pay/notify.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获得支付通知明细
|
||||||
|
export function getNotifyTaskDetail(id) {
|
||||||
|
return request({
|
||||||
|
url: '/pay/notify/get-detail?id=' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得支付通知分页
|
||||||
|
export function getNotifyTaskPage(query) {
|
||||||
|
return request({
|
||||||
|
url: '/pay/notify/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
@ -206,42 +206,6 @@ export const PayOrderStatusEnum = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单回调状态枚举
|
|
||||||
*/
|
|
||||||
export const PayOrderNotifyStatusEnum = {
|
|
||||||
NO: {
|
|
||||||
status: 0,
|
|
||||||
name: '未通知'
|
|
||||||
},
|
|
||||||
SUCCESS: {
|
|
||||||
status: 10,
|
|
||||||
name: '通知成功'
|
|
||||||
},
|
|
||||||
FAILURE: {
|
|
||||||
status: 20,
|
|
||||||
name: '通知失败'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单退款状态枚举
|
|
||||||
*/
|
|
||||||
export const PayOrderRefundStatusEnum = {
|
|
||||||
NO: {
|
|
||||||
status: 0,
|
|
||||||
name: '未退款'
|
|
||||||
},
|
|
||||||
SOME: {
|
|
||||||
status: 10,
|
|
||||||
name: '部分退款'
|
|
||||||
},
|
|
||||||
ALL: {
|
|
||||||
status: 20,
|
|
||||||
name: '全部退款'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付退款订单状态枚举
|
* 支付退款订单状态枚举
|
||||||
*/
|
*/
|
||||||
|
@ -51,15 +51,12 @@ export const DICT_TYPE = {
|
|||||||
|
|
||||||
// ========== PAY 模块 ==========
|
// ========== PAY 模块 ==========
|
||||||
PAY_CHANNEL_WECHAT_VERSION: 'pay_channel_wechat_version', // 微信渠道版本
|
PAY_CHANNEL_WECHAT_VERSION: 'pay_channel_wechat_version', // 微信渠道版本
|
||||||
PAY_CHANNEL_ALIPAY_SIGN_TYPE: 'pay_channel_alipay_sign_type', // 支付渠道支付宝算法类型
|
|
||||||
PAY_CHANNEL_ALIPAY_MODE: 'pay_channel_alipay_mode', // 支付宝公钥类型
|
|
||||||
PAY_CHANNEL_ALIPAY_SERVER_TYPE: 'pay_channel_alipay_server_type', // 支付宝网关地址
|
|
||||||
PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型
|
PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型
|
||||||
PAY_ORDER_NOTIFY_STATUS: 'pay_order_notify_status', // 商户支付订单回调状态
|
|
||||||
PAY_ORDER_STATUS: 'pay_order_status', // 商户支付订单状态
|
PAY_ORDER_STATUS: 'pay_order_status', // 商户支付订单状态
|
||||||
PAY_ORDER_REFUND_STATUS: 'pay_order_refund_status', // 商户支付订单退款状态
|
PAY_REFUND_STATUS: 'pay_refund_status', // 退款订单状态
|
||||||
PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态
|
PAY_NOTIFY_STATUS: 'pay_notify_status', // 商户支付回调状态
|
||||||
PAY_REFUND_ORDER_TYPE: 'pay_refund_order_type', // 退款订单类别
|
PAY_NOTIFY_TYPE: 'pay_notify_type', // 商户支付回调状态
|
||||||
|
|
||||||
// ========== MP 模块 ==========
|
// ========== MP 模块 ==========
|
||||||
MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
|
MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
|
||||||
|
@ -1,349 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-dialog :visible.sync="transferParam.aliPayOpen" :title="title" @closed="close" append-to-body width="800px">
|
|
||||||
<el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"
|
|
||||||
v-loading="transferParam.loading">
|
|
||||||
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
|
||||||
<el-input v-model="form.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
|
|
||||||
<template slot="append">%</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="开放平台APPID" prop="aliPayConfig.appId">
|
|
||||||
<el-input v-model="form.aliPayConfig.appId" placeholder="请输入开放平台APPID" clearable :style="{width: '100%'}">
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="渠道状态" prop="status">
|
|
||||||
<el-radio-group v-model="form.status" size="medium">
|
|
||||||
<el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
|
|
||||||
{{ dict.label }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="网关地址" prop="aliPayConfig.serverUrl">
|
|
||||||
<el-radio-group v-model="form.aliPayConfig.serverUrl" size="medium">
|
|
||||||
<el-radio v-for="dict in aliPayServerDatas" :key="dict.value" :label="dict.value">
|
|
||||||
{{ dict.label }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="算法类型" prop="aliPayConfig.signType">
|
|
||||||
<el-radio-group v-model="form.aliPayConfig.signType" size="medium">
|
|
||||||
<el-radio v-for="dict in aliPaySignTypeDatas" :key="dict.value" :label="dict.value">
|
|
||||||
{{ dict.label }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="公钥类型" prop="aliPayConfig.mode">
|
|
||||||
<el-radio-group v-model="form.aliPayConfig.mode" size="medium">
|
|
||||||
<el-radio v-for="dict in aliPayModeDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
|
|
||||||
{{ dict.label }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<div v-if="form.aliPayConfig.mode === 1">
|
|
||||||
<el-form-item label-width="180px" label="应用私钥" prop="aliPayConfig.privateKey">
|
|
||||||
<el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey"
|
|
||||||
placeholder="请输入应用私钥" clearable :style="{width: '100%'}">
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="支付宝公钥" prop="aliPayConfig.alipayPublicKey">
|
|
||||||
<el-input
|
|
||||||
type="textarea"
|
|
||||||
:autosize="{minRows: 8, maxRows: 8}"
|
|
||||||
v-model="form.aliPayConfig.alipayPublicKey"
|
|
||||||
placeholder="请输入支付宝公钥" clearable
|
|
||||||
:style="{width: '100%'}">
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
<div v-if="form.aliPayConfig.mode === 2">
|
|
||||||
<el-form-item label-width="180px" label="商户公钥应用证书" prop="aliPayConfig.appCertContent">
|
|
||||||
<el-input v-model="form.aliPayConfig.appCertContent" type="textarea"
|
|
||||||
placeholder="请上传商户公钥应用证书"
|
|
||||||
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="">
|
|
||||||
<el-upload
|
|
||||||
action=""
|
|
||||||
ref="privateKeyContentFile"
|
|
||||||
:limit="1"
|
|
||||||
:accept="fileAccept"
|
|
||||||
:http-request="appCertUpload"
|
|
||||||
:before-upload="fileBeforeUpload">
|
|
||||||
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="支付宝公钥证书" prop="aliPayConfig.alipayPublicCertContent">
|
|
||||||
<el-input v-model="form.aliPayConfig.alipayPublicCertContent" type="textarea"
|
|
||||||
placeholder="请上传支付宝公钥证书"
|
|
||||||
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="">
|
|
||||||
<el-upload
|
|
||||||
ref="privateCertContentFile"
|
|
||||||
action=""
|
|
||||||
:limit="1"
|
|
||||||
:accept="fileAccept"
|
|
||||||
:before-upload="fileBeforeUpload"
|
|
||||||
:http-request="alipayPublicCertUpload">
|
|
||||||
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="根证书" prop="aliPayConfig.rootCertContent">
|
|
||||||
<el-input
|
|
||||||
v-model="form.aliPayConfig.rootCertContent"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请上传根证书"
|
|
||||||
readonly :autosize="{minRows: 8, maxRows: 8}"
|
|
||||||
:style="{width: '100%'}">
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label-width="180px" label="">
|
|
||||||
<el-upload
|
|
||||||
ref="privateCertContentFile"
|
|
||||||
:limit="1"
|
|
||||||
:accept="fileAccept"
|
|
||||||
action=""
|
|
||||||
:before-upload="fileBeforeUpload"
|
|
||||||
:http-request="rootCertUpload">
|
|
||||||
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
<el-form-item label-width="180px" label="备注" prop="remark">
|
|
||||||
<el-input v-model="form.remark" :style="{width: '100%'}"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer" class="dialog-footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
|
||||||
import {createChannel, getChannel, updateChannel} from "@/api/pay/channel";
|
|
||||||
|
|
||||||
const defaultForm = {
|
|
||||||
code: '',
|
|
||||||
status: null,
|
|
||||||
remark: '',
|
|
||||||
feeRate: null,
|
|
||||||
appId: '',
|
|
||||||
aliPayConfig: {
|
|
||||||
appId: '',
|
|
||||||
serverUrl: null,
|
|
||||||
signType: '',
|
|
||||||
mode: null,
|
|
||||||
privateKey: '',
|
|
||||||
alipayPublicKey: '',
|
|
||||||
appCertContent: '',
|
|
||||||
alipayPublicCertContent: '',
|
|
||||||
rootCertContent: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "aliPayChannelForm",
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
// 传输的参数
|
|
||||||
transferParam: {
|
|
||||||
// 加载动画
|
|
||||||
"loading": false,
|
|
||||||
// 是否修改
|
|
||||||
"edit": false,
|
|
||||||
// 是否显示
|
|
||||||
"aliPayOpen": false,
|
|
||||||
// 应用ID
|
|
||||||
"appId": null,
|
|
||||||
// 渠道编码
|
|
||||||
"payCode": null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
title:'',
|
|
||||||
form: JSON.parse(JSON.stringify(defaultForm)),
|
|
||||||
rules: {
|
|
||||||
feeRate: [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入渠道费率',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.appId': [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入开放平台上创建的应用的 ID',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
status: [{
|
|
||||||
required: true,
|
|
||||||
message: '渠道状态不能为空',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.serverUrl': [{
|
|
||||||
required: true,
|
|
||||||
message: '请传入网关地址',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.signType': [{
|
|
||||||
required: true,
|
|
||||||
message: '请传入签名算法类型',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.mode': [{
|
|
||||||
required: true,
|
|
||||||
message: '公钥类型不能为空',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.privateKey': [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入商户私钥',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.alipayPublicKey': [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入支付宝公钥字符串',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.appCertContent': [{
|
|
||||||
required: true,
|
|
||||||
message: '请上传商户公钥应用证书',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.alipayPublicCertContent': [{
|
|
||||||
required: true,
|
|
||||||
message: '请上传支付宝公钥证书',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
'aliPayConfig.rootCertContent': [{
|
|
||||||
required: true,
|
|
||||||
message: '请上传指定根证书',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
fileAccept: ".crt",
|
|
||||||
// 渠道状态 数据字典
|
|
||||||
statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS),
|
|
||||||
// 支付宝加密方式
|
|
||||||
aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),
|
|
||||||
// 版本状态 数据字典
|
|
||||||
aliPayModeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_MODE),
|
|
||||||
// 支付宝网关地址
|
|
||||||
aliPayServerDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SERVER_TYPE),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
transferParam: {
|
|
||||||
deep: true, // 深度监听
|
|
||||||
handler(newVal) {
|
|
||||||
if (newVal.aliPayOpen) {
|
|
||||||
this.form.code = newVal.payCode;
|
|
||||||
this.form.appId = newVal.appId;
|
|
||||||
// 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
|
|
||||||
if (newVal.edit === true && newVal.loading) {
|
|
||||||
this.title = "编辑支付渠道";
|
|
||||||
this.init();
|
|
||||||
} else {
|
|
||||||
this.title = "创建支付渠道";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
init() {
|
|
||||||
getChannel(this.transferParam.appId, this.transferParam.payCode)
|
|
||||||
.then(response => {
|
|
||||||
this.form.id = response.data.id;
|
|
||||||
this.form.feeRate = response.data.feeRate;
|
|
||||||
this.form.status = response.data.status;
|
|
||||||
this.form.remark = response.data.remark;
|
|
||||||
|
|
||||||
let config = JSON.parse(response.data.config);
|
|
||||||
this.form.aliPayConfig.appId = config.appId;
|
|
||||||
this.form.aliPayConfig.serverUrl = config.serverUrl;
|
|
||||||
this.form.aliPayConfig.signType = config.signType;
|
|
||||||
this.form.aliPayConfig.mode = config.mode;
|
|
||||||
this.form.aliPayConfig.privateKey = config.privateKey;
|
|
||||||
this.form.aliPayConfig.alipayPublicKey = config.alipayPublicKey;
|
|
||||||
this.form.aliPayConfig.appCertContent = config.appCertContent;
|
|
||||||
this.form.aliPayConfig.alipayPublicCertContent = config.alipayPublicCertContent;
|
|
||||||
this.form.aliPayConfig.rootCertContent = config.rootCertContent;
|
|
||||||
this.transferParam.loading = false;
|
|
||||||
})
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.transferParam.aliPayOpen = false;
|
|
||||||
this.form = JSON.parse(JSON.stringify(defaultForm));
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['aliPayForm'].validate(valid => {
|
|
||||||
if (!valid) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let data = this.form;
|
|
||||||
data.config = JSON.stringify(this.form.aliPayConfig);
|
|
||||||
if (this.transferParam.edit) {
|
|
||||||
updateChannel(data).then(response => {
|
|
||||||
if (response.code === 0) {
|
|
||||||
this.$modal.msgSuccess("修改成功");
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
|
|
||||||
createChannel(data).then(response => {
|
|
||||||
if (response.code === 0) {
|
|
||||||
this.$modal.msgSuccess("新增成功");
|
|
||||||
this.$parent.refreshTable();
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
fileBeforeUpload(file) {
|
|
||||||
let format = '.' + file.name.split(".")[1];
|
|
||||||
if (format !== this.fileAccept) {
|
|
||||||
this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let isRightSize = file.size / 1024 / 1024 < 2
|
|
||||||
if (!isRightSize) {
|
|
||||||
this.$message.error('文件大小超过 2MB')
|
|
||||||
}
|
|
||||||
return isRightSize
|
|
||||||
},
|
|
||||||
appCertUpload(event) {
|
|
||||||
const readFile = new FileReader()
|
|
||||||
readFile.onload = (e) => {
|
|
||||||
this.form.aliPayConfig.appCertContent = e.target.result
|
|
||||||
}
|
|
||||||
readFile.readAsText(event.file);
|
|
||||||
},
|
|
||||||
alipayPublicCertUpload(event) {
|
|
||||||
const readFile = new FileReader()
|
|
||||||
readFile.onload = (e) => {
|
|
||||||
this.form.aliPayConfig.alipayPublicCertContent = e.target.result
|
|
||||||
}
|
|
||||||
readFile.readAsText(event.file);
|
|
||||||
},
|
|
||||||
rootCertUpload(event) {
|
|
||||||
const readFile = new FileReader()
|
|
||||||
readFile.onload = (e) => {
|
|
||||||
this.form.aliPayConfig.rootCertContent = e.target.result
|
|
||||||
}
|
|
||||||
readFile.readAsText(event.file);
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog :visible.sync="dialogVisible" :title="title" @closed="close" append-to-body width="800px">
|
||||||
|
<el-form ref="form" :model="formData" :rules="rules" size="medium" label-width="100px" v-loading="formLoading">
|
||||||
|
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
||||||
|
<el-input v-model="formData.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
|
||||||
|
<template slot="append">%</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="开放平台 APPID" prop="config.appId">
|
||||||
|
<el-input v-model="formData.config.appId" placeholder="请输入开放平台 APPID" clearable :style="{width: '100%'}">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="渠道状态" prop="status">
|
||||||
|
<el-radio-group v-model="formData.status" size="medium">
|
||||||
|
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)"
|
||||||
|
:label="parseInt(dict.value)">
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="网关地址" prop="config.serverUrl">
|
||||||
|
<el-radio-group v-model="formData.config.serverUrl" size="medium">
|
||||||
|
<el-radio label="https://openapi.alipay.com/gateway.do">线上环境</el-radio>
|
||||||
|
<el-radio label="https://openapi-sandbox.dl.alipaydev.com/gateway.do">沙箱环境</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="算法类型" prop="config.signType">
|
||||||
|
<el-radio-group v-model="formData.config.signType" size="medium">
|
||||||
|
<el-radio key="RSA2" label="RSA2">RSA2</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="公钥类型" prop="config.mode">
|
||||||
|
<el-radio-group v-model="formData.config.mode" size="medium">
|
||||||
|
<el-radio key="公钥模式" :label="1">公钥模式</el-radio>
|
||||||
|
<el-radio key="证书模式" :label="2">证书模式</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="formData.config.mode === 1">
|
||||||
|
<el-form-item label-width="180px" label="应用私钥" prop="config.privateKey">
|
||||||
|
<el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="formData.config.privateKey"
|
||||||
|
placeholder="请输入应用私钥" clearable :style="{width: '100%'}">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="支付宝公钥" prop="config.alipayPublicKey">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{minRows: 8, maxRows: 8}"
|
||||||
|
v-model="formData.config.alipayPublicKey"
|
||||||
|
placeholder="请输入支付宝公钥" clearable
|
||||||
|
:style="{width: '100%'}">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div v-if="formData.config.mode === 2">
|
||||||
|
<el-form-item label-width="180px" label="商户公钥应用证书" prop="config.appCertContent">
|
||||||
|
<el-input v-model="formData.config.appCertContent" type="textarea"
|
||||||
|
placeholder="请上传商户公钥应用证书"
|
||||||
|
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="">
|
||||||
|
<el-upload
|
||||||
|
action=""
|
||||||
|
ref="privateKeyContentFile"
|
||||||
|
:limit="1"
|
||||||
|
:accept="fileAccept"
|
||||||
|
:http-request="appCertUpload"
|
||||||
|
:before-upload="fileBeforeUpload">
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="支付宝公钥证书" prop="config.alipayPublicCertContent">
|
||||||
|
<el-input v-model="formData.config.alipayPublicCertContent" type="textarea"
|
||||||
|
placeholder="请上传支付宝公钥证书"
|
||||||
|
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="">
|
||||||
|
<el-upload
|
||||||
|
ref="privateCertContentFile"
|
||||||
|
action=""
|
||||||
|
:limit="1"
|
||||||
|
:accept="fileAccept"
|
||||||
|
:before-upload="fileBeforeUpload"
|
||||||
|
:http-request="alipayPublicCertUpload">
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="根证书" prop="config.rootCertContent">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.config.rootCertContent"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请上传根证书"
|
||||||
|
readonly :autosize="{minRows: 8, maxRows: 8}"
|
||||||
|
:style="{width: '100%'}">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="180px" label="">
|
||||||
|
<el-upload
|
||||||
|
ref="privateCertContentFile"
|
||||||
|
:limit="1"
|
||||||
|
:accept="fileAccept"
|
||||||
|
action=""
|
||||||
|
:before-upload="fileBeforeUpload"
|
||||||
|
:http-request="rootCertUpload">
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label-width="180px" label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" :style="{width: '100%'}"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { createChannel, getChannel, updateChannel } from "@/api/pay/channel";
|
||||||
|
import { CommonStatusEnum } from "@/utils/constants";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "alipayChannelForm",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
formLoading: false,
|
||||||
|
title:'',
|
||||||
|
formData: {
|
||||||
|
appId: '',
|
||||||
|
code: '',
|
||||||
|
status: undefined,
|
||||||
|
feeRate: undefined,
|
||||||
|
remark: '',
|
||||||
|
config: {
|
||||||
|
appId: '',
|
||||||
|
serverUrl: null,
|
||||||
|
signType: '',
|
||||||
|
mode: null,
|
||||||
|
privateKey: '',
|
||||||
|
alipayPublicKey: '',
|
||||||
|
appCertContent: '',
|
||||||
|
alipayPublicCertContent: '',
|
||||||
|
rootCertContent: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
feeRate: [{ required: true, message: '请输入渠道费率', trigger: 'blur' }],
|
||||||
|
status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur' }],
|
||||||
|
'config.appId': [{ required: true, message: '请输入开放平台上创建的应用的 ID', trigger: 'blur' }],
|
||||||
|
'config.serverUrl': [{ required: true, message: '请传入网关地址', trigger: 'blur' }],
|
||||||
|
'config.signType': [{ required: true, message: '请传入签名算法类型', trigger: 'blur' }],
|
||||||
|
'config.mode': [{ required: true, message: '公钥类型不能为空', trigger: 'blur'}],
|
||||||
|
'config.privateKey': [{ required: true, message: '请输入商户私钥', trigger: 'blur' }],
|
||||||
|
'config.alipayPublicKey': [{ required: true, message: '请输入支付宝公钥字符串', trigger: 'blur' }],
|
||||||
|
'config.appCertContent': [{ required: true, message: '请上传商户公钥应用证书', trigger: 'blur' }],
|
||||||
|
'config.alipayPublicCertContent': [{ required: true, message: '请上传支付宝公钥证书', trigger: 'blur'}],
|
||||||
|
'config.rootCertContent': [{ required: true, message: '请上传指定根证书', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
fileAccept: ".crt",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(appId, code) {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.formLoading = true;
|
||||||
|
this.reset(appId, code);
|
||||||
|
getChannel(appId, code).then(response => {
|
||||||
|
if (response.data && response.data.id) {
|
||||||
|
this.formData = response.data;
|
||||||
|
this.formData.config = JSON.parse(response.data.config);
|
||||||
|
}
|
||||||
|
this.title = this.formData.id ? '创建支付渠道' : '编辑支付渠道'
|
||||||
|
}).finally(() => {
|
||||||
|
this.formLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.reset(undefined, undefined);
|
||||||
|
},
|
||||||
|
submitForm() {
|
||||||
|
this.$refs['form'].validate(valid => {
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = { ...this.formData };
|
||||||
|
data.config = JSON.stringify(this.formData.config);
|
||||||
|
if (!data.id) {
|
||||||
|
createChannel(data).then(response => {
|
||||||
|
this.$modal.msgSuccess("新增成功");
|
||||||
|
this.$emit('success')
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateChannel(data).then(response => {
|
||||||
|
this.$modal.msgSuccess("修改成功");
|
||||||
|
this.$emit('success')
|
||||||
|
this.close();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 重置表单 */
|
||||||
|
reset(appId, code) {
|
||||||
|
this.formData = {
|
||||||
|
appId: appId,
|
||||||
|
code: code,
|
||||||
|
status: CommonStatusEnum.ENABLE,
|
||||||
|
remark: '',
|
||||||
|
feeRate: null,
|
||||||
|
config: {
|
||||||
|
appId: '',
|
||||||
|
serverUrl: null,
|
||||||
|
signType: 'RSA2',
|
||||||
|
mode: null,
|
||||||
|
privateKey: '',
|
||||||
|
alipayPublicKey: '',
|
||||||
|
appCertContent: '',
|
||||||
|
alipayPublicCertContent: '',
|
||||||
|
rootCertContent: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.resetForm('form')
|
||||||
|
},
|
||||||
|
fileBeforeUpload(file) {
|
||||||
|
let format = '.' + file.name.split(".")[1];
|
||||||
|
if (format !== this.fileAccept) {
|
||||||
|
this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let isRightSize = file.size / 1024 / 1024 < 2
|
||||||
|
if (!isRightSize) {
|
||||||
|
this.$message.error('文件大小超过 2MB')
|
||||||
|
}
|
||||||
|
return isRightSize
|
||||||
|
},
|
||||||
|
appCertUpload(event) {
|
||||||
|
const readFile = new FileReader()
|
||||||
|
readFile.onload = (e) => {
|
||||||
|
this.formData.config.appCertContent = e.target.result
|
||||||
|
}
|
||||||
|
readFile.readAsText(event.file);
|
||||||
|
},
|
||||||
|
alipayPublicCertUpload(event) {
|
||||||
|
const readFile = new FileReader()
|
||||||
|
readFile.onload = (e) => {
|
||||||
|
this.formData.config.alipayPublicCertContent = e.target.result
|
||||||
|
}
|
||||||
|
readFile.readAsText(event.file);
|
||||||
|
},
|
||||||
|
rootCertUpload(event) {
|
||||||
|
const readFile = new FileReader()
|
||||||
|
readFile.onload = (e) => {
|
||||||
|
this.formData.config.rootCertContent = e.target.result
|
||||||
|
}
|
||||||
|
readFile.readAsText(event.file);
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -213,8 +213,10 @@
|
|||||||
<el-button @click="cancel">取 消</el-button>
|
<el-button @click="cancel">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<wechat-channel-form :transferParam="channelParam"></wechat-channel-form>
|
|
||||||
<ali-pay-channel-form :transferParam="channelParam"></ali-pay-channel-form>
|
<!-- 弹窗 -->
|
||||||
|
<wechat-channel-form :transferParam="channelParam" />
|
||||||
|
<alipay-channel-form ref="alipayChannelFormRef" @success="getList" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -223,13 +225,13 @@ import { createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage }
|
|||||||
import { DICT_TYPE, getDictDatas } from "@/utils/dict";
|
import { DICT_TYPE, getDictDatas } from "@/utils/dict";
|
||||||
import { PayType, PayChannelEnum, CommonStatusEnum } from "@/utils/constants";
|
import { PayType, PayChannelEnum, CommonStatusEnum } from "@/utils/constants";
|
||||||
import wechatChannelForm from "@/views/pay/app/components/wechatChannelForm";
|
import wechatChannelForm from "@/views/pay/app/components/wechatChannelForm";
|
||||||
import aliPayChannelForm from "@/views/pay/app/components/aliPayChannelForm";
|
import alipayChannelForm from "@/views/pay/app/components/alipayChannelForm";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PayApp",
|
name: "PayApp",
|
||||||
components: {
|
components: {
|
||||||
"wechatChannelForm": wechatChannelForm,
|
"wechatChannelForm": wechatChannelForm,
|
||||||
"aliPayChannelForm": aliPayChannelForm
|
"alipayChannelForm": alipayChannelForm
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -283,13 +285,6 @@ export default {
|
|||||||
"appId": null,
|
"appId": null,
|
||||||
// 渠道编码
|
// 渠道编码
|
||||||
"payCode": null,
|
"payCode": null,
|
||||||
// 商户对象
|
|
||||||
"payMerchant": {
|
|
||||||
// 编号
|
|
||||||
"id": null,
|
|
||||||
// 名称
|
|
||||||
"name": null
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -424,14 +419,12 @@ export default {
|
|||||||
this.channelParam.aliPayOpen = false;
|
this.channelParam.aliPayOpen = false;
|
||||||
}
|
}
|
||||||
if (type === PayType.ALIPAY) {
|
if (type === PayType.ALIPAY) {
|
||||||
this.channelParam.aliPayOpen = true;
|
console.log(this.$refs['alipayChannelFormRef'])
|
||||||
this.channelParam.wechatOpen = false;
|
this.$refs['alipayChannelFormRef'].open(row.id, payCode);
|
||||||
|
return;
|
||||||
|
// this.channelParam.aliPayOpen = true;
|
||||||
|
// this.channelParam.wechatOpen = false;
|
||||||
}
|
}
|
||||||
this.channelParam.edit = false;
|
|
||||||
this.channelParam.loading = false;
|
|
||||||
this.channelParam.appId = row.id;
|
|
||||||
this.channelParam.payCode = payCode;
|
|
||||||
this.channelParam.payMerchant = row.payMerchant;
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 根据渠道编码判断渠道列表中是否存在
|
* 根据渠道编码判断渠道列表中是否存在
|
||||||
|
221
yudao-ui-admin/src/views/pay/notify/index.vue
Normal file
221
yudao-ui-admin/src/views/pay/notify/index.vue
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
|
||||||
|
<el-form-item label="应用编号" prop="appId">
|
||||||
|
<el-select clearable v-model="queryParams.appId" filterable placeholder="请选择应用信息">
|
||||||
|
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="通知类型" prop="type">
|
||||||
|
<el-select v-model="queryParams.type" placeholder="请选择通知类型" clearable size="small">
|
||||||
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_NOTIFY_TYPE)"
|
||||||
|
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="关联编号" prop="dataId">
|
||||||
|
<el-input v-model="queryParams.dataId" placeholder="请输入关联编号" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="通知状态" prop="status">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="请选择通知状态" clearable size="small">
|
||||||
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_NOTIFY_STATUS)"
|
||||||
|
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商户订单编号" prop="merchantOrderId">
|
||||||
|
<el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户订单编号" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
|
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
|
||||||
|
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column label="任务编号" align="center" prop="id" />
|
||||||
|
<el-table-column label="应用编号" align="center" prop="appName" />
|
||||||
|
<el-table-column label="商户订单编号" align="center" prop="merchantOrderId" />
|
||||||
|
<el-table-column label="通知类型" align="center" prop="type">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="scope.row.type" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="关联编号" align="center" prop="dataId" />
|
||||||
|
<el-table-column label="通知状态" align="center" prop="status">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="最后通知时间" align="center" prop="lastExecuteTime" width="180">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<span>{{ parseTime(scope.row.lastExecuteTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="下次通知时间" align="center" prop="nextNotifyTime" width="180">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<span>{{ parseTime(scope.row.nextNotifyTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="通知次数" align="center" prop="notifyTimes">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-tag size="mini" type="success">
|
||||||
|
{{ scope.row.notifyTimes }} / {{ scope.row.maxNotifyTimes }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
|
||||||
|
v-hasPermi="['pay:notify:query']">查看详情
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"/>
|
||||||
|
|
||||||
|
<!-- 对话框(详情) -->
|
||||||
|
<el-dialog title="通知详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="商户订单编号">
|
||||||
|
<el-tag size="small">{{ notifyDetail.merchantOrderId }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="通知状态">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="notifyDetail.status" size="small" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="应用编号">{{ notifyDetail.appId }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="应用名称">{{ notifyDetail.appName }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="关联编号">{{ notifyDetail.dataId }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="通知类型">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_NOTIFY_TYPE" :value="notifyDetail.type" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="通知次数">{{ notifyDetail.notifyTimes }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="最大通知次数">{{ notifyDetail.maxNotifyTimes }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="最后通知时间">{{ parseTime(notifyDetail.lastExecuteTime) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="下次通知时间">{{ parseTime(notifyDetail.nextNotifyTime) }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="创建时间">{{ parseTime(notifyDetail.createTime) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="更新时间">{{ parseTime(notifyDetail.updateTime) }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<el-divider />
|
||||||
|
<el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
|
||||||
|
<el-descriptions-item label="回调日志">
|
||||||
|
<el-table :data="notifyDetail.logs">
|
||||||
|
<el-table-column label="日志编号" align="center" prop="id" />
|
||||||
|
<el-table-column label="通知状态" align="center" prop="status">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_NOTIFY_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="通知次数" align="center" prop="notifyTimes" />
|
||||||
|
<el-table-column label="通知时间" align="center" prop="lastExecuteTime" width="180">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="响应结果" align="center" prop="response" />
|
||||||
|
</el-table>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getNotifyTaskPage, getNotifyTaskDetail } from "@/api/pay/notify";
|
||||||
|
import { getAppList } from "@/api/pay/app";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PayNotify",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 遮罩层
|
||||||
|
loading: true,
|
||||||
|
// 导出遮罩层
|
||||||
|
exportLoading: false,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
// 支付通知列表
|
||||||
|
list: [],
|
||||||
|
// 是否显示弹出层
|
||||||
|
open: false,
|
||||||
|
// 查询参数
|
||||||
|
queryParams: {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
appId: null,
|
||||||
|
type: null,
|
||||||
|
dataId: null,
|
||||||
|
status: null,
|
||||||
|
merchantOrderId: null,
|
||||||
|
createTime: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
// 支付应用列表集合
|
||||||
|
appList: [],
|
||||||
|
// 通知详情
|
||||||
|
notifyDetail: {
|
||||||
|
logs: []
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
// 获得筛选项
|
||||||
|
getAppList().then(response => {
|
||||||
|
this.appList = response.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
// 执行查询
|
||||||
|
getNotifyTaskPage(this.queryParams).then(response => {
|
||||||
|
this.list = response.data.list;
|
||||||
|
this.total = response.data.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNo = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
resetQuery() {
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
/** 详情按钮操作 */
|
||||||
|
handleDetail(row) {
|
||||||
|
this.notifyDetail = {};
|
||||||
|
getNotifyTaskDetail(row.id).then(response => {
|
||||||
|
// 设置值
|
||||||
|
this.notifyDetail = response.data;
|
||||||
|
// 弹窗打开
|
||||||
|
this.open = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -8,35 +8,26 @@
|
|||||||
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="渠道编码" prop="channelCode">
|
<el-form-item label="支付渠道" prop="channelCode">
|
||||||
<el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable
|
<el-select v-model="queryParams.channelCode" placeholder="请选择支付渠道" clearable>
|
||||||
@clear="()=>{queryParams.channelCode = null}">
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
<el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="商户订单编号" prop="merchantOrderId">
|
<el-form-item label="商户单号" prop="merchantOrderId">
|
||||||
<el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户订单编号" clearable
|
<el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户单号" clearable
|
||||||
@keyup.enter.native="handleQuery"/>
|
@keyup.enter.native="handleQuery"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="渠道订单号" prop="channelOrderNo">
|
<el-form-item label="支付单号" prop="no">
|
||||||
<el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道订单号" clearable
|
<el-input v-model="queryParams.no" placeholder="请输入支付单号" clearable
|
||||||
|
@keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="渠道单号" prop="channelOrderNo">
|
||||||
|
<el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道单号" clearable
|
||||||
@keyup.enter.native="handleQuery"/>
|
@keyup.enter.native="handleQuery"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="支付状态" prop="status">
|
<el-form-item label="支付状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small">
|
<el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small">
|
||||||
<el-option v-for="dict in payOrderDictDatum" :key="parseInt(dict.value)"
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_STATUS)" :key="parseInt(dict.value)"
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="退款状态" prop="refundStatus">
|
|
||||||
<el-select v-model="queryParams.refundStatus" placeholder="请选择退款状态" clearable>
|
|
||||||
<el-option v-for="dict in payOrderRefundDictDatum" :key="parseInt(dict.value)"
|
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="回调商户状态" prop="notifyStatus">
|
|
||||||
<el-select v-model="queryParams.notifyStatus" placeholder="请选择订单回调商户状态" clearable>
|
|
||||||
<el-option v-for="dict in payOrderNotifyDictDatum" :key="parseInt(dict.value)"
|
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
:label="dict.label" :value="parseInt(dict.value)"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -62,69 +53,64 @@
|
|||||||
|
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<el-table v-loading="loading" :data="list">
|
<el-table v-loading="loading" :data="list">
|
||||||
<el-table-column label="订单编号" align="center" prop="id" width="80"/>
|
<el-table-column label="编号" align="center" prop="id" width="80"/>
|
||||||
<el-table-column label="支付渠道" align="center" width="130">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<el-popover trigger="hover" placement="top">
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
<p>应用名称: {{ scope.row.appName }}</p>
|
|
||||||
<p>渠道名称: {{ scope.row.channelCodeName }}</p>
|
|
||||||
<div slot="reference" class="name-wrapper">
|
|
||||||
{{ scope.row.channelCodeName }}
|
|
||||||
</div>
|
|
||||||
</el-popover>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="支付订单" align="left" width="280">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<p class="order-font"><el-tag size="mini">商户单号</el-tag> {{scope.row.merchantOrderId}}</p>
|
|
||||||
<p class="order-font"><el-tag size="mini" type="warning">支付单号</el-tag> {{scope.row.channelOrderNo}}</p>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="商品标题" align="center" prop="subject" width="180" :show-overflow-tooltip="true"/>
|
|
||||||
<el-table-column label="支付金额" align="center" prop="price" width="100">
|
<el-table-column label="支付金额" align="center" prop="price" width="100">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
¥{{ parseFloat(scope.row.price / 100).toFixed(2) }}
|
¥{{ (scope.row.price / 100.0).toFixed(2) }}
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="手续金额" align="center" prop="channelFeePrice" width="100">
|
|
||||||
<template v-slot="scope">
|
|
||||||
¥{{ parseFloat(scope.row.channelFeePrice / 100).toFixed(2) }}
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
|
<el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
¥{{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }}
|
¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="手续金额" align="center" prop="channelFeePrice" width="100">
|
||||||
|
<template v-slot="scope">
|
||||||
|
¥{{ (scope.row.channelFeePrice / 100.0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="订单号" align="left" width="300">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<p class="order-font"><el-tag size="mini">
|
||||||
|
商户</el-tag> {{scope.row.merchantOrderId}}
|
||||||
|
</p>
|
||||||
|
<p class="order-font" v-if="scope.row.no">
|
||||||
|
<el-tag size="mini" type="warning">支付</el-tag> {{scope.row.no}}
|
||||||
|
</p>
|
||||||
|
<p class="order-font" v-if="scope.row.channelOrderNo">
|
||||||
|
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="支付状态" align="center" prop="status">
|
<el-table-column label="支付状态" align="center" prop="status">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" />
|
<dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- <el-table-column label="退款状态" align="center" prop="refundStatus">-->
|
<el-table-column label="支付渠道" align="center" width="140">
|
||||||
<!-- <template v-slot="scope">-->
|
|
||||||
<!-- <span>{{ getDictDataLabel(DICT_TYPE.PAY_ORDER_REFUND_STATUS, scope.row.refundStatus) }}</span>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </el-table-column>-->
|
|
||||||
<el-table-column label="回调状态" align="center" prop="notifyStatus" width="100">
|
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" />
|
<dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
|
<el-table-column label="支付时间" align="center" prop="successTime" width="180">
|
||||||
<template v-slot="scope">
|
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="支付时间" align="center" prop="successTime" width="100">
|
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span>{{ parseTime(scope.row.successTime) }}</span>
|
<span>{{ parseTime(scope.row.successTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="支付应用" align="center" prop="successTime" width="100">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<span>{{ scope.row.appName }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="商品标题" align="center" prop="subject" width="180" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)"
|
<el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
|
||||||
v-hasPermi="['pay:order:query']">查看详情
|
v-hasPermi="['pay:order:query']">查看详情
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@ -134,67 +120,71 @@
|
|||||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"/>
|
@pagination="getList"/>
|
||||||
|
|
||||||
<!-- 对话框(添加 / 修改) -->
|
<!-- 对话框(详情) -->
|
||||||
<el-dialog title="订单详情" :visible.sync="open" width="50%">
|
<el-dialog title="订单详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>
|
<el-descriptions-item label="商户单号">
|
||||||
<el-descriptions-item label="商品名称">{{ orderDetail.subject }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
<el-divider></el-divider>
|
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
|
||||||
<el-descriptions-item label="商户订单号">
|
|
||||||
<el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag>
|
<el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="渠道订单号">
|
<el-descriptions-item label="支付单号">
|
||||||
<el-tag class="tag-purple" size="small">{{ orderDetail.channelOrderNo }}</el-tag>
|
<el-tag type="warning" size="small" v-if="orderDetail.no">{{ orderDetail.no }}</el-tag>
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="支付订单号">
|
|
||||||
<el-tag v-if="orderDetail.payOrderExtension.no !== ''" class="tag-pink" size="small">
|
|
||||||
{{ orderDetail.payOrderExtension.no }}
|
|
||||||
</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="金额">
|
|
||||||
<el-tag type="success" size="small">{{ parseFloat(orderDetail.price / 100, 2) }}</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="手续费">
|
|
||||||
<el-tag type="warning" size="small">{{ parseFloat(orderDetail.channelFeePrice / 100, 2) }}</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="手续费比例">
|
|
||||||
{{ parseFloat(orderDetail.channelFeeRate / 100, 2) }}%
|
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="应用编号">{{ orderDetail.appId }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="支付状态">
|
<el-descriptions-item label="支付状态">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="orderDetail.status" />
|
<dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="orderDetail.status" size="small" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="回调状态">
|
<el-descriptions-item label="支付金额">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="orderDetail.notifyStatus" />
|
<el-tag type="success" size="small">¥{{ (orderDetail.price / 100.0).toFixed(2) }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="回调地址">{{ orderDetail.notifyUrl }}</el-descriptions-item>
|
</el-descriptions>
|
||||||
<el-descriptions-item label="创建时间">{{ parseTime(orderDetail.createTime) }}</el-descriptions-item>
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="手续费">
|
||||||
|
<el-tag type="warning" size="small">¥{{ (orderDetail.channelFeePrice / 100.0).toFixed(2) }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="手续费比例">{{ (orderDetail.channelFeeRate / 100.0).toFixed(2) }}%</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="支付时间">{{ parseTime(orderDetail.successTime) }}</el-descriptions-item>
|
<el-descriptions-item label="支付时间">{{ parseTime(orderDetail.successTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="失效时间">{{ parseTime(orderDetail.expireTime) }}</el-descriptions-item>
|
<el-descriptions-item label="失效时间">{{ parseTime(orderDetail.expireTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="通知时间">{{ parseTime(orderDetail.notifyTime) }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-divider></el-divider>
|
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="支付渠道">{{ orderDetail.channelCodeName }}</el-descriptions-item>
|
<el-descriptions-item label="创建时间">{{ parseTime(orderDetail.createTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="支付IP">{{ orderDetail.userIp }}</el-descriptions-item>
|
<el-descriptions-item label="更新时间">{{ parseTime(orderDetail.updateTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="退款状态">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_REFUND_STATUS" :value="orderDetail.refundStatus" />
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="退款次数">{{ orderDetail.refundTimes }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="退款金额">
|
|
||||||
<el-tag type="warning">
|
|
||||||
{{ parseFloat(orderDetail.refundPrice / 100, 2) }}
|
|
||||||
</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-divider></el-divider>
|
<!-- 分割线 -->
|
||||||
<el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
|
<el-divider/>
|
||||||
<el-descriptions-item label="商品描述">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
{{ orderDetail.body }}
|
<el-descriptions-item label="商品标题">{{ orderDetail.subject }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="商品描述">{{ orderDetail.body }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="支付渠道">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="orderDetail.channelCode" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="支付 IP">{{ orderDetail.userIp }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="渠道单号">
|
||||||
|
<el-tag size="mini" type="success" v-if="orderDetail.channelOrderNo">{{ orderDetail.channelOrderNo }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="渠道用户">{{ orderDetail.channelUserId }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="退款金额">
|
||||||
|
<el-tag size="mini" type="danger">¥{{ (orderDetail.refundPrice / 100.0).toFixed(2) }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="通知 URL">{{ orderDetail.notifyUrl }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<el-divider />
|
||||||
|
<el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
|
||||||
<el-descriptions-item label="支付通道异步回调内容">
|
<el-descriptions-item label="支付通道异步回调内容">
|
||||||
{{ orderDetail.payOrderExtension.channelNotifyData }}
|
{{ orderDetail.extension.channelNotifyData }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -203,35 +193,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order";
|
import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order";
|
||||||
import { DICT_TYPE, getDictDatas } from "@/utils/dict";
|
import { getAppList } from "@/api/pay/app";
|
||||||
import { getNowDateTime} from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
const defaultOrderDetail = {
|
|
||||||
appName: '',
|
|
||||||
channelCodeName: '',
|
|
||||||
subject: '',
|
|
||||||
merchantOrderId: null,
|
|
||||||
channelOrderNo: '',
|
|
||||||
body: '',
|
|
||||||
price: null,
|
|
||||||
channelFeeRate: null,
|
|
||||||
channelFeePrice: null,
|
|
||||||
userIp: '',
|
|
||||||
status: null,
|
|
||||||
notifyUrl: '',
|
|
||||||
notifyStatus: null,
|
|
||||||
refundStatus: null,
|
|
||||||
refundTimes: '',
|
|
||||||
refundPrice: null,
|
|
||||||
createTime: '',
|
|
||||||
successTime: '',
|
|
||||||
notifyTime: '',
|
|
||||||
expireTime: '',
|
|
||||||
payOrderExtension: {
|
|
||||||
channelNotifyData: '',
|
|
||||||
no: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PayOrder",
|
name: "PayOrder",
|
||||||
@ -250,75 +212,37 @@ export default {
|
|||||||
title: "",
|
title: "",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: false,
|
open: false,
|
||||||
// 查询参数 TODO 芋艿:多余字段的清理
|
// 查询参数
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
appId: null,
|
appId: null,
|
||||||
channelId: null,
|
|
||||||
channelCode: null,
|
channelCode: null,
|
||||||
merchantOrderId: null,
|
merchantOrderId: null,
|
||||||
subject: null,
|
|
||||||
body: null,
|
|
||||||
notifyUrl: null,
|
|
||||||
notifyStatus: null,
|
|
||||||
price: null,
|
|
||||||
channelFeeRate: null,
|
|
||||||
channelFeePrice: null,
|
|
||||||
status: null,
|
|
||||||
userIp: null,
|
|
||||||
successExtensionId: null,
|
|
||||||
refundStatus: null,
|
|
||||||
refundTimes: null,
|
|
||||||
refundPrice: null,
|
|
||||||
channelUserId: null,
|
|
||||||
channelOrderNo: null,
|
channelOrderNo: null,
|
||||||
expireTime: [],
|
no: null,
|
||||||
successTime: [],
|
status: null,
|
||||||
notifyTime: [],
|
createTime: [],
|
||||||
createTime: []
|
|
||||||
},
|
},
|
||||||
// 商户加载遮罩层
|
|
||||||
merchantLoading: false,
|
|
||||||
// 商户列表集合
|
|
||||||
merchantList: null,
|
|
||||||
// 支付应用列表集合
|
// 支付应用列表集合
|
||||||
appList: null,
|
appList: [],
|
||||||
// 支付渠道编码字典数据集合
|
// 订单详情
|
||||||
payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),
|
orderDetail: {
|
||||||
// 订单回调商户状态字典数据集合
|
extension: {}
|
||||||
payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),
|
},
|
||||||
// 订单状态字典数据集合
|
|
||||||
payOrderDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_STATUS),
|
|
||||||
// 订单退款状态字典数据集合
|
|
||||||
payOrderRefundDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS),
|
|
||||||
orderDetail: JSON.parse(JSON.stringify(defaultOrderDetail)),
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
// 初始化默认时间
|
|
||||||
this.initTime();
|
|
||||||
this.getList();
|
this.getList();
|
||||||
this.handleGetMerchantListByName(null);
|
// 获得筛选项
|
||||||
|
getAppList().then(response => {
|
||||||
|
this.appList = response.data;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initTime(){
|
|
||||||
this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];
|
|
||||||
},
|
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
getList() {
|
getList() {
|
||||||
// 判断选择的日期是否超过了一个月
|
|
||||||
let oneMonthTime = 31 * 24 * 3600 * 1000;
|
|
||||||
if (this.queryParams.createTime == null){
|
|
||||||
this.initTime();
|
|
||||||
} else {
|
|
||||||
let minDateTime = new Date(this.queryParams.createTime[0]).getTime();
|
|
||||||
let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()
|
|
||||||
if (maxDateTime - minDateTime > oneMonthTime) {
|
|
||||||
this.$message.error('时间范围最大为 31 天!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
// 执行查询
|
// 执行查询
|
||||||
getOrderPage(this.queryParams).then(response => {
|
getOrderPage(this.queryParams).then(response => {
|
||||||
@ -339,22 +263,20 @@ export default {
|
|||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.resetForm("queryForm");
|
this.resetForm("queryForm");
|
||||||
this.initTime();
|
|
||||||
this.handleQuery();
|
this.handleQuery();
|
||||||
},
|
},
|
||||||
/**
|
/** 详情按钮操作 */
|
||||||
* 查看订单详情
|
handleDetail(row) {
|
||||||
*/
|
this.orderDetail = {};
|
||||||
handleQueryDetails(row) {
|
|
||||||
this.orderDetail = JSON.parse(JSON.stringify(defaultOrderDetail));
|
|
||||||
getOrderDetail(row.id).then(response => {
|
getOrderDetail(row.id).then(response => {
|
||||||
|
// 设置值
|
||||||
this.orderDetail = response.data;
|
this.orderDetail = response.data;
|
||||||
if (response.data.payOrderExtension === null) {
|
if (!this.orderDetail.extension) {
|
||||||
this.orderDetail.payOrderExtension = Object.assign(defaultOrderDetail.payOrderExtension, {});
|
this.orderDetail.extension = {}
|
||||||
}
|
}
|
||||||
|
// 弹窗打开
|
||||||
this.open = true;
|
this.open = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
|
@ -7,31 +7,30 @@
|
|||||||
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="渠道编码" prop="channelCode">
|
<el-form-item label="退款渠道" prop="channelCode">
|
||||||
<el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable
|
<el-select v-model="queryParams.channelCode" placeholder="请选择退款渠道" clearable>
|
||||||
@clear="()=>{queryParams.channelCode = null}">
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
<el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="退款类型" prop="type">
|
<el-form-item label="商户支付单号" prop="merchantOrderId">
|
||||||
<el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable>
|
<el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户支付单号" clearable
|
||||||
<el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"
|
@keyup.enter.native="handleQuery"/>
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="商户退款订单号" prop="merchantRefundNo">
|
<el-form-item label="商户退款单号" prop="merchantRefundId">
|
||||||
<el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable
|
<el-input v-model="queryParams.merchantRefundId" placeholder="请输入商户退款单号" clearable
|
||||||
|
@keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="渠道支付单号" prop="channelOrderNo">
|
||||||
|
<el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道支付单号" clearable
|
||||||
|
@keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="渠道退款单号" prop="channelRefundNo">
|
||||||
|
<el-input v-model="queryParams.channelRefundNo" placeholder="请输入渠道退款单号" clearable
|
||||||
@keyup.enter.native="handleQuery"/>
|
@keyup.enter.native="handleQuery"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="退款状态" prop="status">
|
<el-form-item label="退款状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable>
|
<el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable>
|
||||||
<el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"
|
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_REFUND_STATUS)" :key="parseInt(dict.value)"
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="退款回调状态" prop="notifyStatus">
|
|
||||||
<el-select v-model="queryParams.notifyStatus" placeholder="请选择通知商户退款结果的回调状态" clearable>
|
|
||||||
<el-option v-for="dict in payOrderNotifyDictDatum" :key="parseInt(dict.value)"
|
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
:label="dict.label" :value="parseInt(dict.value)"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -58,79 +57,64 @@
|
|||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<el-table v-loading="loading" :data="list">
|
<el-table v-loading="loading" :data="list">
|
||||||
<el-table-column label="编号" align="center" prop="id"/>
|
<el-table-column label="编号" align="center" prop="id"/>
|
||||||
<el-table-column label="支付渠道" align="center" width="130">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template v-slot="scope">
|
|
||||||
<el-popover trigger="hover" placement="top">
|
|
||||||
<p>应用名称: {{ scope.row.appName }}</p>
|
|
||||||
<p>渠道名称: {{ scope.row.channelCodeName }}</p>
|
|
||||||
<div slot="reference" class="name-wrapper">
|
|
||||||
{{ scope.row.channelCodeName }}
|
|
||||||
</div>
|
|
||||||
</el-popover>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->
|
|
||||||
<!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->
|
|
||||||
<el-table-column label="商户订单号" align="left" width="230">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<p class="order-font">
|
|
||||||
<el-tag size="mini">退款</el-tag>
|
|
||||||
{{ scope.row.merchantRefundNo }}
|
|
||||||
</p>
|
|
||||||
<p class="order-font">
|
|
||||||
<el-tag type="success">交易</el-tag>
|
|
||||||
{{ scope.row.merchantOrderId }}
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="支付订单号" align="center" prop="merchantRefundNo" width="250">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<p class="order-font">
|
|
||||||
<el-tag size="mini">交易</el-tag>
|
|
||||||
{{ scope.row.tradeNo }}
|
|
||||||
</p>
|
|
||||||
<p class="order-font">
|
|
||||||
<el-tag size="mini" type="warning">渠道</el-tag>
|
|
||||||
{{ scope.row.channelOrderNo }}
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="支付金额(元)" align="center" prop="payPrice" width="100">
|
|
||||||
<template v-slot="scope" class="">
|
|
||||||
¥{{ parseFloat(scope.row.payPrice / 100).toFixed(2) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="退款金额(元)" align="center" prop="refundPrice" width="100">
|
|
||||||
<template v-slot="scope">
|
|
||||||
¥{{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="退款类型" align="center" prop="type" width="80">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="scope.row.type" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="退款状态" align="center" prop="status">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="scope.row.status" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="回调状态" align="center" prop="notifyStatus">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="退款原因" align="center" prop="reason" width="140" :show-overflow-tooltip="true"/>
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
|
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="退款成功时间" align="center" prop="successTime" width="100">
|
<el-table-column label="支付金额" align="center" prop="payPrice" width="100">
|
||||||
|
<template v-slot="scope" class="">
|
||||||
|
¥{{ (scope.row.payPrice / 100.0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
|
||||||
|
<template v-slot="scope">
|
||||||
|
¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="退款订单号" align="left" width="300">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<p class="order-font">
|
||||||
|
<el-tag size="mini">商户</el-tag> {{scope.row.merchantRefundId}}
|
||||||
|
</p>
|
||||||
|
<p class="order-font">
|
||||||
|
<el-tag size="mini" type="warning">退款</el-tag> {{scope.row.no}}
|
||||||
|
</p>
|
||||||
|
<p class="order-font" v-if="scope.row.channelRefundNo">
|
||||||
|
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelRefundNo}}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="支付订单号" align="left" width="300">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<p class="order-font">
|
||||||
|
<el-tag size="mini">商户</el-tag> {{scope.row.merchantOrderId}}
|
||||||
|
</p>
|
||||||
|
<p class="order-font">
|
||||||
|
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="退款状态" align="center" prop="status">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="退款渠道" align="center" width="140">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="成功时间" align="center" prop="successTime" width="180">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span>{{ parseTime(scope.row.successTime) }}</span>
|
<span>{{ parseTime(scope.row.successTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="支付应用" align="center" prop="successTime" width="100">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<span>{{ scope.row.appName }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)"
|
<el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)"
|
||||||
@ -143,107 +127,76 @@
|
|||||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"/>
|
@pagination="getList"/>
|
||||||
|
|
||||||
<!-- 对话框(添加 / 修改) -->
|
<!-- 对话框(详情) -->
|
||||||
<el-dialog title="退款订单详情" :visible.sync="open" width="700px" append-to-body>
|
<el-dialog title="退款订单详情" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
|
||||||
<el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="商品名称">{{ refundDetail.subject }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
<el-divider></el-divider>
|
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="商户退款单号">
|
<el-descriptions-item label="商户退款单号">
|
||||||
<el-tag size="mini">{{ refundDetail.merchantRefundNo }}</el-tag>
|
<el-tag size="small">{{ refundDetail.merchantRefundId }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="渠道退款单号">
|
||||||
|
<el-tag type="success" size="small" v-if="refundDetail.channelRefundNo">{{ refundDetail.channelRefundNo }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-divider></el-divider>
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="商户支付单号">
|
||||||
|
<el-tag size="small">{{ refundDetail.merchantOrderId }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="渠道支付单号">
|
||||||
|
<el-tag type="success" size="small">{{ refundDetail.channelOrderNo }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
|
<el-descriptions-item label="应用编号">{{ refundDetail.appId }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="支付金额">
|
<el-descriptions-item label="支付金额">
|
||||||
{{ parseFloat(refundDetail.payPrice / 100).toFixed(2) }}
|
<el-tag type="success" size="small">¥{{ (refundDetail.payPrice / 100.0).toFixed(2) }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="退款金额" size="mini">
|
<el-descriptions-item label="退款金额">
|
||||||
<el-tag class="tag-purple" size="mini">{{ parseFloat(refundDetail.refundPrice / 100).toFixed(2) }}</el-tag>
|
<el-tag size="mini" type="danger">¥{{ (refundDetail.refundPrice / 100.0).toFixed(2) }}</el-tag>
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="退款类型">
|
|
||||||
<template v-slot="scope">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="refundDetail.type" />
|
|
||||||
</template>
|
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="退款状态">
|
<el-descriptions-item label="退款状态">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="refundDetail.status" />
|
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="refundDetail.status" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="退款时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item>
|
<el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="退款成功时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="退款失效时间">{{ parseTime(refundDetail.expireTime) }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item>
|
<el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-divider></el-divider>
|
<!-- 分割线 -->
|
||||||
|
<el-divider />
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="支付渠道">
|
<el-descriptions-item label="退款渠道">
|
||||||
{{ refundDetail.channelCodeName }}
|
<dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="refundDetail.channelCode" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="支付IP" size="mini">
|
<el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item>
|
||||||
{{refundDetail.userIp}}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="回调地址">{{ refundDetail.notifyUrl }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="回调状态">
|
|
||||||
<dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="refundDetail.notifyStatus" />
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="回调时间">{{ parseTime(refundDetail.notifyTime) }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-divider></el-divider>
|
|
||||||
<el-descriptions :column="2" label-class-name="desc-label">
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="渠道订单号">{{ refundDetail.channelOrderNo }}</el-descriptions-item>
|
<el-descriptions-item label="退款 IP">{{ refundDetail.userIp }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="渠道退款单号">{{ refundDetail.channelRefundNo }}</el-descriptions-item>
|
<el-descriptions-item label="通知 URL">{{ refundDetail.notifyUrl }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<el-divider />
|
||||||
|
<el-descriptions :column="2" label-class-name="desc-label">
|
||||||
<el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item>
|
<el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item>
|
<el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<br>
|
|
||||||
<el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
|
<el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
|
||||||
<el-descriptions-item label="渠道额外参数">{{ refundDetail.channelExtras }}</el-descriptions-item>
|
<el-descriptions-item label="支付通道异步回调内容">
|
||||||
<el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item>
|
{{ refundDetail.channelNotifyData }}
|
||||||
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getRefundPage, exportRefundExcel, getRefund} from "@/api/pay/refund";
|
import { getRefundPage, exportRefundExcel, getRefund } from "@/api/pay/refund";
|
||||||
import { DICT_TYPE, getDictDatas } from "@/utils/dict";
|
import { getAppList } from "@/api/pay/app";
|
||||||
import { PayOrderRefundStatusEnum, PayRefundStatusEnum } from "@/utils/constants";
|
|
||||||
import { getNowDateTime } from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
const defaultRefundDetail = {
|
|
||||||
id: null,
|
|
||||||
appId: null,
|
|
||||||
appName: '',
|
|
||||||
channelCode: '',
|
|
||||||
channelCodeName: '',
|
|
||||||
channelErrorCode: '',
|
|
||||||
channelErrorMsg: '',
|
|
||||||
channelExtras: '',
|
|
||||||
channelId: null,
|
|
||||||
channelOrderNo: '',
|
|
||||||
channelRefundNo: '',
|
|
||||||
createTime: null,
|
|
||||||
expireTime: null,
|
|
||||||
merchantOrderId: '',
|
|
||||||
merchantRefundNo: '',
|
|
||||||
notifyStatus: null,
|
|
||||||
notifyTime: null,
|
|
||||||
notifyUrl: '',
|
|
||||||
orderId: null,
|
|
||||||
payPrice: null,
|
|
||||||
reason: '',
|
|
||||||
refundPrice: null,
|
|
||||||
status: null,
|
|
||||||
subject: '',
|
|
||||||
successTime: null,
|
|
||||||
tradeNo: '',
|
|
||||||
type: null,
|
|
||||||
userIp: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PayRefund",
|
name: "PayRefund",
|
||||||
@ -267,73 +220,30 @@ export default {
|
|||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
appId: null,
|
appId: null,
|
||||||
channelId: null,
|
|
||||||
channelCode: null,
|
channelCode: null,
|
||||||
orderId: null,
|
|
||||||
tradeNo: null,
|
|
||||||
merchantOrderId: null,
|
merchantOrderId: null,
|
||||||
merchantRefundNo: null,
|
merchantRefundId: null,
|
||||||
notifyUrl: null,
|
|
||||||
notifyStatus: null,
|
|
||||||
status: null,
|
|
||||||
type: null,
|
|
||||||
payPrice: null,
|
|
||||||
refundPrice: null,
|
|
||||||
reason: null,
|
|
||||||
userIp: null,
|
|
||||||
channelOrderNo: null,
|
channelOrderNo: null,
|
||||||
channelRefundNo: null,
|
channelRefundNo: null,
|
||||||
channelErrorCode: null,
|
status: null,
|
||||||
channelErrorMsg: null,
|
|
||||||
channelExtras: null,
|
|
||||||
expireTime: [],
|
|
||||||
successTime: [],
|
|
||||||
notifyTime: [],
|
|
||||||
createTime: []
|
createTime: []
|
||||||
},
|
},
|
||||||
// 商户加载遮罩层
|
|
||||||
merchantLoading: false,
|
|
||||||
// 商户列表集合
|
|
||||||
merchantList: null,
|
|
||||||
// 支付应用列表集合
|
// 支付应用列表集合
|
||||||
appList: null,
|
appList: [],
|
||||||
// 支付渠道编码字典数据集合
|
|
||||||
payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),
|
|
||||||
// 订单退款状态字典数据集合
|
|
||||||
payRefundOrderDictDatum: getDictDatas(DICT_TYPE.PAY_REFUND_ORDER_STATUS),
|
|
||||||
// 退款订单类别字典数据集合
|
|
||||||
payRefundOrderTypeDictDatum: getDictDatas(DICT_TYPE.PAY_REFUND_ORDER_TYPE),
|
|
||||||
// 订单回调商户状态字典数据集合
|
|
||||||
payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),
|
|
||||||
// el-tag订单退款状态type值
|
|
||||||
refundStatusType: '',
|
|
||||||
// 退款订单详情
|
// 退款订单详情
|
||||||
refundDetail: JSON.parse(JSON.stringify(defaultRefundDetail)),
|
refundDetail: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initTime();
|
|
||||||
this.getList();
|
this.getList();
|
||||||
this.handleGetMerchantListByName(null);
|
// 获得筛选项
|
||||||
|
getAppList().then(response => {
|
||||||
|
this.appList = response.data;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initTime(){
|
|
||||||
this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];
|
|
||||||
},
|
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
getList() {
|
getList() {
|
||||||
// 判断选择的日期是否超过了一个月
|
|
||||||
let oneMonthTime = 31 * 24 * 3600 * 1000;
|
|
||||||
if (this.queryParams.createTime == null){
|
|
||||||
this.initTime();
|
|
||||||
} else {
|
|
||||||
let minDateTime = new Date(this.queryParams.createTime[0]).getTime();
|
|
||||||
let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()
|
|
||||||
if (maxDateTime - minDateTime > oneMonthTime) {
|
|
||||||
this.$message.error('时间范围最大为 31 天!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
// 执行查询
|
// 执行查询
|
||||||
getRefundPage(this.queryParams).then(response => {
|
getRefundPage(this.queryParams).then(response => {
|
||||||
@ -369,60 +279,13 @@ export default {
|
|||||||
this.$download.excel(response, '退款订单.xls');
|
this.$download.excel(response, '退款订单.xls');
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
},
|
},
|
||||||
/**
|
/** 详情按钮操作 */
|
||||||
* 根据商户名称模糊匹配商户信息
|
|
||||||
* @param name 商户名称
|
|
||||||
*/
|
|
||||||
handleGetMerchantListByName(name) {
|
|
||||||
getMerchantListByName(name).then(response => {
|
|
||||||
this.merchantList = response.data;
|
|
||||||
this.merchantLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 根据退款类别得到样式名称
|
|
||||||
* @param refundType 退款类别
|
|
||||||
*/
|
|
||||||
findByRefundTypeGetStyle(refundType) {
|
|
||||||
switch (refundType) {
|
|
||||||
case PayOrderRefundStatusEnum.NO.status:
|
|
||||||
return "success";
|
|
||||||
case PayOrderRefundStatusEnum.SOME.status:
|
|
||||||
return "warning";
|
|
||||||
case PayOrderRefundStatusEnum.ALL.status:
|
|
||||||
return "danger";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 根据退款状态得到样式名称
|
|
||||||
* @param refundStatus 退款状态
|
|
||||||
*/
|
|
||||||
findByRefundStatusGetStyle(refundStatus) {
|
|
||||||
switch (refundStatus) {
|
|
||||||
case PayRefundStatusEnum.CREATE.status:
|
|
||||||
return "info";
|
|
||||||
case PayRefundStatusEnum.SUCCESS.status:
|
|
||||||
return "success";
|
|
||||||
case PayRefundStatusEnum.FAILURE.status:
|
|
||||||
case PayRefundStatusEnum.CLOSE.status:
|
|
||||||
return "danger";
|
|
||||||
case PayRefundStatusEnum.PROCESSING_NOTIFY.status:
|
|
||||||
case PayRefundStatusEnum.PROCESSING_QUERY.status:
|
|
||||||
case PayRefundStatusEnum.UNKNOWN_RETRY.status:
|
|
||||||
case PayRefundStatusEnum.UNKNOWN_QUERY.status:
|
|
||||||
return "warning";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 查看订单详情
|
|
||||||
*/
|
|
||||||
handleQueryDetails(row) {
|
handleQueryDetails(row) {
|
||||||
this.refundDetail = JSON.parse(JSON.stringify(defaultRefundDetail));
|
this.refundDetail = {};
|
||||||
getRefund(row.id).then(response => {
|
getRefund(row.id).then(response => {
|
||||||
this.refundDetail = response.data;
|
this.refundDetail = response.data;
|
||||||
this.open = true;
|
this.open = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user