feat 自动分账/状态同步/自动完结

This commit is contained in:
DaxPay
2024-05-06 21:13:39 +08:00
parent dfbdc83b62
commit d133957e63
11 changed files with 265 additions and 115 deletions

View File

@@ -32,12 +32,13 @@
- [x] 支付订单和退款订单页面添加实时金额汇总展示 - [x] 支付订单和退款订单页面添加实时金额汇总展示
- [ ] 自动分账改造 - [ ] 自动分账改造
- [ ] SDK新增对账接收放添加接口 - [ ] SDK新增对账接收放添加接口
- [ ] 创建定时任务, 自动对待分账订单进行分账 - [x] 创建定时任务, 自动对待分账订单进行分账
- [ ] 增加定时同步分账状态任务 - [x] 增加定时同步分账状态任务
- [ ] 增加自动完结功能 - [x] 增加自动完结功能
2.0.7: 分账完善和基础架构优化 2.0.7: 分账完善和基础架构优化
- [ ] 资金流水优化 - [ ] 资金流水优化
- [ ] 数据加密方式改为类型处理器模式 - [ ] 数据加密方式改为类型处理器模式
- [ ]
- [ ] 支持分账组分账和自己传接收方进行分账 - [ ] 支持分账组分账和自己传接收方进行分账
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能 - [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
- [ ] 分账接收方管理提供接口调用 - [ ] 分账接收方管理提供接口调用

View File

@@ -19,6 +19,7 @@ import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDetailDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto; import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderExtraDto; import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderExtraDto;
import cn.bootx.platform.daxpay.service.param.order.PayOrderQuery; import cn.bootx.platform.daxpay.service.param.order.PayOrderQuery;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -100,6 +101,7 @@ public class PayOrderController {
public ResResult<Void> allocation(String orderNo){ public ResResult<Void> allocation(String orderNo){
AllocationStartParam param = new AllocationStartParam(); AllocationStartParam param = new AllocationStartParam();
param.setOrderNo(orderNo); param.setOrderNo(orderNo);
param.setBizAllocationNo(OrderNoGenerateUtil.allocation());
allocationService.allocation(param); allocationService.allocation(param);
return Res.ok(); return Res.ok();
} }

View File

@@ -5,6 +5,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
/** /**
* 开始分账请求参数 * 开始分账请求参数
* @author xxm * @author xxm
@@ -16,6 +18,7 @@ import lombok.EqualsAndHashCode;
public class AllocationStartParam extends PaymentCommonParam { public class AllocationStartParam extends PaymentCommonParam {
@Schema(description = "商户分账单号") @Schema(description = "商户分账单号")
@NotBlank(message = "商户分账单号不可为空")
private String bizAllocationNo; private String bizAllocationNo;
@Schema(description = "支付订单号") @Schema(description = "支付订单号")

View File

@@ -4,6 +4,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager; import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil; import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.common.query.generator.QueryGenerator; import cn.bootx.platform.common.query.generator.QueryGenerator;
import cn.bootx.platform.daxpay.code.AllocOrderStatusEnum;
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder; import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrder;
import cn.bootx.platform.daxpay.service.param.order.AllocationOrderQuery; import cn.bootx.platform.daxpay.service.param.order.AllocationOrderQuery;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -12,6 +13,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
@@ -46,4 +49,14 @@ public class AllocationOrderManager extends BaseManager<AllocationOrderMapper, A
QueryWrapper<AllocationOrder> generator = QueryGenerator.generator(param); QueryWrapper<AllocationOrder> generator = QueryGenerator.generator(param);
return this.page(mpPage, generator); return this.page(mpPage, generator);
} }
/**
* 查询待同步的分账单
*/
public List<AllocationOrder> findSyncOrder(){
List<String> statusList = Arrays.asList(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode(), AllocOrderStatusEnum.ALLOCATION_END.getCode());
return lambdaQuery()
.in(AllocationOrder::getStatus, statusList)
.list();
}
} }

View File

@@ -4,6 +4,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager; import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil; import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.common.query.generator.QueryGenerator; import cn.bootx.platform.common.query.generator.QueryGenerator;
import cn.bootx.platform.daxpay.code.PayOrderAllocStatusEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum; import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.param.order.PayOrderQuery; import cn.bootx.platform.daxpay.service.param.order.PayOrderQuery;
@@ -17,7 +18,6 @@ import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
/** /**
* 支付订单 * 支付订单
@@ -57,10 +57,11 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
/** /**
* 查询对账用订单记录(指定时间和状态的订单) * 查询对账用订单记录(指定时间和状态的订单)
*/ */
public List<PayOrder> findReconcile(String channel, LocalDateTime startTime, LocalDateTime endTime, PayStatusEnum...statusEnum) { public List<PayOrder> findReconcile(String channel, LocalDateTime startTime, LocalDateTime endTime) {
List<String> status = Arrays.stream(statusEnum) List<String> status = Arrays.asList(PayStatusEnum.SUCCESS.getCode(),
.map(PayStatusEnum::getCode) PayStatusEnum.PARTIAL_REFUND.getCode(),
.collect(Collectors.toList()); PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.REFUNDED.getCode());
return this.lambdaQuery() return this.lambdaQuery()
.eq(PayOrder::getChannel, channel) .eq(PayOrder::getChannel, channel)
.between(PayOrder::getPayTime, startTime, endTime) .between(PayOrder::getPayTime, startTime, endTime)
@@ -68,6 +69,21 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
.list(); .list();
} }
/**
* 查询自动分账用订单记录(指定时间和状态的订单)
*/
public List<PayOrder> findAllocation() {
List<String> status = Arrays.asList(PayStatusEnum.SUCCESS.getCode(),
PayStatusEnum.PARTIAL_REFUND.getCode(),
PayStatusEnum.REFUNDING.getCode(),
PayStatusEnum.REFUNDED.getCode());
return this.lambdaQuery()
.eq(PayOrder::getAllocation, true)
.eq(PayOrder::getAllocationStatus, PayOrderAllocStatusEnum.WAITING.getCode())
.in(PayOrder::getStatus, status)
.list();
}
/** /**
* 查询汇总金额 * 查询汇总金额
*/ */

View File

@@ -16,10 +16,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
/** /**
* 支付退款订单管理 * 支付退款订单管理
@@ -77,14 +75,11 @@ public class RefundOrderManager extends BaseManager<RefundOrderMapper, RefundOrd
/** /**
* 查询对账用订单记录(指定时间和状态的订单) * 查询对账用订单记录(指定时间和状态的订单)
*/ */
public List<RefundOrder> findReconcile(String channel, LocalDateTime startTime, LocalDateTime endTime, RefundStatusEnum...statusEnum) { public List<RefundOrder> findReconcile(String channel, LocalDateTime startTime, LocalDateTime endTime) {
List<String> status = Arrays.stream(statusEnum)
.map(RefundStatusEnum::getCode)
.collect(Collectors.toList());
return this.lambdaQuery() return this.lambdaQuery()
.eq(RefundOrder::getChannel, channel) .eq(RefundOrder::getChannel, channel)
.between(RefundOrder::getFinishTime, startTime, endTime) .between(RefundOrder::getFinishTime, startTime, endTime)
.in(RefundOrder::getStatus, status) .eq(RefundOrder::getStatus, RefundStatusEnum.SUCCESS)
.list(); .list();
} }

View File

@@ -1,16 +0,0 @@
package cn.bootx.platform.daxpay.service.core.payment.allocation.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 分账订单同步服务
* @author xxm
* @since 2024/4/7
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AllocationOrderSyncService {
}

View File

@@ -1,15 +1,16 @@
package cn.bootx.platform.daxpay.service.core.payment.allocation.service; package cn.bootx.platform.daxpay.service.core.payment.allocation.service;
import cn.bootx.platform.common.core.exception.DataNotExistException; import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.daxpay.code.AllocDetailResultEnum; import cn.bootx.platform.daxpay.code.AllocDetailResultEnum;
import cn.bootx.platform.daxpay.code.AllocOrderResultEnum; import cn.bootx.platform.daxpay.code.AllocOrderResultEnum;
import cn.bootx.platform.daxpay.code.AllocOrderStatusEnum; import cn.bootx.platform.daxpay.code.AllocOrderStatusEnum;
import cn.bootx.platform.daxpay.code.PayOrderAllocStatusEnum; import cn.bootx.platform.daxpay.code.PayOrderAllocStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException; import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationSyncParam;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationFinishParam; import cn.bootx.platform.daxpay.param.payment.allocation.AllocationFinishParam;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationResetParam; import cn.bootx.platform.daxpay.param.payment.allocation.AllocationResetParam;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationStartParam; import cn.bootx.platform.daxpay.param.payment.allocation.AllocationStartParam;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationSyncParam;
import cn.bootx.platform.daxpay.result.allocation.AllocationResult; import cn.bootx.platform.daxpay.result.allocation.AllocationResult;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.allocation.dao.AllocationOrderDetailManager; import cn.bootx.platform.daxpay.service.core.order.allocation.dao.AllocationOrderDetailManager;
@@ -18,7 +19,6 @@ import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationO
import cn.bootx.platform.daxpay.service.core.order.allocation.entity.AllocationOrderDetail; 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.allocation.entity.OrderAndDetail;
import cn.bootx.platform.daxpay.service.core.order.allocation.service.AllocationOrderService; import cn.bootx.platform.daxpay.service.core.order.allocation.service.AllocationOrderService;
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.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService; import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
import cn.bootx.platform.daxpay.service.core.payment.allocation.dao.AllocationGroupManager; import cn.bootx.platform.daxpay.service.core.payment.allocation.dao.AllocationGroupManager;
@@ -26,6 +26,8 @@ import cn.bootx.platform.daxpay.service.core.payment.allocation.entity.Allocatio
import cn.bootx.platform.daxpay.service.core.payment.allocation.factory.AllocationFactory; import cn.bootx.platform.daxpay.service.core.payment.allocation.factory.AllocationFactory;
import cn.bootx.platform.daxpay.service.dto.allocation.AllocationGroupReceiverResult; import cn.bootx.platform.daxpay.service.dto.allocation.AllocationGroupReceiverResult;
import cn.bootx.platform.daxpay.service.func.AbsAllocationStrategy; import cn.bootx.platform.daxpay.service.func.AbsAllocationStrategy;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -46,8 +48,6 @@ import java.util.Objects;
@RequiredArgsConstructor @RequiredArgsConstructor
public class AllocationService { public class AllocationService {
private final PayOrderManager payOrderManager;
private final AllocationGroupManager groupManager; private final AllocationGroupManager groupManager;
private final AllocationOrderManager allocationOrderManager; private final AllocationOrderManager allocationOrderManager;
@@ -58,55 +58,70 @@ public class AllocationService {
private final AllocationOrderDetailManager allocationOrderDetailManager; private final AllocationOrderDetailManager allocationOrderDetailManager;
private final PayOrderQueryService payOrderQueryService; private final PayOrderQueryService payOrderQueryService;
private final LockTemplate lockTemplate;
/** /**
* 开启分账, 使用分账组进行分账 * 开启分账, 使用分账组进行分账
*/ */
public AllocationResult allocation(AllocationStartParam param) { public AllocationResult allocation(AllocationStartParam param) {
PayOrder payOrder = this.getAndCheckPayOrder(param); PayOrder payOrder = this.getAndCheckPayOrder(param);
// 查询分账组 未传输使用默认该通道默认分账组 return this.allocation(payOrder, param);
AllocationGroup allocationGroup; }
if (Objects.nonNull(param.getAllocationGroupId())) {
allocationGroup = groupManager.findById(param.getAllocationGroupId()).orElseThrow(() -> new DataNotExistException("未查询到分账组")); /**
} else { * 开启分账, 未传输默认分账组, 则使用默认该通道默认分账组
allocationGroup = groupManager.findDefaultGroup(payOrder.getChannel()).orElseThrow(() -> new DataNotExistException("未查询到默认分账组")); */
public AllocationResult allocation(PayOrder payOrder, AllocationStartParam param) {
LockInfo lock = lockTemplate.lock("payment:allocation:" + payOrder.getId(),10000,200);
if (Objects.isNull(lock)){
throw new RepetitiveOperationException("分账发起处理中,请勿重复操作");
} }
List<AllocationGroupReceiverResult> receiversByGroups = allocationGroupService.findReceiversByGroups(allocationGroup.getId());
// 创建分账单和明细并保存, 同时更新支付订单状态 使用事务
OrderAndDetail orderAndDetail = allocationOrderService.createAndUpdate(param ,payOrder, payOrder.getAmount(), receiversByGroups);
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(payOrder.getChannel());
AllocationOrder order = orderAndDetail.getOrder();
List<AllocationOrderDetail> details = orderAndDetail.getDetails();
allocationStrategy.initParam(order, details);
// 分账预处理
allocationStrategy.doBeforeHandler();
try { try {
// 分账处理 // 查询默认分账组
allocationStrategy.allocation(); AllocationGroup allocationGroup;
// 执行中 if (Objects.nonNull(param.getAllocationGroupId())) {
order.setStatus(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode()) allocationGroup = groupManager.findById(param.getAllocationGroupId()).orElseThrow(() -> new DataNotExistException("未查询到分账组"));
.setErrorMsg(null); } else {
} catch (Exception e) { allocationGroup = groupManager.findDefaultGroup(payOrder.getChannel()).orElseThrow(() -> new DataNotExistException("未查询到默认分账组"));
log.error("分账出现错误:", e); }
// 失败 List<AllocationGroupReceiverResult> receiversByGroups = allocationGroupService.findReceiversByGroups(allocationGroup.getId());
order.setStatus(AllocOrderStatusEnum.ALLOCATION_FAILED.getCode()) // 创建分账单和明细并保存, 同时更新支付订单状态 使用事务
.setErrorMsg(e.getMessage()); OrderAndDetail orderAndDetail = allocationOrderService.createAndUpdate(param ,payOrder, payOrder.getAmount(), receiversByGroups);
}
// 网关分账号
String gatewayNo = PaymentContextLocal.get()
.getAllocationInfo()
.getOutAllocationNo();
order.setOutAllocationNo(gatewayNo);
allocationOrderManager.updateById(order);
return new AllocationResult().setOrderId(order.getId()) // 创建分账策略并初始化
.setAllocationNo(order.getAllocationNo()) AbsAllocationStrategy allocationStrategy = AllocationFactory.create(payOrder.getChannel());
.setStatus(order.getStatus()); AllocationOrder order = orderAndDetail.getOrder();
List<AllocationOrderDetail> details = orderAndDetail.getDetails();
allocationStrategy.initParam(order, details);
// 分账预处理
allocationStrategy.doBeforeHandler();
try {
// 分账处理
allocationStrategy.allocation();
// 执行中
order.setStatus(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
.setErrorMsg(null);
} catch (Exception e) {
log.error("分账出现错误:", e);
// 失败
order.setStatus(AllocOrderStatusEnum.ALLOCATION_FAILED.getCode())
.setErrorMsg(e.getMessage());
}
// 网关分账号
String gatewayNo = PaymentContextLocal.get()
.getAllocationInfo()
.getOutAllocationNo();
order.setOutAllocationNo(gatewayNo);
allocationOrderManager.updateById(order);
return new AllocationResult().setOrderId(order.getId())
.setAllocationNo(order.getAllocationNo())
.setStatus(order.getStatus());
} finally {
lockTemplate.releaseLock(lock);
}
} }
/** /**
@@ -121,35 +136,44 @@ public class AllocationService {
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo()) allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
.orElseThrow(() -> new DataNotExistException("未查询到分账单信息")); .orElseThrow(() -> new DataNotExistException("未查询到分账单信息"));
} }
// 需要是分账中分账中或者完成状态才能重新分账 LockInfo lock = lockTemplate.lock("payment:allocation:" + allocationOrder.getOrderId(),10000,200);
List<String> list = Arrays.asList(AllocOrderStatusEnum.ALLOCATION_END.getCode(), if (Objects.isNull(lock)){
AllocOrderStatusEnum.ALLOCATION_FAILED.getCode(), throw new RepetitiveOperationException("分账发起处理中,请勿重复操作");
AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode());
if (!list.contains(allocationOrder.getStatus())){
throw new PayFailureException("分账单状态错误");
} }
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
allocationStrategy.initParam(allocationOrder, details);
// 分账预处理
allocationStrategy.doBeforeHandler();
try { try {
// 重复分账处理 // 需要是分账中分账中或者完成状态才能重新分账
allocationStrategy.allocation(); List<String> list = Arrays.asList(AllocOrderStatusEnum.ALLOCATION_END.getCode(),
allocationOrder.setStatus(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode()) AllocOrderStatusEnum.ALLOCATION_FAILED.getCode(),
.setErrorMsg(null); AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode());
if (!list.contains(allocationOrder.getStatus())){
throw new PayFailureException("分账单状态错误");
}
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
allocationStrategy.initParam(allocationOrder, details);
// 分账预处理
allocationStrategy.doBeforeHandler();
try {
// 重复分账处理
allocationStrategy.allocation();
allocationOrder.setStatus(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
.setErrorMsg(null);
} catch (Exception e) {
log.error("重新分账出现错误:", e);
// 失败
allocationOrder.setStatus(AllocOrderStatusEnum.ALLOCATION_FAILED.getCode())
.setErrorMsg(e.getMessage());
}
allocationOrderManager.updateById(allocationOrder);
} finally {
} catch (Exception e) {
log.error("重新分账出现错误:", e);
// 失败
allocationOrder.setStatus(AllocOrderStatusEnum.ALLOCATION_FAILED.getCode())
.setErrorMsg(e.getMessage());
} }
allocationOrderManager.updateById(allocationOrder);
} }
/** /**
@@ -164,6 +188,13 @@ public class AllocationService {
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo()) allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
.orElseThrow(() -> new DataNotExistException("未查询到分账单信息")); .orElseThrow(() -> new DataNotExistException("未查询到分账单信息"));
} }
this.finish(allocationOrder);
}
/**
* 分账完结
*/
public void finish(AllocationOrder allocationOrder) {
// 只有分账结束后才可以完结 // 只有分账结束后才可以完结
if (!AllocOrderStatusEnum.ALLOCATION_END.getCode().equals(allocationOrder.getStatus())){ if (!AllocOrderStatusEnum.ALLOCATION_END.getCode().equals(allocationOrder.getStatus())){
throw new PayFailureException("分账单状态错误"); throw new PayFailureException("分账单状态错误");
@@ -206,19 +237,34 @@ public class AllocationService {
allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo()) allocationOrder = allocationOrderManager.findByAllocationNo(param.getAllocationNo())
.orElseThrow(() -> new DataNotExistException("分账单不存在")); .orElseThrow(() -> new DataNotExistException("分账单不存在"));
} }
List<AllocationOrderDetail> detailList = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId()); this.sync(allocationOrder);
// 获取分账策略 }
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
allocationStrategy.initParam(allocationOrder, detailList);
// 分账完结预处理
allocationStrategy.doBeforeHandler();
allocationStrategy.doSync();
// 根据订单明细更新订单的状态和处理结果 /**
this.updateOrderStatus(allocationOrder, detailList); * 分账同步
*/
public void sync(AllocationOrder allocationOrder){
LockInfo lock = lockTemplate.lock("payment:allocation:" + allocationOrder.getOrderId(),10000,200);
if (Objects.isNull(lock)){
throw new RepetitiveOperationException("分账同步中,请勿重复操作");
}
try {
List<AllocationOrderDetail> detailList = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
// 获取分账策略
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
allocationStrategy.initParam(allocationOrder, detailList);
// 分账完结预处理
allocationStrategy.doBeforeHandler();
allocationStrategy.doSync();
allocationOrderDetailManager.updateAllById(detailList); // 根据订单明细更新订单的状态和处理结果
allocationOrderManager.updateById(allocationOrder); this.updateOrderStatus(allocationOrder, detailList);
allocationOrderDetailManager.updateAllById(detailList);
allocationOrderManager.updateById(allocationOrder);
} finally {
lockTemplate.releaseLock(lock);
}
} }
/** /**

View File

@@ -3,16 +3,14 @@ package cn.bootx.platform.daxpay.service.core.payment.reconcile.service;
import cn.bootx.platform.common.core.function.CollectorsFunction; import cn.bootx.platform.common.core.function.CollectorsFunction;
import cn.bootx.platform.common.core.util.CollUtil; import cn.bootx.platform.common.core.util.CollUtil;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil; import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.code.ReconcileTradeEnum; import cn.bootx.platform.daxpay.code.ReconcileTradeEnum;
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum; import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
import cn.bootx.platform.daxpay.service.code.ReconcileDiffTypeEnum; import cn.bootx.platform.daxpay.service.code.ReconcileDiffTypeEnum;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager; 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.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff; import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder; import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager; import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder; import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralTradeInfo; import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralTradeInfo;
@@ -55,8 +53,8 @@ public class ReconcileAssistService {
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime); LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
// 下载支付订单 // 下载支付订单
List<PayOrder> payOrders = payOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, PayStatusEnum.SUCCESS, PayStatusEnum.PARTIAL_REFUND, PayStatusEnum.REFUNDING, PayStatusEnum.REFUNDED); List<PayOrder> payOrders = payOrderManager.findReconcile(reconcileOrder.getChannel(), start, end);
List<RefundOrder> refundOrders = refundOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, RefundStatusEnum.SUCCESS); List<RefundOrder> refundOrders = refundOrderManager.findReconcile(reconcileOrder.getChannel(), start, end);
for (PayOrder payOrder : payOrders) { for (PayOrder payOrder : payOrders) {
generalTradeInfoList.add(new GeneralTradeInfo() generalTradeInfoList.add(new GeneralTradeInfo()
.setTitle(payOrder.getTitle()) .setTitle(payOrder.getTitle())

View File

@@ -0,0 +1,42 @@
package cn.bootx.platform.daxpay.service.task;
import cn.bootx.platform.daxpay.param.payment.allocation.AllocationStartParam;
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.core.payment.allocation.service.AllocationService;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Component;
/**
* 自动分账定时任务, 10s一次
* @author xxm
* @since 2024/5/6
*/
@Slf4j
@Component
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@RequiredArgsConstructor
public class AllocationAutoStartTask implements Job {
private final PayOrderManager payOrderManager;
private final AllocationService allocationService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
for (PayOrder payOrder : payOrderManager.findAllocation()) {
AllocationStartParam param = new AllocationStartParam();
param.setBizAllocationNo(OrderNoGenerateUtil.allocation());
try {
allocationService.allocation(payOrder, param);
} catch (Exception e) {
log.warn("自动分账失败, 支付订单号: {}", payOrder.getOrderNo());
log.warn("自动分账失败:{}", e.getMessage());
}
}
}
}

View File

@@ -0,0 +1,50 @@
package cn.bootx.platform.daxpay.service.task;
import cn.bootx.platform.daxpay.code.AllocOrderStatusEnum;
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.service.AllocationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Component;
/**
* 自动分账信息同步和完结接口 10s一次
* @author xxm
* @since 2024/5/6
*/
@Slf4j
@Component
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@RequiredArgsConstructor
public class AllocationSyncTask implements Job {
private final AllocationOrderManager allocationOrderManager;
private final AllocationService allocationService;
/**
* 分账同步
*/
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
for (AllocationOrder allocationOrder : allocationOrderManager.findSyncOrder()) {
try {
// 分账中走同步逻辑
if (allocationOrder.getStatus().equals(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode())) {
allocationService.sync(allocationOrder);
}
// 如果分账结束, 调用自动完结逻辑
if (allocationOrder.getStatus().equals(AllocOrderStatusEnum.ALLOCATION_END.getCode())) {
allocationService.finish(allocationOrder);
}
} catch (Exception e) {
log.warn("分账同步或完结失败, 分账号:{}", allocationOrder.getAllocationNo());
log.warn("分账同步或完结失败", e);
}
}
}
}