mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-03 11:06:46 +00:00
feat 支付对账开发, 调整支付宝流水表数据结构, 支付修复策略问题调试
This commit is contained in:
@@ -5,7 +5,6 @@ import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.PayReconcileOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.PayReconcileQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.service.PayReconcileService;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.PayReconcileDetailDto;
|
||||
@@ -29,14 +28,13 @@ import org.springframework.web.bind.annotation.*;
|
||||
@RequiredArgsConstructor
|
||||
public class PayReconcileOrderController {
|
||||
private final PayReconcileService reconcileService;
|
||||
private final PayReconcileOrderService reconcileOrderService;
|
||||
private final PayReconcileQueryService reconcileQueryService;
|
||||
|
||||
@Operation(summary = "手动创建支付对账订单")
|
||||
@PostMapping("/create")
|
||||
public ResResult<Void> create(@RequestBody ReconcileOrderCreate param){
|
||||
ValidationUtil.validateParam(param);
|
||||
reconcileOrderService.create(param.getDate(), param.getChannel());
|
||||
reconcileService.create(param.getDate(), param.getChannel());
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@@ -47,6 +45,13 @@ public class PayReconcileOrderController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "手动触发对账单比对")
|
||||
@PostMapping("/compare")
|
||||
public ResResult<Void> compare(Long id){
|
||||
reconcileService.compare(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "订单分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<PayReconcileOrderDto>> page(PageParam pageParam, ReconcileOrderQuery query){
|
||||
|
@@ -4,7 +4,6 @@ import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcile
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -19,8 +18,4 @@ public class ReconcileLocal {
|
||||
/** 通用支付对账记录 */
|
||||
private List<PayReconcileDetail> reconcileDetails;
|
||||
|
||||
|
||||
/** 支付完成时间 从支付网关中获取 */
|
||||
private LocalDateTime payTime;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,34 @@
|
||||
package cn.bootx.platform.daxpay.service.configuration.sequence;
|
||||
|
||||
import cn.bootx.platform.common.sequence.func.Sequence;
|
||||
import cn.bootx.platform.common.sequence.range.SeqRangeManager;
|
||||
import cn.bootx.platform.common.sequence.util.SequenceUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 序列生成器配置类
|
||||
* @author xxm
|
||||
* @since 2024/2/28
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class DaxPaySequenceConfiguration {
|
||||
|
||||
/**
|
||||
* 支付宝对账单序列生成器
|
||||
*/
|
||||
@Bean
|
||||
public Sequence alipayReconcileSequence(SeqRangeManager seqRangeManager) {
|
||||
return SequenceUtil.create(1,1,1,"AlipayReconcileSequence");
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信对账单序列生成器
|
||||
*/
|
||||
@Bean
|
||||
public Sequence wechatReconcileSequence(SeqRangeManager seqRangeManager) {
|
||||
return SequenceUtil.create(1,1,1,"WechatReconcileSequence");
|
||||
}
|
||||
}
|
@@ -12,6 +12,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
@@ -31,4 +34,13 @@ public class AliPayRecordManager extends BaseManager<AliPayRecordMapper, AliPayR
|
||||
QueryWrapper<AliPayRecord> generator = QueryGenerator.generator(param);
|
||||
return this.page(mpPage, generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间范围查询
|
||||
*/
|
||||
public List<AliPayRecord> findByDate(LocalDateTime startDate, LocalDateTime endDate){
|
||||
return this.lambdaQuery()
|
||||
.between(AliPayRecord::getGatewayTime, startDate, endDate)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 支付宝流水记录
|
||||
* @author xxm
|
||||
@@ -47,6 +49,10 @@ public class AliPayRecord extends MpCreateEntity implements EntityBaseFunction<A
|
||||
@DbColumn(comment = "网关订单号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 网关完成时间 */
|
||||
@DbColumn(comment = "网关完成时间")
|
||||
private LocalDateTime gatewayTime;
|
||||
|
||||
@Override
|
||||
public AliPayRecordDto toDto() {
|
||||
return AlipayConvert.CONVERT.convert(this);
|
||||
|
@@ -138,14 +138,14 @@ public class AliPayReconcileService {
|
||||
// 默认为支付对账记录
|
||||
PayReconcileDetail payReconcileDetail = new PayReconcileDetail()
|
||||
.setRecordOrderId(billDetail.getRecordOrderId())
|
||||
.setPaymentId(billDetail.getOutTradeNo())
|
||||
.setOrderId(billDetail.getOutTradeNo())
|
||||
.setType(PayReconcileTradeEnum.PAY.getCode())
|
||||
.setAmount(amount)
|
||||
.setTitle(billDetail.getSubject())
|
||||
.setGatewayOrderNo(billDetail.getTradeNo());
|
||||
// 退款覆盖更新对应的字段
|
||||
if (Objects.equals(billDetail.getTradeType(), "退款")){
|
||||
payReconcileDetail.setRefundId(billDetail.getBatchNo())
|
||||
payReconcileDetail.setOrderId(billDetail.getBatchNo())
|
||||
.setType(PayReconcileTradeEnum.REFUND.getCode());
|
||||
}
|
||||
|
||||
|
@@ -37,8 +37,9 @@ public class AliPayRecordService {
|
||||
.setType(AliPayRecordTypeEnum.PAY.getCode())
|
||||
.setTitle(order.getTitle())
|
||||
.setOrderId(order.getId())
|
||||
.setAmount(channelOrder.getAmount())
|
||||
.setGatewayOrderNo(order.getGatewayOrderNo())
|
||||
.setAmount(channelOrder.getAmount());
|
||||
.setGatewayTime(channelOrder.getPayTime());
|
||||
aliPayRecordManager.save(aliPayRecord);
|
||||
}
|
||||
|
||||
@@ -50,8 +51,9 @@ public class AliPayRecordService {
|
||||
.setType(AliPayRecordTypeEnum.REFUND.getCode())
|
||||
.setTitle(order.getTitle())
|
||||
.setOrderId(order.getId())
|
||||
.setAmount(channelOrder.getAmount())
|
||||
.setGatewayOrderNo(order.getGatewayOrderNo())
|
||||
.setAmount(channelOrder.getAmount());
|
||||
.setGatewayTime(channelOrder.getRefundTime());
|
||||
aliPayRecordManager.save(aliPayRecord);
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
@@ -30,4 +33,13 @@ public class WeChatPayRecordManager extends BaseManager<WeChatPayRecordMapper, W
|
||||
QueryWrapper<WeChatPayRecord> generator = QueryGenerator.generator(param);
|
||||
return this.page(mpPage, generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间范围查询
|
||||
*/
|
||||
public List<WeChatPayRecord> findByDate(LocalDateTime start, LocalDateTime end) {
|
||||
return this.lambdaQuery()
|
||||
.between(WeChatPayRecord::getGatewayTime, start, end)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信支付记录
|
||||
* @author xxm
|
||||
@@ -47,6 +49,10 @@ public class WeChatPayRecord extends MpCreateEntity implements EntityBaseFunctio
|
||||
@DbColumn(comment = "网关订单号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 网关完成时间 */
|
||||
@DbColumn(comment = "网关完成时间")
|
||||
private LocalDateTime gatewayTime;
|
||||
|
||||
@Override
|
||||
public WeChatPayRecordDto toDto() {
|
||||
return WeChatConvert.CONVERT.convert(this);
|
||||
|
@@ -36,8 +36,9 @@ public class WeChatPayRecordService {
|
||||
.setType(WechatPayRecordTypeEnum.PAY.getCode())
|
||||
.setTitle(order.getTitle())
|
||||
.setOrderId(order.getId())
|
||||
.setAmount(channelOrder.getAmount())
|
||||
.setGatewayOrderNo(order.getGatewayOrderNo())
|
||||
.setAmount(channelOrder.getAmount());
|
||||
.setGatewayTime(channelOrder.getPayTime());
|
||||
weChatPayRecordManager.save(weChatPayRecord);
|
||||
}
|
||||
|
||||
@@ -49,8 +50,9 @@ public class WeChatPayRecordService {
|
||||
.setType(WechatPayRecordTypeEnum.REFUND.getCode())
|
||||
.setTitle(order.getTitle())
|
||||
.setOrderId(order.getId())
|
||||
.setAmount(channelOrder.getAmount())
|
||||
.setGatewayOrderNo(order.getGatewayOrderNo())
|
||||
.setAmount(channelOrder.getAmount());
|
||||
.setGatewayTime(channelOrder.getRefundTime());
|
||||
weChatPayRecordManager.save(weChatPayRecord);
|
||||
}
|
||||
|
||||
|
@@ -118,7 +118,7 @@ public class WechatPayReconcileService{
|
||||
// 默认为支付对账记录
|
||||
PayReconcileDetail payReconcileDetail = new PayReconcileDetail()
|
||||
.setRecordOrderId(billDetail.getRecordOrderId())
|
||||
.setPaymentId(billDetail.getMchOrderNo())
|
||||
.setOrderId(billDetail.getMchOrderNo())
|
||||
.setTitle(billDetail.getSubject())
|
||||
.setGatewayOrderNo(billDetail.getWeiXinOrderNo());
|
||||
// 支付
|
||||
@@ -138,7 +138,7 @@ public class WechatPayReconcileService{
|
||||
int amount = Math.abs(((int) v));
|
||||
payReconcileDetail.setType(PayReconcileTradeEnum.REFUND.getCode())
|
||||
.setAmount(amount)
|
||||
.setRefundId(billDetail.getMchRefundNo());
|
||||
.setOrderId(billDetail.getMchRefundNo());
|
||||
}
|
||||
// TODO 已撤销, 暂时未处理
|
||||
if (Objects.equals(billDetail.getStatus(), "REVOKED")){
|
||||
|
@@ -58,6 +58,7 @@ public class PayChannelOrder extends MpCreateEntity implements EntityBaseFunctio
|
||||
private String status;
|
||||
|
||||
@DbColumn(comment = "支付时间")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private LocalDateTime payTime;
|
||||
|
||||
|
||||
|
@@ -10,6 +10,8 @@ import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
|
||||
import cn.bootx.table.modify.mysql.constants.MySqlIndexType;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -76,10 +78,12 @@ public class PayOrder extends MpBaseEntity implements EntityBaseFunction<PayOrde
|
||||
|
||||
/** 支付时间 */
|
||||
@DbColumn(comment = "支付时间")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private LocalDateTime payTime;
|
||||
|
||||
/** 关闭时间 */
|
||||
@DbColumn(comment = "支付时间")
|
||||
@DbColumn(comment = "关闭时间")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private LocalDateTime closeTime;
|
||||
|
||||
/** 过期时间 */
|
||||
|
@@ -12,6 +12,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
@@ -22,6 +24,14 @@ import org.springframework.stereotype.Repository;
|
||||
@RequiredArgsConstructor
|
||||
public class PayReconcileDetailManager extends BaseManager<PayReconcileDetailMapper, PayReconcileDetail> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据订单id查询
|
||||
*/
|
||||
public List<PayReconcileDetail> findAllByOrderId(Long orderId){
|
||||
return this.findAllByField(PayReconcileDetail::getRecordOrderId, orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
|
@@ -45,6 +45,10 @@ public class PayReconcileDetail extends MpCreateEntity implements EntityBaseFunc
|
||||
|
||||
/** 本地订单ID */
|
||||
@DbColumn(comment = "本地订单ID")
|
||||
private String orderId;
|
||||
|
||||
/** 支付订单ID */
|
||||
@DbColumn(comment = "本地订单ID")
|
||||
private String paymentId;
|
||||
|
||||
/** 本地退款ID */
|
||||
|
@@ -55,9 +55,6 @@ public class PayReconcileOrder extends MpCreateEntity implements EntityBaseFunct
|
||||
@DbColumn(comment = "错误信息")
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PayReconcileOrderDto toDto() {
|
||||
return PayReconcileConvert.CONVERT.convert(this);
|
||||
|
@@ -1,19 +1,14 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.reconcile.service;
|
||||
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.sequence.func.Sequence;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.PayReconcileOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileOrder;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -43,37 +38,4 @@ public class PayReconcileOrderService {
|
||||
return reconcileOrderManager.findById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建对账订单
|
||||
*/
|
||||
public PayReconcileOrder create(LocalDate date,String channel) {
|
||||
// 获取通道枚举
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
|
||||
// 判断是否为为异步通道
|
||||
if (!PayChannelEnum.ASYNC_TYPE.contains(channelEnum)){
|
||||
throw new PayFailureException("不支持对账的通道, 请检查");
|
||||
}
|
||||
// 生成批次号
|
||||
String format = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
|
||||
String key = channelEnum.getReconcilePrefix()+format;
|
||||
String seqNo = key + this.genSeqNo(key);
|
||||
|
||||
PayReconcileOrder order = new PayReconcileOrder()
|
||||
.setBatchNo(seqNo)
|
||||
.setChannel(channel)
|
||||
.setDate(date);
|
||||
reconcileOrderManager.save(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成批次号
|
||||
* 规则:通道简称 + yyyyMMdd + 两位流水号
|
||||
* 例子:wx2024012001、ali2024012002
|
||||
*/
|
||||
private String genSeqNo(String key){
|
||||
long next = sequence.next(key);
|
||||
return String.format("%02d",next);
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.PayReconcileDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.PayReconcileOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.PayReconcileOrderService;
|
||||
@@ -11,7 +14,10 @@ import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -23,9 +29,36 @@ import java.util.List;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayReconcileService {
|
||||
private final PayReconcileOrderManager reconcileOrderManager;
|
||||
private final PayReconcileOrderService reconcileOrderService;
|
||||
private final PayReconcileDetailManager reconcileDetailManager;
|
||||
|
||||
/**
|
||||
* 创建对账订单
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public PayReconcileOrder create(LocalDate date, String channel) {
|
||||
|
||||
// 获取通道枚举
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
|
||||
// 判断是否为为异步通道
|
||||
if (!PayChannelEnum.ASYNC_TYPE.contains(channelEnum)){
|
||||
throw new PayFailureException("不支持对账的通道, 请检查");
|
||||
}
|
||||
// 构建对账策略
|
||||
AbsReconcileStrategy reconcileStrategy = PayReconcileStrategyFactory.create(channel);
|
||||
|
||||
// 生成批次号
|
||||
String seqNo = reconcileStrategy.generateSequence(date);
|
||||
|
||||
PayReconcileOrder order = new PayReconcileOrder()
|
||||
.setBatchNo(seqNo)
|
||||
.setChannel(channel)
|
||||
.setDate(date);
|
||||
reconcileOrderManager.save(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载对账单并进行保存
|
||||
*/
|
||||
@@ -38,19 +71,19 @@ public class PayReconcileService {
|
||||
/**
|
||||
* 下载对账单并进行保存
|
||||
*/
|
||||
public void downAndSave(PayReconcileOrder recordOrder) {
|
||||
public void downAndSave(PayReconcileOrder reconcileOrder) {
|
||||
// 构建对账策略
|
||||
AbsReconcileStrategy absReconcileStrategy = PayReconcileStrategyFactory.create(recordOrder.getChannel());
|
||||
absReconcileStrategy.initParam(recordOrder);
|
||||
absReconcileStrategy.doBeforeHandler();
|
||||
AbsReconcileStrategy reconcileStrategy = PayReconcileStrategyFactory.create(reconcileOrder.getChannel());
|
||||
reconcileStrategy.setRecordOrder(reconcileOrder);
|
||||
reconcileStrategy.doBeforeHandler();
|
||||
try {
|
||||
absReconcileStrategy.downAndSave();
|
||||
recordOrder.setDown(true);
|
||||
reconcileOrderService.update(recordOrder);
|
||||
reconcileStrategy.downAndSave();
|
||||
reconcileOrder.setDown(true);
|
||||
reconcileOrderService.update(reconcileOrder);
|
||||
} catch (Exception e) {
|
||||
log.error("下载对账单异常", e);
|
||||
recordOrder.setErrorMsg("原因: " + e.getMessage());
|
||||
reconcileOrderService.update(recordOrder);
|
||||
reconcileOrder.setErrorMsg("原因: " + e.getMessage());
|
||||
reconcileOrderService.update(reconcileOrder);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 保存转换后的通用结构对账单
|
||||
@@ -60,4 +93,47 @@ public class PayReconcileService {
|
||||
reconcileDetailManager.saveAll(reconcileDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账单比对
|
||||
*/
|
||||
public void compare(Long reconcileOrderId){
|
||||
PayReconcileOrder payReconcileOrder = reconcileOrderService.findById(reconcileOrderId)
|
||||
.orElseThrow(() -> new DataNotExistException("未找到对账订单"));
|
||||
this.compare(payReconcileOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账单比对
|
||||
*/
|
||||
public void compare(PayReconcileOrder reconcileOrder){
|
||||
// 判断是否已经下载了对账单明细
|
||||
if (!reconcileOrder.isDown()){
|
||||
throw new PayFailureException("请先下载对账单");
|
||||
}
|
||||
|
||||
// 查询对账单
|
||||
List<PayReconcileDetail> reconcileDetails = reconcileDetailManager.findAllByOrderId(reconcileOrder.getId());
|
||||
// 获取通道枚举
|
||||
if (!PayChannelEnum.ASYNC_TYPE_CODE.contains(reconcileOrder.getChannel())){
|
||||
log.error("不支持对账的通道, 请检查, 对账订单ID: {}", reconcileOrder.getId());
|
||||
throw new PayFailureException("不支持对账的通道, 请检查");
|
||||
}
|
||||
// 判断是否为为异步通道
|
||||
// 构建对账策略
|
||||
AbsReconcileStrategy reconcileStrategy = PayReconcileStrategyFactory.create(reconcileOrder.getChannel());
|
||||
// 初始化参数
|
||||
reconcileStrategy.setRecordOrder(reconcileOrder);
|
||||
reconcileStrategy.setReconcileDetails(reconcileDetails);
|
||||
try {
|
||||
// 执行比对任务
|
||||
reconcileStrategy.compare();
|
||||
// reconcileOrder.setCompare(true);
|
||||
// reconcileOrderService.update(reconcileOrder);
|
||||
} catch (Exception e) {
|
||||
log.error("比对对账单异常", e);
|
||||
reconcileOrder.setErrorMsg("原因: " + e.getMessage());
|
||||
reconcileOrderService.update(reconcileOrder);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,35 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.sequence.func.Sequence;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayReconcileTradeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayRecordTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.dao.AliPayRecordManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayReconcileService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
@@ -27,8 +45,14 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
|
||||
|
||||
private final AliPayReconcileService reconcileService;
|
||||
|
||||
private final AliPayRecordManager recordManager;
|
||||
|
||||
private final AliPayConfigService configService;
|
||||
|
||||
@Getter
|
||||
@Qualifier("alipayReconcileSequence")
|
||||
private final Sequence sequence;
|
||||
|
||||
private AliPayConfig config;
|
||||
|
||||
|
||||
@@ -42,6 +66,19 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成对账序列号
|
||||
* 规则:通道简称 + yyyyMMdd + 两位流水号
|
||||
* 例子:wx2024012001、ali2024012002
|
||||
*/
|
||||
@Override
|
||||
public String generateSequence(LocalDate date) {
|
||||
String prefix = getChannel().getReconcilePrefix();
|
||||
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
|
||||
String key = String.format("%02d", sequence.next());
|
||||
return prefix + dateStr + key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账前处理, 主要是初始化支付SDK配置
|
||||
*/
|
||||
@@ -59,4 +96,69 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
|
||||
String date = LocalDateTimeUtil.format(this.getRecordOrder().getDate(), DatePattern.NORM_DATE_PATTERN);
|
||||
reconcileService.downAndSave(date,this.getRecordOrder().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 比对生成对账差异单
|
||||
* 1. 远程有, 本地无 补单(追加回订单/记录差异表)
|
||||
* 2. 远程无, 本地有 记录差错表
|
||||
* 3. 远程有, 本地有, 但状态不一致 记录差错表
|
||||
*/
|
||||
@Override
|
||||
public void compare() {
|
||||
List<PayReconcileDetail> details = this.getReconcileDetails();
|
||||
if (CollUtil.isEmpty(details)){
|
||||
return;
|
||||
}
|
||||
Map<String, PayReconcileDetail> detailMap = details.stream()
|
||||
.collect(Collectors.toMap(PayReconcileDetail::getOrderId, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 对哪天进行对账
|
||||
LocalDate date = this.getRecordOrder().getDate();
|
||||
|
||||
// 查询流水
|
||||
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(date);
|
||||
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
|
||||
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
|
||||
List<AliPayRecord> records = recordManager.findByDate(start, end);
|
||||
Map<Long, AliPayRecord> recordMap = records.stream()
|
||||
.collect(Collectors.toMap(AliPayRecord::getOrderId, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 对账与流水比对
|
||||
for (PayReconcileDetail detail : details) {
|
||||
// 判断本地有没有记录
|
||||
AliPayRecord record = recordMap.get(Long.valueOf(detail.getOrderId()));
|
||||
if (Objects.isNull(record)){
|
||||
log.info("本地订单不存在: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
System.out.println(detail.getId());
|
||||
// 交易类型 支付/退款
|
||||
if (Objects.equals(detail.getType(), PayReconcileTradeEnum.PAY.getCode())){
|
||||
// 判断类型是否存在差异
|
||||
if (!Objects.equals(record.getType(), AliPayRecordTypeEnum.PAY.getCode())){
|
||||
log.info("本地订单类型不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// 判断类型是否存在差异
|
||||
if (!Objects.equals(record.getType(), AliPayRecordTypeEnum.REFUND.getCode())){
|
||||
log.info("本地订单类型不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 判断是否存在差异 金额, 状态
|
||||
if (!Objects.equals(record.getAmount(), detail.getAmount())){
|
||||
log.info("本地订单金额不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 流水与对账单比对, 找出本地有, 远程没有的记录
|
||||
for (AliPayRecord record : records) {
|
||||
PayReconcileDetail detail = detailMap.get(String.valueOf(record.getOrderId()));
|
||||
if (Objects.isNull(detail)){
|
||||
log.info("远程订单不存在: {}", record.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,34 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.sequence.func.Sequence;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayReconcileTradeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayRecordTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.dao.WeChatPayRecordManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatPayReconcileService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
@@ -29,6 +46,11 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
private final WeChatPayRecordManager recordManager;
|
||||
|
||||
@Qualifier("wechatReconcileSequence")
|
||||
private final Sequence sequence;
|
||||
|
||||
private WeChatPayConfig config;
|
||||
|
||||
/**
|
||||
@@ -41,6 +63,20 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成对账序列号
|
||||
* 生成批次号
|
||||
* 规则:通道简称 + yyyyMMdd + 两位流水号
|
||||
* 例子:wx2024012001、ali2024012002
|
||||
*/
|
||||
@Override
|
||||
public String generateSequence(LocalDate date) {
|
||||
String prefix = getChannel().getReconcilePrefix();
|
||||
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
|
||||
String key = String.format("%02d", sequence.next());
|
||||
return prefix + dateStr + key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账前处理, 主要是初始化支付SDK配置
|
||||
*/
|
||||
@@ -57,4 +93,68 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
String format = LocalDateTimeUtil.format(this.getRecordOrder().getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
reconcileService.downAndSave(format,this.getRecordOrder().getId(), this.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比对生成对账差异单
|
||||
* 1. 远程有, 本地无 补单(追加回订单/记录差异表)
|
||||
* 2. 远程无, 本地有 记录差错表
|
||||
* 3. 远程有, 本地有, 但状态不一致 记录差错表
|
||||
*/
|
||||
@Override
|
||||
public void compare() {
|
||||
List<PayReconcileDetail> details = this.getReconcileDetails();
|
||||
if (CollUtil.isEmpty(details)){
|
||||
return;
|
||||
}
|
||||
Map<String, PayReconcileDetail> detailMap = details.stream()
|
||||
.collect(Collectors.toMap(PayReconcileDetail::getOrderId, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 对哪天进行对账
|
||||
LocalDate date = this.getRecordOrder().getDate();
|
||||
|
||||
// 查询流水
|
||||
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(date);
|
||||
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
|
||||
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
|
||||
List<WeChatPayRecord> records = recordManager.findByDate(start, end);
|
||||
Map<Long, WeChatPayRecord> recordMap = records.stream()
|
||||
.collect(Collectors.toMap(WeChatPayRecord::getOrderId, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 对账与流水比对
|
||||
for (PayReconcileDetail detail : details) {
|
||||
// 判断本地有没有记录
|
||||
WeChatPayRecord record = recordMap.get(Long.valueOf(detail.getOrderId()));
|
||||
if (Objects.isNull(record)){
|
||||
log.info("本地订单不存在: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
// 交易类型 支付/退款
|
||||
if (Objects.equals(detail.getType(), PayReconcileTradeEnum.PAY.getCode())){
|
||||
// 判断类型是否存在差异
|
||||
if (!Objects.equals(record.getType(), AliPayRecordTypeEnum.PAY.getCode())){
|
||||
log.info("本地订单类型不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// 判断类型是否存在差异
|
||||
if (!Objects.equals(record.getType(), AliPayRecordTypeEnum.REFUND.getCode())){
|
||||
log.info("本地订单类型不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 判断是否存在差异 金额, 状态
|
||||
if (!Objects.equals(record.getAmount(), detail.getAmount())){
|
||||
log.info("本地订单金额不正常: {}", detail.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 流水与对账单比对, 找出本地有, 远程没有的记录
|
||||
for (WeChatPayRecord record : records) {
|
||||
PayReconcileDetail detail = detailMap.get(String.valueOf(record.getOrderId()));
|
||||
if (Objects.isNull(detail)){
|
||||
log.info("远程订单不存在: {}", record.getOrderId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -98,6 +98,9 @@ public class PayRepairService {
|
||||
List<PayChannelOrder> channelOrders = repairStrategies.stream()
|
||||
.map(AbsPayRepairStrategy::getChannelOrder)
|
||||
.collect(Collectors.toList());
|
||||
// 更新通道订单
|
||||
channelOrderManager.updateAllById(channelOrders);
|
||||
// 发送通知
|
||||
clientNoticeService.registerPayNotice(order, null, channelOrders);
|
||||
this.saveRecord(order, repairType, repairResult);
|
||||
return repairResult;
|
||||
@@ -105,13 +108,15 @@ public class PayRepairService {
|
||||
|
||||
/**
|
||||
* 变更未待支付
|
||||
*
|
||||
* TODO 后期保存为异常订单
|
||||
*/
|
||||
private void waitPay(PayOrder order, List<AbsPayRepairStrategy> repairStrategies) {
|
||||
|
||||
repairStrategies.forEach(AbsPayRepairStrategy::doCloseLocalHandler);
|
||||
// 修改订单支付状态为成功
|
||||
order.setStatus(PayStatusEnum.PROGRESS.getCode());
|
||||
// 待支付批量处理
|
||||
repairStrategies.forEach(AbsPayRepairStrategy::doWaitPayHandler);
|
||||
// 修改订单支付状态为待支付
|
||||
order.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
.setPayTime(null)
|
||||
.setCloseTime(null);
|
||||
payOrderService.updateById(order);
|
||||
}
|
||||
|
||||
@@ -141,7 +146,7 @@ public class PayRepairService {
|
||||
// 执行策略的关闭方法
|
||||
absPayStrategies.forEach(AbsPayRepairStrategy::doCloseLocalHandler);
|
||||
order.setStatus(PayStatusEnum.CLOSE.getCode())
|
||||
// TODO 尝试是否可以使用网关返回的
|
||||
// TODO 尝试是否可以使用网关返回的时间
|
||||
.setCloseTime(LocalDateTime.now());
|
||||
payOrderService.updateById(order);
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayCloseService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayRecordService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayRepairStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -34,8 +33,6 @@ public class AliPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
|
||||
private final AliPayRecordService aliRecordService;
|
||||
|
||||
private final PayChannelOrderManager payChannelOrderManager;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*/
|
||||
@@ -63,7 +60,6 @@ public class AliPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
.getFinishTime();
|
||||
this.getChannelOrder().setStatus(PayStatusEnum.SUCCESS.getCode())
|
||||
.setPayTime(payTime);
|
||||
payChannelOrderManager.updateById(this.getChannelOrder());
|
||||
// 支付完成, 保存记录
|
||||
aliRecordService.pay(this.getOrder(), this.getChannelOrder());
|
||||
}
|
||||
@@ -72,8 +68,8 @@ public class AliPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
* 等待支付处理
|
||||
*/
|
||||
@Override
|
||||
public void doWaitPayHandler() {
|
||||
super.doWaitPayHandler();
|
||||
public void doWaitPayHandler(){
|
||||
this.getChannelOrder().setPayTime(null).setStatus(PayStatusEnum.PROGRESS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -7,7 +7,6 @@ import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConf
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayCloseService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayRecordService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayRepairStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -32,8 +31,6 @@ public class WeChatPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
private final PayChannelOrderManager payChannelOrderManager;
|
||||
|
||||
private final WeChatPayRecordService weChatPayRecordService;
|
||||
|
||||
private WeChatPayConfig weChatPayConfig;
|
||||
@@ -46,6 +43,14 @@ public class WeChatPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待支付处理
|
||||
*/
|
||||
@Override
|
||||
public void doWaitPayHandler(){
|
||||
this.getChannelOrder().setPayTime(null).setStatus(PayStatusEnum.PROGRESS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复前处理
|
||||
*/
|
||||
@@ -64,7 +69,6 @@ public class WeChatPayRepairStrategy extends AbsPayRepairStrategy {
|
||||
.getFinishTime();
|
||||
this.getChannelOrder().setStatus(PayStatusEnum.SUCCESS.getCode())
|
||||
.setPayTime(payTime);
|
||||
payChannelOrderManager.updateById(this.getChannelOrder());
|
||||
// 保存流水记录
|
||||
weChatPayRecordService.pay(this.getOrder(), this.getChannelOrder());
|
||||
}
|
||||
|
@@ -104,11 +104,10 @@ public class PaySyncService {
|
||||
if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(payOrder, syncResult, false, null, syncResult.getErrorMsg());
|
||||
// return new SyncResult().setErrorMsg(syncResult.getErrorMsg());
|
||||
throw new PayFailureException(syncResult.getErrorMsg());
|
||||
}
|
||||
// 支付订单的网关订单号是否一致, 不一致进行更新
|
||||
if (Objects.nonNull(syncResult.getGatewayOrderNo()) && !Objects.equals(syncResult.getGatewayOrderNo(), payOrder.getGatewayOrderNo())){
|
||||
if (!Objects.equals(syncResult.getGatewayOrderNo(), payOrder.getGatewayOrderNo())){
|
||||
payOrder.setGatewayOrderNo(syncResult.getGatewayOrderNo());
|
||||
payOrderService.updateById(payOrder);
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信支付记录
|
||||
* @author xxm
|
||||
@@ -41,4 +43,8 @@ public class AliPayRecordDto extends BaseDto {
|
||||
@Schema(description = "网关订单号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 网关完成时间 */
|
||||
@Schema(description = "网关完成时间")
|
||||
private LocalDateTime gatewayTime;
|
||||
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信支付记录
|
||||
* @author xxm
|
||||
@@ -41,4 +43,8 @@ public class WeChatPayRecordDto extends BaseDto {
|
||||
@Schema(description = "网关订单号")
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 网关完成时间 */
|
||||
@Schema(description = "网关完成时间")
|
||||
private LocalDateTime gatewayTime;
|
||||
|
||||
}
|
||||
|
@@ -47,9 +47,7 @@ public abstract class AbsPayRepairStrategy implements PayStrategy{
|
||||
/**
|
||||
* 等待支付处理
|
||||
*/
|
||||
public void doWaitPayHandler(){
|
||||
|
||||
}
|
||||
public void doWaitPayHandler(){}
|
||||
|
||||
/**
|
||||
* 关闭本地支付
|
||||
|
@@ -1,32 +1,40 @@
|
||||
package cn.bootx.platform.daxpay.service.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付对账策略
|
||||
* @author xxm
|
||||
* @since 2024/1/18
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class AbsReconcileStrategy implements PayStrategy {
|
||||
|
||||
/** 对账订单 */
|
||||
private PayReconcileOrder recordOrder;
|
||||
|
||||
/** 对账订单明细 */
|
||||
private List<PayReconcileDetail> reconcileDetails;
|
||||
|
||||
|
||||
/**
|
||||
* 生成对账序列号
|
||||
*/
|
||||
public abstract String generateSequence(LocalDate date);
|
||||
|
||||
/**
|
||||
* 对账前处理, 主要是初始化支付SDK配置
|
||||
*/
|
||||
public void doBeforeHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化参数
|
||||
*/
|
||||
public void initParam(PayReconcileOrder recordOrder){
|
||||
this.recordOrder = recordOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载对账单到本地进行保存
|
||||
*/
|
||||
@@ -36,10 +44,8 @@ public abstract class AbsReconcileStrategy implements PayStrategy {
|
||||
* 比对生成对账差异单
|
||||
* 1. 远程有, 本地无 补单(追加回订单/记录差异表)
|
||||
* 2. 远程无, 本地有 记录差错表
|
||||
* 3. 远程有, 本地有, 但状态不一致
|
||||
* 3. 远程有, 本地有, 但状态不一致 记录差错表
|
||||
*/
|
||||
public void offsetting(){
|
||||
|
||||
}
|
||||
public abstract void compare();
|
||||
|
||||
}
|
||||
|
@@ -20,10 +20,13 @@ import lombok.experimental.Accessors;
|
||||
@Schema(title = "支付退款查询参数")
|
||||
public class RefundOrderQuery extends QueryOrder {
|
||||
|
||||
@Schema(description = "退款号")
|
||||
@Schema(description = "退款Id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "支付号")
|
||||
@Schema(description = "退款号")
|
||||
private String refundNo;
|
||||
|
||||
@Schema(description = "支付ID")
|
||||
private Long paymentId;
|
||||
|
||||
@Schema(description = "关联的业务号")
|
||||
|
@@ -24,7 +24,7 @@ public class PayReconcileTask implements Job {
|
||||
private final PayReconcileTaskService reconcileTaskService;
|
||||
|
||||
/**
|
||||
* 若参数变量名修改 QuartzJobScheduler 中也需对应修改 需要给一个set方法, 让系统设置值
|
||||
* 要同步的通道
|
||||
*/
|
||||
@Setter
|
||||
private String channel;
|
||||
@@ -47,6 +47,6 @@ public class PayReconcileTask implements Job {
|
||||
} else {
|
||||
date = date.minusDays(1);
|
||||
}
|
||||
reconcileTaskService.x1(date,channel);
|
||||
reconcileTaskService.reconcileTask(date,channel);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.task.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.PayReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.PayReconcileOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.service.PayReconcileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -19,21 +18,20 @@ import java.time.LocalDate;
|
||||
@RequiredArgsConstructor
|
||||
public class PayReconcileTaskService {
|
||||
private final PayReconcileService reconcileService;
|
||||
private final PayReconcileOrderService reconcileOrderService;
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*/
|
||||
public void x1(LocalDate date, String channel){
|
||||
public void reconcileTask(LocalDate date, String channel){
|
||||
|
||||
// 1. 查询需要定时对账的通道, 创建出来对账订单
|
||||
PayReconcileOrder reconcileOrder = reconcileOrderService.create(date, channel);
|
||||
PayReconcileOrder reconcileOrder = reconcileService.create(date, channel);
|
||||
|
||||
// 2. 执行对账任务, 下载对账单并解析, 分别存储为原始数据和通用对账数据
|
||||
reconcileService.downAndSave(reconcileOrder);
|
||||
|
||||
// 3. 执行账单比对, 生成差异单
|
||||
|
||||
reconcileService.compare(reconcileOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
# 将字段上的注解拷贝到对应构造参数上, 如果要新增别的注解, 需要在下方重新进行定义,
|
||||
lombok.copyableAnnotations += org.springframework.context.annotation.Lazy
|
||||
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
|
||||
# 默认开启实体类的链式API 会导致一些反射相关类库出问题, 如 easyExcel
|
||||
#lombok.accessors.chain = true
|
||||
|
Reference in New Issue
Block a user