mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-03 11:06:46 +00:00
feat 支付/退款/关闭结构调整
This commit is contained in:
@@ -76,11 +76,12 @@
|
||||
- [x] 支付对账收尾
|
||||
- [x] 支付退款调整为订单+明细
|
||||
- 2024-01-24:
|
||||
- [ ] 支付策略优化通道支付单和可退款信息相关关系
|
||||
- [x] 支付策略优化通道支付单和可退款信息相关关系
|
||||
- [x] 支付退款处理退款中状态
|
||||
- [ ] 支付修复策略优化存储记录信息
|
||||
- [ ] 优化支付修复时的触发来源的获取
|
||||
- [ ] 微信退款状态不一致补偿
|
||||
- [ ] 去除各通道支付记录,统一为通道支付记录
|
||||
- [x] 去除各通道支付记录,统一为通道支付记录
|
||||
- **任务池**
|
||||
- [ ] 支付SDK编写
|
||||
- [ ] 接入支付网关的演示项目
|
||||
|
@@ -66,11 +66,16 @@ public class PayOrderController {
|
||||
return Res.ok(payOrderExtraService.findById(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询支付订单关联支付通道")
|
||||
@GetMapping("/getChannels")
|
||||
public ResResult<List<PayChannelOrderDto>> getChannels(Long paymentId){
|
||||
@Operation(summary = "查询支付订单关联支付通道订单")
|
||||
@GetMapping("/listByChannel")
|
||||
public ResResult<List<PayChannelOrderDto>> listByChannel(Long paymentId){
|
||||
return Res.ok(payChannelOrderService.findAllByPaymentId(paymentId));
|
||||
}
|
||||
@Operation(summary = "查询支付通道订单详情")
|
||||
@GetMapping("/getChannel")
|
||||
public ResResult<PayChannelOrderDto> getChannel(Long id){
|
||||
return Res.ok(payChannelOrderService.findById(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "同步支付状态")
|
||||
@PostMapping("/sync")
|
||||
|
@@ -12,8 +12,12 @@ import lombok.Getter;
|
||||
@AllArgsConstructor
|
||||
public enum PayRefundStatusEnum {
|
||||
|
||||
/**
|
||||
* 接口调用成功不代表成功
|
||||
*/
|
||||
PROGRESS("progress","退款中"),
|
||||
SUCCESS("success","成功"),
|
||||
FAIL("fail"," ");
|
||||
FAIL("fail","失败");
|
||||
|
||||
/** 编码 */
|
||||
private final String code;
|
||||
|
@@ -18,6 +18,7 @@ public enum PayStatusEnum {
|
||||
PROGRESS("progress","支付中"),
|
||||
SUCCESS("success","成功"),
|
||||
CLOSE("close","支付关闭"),
|
||||
REFUNDING("refunding","退款中"),
|
||||
PARTIAL_REFUND("partial_refund","部分退款"),
|
||||
REFUNDED("refunded","全部退款"),
|
||||
FAIL("fail","失败");
|
||||
|
@@ -20,6 +20,7 @@ public enum PaySyncStatusEnum {
|
||||
PAY_SUCCESS("pay_success", "支付成功"),
|
||||
PAY_WAIT("pay_wait", "待支付"),
|
||||
CLOSED("closed", "已关闭"),
|
||||
REFUNDING("refunding", "退款中"),
|
||||
/** 部分退款 */
|
||||
PARTIAL_REFUND("partial_refund","部分退款"),
|
||||
/** 全部退款 */
|
||||
|
@@ -1,10 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.param.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WeChatPayParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -35,15 +31,4 @@ public class RefundChannelParam {
|
||||
@Min(1)
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 预留的扩展参数, 暂时未使用
|
||||
* @see AliPayParam
|
||||
* @see WeChatPayParam
|
||||
* @see VoucherPayParam
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
@Schema(description = "附加退款参数")
|
||||
private String channelExtra;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ public class RefundParam extends PayCommonParam {
|
||||
private boolean refundAll;
|
||||
|
||||
/**
|
||||
* 退款号, 可以为空, 但不可以重复, 部分退款时推荐传输
|
||||
* 退款号可以为空, 但不可以重复, 如果退款号为空, 则系统会自动生成退款号, 与退款ID一致
|
||||
*/
|
||||
@Schema(description = "退款号")
|
||||
private String refundNo;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.result.order;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -12,15 +13,32 @@ import lombok.Data;
|
||||
@Schema(title = "支付订单通道响应参数")
|
||||
public class PayOrderChannelResult {
|
||||
|
||||
|
||||
@Schema(description = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@Schema(description = "通道")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "支付方式")
|
||||
private String payWay;
|
||||
|
||||
@Schema(description = "异步支付方式")
|
||||
private boolean async;
|
||||
/**
|
||||
* 第三方支付网关生成的订单号, 用与将记录关联起来
|
||||
*/
|
||||
@Schema(description = "关联网关支付号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
@Schema(description = "支付状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "金额")
|
||||
private Integer amount;
|
||||
|
||||
@Schema(description = "可退款金额")
|
||||
private Integer refundableBalance;
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package cn.bootx.platform.daxpay.result.order;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.result.CommonResult;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
@@ -73,9 +72,6 @@ public class PayOrderResult extends CommonResult {
|
||||
@Schema(description = "过期时间")
|
||||
private LocalDateTime expiredTime;
|
||||
|
||||
@Schema(description = "可退款信息列表")
|
||||
private List<RefundableInfo> refundableInfos;
|
||||
|
||||
@Schema(description = "支付通道列表")
|
||||
private List<PayOrderChannelResult> channels;
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ public class RefundChannelOrderResult {
|
||||
private boolean async;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private Integer totalAmount;
|
||||
private Integer orderAmount;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private Integer amount;
|
||||
|
@@ -7,7 +7,7 @@ import lombok.experimental.Accessors;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 异步支付信息,不只局限在支付流程,同步、退款、回调中都会用到
|
||||
* 异步支付信息
|
||||
* @author xxm
|
||||
* @since 2021/2/28
|
||||
*/
|
||||
@@ -22,20 +22,21 @@ public class AsyncPayLocal {
|
||||
private String payWay;
|
||||
|
||||
/**
|
||||
* 第三方支付平台订单号
|
||||
* 第三方支付网关生成的订单号, 用与将记录关联起来
|
||||
* 1. 如付款码支付直接成功时会出现
|
||||
* 2. 回调或者支付同步时也会有这个值
|
||||
*/
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 是否支付完成 */
|
||||
private boolean payComplete;
|
||||
|
||||
/** 支付参数体(通常用于发起支付的参数) */
|
||||
private String payBody;
|
||||
|
||||
/** 订单失效时间, 优先用这个 */
|
||||
/** 订单失效时间, */
|
||||
private LocalDateTime expiredTime;
|
||||
|
||||
/** 支付完成时间(通常用于接收异步支付返回的时间) */
|
||||
/** 支付完成时间 从支付网关中获取 */
|
||||
private LocalDateTime payTime;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
package cn.bootx.platform.daxpay.service.common.context;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 回调信息上下文
|
||||
* @author xxm
|
||||
* @since 2024/1/24
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CallbackLocal {
|
||||
|
||||
/** 回调参数内容 */
|
||||
private final Map<String, String> callbackParam = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 第三方支付平台订单号
|
||||
* 1. 如付款码支付直接成功时会出现
|
||||
*/
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 支付完成时间 */
|
||||
private LocalDateTime payTime;
|
||||
}
|
@@ -4,7 +4,7 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付通知
|
||||
* 支付通知(主动发起, 用于通知客户系统)
|
||||
* @author xxm
|
||||
* @since 2023/12/24
|
||||
*/
|
||||
|
@@ -0,0 +1,26 @@
|
||||
package cn.bootx.platform.daxpay.service.common.context;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 支付同步信息
|
||||
* @author xxm
|
||||
* @since 2024/1/24
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PaySyncLocal {
|
||||
|
||||
/**
|
||||
* 第三方支付网关生成的订单号, 用与将记录关联起来
|
||||
* 1. 如付款码支付直接成功时会出现
|
||||
*/
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 支付完成时间(通常用于接收异步支付返回的时间) */
|
||||
private LocalDateTime payTime;
|
||||
|
||||
}
|
@@ -3,9 +3,6 @@ package cn.bootx.platform.daxpay.service.common.context;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 支付上下文
|
||||
* @author xxm
|
||||
@@ -19,24 +16,27 @@ public class PaymentContext {
|
||||
private final ApiInfoLocal apiInfo = new ApiInfoLocal();;
|
||||
|
||||
/** 平台全局配置 */
|
||||
private final PlatformLocal platform = new PlatformLocal();
|
||||
private final PlatformLocal platformInfo = new PlatformLocal();
|
||||
|
||||
/** 异步支付相关信息, 不只局限在支付流程,同步、回调中都会用到 */
|
||||
/** 异步支付相关信息 */
|
||||
private final AsyncPayLocal asyncPayInfo = new AsyncPayLocal();
|
||||
|
||||
/** 异步退款相关信息 */
|
||||
/** 退款相关信息 */
|
||||
private final RefundLocal refundInfo = new RefundLocal();
|
||||
|
||||
/** 消息通知相关信息 */
|
||||
/** 消息通知(主动发起)相关信息 */
|
||||
private final NoticeLocal noticeInfo = new NoticeLocal();
|
||||
|
||||
/** 回调参数内容 */
|
||||
private final Map<String, String> callbackParam = new HashMap<>();
|
||||
/** 回调相关信息 */
|
||||
private final CallbackLocal callbackInfo = new CallbackLocal();
|
||||
|
||||
/** 支付请求相关信息 */
|
||||
private final RequestLocal request = new RequestLocal();
|
||||
/** 请求相关信息 */
|
||||
private final RequestLocal requestInfo = new RequestLocal();
|
||||
|
||||
/** 支付对账相关信息 */
|
||||
private final ReconcileLocal reconcile = new ReconcileLocal();
|
||||
/** 支付同步相关信息 */
|
||||
private final PaySyncLocal paySyncInfo = new PaySyncLocal();
|
||||
|
||||
/** 对账相关信息 */
|
||||
private final ReconcileLocal reconcileInfo = new ReconcileLocal();
|
||||
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcile
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -19,4 +20,7 @@ public class ReconcileLocal {
|
||||
private List<PayReconcileDetail> reconcileDetails;
|
||||
|
||||
|
||||
/** 支付完成时间 从支付网关中获取 */
|
||||
private LocalDateTime payTime;
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.common.context;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -13,9 +15,19 @@ import lombok.experimental.Accessors;
|
||||
public class RefundLocal {
|
||||
|
||||
/**
|
||||
* 异步通道退款时发给网关的退款号, 用与将记录关联起来
|
||||
* 第三方支付网关生成的退款订单号, 用与将记录关联起来
|
||||
*/
|
||||
private String gatewayRequestNo;
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/**
|
||||
* 支付退款ID, 用于异步支付时传入的退款号, 使用退款单ID
|
||||
*/
|
||||
private long refundId = IdUtil.getSnowflakeNextId();
|
||||
|
||||
/**
|
||||
* 退款状态, 默认为成功, 通常含有异步支付时, 才会出现别的状态
|
||||
*/
|
||||
private PayRefundStatusEnum status = PayRefundStatusEnum.SUCCESS;
|
||||
|
||||
/** 错误码 */
|
||||
private String errorCode;
|
||||
|
@@ -5,6 +5,7 @@ import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.redis.RedisClient;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
|
||||
@@ -58,7 +59,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public String getTradeStatus() {
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
String tradeStatus = params.get(TRADE_STATUS);
|
||||
if (Objects.equals(tradeStatus, NOTIFY_TRADE_SUCCESS)) {
|
||||
return PayStatusEnum.SUCCESS.getCode();
|
||||
@@ -72,7 +73,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
Map<String, String> params =PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params =PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
String callReq = JSONUtil.toJsonStr(params);
|
||||
String appId = params.get(APP_ID);
|
||||
if (StrUtil.isBlank(appId)) {
|
||||
@@ -102,16 +103,19 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void initContext() {
|
||||
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
|
||||
CallbackLocal callback = PaymentContextLocal.get()
|
||||
.getCallbackInfo();
|
||||
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackInfo()
|
||||
.getCallbackParam();
|
||||
// 订单号
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setGatewayOrderNo(callbackParam.get(TRADE_NO));
|
||||
callback.setGatewayOrderNo(callbackParam.get(TRADE_NO));
|
||||
// 支付时间
|
||||
String gmpTime = callbackParam.get(GMT_PAYMENT);
|
||||
if (StrUtil.isNotBlank(gmpTime)) {
|
||||
LocalDateTime time = LocalDateTimeUtil.parse(gmpTime, DatePattern.NORM_DATETIME_PATTERN);
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(time);
|
||||
callback.setPayTime(time);
|
||||
} else {
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(LocalDateTime.now());
|
||||
callback.setPayTime(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +124,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public Long getPaymentId() {
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
return Long.valueOf(params.get(OUT_TRADE_NO));
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,16 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.dao.AliPayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -36,27 +31,6 @@ public class AliPayOrderService {
|
||||
|
||||
private final PayChannelOrderService payChannelOrderService;
|
||||
|
||||
/**
|
||||
* 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建支付宝支付单
|
||||
*/
|
||||
public void updatePaySuccess(PayOrder payOrder, PayChannelParam payChannelParam) {
|
||||
// 更新支付宝异步支付类型信息
|
||||
payOrder.setAsyncPay(true).setAsyncChannel(PayChannelEnum.ALI.getCode());
|
||||
payChannelOrderService.updateAsyncChannelOrder(payOrder,payChannelParam);
|
||||
|
||||
// 更新支付宝可退款类型信息
|
||||
List<RefundableInfo> refundableInfos = payOrder.getRefundableInfos();
|
||||
refundableInfos.removeIf(payTypeInfo -> PayChannelEnum.ASYNC_TYPE_CODE.contains(payTypeInfo.getChannel()));
|
||||
refundableInfos.add(new RefundableInfo()
|
||||
.setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setAmount(payChannelParam.getAmount())
|
||||
);
|
||||
payOrder.setRefundableInfos(refundableInfos);
|
||||
// 如果支付完成(付款码情况) 调用 updateSyncSuccess 创建支付宝支付记录
|
||||
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.SUCCESS.getCode())) {
|
||||
this.updateAsyncSuccess(payOrder, payChannelParam.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新异步支付记录成功状态, 并创建支付宝支付记录
|
||||
|
@@ -123,7 +123,7 @@ public class AliPayReconcileService {
|
||||
.map(this::convert)
|
||||
.collect(Collectors.toList());
|
||||
// 写入到上下文中
|
||||
PaymentContextLocal.get().getReconcile().setReconcileDetails(collect);
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,11 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||
@@ -32,14 +32,13 @@ public class AliPayRefundService {
|
||||
public void refund(PayOrder payOrder, int amount) {
|
||||
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
|
||||
refundModel.setOutTradeNo(String.valueOf(payOrder.getId()));
|
||||
|
||||
// 金额转换
|
||||
String refundAmount = String.valueOf(amount*0.01);
|
||||
refundModel.setRefundAmount(refundAmount);
|
||||
|
||||
// 设置退款信息
|
||||
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setGatewayRequestNo(PayUtil.getRefundNo());
|
||||
refundModel.setOutRequestNo(refundInfo.getGatewayRequestNo());
|
||||
refundModel.setOutRequestNo(String.valueOf(refundInfo.getRefundId()));
|
||||
try {
|
||||
AlipayTradeRefundResponse response = AliPayApi.tradeRefundToResponse(refundModel);
|
||||
if (!Objects.equals(AliPayCode.SUCCESS, response.getCode())) {
|
||||
@@ -48,6 +47,11 @@ public class AliPayRefundService {
|
||||
log.error("网关返回退款失败: {}", response.getSubMsg());
|
||||
throw new PayFailureException(response.getSubMsg());
|
||||
}
|
||||
// 接口返回fund_change=Y为退款成功,fund_change=N或无此字段值返回时需通过退款查询接口进一步确认退款状态
|
||||
if (response.getFundChange().equals("Y")){
|
||||
refundInfo.setStatus(PayRefundStatusEnum.SUCCESS)
|
||||
.setGatewayOrderNo(response.getTradeNo());
|
||||
}
|
||||
}
|
||||
catch (AlipayApiException e) {
|
||||
log.error("订单退款失败:", e);
|
||||
|
@@ -87,8 +87,7 @@ public class AliPayService {
|
||||
}
|
||||
// 付款码支付
|
||||
else if (Objects.equals(payChannelParam.getWay(), PayWayEnum.BARCODE.getCode())) {
|
||||
String tradeNo = this.barCode(amount, payOrder, aliPayParam, alipayConfig);
|
||||
asyncPayInfo.setGatewayOrderNo(tradeNo);
|
||||
this.barCode(amount, payOrder, aliPayParam, alipayConfig);
|
||||
}
|
||||
// 通常是发起支付的参数
|
||||
asyncPayInfo.setPayBody(payBody);
|
||||
@@ -99,7 +98,6 @@ public class AliPayService {
|
||||
*/
|
||||
public String wapPay(int amount, PayOrder payOrder, AliPayConfig alipayConfig) {
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
|
||||
model.setSubject(payOrder.getTitle());
|
||||
model.setOutTradeNo(String.valueOf(payOrder.getId()));
|
||||
@@ -210,9 +208,10 @@ public class AliPayService {
|
||||
/**
|
||||
* 付款码支付
|
||||
*/
|
||||
public String barCode(int amount, PayOrder payOrder, AliPayParam aliPayParam, AliPayConfig alipayConfig) {
|
||||
AlipayTradePayModel model = new AlipayTradePayModel();
|
||||
public void barCode(int amount, PayOrder payOrder, AliPayParam aliPayParam, AliPayConfig alipayConfig) {
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
|
||||
AlipayTradePayModel model = new AlipayTradePayModel();
|
||||
model.setSubject(payOrder.getTitle());
|
||||
model.setOutTradeNo(String.valueOf(payOrder.getId()));
|
||||
model.setScene(AliPayCode.BAR_CODE);
|
||||
@@ -227,7 +226,8 @@ public class AliPayService {
|
||||
// 支付成功处理 金额2000以下免密支付
|
||||
if (Objects.equals(response.getCode(), AliPayCode.SUCCESS)) {
|
||||
payOrder.setStatus(PayStatusEnum.SUCCESS.getCode()).setPayTime(LocalDateTime.now());
|
||||
return response.getTradeNo();
|
||||
asyncPayInfo.setGatewayOrderNo(response.getTradeNo())
|
||||
.setPayComplete(true);
|
||||
}
|
||||
// 非支付中响应码, 进行错误处理
|
||||
if (!Objects.equals(response.getCode(), AliPayCode.INPROCESS)) {
|
||||
@@ -238,7 +238,6 @@ public class AliPayService {
|
||||
log.error("主动扫码支付失败", e);
|
||||
throw new PayFailureException("主动扫码支付失败");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -51,10 +51,10 @@ public class AliPaySyncService {
|
||||
syncResult.setSyncPayInfo(JSONUtil.toJsonStr(response));
|
||||
// 支付完成 TODO 部分退款也在这个地方, 但无法进行区分, 需要借助对账进行处理
|
||||
if (Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_SUCCESS) || Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_FINISHED)) {
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setGatewayOrderNo(response.getTradeNo());
|
||||
PaymentContextLocal.get().getPaySyncInfo().setGatewayOrderNo(response.getTradeNo());
|
||||
// 支付完成时间
|
||||
LocalDateTime payTime = LocalDateTimeUtil.of(response.getSendPayDate());
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(payTime);
|
||||
PaymentContextLocal.get().getPaySyncInfo().setPayTime(payTime);
|
||||
return syncResult.setSyncStatus(PaySyncStatusEnum.PAY_SUCCESS);
|
||||
}
|
||||
// 待支付
|
||||
|
@@ -5,6 +5,7 @@ import cn.bootx.platform.common.redis.RedisClient;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.record.callback.dao.PayCallbackRecordManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
@@ -57,7 +58,7 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public Long getPaymentId() {
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
String paymentId = params.get(WeChatPayCode.OUT_TRADE_NO);
|
||||
return Long.valueOf(paymentId);
|
||||
}
|
||||
@@ -67,7 +68,7 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public String getTradeStatus() {
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
if (WxPayKit.codeIsOk(params.get(WeChatPayCode.RESULT_CODE))) {
|
||||
return PayStatusEnum.SUCCESS.getCode();
|
||||
}
|
||||
@@ -81,7 +82,7 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> params = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
String callReq = JSONUtil.toJsonStr(params);
|
||||
log.info("微信发起回调 报文: {}", callReq);
|
||||
String appId = params.get(APPID);
|
||||
@@ -104,16 +105,17 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void initContext() {
|
||||
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
// 订单号
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setGatewayOrderNo(callbackParam.get(WeChatPayCode.TRANSACTION_ID));
|
||||
callbackInfo.setGatewayOrderNo(callbackParam.get(WeChatPayCode.TRANSACTION_ID));
|
||||
// 支付时间
|
||||
String timeEnd = callbackParam.get(TIME_END);
|
||||
if (StrUtil.isNotBlank(timeEnd)) {
|
||||
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(time);
|
||||
callbackInfo.setPayTime(time);
|
||||
} else {
|
||||
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(LocalDateTime.now());
|
||||
callbackInfo.setPayTime(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,19 +1,15 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.dao.WeChatPayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -27,23 +23,8 @@ import java.util.Optional;
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayOrderService {
|
||||
|
||||
private final PayChannelOrderService payChannelOrderService;
|
||||
|
||||
private final WeChatPayOrderManager weChatPayOrderManager;
|
||||
|
||||
/**
|
||||
* 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建微信支付单
|
||||
*/
|
||||
public void updatePaySuccess(PayOrder payOrder, PayChannelParam payChannelParam) {
|
||||
payOrder.setAsyncPay(true)
|
||||
.setAsyncChannel(PayChannelEnum.WECHAT.getCode());
|
||||
payChannelOrderService.updateAsyncChannelOrder(payOrder,payChannelParam);
|
||||
|
||||
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.SUCCESS.getCode())) {
|
||||
this.createWeChatOrder(payOrder, payChannelParam.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步支付成功, 更新支付记录成功状态, 并创建微信支付记录
|
||||
*/
|
||||
|
@@ -104,8 +104,7 @@ public class WeChatPayService {
|
||||
}
|
||||
// 付款码支付
|
||||
else if (payWayEnum == PayWayEnum.BARCODE) {
|
||||
String tradeNo = this.barCode(totalFee, payOrder, weChatPayParam.getAuthCode(), weChatPayConfig);
|
||||
asyncPayInfo.setGatewayOrderNo(tradeNo);
|
||||
this.barCode(totalFee, payOrder, weChatPayParam.getAuthCode(), weChatPayConfig);
|
||||
}
|
||||
asyncPayInfo.setPayBody(payBody);
|
||||
}
|
||||
@@ -176,7 +175,9 @@ public class WeChatPayService {
|
||||
/**
|
||||
* 付款码支付
|
||||
*/
|
||||
private String barCode(String amount, PayOrder payment, String authCode, WeChatPayConfig weChatPayConfig) {
|
||||
private void barCode(String amount, PayOrder payment, String authCode, WeChatPayConfig weChatPayConfig) {
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
|
||||
Map<String, String> params = MicroPayModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
@@ -205,27 +206,27 @@ public class WeChatPayService {
|
||||
if (Objects.equals(resultCode, WeChatPayCode.TRADE_SUCCESS)) {
|
||||
payment.setStatus(PayStatusEnum.SUCCESS.getCode())
|
||||
.setPayTime(LocalDateTime.now());
|
||||
return result.get(WeChatPayCode.TRANSACTION_ID);
|
||||
asyncPayInfo.setGatewayOrderNo(result.get(WeChatPayCode.TRANSACTION_ID))
|
||||
.setPayComplete(true);
|
||||
return;
|
||||
}
|
||||
// 支付中, 发起轮训同步
|
||||
if (Objects.equals(resultCode, WeChatPayCode.TRADE_FAIL)
|
||||
&& Objects.equals(errCode, WeChatPayCode.TRADE_USERPAYING)) {
|
||||
SpringUtil.getBean(this.getClass()).rotationSync(payment);
|
||||
return result.get(WeChatPayCode.TRANSACTION_ID);
|
||||
asyncPayInfo.setGatewayOrderNo(result.get(WeChatPayCode.TRANSACTION_ID));
|
||||
return;
|
||||
}
|
||||
|
||||
// 支付撤销
|
||||
if (Objects.equals(resultCode, WeChatPayCode.TRADE_REVOKED)) {
|
||||
throw new PayFailureException("用户已撤销支付");
|
||||
}
|
||||
|
||||
// 支付失败
|
||||
if (Objects.equals(resultCode, WeChatPayCode.TRADE_PAYERROR)
|
||||
|| Objects.equals(resultCode, WeChatPayCode.TRADE_FAIL)) {
|
||||
String errorMsg = result.get(WeChatPayCode.ERR_CODE_DES);
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +266,7 @@ public class WeChatPayService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试同步支付状态, 最多10次, 30秒不操作微信会自动关闭
|
||||
* 多次重试同步支付状态, 最多10次, 30秒不操作微信会自动关闭
|
||||
*/
|
||||
@Async("bigExecutor")
|
||||
@Retryable(value = RetryableException.class, maxAttempts = 10, backoff = @Backoff(value = 5000L))
|
||||
|
@@ -108,7 +108,7 @@ public class WechatPayReconcileService{
|
||||
.map(this::convert)
|
||||
.collect(Collectors.toList());
|
||||
// 写入到上下文中
|
||||
PaymentContextLocal.get().getReconcile().setReconcileDetails(collect);
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -7,9 +7,8 @@ import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
@@ -45,13 +44,12 @@ public class WechatRefundService {
|
||||
String totalFee = String.valueOf(orderChannel.getAmount());
|
||||
// 设置退款信息
|
||||
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
refundInfo.setGatewayRequestNo(PayUtil.getRefundNo());
|
||||
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.notify_url(weChatPayConfig.getNotifyUrl())
|
||||
.out_trade_no(String.valueOf(payOrder.getId()))
|
||||
.out_refund_no(refundInfo.getGatewayRequestNo())
|
||||
.out_refund_no(String.valueOf(refundInfo.getRefundId()))
|
||||
.total_fee(totalFee)
|
||||
.refund_fee(refundFee)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
@@ -70,6 +68,9 @@ public class WechatRefundService {
|
||||
String xmlResult = WxPayApi.orderRefund(false, params, inputStream, weChatPayConfig.getWxMchId());
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
// 微信退款是否成功需要查询状态或者回调, 所以设置为退款中状态
|
||||
refundInfo.setStatus(PayRefundStatusEnum.PROGRESS)
|
||||
.setGatewayOrderNo(result.get("refund_id"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class PayNoticeService {
|
||||
try {
|
||||
// 获取通知地址和内容相关的信息
|
||||
ApiInfoLocal apiInfo = PaymentContextLocal.get().getApiInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
// 首先判断接口是开启了通知回调功能
|
||||
if (apiInfo.isNotice()){
|
||||
PayOrder payOrder = payOrderManager.findById(paymentId).orElseThrow(DataNotExistException::new);
|
||||
|
@@ -41,9 +41,6 @@ public class PayBuilder {
|
||||
LocalDateTime expiredTime = PaymentContextLocal.get()
|
||||
.getAsyncPayInfo()
|
||||
.getExpiredTime();
|
||||
// 可退款信息
|
||||
@Deprecated
|
||||
List<RefundableInfo> refundableInfos = buildRefundableInfo(payParam.getPayChannels());
|
||||
// 计算总价
|
||||
int sumAmount = payParam.getPayChannels().stream()
|
||||
.map(PayChannelParam::getAmount)
|
||||
@@ -59,7 +56,6 @@ public class PayBuilder {
|
||||
return new PayOrder()
|
||||
.setBusinessNo(payParam.getBusinessNo())
|
||||
.setTitle(payParam.getTitle())
|
||||
.setRefundableInfos(refundableInfos)
|
||||
.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
.setAmount(sumAmount)
|
||||
.setExpiredTime(expiredTime)
|
||||
@@ -75,7 +71,7 @@ public class PayBuilder {
|
||||
* @param paymentId 支付订单id
|
||||
*/
|
||||
public PayOrderExtra buildPayOrderExtra(PayParam payParam, Long paymentId) {
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
PayOrderExtra payOrderExtra = new PayOrderExtra()
|
||||
.setClientIp(payParam.getClientIp())
|
||||
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.core.order.pay.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
|
||||
@@ -15,6 +16,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 关联支付订单支付时通道信息
|
||||
* @author xxm
|
||||
@@ -30,26 +33,37 @@ public class PayChannelOrder extends MpCreateEntity implements EntityBaseFunctio
|
||||
@DbColumn(comment = "支付id")
|
||||
private Long paymentId;
|
||||
|
||||
@DbColumn(comment = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@DbColumn(comment = "通道")
|
||||
private String channel;
|
||||
|
||||
@DbColumn(comment = "支付方式")
|
||||
private String payWay;
|
||||
|
||||
@DbColumn(comment = "金额")
|
||||
private Integer amount;
|
||||
|
||||
@DbColumn(comment = "可退款余额")
|
||||
@DbColumn(comment = "可退款金额")
|
||||
private Integer refundableBalance;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
@DbColumn(comment = "支付状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 异步支付通道发给网关的退款号, 用与将记录关联起来
|
||||
*/
|
||||
@DbColumn(comment = "关联网关支付号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
@DbColumn(comment = "支付方式")
|
||||
private String payWay;
|
||||
@DbColumn(comment = "支付时间")
|
||||
private LocalDateTime payTime;
|
||||
|
||||
@DbColumn(comment = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
/**
|
||||
* @see AliPayParam
|
||||
|
@@ -1,8 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.pay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.util.ResultConvertUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.service.common.context.AsyncPayLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
@@ -24,13 +27,20 @@ import java.util.Optional;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayChannelOrderService {
|
||||
private final PayChannelOrderManager payChannelOrderManager;
|
||||
private final PayChannelOrderManager channelOrderManager;
|
||||
|
||||
/**
|
||||
* 根据支付ID查询列表
|
||||
*/
|
||||
public List<PayChannelOrderDto> findAllByPaymentId(Long paymentId){
|
||||
return ResultConvertUtil.dtoListConvert(payChannelOrderManager.findAllByPaymentId(paymentId));
|
||||
return ResultConvertUtil.dtoListConvert(channelOrderManager.findAllByPaymentId(paymentId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单条
|
||||
*/
|
||||
public PayChannelOrderDto findById(Long id){
|
||||
return channelOrderManager.findById(id).map(PayChannelOrder::toDto).orElseThrow(() -> new DataNotExistException("通道支付订单未查到"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,33 +48,37 @@ public class PayChannelOrderService {
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateAsyncChannelOrder(PayOrder payOrder, PayChannelParam payChannelParam){
|
||||
Optional<PayChannelOrder> payOrderChannelOpt = payChannelOrderManager.findByPaymentIdAndChannel(payOrder.getId(), PayChannelEnum.WECHAT.getCode());
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
// 是否支付完成
|
||||
PayStatusEnum payStatus = asyncPayInfo.isPayComplete() ? PayStatusEnum.SUCCESS : PayStatusEnum.PROGRESS;
|
||||
Optional<PayChannelOrder> payOrderChannelOpt =
|
||||
channelOrderManager.findByPaymentIdAndChannel(payOrder.getId(), payChannelParam.getChannel());
|
||||
if (!payOrderChannelOpt.isPresent()){
|
||||
payChannelOrderManager.deleteByPaymentIdAndAsync(payOrder.getId());
|
||||
payChannelOrderManager.save(new PayChannelOrder()
|
||||
PayChannelOrder payChannelOrder = new PayChannelOrder();
|
||||
// 替换原有的的支付通道信息
|
||||
payChannelOrder.setPayWay(payChannelParam.getWay())
|
||||
.setPaymentId(payOrder.getId())
|
||||
.setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setAsync(true)
|
||||
.setChannel(payChannelParam.getChannel())
|
||||
.setPayWay(payChannelParam.getWay())
|
||||
.setAmount(payChannelParam.getAmount())
|
||||
.setRefundableBalance(payChannelParam.getAmount())
|
||||
.setPayWay(payChannelParam.getWay())
|
||||
.setGatewayOrderNo(asyncPayInfo.getGatewayOrderNo())
|
||||
.setPayTime(asyncPayInfo.getPayTime())
|
||||
.setChannelExtra(payChannelParam.getChannelExtra())
|
||||
.setAsync(true)
|
||||
);
|
||||
.setStatus(payStatus.getCode());
|
||||
channelOrderManager.deleteByPaymentIdAndAsync(payChannelOrder.getId());
|
||||
channelOrderManager.save(payChannelOrder);
|
||||
} else {
|
||||
// 更新支付通道信息
|
||||
payOrderChannelOpt.get()
|
||||
.setPayWay(payChannelParam.getWay())
|
||||
.setGatewayOrderNo(asyncPayInfo.getGatewayOrderNo())
|
||||
.setPayTime(asyncPayInfo.getPayTime())
|
||||
.setChannelExtra(payChannelParam.getChannelExtra())
|
||||
.setPayWay(payChannelParam.getWay());
|
||||
payChannelOrderManager.updateById(payOrderChannelOpt.get());
|
||||
.setStatus(payStatus.getCode());
|
||||
channelOrderManager.updateById(payOrderChannelOpt.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付调起成功 更新payment中异步支付类型信息, 如果支付完成, 创建支付宝支付单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updatePaySuccess(PayOrder payOrder, PayChannelParam payChannelParam) {
|
||||
// 更新支付宝异步支付类型信息
|
||||
this.updateAsyncChannelOrder(payOrder, payChannelParam);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -63,7 +63,6 @@ public class PayOrderService {
|
||||
refundableInfos.remove(refundableInfo);
|
||||
refundableInfo.setAmount(refundableInfo.getAmount() - amount);
|
||||
refundableInfos.add(refundableInfo);
|
||||
payment.setRefundableInfos(refundableInfos);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.core.order.refund.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderChannelConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundChannelOrderDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
@@ -42,11 +43,19 @@ public class PayRefundChannelOrder extends MpBaseEntity implements EntityBaseFun
|
||||
private boolean async;
|
||||
|
||||
@DbColumn(comment = "订单金额")
|
||||
private Integer totalAmount;
|
||||
private Integer orderAmount;
|
||||
|
||||
@DbColumn(comment = "退款金额")
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see PayRefundStatusEnum
|
||||
*/
|
||||
@DbColumn(comment = "退款状态")
|
||||
private String status;
|
||||
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
|
@@ -3,22 +3,16 @@ package cn.bootx.platform.daxpay.service.core.order.refund.entity;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.service.common.typehandler.RefundableInfoTypeHandler;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.PayRefundOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
|
||||
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 退款记录
|
||||
@@ -51,6 +45,10 @@ public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<P
|
||||
@DbColumn(comment = "标题")
|
||||
private String title;
|
||||
|
||||
/** 订单金额 */
|
||||
@DbColumn(comment = "订单金额")
|
||||
private Integer orderAmount;
|
||||
|
||||
/** 退款金额 */
|
||||
@DbColumn(comment = "退款金额")
|
||||
private Integer amount;
|
||||
@@ -75,14 +73,6 @@ public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<P
|
||||
@DbColumn(comment = "退款时间")
|
||||
private LocalDateTime refundTime;
|
||||
|
||||
/**
|
||||
* 退款信息列表
|
||||
*/
|
||||
@DbColumn(comment = "退款信息列表")
|
||||
@TableField(typeHandler = RefundableInfoTypeHandler.class)
|
||||
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
|
||||
private List<RefundableInfo> refundableInfo;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see PayRefundStatusEnum
|
||||
|
@@ -1,18 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayCloseParam;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.close.factory.PayCloseStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.record.close.service.PayCloseRecordService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
@@ -23,7 +25,9 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -35,6 +39,7 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayCloseService {
|
||||
private final PayChannelOrderManager payChannelOrderManager;
|
||||
private final PayOrderService payOrderService;
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
private final PayCloseRecordService payCloseRecordService;
|
||||
@@ -70,30 +75,39 @@ public class PayCloseService {
|
||||
* 关闭支付记录
|
||||
*/
|
||||
private void close(PayOrder payOrder) {
|
||||
// 状态检查, 只有支付中可以进行取消支付
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())){
|
||||
throw new PayFailureException("订单不是支付中, 无法进行关闭订单");
|
||||
}
|
||||
|
||||
// 1.获取支付方式(退款列表中提取),通过工厂生成对应的策略组
|
||||
List<String> channels = payOrder.getRefundableInfos()
|
||||
.stream()
|
||||
.map(RefundableInfo::getChannel)
|
||||
.collect(Collectors.toList());
|
||||
List<AbsPayCloseStrategy> payCloseStrategies = PayCloseStrategyFactory.createAsyncLast(channels);
|
||||
if (CollectionUtil.isEmpty(payCloseStrategies)) {
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
|
||||
// 2.初始化关闭支付的参数
|
||||
payCloseStrategies.forEach(strategy -> strategy.initCloseParam(payOrder));
|
||||
|
||||
try {
|
||||
// 状态检查, 只有支付中可以进行取消支付
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())){
|
||||
throw new PayFailureException("订单不是支付中, 无法进行关闭订单");
|
||||
}
|
||||
|
||||
// 0.基础数据准备
|
||||
Map<String, PayChannelOrder> orderChannelMap = payChannelOrderManager.findAllByPaymentId(payOrder.getId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 1.获取支付方式, 通过工厂生成对应的策略组
|
||||
List<String> channels = orderChannelMap.values().stream()
|
||||
.map(PayChannelOrder::getChannel)
|
||||
.collect(Collectors.toList());
|
||||
List<AbsPayCloseStrategy> payCloseStrategies = PayCloseStrategyFactory.createAsyncLast(channels);
|
||||
if (CollectionUtil.isEmpty(payCloseStrategies)) {
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
|
||||
// 2.初始化关闭支付的参数
|
||||
for (AbsPayCloseStrategy strategy : payCloseStrategies) {
|
||||
strategy.initCloseParam(payOrder, orderChannelMap.get(strategy.getType().getCode()));
|
||||
}
|
||||
|
||||
// 3.关闭前准备
|
||||
payCloseStrategies.forEach(AbsPayCloseStrategy::doBeforeCloseHandler);
|
||||
|
||||
// 4.执行关闭策略
|
||||
payCloseStrategies.forEach(AbsPayCloseStrategy::doCloseHandler);
|
||||
|
||||
// 5.关闭成功后处理
|
||||
payCloseStrategies.forEach(AbsPayCloseStrategy::doSuccessHandler);
|
||||
}
|
||||
catch (PayFailureException e) {
|
||||
// 记录关闭失败的记录
|
||||
@@ -120,10 +134,10 @@ public class PayCloseService {
|
||||
*/
|
||||
private void saveRecord(PayOrder payOrder, boolean closed, String errMsg){
|
||||
String clientIp = PaymentContextLocal.get()
|
||||
.getRequest()
|
||||
.getRequestInfo()
|
||||
.getClientIp();
|
||||
String reqId = PaymentContextLocal.get()
|
||||
.getRequest()
|
||||
.getRequestInfo()
|
||||
.getReqId();
|
||||
PayCloseRecord record = new PayCloseRecord()
|
||||
.setPaymentId(payOrder.getId())
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayCloseService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayOrderService;
|
||||
@@ -29,6 +30,11 @@ public class AliPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
private final AliPayCloseService aliPayCloseService;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭前的处理方式
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.cash.service.CashService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -20,6 +21,12 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
|
||||
@RequiredArgsConstructor
|
||||
public class CashPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
private final CashService cashService;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.CASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -20,6 +21,11 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
|
||||
public class UnionPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.UNION_PAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.voucher.service.VoucherPayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.voucher.service.VoucherPayService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
|
||||
@@ -24,6 +25,11 @@ public class VoucherPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
private final VoucherPayService voucherPayService;
|
||||
private final VoucherPayOrderService voucherPayOrderService;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.VOUCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
|
||||
@@ -23,6 +24,11 @@ public class WalletPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
private final WalletPayService walletPayService;
|
||||
private final WalletPayOrderService walletPayOrderService;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.WALLET;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.close.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayCloseService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
@@ -28,6 +29,12 @@ public class WeChatPayCloseStrategy extends AbsPayCloseStrategy {
|
||||
private final WeChatPayCloseService weChatPayCloseService;
|
||||
|
||||
private WeChatPayConfig weChatPayConfig;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getType() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭前的处理方式
|
||||
*/
|
||||
|
@@ -37,7 +37,7 @@ public class PaymentAssistService {
|
||||
*/
|
||||
private void initPlatform(){
|
||||
PlatformConfig config = platformConfigService.getConfig();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
platform.setSignType(config.getSignType());
|
||||
platform.setSignSecret(config.getSignSecret());
|
||||
platform.setNotifyUrl(config.getNotifyUrl());
|
||||
@@ -50,7 +50,7 @@ public class PaymentAssistService {
|
||||
* 初始化请求相关信息上下文
|
||||
*/
|
||||
private void initRequest(PayCommonParam payCommonParam){
|
||||
RequestLocal request = PaymentContextLocal.get().getRequest();
|
||||
RequestLocal request = PaymentContextLocal.get().getRequestInfo();
|
||||
request.setClientIp(payCommonParam.getClientIp())
|
||||
.setAttach(payCommonParam.getAttach())
|
||||
.setSign(payCommonParam.getSign())
|
||||
|
@@ -39,7 +39,7 @@ public class PaymentSignService {
|
||||
return;
|
||||
}
|
||||
// 参数转换为Map对象
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
String signType = platform.getSignType();
|
||||
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
|
||||
boolean verified = PaySignUtil.verifyHmacSha256Sign(param, platform.getSignSecret(), param.getSign());
|
||||
|
@@ -3,7 +3,6 @@ package cn.bootx.platform.daxpay.service.core.payment.pay.service;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
@@ -31,6 +30,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.bootx.platform.daxpay.code.PayStatusEnum.*;
|
||||
|
||||
/**
|
||||
* 支付支持服务
|
||||
* @author xxm
|
||||
@@ -73,7 +74,7 @@ public class PayAssistService {
|
||||
return;
|
||||
}
|
||||
AsyncPayLocal asyncPayInfo = PaymentContextLocal.get().getAsyncPayInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
// 支付订单是非为空
|
||||
if (Objects.nonNull(order)){
|
||||
asyncPayInfo.setExpiredTime(order.getExpiredTime());
|
||||
@@ -93,7 +94,7 @@ public class PayAssistService {
|
||||
*/
|
||||
private void initNotice(PayParam payParam){
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
// 异步回调
|
||||
if (!payParam.isNotNotify()){
|
||||
noticeInfo.setNotifyUrl(payParam.getReturnUrl());
|
||||
@@ -171,7 +172,7 @@ public class PayAssistService {
|
||||
PayOrder payOrder = payOrderQueryService.findByBusinessNo(businessNo).orElse(null);
|
||||
if (Objects.nonNull(payOrder)) {
|
||||
// 待支付
|
||||
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())){
|
||||
if (Objects.equals(payOrder.getStatus(), PROGRESS.getCode())){
|
||||
// 如果支付超时, 触发订单同步操作, 同时抛出异常
|
||||
if (Objects.nonNull(payOrder.getExpiredTime()) && LocalDateTimeUtil.ge(LocalDateTime.now(), payOrder.getExpiredTime())) {
|
||||
paySyncService.syncPayOrder(payOrder);
|
||||
@@ -180,16 +181,16 @@ public class PayAssistService {
|
||||
return payOrder;
|
||||
}
|
||||
// 已经支付状态
|
||||
if (PayStatusEnum.SUCCESS.getCode().equals(payOrder.getStatus())) {
|
||||
if (SUCCESS.getCode().equals(payOrder.getStatus())) {
|
||||
throw new PayFailureException("已经支付成功,请勿重新支付");
|
||||
}
|
||||
// 支付失败类型状态
|
||||
List<String> tradesStatus = Arrays.asList(PayStatusEnum.FAIL.getCode(), PayStatusEnum.CLOSE.getCode());
|
||||
List<String> tradesStatus = Arrays.asList(FAIL.getCode(), CLOSE.getCode());
|
||||
if (tradesStatus.contains(payOrder.getStatus())) {
|
||||
throw new PayFailureException("支付失败或已经被关闭");
|
||||
}
|
||||
// 退款类型状态
|
||||
tradesStatus = Arrays.asList(PayStatusEnum.REFUNDED.getCode(), PayStatusEnum.PARTIAL_REFUND.getCode());
|
||||
tradesStatus = Arrays.asList(REFUNDED.getCode(), PARTIAL_REFUND.getCode(), REFUNDING.getCode());
|
||||
if (tradesStatus.contains(payOrder.getStatus())) {
|
||||
throw new PayFailureException("退款中");
|
||||
}
|
||||
|
@@ -1,20 +1,18 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.pay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.SimplePayParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.builder.PayBuilder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.pay.factory.PayStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.builder.PayBuilder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.pay.factory.PayStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
|
||||
import cn.bootx.platform.daxpay.service.func.PayStrategyConsumer;
|
||||
import cn.bootx.platform.daxpay.util.PayUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
@@ -27,10 +25,14 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.bootx.platform.daxpay.code.PayStatusEnum.*;
|
||||
|
||||
|
||||
/**
|
||||
* 支付流程
|
||||
@@ -146,23 +148,26 @@ public class PayService {
|
||||
paymentStrategy.initPayParam(payOrder, payParam);
|
||||
}
|
||||
|
||||
// 3.执行支付前处理动作
|
||||
// 3.1 执行支付前处理动作
|
||||
payStrategyList.forEach(AbsPayStrategy::doBeforePayHandler);
|
||||
// 3.2 执行通道支付但的生成动作
|
||||
payStrategyList.forEach(AbsPayStrategy::generateChannelOrder);
|
||||
|
||||
// 4.1 支付操作
|
||||
payStrategyList.forEach(AbsPayStrategy::doPayHandler);
|
||||
// 4.2 支付调用成功操作, 进行扣款、创建记录类类似的操作
|
||||
payStrategyList.forEach(AbsPayStrategy::doSuccessHandler);
|
||||
// 4.3 获取通道支付订单进行保存
|
||||
// 4.3 获取通道支付订单进行保存, 异步支付通道的订单单独处理
|
||||
List<PayChannelOrder> channelOrders = payStrategyList.stream()
|
||||
.map(AbsPayStrategy::generateChannelOrder)
|
||||
.map(AbsPayStrategy::getChannelOrder)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
payChannelOrderManager.saveAll(channelOrders);
|
||||
|
||||
// 5. 如果没有异步支付, 直接进行成功处理
|
||||
if (PayUtil.isNotSync(payParam.getPayChannels())) {
|
||||
// 修改支付订单状态为成功
|
||||
payOrder.setStatus(PayStatusEnum.SUCCESS.getCode());
|
||||
payOrder.setStatus(SUCCESS.getCode());
|
||||
payOrder.setPayTime(LocalDateTime.now());
|
||||
payOrderService.updateById(payOrder);
|
||||
}
|
||||
@@ -173,9 +178,9 @@ public class PayService {
|
||||
*/
|
||||
private PayResult paySyncNotFirst(PayParam payParam, PayOrder payOrder) {
|
||||
|
||||
// 1. 处理支付完成情况(完成/退款)
|
||||
List<String> trades = Arrays.asList(PayStatusEnum.SUCCESS.getCode(), PayStatusEnum.CLOSE.getCode(),
|
||||
PayStatusEnum.PARTIAL_REFUND.getCode(), PayStatusEnum.REFUNDED.getCode());
|
||||
// 1. 处理支付结束情况(完成/退款/关闭/错误)
|
||||
List<String> trades = Arrays.asList(SUCCESS.getCode(), CLOSE.getCode(), PARTIAL_REFUND.getCode(),
|
||||
REFUNDED.getCode(), REFUNDING.getCode(), FAIL.getCode());
|
||||
if (trades.contains(payOrder.getStatus())) {
|
||||
return PayBuilder.buildPayResultByPayOrder(payOrder);
|
||||
}
|
||||
@@ -203,22 +208,4 @@ public class PayService {
|
||||
// 7. 组装返回参数
|
||||
return PayBuilder.buildPayResultByPayOrder(payOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行策略中不同的handler
|
||||
* @param payment 主支付对象
|
||||
* @param strategyList 策略列表
|
||||
* @param payMethod 执行支付的函数或者支付前的函数
|
||||
* @param successMethod 执行成功的函数
|
||||
*/
|
||||
private void doHandler(PayOrder payment, List<AbsPayStrategy> strategyList, Consumer<AbsPayStrategy> payMethod,
|
||||
PayStrategyConsumer<List<AbsPayStrategy>, PayOrder> successMethod) {
|
||||
// 执行策略操作,如支付前/支付时
|
||||
// 等同strategyList.forEach(payMethod.accept(PaymentStrategy))
|
||||
strategyList.forEach(payMethod);
|
||||
|
||||
// 执行操作成功的处理
|
||||
Optional.ofNullable(successMethod).ifPresent(fun -> fun.accept(strategyList, payment));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,11 +5,9 @@ import cn.bootx.platform.daxpay.exception.pay.PayAmountAbnormalException;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -84,7 +82,7 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付调起成功
|
||||
* 支付调起成功, 保存或更新通道支付订单
|
||||
*/
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
@@ -92,19 +90,12 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道支付单
|
||||
* 不使用默认的生成通道支付单方法, 异步支付通道的支付订单自己管理
|
||||
*/
|
||||
@Override
|
||||
public PayChannelOrder generateChannelOrder() {
|
||||
String gatewayOrderNo = PaymentContextLocal.get()
|
||||
.getAsyncPayInfo()
|
||||
.getGatewayOrderNo();
|
||||
PayChannelOrder payChannelOrder = super.generateChannelOrder();
|
||||
payChannelOrder.setGatewayOrderNo(gatewayOrderNo);
|
||||
return payChannelOrder;
|
||||
public void generateChannelOrder() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化支付宝配置信息
|
||||
*/
|
||||
|
@@ -31,9 +31,5 @@ public class UnionPayStrategy extends AbsPayStrategy {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCloseHandler() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.pay.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.Voucher;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.VoucherRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.voucher.service.VoucherPayService;
|
||||
@@ -47,17 +48,15 @@ public class VoucherPayStrategy extends AbsPayStrategy {
|
||||
|
||||
/**
|
||||
* 支付操作
|
||||
* 1. 异步支付: 发起支付时冻结, 支付完成后扣减, 支付失败和关闭支付后解冻
|
||||
* 2. 同步支付: 直接扣减
|
||||
*/
|
||||
@Override
|
||||
public void doPayHandler() {
|
||||
VoucherRecord voucherRecord;
|
||||
if (this.getOrder().isAsyncPay()){
|
||||
voucherRecord = voucherPayService.freezeBalance(this.getPayChannelParam().getAmount(), this.getOrder(), this.voucher);
|
||||
} else {
|
||||
voucherRecord = voucherPayService.pay(this.getPayChannelParam().getAmount(), this.getOrder(), this.voucher);
|
||||
}
|
||||
// if (this.getOrder().isAsyncPay()){
|
||||
// voucherRecord = voucherPayService.freezeBalance(this.getPayChannelParam().getAmount(), this.getOrder(), this.voucher);
|
||||
// } else {
|
||||
voucherRecord = voucherPayService.pay(this.getPayChannelParam().getAmount(), this.getOrder(), this.voucher);
|
||||
// }
|
||||
voucherPayOrderService.savePayment(this.getOrder(), getPayParam(), getPayChannelParam(), voucherRecord);
|
||||
}
|
||||
|
||||
@@ -69,16 +68,8 @@ public class VoucherPayStrategy extends AbsPayStrategy {
|
||||
if (this.getOrder().isAsyncPay()){
|
||||
voucherPayService.paySuccess(this.getOrder().getId());
|
||||
}
|
||||
this.getChannelOrder().setStatus(PayStatusEnum.SUCCESS.getCode());
|
||||
voucherPayOrderService.updateSuccess(this.getOrder().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭支付
|
||||
*/
|
||||
@Override
|
||||
public void doCloseHandler() {
|
||||
voucherPayService.close(this.getOrder().getId());
|
||||
voucherPayOrderService.updateClose(this.getOrder().getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -101,13 +101,4 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
walletPayOrderService.updateSuccess(this.getOrder().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消支付并返还金额
|
||||
*/
|
||||
@Override
|
||||
public void doCloseHandler() {
|
||||
walletPayService.close(this.getOrder().getId());
|
||||
walletPayOrderService.updateClose(this.getOrder().getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,11 +4,9 @@ import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayAmountAbnormalException;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.wechat.WeChatPayParam;
|
||||
@@ -89,26 +87,18 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付调起成功
|
||||
* 支付调起成功 , 保存或更新通道支付订单
|
||||
*/
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
channelOrderService.updateAsyncChannelOrder(this.getOrder(), this.getPayChannelParam());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道支付单
|
||||
* 不使用默认的生成通道支付单方法, 异步支付通道的支付订单自己管理
|
||||
*/
|
||||
@Override
|
||||
public PayChannelOrder generateChannelOrder() {
|
||||
String gatewayOrderNo = PaymentContextLocal.get()
|
||||
.getAsyncPayInfo()
|
||||
.getGatewayOrderNo();
|
||||
PayChannelOrder payChannelOrder = super.generateChannelOrder();
|
||||
payChannelOrder.setGatewayOrderNo(gatewayOrderNo);
|
||||
return payChannelOrder;
|
||||
}
|
||||
public void generateChannelOrder() {}
|
||||
|
||||
/**
|
||||
* 初始化微信支付
|
||||
|
@@ -58,7 +58,7 @@ public class PayReconcileService {
|
||||
}
|
||||
// 保存转换后的通用结构对账单
|
||||
List<PayReconcileDetail> reconcileDetails = PaymentContextLocal.get()
|
||||
.getReconcile()
|
||||
.getReconcileInfo()
|
||||
.getReconcileDetails();
|
||||
reconcileDetailManager.saveAll(reconcileDetails);
|
||||
}
|
||||
|
@@ -2,22 +2,20 @@ package cn.bootx.platform.daxpay.service.core.payment.refund.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.ValidationFailedException;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundParam;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.PayRefundChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.PayRefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundChannelOrder;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundOrder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -42,6 +40,7 @@ public class PayRefundAssistService {
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
|
||||
private final PayRefundOrderManager payRefundOrderManager;
|
||||
|
||||
private final PayRefundChannelOrderManager payRefundChannelOrderManager;
|
||||
|
||||
/**
|
||||
@@ -57,7 +56,7 @@ public class PayRefundAssistService {
|
||||
*/
|
||||
private void initNotice(RefundParam param) {
|
||||
NoticeLocal noticeInfo = PaymentContextLocal.get().getNoticeInfo();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatform();
|
||||
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
|
||||
// 异步回调
|
||||
if (!param.isNotNotify()){
|
||||
noticeInfo.setNotifyUrl(param.getReturnUrl());
|
||||
@@ -67,25 +66,11 @@ public class PayRefundAssistService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据退款参数获取支付订单, 并进行检查
|
||||
*/
|
||||
public PayOrder getPayOrderAndCheckByRefundParam(RefundParam param, boolean simple){
|
||||
// 全额退款和部分退款校验
|
||||
if (!param.isRefundAll()) {
|
||||
if (CollUtil.isEmpty(param.getRefundChannels())) {
|
||||
throw new ValidationFailedException("退款通道参数不能为空");
|
||||
}
|
||||
if (Objects.isNull(param.getRefundNo())) {
|
||||
throw new ValidationFailedException("部分退款时退款单号必传");
|
||||
}
|
||||
}
|
||||
// 退款号唯一校验
|
||||
if (StrUtil.isNotBlank(param.getRefundNo())
|
||||
&& payRefundOrderManager.existsByRefundNo(param.getRefundNo())){
|
||||
throw new PayFailureException("退款单号已存在");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据退款参数获取支付订单
|
||||
*/
|
||||
public PayOrder getPayOrder(RefundParam param){
|
||||
PayOrder payOrder = null;
|
||||
if (Objects.nonNull(param.getPaymentId())){
|
||||
payOrder = payOrderQueryService.findById(param.getPaymentId())
|
||||
@@ -95,20 +80,27 @@ public class PayRefundAssistService {
|
||||
payOrder = payOrderQueryService.findByBusinessNo(param.getBusinessNo())
|
||||
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
|
||||
}
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
// 简单退款处理
|
||||
if (simple){
|
||||
// 简单退款校验
|
||||
if (payOrder.isCombinationPay()){
|
||||
throw new PayFailureException("组合支付不可以使用简单退款方式");
|
||||
/**
|
||||
* 根据退款参数获取支付订单, 并进行检查
|
||||
*/
|
||||
public void checkByRefundParam(RefundParam param, PayOrder payOrder){
|
||||
// 全额退款和部分退款校验
|
||||
if (!param.isRefundAll()) {
|
||||
if (CollUtil.isEmpty(param.getRefundChannels())) {
|
||||
throw new ValidationFailedException("退款通道参数不能为空");
|
||||
}
|
||||
if (Objects.isNull(param.getRefundNo())) {
|
||||
throw new ValidationFailedException("部分退款时退款单号必传");
|
||||
}
|
||||
// 设置退款参数的通道配置
|
||||
String channel = payOrder.getRefundableInfos()
|
||||
.get(0)
|
||||
.getChannel();
|
||||
param.getRefundChannels().get(0).setChannel(channel);
|
||||
}
|
||||
|
||||
// 简单退款校验
|
||||
if (payOrder.isCombinationPay()){
|
||||
throw new PayFailureException("组合支付不可以使用简单退款方式");
|
||||
}
|
||||
|
||||
// 状态判断, 支付中/失败/取消等不能进行退款
|
||||
List<String> tradesStatus = Arrays.asList(
|
||||
@@ -119,39 +111,46 @@ public class PayRefundAssistService {
|
||||
PayStatusEnum statusEnum = PayStatusEnum.findByCode(payOrder.getStatus());
|
||||
throw new PayFailureException("当前状态["+statusEnum.getName()+"]不允许状态非法, 无法退款");
|
||||
}
|
||||
return payOrder;
|
||||
|
||||
// 退款号唯一校验
|
||||
if (StrUtil.isNotBlank(param.getRefundNo())
|
||||
&& payRefundOrderManager.existsByRefundNo(param.getRefundNo())){
|
||||
throw new PayFailureException("退款单号已存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存退款记录 成不成功都记录
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public PayRefundOrder generateRefundOrder(RefundParam refundParam, PayOrder payOrder){
|
||||
RefundLocal asyncRefundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
// 总退款金额
|
||||
// 此次的总退款金额
|
||||
Integer amount = refundParam.getRefundChannels()
|
||||
.stream()
|
||||
.map(RefundChannelParam::getAmount)
|
||||
.reduce(0, Integer::sum);
|
||||
|
||||
// 生成退款订单
|
||||
PayRefundOrder refundOrder = new PayRefundOrder()
|
||||
.setPaymentId(payOrder.getId())
|
||||
.setBusinessNo(payOrder.getBusinessNo())
|
||||
.setRefundNo(refundParam.getRefundNo())
|
||||
.setOrderAmount(payOrder.getAmount())
|
||||
.setAmount(amount)
|
||||
.setRefundableBalance(payOrder.getRefundableBalance())
|
||||
.setRefundTime(LocalDateTime.now())
|
||||
.setTitle(payOrder.getTitle())
|
||||
.setErrorCode(asyncRefundInfo.getErrorCode())
|
||||
.setErrorMsg(asyncRefundInfo.getErrorMsg())
|
||||
.setStatus(Objects.isNull(asyncRefundInfo.getErrorCode()) ? PayRefundStatusEnum.SUCCESS.getCode() : PayRefundStatusEnum.FAIL.getCode())
|
||||
.setStatus(asyncRefundInfo.getStatus().getCode())
|
||||
.setClientIp(refundParam.getClientIp())
|
||||
.setReqId(PaymentContextLocal.get().getRequest().getReqId());
|
||||
.setReqId(PaymentContextLocal.get().getRequestInfo().getReqId());
|
||||
// 主键使用预先生成的ID, 如果有异步通道, 关联的退款号就是这个ID
|
||||
long refundId = asyncRefundInfo.getRefundId();
|
||||
refundOrder.setId(refundId);
|
||||
|
||||
// 退款号, 如不传输, 使用ID作为退款号
|
||||
if(StrUtil.isBlank(refundOrder.getRefundNo())){
|
||||
long id = IdUtil.getSnowflakeNextId();
|
||||
refundOrder.setRefundNo(String.valueOf(id))
|
||||
.setId(id);
|
||||
refundOrder.setRefundNo(String.valueOf(refundId));
|
||||
}
|
||||
return refundOrder;
|
||||
}
|
||||
@@ -159,7 +158,7 @@ public class PayRefundAssistService {
|
||||
/**
|
||||
* 保存退款记录和对应的通道记录
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveOrderAndChannels(PayRefundOrder refundOrder,List<PayRefundChannelOrder> refundChannelOrders){
|
||||
payRefundOrderManager.save(refundOrder);
|
||||
for (PayRefundChannelOrder refundOrderChannel : refundChannelOrders) {
|
||||
|
@@ -3,6 +3,7 @@ package cn.bootx.platform.daxpay.service.core.payment.refund.service;
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
@@ -10,6 +11,8 @@ import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.SimpleRefundParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.RefundResult;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RefundLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
@@ -57,7 +60,7 @@ public class PayRefundService {
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class )
|
||||
public RefundResult refund(RefundParam param){
|
||||
return this.refund(param,false);
|
||||
return this.refundAdapter(param,false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,46 +72,53 @@ public class PayRefundService {
|
||||
// 构建退款参数
|
||||
RefundParam refundParam = new RefundParam();
|
||||
BeanUtil.copyProperties(param,refundParam);
|
||||
RefundChannelParam channelParam = new RefundChannelParam()
|
||||
.setAmount(param.getAmount())
|
||||
.setChannelExtra(param.getChannelExtra());
|
||||
RefundChannelParam channelParam = new RefundChannelParam().setAmount(param.getAmount());
|
||||
refundParam.setRefundChannels(Collections.singletonList(channelParam));
|
||||
return this.refund(refundParam,true);
|
||||
return this.refundAdapter(refundParam,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付退款方法
|
||||
* 支付退款适配方法, 处理简单退款与普通退款, 全部退款和部分退款的参数转换
|
||||
* @param param 退款参数
|
||||
* @param simple 是否简单退款
|
||||
*/
|
||||
private RefundResult refund(RefundParam param, boolean simple){
|
||||
// 检查获取支付订单, 同时设置退款参数中对应的支付通道参数
|
||||
PayOrder payOrder = payRefundAssistService.getPayOrderAndCheckByRefundParam(param, simple);
|
||||
private RefundResult refundAdapter(RefundParam param, boolean simple){
|
||||
// 获取支付订单
|
||||
PayOrder payOrder = payRefundAssistService.getPayOrder(param);
|
||||
// 第一次检查退款参数, 校验一些特殊情况
|
||||
payRefundAssistService.checkByRefundParam(param, payOrder);
|
||||
|
||||
// 组装退款参数, 处理全部退款和简单退款情况
|
||||
List<PayChannelOrder> payChannelOrders = payChannelOrderManager.findAllByPaymentId(payOrder.getId());
|
||||
// 是否全部退款
|
||||
if (param.isRefundAll()){
|
||||
// 全部退款根据支付订单的退款信息构造退款参数
|
||||
List<RefundChannelParam> channelParams = payChannelOrders
|
||||
.stream()
|
||||
.map(o -> new RefundChannelParam()
|
||||
.setChannel(o.getChannel())
|
||||
.setAmount(o.getAmount()))
|
||||
.collect(Collectors.toList());
|
||||
param.setRefundChannels(channelParams);
|
||||
} else if (simple) {
|
||||
// 如果不是全部退款且是简单退款的情况下, 设置要退款金额
|
||||
String channel = payChannelOrders.get(0).getChannel();
|
||||
param.getRefundChannels().get(0).setChannel(channel);
|
||||
}
|
||||
|
||||
// 参数校验
|
||||
ValidationUtil.validateParam(param);
|
||||
|
||||
// ----------------------------- 发起退款操作 --------------------------------------------
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("payment:refund:" + payOrder.getId());
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("退款处理中,请勿重复操作");
|
||||
}
|
||||
|
||||
try {
|
||||
// 退款上下文初始化
|
||||
payRefundAssistService.initRefundContext(param);
|
||||
// 是否全部退款
|
||||
if (param.isRefundAll()){
|
||||
// 全部退款根据支付订单的退款信息构造退款参数
|
||||
List<RefundChannelParam> channelParams = payOrder.getRefundableInfos()
|
||||
.stream()
|
||||
.map(o -> new RefundChannelParam()
|
||||
.setChannel(o.getChannel())
|
||||
.setAmount(o.getAmount()))
|
||||
.collect(Collectors.toList());
|
||||
param.setRefundChannels(channelParams);
|
||||
}
|
||||
// 分支付通道进行退款
|
||||
return this.refundByChannel(param,payOrder);
|
||||
return this.refundByChannel(param,payOrder,payChannelOrders);
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
@@ -117,75 +127,101 @@ public class PayRefundService {
|
||||
/**
|
||||
* 分支付通道进行退款
|
||||
*/
|
||||
public RefundResult refundByChannel(RefundParam refundParam, PayOrder payOrder){
|
||||
try {
|
||||
// 0.基础数据准备
|
||||
List<RefundChannelParam> refundChannels = refundParam.getRefundChannels();
|
||||
Map<String, PayChannelOrder> orderChannelMap = payChannelOrderManager.findAllByPaymentId(payOrder.getId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 比对通道支付单是否与可退款记录数量一致
|
||||
if (orderChannelMap.size() != refundChannels.size()){
|
||||
throw new PayFailureException("通道支付单是否与可退款记录数量不一致");
|
||||
}
|
||||
public RefundResult refundByChannel(RefundParam refundParam, PayOrder payOrder, List<PayChannelOrder> payChannelOrders){
|
||||
// 0.基础数据准备, 并比对通道支付单是否与可退款记录数量一致
|
||||
Map<String, PayChannelOrder> orderChannelMap = payChannelOrders.stream()
|
||||
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
List<RefundChannelParam> refundChannels = refundParam.getRefundChannels();
|
||||
|
||||
try {
|
||||
// 1.获取退款参数方式,通过工厂生成对应的策略组
|
||||
List<AbsPayRefundStrategy> payRefundStrategies = PayRefundStrategyFactory.createAsyncLast(refundChannels);
|
||||
if (CollectionUtil.isEmpty(payRefundStrategies)) {
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
|
||||
// 2.初始化退款策略的参数
|
||||
for (AbsPayRefundStrategy refundStrategy : payRefundStrategies) {
|
||||
refundStrategy.initRefundParam(payOrder, refundParam, orderChannelMap.get(refundStrategy.getType().getCode()));
|
||||
PayChannelOrder payChannelOrder = orderChannelMap.get(refundStrategy.getType().getCode());
|
||||
if (Objects.isNull(payChannelOrder)){
|
||||
throw new PayFailureException("[数据异常]进行退款的通道没有对应的支付单, 无法退款");
|
||||
}
|
||||
refundStrategy.initRefundParam(payOrder, refundParam, payChannelOrder);
|
||||
}
|
||||
// 3.退款前准备操作
|
||||
|
||||
// 3.1 退款前准备操作
|
||||
payRefundStrategies.forEach(AbsPayRefundStrategy::doBeforeRefundHandler);
|
||||
// 4.执行退款策略
|
||||
// 3.2 生成各通道退款订单
|
||||
payRefundStrategies.forEach(AbsPayRefundStrategy::generateChannelOrder);
|
||||
// 3.3 执行退款策略
|
||||
payRefundStrategies.forEach(AbsPayRefundStrategy::doRefundHandler);
|
||||
// 5 生成退款相关订单并保存
|
||||
List<PayRefundChannelOrder> refundChannelOrders = payRefundStrategies.stream()
|
||||
.map(AbsPayRefundStrategy::generateChannelOrder)
|
||||
// 3.4 执行退款发起成功后操作
|
||||
payRefundStrategies.forEach(AbsPayRefundStrategy::doSuccessHandler);
|
||||
|
||||
// 4 更新各支付通道订单的信息
|
||||
List<PayChannelOrder> channelOrders = payRefundStrategies.stream()
|
||||
.map(AbsPayRefundStrategy::getPayChannelOrder)
|
||||
.collect(Collectors.toList());
|
||||
PayRefundOrder refundOrder = payRefundAssistService.generateRefundOrder(refundParam, payOrder);
|
||||
payRefundAssistService.saveOrderAndChannels(refundOrder,refundChannelOrders);
|
||||
// 6.退款成功后支付单处理
|
||||
this.successHandler(refundParam, payOrder);
|
||||
// 7. 返回结果
|
||||
payChannelOrderManager.updateAllById(channelOrders);
|
||||
|
||||
// 5 获取退款通道订单, 进行保存
|
||||
List<PayRefundChannelOrder> refundChannelOrders = payRefundStrategies.stream()
|
||||
.map(AbsPayRefundStrategy::getRefundChannelOrder)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 6.进行成功处理, 分别处理退款订单, 通道退款订单, 支付订单
|
||||
PayRefundOrder refundOrder = this.successHandler(refundParam, refundChannelOrders, payOrder);
|
||||
return new RefundResult()
|
||||
.setRefundId(refundOrder.getId())
|
||||
.setRefundNo(refundParam.getRefundNo());
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 失败处理
|
||||
this.errorHandler(refundParam, payOrder, e);
|
||||
PaymentContextLocal.get().getRefundInfo().setStatus(PayRefundStatusEnum.FAIL);
|
||||
this.errorHandler(refundParam, payOrder);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款订单成功处理, 保存退房订单, 通道退款订单, 更新支付订单
|
||||
* 退款订单成功处理, 保存退款订单, 通道退款订单, 更新支付订单
|
||||
*/
|
||||
private void successHandler(RefundParam refundParam, PayOrder payOrder) {
|
||||
// 退款金额
|
||||
private PayRefundOrder successHandler(RefundParam refundParam, List<PayRefundChannelOrder> refundChannelOrders, PayOrder payOrder) {
|
||||
RefundLocal asyncRefundInfo = PaymentContextLocal.get().getRefundInfo();
|
||||
// ----------------------- 支付订单处理 ---------------------------------------
|
||||
// 此次的总退款金额
|
||||
Integer amount = refundParam.getRefundChannels().stream()
|
||||
.map(RefundChannelParam::getAmount)
|
||||
.reduce(0, Integer::sum);
|
||||
// 剩余可退款余额
|
||||
int refundableBalance = payOrder.getRefundableBalance() - amount;
|
||||
// 退款完成
|
||||
if (refundableBalance == 0) {
|
||||
payOrder.setRefundableBalance(refundableBalance);
|
||||
|
||||
// 设置支付订单状态
|
||||
if (asyncRefundInfo.getStatus() == PayRefundStatusEnum.PROGRESS) {
|
||||
// 设置为退款中
|
||||
payOrder.setStatus(PayStatusEnum.REFUNDING.getCode());
|
||||
} else if (refundableBalance == 0) {
|
||||
// 退款完成
|
||||
payOrder.setStatus(PayStatusEnum.REFUNDED.getCode());
|
||||
} else {
|
||||
// 部分退款
|
||||
payOrder.setStatus(PayStatusEnum.PARTIAL_REFUND.getCode());
|
||||
}
|
||||
payOrder.setRefundableBalance(refundableBalance);
|
||||
|
||||
// ----------------------- 退款订单处理 ---------------------------------------
|
||||
// 生成退款订单
|
||||
PayRefundOrder refundOrder = payRefundAssistService.generateRefundOrder(refundParam, payOrder);
|
||||
// 更新或保存相关订单
|
||||
payRefundAssistService.saveOrderAndChannels(refundOrder,refundChannelOrders);
|
||||
payOrderService.updateById(payOrder);
|
||||
return refundOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败处理
|
||||
*/
|
||||
private void errorHandler(RefundParam refundParam, PayOrder payOrder, Exception e) {
|
||||
private void errorHandler(RefundParam refundParam, PayOrder payOrder) {
|
||||
// 记录退款失败的记录
|
||||
PayRefundOrder refundOrder = payRefundAssistService.generateRefundOrder(refundParam, payOrder);
|
||||
payRefundAssistService.saveOrder(refundOrder);
|
||||
|
@@ -1,13 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayRefundService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
@@ -26,7 +22,6 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
|
||||
public class AliPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
|
||||
private final AliPayConfigService alipayConfigService;
|
||||
private final AliPayOrderService aliPayOrderService;
|
||||
private final AliPayRefundService aliRefundService;
|
||||
/**
|
||||
* 策略标识
|
||||
@@ -38,8 +33,6 @@ public class AliPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
private final PayOrderService payOrderService;
|
||||
|
||||
|
||||
/**
|
||||
* 退款前前操作
|
||||
@@ -56,20 +49,13 @@ public class AliPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
aliRefundService.refund(this.getPayOrder(), this.getRefundChannelParam().getAmount());
|
||||
aliPayOrderService.updateRefund(this.getPayOrder().getId(), this.getRefundChannelParam().getAmount());
|
||||
payOrderService.updateRefundSuccess(this.getPayOrder(), this.getRefundChannelParam().getAmount(), PayChannelEnum.ALI);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道退款订单对象
|
||||
* 退款发起成功操作
|
||||
*/
|
||||
@Override
|
||||
public PayRefundChannelOrder generateChannelOrder() {
|
||||
PayRefundChannelOrder payRefundChannelOrder = super.generateChannelOrder();
|
||||
// 追加关联对款请求号
|
||||
String refundRequestNo = PaymentContextLocal.get()
|
||||
.getRefundInfo()
|
||||
.getGatewayRequestNo();
|
||||
return payRefundChannelOrder.setGatewayOrderNo(refundRequestNo);
|
||||
public void doSuccessHandler() {
|
||||
// 查看
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.refund.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatRefundService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayRefundStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
@@ -61,17 +59,4 @@ public class WeChatPayRefundStrategy extends AbsPayRefundStrategy {
|
||||
payOrderService.updateRefundSuccess(this.getPayOrder(), this.getRefundChannelParam().getAmount(), PayChannelEnum.WECHAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道退款订单对象
|
||||
*/
|
||||
@Override
|
||||
public PayRefundChannelOrder generateChannelOrder() {
|
||||
PayRefundChannelOrder payRefundChannelOrder = super.generateChannelOrder();
|
||||
// 追加关联对款请求号
|
||||
String refundRequestNo = PaymentContextLocal.get()
|
||||
.getRefundInfo()
|
||||
.getGatewayRequestNo();
|
||||
return payRefundChannelOrder.setGatewayOrderNo(refundRequestNo);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -99,7 +99,7 @@ public class PayRepairService {
|
||||
*/
|
||||
private void success(PayOrder order, List<AbsPayRepairStrategy> strategies) {
|
||||
LocalDateTime payTime = PaymentContextLocal.get()
|
||||
.getAsyncPayInfo()
|
||||
.getReconcileInfo()
|
||||
.getPayTime();
|
||||
// 执行个通道的成功处理方法
|
||||
strategies.forEach(AbsPayRepairStrategy::doSuccessHandler);
|
||||
|
@@ -243,8 +243,8 @@ public class PaySyncService {
|
||||
.setRepairOrder(repair)
|
||||
.setRepairOrderId(repairOrderId)
|
||||
.setErrorMsg(errorMsg)
|
||||
.setClientIp(PaymentContextLocal.get().getRequest().getClientIp())
|
||||
.setReqId(PaymentContextLocal.get().getRequest().getReqId());
|
||||
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp())
|
||||
.setReqId(PaymentContextLocal.get().getRequestInfo().getReqId());
|
||||
paySyncRecordService.saveRecord(paySyncRecord);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.pay;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -20,15 +21,31 @@ public class PayChannelOrderDto extends BaseDto {
|
||||
@Schema(description = "支付id")
|
||||
private Long paymentId;
|
||||
|
||||
@Schema(description = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@Schema(description = "通道")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "支付方式")
|
||||
private String payWay;
|
||||
|
||||
@Schema(description = "异步支付方式")
|
||||
private boolean async;
|
||||
/**
|
||||
* 异步支付通道发给网关的退款号, 用与将记录关联起来
|
||||
*/
|
||||
@Schema(description = "关联网关支付号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
@Schema(description = "支付状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "金额")
|
||||
private Integer amount;
|
||||
|
||||
@Schema(description = "可退款金额")
|
||||
private Integer refundableBalance;
|
||||
}
|
||||
|
@@ -3,14 +3,12 @@ package cn.bootx.platform.daxpay.service.dto.order.pay;
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.entity.RefundableInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
@@ -53,13 +51,6 @@ public class PayOrderDto extends BaseDto {
|
||||
@Schema(description = "可退款余额")
|
||||
private Integer refundableBalance;
|
||||
|
||||
/**
|
||||
* 可退款信息列表
|
||||
* @see RefundableInfo
|
||||
*/
|
||||
@Schema(description = "可退款信息列表")
|
||||
private List<RefundableInfo> refundableInfos;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
|
@@ -48,9 +48,6 @@ public class PayRefundOrderDto extends BaseDto {
|
||||
@Schema(description = "退款时间")
|
||||
private LocalDateTime refundTime;
|
||||
|
||||
@Schema(description = "退款信息列表")
|
||||
private List<RefundableInfo> refundableInfo;
|
||||
|
||||
/**
|
||||
* @see PayRefundStatusEnum
|
||||
*/
|
||||
|
@@ -35,7 +35,7 @@ public class RefundChannelOrderDto extends BaseDto {
|
||||
private boolean async;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private Integer totalAmount;
|
||||
private Integer orderAmount;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private Integer amount;
|
||||
|
@@ -34,7 +34,7 @@ public abstract class AbsPayCallbackStrategy implements PayStrategy {
|
||||
* 支付回调
|
||||
*/
|
||||
public String payCallback(Map<String, String> params) {
|
||||
PaymentContextLocal.get().getCallbackParam().putAll(params);
|
||||
PaymentContextLocal.get().getCallbackInfo().getCallbackParam().putAll(params);
|
||||
log.info("支付回调处理: {}", params);
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
@@ -99,7 +99,7 @@ public abstract class AbsPayCallbackStrategy implements PayStrategy {
|
||||
* 保存回调记录
|
||||
*/
|
||||
public void saveNotifyRecord(PayCallbackResult result) {
|
||||
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
|
||||
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
|
||||
.setNotifyInfo(JSONUtil.toJsonStr(callbackParam))
|
||||
.setNotifyTime(LocalDateTime.now())
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.common.exception.ExceptionInfo;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -14,11 +15,21 @@ import lombok.Setter;
|
||||
@Setter
|
||||
public abstract class AbsPayCloseStrategy implements PayStrategy{
|
||||
|
||||
/** 支付对象 */
|
||||
/** 支付订单 */
|
||||
private PayOrder order = null;
|
||||
|
||||
public void initCloseParam(PayOrder order){
|
||||
/** 支付通道订单 */
|
||||
private PayChannelOrder channelOrder = null;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
public abstract PayChannelEnum getType();
|
||||
|
||||
public void initCloseParam(PayOrder order, PayChannelOrder channelOrder){
|
||||
this.order = order;
|
||||
this.channelOrder = channelOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,6 +47,6 @@ public abstract class AbsPayCloseStrategy implements PayStrategy{
|
||||
/**
|
||||
* 关闭失败的处理方式
|
||||
*/
|
||||
public void doErrorHandler(ExceptionInfo exceptionInfo) {
|
||||
public void doSuccessHandler() {
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.RefundParam;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
@@ -19,18 +20,21 @@ import lombok.Setter;
|
||||
@Setter
|
||||
public abstract class AbsPayRefundStrategy implements PayStrategy{
|
||||
|
||||
/** 支付对象 */
|
||||
/** 支付订单 */
|
||||
private PayOrder payOrder = null;
|
||||
|
||||
/** 支付通道对象 */
|
||||
/** 当前通道的订单 */
|
||||
private PayChannelOrder payChannelOrder = null;
|
||||
|
||||
/** 退款参数 */
|
||||
private RefundParam refundParam = null;
|
||||
|
||||
/** 当前支付通道退款参数 退款参数中的与这个不一致, 以这个为准 */
|
||||
/** 当前通道的退款参数 退款参数中的与这个不一致, 以这个为准 */
|
||||
private RefundChannelParam refundChannelParam = null;
|
||||
|
||||
/** 当前通道的退款订单 */
|
||||
private PayRefundChannelOrder refundChannelOrder;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
* @see PayChannelEnum
|
||||
@@ -49,24 +53,30 @@ public abstract class AbsPayRefundStrategy implements PayStrategy{
|
||||
/**
|
||||
* 退款前对处理 包含必要的校验以及对Payment对象的创建和保存操作
|
||||
*/
|
||||
public void doBeforeRefundHandler() {
|
||||
}
|
||||
public void doBeforeRefundHandler() {}
|
||||
|
||||
/**
|
||||
* 退款操作
|
||||
*/
|
||||
public abstract void doRefundHandler();
|
||||
|
||||
/**
|
||||
* 退款发起成功操作
|
||||
*/
|
||||
public void doSuccessHandler() {
|
||||
this.refundChannelOrder.setStatus(PayRefundStatusEnum.SUCCESS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道退款订单对象
|
||||
*/
|
||||
public PayRefundChannelOrder generateChannelOrder() {
|
||||
return new PayRefundChannelOrder()
|
||||
.setChannel(this.getPayChannelOrder().getChannel())
|
||||
.setTotalAmount(this.getPayChannelOrder().getAmount())
|
||||
.setAmount(this.getRefundChannelParam().getAmount())
|
||||
public void generateChannelOrder() {
|
||||
this.refundChannelOrder = new PayRefundChannelOrder()
|
||||
.setPayChannelId(this.getPayChannelOrder().getId())
|
||||
.setAsync(this.getPayChannelOrder().isAsync())
|
||||
.setPayChannelId(this.getPayChannelOrder().getId());
|
||||
.setChannel(this.getPayChannelOrder().getChannel())
|
||||
.setOrderAmount(this.getPayChannelOrder().getAmount())
|
||||
.setAmount(this.getRefundChannelParam().getAmount());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,9 +20,12 @@ import lombok.Setter;
|
||||
public abstract class AbsPayStrategy implements PayStrategy{
|
||||
|
||||
|
||||
/** 支付对象 */
|
||||
/** 支付订单 */
|
||||
private PayOrder order = null;
|
||||
|
||||
/** 通道支付订单, 异步支付通道单独处理通道支付订单 */
|
||||
private PayChannelOrder channelOrder = null;
|
||||
|
||||
/** 支付参数 */
|
||||
private PayParam payParam = null;
|
||||
|
||||
@@ -62,14 +65,11 @@ public abstract class AbsPayStrategy implements PayStrategy{
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通道支付单
|
||||
* 生成通道支付单, 如果不需要可以进行覆盖
|
||||
*/
|
||||
public PayChannelOrder generateChannelOrder() {
|
||||
public void generateChannelOrder() {
|
||||
PayChannelOrder payChannelOrder = PayBuilder.buildPayChannelOrder(this.getPayChannelParam());
|
||||
payChannelOrder.setId(this.getOrder().getId());
|
||||
return payChannelOrder;
|
||||
this.channelOrder = payChannelOrder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user