ref 修复单重构为调整单

This commit is contained in:
DaxPay
2024-07-15 19:09:22 +08:00
parent fc1b753afe
commit 42c706619b
53 changed files with 564 additions and 206 deletions

View File

@@ -10,15 +10,12 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum PayRepairWayEnum {
public enum PayAdjustWayEnum {
PAY_SUCCESS("pay_success","支付成功"),
SUCCESS("pay_success","支付成功"),
CLOSE_LOCAL("pay_close_local","关闭本地支付"),
PROGRESS("pay_progress","切换到支付中"),
/** 同时也会关闭本地支付 */
CLOSE_GATEWAY("pay_close_gateway","关闭网关支付"),
REFUND_SUCCESS("refund_success","退款成功"),
REFUND_FAIL("refund_fail","退款失败");;
CLOSE_GATEWAY("pay_close_gateway","关闭网关支付");
private final String code;
private final String name;

View File

@@ -4,19 +4,18 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付修复来源, 不同来源的修复类型要执行的逻辑不相同
* 交易调整出发来源, 不同来源的修复类型要执行的逻辑不相同
* @author xxm
* @since 2023/12/29
*/
@Getter
@AllArgsConstructor
public enum PayRepairSourceEnum{
public enum TradeAdjustSourceEnum {
SYNC("sync","同步"),
CALLBACK("callback","回调"),
TASK("task","定时任务"),
RECONCILE("reconcile","对账");
;
private final String code;
private final String name;
}

View File

@@ -8,13 +8,13 @@ import java.util.Arrays;
import java.util.Objects;
/**
* 支付系统中常见的操作类型, 如支付/退款/转账等
* 交易类型类型, 如支付/退款/转账等
* @author xxm
* @since 2024/1/28
*/
@Getter
@AllArgsConstructor
public enum PaymentTypeEnum {
public enum TradeTypeEnum {
PAY("pay","支付"),
REFUND("refund","退款"),
@@ -24,11 +24,11 @@ public enum PaymentTypeEnum {
private final String code;
private final String name;
public static PaymentTypeEnum findByCode(String code){
public static TradeTypeEnum findByCode(String code){
return Arrays.stream(values())
.filter(value -> Objects.equals(value.getCode(), code))
.findFirst()
.orElseThrow(() -> new DataNotExistException("未找到对应的支付类型"));
.orElseThrow(() -> new DataNotExistException("未找到对应的交易类型"));
}
}

View File

@@ -1,6 +1,6 @@
package cn.daxpay.single.service.common.context;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -13,14 +13,14 @@ import java.time.LocalDateTime;
*/
@Data
@Accessors(chain = true)
public class RepairLocal {
public class AdjustLocal {
/**
* 触发来源
*/
private PayRepairSourceEnum source;
private TradeAdjustSourceEnum source;
/** 完成/退款时间 */
/** 完成时间 */
private LocalDateTime finishTime;
}

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.common.context;
import cn.daxpay.single.core.code.RefundStatusEnum;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -53,7 +53,7 @@ public class CallbackLocal {
private String repairNo;
/** 回调类型 */
private PaymentTypeEnum callbackType;
private TradeTypeEnum callbackType;
/**
* 回调处理状态

View File

@@ -25,7 +25,7 @@ public class PayLocal {
private boolean complete;
/** 完成时间 */
private LocalDateTime completeTime;
private LocalDateTime finishTime;
/** 支付参数体(通常用于发起支付的参数) */
private String payBody;

View File

@@ -31,7 +31,7 @@ public class PaymentContext {
private final CallbackLocal callbackInfo = new CallbackLocal();
/** 修复相关信息 */
private final RepairLocal repairInfo = new RepairLocal();
private final AdjustLocal repairInfo = new AdjustLocal();
/** 对账相关信息 */
private final ReconcileLocal reconcileInfo = new ReconcileLocal();

View File

@@ -5,8 +5,8 @@ import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.common.context.CallbackLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig;
@@ -60,7 +60,7 @@ public class AliPayCallbackService {
callbackInfo.getCallbackParam().putAll(params);
// 判断并保存回调类型
PaymentTypeEnum callbackType = this.getCallbackType();
TradeTypeEnum callbackType = this.getCallbackType();
callbackInfo.setCallbackType(callbackType)
.setChannel(PayChannelEnum.ALI.getCode());
@@ -72,9 +72,9 @@ public class AliPayCallbackService {
return null;
}
// 提前设置订单修复的来源
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
PaymentContextLocal.get().getRepairInfo().setSource(TradeAdjustSourceEnum.CALLBACK);
if (callbackType == PaymentTypeEnum.PAY){
if (callbackType == TradeTypeEnum.PAY){
// 解析支付数据并放处理
this.resolvePayData();
payCallbackService.payCallback();
@@ -177,17 +177,17 @@ public class AliPayCallbackService {
/**
* 判断类型 支付回调/退款回调
*
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
public PaymentTypeEnum getCallbackType() {
public TradeTypeEnum getCallbackType() {
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callback.getCallbackParam();
String refundFee = callbackParam.get(REFUND_FEE);
// 如果有退款金额,说明是退款回调
if (StrUtil.isNotBlank(refundFee)){
return PaymentTypeEnum.REFUND;
return TradeTypeEnum.REFUND;
} else {
return PaymentTypeEnum.PAY;
return TradeTypeEnum.PAY;
}
}

View File

@@ -325,7 +325,7 @@ public class AliPayService {
Date gmtPayment = response.getGmtPayment();
payInfo.setOutOrderNo(response.getTradeNo())
.setComplete(true)
.setCompleteTime(LocalDateTimeUtil.of(gmtPayment));
.setFinishTime(LocalDateTimeUtil.of(gmtPayment));
}
// 非支付中响应码, 进行错误处理
if (!Objects.equals(response.getCode(), AliPayCode.INPROCESS)) {

View File

@@ -5,8 +5,8 @@ import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.core.code.RefundStatusEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.UnionPayCode;
import cn.daxpay.single.service.common.context.CallbackLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
@@ -58,7 +58,7 @@ public class UnionPayCallbackService {
callbackInfo.getCallbackParam().putAll(params);
// 判断并保存回调类型
PaymentTypeEnum callbackType = this.getCallbackType();
TradeTypeEnum callbackType = this.getCallbackType();
callbackInfo.setCallbackType(callbackType)
.setChannel(PayChannelEnum.UNION_PAY.getCode());
@@ -70,9 +70,9 @@ public class UnionPayCallbackService {
return null;
}
// 提前设置订单修复的来源
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
PaymentContextLocal.get().getRepairInfo().setSource(TradeAdjustSourceEnum.CALLBACK);
if (callbackType == PaymentTypeEnum.PAY){
if (callbackType == TradeTypeEnum.PAY){
// 解析支付数据并放处理
this.resolvePayData();
payCallbackService.payCallback();
@@ -112,16 +112,16 @@ public class UnionPayCallbackService {
/**
* 判断类型 支付回调/退款回调
*
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
public PaymentTypeEnum getCallbackType() {
public TradeTypeEnum getCallbackType() {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> params = callbackInfo.getCallbackParam();
String txnType = params.get(TXN_TYPE);
if (UnionPayCode.TXN_TYPE_PAY.equals(txnType)){
return PaymentTypeEnum.PAY;
return TradeTypeEnum.PAY;
} else {
return PaymentTypeEnum.REFUND;
return TradeTypeEnum.REFUND;
}
}

View File

@@ -5,8 +5,8 @@ import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.core.code.RefundStatusEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.common.context.CallbackLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.channel.wechat.entity.WeChatPayConfig;
@@ -58,7 +58,7 @@ public class WeChatPayCallbackService {
callbackInfo.getCallbackParam().putAll(params);
// 判断并保存回调类型
PaymentTypeEnum callbackType = this.getCallbackType();
TradeTypeEnum callbackType = this.getCallbackType();
callbackInfo.setCallbackType(callbackType)
.setChannel(PayChannelEnum.WECHAT.getCode());
@@ -70,9 +70,9 @@ public class WeChatPayCallbackService {
return null;
}
// 提前设置订单修复的来源
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
PaymentContextLocal.get().getRepairInfo().setSource(TradeAdjustSourceEnum.CALLBACK);
if (callbackType == PaymentTypeEnum.PAY){
if (callbackType == TradeTypeEnum.PAY){
// 解析支付数据并放处理
this.resolvePayData();
payCallbackService.payCallback();
@@ -104,8 +104,8 @@ public class WeChatPayCallbackService {
}
// 退款回调不用进行校验
PaymentTypeEnum callbackType = callbackInfo.getCallbackType();
if (callbackType == PaymentTypeEnum.REFUND){
TradeTypeEnum callbackType = callbackInfo.getCallbackType();
if (callbackType == TradeTypeEnum.REFUND){
return true;
}
// 支付回调信息校验
@@ -182,15 +182,15 @@ public class WeChatPayCallbackService {
/**
* 判断类型 支付回调/退款回调
*
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
public PaymentTypeEnum getCallbackType() {
public TradeTypeEnum getCallbackType() {
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
if (StrUtil.isNotBlank(callbackParam.get(REQ_INFO))){
return PaymentTypeEnum.REFUND;
return TradeTypeEnum.REFUND;
} else {
return PaymentTypeEnum.PAY;
return TradeTypeEnum.PAY;
}
}

View File

@@ -213,7 +213,7 @@ public class WeChatPayService {
String timeEnd = result.get(WeChatPayCode.TIME_END);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
payInfo.setOutOrderNo(result.get(WeChatPayCode.TRANSACTION_ID))
.setCompleteTime(time)
.setFinishTime(time)
.setComplete(true);
return;
}

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.core.order.reconcile.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.core.order.reconcile.conver.ReconcileConvert;
import cn.daxpay.single.service.dto.order.reconcile.ReconcileOutTradeDto;
import cn.bootx.table.modify.annotation.DbColumn;
@@ -42,7 +42,7 @@ public class ReconcileOutTrade extends MpCreateEntity implements EntityBaseFunct
/**
* 交易类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@DbColumn(comment = "交易类型", length = 20, isNull = false)
private String type;

View File

@@ -7,7 +7,7 @@ import cn.daxpay.single.core.code.AllocOrderResultEnum;
import cn.daxpay.single.core.code.AllocOrderStatusEnum;
import cn.daxpay.single.core.param.payment.allocation.AllocSyncParam;
import cn.daxpay.single.core.result.sync.AllocSyncResult;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.allocation.dao.AllocOrderDetailManager;
import cn.daxpay.single.service.core.order.allocation.dao.AllocationOrderManager;
@@ -162,7 +162,7 @@ public class AllocationSyncService {
.setBizTradeNo(order.getBizAllocNo())
.setTradeNo(order.getAllocNo())
.setOutTradeNo(order.getOutAllocNo())
.setSyncType(PaymentTypeEnum.ALLOCATION.getCode())
.setSyncType(TradeTypeEnum.ALLOCATION.getCode())
.setChannel(order.getChannel())
.setSyncInfo(syncResult.getSyncInfo())
.setErrorCode(errorCode)

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.core.payment.callback.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.common.context.CallbackLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
@@ -96,7 +96,7 @@ public class PayCallbackService {
// 设置支付成功时间
PaymentContextLocal.get().getRepairInfo().setFinishTime(callbackInfo.getFinishTime());
// 执行支付完成修复逻辑
PayRepairResult repair = payRepairService.repair(payOrder, PayRepairWayEnum.PAY_SUCCESS);
PayRepairResult repair = payRepairService.repair(payOrder, PayAdjustWayEnum.SUCCESS);
callbackInfo.setRepairNo(repair.getRepairNo());
}
@@ -116,7 +116,7 @@ public class PayCallbackService {
return;
}
// 执行支付关闭修复逻辑
PayRepairResult repair = payRepairService.repair(payOrder, PayRepairWayEnum.CLOSE_LOCAL);
PayRepairResult repair = payRepairService.repair(payOrder, PayAdjustWayEnum.CLOSE_LOCAL);
callbackInfo.setRepairNo(repair.getRepairNo());
}

View File

@@ -122,7 +122,7 @@ public class PayService {
if (payInfo.isComplete()) {
payOrder.setOutOrderNo(payInfo.getOutOrderNo())
.setStatus(SUCCESS.getCode())
.setPayTime(payInfo.getCompleteTime());
.setPayTime(payInfo.getFinishTime());
}
payOrderService.updateById(payOrder);
// 扩展记录更新
@@ -177,7 +177,7 @@ public class PayService {
if (payInfo.isComplete()) {
payOrder.setOutOrderNo(payInfo.getOutOrderNo())
.setStatus(SUCCESS.getCode())
.setPayTime(payInfo.getCompleteTime());
.setPayTime(payInfo.getFinishTime());
}
payOrderService.updateById(payOrder);
// 扩展记录更新

View File

@@ -1,6 +1,6 @@
package cn.daxpay.single.service.core.payment.reconcile.domain;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.handler.excel.AmountConverter;
import cn.daxpay.single.service.handler.excel.PaymentTypeConvert;
import com.alibaba.excel.annotation.ExcelProperty;
@@ -27,7 +27,7 @@ public class GeneralTradeInfo {
/**
* 业务类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@ExcelProperty(value = "业务类型", converter = PaymentTypeConvert.class)
private String type;

View File

@@ -4,7 +4,7 @@ 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.daxpay.single.core.code.ReconcileTradeEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.ReconcileDiffTypeEnum;
import cn.daxpay.single.service.core.order.pay.dao.PayOrderManager;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
@@ -61,7 +61,7 @@ public class ReconcileAssistService {
.setTradeNo(payOrder.getOrderNo())
.setOutTradeNo(payOrder.getOutOrderNo())
.setFinishTime(payOrder.getPayTime())
.setType(PaymentTypeEnum.PAY.getCode())
.setType(TradeTypeEnum.PAY.getCode())
.setAmount(payOrder.getAmount())
);
}
@@ -71,7 +71,7 @@ public class ReconcileAssistService {
.setTradeNo(refundOrder.getRefundNo())
.setOutTradeNo(refundOrder.getOutRefundNo())
.setFinishTime(refundOrder.getFinishTime())
.setType(PaymentTypeEnum.REFUND.getCode())
.setType(TradeTypeEnum.REFUND.getCode())
.setAmount(refundOrder.getAmount()));
}
return generalTradeInfoList;
@@ -176,12 +176,12 @@ public class ReconcileAssistService {
// 判断类型是否相同
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.PAY.getCode())
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.PAY.getCode())){
&& !Objects.equals(localTrade.getType(), TradeTypeEnum.PAY.getCode())){
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
diffs.add(new ReconcileDiffDetail().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
}
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.REFUND.getCode())
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.REFUND.getCode())){
&& !Objects.equals(localTrade.getType(), TradeTypeEnum.REFUND.getCode())){
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
diffs.add(new ReconcileDiffDetail().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
}

View File

@@ -1,6 +1,7 @@
package cn.daxpay.single.service.core.payment.repair.param;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -14,6 +15,12 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
public class PayRepairParam {
@Schema(description = "修复类型")
private PayRepairWayEnum repairType;
@Schema(description = "触发来源")
private TradeAdjustSourceEnum source;
@Schema(description = "调整方式")
private PayAdjustWayEnum adjustWay;
@Schema(description = "支付订单号")
private String orderNo;
}

View File

@@ -1,6 +1,5 @@
package cn.daxpay.single.service.core.payment.repair.result;
import cn.daxpay.single.core.code.PayStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -14,8 +13,4 @@ import lombok.experimental.Accessors;
public class PayRepairResult {
/** 修复号 */
private String repairNo;
/** 修复前状态 */
private PayStatusEnum beforeStatus;
/** 修复后状态 */
private PayStatusEnum afterPayStatus;
}

View File

@@ -0,0 +1,148 @@
package cn.daxpay.single.service.core.payment.repair.service;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.core.exception.OperationProcessingException;
import cn.daxpay.single.core.exception.SystemUnknownErrorException;
import cn.daxpay.single.core.exception.TradeStatusErrorException;
import cn.daxpay.single.core.util.TradeNoGenerateUtil;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.payment.repair.param.PayRepairParam;
import cn.daxpay.single.service.core.record.flow.service.TradeFlowRecordService;
import cn.daxpay.single.service.core.record.repair.entity.TradeAdjustRecord;
import cn.daxpay.single.service.core.record.repair.service.TradeAdjustRecordService;
import cn.daxpay.single.service.func.AbsPayAdjustStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 支付订单调整服务
* @author xxm
* @since 2024/7/15
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PayAdjustService {
private final ClientNoticeService clientNoticeService;
private final LockTemplate lockTemplate;
private final TradeAdjustRecordService tradeAdjustRecordService;
private final PayOrderService payOrderService;
private final TradeFlowRecordService tradeFlowRecordService;
/**
* 调整服务
*/
public String adjust(PayOrder order, PayRepairParam param){
// 添加分布式锁
LockInfo lock = lockTemplate.lock("repair:pay:" + order.getId(), 10000, 200);
if (Objects.isNull(lock)){
log.warn("当前支付订单正在修复中: {}", order.getId());
throw new OperationProcessingException("当前支付订单正在修复中");
}
// 如果到达终态不能向前回滚
if (Objects.equals(order.getStatus(), PayStatusEnum.SUCCESS.getCode())){
throw new TradeStatusErrorException("当前支付订单已支付成功");
}
// 初始化调整参数
AbsPayAdjustStrategy repairStrategy = PayStrategyFactory.create(order.getChannel(), AbsPayAdjustStrategy.class);
repairStrategy.setOrder(order);
// 执行前置处理
repairStrategy.doBeforeHandler();
String beforeStatus = order.getStatus();
// 根据不同的调整方式执行对应的修复逻辑
switch (param.getAdjustWay()) {
case SUCCESS:
this.success(order);
break;
case CLOSE_LOCAL:
this.closeLocal(order);
break;
case CLOSE_GATEWAY:
this.closeRemote(order, repairStrategy);
break;
default:
log.error("走到了理论上讲不会走到的分支");
throw new SystemUnknownErrorException("走到了理论上讲不会走到的分支");
}
// 发送通知
clientNoticeService.registerPayNotice(order);
TradeAdjustRecord record = this.saveRecord(order, param, beforeStatus);
return record.getRepairNo();
}
/**
* 变更为已支付
* 同步: 将异步支付状态修改为成功
* 回调: 将异步支付状态修改为成功
*/
private void success(PayOrder order) {
// 读取支付网关中的完成时间
LocalDateTime payTime = PaymentContextLocal.get()
.getRepairInfo()
.getFinishTime();
// 修改订单支付状态为成功
order.setStatus(PayStatusEnum.SUCCESS.getCode())
.setPayTime(payTime)
.setCloseTime(null);
tradeFlowRecordService.savePay(order);
payOrderService.updateById(order);
}
/**
* 关闭支付
* 同步/对账: 执行支付单所有的支付通道关闭支付逻辑, 不需要调用网关关闭,
*/
private void closeLocal(PayOrder order) {
// 执行策略的关闭方法
order.setStatus(PayStatusEnum.CLOSE.getCode())
.setCloseTime(LocalDateTime.now());
payOrderService.updateById(order);
}
/**
* 关闭网关交易, 同时也会关闭本地支付
* 回调: 执行所有的支付通道关闭支付逻辑
*/
private void closeRemote(PayOrder payOrder, AbsPayAdjustStrategy strategy) {
// 执行策略的关闭方法
strategy.doCloseRemoteHandler();
payOrder.setStatus(PayStatusEnum.CLOSE.getCode())
.setCloseTime(LocalDateTime.now());
payOrderService.updateById(payOrder);
}
/**
* 保存记录
*/
private TradeAdjustRecord saveRecord(PayOrder order, PayRepairParam param, String beforeStatus){
// 修复后的状态
TradeAdjustRecord record = new TradeAdjustRecord()
.setRepairNo(TradeNoGenerateUtil.adjust())
.setTradeId(order.getId())
.setChannel(order.getChannel())
.setSource(param.getSource().getCode())
.setTradeNo(order.getOrderNo())
.setBeforeStatus(beforeStatus)
.setAfterStatus(order.getStatus())
.setType(TradeTypeEnum.PAY.getCode())
.setWay(param.getAdjustWay().getCode());
tradeAdjustRecordService.saveRecord(record);
return record;
}
}

View File

@@ -2,19 +2,16 @@ package cn.daxpay.single.service.core.payment.repair.service;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.core.exception.SystemUnknownErrorException;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
import cn.daxpay.single.service.core.payment.repair.result.PayRepairResult;
import cn.daxpay.single.service.core.record.flow.service.TradeFlowRecordService;
import cn.daxpay.single.service.core.record.repair.entity.PayRepairRecord;
import cn.daxpay.single.service.core.record.repair.service.PayRepairRecordService;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.daxpay.single.service.func.AbsPayAdjustStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.hutool.core.util.IdUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
@@ -24,7 +21,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;
/**
* 支付修复服务
@@ -49,7 +45,7 @@ public class PayRepairService {
* 修复支付单
*/
@Transactional(rollbackFor = Exception.class)
public PayRepairResult repair(PayOrder order, PayRepairWayEnum repairType){
public PayRepairResult repair(PayOrder order, PayAdjustWayEnum repairType){
// 添加分布式锁
LockInfo lock = lockTemplate.lock("repair:pay:" + order.getId(), 10000, 200);
if (Objects.isNull(lock)){
@@ -58,39 +54,30 @@ public class PayRepairService {
}
// 2.1 初始化修复参数
AbsPayRepairStrategy repairStrategy = PayStrategyFactory.create(order.getChannel(),AbsPayRepairStrategy.class);
AbsPayAdjustStrategy repairStrategy = PayStrategyFactory.create(order.getChannel(), AbsPayAdjustStrategy.class);
repairStrategy.setOrder(order);
// 2.2 执行前置处理
repairStrategy.doBeforeHandler();
// 3. 根据不同的类型执行对应的修复逻辑
PayRepairResult repairResult = new PayRepairResult().setBeforeStatus(PayStatusEnum.findByCode(order.getStatus()));
switch (repairType) {
case PAY_SUCCESS:
case SUCCESS:
this.success(order);
repairResult.setAfterPayStatus(PayStatusEnum.SUCCESS);
break;
case CLOSE_LOCAL:
this.closeLocal(order);
repairResult.setAfterPayStatus(PayStatusEnum.CLOSE);
break;
case PROGRESS:
// TODO 保存为异常订单
break;
case CLOSE_GATEWAY:
this.closeRemote(order, repairStrategy);
repairResult.setAfterPayStatus(PayStatusEnum.CLOSE);
break;
default:
log.error("走到了理论上讲不会走到的分支");
throw new SystemUnknownErrorException("走到了理论上讲不会走到的分支");
}
// 设置修复iD
repairResult.setRepairNo(IdUtil.getSnowflakeNextIdStr());
// 发送通知
clientNoticeService.registerPayNotice(order);
this.saveRecord(order, repairType, repairResult);
return repairResult;
return null;
}
@@ -127,7 +114,7 @@ public class PayRepairService {
* 关闭网关交易, 同时也会关闭本地支付
* 回调: 执行所有的支付通道关闭支付逻辑
*/
private void closeRemote(PayOrder payOrder, AbsPayRepairStrategy strategy) {
private void closeRemote(PayOrder payOrder, AbsPayAdjustStrategy strategy) {
// 执行策略的关闭方法
strategy.doCloseRemoteHandler();
payOrder.setStatus(PayStatusEnum.CLOSE.getCode())
@@ -135,27 +122,4 @@ public class PayRepairService {
.setCloseTime(LocalDateTime.now());
payOrderService.updateById(payOrder);
}
/**
* 保存记录
*/
private void saveRecord(PayOrder order, PayRepairWayEnum recordType, PayRepairResult repairResult){
// 修复后的状态
String afterStatus = Optional.ofNullable(repairResult.getAfterPayStatus()).map(PayStatusEnum::getCode).orElse(null);
// 修复发起来源
String source = PaymentContextLocal.get()
.getRepairInfo()
.getSource().getCode();
PayRepairRecord payRepairRecord = new PayRepairRecord()
.setRepairNo(repairResult.getRepairNo())
.setTradeId(order.getId())
.setChannel(order.getChannel())
.setTradeNo(order.getOrderNo())
.setBeforeStatus(repairResult.getBeforeStatus().getCode())
.setAfterStatus(afterStatus)
.setRepairType(PaymentTypeEnum.PAY.getCode())
.setRepairSource(source)
.setRepairWay(recordType.getCode());
recordService.saveRecord(payRepairRecord);
}
}

View File

@@ -3,9 +3,9 @@ package cn.daxpay.single.service.core.payment.repair.service;
import cn.daxpay.single.core.code.PayOrderRefundStatusEnum;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.core.code.RefundStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.RefundRepairWayEnum;
import cn.daxpay.single.service.common.context.RepairLocal;
import cn.daxpay.single.service.common.context.AdjustLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
@@ -80,7 +80,7 @@ public class RefundRepairService {
}
// 设置修复ID并保存修复记录
repairResult.setRepairNo(TradeNoGenerateUtil.repair());
repairResult.setRepairNo(TradeNoGenerateUtil.adjust());
// 支付修复记录
PayRepairRecord payRepairRecord = this.payRepairRecord(payOrder, repairType, repairResult);
// 退款修复记录
@@ -99,7 +99,7 @@ public class RefundRepairService {
* 退款成功, 更新退款单和支付单
*/
private RefundRepairResult success(RefundOrder refundOrder, PayOrder payOrder) {
RepairLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
AdjustLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
// 订单相关状态
PayOrderRefundStatusEnum beforePayStatus = PayOrderRefundStatusEnum.findByCode(payOrder.getRefundStatus());
PayOrderRefundStatusEnum afterPayRefundStatus;
@@ -190,7 +190,7 @@ public class RefundRepairService {
.setTradeId(order.getId())
.setTradeNo(order.getOrderNo())
.setRepairNo(repairResult.getRepairNo())
.setRepairType(PaymentTypeEnum.PAY.getCode())
.setRepairType(TradeTypeEnum.PAY.getCode())
.setRepairSource(source)
.setRepairWay(repairType.getCode())
.setChannel(order.getChannel())
@@ -214,7 +214,7 @@ public class RefundRepairService {
.setRepairNo(repairResult.getRepairNo())
.setTradeNo(refundOrder.getRefundNo())
.setChannel(refundOrder.getChannel())
.setRepairType(PaymentTypeEnum.REFUND.getCode())
.setRepairType(TradeTypeEnum.REFUND.getCode())
.setBeforeStatus(repairResult.getBeforeRefundStatus().getCode())
.setAfterStatus(afterStatus)
.setRepairSource(source)

View File

@@ -4,7 +4,7 @@ import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig;
import cn.daxpay.single.service.core.channel.alipay.service.AliPayCloseService;
import cn.daxpay.single.service.core.channel.alipay.service.AliPayConfigService;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.daxpay.single.service.func.AbsPayAdjustStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
@@ -21,7 +21,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@Scope(SCOPE_PROTOTYPE)
@Service
@RequiredArgsConstructor
public class AliPayRepairStrategy extends AbsPayRepairStrategy {
public class AliPayAdjustStrategy extends AbsPayAdjustStrategy {
private final AliPayCloseService closeService;
private final AliPayConfigService aliPayConfigService;

View File

@@ -1,7 +1,7 @@
package cn.daxpay.single.service.core.payment.repair.strategy.pay;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.daxpay.single.service.func.AbsPayAdjustStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
@@ -18,7 +18,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@Scope(SCOPE_PROTOTYPE)
@Service
@RequiredArgsConstructor
public class UnionPayRepairStrategy extends AbsPayRepairStrategy {
public class UnionPayAdjustStrategy extends AbsPayAdjustStrategy {
/**
* 策略标识

View File

@@ -4,7 +4,7 @@ import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.daxpay.single.service.core.channel.wechat.service.WeChatPayCloseService;
import cn.daxpay.single.service.core.channel.wechat.service.WeChatPayConfigService;
import cn.daxpay.single.service.func.AbsPayRepairStrategy;
import cn.daxpay.single.service.func.AbsPayAdjustStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
@@ -21,7 +21,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@Scope(SCOPE_PROTOTYPE)
@Service
@RequiredArgsConstructor
public class WeChatPayRepairStrategy extends AbsPayRepairStrategy {
public class WeChatPayAdjustStrategy extends AbsPayAdjustStrategy {
private final WeChatPayCloseService closeService;
private final WeChatPayConfigService weChatPayConfigService;

View File

@@ -9,10 +9,10 @@ import cn.daxpay.single.core.code.PaySyncStatusEnum;
import cn.daxpay.single.core.exception.*;
import cn.daxpay.single.core.param.payment.pay.PaySyncParam;
import cn.daxpay.single.core.result.sync.PaySyncResult;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.common.context.RepairLocal;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.common.context.AdjustLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
@@ -110,9 +110,9 @@ public class PaySyncService {
// 状态不一致,执行支付单修复逻辑
if (!statusSync){
// 如果没有修复触发来源, 设置修复触发来源为同步
RepairLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
AdjustLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
if (Objects.isNull(repairInfo.getSource())){
repairInfo.setSource(PayRepairSourceEnum.SYNC);
repairInfo.setSource(TradeAdjustSourceEnum.SYNC);
}
// 设置支付单完成时间
repairInfo.setFinishTime(payRemoteSyncResult.getPayTime());
@@ -187,12 +187,7 @@ public class PaySyncService {
switch (syncStatusEnum) {
// 支付成功 支付宝退款时也是支付成功状态, 除非支付完成
case SUCCESS: {
repair = repairService.repair(payOrder, PayRepairWayEnum.PAY_SUCCESS);
break;
}
// 待支付, 将订单状态重新设置为待支付
case PROGRESS: {
repair = repairService.repair(payOrder, PayRepairWayEnum.PROGRESS);
repair = repairService.repair(payOrder, PayAdjustWayEnum.SUCCESS);
break;
}
case REFUND:
@@ -200,13 +195,13 @@ public class PaySyncService {
// 交易关闭和未找到, 都对本地支付订单进行关闭, 不需要再调用网关进行关闭
case CLOSED:
case NOT_FOUND: {
repair = repairService.repair(payOrder, PayRepairWayEnum.CLOSE_LOCAL);
repair = repairService.repair(payOrder, PayAdjustWayEnum.CLOSE_LOCAL);
break;
}
// 超时关闭和交易不存在(特殊) 关闭本地支付订单, 同时调用网关进行关闭, 确保后续这个订单不能被支付
case TIMEOUT:
case NOT_FOUND_UNKNOWN:{
repair = repairService.repair(payOrder, PayRepairWayEnum.CLOSE_GATEWAY);
repair = repairService.repair(payOrder, PayAdjustWayEnum.CLOSE_GATEWAY);
break;
}
// 调用出错
@@ -237,7 +232,7 @@ public class PaySyncService {
.setTradeNo(payOrder.getOrderNo())
.setOutTradeNo(payOrder.getOutOrderNo())
.setOutTradeStatus(payRemoteSyncResult.getSyncStatus().getCode())
.setSyncType(PaymentTypeEnum.PAY.getCode())
.setSyncType(TradeTypeEnum.PAY.getCode())
.setChannel(payOrder.getChannel())
.setSyncInfo(payRemoteSyncResult.getSyncInfo())
.setRepair(repair)

View File

@@ -9,10 +9,10 @@ import cn.daxpay.single.core.exception.PayFailureException;
import cn.daxpay.single.core.exception.TradeNotExistException;
import cn.daxpay.single.core.param.payment.refund.RefundSyncParam;
import cn.daxpay.single.core.result.sync.RefundSyncResult;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.RefundRepairWayEnum;
import cn.daxpay.single.service.common.context.RepairLocal;
import cn.daxpay.single.service.common.context.AdjustLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.order.refund.dao.RefundOrderManager;
import cn.daxpay.single.service.core.order.refund.entity.RefundOrder;
@@ -105,9 +105,9 @@ public class RefundSyncService {
// 状态不一致,执行退款单修复逻辑
if (!statusSync) {
// 如果没有支付来源, 设置支付来源为同步
RepairLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
AdjustLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
if (Objects.isNull(repairInfo.getSource())){
repairInfo.setSource(PayRepairSourceEnum.SYNC);
repairInfo.setSource(TradeAdjustSourceEnum.SYNC);
}
repairInfo.setFinishTime(refundRemoteSyncResult.getFinishTime());
repairResult = this.repairHandler(refundRemoteSyncResult, refundOrder);
@@ -196,7 +196,7 @@ public class RefundSyncService {
.setBizTradeNo(refundOrder.getBizRefundNo())
.setOutTradeNo(syncResult.getOutRefundNo())
.setOutTradeStatus(syncResult.getSyncStatus().getCode())
.setSyncType(PaymentTypeEnum.REFUND.getCode())
.setSyncType(TradeTypeEnum.REFUND.getCode())
.setChannel(refundOrder.getChannel())
.setSyncInfo(syncResult.getSyncInfo())
.setRepair(repair)

View File

@@ -9,7 +9,7 @@ import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.core.record.callback.convert.PayCallbackRecordConvert;
import cn.daxpay.single.service.dto.record.callback.PayCallbackRecordDto;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -48,7 +48,7 @@ public class PayCallbackRecord extends MpCreateEntity implements EntityBaseFunct
/**
* 回调类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@DbColumn(comment = "回调类型", length = 20, isNull = false)
private String callbackType;

View File

@@ -0,0 +1,18 @@
package cn.daxpay.single.service.core.record.repair.convert;
import cn.daxpay.single.service.core.record.repair.entity.TradeAdjustRecord;
import cn.daxpay.single.service.dto.record.repair.TradeAdjustRecordDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author xxm
* @since 2024/7/15
*/
@Mapper
public interface TradeAdjustRecordConvert {
TradeAdjustRecordConvert CONVERT = Mappers.getMapper(TradeAdjustRecordConvert.class);
TradeAdjustRecordDto convert(TradeAdjustRecord in);
}

View File

@@ -0,0 +1,32 @@
package cn.daxpay.single.service.core.record.repair.dao;
import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.common.query.generator.QueryGenerator;
import cn.daxpay.single.service.core.record.repair.entity.TradeAdjustRecord;
import cn.daxpay.single.service.param.report.TradeAdjustRecordQuery;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
/**
*
* @author xxm
* @since 2024/7/15
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class TradeAdjustRecordManager extends BaseManager<TradeAdjustRecordMapper, TradeAdjustRecord> {
public Page<TradeAdjustRecord> page(PageParam pageParam, TradeAdjustRecordQuery param){
QueryWrapper<TradeAdjustRecord> generator = QueryGenerator.generator(param);
Page<TradeAdjustRecord> mpPage = MpUtil.getMpPage(pageParam, TradeAdjustRecord.class);
return this.page(mpPage, generator);
}
}

View File

@@ -0,0 +1,14 @@
package cn.daxpay.single.service.core.record.repair.dao;
import cn.daxpay.single.service.core.record.repair.entity.TradeAdjustRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 交易调整记录
* @author xxm
* @since 2024/7/15
*/
@Mapper
public interface TradeAdjustRecordMapper extends BaseMapper<TradeAdjustRecord> {
}

View File

@@ -6,9 +6,9 @@ import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.RefundRepairWayEnum;
import cn.daxpay.single.service.core.record.repair.convert.PayRepairRecordConvert;
import cn.daxpay.single.service.dto.record.repair.PayRepairRecordDto;
@@ -18,6 +18,7 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 调整
* 支付修复记录 包括支付修复记录和退款修复记录
* @author xxm
* @since 2024/1/6
@@ -49,21 +50,21 @@ public class PayRepairRecord extends MpCreateEntity implements EntityBaseFunctio
/**
* 修复类型 支付修复/退款修复
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@DbColumn(comment = "修复类型", length = 20, isNull = false)
private String repairType;
/**
* 修复来源
* @see PayRepairSourceEnum
* @see TradeAdjustSourceEnum
*/
@DbColumn(comment = "修复来源", length = 20, isNull = false)
private String repairSource;
/**
* 修复方式
* @see PayRepairWayEnum
* @see PayAdjustWayEnum
* @see RefundRepairWayEnum
*/
@DbColumn(comment = "修复方式", length = 20, isNull = false)

View File

@@ -0,0 +1,92 @@
package cn.daxpay.single.service.core.record.repair.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.core.record.repair.convert.TradeAdjustRecordConvert;
import cn.daxpay.single.service.dto.record.repair.TradeAdjustRecordDto;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 订单调整记录
* @author xxm
* @since 2024/7/15
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName("pay_trade_adjust_record")
public class TradeAdjustRecord extends MpCreateEntity implements EntityBaseFunction<TradeAdjustRecordDto> {
/**
* 调整号
* 如果记录有多个, 使用这个作为关联
*/
@DbColumn(comment = "修复号", length = 32, isNull = false)
private String repairNo;
/** 交易ID */
@DbColumn(comment = "本地订单ID", isNull = false)
private Long tradeId;
/**
* 本地交易号, 支付号/退款号
*/
@DbMySqlIndex(comment = "本地交易号索引")
@DbColumn(comment = "本地交易号", length = 32, isNull = false)
private String tradeNo;
/** 通道 */
@DbColumn(comment = "通道", length = 20, isNull = false)
private String channel;
/**
* 来源
* @see TradeAdjustSourceEnum
*/
@DbColumn(comment = "修复来源", length = 20, isNull = false)
private String source;
/**
* 调整类型
* @see cn.daxpay.single.service.code.TradeNotifyTypeEnum
*/
@DbColumn(comment = "调整类型", length = 20, isNull = false)
private String type;
/**
* 调整方式
*/
@DbColumn(comment = "调整方式", length = 20, isNull = false)
private String way;
/**
* 调整前状态
* @see PayStatusEnum
*/
@DbColumn(comment = "修复前状态", length = 20, isNull = false)
private String beforeStatus;
/**
* 调整后状态
*/
@DbColumn(comment = "修复后状态", length = 20, isNull = false)
private String afterStatus;
/**
* 备注
*/
@DbColumn(comment = "备注", length = 600)
private String remark;
@Override
public TradeAdjustRecordDto toDto() {
return TradeAdjustRecordConvert.CONVERT.convert(this);
}
}

View File

@@ -0,0 +1,58 @@
package cn.daxpay.single.service.core.record.repair.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.rest.PageResult;
import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.daxpay.single.service.core.record.repair.dao.TradeAdjustRecordManager;
import cn.daxpay.single.service.core.record.repair.entity.TradeAdjustRecord;
import cn.daxpay.single.service.dto.record.repair.TradeAdjustRecordDto;
import cn.daxpay.single.service.param.report.TradeAdjustRecordQuery;
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.List;
/**
*
* @author xxm
* @since 2024/7/15
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class TradeAdjustRecordService {
private final TradeAdjustRecordManager tradeAdjustRecordManager;
/**
* 根据id查询
*/
public TradeAdjustRecordDto findById(Long id) {
return tradeAdjustRecordManager.findById(id).map(TradeAdjustRecord::toDto).orElseThrow(DataNotExistException::new);
}
/**
* 分页查询
*/
public PageResult<TradeAdjustRecordDto> page(PageParam pageParam, TradeAdjustRecordQuery param){
return MpUtil.convert2DtoPageResult(tradeAdjustRecordManager.page(pageParam,param));
}
/**
* 保存记录
*/
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void saveRecord(TradeAdjustRecord record){
tradeAdjustRecordManager.save(record);
}
/**
* 保存记录
*/
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void saveAllRecord(List<TradeAdjustRecord> records){
tradeAdjustRecordManager.saveAll(records);
}
}

View File

@@ -10,7 +10,7 @@ import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.PaySyncStatusEnum;
import cn.daxpay.single.core.code.RefundSyncStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.core.record.sync.convert.PaySyncRecordConvert;
import cn.daxpay.single.service.dto.record.sync.PaySyncRecordDto;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -55,7 +55,7 @@ public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction<
/**
* 同步类型 支付/退款/分账/转账
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@DbColumn(comment = "同步类型", length = 20, isNull = false)
private String syncType;

View File

@@ -1,7 +1,7 @@
package cn.daxpay.single.service.dto.channel.wechat;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -30,7 +30,7 @@ public class WeChatPayRecordDto extends BaseDto {
/**
* 业务类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "业务类型")
private String type;

View File

@@ -1,7 +1,7 @@
package cn.daxpay.single.service.dto.order.reconcile;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.handler.excel.AmountConverter;
import cn.daxpay.single.service.handler.excel.PaymentTypeConvert;
import com.alibaba.excel.annotation.ExcelIgnore;
@@ -43,7 +43,7 @@ public class ReconcileOutTradeDto extends BaseDto {
/**
* 交易类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "交易类型")
@ExcelProperty(value = "交易类型",converter = PaymentTypeConvert.class)

View File

@@ -1,6 +1,6 @@
package cn.daxpay.single.service.dto.order.reconcile;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.handler.excel.AmountConverter;
import cn.daxpay.single.service.handler.excel.PaymentTypeConvert;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
@@ -32,7 +32,7 @@ public class ReconcileTradeDetailExcel {
/**
* 交易类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "交易类型")
@ExcelProperty(value = "交易类型",converter = PaymentTypeConvert.class)

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.dto.record.callback;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -34,7 +34,7 @@ public class PayCallbackRecordDto extends BaseDto {
/**
* 回调类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "回调类型")
private String callbackType;

View File

@@ -2,9 +2,9 @@ package cn.daxpay.single.service.dto.record.repair;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.RefundRepairWayEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -41,7 +41,7 @@ public class PayRepairRecordDto extends BaseDto {
/**
* 修复方式
* @see PayRepairWayEnum
* @see PayAdjustWayEnum
* @see RefundRepairWayEnum
*/
@Schema(description = "修复方式")
@@ -49,14 +49,14 @@ public class PayRepairRecordDto extends BaseDto {
/**
* 修复类型 支付修复/退款修复
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "修复类型")
private String repairType;
/**
* 修复来源
* @see PayRepairSourceEnum
* @see TradeAdjustSourceEnum
*/
@Schema(description = "修复来源")
private String repairSource;

View File

@@ -0,0 +1,20 @@
package cn.daxpay.single.service.dto.record.repair;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 交易调整记录
* @author xxm
* @since 2024/7/15
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "交易调整记录")
public class TradeAdjustRecordDto extends BaseDto {
}

View File

@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.RefundSyncStatusEnum;
import cn.daxpay.single.core.code.PaySyncStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -47,7 +47,7 @@ public class PaySyncRecordDto extends BaseDto {
/**
* 同步类型 支付/退款
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "同步类型")
private String syncType;

View File

@@ -13,7 +13,7 @@ import lombok.Setter;
*/
@Getter
@Setter
public abstract class AbsPayRepairStrategy implements PayStrategy{
public abstract class AbsPayAdjustStrategy implements PayStrategy{
/** 支付订单 */
private PayOrder order = null;

View File

@@ -1,6 +1,6 @@
package cn.daxpay.single.service.handler.excel;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
@@ -17,7 +17,7 @@ public class PaymentTypeConvert implements Converter<String> {
if (value == null){
return new WriteCellData<>("");
}
PaymentTypeEnum typeEnum = PaymentTypeEnum.findByCode(value);
TradeTypeEnum typeEnum = TradeTypeEnum.findByCode(value);
return new WriteCellData<>(typeEnum.getName());
}
}

View File

@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.annotation.QueryParam;
import cn.bootx.platform.common.core.rest.param.QueryOrder;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.service.code.PayCallbackStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -37,7 +37,7 @@ public class PayCallbackRecordQuery extends QueryOrder {
/**
* 回调类型
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "回调类型")
private String callbackType;

View File

@@ -2,9 +2,9 @@ package cn.daxpay.single.service.param.record;
import cn.bootx.platform.common.core.annotation.QueryParam;
import cn.daxpay.single.core.code.PayStatusEnum;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.PayRepairWayEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.code.PayAdjustWayEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.daxpay.single.service.code.RefundRepairWayEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -37,21 +37,21 @@ public class PayRepairRecordQuery {
/**
* 修复类型 支付修复/退款修复
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "修复类型")
private String repairType;
/**
* 修复来源
* @see PayRepairSourceEnum
* @see TradeAdjustSourceEnum
*/
@Schema(description = "修复来源")
private String repairSource;
/**
* 修复方式
* @see PayRepairWayEnum
* @see PayAdjustWayEnum
* @see RefundRepairWayEnum
*/
@Schema(description = "修复方式")

View File

@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.annotation.QueryParam;
import cn.daxpay.single.core.code.PayChannelEnum;
import cn.daxpay.single.core.code.PaySyncStatusEnum;
import cn.daxpay.single.core.code.RefundSyncStatusEnum;
import cn.daxpay.single.service.code.PaymentTypeEnum;
import cn.daxpay.single.service.code.TradeTypeEnum;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -46,7 +46,7 @@ public class PaySyncRecordQuery {
/**
* 同步类型 支付/退款
* @see PaymentTypeEnum
* @see TradeTypeEnum
*/
@Schema(description = "同步类型")
private String syncType;

View File

@@ -0,0 +1,16 @@
package cn.daxpay.single.service.param.report;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 交易调整记录查询参数
* @author xxm
* @since 2024/7/15
*/
@Data
@Accessors(chain = true)
@Schema(title = "交易调整记录查询参数")
public class TradeAdjustRecordQuery {
}

View File

@@ -1,7 +1,7 @@
package cn.daxpay.single.service.task;
import cn.daxpay.single.core.param.payment.pay.PaySyncParam;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
import cn.daxpay.single.service.code.TradeAdjustSourceEnum;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.payment.pay.dao.PayExpiredTimeRepository;
import cn.daxpay.single.service.core.payment.sync.service.PaySyncService;
@@ -48,7 +48,7 @@ public class PayExpiredTimeTask implements Job {
}
try {
// 设置补偿来源为定时任务
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.TASK);
PaymentContextLocal.get().getRepairInfo().setSource(TradeAdjustSourceEnum.TASK);
// 执行同步操作, 网关同步时会对支付的进行状态的处理
PaySyncParam paySyncParam = new PaySyncParam();
paySyncParam.setOrderNo(orderNo);