feat 支付订单拆分退款状态为单独的字段, 策略工厂修改为通用策略工厂

This commit is contained in:
DaxPay
2024-06-07 17:21:02 +08:00
parent 848c55d13c
commit ce8dee8afe
59 changed files with 241 additions and 493 deletions

View File

@@ -7,8 +7,8 @@
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
- [ ] 管理端界面支持扫码绑定对账接收方功能
- [ ] 支付通道两个独立的配置进行合并为一个
- [ ] 支付拆分退款状态为单独的字段
- [ ] 工厂支持自适应
- [x] 支付订单拆分退款状态为单独的字段
- [x] 策略工厂修改为通用策略工厂
- [x] 支付和退款达到终态不可以再回退回之前的状态
- [x] 修复支付关闭参数名称不正确问题
2.0.9: 消息通知改版和功能优化

View File

@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付订单分账状态
* 支付订单分账状态
* @author xxm
* @since 2024/4/16
*/

View File

@@ -0,0 +1,36 @@
package cn.daxpay.single.code;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Objects;
/**
* 支付订单的退款状态
* @author xxm
* @since 2024/6/7
*/
@Getter
@AllArgsConstructor
public enum PayOrderRefundStatusEnum {
NO_REFUND("no_refund","未退款"),
REFUNDING("refunding","退款中"),
PARTIAL_REFUND("partial_refund","部分退款"),
REFUNDED("refunded","全部退款"),
;
private final String code;
private final String name;
/**
* 根据编码获取枚举
*/
public static PayOrderRefundStatusEnum findByCode(String code){
return Arrays.stream(values())
.filter(payStatusEnum -> Objects.equals(payStatusEnum.getCode(), code))
.findFirst()
.orElseThrow(() -> new DataNotExistException("该枚举不存在"));
}
}

View File

@@ -19,9 +19,6 @@ public enum PayStatusEnum {
SUCCESS("success","成功"),
CLOSE("close","支付关闭"),
CANCEL("cancel","支付撤销"),
REFUNDING("refunding","退款中"),
PARTIAL_REFUND("partial_refund","部分退款"),
REFUNDED("refunded","全部退款"),
FAIL("fail","失败");
/** 编码 */

View File

@@ -1,6 +1,7 @@
package cn.daxpay.single.service.core.order.pay.builder;
import cn.daxpay.single.code.PayOrderAllocStatusEnum;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.param.payment.pay.PayParam;
import cn.daxpay.single.service.common.context.NoticeLocal;
@@ -38,6 +39,7 @@ public class PayBuilder {
.setTitle(payParam.getTitle())
.setDescription(payParam.getDescription())
.setStatus(PayStatusEnum.PROGRESS.getCode())
.setRefundStatus(PayOrderRefundStatusEnum.NO_REFUND.getCode())
.setAllocation(payParam.getAllocation())
.setAmount(payParam.getAmount())
.setChannel(payParam.getChannel())

View File

@@ -15,7 +15,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -58,14 +57,10 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
* 查询对账用订单记录(指定时间和状态的订单)
*/
public List<PayOrder> findReconcile(String channel, LocalDateTime startTime, LocalDateTime endTime) {
List<String> status = Arrays.asList(PayStatusEnum.SUCCESS.getCode(),
PayStatusEnum.PARTIAL_REFUND.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.REFUNDED.getCode());
return this.lambdaQuery()
.eq(PayOrder::getChannel, channel)
.between(PayOrder::getPayTime, startTime, endTime)
.in(PayOrder::getStatus, status)
.eq(PayOrder::getStatus, PayStatusEnum.SUCCESS.getCode())
.list();
}
@@ -73,15 +68,11 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
* 查询自动分账的订单记录(指定时间和状态的订单)
*/
public List<PayOrder> findAutoAllocation() {
List<String> status = Arrays.asList(PayStatusEnum.SUCCESS.getCode(),
PayStatusEnum.PARTIAL_REFUND.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.REFUNDED.getCode());
return this.lambdaQuery()
.eq(PayOrder::getAllocation, true)
.eq(PayOrder::getAutoAllocation, true)
.eq(PayOrder::getAllocationStatus, PayOrderAllocStatusEnum.WAITING.getCode())
.in(PayOrder::getStatus, status)
.eq(PayOrder::getStatus, PayStatusEnum.SUCCESS.getCode())
.list();
}
@@ -90,13 +81,7 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
*/
public Integer getTalAmount(PayOrderQuery query){
QueryWrapper<PayOrder> generator = QueryGenerator.generator(query);
// 成功, 退款相关都算
generator.in(MpUtil.getColumnName(PayOrder::getStatus),
PayStatusEnum.SUCCESS.getCode(),
PayStatusEnum.REFUNDED.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.PARTIAL_REFUND.getCode()
);
generator.eq(MpUtil.getColumnName(PayOrder::getStatus), PayStatusEnum.SUCCESS.getCode());
return baseMapper.getTalAmount(generator);
}
@@ -105,7 +90,7 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
*/
public List<PayOrder> queryExpiredOrder() {
return lambdaQuery()
.eq(PayOrder::getStatus, PayStatusEnum.REFUNDING.getCode())
.eq(PayOrder::getStatus, PayStatusEnum.PROGRESS.getCode())
.lt(PayOrder::getExpiredTime, LocalDateTime.now())
.list();
}

View File

@@ -5,6 +5,7 @@ import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
import cn.daxpay.single.code.PayMethodEnum;
import cn.daxpay.single.code.PayOrderAllocStatusEnum;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.service.core.order.pay.convert.PayOrderConvert;
import cn.daxpay.single.service.dto.order.pay.PayOrderDto;
@@ -92,6 +93,14 @@ public class PayOrder extends MpBaseEntity implements EntityBaseFunction<PayOrde
@DbColumn(comment = "支付状态")
private String status;
/**
* 退款状态
* @see PayOrderRefundStatusEnum
*/
@DbColumn(comment = "退款状态")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String refundStatus;
/**
* 分账状态
* @see PayOrderAllocStatusEnum

View File

@@ -38,8 +38,8 @@ public class AliPayAllocationStrategy extends AbsAllocationStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -37,8 +37,8 @@ public class WeChatPayAllocationStrategy extends AbsAllocationStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -36,8 +36,8 @@ public class AliPayAllocationReceiverStrategy extends AbsAllocationReceiverStrat
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -36,8 +36,8 @@ public class WeChatPayAllocationReceiverStrategy extends AbsAllocationReceiverSt
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,38 +0,0 @@
package cn.daxpay.single.service.core.payment.cancel.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.cancel.strategy.AliPayCancelStrategy;
import cn.daxpay.single.service.core.payment.cancel.strategy.WeChatPayCancelStrategy;
import cn.daxpay.single.service.func.AbsPayCancelStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 订单撤销策略工厂
* @author xxm
* @since 2024/6/5
*/
@UtilityClass
public class PayCancelStrategyFactory {
/**
* 根据传入的支付通道创建策略
* @return 支付策略
*/
public static AbsPayCancelStrategy create(String channel) {
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
AbsPayCancelStrategy strategy;
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliPayCancelStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatPayCancelStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
return strategy;
}
}

View File

@@ -10,11 +10,11 @@ import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.cancel.factory.PayCancelStrategyFactory;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.record.close.entity.PayCloseRecord;
import cn.daxpay.single.service.core.record.close.service.PayCloseRecordService;
import cn.daxpay.single.service.func.AbsPayCancelStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
@@ -57,7 +57,7 @@ public class PayCancelService {
throw new PayFailureException("订单不是支付中, 无法进行撤销订单");
}
try {
AbsPayCancelStrategy strategy = PayCancelStrategyFactory.create(payOrder.getChannel());
AbsPayCancelStrategy strategy = PayStrategyFactory.create(payOrder.getChannel(), AbsPayCancelStrategy.class);
// 设置支付订单
strategy.setOrder(payOrder);
// 撤销前准备
@@ -110,4 +110,5 @@ public class PayCancelService {
.setClientIp(clientIp);
payCloseRecordService.saveRecord(record);
}
}

View File

@@ -28,8 +28,8 @@ public class AliPayCancelStrategy extends AbsPayCancelStrategy {
private final AliPayCloseService aliPayCloseService;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -32,8 +32,8 @@ public class WeChatPayCancelStrategy extends AbsPayCancelStrategy {
private WeChatPayConfig weChatPayConfig;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,42 +0,0 @@
package cn.daxpay.single.service.core.payment.close.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.close.strategy.AliPayCloseStrategy;
import cn.daxpay.single.service.core.payment.close.strategy.UnionPayCloseStrategy;
import cn.daxpay.single.service.core.payment.close.strategy.WeChatPayCloseStrategy;
import cn.daxpay.single.service.func.AbsPayCloseStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 支付关闭策略工厂
* @author xxm
* @since 2023/12/29
*/
@UtilityClass
public class PayCloseStrategyFactory {
/**
* 根据传入的支付通道创建策略
* @return 支付策略
*/
public static AbsPayCloseStrategy create(String channel) {
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
AbsPayCloseStrategy strategy;
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliPayCloseStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatPayCloseStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionPayCloseStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
return strategy;
}
}

View File

@@ -10,11 +10,11 @@ import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.close.factory.PayCloseStrategyFactory;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.record.close.entity.PayCloseRecord;
import cn.daxpay.single.service.core.record.close.service.PayCloseRecordService;
import cn.daxpay.single.service.func.AbsPayCloseStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
@@ -67,7 +67,7 @@ public class PayCloseService {
throw new PayFailureException("订单不是支付中, 无法进行关闭订单");
}
try {
AbsPayCloseStrategy strategy = PayCloseStrategyFactory.create(payOrder.getChannel());
AbsPayCloseStrategy strategy = PayStrategyFactory.create(payOrder.getChannel(), AbsPayCloseStrategy.class);
// 设置支付订单
strategy.setOrder(payOrder);
// 关闭前准备
@@ -117,4 +117,5 @@ public class PayCloseService {
.setClientIp(clientIp);
payCloseRecordService.saveRecord(record);
}
}

View File

@@ -28,8 +28,8 @@ public class AliPayCloseStrategy extends AbsPayCloseStrategy {
private final AliPayCloseService aliPayCloseService;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -32,8 +32,8 @@ public class UnionPayCloseStrategy extends AbsPayCloseStrategy {
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
/**

View File

@@ -29,8 +29,8 @@ public class WeChatPayCloseStrategy extends AbsPayCloseStrategy {
private WeChatPayConfig weChatPayConfig;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,48 +0,0 @@
package cn.daxpay.single.service.core.payment.pay.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.pay.strategy.AliPayStrategy;
import cn.daxpay.single.service.core.payment.pay.strategy.UnionPayStrategy;
import cn.daxpay.single.service.core.payment.pay.strategy.WalletPayStrategy;
import cn.daxpay.single.service.core.payment.pay.strategy.WeChatPayStrategy;
import cn.daxpay.single.service.func.AbsPayStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 支付策略工厂
*
* @author xxm
* @since 2020/12/11
*/
@UtilityClass
public class PayStrategyFactory {
/**
* 根据传入的支付通道创建策略
* @return 支付策略
*/
public AbsPayStrategy create(String channel) {
AbsPayStrategy strategy;
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliPayStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatPayStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionPayStrategy.class);
break;
case WALLET:
strategy = SpringUtil.getBean(WalletPayStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
return strategy;
}
}

View File

@@ -3,6 +3,7 @@ package cn.daxpay.single.service.core.payment.pay.service;
import cn.bootx.platform.common.core.util.CollUtil;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.param.payment.pay.PayParam;
import cn.daxpay.single.result.pay.PayResult;
@@ -205,8 +206,7 @@ public class PayAssistService {
throw new PayFailureException("支付失败或已经被关闭");
}
// 退款类型状态
tradesStatus = Arrays.asList(REFUNDED.getCode(), PARTIAL_REFUND.getCode(), REFUNDING.getCode());
if (tradesStatus.contains(payOrder.getStatus())) {
if (Objects.equals(payOrder.getRefundStatus(), PayOrderRefundStatusEnum.REFUNDING.getCode())) {
throw new PayFailureException("该订单处于退款状态");
}
// 其他状态直接抛出兜底异常

View File

@@ -1,6 +1,7 @@
package cn.daxpay.single.service.core.payment.pay.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.param.payment.pay.PayParam;
import cn.daxpay.single.result.pay.PayResult;
import cn.daxpay.single.service.common.context.PayLocal;
@@ -10,15 +11,17 @@ import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.entity.PayOrderExtra;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.payment.pay.factory.PayStrategyFactory;
import cn.daxpay.single.service.core.record.flow.service.TradeFlowRecordService;
import cn.daxpay.single.service.func.AbsPayStrategy;
import cn.daxpay.single.service.func.AbsRefundSyncStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.daxpay.single.util.PayUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -94,7 +97,7 @@ public class PayService {
*/
public PayResult firstPay(PayParam payParam){
// 获取支付策略类
AbsPayStrategy payStrategy = PayStrategyFactory.create(payParam.getChannel());
AbsPayStrategy payStrategy = PayStrategyFactory.create(payParam.getChannel(), AbsPayStrategy.class);
// 初始化支付的参数
payStrategy.setPayParam(payParam);
// 执行支付前处理动作, 进行各种校验, 校验通过才会进行下面的操作
@@ -145,7 +148,7 @@ public class PayService {
*/
public PayResult repeatPay(PayParam payParam, PayOrder payOrder){
// 获取支付策略类
AbsPayStrategy payStrategy = PayStrategyFactory.create(payParam.getChannel());
AbsPayStrategy payStrategy = PayStrategyFactory.create(payParam.getChannel(),AbsPayStrategy.class);
// 初始化支付的参数
payStrategy.initPayParam(payOrder, payParam);
// 执行支付前处理动作
@@ -192,4 +195,17 @@ public class PayService {
}
return payAssistService.buildResult(payOrder);
}
/**
* 根据传入的通道获取策略
* @return 支付策略
*/
private AbsPayStrategy getStrategy(String channel) {
val beansOfType = SpringUtil.getBeansOfType(AbsPayStrategy.class);
return beansOfType.values().stream()
.filter(strategy -> strategy.getChannel().equals(channel))
.findFirst()
.orElseThrow(PayUnsupportedMethodException::new);
}
}

View File

@@ -37,9 +37,9 @@ public class AliPayStrategy extends AbsPayStrategy {
private AliPayParam aliPayParam;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -41,8 +41,8 @@ public class UnionPayStrategy extends AbsPayStrategy {
private UnionPayConfig unionPayConfig;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
/**
* 支付前操作

View File

@@ -44,8 +44,8 @@ public class WalletPayStrategy extends AbsPayStrategy {
private Wallet wallet;
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WALLET;
public String getChannel() {
return PayChannelEnum.WALLET.getCode();
}
/**

View File

@@ -39,8 +39,8 @@ public class WeChatPayStrategy extends AbsPayStrategy {
* 类型
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,32 +0,0 @@
package cn.daxpay.single.service.core.payment.reconcile.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.func.AbsReconcileStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
import java.util.Map;
import java.util.Objects;
/**
* 支付对账工厂类
* @author xxm
* @since 2024/1/18
*/
@UtilityClass
public class ReconcileStrategyFactory {
/**
* 根据传入的支付类型批量创建策略
*/
public AbsReconcileStrategy create(String channel) {
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
Map<String, AbsReconcileStrategy> beansOfType = SpringUtil.getBeansOfType(AbsReconcileStrategy.class);
return beansOfType.values().stream()
.filter(strategy -> Objects.equals(strategy.getChannel(), channelEnum))
.findFirst()
.orElseThrow(PayUnsupportedMethodException::new);
}
}

View File

@@ -12,17 +12,17 @@ import cn.daxpay.single.service.core.order.reconcile.dao.ReconcileDiffManager;
import cn.daxpay.single.service.core.order.reconcile.dao.ReconcileFileManager;
import cn.daxpay.single.service.core.order.reconcile.dao.ReconcileOrderManager;
import cn.daxpay.single.service.core.order.reconcile.dao.ReconcileOutTradeManager;
import cn.daxpay.single.service.core.order.reconcile.entity.ReconcileOutTrade;
import cn.daxpay.single.service.core.order.reconcile.entity.ReconcileDiff;
import cn.daxpay.single.service.core.order.reconcile.entity.ReconcileFile;
import cn.daxpay.single.service.core.order.reconcile.entity.ReconcileOrder;
import cn.daxpay.single.service.core.order.reconcile.entity.ReconcileOutTrade;
import cn.daxpay.single.service.core.order.reconcile.service.ReconcileOrderService;
import cn.daxpay.single.service.core.payment.reconcile.domain.GeneralTradeInfo;
import cn.daxpay.single.service.core.payment.reconcile.factory.ReconcileStrategyFactory;
import cn.daxpay.single.service.dto.order.reconcile.ReconcileDiffExcel;
import cn.daxpay.single.service.dto.order.reconcile.ReconcileTradeDetailExcel;
import cn.daxpay.single.service.func.AbsReconcileStrategy;
import cn.daxpay.single.service.param.reconcile.ReconcileUploadParam;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.daxpay.single.util.OrderNoGenerateUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
@@ -106,7 +106,7 @@ public class ReconcileService {
// 将对账订单写入到上下文中
PaymentContextLocal.get().getReconcileInfo().setReconcileOrder(reconcileOrder);
// 构建对账策略
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
AbsReconcileStrategy reconcileStrategy = PayStrategyFactory.create(reconcileOrder.getChannel(), AbsReconcileStrategy.class);
reconcileStrategy.setRecordOrder(reconcileOrder);
reconcileStrategy.doBeforeHandler();
try {
@@ -136,7 +136,7 @@ public class ReconcileService {
.orElseThrow(() -> new DataNotExistException("未找到对账订单"));
// 将对账订单写入到上下文中
PaymentContextLocal.get().getReconcileInfo().setReconcileOrder(reconcileOrder);
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
AbsReconcileStrategy reconcileStrategy = PayStrategyFactory.create(reconcileOrder.getChannel(), AbsReconcileStrategy.class);
reconcileStrategy.setRecordOrder(reconcileOrder);
reconcileStrategy.doBeforeHandler();
@@ -183,7 +183,7 @@ public class ReconcileService {
// 查询对账单
List<ReconcileOutTrade> reconcileTradeDetails = reconcileOutTradeManager.findAllByReconcileId(reconcileOrder.getId());
// 构建对账策略
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
AbsReconcileStrategy reconcileStrategy =PayStrategyFactory.create(reconcileOrder.getChannel(), AbsReconcileStrategy.class);
// 初始化参数
reconcileStrategy.setRecordOrder(reconcileOrder);

View File

@@ -37,9 +37,9 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
*
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -40,8 +40,8 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
/**

View File

@@ -40,8 +40,8 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,47 +0,0 @@
package cn.daxpay.single.service.core.payment.refund.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.refund.strategy.AliRefundStrategy;
import cn.daxpay.single.service.core.payment.refund.strategy.UnionRefundStrategy;
import cn.daxpay.single.service.core.payment.refund.strategy.WalletRefundStrategy;
import cn.daxpay.single.service.core.payment.refund.strategy.WeChatRefundStrategy;
import cn.daxpay.single.service.func.AbsRefundStrategy;
import cn.hutool.extra.spring.SpringUtil;
/**
* 退款策略工厂
* @author xxm
* @since 2023/7/4
*/
public class RefundStrategyFactory {
/**
* 根据传入的支付通道创建策略
* @return 支付策略
*/
public static AbsRefundStrategy create(String channel) {
AbsRefundStrategy strategy;
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliRefundStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatRefundStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionRefundStrategy.class);
break;
case WALLET:
strategy = SpringUtil.getBean(WalletRefundStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
return strategy;
}
}

View File

@@ -1,5 +1,6 @@
package cn.daxpay.single.service.core.payment.refund.service;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.PaySignTypeEnum;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.code.RefundStatusEnum;
@@ -21,6 +22,7 @@ import cn.daxpay.single.util.PaySignUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -78,20 +80,19 @@ public class RefundAssistService {
* 检查并处理退款参数
*/
public void checkAndParam(RefundParam param, PayOrder payOrder){
// 状态判断, 支付中/失败/取消等不能进行退款
List<String> tradesStatus = Arrays.asList(
PayStatusEnum.PROGRESS.getCode(),
PayStatusEnum.CLOSE.getCode(),
PayStatusEnum.CANCEL.getCode(),
PayStatusEnum.REFUNDED.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.FAIL.getCode());
if (tradesStatus.contains(payOrder.getStatus())) {
// 非支付完成的不能进行退款
if (!Objects.equals(SUCCESS.getCode(), payOrder.getStatus())) {
PayStatusEnum statusEnum = PayStatusEnum.findByCode(payOrder.getStatus());
throw new PayFailureException("当前支付单订状态["+statusEnum.getName()+"]不允许发起退款操作");
}
// 退款中和退款完成不能退款
List<String> tradesStatus = Arrays.asList(
PayOrderRefundStatusEnum.REFUNDED.getCode(),
PayOrderRefundStatusEnum.REFUNDING.getCode());
if (tradesStatus.contains(payOrder.getRefundStatus())){
val statusEnum = PayOrderRefundStatusEnum.findByCode(payOrder.getRefundStatus());
throw new PayFailureException("当前支付单退款状态["+statusEnum.getName()+"]不允许发起退款操作");
}
// 退款号唯一校验
if (StrUtil.isNotBlank(param.getBizRefundNo()) && refundOrderManager.existsByRefundNo(param.getBizRefundNo())){
throw new PayFailureException("退款单号已存在");

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.core.payment.refund.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.util.CollUtil;
import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.RefundStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.param.payment.refund.RefundParam;
@@ -18,9 +18,9 @@ import cn.daxpay.single.service.core.order.refund.dao.RefundOrderManager;
import cn.daxpay.single.service.core.order.refund.entity.RefundOrder;
import cn.daxpay.single.service.core.order.refund.entity.RefundOrderExtra;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.payment.refund.factory.RefundStrategyFactory;
import cn.daxpay.single.service.core.record.flow.service.TradeFlowRecordService;
import cn.daxpay.single.service.func.AbsRefundStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.lock.LockInfo;
@@ -106,7 +106,7 @@ public class RefundService {
// 检查退款参数
refundAssistService.checkAndParam(param, payOrder);
// 通过退款参数获取退款策略
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(payOrder.getChannel());
AbsRefundStrategy refundStrategy = PayStrategyFactory.create(payOrder.getChannel(), AbsRefundStrategy.class);
// 进行退款前预处理
refundStrategy.doBeforeRefundHandler();
// 退款操作的预处理, 对支付订单进行预扣款, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
@@ -136,7 +136,7 @@ public class RefundService {
// 预扣支付订单要退款的金额并进行更新
int orderRefundableBalance = payOrder.getRefundableBalance() - refundParam.getAmount();
payOrder.setRefundableBalance(orderRefundableBalance)
.setStatus(PayStatusEnum.REFUNDING.getCode());
.setRefundStatus(PayOrderRefundStatusEnum.REFUNDING.getCode());
payOrderService.updateById(payOrder);
// ----------------------- 退款订单创建 -------------------------
return refundAssistService.createOrder(refundParam, payOrder);
@@ -158,7 +158,7 @@ public class RefundService {
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
RefundOrderExtra refundOrderExtra = refundOrderExtraManager.findById(refundOrder.getId())
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(refundOrder.getChannel());
AbsRefundStrategy refundStrategy = PayStrategyFactory.create(refundOrder.getChannel(), AbsRefundStrategy.class);
// 设置退款订单对象
refundStrategy.setRefundOrder(refundOrder);
// 退款前准备操作
@@ -208,14 +208,14 @@ public class RefundService {
int refundableBalance = payOrder.getRefundableBalance();
// 退款状态为退款中
if (refundInfo.getStatus() == RefundStatusEnum.PROGRESS) {
payOrder.setStatus(PayStatusEnum.REFUNDING.getCode());
payOrder.setRefundStatus(PayOrderRefundStatusEnum.REFUNDING.getCode());
}
// 退款状态为成功
else {
if (refundableBalance == 0) {
payOrder.setStatus(PayStatusEnum.REFUNDED.getCode());
payOrder.setRefundStatus(PayOrderRefundStatusEnum.REFUNDED.getCode());
} else {
payOrder.setStatus(PayStatusEnum.PARTIAL_REFUND.getCode());
payOrder.setRefundStatus(PayOrderRefundStatusEnum.PARTIAL_REFUND.getCode());
}
// 记录流水
tradeFlowRecordService.saveRefund(refundOrder);

View File

@@ -28,9 +28,9 @@ public class AliRefundStrategy extends AbsRefundStrategy {
*
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}

View File

@@ -34,8 +34,8 @@ public class UnionRefundStrategy extends AbsRefundStrategy {
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
/**

View File

@@ -36,8 +36,8 @@ public class WalletRefundStrategy extends AbsRefundStrategy {
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WALLET;
public String getChannel() {
return PayChannelEnum.WALLET.getCode();
}

View File

@@ -33,8 +33,8 @@ public class WeChatRefundStrategy extends AbsRefundStrategy {
* @see PayChannelEnum
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -1,42 +0,0 @@
package cn.daxpay.single.service.core.payment.repair.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.repair.strategy.pay.AliPayRepairStrategy;
import cn.daxpay.single.service.core.payment.repair.strategy.pay.UnionPayRepairStrategy;
import cn.daxpay.single.service.core.payment.repair.strategy.pay.WeChatPayRepairStrategy;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 支付修复策略工厂类
* @author xxm
* @since 2023/12/29
*/
@UtilityClass
public class PayRepairStrategyFactory {
/**
* 根据传入的支付通道创建策略
* @return 支付修复策略
*/
public static AbsPayRepairStrategy create(String channel) {
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
AbsPayRepairStrategy strategy;
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliPayRepairStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatPayRepairStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionPayRepairStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
return strategy;
}
}

View File

@@ -1,7 +1,7 @@
package cn.daxpay.single.service.core.payment.repair.result;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.RefundStatusEnum;
import cn.daxpay.single.code.PayStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -21,7 +21,7 @@ public class RefundRepairResult {
/** 退款修复后状态 */
private RefundStatusEnum afterRefundStatus;
/** 支付修复前状态 */
private PayStatusEnum beforePayStatus;
private PayOrderRefundStatusEnum beforePayStatus;
/** 支付修复后状态 */
private PayStatusEnum afterPayStatus;
private PayOrderRefundStatusEnum afterPayStatus;
}

View File

@@ -8,12 +8,12 @@ import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.payment.repair.factory.PayRepairStrategyFactory;
import cn.daxpay.single.service.core.payment.repair.result.PayRepairResult;
import cn.daxpay.single.service.core.record.flow.service.TradeFlowRecordService;
import cn.daxpay.single.service.core.record.repair.entity.PayRepairRecord;
import cn.daxpay.single.service.core.record.repair.service.PayRepairRecordService;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.hutool.core.util.IdUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
@@ -23,7 +23,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Objects;
import java.util.Optional;
/**
* 支付修复服务
@@ -57,7 +58,7 @@ public class PayRepairService {
}
// 2.1 初始化修复参数
AbsPayRepairStrategy repairStrategy = PayRepairStrategyFactory.create(order.getChannel());
AbsPayRepairStrategy repairStrategy = PayStrategyFactory.create(order.getChannel(),AbsPayRepairStrategy.class);
repairStrategy.setOrder(order);
// 2.2 执行前置处理
repairStrategy.doBeforeHandler();

View File

@@ -1,5 +1,6 @@
package cn.daxpay.single.service.core.payment.repair.service;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.code.RefundStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
@@ -100,20 +101,20 @@ public class RefundRepairService {
private RefundRepairResult success(RefundOrder refundOrder, PayOrder payOrder) {
RepairLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
// 订单相关状态
PayStatusEnum beforePayStatus = PayStatusEnum.findByCode(payOrder.getStatus());
PayStatusEnum afterPayRefundStatus;
PayOrderRefundStatusEnum beforePayStatus = PayOrderRefundStatusEnum.findByCode(payOrder.getRefundStatus());
PayOrderRefundStatusEnum afterPayRefundStatus;
RefundStatusEnum beforeRefundStatus = RefundStatusEnum.findByCode(refundOrder.getStatus());
// 判断订单全部退款还是部分退款
if (Objects.equals(payOrder.getRefundableBalance(),0)){
afterPayRefundStatus = PayStatusEnum.REFUNDED;
afterPayRefundStatus = PayOrderRefundStatusEnum.REFUNDED;
} else {
afterPayRefundStatus = PayStatusEnum.PARTIAL_REFUND;
afterPayRefundStatus = PayOrderRefundStatusEnum.PARTIAL_REFUND;
}
// 设置退款为完成状态和完成时间
refundOrder.setStatus(RefundStatusEnum.SUCCESS.getCode())
.setFinishTime(repairInfo.getFinishTime());
payOrder.setStatus(afterPayRefundStatus.getCode());
payOrder.setRefundStatus(afterPayRefundStatus.getCode());
// 更新订单和退款相关订单
payOrderService.updateById(payOrder);
@@ -144,7 +145,7 @@ public class RefundRepairService {
RefundRepairResult repairResult = new RefundRepairResult();
// 订单修复前状态
PayStatusEnum beforePayStatus = PayStatusEnum.findByCode(refundOrder.getStatus());
PayOrderRefundStatusEnum beforePayStatus = PayOrderRefundStatusEnum.findByCode(payOrder.getRefundStatus());
RefundStatusEnum beforeRefundStatus = RefundStatusEnum.findByCode(refundOrder.getStatus());
repairResult.setBeforePayStatus(beforePayStatus)
.setBeforeRefundStatus(beforeRefundStatus);
@@ -154,11 +155,11 @@ public class RefundRepairService {
// 退款失败返还后的余额+可退余额 == 订单金额 支付订单回退为为支付成功状态
if (payOrderAmount == payOrder.getAmount()){
payOrder.setStatus(PayStatusEnum.SUCCESS.getCode());
repairResult.setAfterPayStatus(PayStatusEnum.SUCCESS);
repairResult.setAfterPayStatus(PayOrderRefundStatusEnum.NO_REFUND);
} else {
// 回归部分退款状态
payOrder.setStatus(PayStatusEnum.PARTIAL_REFUND.getCode());
repairResult.setAfterPayStatus(PayStatusEnum.PARTIAL_REFUND);
payOrder.setRefundStatus(PayOrderRefundStatusEnum.PARTIAL_REFUND.getCode());
repairResult.setAfterPayStatus(PayOrderRefundStatusEnum.PARTIAL_REFUND);
}
// 更新支付订单相关的可退款金额
@@ -179,7 +180,8 @@ public class RefundRepairService {
*/
private PayRepairRecord payRepairRecord(PayOrder order, RefundRepairWayEnum repairType, RefundRepairResult repairResult){
// 修复前的状态
String beforeStatus = Optional.ofNullable(repairResult.getBeforePayStatus()).map(PayStatusEnum::getCode).orElse(null);
String beforeStatus = Optional.ofNullable(repairResult.getBeforePayStatus())
.map(PayOrderRefundStatusEnum::getCode).orElse(null);
// 修复发起来源
String source = PaymentContextLocal.get()
.getRepairInfo()

View File

@@ -29,9 +29,9 @@ public class AliPayRepairStrategy extends AbsPayRepairStrategy {
/**
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -24,8 +24,8 @@ public class UnionPayRepairStrategy extends AbsPayRepairStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
/**

View File

@@ -32,8 +32,8 @@ public class WeChatPayRepairStrategy extends AbsPayRepairStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}

View File

@@ -1,44 +0,0 @@
package cn.daxpay.single.service.core.payment.sync.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.sync.strategy.pay.AliPaySyncStrategy;
import cn.daxpay.single.service.core.payment.sync.strategy.pay.UnionPaySyncStrategy;
import cn.daxpay.single.service.core.payment.sync.strategy.pay.WeChatPaySyncStrategy;
import cn.daxpay.single.service.func.AbsPaySyncStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 支付同步策略工厂类
* @author xxm
* @since 2023/7/14
*/
@UtilityClass
public class PaySyncStrategyFactory {
/**
* 获取支付同步策略
* @param channelCode 支付通道编码
* @return 支付同步策略类
*/
public AbsPaySyncStrategy create(String channelCode) {
AbsPaySyncStrategy strategy;
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channelCode);
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliPaySyncStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatPaySyncStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionPaySyncStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
// noinspection ConstantConditions
return strategy;
}
}

View File

@@ -1,43 +0,0 @@
package cn.daxpay.single.service.core.payment.sync.factory;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.core.payment.sync.strategy.Refund.AliRefundSyncStrategy;
import cn.daxpay.single.service.core.payment.sync.strategy.Refund.UnionRefundSyncStrategy;
import cn.daxpay.single.service.core.payment.sync.strategy.Refund.WeChatRefundSyncStrategy;
import cn.daxpay.single.service.func.AbsRefundSyncStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
/**
* 支付退款同步策略工厂
* @author xxm
* @since 2024/1/29
*/
@UtilityClass
public class RefundSyncStrategyFactory {
/**
* 获取支付同步策略, 只有异步支付方式才需要这个功能
* @param channelCode 支付通道编码
* @return 支付同步策略类
*/
public static AbsRefundSyncStrategy create(String channelCode) {
AbsRefundSyncStrategy strategy;
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channelCode);
switch (channelEnum) {
case ALI:
strategy = SpringUtil.getBean(AliRefundSyncStrategy.class);
break;
case UNION_PAY:
strategy = SpringUtil.getBean(UnionRefundSyncStrategy.class);
break;
case WECHAT:
strategy = SpringUtil.getBean(WeChatRefundSyncStrategy.class);
break;
default:
throw new PayUnsupportedMethodException();
}
// noinspection ConstantConditions
return strategy;
}
}

View File

@@ -3,6 +3,7 @@ package cn.daxpay.single.service.core.payment.sync.service;
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.daxpay.single.code.PayChannelEnum;
import cn.daxpay.single.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.code.PayStatusEnum;
import cn.daxpay.single.code.PaySyncStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
@@ -18,11 +19,11 @@ import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.repair.result.PayRepairResult;
import cn.daxpay.single.service.core.payment.repair.service.PayRepairService;
import cn.daxpay.single.service.core.payment.sync.factory.PaySyncStrategyFactory;
import cn.daxpay.single.service.core.payment.sync.result.PayRemoteSyncResult;
import cn.daxpay.single.service.core.record.sync.entity.PaySyncRecord;
import cn.daxpay.single.service.core.record.sync.service.PaySyncRecordService;
import cn.daxpay.single.service.func.AbsPaySyncStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
@@ -64,9 +65,10 @@ public class PaySyncService {
public PaySyncResult sync(PaySyncParam param) {
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizOrderNo())
.orElseThrow(() -> new PayFailureException("支付订单不存在"));
// 钱包支付钱包不需要
// 钱包支付钱包不需要同步
if (PayChannelEnum.WALLET.getCode().equals(payOrder.getChannel())){
throw new PayFailureException("订单没有异步支付方式,不需要同步");
throw new PayFailureException("支付订单不需要同步");
}
// 执行订单同步逻辑
return this.syncPayOrder(payOrder);
@@ -84,10 +86,9 @@ public class PaySyncService {
if (Objects.isNull(lock)){
throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
}
try {
// 获取支付同步策略类
AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(payOrder.getChannel());
AbsPaySyncStrategy syncPayStrategy = PayStrategyFactory.create(payOrder.getChannel(), AbsPaySyncStrategy.class);
syncPayStrategy.initPayParam(payOrder);
// 执行操作, 获取支付网关同步的结果
PayRemoteSyncResult payRemoteSyncResult = syncPayStrategy.doSyncStatus();
@@ -168,12 +169,9 @@ public class PaySyncService {
return true;
}
// 退款比对状态不做额外处理, 需要通过退款接口进行处理
List<String> orderClose = Arrays.asList(
PayStatusEnum.REFUNDED.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.PARTIAL_REFUND.getCode());
if (orderClose.contains(orderStatus) || syncStatus.equals(PaySyncStatusEnum.REFUND)){
// 退款状态不做额外处理, 需要通过退款接口进行处理
if (!Objects.equals(order.getRefundStatus(),PayOrderRefundStatusEnum.NO_REFUND.getCode())
|| syncStatus.equals(PaySyncStatusEnum.REFUND)){
return true;
}
return false;
@@ -248,4 +246,5 @@ public class PaySyncService {
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
paySyncRecordService.saveRecord(paySyncRecord);
}
}

View File

@@ -5,6 +5,7 @@ import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.daxpay.single.code.RefundStatusEnum;
import cn.daxpay.single.code.RefundSyncStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.param.payment.refund.RefundSyncParam;
import cn.daxpay.single.result.sync.RefundSyncResult;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
@@ -17,15 +18,17 @@ import cn.daxpay.single.service.core.order.refund.entity.RefundOrder;
import cn.daxpay.single.service.core.order.refund.service.RefundOrderQueryService;
import cn.daxpay.single.service.core.payment.repair.result.RefundRepairResult;
import cn.daxpay.single.service.core.payment.repair.service.RefundRepairService;
import cn.daxpay.single.service.core.payment.sync.factory.RefundSyncStrategyFactory;
import cn.daxpay.single.service.core.payment.sync.result.RefundRemoteSyncResult;
import cn.daxpay.single.service.core.record.sync.entity.PaySyncRecord;
import cn.daxpay.single.service.core.record.sync.service.PaySyncRecordService;
import cn.daxpay.single.service.func.AbsRefundSyncStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -78,7 +81,7 @@ public class RefundSyncService {
}
try {
// 获取支付同步策略类
AbsRefundSyncStrategy syncPayStrategy = RefundSyncStrategyFactory.create(refundOrder.getChannel());
AbsRefundSyncStrategy syncPayStrategy = PayStrategyFactory.create(refundOrder.getChannel(),AbsRefundSyncStrategy.class);
syncPayStrategy.setRefundOrder(refundOrder);
// 同步前处理, 主要预防请求过于迅速
syncPayStrategy.doBeforeHandler();
@@ -203,4 +206,5 @@ public class RefundSyncService {
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
paySyncRecordService.saveRecord(paySyncRecord);
}
}

View File

@@ -30,9 +30,9 @@ public class AliRefundSyncStrategy extends AbsRefundSyncStrategy {
/**
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -43,7 +43,7 @@ public class UnionRefundSyncStrategy extends AbsRefundSyncStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
}

View File

@@ -28,8 +28,8 @@ public class WeChatRefundSyncStrategy extends AbsRefundSyncStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -30,9 +30,9 @@ public class AliPaySyncStrategy extends AbsPaySyncStrategy {
/**
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -44,7 +44,7 @@ public class UnionPaySyncStrategy extends AbsPaySyncStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.UNION_PAY;
public String getChannel() {
return PayChannelEnum.UNION_PAY.getCode();
}
}

View File

@@ -32,8 +32,8 @@ public class WeChatPaySyncStrategy extends AbsPaySyncStrategy {
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.WECHAT;
public String getChannel() {
return PayChannelEnum.WECHAT.getCode();
}
/**

View File

@@ -32,9 +32,9 @@ public class AliPayTransferStrategy extends AbsTransferStrategy {
/**
* 策略标识
*/
@Override
public PayChannelEnum getChannel() {
return PayChannelEnum.ALI;
@Override
public String getChannel() {
return PayChannelEnum.ALI.getCode();
}
/**

View File

@@ -1,7 +1,5 @@
package cn.daxpay.single.service.func;
import cn.daxpay.single.code.PayChannelEnum;
/**
* 支付相关策略标识接口
* @author xxm
@@ -11,6 +9,7 @@ public interface PayStrategy {
/**
* 策略标识
* @see cn.daxpay.single.param.payment.pay.PayCancelParam
*/
PayChannelEnum getChannel();
String getChannel();
}

View File

@@ -0,0 +1,31 @@
package cn.daxpay.single.service.util;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.service.func.PayStrategy;
import cn.hutool.extra.spring.SpringUtil;
import lombok.experimental.UtilityClass;
import lombok.val;
/**
* 策略工厂工具类
* @author xxm
* @since 2024/6/7
*/
@UtilityClass
public class PayStrategyFactory {
/**
* 获取策略
* @param channel 通道编码
* @param clazz 策略类型
* @return 策略类
* @param <T> 需要为 PayStrategy 的子类
*/
public <T extends PayStrategy> T create(String channel, Class<T> clazz) {
val beansOfType = SpringUtil.getBeansOfType(clazz);
return beansOfType.values().stream()
.filter(strategy -> strategy.getChannel().equals(channel))
.findFirst()
.orElseThrow(PayUnsupportedMethodException::new);
}
}