From 730876021e4c8afe88cae0b1fcb34269ff314ae4 Mon Sep 17 00:00:00 2001 From: xxm1995 Date: Thu, 21 Mar 2024 23:23:21 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E6=94=AF=E4=BB=98=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=85=88=E8=90=BD=E5=BA=93,=20=E5=90=8E?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/controller/TestController.java | 10 + .../alipay/service/AliPayTransferService.java | 40 ++++ .../convert/TransferOrderConvert.java | 15 ++ .../transfer/dao/TransferOrderManager.java | 18 ++ .../transfer/dao/TransferOrderMapper.java | 14 ++ .../order/transfer/entity/TransferOrder.java | 49 +++++ .../service/TransferOrderService.java | 16 ++ .../payment/pay/result/StrategyAndOrder.java | 25 +++ .../core/payment/pay/service/PayService.java | 203 ++++++++++++++---- .../payment/pay/strategy/AliPayStrategy.java | 1 + .../pay/strategy/UnionPayStrategy.java | 1 + .../pay/strategy/WeChatPayStrategy.java | 4 +- .../transfer/factory/TransferFactory.java | 12 ++ .../transfer/service/TransferService.java | 16 ++ .../strategy/AliPayTransferStrategy.java | 49 +++++ .../daxpay/service/func/AbsPayStrategy.java | 3 +- .../service/func/AbsTransferStrategy.java | 23 ++ daxpay-single/daxpay-single-start/pom.xml | 6 + 18 files changed, 456 insertions(+), 49 deletions(-) create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/service/AliPayTransferService.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/convert/TransferOrderConvert.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderManager.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderMapper.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/entity/TransferOrder.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/service/TransferOrderService.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/result/StrategyAndOrder.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/factory/TransferFactory.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/service/TransferService.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/strategy/AliPayTransferStrategy.java create mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsTransferStrategy.java diff --git a/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/TestController.java b/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/TestController.java index beafec15d..e0d729113 100644 --- a/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/TestController.java +++ b/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/TestController.java @@ -4,6 +4,7 @@ import cn.bootx.platform.common.core.annotation.IgnoreAuth; import cn.bootx.platform.common.core.exception.BizException; import cn.bootx.platform.common.core.rest.Res; import cn.bootx.platform.common.core.rest.ResResult; +import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayTransferService; import cn.hutool.core.thread.ThreadUtil; import com.baomidou.lock.LockInfo; import com.baomidou.lock.LockTemplate; @@ -27,6 +28,7 @@ import java.util.Objects; @RequiredArgsConstructor public class TestController { private final LockTemplate lockTemplate; + private final AliPayTransferService aliPayTransferService; @Operation(summary = "锁测试1") @GetMapping("/lock1") @@ -54,7 +56,15 @@ public class TestController { @Operation(summary = "微信回调测试") @GetMapping(value = {"/wxcs/","wxcs"}) public String wxcs(){ + return "ok"; + } + @IgnoreAuth + @Operation(summary = "支付宝回调测试") + @GetMapping("/queryAmount") + public String alipay(){ + + aliPayTransferService.queryAccountAmount(); return "ok"; } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/service/AliPayTransferService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/service/AliPayTransferService.java new file mode 100644 index 000000000..8f993f4dd --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/service/AliPayTransferService.java @@ -0,0 +1,40 @@ +package cn.bootx.platform.daxpay.service.core.channel.alipay.service; + +import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig; +import com.alipay.api.domain.AlipayFundAccountQueryModel; +import com.alipay.api.response.AlipayFundAccountQueryResponse; +import com.ijpay.alipay.AliPayApi; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AliPayTransferService { + + private final AliPayConfigService payConfigService; + /** + * 余额查询接口 + */ + @SneakyThrows + public void queryAccountAmount() { + + AliPayConfig config = payConfigService.getAndCheckConfig(); + payConfigService.initConfig(config); + AlipayFundAccountQueryModel model = new AlipayFundAccountQueryModel(); + model.setAccountType("ACCTRANS_ACCOUNT"); + model.setAlipayUserId(config.getAppId()); + AlipayFundAccountQueryResponse response = AliPayApi.accountQueryToResponse(model, null); + System.out.println(response); + } + + /** + * 转账接口 + */ + @SneakyThrows + public void transfer() { + + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/convert/TransferOrderConvert.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/convert/TransferOrderConvert.java new file mode 100644 index 000000000..6881544ee --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/convert/TransferOrderConvert.java @@ -0,0 +1,15 @@ +package cn.bootx.platform.daxpay.service.core.order.transfer.convert; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * + * @author xxm + * @since 2024/3/21 + */ +@Mapper +public interface TransferOrderConvert { + TransferOrderConvert CONVERT = Mappers.getMapper(TransferOrderConvert.class); + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderManager.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderManager.java new file mode 100644 index 000000000..7d0e3cfae --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderManager.java @@ -0,0 +1,18 @@ +package cn.bootx.platform.daxpay.service.core.order.transfer.dao; + +import cn.bootx.platform.common.mybatisplus.impl.BaseManager; +import cn.bootx.platform.daxpay.service.core.order.transfer.entity.TransferOrder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +/** + * + * @author xxm + * @since 2024/3/21 + */ +@Slf4j +@Repository +@RequiredArgsConstructor +public class TransferOrderManager extends BaseManager { +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderMapper.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderMapper.java new file mode 100644 index 000000000..01f37d647 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/dao/TransferOrderMapper.java @@ -0,0 +1,14 @@ +package cn.bootx.platform.daxpay.service.core.order.transfer.dao; + +import cn.bootx.platform.daxpay.service.core.order.transfer.entity.TransferOrder; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * + * @author xxm + * @since 2024/3/21 + */ +@Mapper +public interface TransferOrderMapper extends BaseMapper { +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/entity/TransferOrder.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/entity/TransferOrder.java new file mode 100644 index 000000000..46ac8e0d1 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/entity/TransferOrder.java @@ -0,0 +1,49 @@ +package cn.bootx.platform.daxpay.service.core.order.transfer.entity; + +import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity; +import cn.bootx.platform.daxpay.code.PayChannelEnum; +import cn.bootx.table.modify.annotation.DbTable; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 转账订单 + * @author xxm + * @since 2024/3/21 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +@DbTable(comment = "转账订单") +@TableName("pay_transfer_order") +public class TransferOrder extends MpBaseEntity { + + /** 业务号 */ + private String outTradeNo; + + /** + * 支付通道 + * @see PayChannelEnum + */ + private String channel; + + /** 金额 */ + private Integer amount; + + /** 状态 */ + private String status; + + /** 付款方 */ + private String payer; + + /** 收款方 */ + private String payee; + + /** 成功时间 */ + private LocalDateTime successTime; + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/service/TransferOrderService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/service/TransferOrderService.java new file mode 100644 index 000000000..3782061c3 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/transfer/service/TransferOrderService.java @@ -0,0 +1,16 @@ +package cn.bootx.platform.daxpay.service.core.order.transfer.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 转正订单服务 + * @author xxm + * @since 2024/3/21 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TransferOrderService { +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/result/StrategyAndOrder.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/result/StrategyAndOrder.java new file mode 100644 index 000000000..c41cdfa3e --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/result/StrategyAndOrder.java @@ -0,0 +1,25 @@ +package cn.bootx.platform.daxpay.service.core.payment.pay.result; + +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; +import cn.bootx.platform.daxpay.service.func.AbsPayStrategy; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +/** + * 策略和订单 + * @author xxm + * @since 2024/3/21 + */ +@Getter +@AllArgsConstructor +public class StrategyAndOrder { + + /** 支付订单 */ + private final PayOrder order; + + /** 支付策略集合 */ + private final List strategies; + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java index 0444faab1..e28b13ec4 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java @@ -1,6 +1,7 @@ package cn.bootx.platform.daxpay.service.core.payment.pay.service; import cn.bootx.platform.common.core.exception.RepetitiveOperationException; +import cn.bootx.platform.common.core.function.CollectorsFunction; import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException; import cn.bootx.platform.daxpay.param.pay.PayChannelParam; import cn.bootx.platform.daxpay.param.pay.PayParam; @@ -9,6 +10,8 @@ import cn.bootx.platform.daxpay.result.pay.PayResult; import cn.bootx.platform.daxpay.service.common.context.PayLocal; import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; 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.order.pay.entity.PayOrder; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra; import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService; @@ -19,20 +22,24 @@ import cn.bootx.platform.daxpay.util.PayUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.collection.CollectionUtil; +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 org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; -import static cn.bootx.platform.daxpay.code.PayStatusEnum.*; +import static cn.bootx.platform.daxpay.code.PayStatusEnum.SUCCESS; /** @@ -50,6 +57,8 @@ public class PayService { private final PayAssistService payAssistService; + private final PayChannelOrderManager channelOrderManager; + private final ClientNoticeService clientNoticeService; private final LockTemplate lockTemplate; @@ -62,6 +71,8 @@ public class PayService { * 注意: * 组合支付在非第一次支付的时候,只对新传入的异步支付通道进行处理,该通道的价格使用第一次发起的价格,旧的同步支付如果传入后也不做处理, * 支付单中支付通道列表将会为 旧有的同步支付+新传入的异步支付方式(在具体支付实现中处理) + * + * 订单数据会先进行入库, 才会进行发起支付, 在调用各通道支付之前发生错误, 数据不会入库 */ @Transactional(rollbackFor = Exception.class) public PayResult pay(PayParam payParam) { @@ -81,18 +92,38 @@ public class PayService { // 初始化上下文 payAssistService.initPayContext(payOrder, payParam); - // 异步支付且非第一次支付 - if (Objects.nonNull(payOrder) && payOrder.isAsyncPay()) { - return this.paySyncNotFirst(payParam, payOrder); + // 订单为空, 创建支付订单和通道支付订单 + if (Objects.isNull(payOrder)){ + // 预支付处理, 无论请求成功还是失败, 各种订单对象都会保存 + List strategies = SpringUtil.getBean(this.getClass()).prePay(payParam); + // 执行首次支付逻辑 + return this.onePay(strategies); } else { - // 第一次发起支付或同步支付 - return this.firstPay(payParam, payOrder); + // 分为同步通道全部支付成功和所有支付都是支付中状态(上次支付失败) + return this.towPay(payParam, payOrder); } } finally { lockTemplate.releaseLock(lock); } } + /** + * 组合支付分为同步通道全部支付成功和所有支付都是支付中状态(上次支付失败) + * 单通道支付不需要区分上次支付发起是否成功 + */ + private PayResult towPay(PayParam payParam, PayOrder payOrder) { + // 判断是否组合支付且同时包含异步支付 + if (payOrder.isCombinationPay()&&payOrder.isAsyncPay()) { + // 同步支付通道全部支付成功, 单独走异步支付支付流程 + this.onlyAsyncPay(payParam, payOrder); + // 通道订单全部支付中, 相当于上次支付异常, 重新走支付流程 + return this.allPay(payParam, payOrder); + } else { + // 单通道支付走标准支付流程 + return this.allPay(payParam, payOrder); + } + } + /** * 简单下单, 可以视为不支持组合支付的下单接口 */ @@ -111,14 +142,46 @@ public class PayService { return this.pay(payParam); } + + /** + * 预支付处理, 无论请求成功还是失败, 各种订单对象都会保存 + * 1. 校验参数 + * 2. 创建支付订单/通道支付订单/扩展信息 + * 3, 返回数据 + */ + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) + public List prePay(PayParam payParam){ + + // 价格检测 + PayUtil.validationAmount(payParam.getPayChannels()); + + // 创建支付订单和扩展记录并返回支付订单对象 + PayOrder payOrder = payAssistService.createPayOrder(payParam); + + // 获取支付方式,通过工厂生成对应的策略组 + List strategies = PayStrategyFactory.createAsyncLast(payParam.getPayChannels()); + if (CollectionUtil.isEmpty(strategies)) { + throw new PayUnsupportedMethodException(); + } + // 初始化支付的参数 + for (AbsPayStrategy strategy : strategies) { + strategy.initPayParam(payOrder, payParam); + } + + // 执行支付前处理动作 + strategies.forEach(AbsPayStrategy::doBeforePayHandler); + // 执行通道支付通道订单的生成 + strategies.forEach(AbsPayStrategy::generateChannelOrder); + + // 保存通道支付订单 + payAssistService.savePayChannelOrder(strategies); + return strategies; + } + /** * 发起的第一次支付请求(同步/异步) */ private PayResult firstPay(PayParam payParam, PayOrder payOrder) { - // 1. 已经发起过支付情况直接返回支付结果 - if (Objects.nonNull(payOrder)) { - return PayBuilder.buildPayResultByPayOrder(payOrder); - } // 2. 价格检测 PayUtil.validationAmount(payParam.getPayChannels()); @@ -127,48 +190,40 @@ public class PayService { payOrder = payAssistService.createPayOrder(payParam); // 4. 调用支付方法进行发起支付 - this.firstPayHandler(payParam, payOrder); + this.allPay(payParam, payOrder); // 5. 返回支付结果 return PayBuilder.buildPayResultByPayOrder(payOrder); } + /** - * 执行第一次发起支付的方法 + * 执行首次支付操作 */ - private void firstPayHandler(PayParam payParam, PayOrder payOrder) { - - // 1.获取支付方式,通过工厂生成对应的策略组 - List strategies = PayStrategyFactory.createAsyncLast(payParam.getPayChannels()); - if (CollectionUtil.isEmpty(strategies)) { - throw new PayUnsupportedMethodException(); + public PayResult onePay(List strategies){ + PayLocal payInfo = PaymentContextLocal.get().getPayInfo(); + // 支付操作 + try { + strategies.forEach(AbsPayStrategy::doPayHandler); + } catch (Exception e) { + // 记录错误原因 + PayOrderExtra payOrderExtra = payInfo.getPayOrderExtra(); + payOrderExtra.setErrorMsg(e.getMessage()); + throw e; } + PayOrder payOrder = payInfo.getPayOrder(); - // 2.初始化支付的参数 - for (AbsPayStrategy strategy : strategies) { - strategy.initPayParam(payOrder, payParam); - } - - // 3.1 执行支付前处理动作 - strategies.forEach(AbsPayStrategy::doBeforePayHandler); - // 3.2 执行通道支付单的生成动作 - strategies.forEach(AbsPayStrategy::generateChannelOrder); - - // 4.1 支付操作 - strategies.forEach(AbsPayStrategy::doPayHandler); - // 4.2 支付调用成功操作, 进行扣款、创建记录类类似的操作 + // 支付调用成功操作, 进行扣款、创建记录类类似的操作 strategies.forEach(AbsPayStrategy::doSuccessHandler); - // 4.3 保存通道支付订单 - payAssistService.savePayChannelOrder(strategies); - // 5.1 如果没有异步支付, 直接进行订单完成处理 - if (PayUtil.isNotSync(payParam.getPayChannels())) { + // 如果没有异步支付, 直接进行订单完成处理 + if (!payOrder.isAsyncPay()) { // 修改支付订单状态为成功 payOrder.setStatus(SUCCESS.getCode()) .setPayTime(LocalDateTime.now()); payOrderService.updateById(payOrder); } - // 5.2 如果异步支付完成, 进行订单完成处理, 同时发送回调消息 + // 如果异步支付完成, 进行订单完成处理, 同时发送回调消息 PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo(); if (asyncPayInfo.isPayComplete()) { payOrder.setGatewayOrderNo(asyncPayInfo.getGatewayOrderNo()) @@ -179,22 +234,78 @@ public class PayService { // 如果支付完成 发送通知 if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){ - PayLocal payInfo = PaymentContextLocal.get().getPayInfo(); clientNoticeService.registerPayNotice(payOrder, payInfo.getPayOrderExtra(), payInfo.getPayChannelOrders()); } + // 组装返回参数 + return PayBuilder.buildPayResultByPayOrder(payOrder); + } + + + /** + * 执行所有的支付方法 + */ + private PayResult allPay(PayParam payParam, PayOrder payOrder) { + PayLocal payInfo = PaymentContextLocal.get().getPayInfo(); + + // 获取支付方式,通过工厂生成对应的策略组 + List strategies = PayStrategyFactory.createAsyncLast(payParam.getPayChannels()); + if (CollectionUtil.isEmpty(strategies)) { + throw new PayUnsupportedMethodException(); + } + // 查询通道支付订单 + List orders = channelOrderManager.findAllByPaymentId(payOrder.getId()); + Map channelOrderMap = orders.stream() + .collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainFirst)); + + // 初始化支付参数 + for (AbsPayStrategy strategy : strategies) { + strategy.initPayParam(payOrder, payParam); + strategy.setChannelOrder(channelOrderMap.get(strategy.getChannel().getCode())); + } + + // 执行支付前处理动作 + strategies.forEach(AbsPayStrategy::doBeforePayHandler); + // 支付操作 + + try { + strategies.forEach(AbsPayStrategy::doPayHandler); + } catch (Exception e) { + // 记录错误原因 + PayOrderExtra payOrderExtra = payInfo.getPayOrderExtra(); + payOrderExtra.setErrorMsg(e.getMessage()); + throw e; + } + + // 支付调用成功操作, 进行扣款、创建记录类类似的操作 + strategies.forEach(AbsPayStrategy::doSuccessHandler); + + // 如果没有异步支付, 直接进行订单完成处理 + if (PayUtil.isNotSync(payParam.getPayChannels())) { + // 修改支付订单状态为成功 + payOrder.setStatus(SUCCESS.getCode()) + .setPayTime(LocalDateTime.now()); + payOrderService.updateById(payOrder); + } + // 如果异步支付完成, 进行订单完成处理, 同时发送回调消息 + PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo(); + if (asyncPayInfo.isPayComplete()) { + payOrder.setGatewayOrderNo(asyncPayInfo.getGatewayOrderNo()) + .setStatus(SUCCESS.getCode()) + .setPayTime(LocalDateTime.now()); + payOrderService.updateById(payOrder); + } + + // 如果支付完成 发送通知 + if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){ + clientNoticeService.registerPayNotice(payOrder, payInfo.getPayOrderExtra(), payInfo.getPayChannelOrders()); + } + return PayBuilder.buildPayResultByPayOrder(payOrder); } /** * 异步支付执行(非第一次请求), 只执行异步支付策略, 因为同步支付已经支付成功. 报错不影响继续发起支付 */ - private PayResult paySyncNotFirst(PayParam payParam, PayOrder payOrder) { - - // 1. 处理支付结束情况(完成/退款/关闭/错误) - List 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); - } + private PayResult onlyAsyncPay(PayParam payParam, PayOrder payOrder) { // 2.获取 异步支付通道,通过工厂生成对应的策略组(只包含异步支付的策略, 同步支付已经成功不再继续执行) PayChannelParam payChannelParam = payAssistService.getAsyncPayParam(payParam, payOrder); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java index deff9371c..04b637078 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java @@ -95,6 +95,7 @@ public class AliPayStrategy extends AbsPayStrategy { */ @Override public void generateChannelOrder() { + super.generateChannelOrder(); } /** diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java index 3f8de3bc2..43ec5fb81 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java @@ -98,6 +98,7 @@ public class UnionPayStrategy extends AbsPayStrategy { */ @Override public void generateChannelOrder() { + super.generateChannelOrder(); } /** diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java index cc26fa251..0df77c4d5 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java @@ -104,7 +104,9 @@ public class WeChatPayStrategy extends AbsPayStrategy { * 不使用默认的生成通道支付单方法, 异步支付通道的支付订单自己管理 */ @Override - public void generateChannelOrder() {} + public void generateChannelOrder() { + super.generateChannelOrder(); + } /** * 初始化微信支付 diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/factory/TransferFactory.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/factory/TransferFactory.java new file mode 100644 index 000000000..5fb890c8b --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/factory/TransferFactory.java @@ -0,0 +1,12 @@ +package cn.bootx.platform.daxpay.service.core.payment.transfer.factory; + +import lombok.experimental.UtilityClass; + +/** + * 转账工具类 + * @author xxm + * @since 2024/3/21 + */ +@UtilityClass +public class TransferFactory { +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/service/TransferService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/service/TransferService.java new file mode 100644 index 000000000..38511f009 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/service/TransferService.java @@ -0,0 +1,16 @@ +package cn.bootx.platform.daxpay.service.core.payment.transfer.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 转账服务 + * @author xxm + * @since 2024/3/21 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TransferService { +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/strategy/AliPayTransferStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/strategy/AliPayTransferStrategy.java new file mode 100644 index 000000000..ae95d5a7b --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/transfer/strategy/AliPayTransferStrategy.java @@ -0,0 +1,49 @@ +package cn.bootx.platform.daxpay.service.core.payment.transfer.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.AliPayConfigService; +import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayTransferService; +import cn.bootx.platform.daxpay.service.func.AbsTransferStrategy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +/** + * 支付宝转账测策略 + * @author xxm + * @since 2024/3/21 + */ +@Slf4j +@Service +@Scope(SCOPE_PROTOTYPE) +@RequiredArgsConstructor +public class AliPayTransferStrategy extends AbsTransferStrategy { + + private final AliPayConfigService payConfigService; + + private final AliPayTransferService aliPayTransferService; + + private AliPayConfig config; + + /** + * 策略标识 + */ + @Override + public PayChannelEnum getChannel() { + return PayChannelEnum.ALI; + } + + /** + * 转账前操作 + */ + @Override + public void doBeforeHandler() { + this.config = payConfigService.getAndCheckConfig(); + payConfigService.initConfig(this.config); + } + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsPayStrategy.java index a5e5fc080..a0b485408 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsPayStrategy.java @@ -58,8 +58,7 @@ public abstract class AbsPayStrategy implements PayStrategy{ * 支付调起成功的处理方式 */ public void doSuccessHandler() { - this.channelOrder.setStatus(PayStatusEnum.SUCCESS.getCode()) - .setPayTime(LocalDateTime.now()); + this.channelOrder.setStatus(PayStatusEnum.SUCCESS.getCode()).setPayTime(LocalDateTime.now()); } /** diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsTransferStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsTransferStrategy.java new file mode 100644 index 000000000..74b2238fd --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/func/AbsTransferStrategy.java @@ -0,0 +1,23 @@ +package cn.bootx.platform.daxpay.service.func; + +import cn.bootx.platform.daxpay.service.core.order.transfer.entity.TransferOrder; +import lombok.Getter; +import lombok.Setter; + +/** + * 转账抽象策略 + * @author xxm + * @since 2024/3/21 + */ +@Getter +@Setter +public abstract class AbsTransferStrategy implements PayStrategy{ + /** 转账订单 */ + private TransferOrder transferOrder; + + /** + * 转账前操作 + */ + public void doBeforeHandler(){} + +} diff --git a/daxpay-single/daxpay-single-start/pom.xml b/daxpay-single/daxpay-single-start/pom.xml index c3d65fc37..bb0ad7270 100644 --- a/daxpay-single/daxpay-single-start/pom.xml +++ b/daxpay-single/daxpay-single-start/pom.xml @@ -40,6 +40,12 @@ daxpay-single-demo ${daxpay.version} + + cn.afterturn + easypoi-spring-boot-starter + 4.4.0 + +