mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-06 12:39:38 +00:00
feat 分账前后端调试
This commit is contained in:
12
_doc/Task.md
12
_doc/Task.md
@@ -14,10 +14,11 @@
|
||||
- [x] 分账完结
|
||||
- [x] 分账处理
|
||||
- [x] 发起分账
|
||||
- [ ] 分账同步
|
||||
- [x] 分账同步
|
||||
- [x] 修复创建支付订单报错时, 订单保存数据不完整
|
||||
- [x] 收银台演示支持传输分账标识
|
||||
|
||||
2.0.6: 分账完善和去除组合支付
|
||||
2.0.6: 去除组合支付, 一系列代码优化
|
||||
- [ ] 去除组合支付和场景,降低逻辑的的复杂度
|
||||
- [ ] 退款场景
|
||||
- [ ] 关闭支付订单
|
||||
@@ -26,17 +27,20 @@
|
||||
- [ ] 支付和退款回调
|
||||
- [ ] 去除现金支付和储值卡支付方式
|
||||
- [ ] 三方支付外部订单号规则优化: 支付P、退款R、分账A,根据环境加前缀:DEV_、DEMO_、PRE_
|
||||
- [ ] 资金流水优化
|
||||
- [ ] 资金流水优化(去除)
|
||||
- [ ] 金额显示统一使用元
|
||||
|
||||
2.0.7: 分账完善
|
||||
- [ ] 支持分账组分账和自己传接收方进行分账
|
||||
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
|
||||
- [ ] 分账接收方管理提供接口调用
|
||||
- [ ] 分账情况查询, 分账结果/剩余可分账金额
|
||||
- [ ] 分账回调处理
|
||||
- [ ] 分账组管理提供接口调用
|
||||
- [ ] 对账回退及退款
|
||||
- [ ] 分账通知
|
||||
|
||||
2.0.x 版本内容
|
||||
- [ ] 对账回退及退款
|
||||
- [ ] 统计报表功能
|
||||
- [ ] 微信新增V3版本接口
|
||||
- [ ] 付款码支付自动路由到V2接口
|
||||
|
@@ -10,7 +10,6 @@ import cn.bootx.platform.daxpay.param.pay.allocation.AllocationFinishParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.allocation.AllocationResetParam;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.service.AllocationOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.allocation.service.AllocationService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.allocation.service.AllocationSyncService;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.param.order.AllocationOrderQuery;
|
||||
@@ -37,7 +36,6 @@ public class AllocationOrderController {
|
||||
|
||||
private final AllocationOrderService allocationOrderService;
|
||||
|
||||
private final AllocationSyncService allocationSyncService;
|
||||
private final AllocationService allocationService;
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@@ -76,7 +74,7 @@ public class AllocationOrderController {
|
||||
public ResResult<Void> sync(Long id){
|
||||
AllocationSyncParam param = new AllocationSyncParam();
|
||||
param.setAllocationId(id);
|
||||
allocationSyncService.sync(param);
|
||||
allocationService.sync(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付分账明细处理结果
|
||||
* @author xxm
|
||||
* @since 2024/4/16
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AllocationDetailResultEnum {
|
||||
|
||||
PENDING("pending", "待分账"),
|
||||
SUCCESS("success", "分账成功"),
|
||||
FAIL("fail", "分账失败"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付分账订单处理结果
|
||||
* @author xxm
|
||||
* @since 2024/4/16
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AllocationOrderResultEnum {
|
||||
|
||||
ALL_PENDING("all_pending", "全部成功"),
|
||||
ALL_SUCCESS("all_success", "全部成功"),
|
||||
PART_SUCCESS("part_success", "部分成功"),
|
||||
ALL_FAILED("all_failed", "全部失败"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 分账状态枚举
|
||||
* @author xxm
|
||||
* @since 2024/4/7
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AllocationOrderStatusEnum {
|
||||
|
||||
ALLOCATION_PROCESSING("allocation_processing", "分账处理中"),
|
||||
ALLOCATION_END("allocation_end", "分账完成"),
|
||||
ALLOCATION_FAILED("allocation_failed", "分账失败"),
|
||||
FINISH("finish", "完结"),
|
||||
FINISH_FAILED("finish_failed", "完结失败"),
|
||||
;
|
||||
|
||||
final String code;
|
||||
final String name;
|
||||
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 分账状态枚举
|
||||
* @author xxm
|
||||
* @since 2024/4/7
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AllocationStatusEnum {
|
||||
|
||||
// 待分账
|
||||
WAITING("waiting", "待分账"),
|
||||
PARTIAL_PROCESSING("partial_processing", "分账处理中"),
|
||||
PARTIAL_SUCCESS("partial_success", "部分分账完成"),
|
||||
FINISH_PROCESSING("finish_processing", "分账完结处理中"),
|
||||
FINISH_SUCCESS("finish_success", "分账完成"),
|
||||
PARTIAL_FAILED("partial_failed", "部分分账完成"),
|
||||
FINISH_FAILED("finish_failed", "分账失败"),
|
||||
CLOSED("closed", "分账关闭"),
|
||||
UNKNOWN("unknown", "分账状态未知");
|
||||
|
||||
final String code;
|
||||
final String name;
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付订单分账状态
|
||||
* @author xxm
|
||||
* @since 2024/4/16
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PayOrderAllocationStatusEnum {
|
||||
WAITING("waiting", "待分账"),
|
||||
ALLOCATION("allocation", "已分账"),
|
||||
;
|
||||
|
||||
final String code;
|
||||
final String name;
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.result.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.RefundSyncStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
|
||||
import cn.bootx.platform.daxpay.result.CommonResult;
|
||||
@@ -26,7 +26,7 @@ public class SyncResult extends CommonResult {
|
||||
* 支付网关同步状态
|
||||
* @see PaySyncStatusEnum
|
||||
* @see RefundSyncStatusEnum
|
||||
* @see AllocationStatusEnum
|
||||
* @see AllocationOrderStatusEnum
|
||||
*/
|
||||
@Schema(description = "支付网关同步状态")
|
||||
private String gatewayStatus = FAIL.getCode();
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package cn.bootx.platform.daxpay.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 网关消息通知
|
||||
* @author xxm
|
||||
* @since 2024/4/16
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@Tag(name = "三方支付网关消息通知")
|
||||
@RestController
|
||||
@RequestMapping("/gateway/notice")
|
||||
@RequiredArgsConstructor
|
||||
public class PayGatewayNoticeController {
|
||||
|
||||
@Operation(summary = "支付宝消息通知")
|
||||
@PostMapping("/alipay")
|
||||
public String aliPayNotice() {
|
||||
return "success";
|
||||
}
|
||||
|
||||
@Operation(summary = "微信消息通知")
|
||||
@PostMapping("/wechat")
|
||||
public Map<String, Objects> wechatPayNotice() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
@@ -105,4 +105,15 @@ public interface AliPayCode {
|
||||
/** 分账金额超过最大可分账金额 */
|
||||
String ALLOC_AMOUNT_VALIDATE_ERROR = "ACQ.ALLOC_AMOUNT_VALIDATE_ERROR";
|
||||
|
||||
/** 分账 进行中 */
|
||||
String ALLOC_PROCESSING = "PROCESSING";
|
||||
/** 分账 成功 */
|
||||
String ALLOC_SUCCESS = "SUCCESS";
|
||||
/** 分账 失败 */
|
||||
String ALLOC_FAIL = "FAIL";
|
||||
|
||||
/** 异步分账 */
|
||||
String ALLOC_ASYNC = "ASYNC";
|
||||
/** 同步分账 */
|
||||
String ALLOC_SYNC = "SYNC";
|
||||
}
|
||||
|
@@ -146,4 +146,7 @@ public interface WeChatPayCode {
|
||||
/** 个人openid */
|
||||
String PERSONAL_OPENID = "PERSONAL_OPENID";
|
||||
|
||||
/** 获取分账订单明细 */
|
||||
String ALLOC_RECEIVERS = "receivers";
|
||||
|
||||
}
|
||||
|
@@ -1,10 +1,14 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrderDetail;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alipay.api.AlipayResponse;
|
||||
import com.alipay.api.domain.*;
|
||||
@@ -17,8 +21,12 @@ import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -40,9 +48,10 @@ public class AliPayAllocationService {
|
||||
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
|
||||
model.setOutRequestNo(String.valueOf(allocationOrder.getOrderNo()));
|
||||
model.setTradeNo(allocationOrder.getGatewayPayOrderNo());
|
||||
model.setRoyaltyMode("async");
|
||||
model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC);
|
||||
|
||||
// 分账子参数
|
||||
// 分账子参数 根据Id排序
|
||||
orderDetails.sort(Comparator.comparing(MpIdEntity::getId));
|
||||
List<OpenApiRoyaltyDetailInfoPojo> royaltyParameters = orderDetails.stream()
|
||||
.map(o -> {
|
||||
OpenApiRoyaltyDetailInfoPojo infoPojo = new OpenApiRoyaltyDetailInfoPojo();
|
||||
@@ -69,13 +78,14 @@ public class AliPayAllocationService {
|
||||
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
|
||||
model.setOutRequestNo(String.valueOf(allocationOrder.getOrderNo()));
|
||||
model.setTradeNo(allocationOrder.getGatewayPayOrderNo());
|
||||
model.setRoyaltyMode("async");
|
||||
model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC);
|
||||
// 分账完结参数
|
||||
SettleExtendParams extendParams = new SettleExtendParams();
|
||||
extendParams.setRoyaltyFinish("true");
|
||||
model.setExtendParams(extendParams);
|
||||
|
||||
// 分账子参数
|
||||
// 分账子参数 根据Id排序
|
||||
orderDetails.sort(Comparator.comparing(MpIdEntity::getId));
|
||||
List<OpenApiRoyaltyDetailInfoPojo> royaltyParameters = orderDetails.stream()
|
||||
.map(o -> {
|
||||
OpenApiRoyaltyDetailInfoPojo infoPojo = new OpenApiRoyaltyDetailInfoPojo();
|
||||
@@ -90,10 +100,10 @@ public class AliPayAllocationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账状态查询
|
||||
* 分账状态同步
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void queryStatus(AllocationOrder allocationOrder){
|
||||
public void sync(AllocationOrder allocationOrder, List<AllocationOrderDetail> allocationOrderDetails){
|
||||
AlipayTradeOrderSettleQueryModel model = new AlipayTradeOrderSettleQueryModel();
|
||||
model.setTradeNo(allocationOrder.getGatewayPayOrderNo());
|
||||
model.setOutRequestNo(allocationOrder.getOrderNo());
|
||||
@@ -102,22 +112,23 @@ public class AliPayAllocationService {
|
||||
AlipayTradeOrderSettleQueryResponse response = AliPayApi.execute(request);
|
||||
// 验证
|
||||
this.verifyErrorMsg(response);
|
||||
Map<String, AllocationOrderDetail> detailMap = allocationOrderDetails.stream()
|
||||
.collect(Collectors.toMap(AllocationOrderDetail::getReceiverAccount, Function.identity(), CollectorsFunction::retainLatest));
|
||||
List<RoyaltyDetail> royaltyDetailList = response.getRoyaltyDetailList();
|
||||
|
||||
// 转换成通用的明细详情
|
||||
for (RoyaltyDetail royaltyDetail : royaltyDetailList) {
|
||||
System.out.println(royaltyDetail);
|
||||
System.out.println(royaltyDetail.getState());
|
||||
System.out.println(royaltyDetail.getDetailId());
|
||||
|
||||
for (RoyaltyDetail receiver : royaltyDetailList) {
|
||||
AllocationOrderDetail 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 (AllocationDetailResultEnum.SUCCESS.getCode().equals(detail.getResult())){
|
||||
LocalDateTime finishTime = LocalDateTimeUtil.of(receiver.getExecuteDt());
|
||||
detail.setFinishTime(finishTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账剩余金额查询
|
||||
*/
|
||||
public void queryAmount(AllocationOrder allocationOrder){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,8 +140,24 @@ public class AliPayAllocationService {
|
||||
if (StrUtil.isBlank(errorMsg)) {
|
||||
errorMsg = alipayResponse.getMsg();
|
||||
}
|
||||
log.error("分账接收方处理失败 {}", errorMsg);
|
||||
log.error("分账处理失败 {}", errorMsg);
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换支付宝分账类型到系统中统一的
|
||||
*/
|
||||
private AllocationDetailResultEnum getDetailResultEnum (String result){
|
||||
// 进行中
|
||||
if(Objects.equals(AliPayCode.ALLOC_PROCESSING, result)){
|
||||
return AllocationDetailResultEnum.PENDING;
|
||||
}
|
||||
// 成功
|
||||
if(Objects.equals(AliPayCode.ALLOC_SUCCESS, result)){
|
||||
return AllocationDetailResultEnum.SUCCESS;
|
||||
}
|
||||
// 失败
|
||||
return AllocationDetailResultEnum.FAIL;
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ public class WeChatPayAllocationReceiverService {
|
||||
public boolean validation(AllocationReceiver allocationReceiver){
|
||||
List<String> list = Arrays.asList(WX_MERCHANT.getCode(), WX_MERCHANT.getCode());
|
||||
String receiverType = allocationReceiver.getReceiverType();
|
||||
return !list.contains(receiverType);
|
||||
return list.contains(receiverType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,12 +1,19 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrderDetail;
|
||||
import cn.bootx.platform.daxpay.service.dto.channel.wechat.WeChatPayAllocationReceiver;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
@@ -21,8 +28,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -45,6 +56,7 @@ public class WeChatPayAllocationService {
|
||||
description = "分账";
|
||||
}
|
||||
String finalDescription = description;
|
||||
orderDetails.sort(Comparator.comparing(MpIdEntity::getId));
|
||||
List<ReceiverModel> list = orderDetails.stream().map(o->{
|
||||
AllocationReceiverTypeEnum receiverTypeEnum = AllocationReceiverTypeEnum.findByCode(o.getReceiverType());
|
||||
return ReceiverModel.builder()
|
||||
@@ -75,7 +87,7 @@ public class WeChatPayAllocationService {
|
||||
/**
|
||||
* 完成分账
|
||||
*/
|
||||
public void finish(AllocationOrder allocationOrder, List<AllocationOrderDetail> allocationOrderDetails, WeChatPayConfig config){
|
||||
public void finish(AllocationOrder allocationOrder, WeChatPayConfig config){
|
||||
Map<String, String> params = ProfitSharingModel.builder()
|
||||
.mch_id(config.getWxMchId())
|
||||
.appid(config.getWxAppId())
|
||||
@@ -94,9 +106,9 @@ public class WeChatPayAllocationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询分账状态
|
||||
* 同步分账状态
|
||||
*/
|
||||
public void queryStatus(AllocationOrder allocationOrder, WeChatPayConfig config){
|
||||
public void sync(AllocationOrder allocationOrder, List<AllocationOrderDetail> allocationOrderDetails, WeChatPayConfig config){
|
||||
// 不要传输AppId参数, 否则会失败
|
||||
Map<String, String> params = ProfitSharingModel.builder()
|
||||
.mch_id(config.getWxMchId())
|
||||
@@ -108,7 +120,23 @@ public class WeChatPayAllocationService {
|
||||
String xmlResult = WxPayApi.profitSharingQuery(params);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
JSONUtil.parse(result.get("receivers"));
|
||||
String json = result.get(WeChatPayCode.ALLOC_RECEIVERS);
|
||||
List<WeChatPayAllocationReceiver> receivers = JSONUtil.toBean(json, new TypeReference<List<WeChatPayAllocationReceiver>>() {}, false);
|
||||
Map<String, AllocationOrderDetail> detailMap = allocationOrderDetails.stream()
|
||||
.collect(Collectors.toMap(AllocationOrderDetail::getReceiverAccount, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 根据明细更新订单明细内容
|
||||
for (WeChatPayAllocationReceiver receiver : receivers) {
|
||||
AllocationOrderDetail detail = detailMap.get(receiver.getAccount());
|
||||
if (Objects.nonNull(detail)){
|
||||
detail.setResult(this.getDetailResultEnum(receiver.getResult()).getCode());
|
||||
detail.setErrorMsg(receiver.getFailReason());
|
||||
// 如果是完成, 更新时间
|
||||
if (AllocationDetailResultEnum.SUCCESS.getCode().equals(detail.getResult())){
|
||||
LocalDateTime finishTime = LocalDateTimeUtil.parse(receiver.getFinishTime(), DatePattern.PURE_DATETIME_PATTERN);
|
||||
detail.setFinishTime(finishTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,4 +155,20 @@ public class WeChatPayAllocationService {
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换微信分账类型到系统中统一的
|
||||
*/
|
||||
private AllocationDetailResultEnum getDetailResultEnum (String result){
|
||||
// 进行中
|
||||
if(Objects.equals("PENDING", result)){
|
||||
return AllocationDetailResultEnum.PENDING;
|
||||
}
|
||||
// 成功
|
||||
if(Objects.equals("SUCCESS", result)){
|
||||
return AllocationDetailResultEnum.SUCCESS;
|
||||
}
|
||||
// 失败
|
||||
return AllocationDetailResultEnum.FAIL;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,8 @@ package cn.bootx.platform.daxpay.service.core.order.allocation.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.convert.AllocationConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDto;
|
||||
@@ -18,8 +19,6 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 分账订单
|
||||
* @author xxm
|
||||
@@ -91,11 +90,18 @@ public class AllocationOrder extends MpBaseEntity implements EntityBaseFunction<
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* @see AllocationStatusEnum
|
||||
* @see AllocationOrderStatusEnum
|
||||
*/
|
||||
@DbColumn(comment = "状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 分账处理结果
|
||||
* @see AllocationOrderResultEnum
|
||||
*/
|
||||
@DbColumn(comment = "分账处理结果")
|
||||
private String result;
|
||||
|
||||
/**
|
||||
* 错误原因
|
||||
*/
|
||||
@@ -103,12 +109,6 @@ public class AllocationOrder extends MpBaseEntity implements EntityBaseFunction<
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
@DbColumn(comment = "完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
|
@@ -3,6 +3,7 @@ package cn.bootx.platform.daxpay.service.core.order.allocation.entity;
|
||||
import cn.bootx.platform.common.core.annotation.EncryptionField;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.convert.AllocationConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDetailDto;
|
||||
@@ -13,6 +14,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 分账订单明细
|
||||
* @author xxm
|
||||
@@ -57,9 +60,12 @@ public class AllocationOrderDetail extends MpBaseEntity implements EntityBaseFun
|
||||
@DbColumn(comment = "接收方姓名")
|
||||
private String receiverName;
|
||||
|
||||
/** 状态 */
|
||||
@DbColumn(comment = "状态")
|
||||
private String status;
|
||||
/**
|
||||
* 分账结果
|
||||
* @see AllocationDetailResultEnum
|
||||
*/
|
||||
@DbColumn(comment = "分账结果")
|
||||
private String result;
|
||||
|
||||
/** 错误代码 */
|
||||
@DbColumn(comment = "错误代码")
|
||||
@@ -69,6 +75,10 @@ public class AllocationOrderDetail extends MpBaseEntity implements EntityBaseFun
|
||||
@DbColumn(comment = "错误原因")
|
||||
private String errorMsg;
|
||||
|
||||
/** 分账完成时间 */
|
||||
@DbColumn(comment = "分账完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
|
@@ -6,14 +6,17 @@ import cn.bootx.platform.common.core.rest.dto.LabelValue;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.core.util.ResultConvertUtil;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayOrderAllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.pay.allocation.AllocationStartParam;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.dao.AllocationOrderDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.dao.AllocationOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrderDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.OrderAndDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.dto.allocation.AllocationGroupReceiverResult;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.allocation.AllocationOrderDetailDto;
|
||||
@@ -43,6 +46,8 @@ public class AllocationOrderService {
|
||||
private final AllocationOrderManager allocationOrderManager;
|
||||
private final AllocationOrderDetailManager allocationOrderDetailManager;
|
||||
|
||||
private final PayOrderManager payOrderManager;
|
||||
|
||||
|
||||
/**
|
||||
* 获取可以分账的通道
|
||||
@@ -106,8 +111,8 @@ public class AllocationOrderService {
|
||||
AllocationOrderDetail detail = new AllocationOrderDetail();
|
||||
detail.setAllocationId(orderId)
|
||||
.setReceiverId(o.getId())
|
||||
.setStatus(AllocationStatusEnum.WAITING.getCode())
|
||||
.setAmount(amount)
|
||||
.setResult(AllocationDetailResultEnum.PENDING.getCode())
|
||||
.setRate(rate)
|
||||
.setReceiverType(o.getReceiverType())
|
||||
.setReceiverName(o.getReceiverName())
|
||||
@@ -128,10 +133,12 @@ public class AllocationOrderService {
|
||||
.setGatewayPayOrderNo(payOrder.getGatewayOrderNo())
|
||||
.setOrderNo(String.valueOf(orderId))
|
||||
.setDescription(param.getDescription())
|
||||
.setStatus(AllocationStatusEnum.WAITING.getCode())
|
||||
.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
|
||||
.setAmount(sumAmount);
|
||||
allocationOrder.setId(orderId);
|
||||
// 保存
|
||||
// 更新支付订单分账状态
|
||||
payOrder.setAllocationStatus(PayOrderAllocationStatusEnum.ALLOCATION.getCode());
|
||||
payOrderManager.updateById(payOrder);
|
||||
// 因为加密后字段值会发生变更, 所以在保存前备份一下
|
||||
List<AllocationOrderDetail> detailsBack = details.stream()
|
||||
.map(o -> {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.pay.builder;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayOrderAllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
@@ -52,7 +53,7 @@ public class PayBuilder {
|
||||
.filter(PayChannelEnum.ASYNC_TYPE_CODE::contains)
|
||||
.findFirst();
|
||||
// 构建支付订单对象
|
||||
return new PayOrder()
|
||||
PayOrder payOrder = new PayOrder()
|
||||
.setBusinessNo(payParam.getBusinessNo())
|
||||
.setTitle(payParam.getTitle())
|
||||
.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
@@ -62,6 +63,11 @@ public class PayBuilder {
|
||||
.setCombinationPay(payParam.getPayChannels().size() > 1)
|
||||
.setAsyncPay(asyncPay.isPresent())
|
||||
.setRefundableBalance(sumAmount);
|
||||
// 设置分账状态
|
||||
if (payOrder.isAllocation()) {
|
||||
payOrder.setAllocationStatus(PayOrderAllocationStatusEnum.WAITING.getCode());
|
||||
}
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2,9 +2,9 @@ package cn.bootx.platform.daxpay.service.core.order.pay.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.PayOrderAllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.convert.PayOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
@@ -83,7 +83,7 @@ public class PayOrder extends MpBaseEntity implements EntityBaseFunction<PayOrde
|
||||
|
||||
/**
|
||||
* 分账状态
|
||||
* @see AllocationStatusEnum
|
||||
* @see PayOrderAllocationStatusEnum
|
||||
*/
|
||||
@DbColumn(comment = "分账状态")
|
||||
private String allocationStatus;
|
||||
|
@@ -1,39 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.allocation.factory;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.allocation.AliPayAllocationSyncStrategy;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.allocation.WechatPayAllocationSyncStrategy;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsAllocationSyncStrategy;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* 分账同步策略工厂
|
||||
* @author xxm
|
||||
* @since 2024/4/12
|
||||
*/
|
||||
@UtilityClass
|
||||
public class AllocationSyncFactory {
|
||||
|
||||
/**
|
||||
* 根据传入的支付通道创建策略
|
||||
* @return 支付策略
|
||||
*/
|
||||
public static AbsAllocationSyncStrategy create(String channel) {
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
|
||||
|
||||
AbsAllocationSyncStrategy strategy;
|
||||
switch (channelEnum) {
|
||||
case ALI:
|
||||
strategy = SpringUtil.getBean(AliPayAllocationSyncStrategy.class);
|
||||
break;
|
||||
case WECHAT:
|
||||
strategy = SpringUtil.getBean(WechatPayAllocationSyncStrategy.class);
|
||||
break;
|
||||
default:
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
}
|
@@ -1,8 +1,12 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.allocation.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayOrderAllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.AllocationSyncParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.allocation.AllocationFinishParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.allocation.AllocationResetParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.allocation.AllocationStartParam;
|
||||
@@ -27,7 +31,10 @@ import cn.hutool.core.util.StrUtil;
|
||||
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.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -73,6 +80,7 @@ public class AllocationService {
|
||||
} else {
|
||||
allocationGroup = groupManager.findDefaultGroup(payOrder.getAsyncChannel()).orElseThrow(() -> new DataNotExistException("未查询到默认分账组"));
|
||||
}
|
||||
|
||||
List<AllocationGroupReceiverResult> receiversByGroups = allocationGroupService.findReceiversByGroups(allocationGroup.getId());
|
||||
|
||||
// 创建分账单和明细并保存, 同时更新支付订单状态 使用事务
|
||||
@@ -90,11 +98,11 @@ public class AllocationService {
|
||||
// 分账处理
|
||||
allocationStrategy.allocation();
|
||||
// 执行中
|
||||
order.setStatus(AllocationStatusEnum.PARTIAL_PROCESSING.getCode())
|
||||
order.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
|
||||
.setErrorMsg(null);
|
||||
} catch (Exception e) {
|
||||
// 失败
|
||||
order.setStatus(AllocationStatusEnum.PARTIAL_FAILED.getCode())
|
||||
order.setStatus(AllocationOrderStatusEnum.ALLOCATION_FAILED.getCode())
|
||||
.setErrorMsg(e.getMessage());
|
||||
}
|
||||
// 网关分账号
|
||||
@@ -121,6 +129,14 @@ public class AllocationService {
|
||||
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
|
||||
.orElseThrow(() -> new DataNotExistException("未查询到分账单信息"));
|
||||
}
|
||||
// 需要是分账中分账中或者完成状态才能重新分账
|
||||
List<String> list = Arrays.asList(AllocationOrderStatusEnum.ALLOCATION_END.getCode(),
|
||||
AllocationOrderStatusEnum.ALLOCATION_FAILED.getCode(),
|
||||
AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode());
|
||||
if (!list.contains(allocationOrder.getStatus())){
|
||||
throw new PayFailureException("分账单状态错误");
|
||||
}
|
||||
|
||||
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
|
||||
|
||||
// 创建分账策略并初始化
|
||||
@@ -132,9 +148,15 @@ public class AllocationService {
|
||||
try {
|
||||
// 重复分账处理
|
||||
allocationStrategy.allocation();
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
|
||||
.setErrorMsg(null);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 失败
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_FAILED.getCode())
|
||||
.setErrorMsg(e.getMessage());
|
||||
}
|
||||
allocationOrderManager.updateById(allocationOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,8 +171,12 @@ public class AllocationService {
|
||||
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
|
||||
.orElseThrow(() -> new DataNotExistException("未查询到分账单信息"));
|
||||
}
|
||||
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
|
||||
// 只有分账结束后才可以完结
|
||||
if (!AllocationOrderStatusEnum.ALLOCATION_END.getCode().equals(allocationOrder.getStatus())){
|
||||
throw new PayFailureException("分账单状态错误");
|
||||
}
|
||||
|
||||
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
|
||||
// 创建分账策略并初始化
|
||||
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
|
||||
allocationStrategy.initParam(allocationOrder, details);
|
||||
@@ -158,20 +184,90 @@ public class AllocationService {
|
||||
// 分账完结预处理
|
||||
allocationStrategy.doBeforeHandler();
|
||||
try {
|
||||
// 分账处理
|
||||
// 完结处理
|
||||
allocationStrategy.finish();
|
||||
// 执行中
|
||||
allocationOrder.setStatus(AllocationStatusEnum.FINISH_PROCESSING.getCode())
|
||||
// 完结状态
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.FINISH.getCode())
|
||||
.setErrorMsg(null);
|
||||
} catch (Exception e) {
|
||||
// 失败
|
||||
allocationOrder.setStatus(AllocationStatusEnum.FINISH_FAILED.getCode())
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.FINISH_FAILED.getCode())
|
||||
.setErrorMsg(e.getMessage());
|
||||
}
|
||||
|
||||
allocationOrderManager.updateById(allocationOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账同步, 开启一个新的事务, 不受外部抛出异常的影响
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void sync(AllocationSyncParam param) {
|
||||
// 获取分账订单
|
||||
AllocationOrder allocationOrder = null;
|
||||
if (Objects.nonNull(param.getAllocationId())){
|
||||
allocationOrder = allocationOrderManager.findById(param.getAllocationId())
|
||||
.orElseThrow(() -> new DataNotExistException("分账单不存在"));
|
||||
}
|
||||
if (Objects.isNull(allocationOrder)){
|
||||
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
|
||||
.orElseThrow(() -> new DataNotExistException("分账单不存在"));
|
||||
}
|
||||
List<AllocationOrderDetail> detailList = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
|
||||
// 获取分账策略
|
||||
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
|
||||
allocationStrategy.initParam(allocationOrder, detailList);
|
||||
// 分账完结预处理
|
||||
allocationStrategy.doBeforeHandler();
|
||||
allocationStrategy.doSync();
|
||||
|
||||
// 根据订单明细更新订单的状态和处理结果
|
||||
this.updateOrderStatus(allocationOrder, detailList);
|
||||
|
||||
allocationOrderDetailManager.updateAllById(detailList);
|
||||
allocationOrderManager.updateById(allocationOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单明细更新订单的状态和处理结果, 如果订单是分账结束或失败, 不更新状态
|
||||
*/
|
||||
private void updateOrderStatus(AllocationOrder allocationOrder, List<AllocationOrderDetail> details){
|
||||
// 如果是分账结束或失败, 不更新状态
|
||||
String status = allocationOrder.getStatus();
|
||||
// 判断明细状态. 获取成功和失败的
|
||||
long successCount = details.stream()
|
||||
.map(AllocationOrderDetail::getResult)
|
||||
.filter(AllocationDetailResultEnum.SUCCESS.getCode()::equals)
|
||||
.count();
|
||||
long failCount = details.stream()
|
||||
.map(AllocationOrderDetail::getResult)
|
||||
.filter(AllocationDetailResultEnum.FAIL.getCode()::equals)
|
||||
.count();
|
||||
|
||||
// 成功和失败都为0 进行中
|
||||
if (successCount == 0 && failCount == 0){
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
|
||||
.setResult(AllocationOrderResultEnum.ALL_PENDING.getCode());
|
||||
} else if (failCount == details.size()){
|
||||
// 全部失败
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_END.getCode())
|
||||
.setResult(AllocationOrderResultEnum.ALL_FAILED.getCode());
|
||||
} else if (successCount == details.size()){
|
||||
// 全部成功
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_END.getCode())
|
||||
.setResult(AllocationOrderResultEnum.ALL_SUCCESS.getCode());
|
||||
} else {
|
||||
// 部分成功
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_END.getCode())
|
||||
.setResult(AllocationOrderResultEnum.PART_SUCCESS.getCode());
|
||||
}
|
||||
// 如果是分账结束或失败, 状态复原
|
||||
List<String> list = Arrays.asList(AllocationOrderStatusEnum.FINISH.getCode(), AllocationOrderStatusEnum.FINISH_FAILED.getCode());
|
||||
if (list.contains(status)){
|
||||
allocationOrder.setStatus(AllocationOrderStatusEnum.FINISH.getCode())
|
||||
.setResult(AllocationOrderResultEnum.ALL_SUCCESS.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并检查支付订单
|
||||
*/
|
||||
@@ -191,11 +287,9 @@ public class AllocationService {
|
||||
throw new PayFailureException("该订单不允许分账");
|
||||
}
|
||||
// 判断分账状态
|
||||
if (Objects.equals(AllocationStatusEnum.FINISH_SUCCESS.getCode(), payOrder.getAllocationStatus())){
|
||||
if (Objects.equals(PayOrderAllocationStatusEnum.ALLOCATION.getCode(), payOrder.getAllocationStatus())){
|
||||
throw new PayFailureException("该订单已分账完成");
|
||||
}
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,50 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.allocation.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.daxpay.param.pay.AllocationSyncParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.SyncResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.dao.AllocationOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.allocation.factory.AllocationSyncFactory;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsAllocationSyncStrategy;
|
||||
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.util.Objects;
|
||||
|
||||
/**
|
||||
* 分账状态同步
|
||||
* @author xxm
|
||||
* @since 2024/4/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AllocationSyncService {
|
||||
private final AllocationOrderManager allocationOrderManager;
|
||||
|
||||
/**
|
||||
* 支付同步, 开启一个新的事务, 不受外部抛出异常的影响
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public SyncResult sync(AllocationSyncParam param) {
|
||||
// 获取分账订单
|
||||
AllocationOrder allocationOrder = null;
|
||||
if (Objects.nonNull(param.getAllocationId())){
|
||||
allocationOrder = allocationOrderManager.findById(param.getAllocationId())
|
||||
.orElseThrow(() -> new DataNotExistException("分账单不存在"));
|
||||
}
|
||||
if (Objects.isNull(allocationOrder)){
|
||||
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
|
||||
.orElseThrow(() -> new DataNotExistException("分账单不存在"));
|
||||
}
|
||||
// 获取分账策略
|
||||
AbsAllocationSyncStrategy allocationSyncStrategy = AllocationSyncFactory.create(allocationOrder.getChannel());
|
||||
allocationSyncStrategy.initPayParam(allocationOrder);
|
||||
allocationSyncStrategy.doSyncStatus();
|
||||
return new SyncResult();
|
||||
}
|
||||
}
|
@@ -70,4 +70,12 @@ public class AliPayAllocationStrategy extends AbsAllocationStrategy {
|
||||
aliPayAllocationService.finish(this.getAllocationOrder(), this.getAllocationOrderDetails());
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
@Override
|
||||
public void doSync() {
|
||||
aliPayAllocationService.sync(this.getAllocationOrder(), this.getAllocationOrderDetails());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -65,8 +65,15 @@ public class WeChatPayAllocationStrategy extends AbsAllocationStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void finish() {
|
||||
weChatPayAllocationService.finish(getAllocationOrder(), this.getAllocationOrderDetails(), weChatPayConfig);
|
||||
weChatPayAllocationService.finish(getAllocationOrder(), weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
@Override
|
||||
public void doSync() {
|
||||
weChatPayAllocationService.sync(this.getAllocationOrder(),this.getAllocationOrderDetails(),weChatPayConfig);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.SimplePayParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
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;
|
||||
@@ -271,10 +270,6 @@ public class PayService {
|
||||
payOrderExtraManager.update(payOrderExtra);
|
||||
// 如果支付完成 发送通知
|
||||
if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){
|
||||
// 如果是是允许分账的订单, 设置为待分装
|
||||
if (payOrder.isAllocation()){
|
||||
payOrder.setAllocationStatus(AllocationStatusEnum.WAITING.getCode());
|
||||
}
|
||||
clientNoticeService.registerPayNotice(payOrder, payOrderExtra, payInfo.getPayChannelOrders());
|
||||
}
|
||||
return PayBuilder.buildPayResultByPayOrder(payOrder);
|
||||
@@ -373,10 +368,6 @@ public class PayService {
|
||||
payOrderExtraManager.update(payOrderExtra);
|
||||
// 如果支付完成 发送通知
|
||||
if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){
|
||||
// 如果是是允许分账的订单, 设置为待分装
|
||||
if (payOrder.isAllocation()){
|
||||
payOrder.setAllocationStatus(AllocationStatusEnum.WAITING.getCode());
|
||||
}
|
||||
clientNoticeService.registerPayNotice(payOrder, payOrderExtra, payInfo.getPayChannelOrders());
|
||||
}
|
||||
return PayBuilder.buildPayResultByPayOrder(payOrder);
|
||||
|
@@ -1,44 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.sync.strategy.allocation;
|
||||
|
||||
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.AliPayAllocationService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsAllocationSyncStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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/4/12
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AliPayAllocationSyncStrategy extends AbsAllocationSyncStrategy {
|
||||
private final AliPayConfigService aliPayConfigService;
|
||||
|
||||
private final AliPayAllocationService aliPayAllocationService;
|
||||
/**
|
||||
* 策略标识
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
@Override
|
||||
public void doSyncStatus() {
|
||||
AliPayConfig aliPayConfig = aliPayConfigService.getAndCheckConfig();
|
||||
aliPayConfigService.initConfig(aliPayConfig);
|
||||
aliPayAllocationService.queryStatus(this.getAllocationOrder());
|
||||
}
|
||||
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.sync.strategy.allocation;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayAllocationService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsAllocationSyncStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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/4/12
|
||||
*/
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class WechatPayAllocationSyncStrategy extends AbsAllocationSyncStrategy {
|
||||
|
||||
private final WeChatPayAllocationService weChatPayAllocationService;
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
@Override
|
||||
public void doSyncStatus() {
|
||||
WeChatPayConfig wechatPayConfig = weChatPayConfigService.getAndCheckConfig();
|
||||
weChatPayAllocationService.queryStatus(this.getAllocationOrder(),wechatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.dto.allocation;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationRelationTypeEnum;
|
||||
import cn.bootx.platform.starter.data.perm.sensitive.SensitiveInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -37,6 +38,7 @@ public class AllocationGroupReceiverResult {
|
||||
|
||||
|
||||
@Schema(description = "接收方账号")
|
||||
@SensitiveInfo
|
||||
private String receiverAccount;
|
||||
|
||||
/** 接收方姓名 */
|
||||
|
@@ -0,0 +1,63 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.channel.wechat;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.hutool.core.annotation.Alias;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 微信分账单状态
|
||||
* @author xxm
|
||||
* @since 2024/4/16
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class WeChatPayAllocationReceiver {
|
||||
|
||||
/** 分账金额 */
|
||||
private Integer amount;
|
||||
|
||||
/** 分账描述 */
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 分账接收方类型
|
||||
* @see AllocationReceiverTypeEnum
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 分账接收方账号
|
||||
*/
|
||||
private String account;
|
||||
|
||||
/**
|
||||
* 分账结果
|
||||
*/
|
||||
private String result;
|
||||
|
||||
/**
|
||||
* 分账完成时间 yyyyMMddHHmmss
|
||||
*/
|
||||
@Alias("finish_time")
|
||||
@JsonProperty("finish_time")
|
||||
private String finishTime;
|
||||
|
||||
/**
|
||||
* 分账失败原因
|
||||
*/
|
||||
@Alias("fail_reason")
|
||||
@JsonProperty("fail_reason")
|
||||
private String failReason;
|
||||
|
||||
/**
|
||||
* 分账明细单号
|
||||
*/
|
||||
@Alias("detail_id")
|
||||
@JsonProperty("detail_id")
|
||||
private String detailId;
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.allocation;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.AllocationDetailResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.starter.data.perm.sensitive.SensitiveInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -8,6 +9,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 分账订单详情
|
||||
* @author xxm
|
||||
@@ -52,7 +55,23 @@ public class AllocationOrderDetailDto extends BaseDto {
|
||||
@Schema(description = "接收方姓名")
|
||||
private String receiverName;
|
||||
|
||||
/** 状态 */
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
/**
|
||||
* 分账结果
|
||||
* @see AllocationDetailResultEnum
|
||||
*/
|
||||
@Schema(description = "分账结果")
|
||||
private String result;
|
||||
|
||||
/** 错误代码 */
|
||||
@Schema(description = "错误代码")
|
||||
private String errorCode;
|
||||
|
||||
/** 错误原因 */
|
||||
@Schema(description = "错误原因")
|
||||
private String errorMsg;
|
||||
|
||||
/** 分账完成时间 */
|
||||
@Schema(description = "分账完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
}
|
||||
|
@@ -1,16 +1,13 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.allocation;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderResultEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 分账订单
|
||||
* @author xxm
|
||||
@@ -78,22 +75,21 @@ public class AllocationOrderDto extends BaseDto {
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* @see AllocationStatusEnum
|
||||
* @see AllocationOrderStatusEnum
|
||||
*/
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 分账处理结果
|
||||
* @see AllocationOrderResultEnum
|
||||
*/
|
||||
@Schema(description = "分账处理结果")
|
||||
private String result;
|
||||
/**
|
||||
* 错误原因
|
||||
*/
|
||||
@Schema(description = "错误原因")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
@Schema(description = "完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ package cn.bootx.platform.daxpay.service.dto.order.pay;
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.AllocationOrderStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -71,7 +71,7 @@ public class PayOrderDto extends BaseDto {
|
||||
|
||||
/**
|
||||
* 分账状态
|
||||
* @see AllocationStatusEnum
|
||||
* @see AllocationOrderStatusEnum
|
||||
*/
|
||||
@Schema(description = "分账状态")
|
||||
private String allocationStatus;
|
||||
|
@@ -44,4 +44,9 @@ public abstract class AbsAllocationStrategy implements PayStrategy{
|
||||
* 分账完结
|
||||
*/
|
||||
public abstract void finish();
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
public abstract void doSync();
|
||||
}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 抽象的分账状态同步策略
|
||||
* @author xxm
|
||||
* @since 2024/4/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class AbsAllocationSyncStrategy implements PayStrategy{
|
||||
|
||||
private AllocationOrder allocationOrder;
|
||||
|
||||
/**
|
||||
* 初始化参数
|
||||
*/
|
||||
public void initPayParam(AllocationOrder allocationOrder) {
|
||||
this.allocationOrder = allocationOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步状态
|
||||
*/
|
||||
public abstract void doSyncStatus();
|
||||
|
||||
|
||||
}
|
@@ -159,7 +159,7 @@ dax-pay:
|
||||
# 服务地址
|
||||
server-url: http://localhost:9000
|
||||
# 前端h5地址
|
||||
front-h5-url: http://localhost:5173/#
|
||||
front-h5-url: http://pay1.bootx.cn/h5/#
|
||||
# 前端web地址
|
||||
front-web-url: http://localhost:9000/#
|
||||
# 演示模块
|
||||
@@ -167,7 +167,7 @@ dax-pay:
|
||||
# 网关地址
|
||||
server-url: http://localhost:9000
|
||||
# 前端h5地址
|
||||
front-h5-url: http://localhost:5173/#
|
||||
front-h5-url: http://pay1.bootx.cn/h5/#
|
||||
# 签名秘钥
|
||||
sign-secret: 123456
|
||||
# 签名方式
|
||||
|
Reference in New Issue
Block a user