From 181993c4d31499c03af0824a934a4b356e12cb70 Mon Sep 17 00:00:00 2001 From: bootx Date: Mon, 9 Dec 2024 22:34:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E5=AE=9D=E5=88=86=E8=B4=A6=E5=92=8C=E5=BE=AE=E4=BF=A1=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AliPayConfigController.java | 4 +- ...gConvert.java => AliPayConfigConvert.java} | 8 +- .../alipay/entity/config/AliPayConfig.java | 12 +- .../{AlipayParam.java => AliPayParam.java} | 2 +- ...figResult.java => AliPayConfigResult.java} | 2 +- .../allocation/AliPayAllocationService.java | 178 ++++++++++++++++++ .../service/config/AliPayConfigService.java | 8 +- .../alipay/service/pay/AliPayService.java | 8 +- .../strategy/AliAllocationStrategy.java | 46 +++++ ...tegy.java => AliPayReconcileStrategy.java} | 2 +- .../alipay/strategy/AliPayStrategy.java | 8 +- .../WeChatPayAllocationV2Service.java | 16 ++ .../WeChatPayAllocationV3Service.java | 106 +++++++++++ .../WechatPayAllocReceiverV2Service.java | 2 +- .../WechatPayAllocReceiverV3Service.java | 2 +- .../strategy/WechatAllocReceiverStrategy.java | 4 +- .../strategy/WechatAllocationStrategy.java | 49 +++++ .../bo/allocation/AllocStartResultBo.java | 6 + .../strategy/AbsAllocationStrategy.java | 12 +- 19 files changed, 439 insertions(+), 36 deletions(-) rename daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/{AlipayConfigConvert.java => AliPayConfigConvert.java} (67%) rename daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/{AlipayParam.java => AliPayParam.java} (97%) rename daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/{AlipayConfigResult.java => AliPayConfigResult.java} (98%) create mode 100644 daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/allocation/AliPayAllocationService.java create mode 100644 daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliAllocationStrategy.java rename daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/{AlipayReconcileStrategy.java => AliPayReconcileStrategy.java} (96%) create mode 100644 daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV2Service.java create mode 100644 daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV3Service.java rename daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/{ => receiver}/WechatPayAllocReceiverV2Service.java (98%) rename daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/{ => receiver}/WechatPayAllocReceiverV3Service.java (98%) create mode 100644 daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocationStrategy.java diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/controller/AliPayConfigController.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/controller/AliPayConfigController.java index 450ab25c..8c29fc29 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/controller/AliPayConfigController.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/controller/AliPayConfigController.java @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.dromara.daxpay.channel.alipay.param.config.AliPayConfigParam; -import org.dromara.daxpay.channel.alipay.result.config.AlipayConfigResult; +import org.dromara.daxpay.channel.alipay.result.config.AliPayConfigResult; import org.dromara.daxpay.channel.alipay.service.config.AliPayConfigService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -31,7 +31,7 @@ public class AliPayConfigController { @RequestPath("获取配置") @Operation(summary = "获取配置") @GetMapping("/findById") - public Result findById(@NotNull(message = "ID不可为空") Long id) { + public Result findById(@NotNull(message = "ID不可为空") Long id) { return Res.ok(alipayConfigService.findById(id)); } diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AlipayConfigConvert.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AliPayConfigConvert.java similarity index 67% rename from daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AlipayConfigConvert.java rename to daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AliPayConfigConvert.java index 4570571a..1393554e 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AlipayConfigConvert.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/convert/config/AliPayConfigConvert.java @@ -2,7 +2,7 @@ package org.dromara.daxpay.channel.alipay.convert.config; import org.dromara.daxpay.channel.alipay.entity.config.AliPayConfig; import org.dromara.daxpay.channel.alipay.param.config.AliPayConfigParam; -import org.dromara.daxpay.channel.alipay.result.config.AlipayConfigResult; +import org.dromara.daxpay.channel.alipay.result.config.AliPayConfigResult; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -12,10 +12,10 @@ import org.mapstruct.factory.Mappers; * @since 2024/6/25 */ @Mapper -public interface AlipayConfigConvert { - AlipayConfigConvert CONVERT = Mappers.getMapper(AlipayConfigConvert.class); +public interface AliPayConfigConvert { + AliPayConfigConvert CONVERT = Mappers.getMapper(AliPayConfigConvert.class); - AlipayConfigResult toResult(AliPayConfig in); + AliPayConfigResult toResult(AliPayConfig in); AliPayConfig copy(AliPayConfig in); diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/entity/config/AliPayConfig.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/entity/config/AliPayConfig.java index 0a4a45fd..49547766 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/entity/config/AliPayConfig.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/entity/config/AliPayConfig.java @@ -3,8 +3,8 @@ package org.dromara.daxpay.channel.alipay.entity.config; import cn.bootx.platform.common.mybatisplus.function.ToResult; import cn.bootx.platform.core.util.JsonUtil; import org.dromara.daxpay.channel.alipay.code.AliPayCode; -import org.dromara.daxpay.channel.alipay.convert.config.AlipayConfigConvert; -import org.dromara.daxpay.channel.alipay.result.config.AlipayConfigResult; +import org.dromara.daxpay.channel.alipay.convert.config.AliPayConfigConvert; +import org.dromara.daxpay.channel.alipay.result.config.AliPayConfigResult; import org.dromara.daxpay.core.enums.ChannelEnum; import org.dromara.daxpay.service.entity.config.ChannelConfig; import lombok.Data; @@ -19,7 +19,7 @@ import java.math.BigDecimal; */ @Data @Accessors(chain = true) -public class AliPayConfig implements ToResult { +public class AliPayConfig implements ToResult { /** 主键 */ private Long id; @@ -78,7 +78,7 @@ public class AliPayConfig implements ToResult { channelConfig.setAppId(this.getAppId()); channelConfig.setEnable(this.getEnable()); channelConfig.setChannel(ChannelEnum.ALI.getCode()); - AliPayConfig copy = AlipayConfigConvert.CONVERT.copy(this); + AliPayConfig copy = AliPayConfigConvert.CONVERT.copy(this); // 清空不需要序列化的字段 copy.setId(null).setAppId(null).setEnable(null).setAliAppId(null).setAppId(null); String jsonStr = JsonUtil.toJsonStr(copy); @@ -99,7 +99,7 @@ public class AliPayConfig implements ToResult { } @Override - public AlipayConfigResult toResult() { - return AlipayConfigConvert.CONVERT.toResult(this); + public AliPayConfigResult toResult() { + return AliPayConfigConvert.CONVERT.toResult(this); } } diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AlipayParam.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AliPayParam.java similarity index 97% rename from daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AlipayParam.java rename to daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AliPayParam.java index 1f6c1c25..671c42e1 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AlipayParam.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/param/pay/AliPayParam.java @@ -10,7 +10,7 @@ import lombok.Data; */ @Data @Schema(title = "支付宝支付参数") -public class AlipayParam { +public class AliPayParam { /** * 授权码(主动扫描用户的付款码) */ diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AlipayConfigResult.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AliPayConfigResult.java similarity index 98% rename from daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AlipayConfigResult.java rename to daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AliPayConfigResult.java index ed407017..4622c940 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AlipayConfigResult.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/result/config/AliPayConfigResult.java @@ -16,7 +16,7 @@ import java.math.BigDecimal; @Data @Accessors(chain = true) @Schema(title = "支付宝配置") -public class AlipayConfigResult { +public class AliPayConfigResult { /** 主键 */ @Schema(description = "主键") diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/allocation/AliPayAllocationService.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/allocation/AliPayAllocationService.java new file mode 100644 index 00000000..bf53d56e --- /dev/null +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/allocation/AliPayAllocationService.java @@ -0,0 +1,178 @@ +package org.dromara.daxpay.channel.alipay.service.allocation; + +import cn.bootx.platform.common.mybatisplus.base.MpIdEntity; +import cn.hutool.core.util.StrUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayResponse; +import com.alipay.api.domain.AlipayTradeOrderSettleModel; +import com.alipay.api.domain.OpenApiRoyaltyDetailInfoPojo; +import com.alipay.api.domain.SettleExtendParams; +import com.alipay.api.request.AlipayTradeOrderSettleRequest; +import com.alipay.api.response.AlipayTradeOrderSettleResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.daxpay.channel.alipay.code.AliPayCode; +import org.dromara.daxpay.channel.alipay.service.config.AliPayConfigService; +import org.dromara.daxpay.core.enums.AllocDetailResultEnum; +import org.dromara.daxpay.core.exception.TradeFailException; +import org.dromara.daxpay.core.util.PayUtil; +import org.dromara.daxpay.service.bo.allocation.AllocStartResultBo; +import org.dromara.daxpay.service.entity.allocation.transaction.AllocDetail; +import org.dromara.daxpay.service.entity.allocation.transaction.AllocOrder; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 支付宝分账服务 + * @author xxm + * @since 2024/12/9 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AliPayAllocationService { + private final AliPayConfigService aliPayConfigService; + + /** + * 发起分账 + */ + public AllocStartResultBo start(AllocOrder allocOrder, List orderDetails){ + // 分账主体参数 + AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel(); + model.setOutRequestNo(allocOrder.getAllocNo()); + model.setTradeNo(allocOrder.getOutOrderNo()); + model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC); + + // 分账子参数 根据Id排序 + orderDetails.sort(Comparator.comparing(MpIdEntity::getId)); + List royaltyParameters = orderDetails.stream() + .map(o -> { + OpenApiRoyaltyDetailInfoPojo infoPojo = new OpenApiRoyaltyDetailInfoPojo(); + infoPojo.setAmount(PayUtil.toDecimal(o.getAmount()).toPlainString()); + infoPojo.setTransIn(o.getReceiverAccount()); + return infoPojo; + }) + .collect(Collectors.toList()); + model.setRoyaltyParameters(royaltyParameters); + AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest(); + request.setBizModel(model); + AlipayTradeOrderSettleResponse response = null; + try { + response = aliPayConfigService.execute(request); + this.verifyErrorMsg(response); + } catch (AlipayApiException e) { + log.error("网关返回分账失败: {}", e.getMessage()); + throw new TradeFailException(e.getMessage()); + } + // 需要写入到分账订单中 + String settleNo = response.getSettleNo(); + return new AllocStartResultBo().setOutAllocNo(settleNo); + } + + /** + * 分账完结 + */ + public void finish(AllocOrder allocOrder, List orderDetails){ + // 分账主体参数 + AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel(); + model.setOutRequestNo(String.valueOf(allocOrder.getAllocNo())); + model.setTradeNo(allocOrder.getOutOrderNo()); + model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC); + // 分账完结参数 + SettleExtendParams extendParams = new SettleExtendParams(); + extendParams.setRoyaltyFinish(Boolean.TRUE.toString()); + model.setExtendParams(extendParams); + + // 分账子参数 根据Id排序 + orderDetails.sort(Comparator.comparing(MpIdEntity::getId)); + List royaltyParameters = orderDetails.stream() + .map(o -> { + OpenApiRoyaltyDetailInfoPojo infoPojo = new OpenApiRoyaltyDetailInfoPojo(); + infoPojo.setAmount(PayUtil.toDecimal(o.getAmount()).toPlainString()); + infoPojo.setTransIn(o.getReceiverAccount()); + return infoPojo; + }) + .collect(Collectors.toList()); + model.setRoyaltyParameters(royaltyParameters); + AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest(); + request.setBizModel(model); + AlipayTradeOrderSettleResponse response = null; + try { + response = aliPayConfigService.execute(request); + } catch (AlipayApiException e) { + log.error("网关返回分账失败: {}", e.getMessage()); + throw new TradeFailException(e.getMessage()); + } + this.verifyErrorMsg(response); + } + + /** + * 分账状态同步 + */ +// @SneakyThrows +// public AllocRemoteSyncResult sync(AllocOrder allocOrder, List allocOrderDetails, AliPayConfig config){ +// AlipayClient alipayClient = aliPayConfigService.getAlipayClient(config); +// AlipayTradeOrderSettleQueryModel model = new AlipayTradeOrderSettleQueryModel(); +// model.setTradeNo(allocOrder.getOutOrderNo()); +// model.setOutRequestNo(allocOrder.getAllocNo()); +// AlipayTradeOrderSettleQueryRequest request = new AlipayTradeOrderSettleQueryRequest(); +// request.setBizModel(model); +// AlipayTradeOrderSettleQueryResponse response = alipayClient.execute(request); +// // 验证 +// this.verifyErrorMsg(response); +// Map detailMap = allocOrderDetails.stream() +// .collect(Collectors.toMap(AllocOrderDetail::getReceiverAccount, Function.identity(), CollectorsFunction::retainLatest)); +// List royaltyDetailList = response.getRoyaltyDetailList(); +// for (RoyaltyDetail receiver : royaltyDetailList) { +// AllocOrderDetail detail = detailMap.get(receiver.getTransIn()); +// if (Objects.nonNull(detail)) { +// detail.setResult(this.getDetailResultEnum(receiver.getState()).getCode()); +// detail.setErrorCode(receiver.getErrorCode()); +// detail.setErrorMsg(receiver.getErrorDesc()); +// // 如果是完成, 更新时间 +// if (AllocDetailResultEnum.SUCCESS.getCode().equals(detail.getResult())){ +// LocalDateTime finishTime = LocalDateTimeUtil.of(receiver.getExecuteDt()); +// detail.setFinishTime(finishTime) +// .setErrorMsg(null) +// .setErrorCode(null); +// } +// } +// } +// return new AllocRemoteSyncResult().setSyncInfo(JSONUtil.toJsonStr(response)); +// } + + /** + * 验证错误信息 + */ + private void verifyErrorMsg(AlipayResponse alipayResponse) { + if (alipayResponse.isSuccess()) { + String errorMsg = alipayResponse.getSubMsg(); + if (StrUtil.isBlank(errorMsg)) { + errorMsg = alipayResponse.getMsg(); + } + log.error("分账处理失败 {}", errorMsg); + throw new TradeFailException(errorMsg); + } + } + + /** + * 转换支付宝分账类型到系统中统一的状态 + */ + private AllocDetailResultEnum getDetailResultEnum (String result){ + // 进行中 + if(Objects.equals(AliPayCode.ALLOC_PROCESSING, result)){ + return AllocDetailResultEnum.PENDING; + } + // 成功 + if(Objects.equals(AliPayCode.ALLOC_SUCCESS, result)){ + return AllocDetailResultEnum.SUCCESS; + } + // 失败 + return AllocDetailResultEnum.FAIL; + } + +} diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/config/AliPayConfigService.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/config/AliPayConfigService.java index 98ccca3e..4ff28398 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/config/AliPayConfigService.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/config/AliPayConfigService.java @@ -12,10 +12,10 @@ import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.dromara.daxpay.channel.alipay.code.AliPayCode; -import org.dromara.daxpay.channel.alipay.convert.config.AlipayConfigConvert; +import org.dromara.daxpay.channel.alipay.convert.config.AliPayConfigConvert; import org.dromara.daxpay.channel.alipay.entity.config.AliPayConfig; import org.dromara.daxpay.channel.alipay.param.config.AliPayConfigParam; -import org.dromara.daxpay.channel.alipay.result.config.AlipayConfigResult; +import org.dromara.daxpay.channel.alipay.result.config.AliPayConfigResult; import org.dromara.daxpay.core.enums.ChannelEnum; import org.dromara.daxpay.core.exception.ChannelNotEnableException; import org.dromara.daxpay.core.exception.ConfigNotEnableException; @@ -48,7 +48,7 @@ public class AliPayConfigService { /** * 查询 */ - public AlipayConfigResult findById(Long id) { + public AliPayConfigResult findById(Long id) { return channelConfigManager.findById(id) .map(AliPayConfig::convertConfig) .map(AliPayConfig::toResult) @@ -71,7 +71,7 @@ public class AliPayConfigService { * 添加 */ public void save(AliPayConfigParam param) { - AliPayConfig entity = AlipayConfigConvert.CONVERT.toEntity(param); + AliPayConfig entity = AliPayConfigConvert.CONVERT.toEntity(param); ChannelConfig channelConfig = entity.toChannelConfig(); // 判断商户应用下是否存在该配置 if (channelConfigManager.existsByAppIdAndChannel(channelConfig.getAppId(), channelConfig.getChannel())){ diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/pay/AliPayService.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/pay/AliPayService.java index 62f0c4b0..f254ac26 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/pay/AliPayService.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/service/pay/AliPayService.java @@ -3,7 +3,7 @@ package org.dromara.daxpay.channel.alipay.service.pay; import cn.bootx.platform.core.util.BigDecimalUtil; import org.dromara.daxpay.channel.alipay.code.AliPayCode; import org.dromara.daxpay.channel.alipay.entity.config.AliPayConfig; -import org.dromara.daxpay.channel.alipay.param.pay.AlipayParam; +import org.dromara.daxpay.channel.alipay.param.pay.AliPayParam; import org.dromara.daxpay.channel.alipay.service.config.AliPayConfigService; import org.dromara.daxpay.core.enums.PayMethodEnum; import org.dromara.daxpay.core.exception.AmountExceedLimitException; @@ -57,7 +57,7 @@ public class AliPayService { /** * 调起支付 */ - public PayResultBo pay(PayOrder payOrder, AlipayParam aliPayParam) { + public PayResultBo pay(PayOrder payOrder, AliPayParam aliPayParam) { String amount = PayUtil.toDecimal(payOrder.getAmount()).toString(); String payBody = null; // 异步线程存储 @@ -209,7 +209,7 @@ public class AliPayService { * jsapi支付 */ @SneakyThrows - public String jsapiPay(String amount, PayOrder payOrder, AlipayParam aliPayParam) { + public String jsapiPay(String amount, PayOrder payOrder, AliPayParam aliPayParam) { // 构造请求参数以调用接口 AlipayTradeCreateRequest request = new AlipayTradeCreateRequest(); AlipayTradeCreateModel model = new AlipayTradeCreateModel(); @@ -280,7 +280,7 @@ public class AliPayService { * 付款码支付 */ @SneakyThrows - public void barCode(String amount, PayOrder payOrder, AlipayParam aliPayParam, PayResultBo result) { + public void barCode(String amount, PayOrder payOrder, AliPayParam aliPayParam, PayResultBo result) { AlipayTradePayModel model = new AlipayTradePayModel(); model.setSubject(payOrder.getTitle()); model.setOutTradeNo(payOrder.getOrderNo()); diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliAllocationStrategy.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliAllocationStrategy.java new file mode 100644 index 00000000..9518195b --- /dev/null +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliAllocationStrategy.java @@ -0,0 +1,46 @@ +package org.dromara.daxpay.channel.alipay.strategy; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.daxpay.channel.alipay.service.allocation.AliPayAllocationService; +import org.dromara.daxpay.core.enums.ChannelEnum; +import org.dromara.daxpay.service.bo.allocation.AllocStartResultBo; +import org.dromara.daxpay.service.strategy.AbsAllocationStrategy; +import org.springframework.stereotype.Component; + +/** + * 支付宝分账 + * @author xxm + * @since 2024/12/9 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class AliAllocationStrategy extends AbsAllocationStrategy { + + private final AliPayAllocationService aliPayAllocationService; + + /** + * 分账通道 + */ + @Override + public String getChannel() { + return ChannelEnum.ALI.getCode(); + } + + /** + * 开始分账 + */ + @Override + public AllocStartResultBo start() { + return aliPayAllocationService.start(getOrder(), getDetails()); + } + + /** + * 分账完结 + */ + @Override + public void finish() { + aliPayAllocationService.finish(getOrder(), getDetails()); + } +} diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AlipayReconcileStrategy.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayReconcileStrategy.java similarity index 96% rename from daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AlipayReconcileStrategy.java rename to daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayReconcileStrategy.java index ea1f8371..32b0bed2 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AlipayReconcileStrategy.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayReconcileStrategy.java @@ -25,7 +25,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT @Service @Scope(SCOPE_PROTOTYPE) @RequiredArgsConstructor -public class AlipayReconcileStrategy extends AbsReconcileStrategy { +public class AliPayReconcileStrategy extends AbsReconcileStrategy { private final AliPayReconcileService reconcileService; diff --git a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayStrategy.java b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayStrategy.java index 92ce49fa..4466c697 100644 --- a/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayStrategy.java +++ b/daxpay-single-channel/daxpay-single-alipay/src/main/java/org/dromara/daxpay/channel/alipay/strategy/AliPayStrategy.java @@ -2,7 +2,7 @@ package org.dromara.daxpay.channel.alipay.strategy; import cn.bootx.platform.core.exception.ValidationFailedException; import cn.bootx.platform.core.util.JsonUtil; -import org.dromara.daxpay.channel.alipay.param.pay.AlipayParam; +import org.dromara.daxpay.channel.alipay.param.pay.AliPayParam; import org.dromara.daxpay.channel.alipay.service.pay.AliPayService; import org.dromara.daxpay.core.enums.ChannelEnum; import org.dromara.daxpay.service.bo.trade.PayResultBo; @@ -27,7 +27,7 @@ public class AliPayStrategy extends AbsPayStrategy { private final AliPayService aliPayService; - private AlipayParam aliPayParam; + private AliPayParam aliPayParam; @Override public String getChannel() { @@ -43,10 +43,10 @@ public class AliPayStrategy extends AbsPayStrategy { // 支付宝参数验证 String channelParam = this.getPayParam().getExtraParam(); if (StrUtil.isNotBlank(channelParam)) { - this.aliPayParam = JsonUtil.toBean(channelParam, AlipayParam.class); + this.aliPayParam = JsonUtil.toBean(channelParam, AliPayParam.class); } else { - this.aliPayParam = new AlipayParam(); + this.aliPayParam = new AliPayParam(); } } catch (JSONException e) { diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV2Service.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV2Service.java new file mode 100644 index 00000000..4cce6cb3 --- /dev/null +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV2Service.java @@ -0,0 +1,16 @@ +package org.dromara.daxpay.channel.wechat.service.allocation; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 微信分账V2版本接口 + * @author xxm + * @since 2024/12/9 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class WeChatPayAllocationV2Service { +} diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV3Service.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV3Service.java new file mode 100644 index 00000000..b9a1bbb7 --- /dev/null +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WeChatPayAllocationV3Service.java @@ -0,0 +1,106 @@ +package org.dromara.daxpay.channel.wechat.service.allocation; + +import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingUnfreezeV3Request; +import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request; +import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.ProfitSharingService; +import com.github.binarywang.wxpay.service.WxPayService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.daxpay.channel.wechat.entity.config.WechatPayConfig; +import org.dromara.daxpay.channel.wechat.service.config.WechatPayConfigService; +import org.dromara.daxpay.core.enums.AllocReceiverTypeEnum; +import org.dromara.daxpay.core.exception.ConfigErrorException; +import org.dromara.daxpay.core.exception.OperationFailException; +import org.dromara.daxpay.core.util.PayUtil; +import org.dromara.daxpay.service.bo.allocation.AllocStartResultBo; +import org.dromara.daxpay.service.entity.allocation.transaction.AllocDetail; +import org.dromara.daxpay.service.entity.allocation.transaction.AllocOrder; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static org.dromara.daxpay.core.enums.AllocReceiverTypeEnum.MERCHANT_NO; +import static org.dromara.daxpay.core.enums.AllocReceiverTypeEnum.OPEN_ID; + +/** + * 微信分账V3版本接口 + * @author xxm + * @since 2024/12/9 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class WeChatPayAllocationV3Service { + private final WechatPayConfigService wechatPayConfigService; + + /** + * 发起分账 + */ + public AllocStartResultBo start(AllocOrder allocOrder, List orderDetails, WechatPayConfig config){ + + WxPayService wxPayService = wechatPayConfigService.wxJavaSdk(config); + ProfitSharingService sharingService = wxPayService.getProfitSharingService(); + + ProfitSharingV3Request request = new ProfitSharingV3Request(); + request.setOutOrderNo(allocOrder.getAllocNo()); + request.setTransactionId(allocOrder.getOutOrderNo()); + request.setUnfreezeUnsplit(true); + + // 分账接收方信息 + var receivers = orderDetails.stream() + .map(o -> { + AllocReceiverTypeEnum receiverTypeEnum = AllocReceiverTypeEnum.findByCode(o.getReceiverType()); + String receiverType = this.getReceiverType(receiverTypeEnum); + var receiver = new ProfitSharingV3Request.Receiver(); + receiver.setType(receiverType); + receiver.setAmount(PayUtil.convertCentAmount(o.getAmount())); + receiver.setAccount(o.getReceiverAccount()); + receiver.setName(o.getReceiverName()); + receiver.setDescription("订单分账"); + receiver.setRelationType("PARTNER"); + return receiver; + }) + .toList(); + + request.setReceivers(receivers); + try { + ProfitSharingV3Result result = sharingService.profitSharingV3(request); + + return new AllocStartResultBo().setOutAllocNo(result.getOrderId()); + } catch (WxPayException e) { + throw new OperationFailException("微信分账V3失败: "+e.getMessage()); + } + } + + /** + * 分账完结 + */ + public void finish(AllocOrder allocOrder, List orderDetails, WechatPayConfig config){ + WxPayService wxPayService = wechatPayConfigService.wxJavaSdk(config); + ProfitSharingService sharingService = wxPayService.getProfitSharingService(); + var request = new ProfitSharingUnfreezeV3Request(); + request.setOutOrderNo(allocOrder.getAllocNo()); + request.setTransactionId(allocOrder.getOutOrderNo()); + request.setDescription("分账完结"); + try { + sharingService.profitSharingUnfreeze(request); + } catch (WxPayException e) { + throw new OperationFailException("微信分账V3失败: "+e.getMessage()); + } + } + + /** + * 获取分账接收方类型编码 + */ + private String getReceiverType(AllocReceiverTypeEnum receiverTypeEnum){ + if (receiverTypeEnum == OPEN_ID){ + return "PERSONAL_OPENID"; + } + if (receiverTypeEnum == MERCHANT_NO){ + return "MERCHANT_ID"; + } + throw new ConfigErrorException("分账接收方类型错误"); + } +} diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV2Service.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV2Service.java similarity index 98% rename from daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV2Service.java rename to daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV2Service.java index ecf76da1..1ab17a34 100644 --- a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV2Service.java +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV2Service.java @@ -1,4 +1,4 @@ -package org.dromara.daxpay.channel.wechat.service.allocation; +package org.dromara.daxpay.channel.wechat.service.allocation.receiver; import com.github.binarywang.wxpay.bean.profitsharing.Receiver; import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReceiverRequest; diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV3Service.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV3Service.java similarity index 98% rename from daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV3Service.java rename to daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV3Service.java index 264a9714..0b9e9b9e 100644 --- a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/WechatPayAllocReceiverV3Service.java +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/service/allocation/receiver/WechatPayAllocReceiverV3Service.java @@ -1,4 +1,4 @@ -package org.dromara.daxpay.channel.wechat.service.allocation; +package org.dromara.daxpay.channel.wechat.service.allocation.receiver; import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReceiverV3Request; import com.github.binarywang.wxpay.exception.WxPayException; diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocReceiverStrategy.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocReceiverStrategy.java index 7ddc0be9..a8436e91 100644 --- a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocReceiverStrategy.java +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocReceiverStrategy.java @@ -4,8 +4,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.daxpay.channel.wechat.code.WechatPayCode; import org.dromara.daxpay.channel.wechat.entity.config.WechatPayConfig; -import org.dromara.daxpay.channel.wechat.service.allocation.WechatPayAllocReceiverV2Service; -import org.dromara.daxpay.channel.wechat.service.allocation.WechatPayAllocReceiverV3Service; +import org.dromara.daxpay.channel.wechat.service.allocation.receiver.WechatPayAllocReceiverV2Service; +import org.dromara.daxpay.channel.wechat.service.allocation.receiver.WechatPayAllocReceiverV3Service; import org.dromara.daxpay.channel.wechat.service.config.WechatPayConfigService; import org.dromara.daxpay.core.enums.AllocReceiverTypeEnum; import org.dromara.daxpay.core.enums.ChannelEnum; diff --git a/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocationStrategy.java b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocationStrategy.java new file mode 100644 index 00000000..47e59ae8 --- /dev/null +++ b/daxpay-single-channel/daxpay-single-wechat/src/main/java/org/dromara/daxpay/channel/wechat/strategy/WechatAllocationStrategy.java @@ -0,0 +1,49 @@ +package org.dromara.daxpay.channel.wechat.strategy; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.daxpay.core.enums.ChannelEnum; +import org.dromara.daxpay.service.bo.allocation.AllocStartResultBo; +import org.dromara.daxpay.service.strategy.AbsAllocationStrategy; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +/** + * 微信分账策略 + * @author xxm + * @since 2024/12/9 + */ +@Slf4j +@Scope(SCOPE_PROTOTYPE) +@Component +@RequiredArgsConstructor +public class WechatAllocationStrategy extends AbsAllocationStrategy { + + + /** + * 分账通道 + */ + @Override + public String getChannel() { + return ChannelEnum.WECHAT.getCode(); + } + + /** + * 开始分账 + */ + @Override + public AllocStartResultBo start() { + return null; + } + + /** + * + */ + @Override + public void finish() { + + } + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/bo/allocation/AllocStartResultBo.java b/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/bo/allocation/AllocStartResultBo.java index b245f559..92c4cb71 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/bo/allocation/AllocStartResultBo.java +++ b/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/bo/allocation/AllocStartResultBo.java @@ -2,6 +2,7 @@ package org.dromara.daxpay.service.bo.allocation; import lombok.Data; import lombok.experimental.Accessors; +import org.dromara.daxpay.core.enums.AllocationStatusEnum; /** * 分账操作结果 @@ -14,4 +15,9 @@ public class AllocStartResultBo { /** 通道分账号 */ private String outAllocNo; + /** + * 分账状态 + * @see AllocationStatusEnum + */ + private String status; } diff --git a/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/strategy/AbsAllocationStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/strategy/AbsAllocationStrategy.java index cf88cbc6..352455b7 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/strategy/AbsAllocationStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/org/dromara/daxpay/service/strategy/AbsAllocationStrategy.java @@ -18,25 +18,27 @@ import java.util.List; @Getter @Setter public abstract class AbsAllocationStrategy implements PaymentStrategy{ - private AllocOrder transaction; + private AllocOrder order; private List details; /** * 初始化参数 */ - public void initParam(AllocOrder transaction, List details) { - this.transaction = transaction; + public void initParam(AllocOrder order, List details) { + this.order = order; this.details = details; } /** * 操作前处理, 校验和初始化支付配置 */ - public abstract void doBeforeHandler(); + public void doBeforeHandler(){ + + }; /** - * 分账启动 + * 开始分账 */ public abstract AllocStartResultBo start();