feat 支付同步/发起支付时, 如果订单已经超时, 但状态还是待支付, 触发修复操作关闭订单, 增加支付单关闭记录功能, 同步记录/关闭记录/修复记录 增加记录请求ID, 支付单存在异步支付时, 支付时间需要读取支付网关的返回的时间

fix 支付宝关闭支付订单,如果网关已经关闭,会返回错误导致本地订单无法关闭
This commit is contained in:
nws
2024-01-05 00:39:50 +08:00
parent 6d38269cb3
commit 4546b1c8f5
62 changed files with 671 additions and 195 deletions

View File

@@ -13,6 +13,8 @@
## 🙏🙏🙏 求star呀走过路过留个star吧非常非常感谢。🙏🙏🙏
## 🍈项目介绍
[**查看开发进度**](https://gitee.com/bootx/dax-pay/issues/I8TQ9Q)
单商户模式模式重构中, 敬请期待!!!

View File

@@ -1,28 +1,40 @@
2.0.0
2.0.0 重构进度
- 已经完成的
- 参数签名和验签机制
- 开放接口供第三方调用
- 将零散的上下文对象进行抽取为统一的上下文对象
- 拆分原有的策略类,实现粒度更细
- 去除用户概念,作为独立的支付网关使用, 不与其他系统产生耦合性
- [x] 参数签名和验签机制
- [x] 开放接口供第三方调用
- [x] 将零散的上下文对象进行抽取为统一的上下文对象
- [x] 拆分原有的策略类,实现粒度更细
- [x] 去除用户概念,作为独立的支付网关使用, 不与其他系统产生耦合性
- 2023-12-31:
- 支付关闭相关逻辑
- 各支付通道补充相关未实现的逻辑
- 支付订单修复逻辑, 用于回调和支付同步不一致的情况处理
- [x] 支付关闭相关逻辑
- [x] 各支付通道补充相关未实现的逻辑
- [x] 支付订单修复逻辑, 用于回调和同步不一致的情况处理
- 2024-01-01:
- 支付订单修复逻辑, 用于回调和支付同步后不一致的情况处理
- [x] 支付订单修复逻辑, 用于回调和支付同步后不一致的情况处理
- 2024-01-02:
- 添加管理端的各类`Controller`
- x 支持定时同步支付中订单状态, 借助订单超时任务
- 订单取消/修复/取消/同步添加分布式锁, 防止操作订单时出现重复操作
- [x] 添加管理端的各类`Controller`
- [x] 支持定时同步支付中订单状态, 借助订单超时任务
- 2024-01-03:
- [x] 支付流程联调
- [x] 支付同步和支付修复流程优化
- [x] 支付平台全局性配置
- 2024-01-04:
- [x] 支付同步时, 如果订单已经超时, 但状态还是待支付, 触发修复操作关闭订单
- [x] 发起支付时, 如果已经超过订单超时时间, 但状态还是待支付, 触发同步和修复操作
- [x] 支付宝关闭支付订单,如果网关已经关闭,会返回错误导致本地订单无法关闭
- [x] 增加支付单关闭记录功能
- [x] 支付单存在异步支付时, 支付时间需要读取支付网关的返回的时间
- [x] 同步记录/关闭记录/修复记录 增加记录请求ID
- 2024-01-05:
- [x] 支付同步日志记录, 无论同步成功还是失败, 以及修复成功还是失败, 都需要记录日志
- [ ] 超时自动取消功能联调
- **任务池**
- 订单取消/修复/取消/同步添加分布式锁, 防止操作订单时出现重复操作
- 支付配置支持数据库配置和配置文件配置
- 支付订单的各类操作接入订单超时任务处理
- 超时任务处理支持轮训表+Redis过期事件
- 增加回调机制
- 增加消息通知机制
- 超时任务处理支持轮训表
- 增加回调机制(通知客户端)
- 增加消息通知机制(通知客户端)
- 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
- 记录支付修复单的情况, 主要分为自动修复, 人工介入
- 支付平台全局性配置
- 微信消息通知相关配置
- 钉钉消息通知配置

View File

@@ -1,8 +1,12 @@
package cn.bootx.platform.daxpay.code;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Objects;
/**
* 支付状态
* @author xxm
@@ -27,4 +31,14 @@ public enum PayStatusEnum {
/** 名称 */
private final String name;
/**
* 根据编码获取枚举
*/
public static PayStatusEnum findByCode(String code){
return Arrays.stream(PayStatusEnum.values())
.filter(payStatusEnum -> Objects.equals(payStatusEnum.getCode(), code))
.findFirst()
.orElseThrow(() -> new DataNotExistException("该枚举不存在"));
}
}

View File

@@ -16,18 +16,14 @@ import java.util.Objects;
@Getter
@AllArgsConstructor
public enum PaySyncStatusEnum {
NOT_SYNC("not_sync", "不需要同步"),
FAIL("fail", "查询失败"),
PAY_SUCCESS("pay_success", "支付成功"),
PAY_WAIT("pay_wait", "等待付款中"),
CLOSED("closed", "已关闭"),
REFUND("refund", "已退款"),
NOT_FOUND("not_found", "未查询到订单"),
/** 例如支付宝支付后, 客户未进行操作, 将不会创建出订单, 所以同步会返回未查询到订单 */
IGNORE("ignore", "忽略"),
/** 本地订单到了超时时间, 但是网关和本地都未关闭, 需要触发关闭相关处理 */
TIMEOUT("timeout", "超时未关闭"),
FAIL("fail", "查询失败");
TIMEOUT("timeout", "超时未关闭");
/** 编码 */
private final String code;

View File

@@ -27,7 +27,7 @@ public abstract class PayCommonParam {
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String extraParam;
private String attach;
@Schema(description = "是否不进行同步通知的跳转")
private boolean notReturn;

View File

@@ -18,5 +18,5 @@ public class PayCommonResult {
private String reqId = MDC.get(CommonCode.TRACE_ID);
@Schema(description = "商户扩展参数,回调时会原样返回")
private String extraParam;
private String attach;
}

View File

@@ -6,7 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import static cn.bootx.platform.daxpay.code.PaySyncStatusEnum.NOT_SYNC;
import static cn.bootx.platform.daxpay.code.PaySyncStatusEnum.FAIL;
/**
* 支付单同步结果
@@ -21,13 +21,23 @@ public class PaySyncResult extends PayCommonResult{
/**
* 支付网关同步状态
* @see PaySyncStatusEnum#NOT_SYNC
* @see PaySyncStatusEnum
*/
private String syncStatus = NOT_SYNC.getCode();
private String syncStatus = FAIL.getCode();
@Schema(description = "是否同步成功")
private boolean success;
@Schema(description = "失败原因")
private String errorMsg;
@Schema(description = "是否进行了修复")
private boolean repair;
@Schema(description = "支付单修复前状态")
private String oldStatus;
@Schema(description = "支付单修复后状态")
private String repairStatus;
}

View File

@@ -38,6 +38,7 @@ public class PayCallbackController {
@Operation(summary = "支付宝回调")
@PostMapping("/alipay")
public String aliPay(HttpServletRequest request) {
Map<String, String> stringStringMap = AliPayApi.toMap(request);
return aliPayCallbackService.payCallback(stringStringMap);
}

View File

@@ -44,6 +44,9 @@ public interface AliPayCode {
/** 支付宝流水号 */
String TRADE_NO = "trade_no";
/** 交易付款时间 yyyy-MM-dd HH:mm:ss */
String GMT_PAYMENT = "gmt_payment";
/** appId */
String APP_ID = "app_id";
@@ -76,6 +79,8 @@ public interface AliPayCode {
// 错误提示
/** 交易不存在 */
String ACQ_TRADE_NOT_EXIST = "ACQ.TRADE_NOT_EXIST";
/** 交易不存在 */
String ACQ_TRADE_STATUS_ERROR = "ACQ.TRADE_STATUS_ERROR";
// 网关返回码
String SUCCESS = "10000";

View File

@@ -57,6 +57,9 @@ public interface WeChatPayCode {
/** 微信交易单号 */
String TRANSACTION_ID = "transaction_id";
/** 支付完成时间 */
String TIME_END = "time_end";
// 交易状态
/** 支付成功 */
String TRADE_SUCCESS = "SUCCESS";

View File

@@ -18,7 +18,6 @@ public class AsyncPayLocal {
/** 异步支付方式 */
private PayWayEnum payWay;
/**
* 第三方支付平台订单号
* 1. 如付款码支付直接成功时会出现
@@ -33,4 +32,7 @@ public class AsyncPayLocal {
/** 订单失效时间, 优先用这个 */
private LocalDateTime expiredTime;
/** 支付完成时间(通常用于接收异步支付返回的时间) */
private LocalDateTime payTime;
}

View File

@@ -21,7 +21,7 @@ public class PaymentContext {
/** 平台全局配置 */
private final PlatformLocal platform = new PlatformLocal();
/** 异步支付相关信息, 不只局限在支付流程,同步、退款、回调中都会用到 */
/** 异步支付相关信息, 不只局限在支付流程,同步、回调中都会用到 */
private final AsyncPayLocal asyncPayInfo = new AsyncPayLocal();
/** 异步退款相关信息 */

View File

@@ -18,7 +18,7 @@ public class RequestLocal {
private String clientIp;
/** 商户扩展参数,回调时会原样返回 */
private String extraParam;
private String attach;
/** 签名 */
private String sign;

View File

@@ -20,7 +20,7 @@ import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@DbTable(comment = "支付宝支付记录")
@TableName("pay_ali_payment")
@TableName("pay_ali_pay_order")
public class AliPayOrder extends BasePayOrder implements EntityBaseFunction<AliPaymentDto> {
/** 支付宝交易号 */

View File

@@ -1,15 +1,16 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
import cn.bootx.platform.common.core.util.CertUtil;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.redis.RedisClient;
import cn.bootx.platform.daxpay.service.code.AliPayCode;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.CallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.PayCallbackRecordManager;
import cn.bootx.platform.daxpay.service.func.AbsPayCallbackStrategy;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
@@ -20,9 +21,12 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import static cn.bootx.platform.daxpay.service.code.AliPayCode.*;
/**
* 支付宝回调处理
*
@@ -35,7 +39,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
private final AliPayConfigService aliasConfigService;
public AliPayCallbackService(RedisClient redisClient, CallbackRecordManager callbackRecordManager,
public AliPayCallbackService(RedisClient redisClient, PayCallbackRecordManager callbackRecordManager,
PayCallbackService payCallbackService, AliPayConfigService aliasConfigService) {
super(redisClient, callbackRecordManager, payCallbackService);
this.aliasConfigService = aliasConfigService;
@@ -55,8 +59,8 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
@Override
public String getTradeStatus() {
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
String tradeStatus = params.get(AliPayCode.TRADE_STATUS);
if (Objects.equals(tradeStatus, AliPayCode.NOTIFY_TRADE_SUCCESS)) {
String tradeStatus = params.get(TRADE_STATUS);
if (Objects.equals(tradeStatus, NOTIFY_TRADE_SUCCESS)) {
return PayStatusEnum.SUCCESS.getCode();
}
return PayStatusEnum.FAIL.getCode();
@@ -70,7 +74,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
public boolean verifyNotify() {
Map<String, String> params =PaymentContextLocal.get().getCallbackParam();
String callReq = JSONUtil.toJsonStr(params);
String appId = params.get(AliPayCode.APP_ID);
String appId = params.get(APP_ID);
if (StrUtil.isBlank(appId)) {
log.error("支付宝回调报文 appId 为空 {}", callReq);
return false;
@@ -81,7 +85,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
return false;
}
try {
if (Objects.equals(alipayConfig.getAuthType(), AliPayCode.AUTH_TYPE_KEY)) {
if (Objects.equals(alipayConfig.getAuthType(), AUTH_TYPE_KEY)) {
return AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
}
else {
@@ -99,7 +103,16 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
@Override
public void initContext() {
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
PaymentContextLocal.get().getAsyncPayInfo().setTradeNo(callbackParam.get(AliPayCode.TRADE_NO));
// 订单号
PaymentContextLocal.get().getAsyncPayInfo().setTradeNo(callbackParam.get(TRADE_NO));
// 支付时间
String gmpTime = callbackParam.get(GMT_PAYMENT);
if (StrUtil.isNotBlank(gmpTime)) {
LocalDateTime time = LocalDateTimeUtil.parse(gmpTime, DatePattern.NORM_DATETIME_PATTERN);
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(time);
} else {
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(LocalDateTime.now());
}
}
/**
@@ -108,7 +121,7 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
@Override
public Long getPaymentId() {
Map<String, String> params = PaymentContextLocal.get().getCallbackParam();
return Long.valueOf(params.get(AliPayCode.OUT_TRADE_NO));
return Long.valueOf(params.get(OUT_TRADE_NO));
}
/**

View File

@@ -1,7 +1,9 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
import cn.bootx.platform.common.spring.exception.RetryableException;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.platform.daxpay.service.code.AliPayCode;
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import com.alipay.api.AlipayApiException;
@@ -25,13 +27,16 @@ import java.util.Objects;
@Service
@RequiredArgsConstructor
public class AliPayCloseService {
private final AliPaySyncService paySyncService;
/**
* 关闭支付 此处使用交易关闭接口, 支付宝支持 交易关闭 和 交易撤销 两种关闭订单的方式, 区别如下
* 交易关闭: 只有订单在未支付的状态下才可以进行关闭, 商户不需要额外申请就有此接口的权限
* 交易撤销: 如果用户支付成功,会将此订单资金退还给用户. 限制时间为1天过了24小时该接口无法再使用。可以视为一个特殊的接口, 需要专门签约这个接口的权限
*
* TODO 如果返回已经关闭, 也视为关闭成功, 考虑如果关闭识别, 查询一下网关的状态进行对比
* 1. 如果未查询到支付单,视为支付关闭,
* 2. 如果返回"当前交易状态不支持此操作", 同步网关支付状态, 判断网关是否已经被关闭
*
*/
@Retryable(value = RetryableException.class)
public void close(PayOrder payOrder) {
@@ -41,6 +46,16 @@ public class AliPayCloseService {
try {
AlipayTradeCloseResponse response = AliPayApi.tradeCloseToResponse(model);
if (!Objects.equals(AliPayCode.SUCCESS, response.getCode())) {
// 如果返回"当前交易状态不支持此操作", 同步网关支付状态, 判断网关是否已经被关闭
if (Objects.equals(response.getSubCode(),AliPayCode.ACQ_TRADE_STATUS_ERROR)){
if (this.syncStatus(payOrder)){
return;
}
}
// 返回"交易不存在"视同关闭成功
if (Objects.equals(response.getSubCode(),AliPayCode.ACQ_TRADE_NOT_EXIST)){
return;
}
log.error("网关返回关闭失败: {}", response.getSubMsg());
throw new PayFailureException(response.getSubMsg());
}
@@ -50,4 +65,23 @@ public class AliPayCloseService {
}
}
/**
* 关闭失败后, 获取支付网关的状态, 如果是关闭返回true, 其他情况抛出异常
*/
private boolean syncStatus(PayOrder payOrder){
GatewaySyncResult gatewaySyncResult = paySyncService.syncPayStatus(payOrder);
// 已经关闭
if (Objects.equals(gatewaySyncResult.getSyncStatus(), PaySyncStatusEnum.CLOSED)){
return true;
}
// 同步错误
else if (Objects.equals(gatewaySyncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
throw new PayFailureException("关闭失败, 原因: "+gatewaySyncResult.getErrorMsg());
}
// 其他状态
else {
throw new PayFailureException("当前交易状态不支持关闭操作, 请对订单同步状态后再进行操作");
}
}
}

View File

@@ -1,10 +1,10 @@
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.platform.daxpay.service.code.AliPayCode;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.channel.alipay.dao.AliPayOrderManager;
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.hutool.json.JSONUtil;
@@ -16,6 +16,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Objects;
/**
@@ -28,8 +29,6 @@ import java.util.Objects;
@Service
@RequiredArgsConstructor
public class AliPaySyncService {
private final AliPayOrderManager payOrderManager;
/**
* 与支付宝网关同步状态, 退款状态会
* 1 远程支付成功
@@ -47,10 +46,13 @@ public class AliPaySyncService {
// 查询退款参数
AlipayTradeQueryResponse response = AliPayApi.tradeQueryToResponse(queryModel);
String tradeStatus = response.getTradeStatus();
syncResult.setJson(JSONUtil.toJsonStr(response));
syncResult.setSyncInfo(JSONUtil.toJsonStr(response));
// 支付完成
if (Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_SUCCESS) || Objects.equals(tradeStatus, AliPayCode.PAYMENT_TRADE_FINISHED)) {
PaymentContextLocal.get().getAsyncPayInfo().setTradeNo(response.getTradeNo());
// 支付完成时间
LocalDateTime payTime = LocalDateTimeUtil.of(response.getSendPayDate());
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(payTime);
return syncResult.setSyncStatus(PaySyncStatusEnum.PAY_SUCCESS);
}
// 待支付
@@ -68,12 +70,12 @@ public class AliPaySyncService {
}
// 支付宝支付后, 客户未进行操作将不会创建出订单, 所以交易不存在等于未查询订单
if (Objects.equals(response.getSubCode(), AliPayCode.ACQ_TRADE_NOT_EXIST)) {
return syncResult.setSyncStatus(PaySyncStatusEnum.IGNORE);
return syncResult.setSyncStatus(PaySyncStatusEnum.PAY_WAIT);
}
}
catch (AlipayApiException e) {
log.error("查询订单失败:", e);
syncResult.setMsg(e.getErrMsg());
syncResult.setErrorMsg(e.getErrMsg());
}
return syncResult;
}

View File

@@ -16,7 +16,7 @@ import lombok.experimental.Accessors;
@Data
@EqualsAndHashCode(callSuper = true)
@DbTable(comment = "现金支付记录")
@TableName("pay_cash_payment")
@TableName("pay_cash_pay_order")
@Accessors(chain = true)
public class CashPayOrder extends BasePayOrder {

View File

@@ -16,7 +16,7 @@ import lombok.experimental.Accessors;
@Data
@DbTable(comment = "云闪付支付订单")
@Accessors(chain = true)
@TableName("pay_union_payment")
@TableName("pay_union_pay_order")
public class UnionPayOrder extends BasePayOrder {
}

View File

@@ -25,7 +25,7 @@ import lombok.experimental.Accessors;
@Data
@DbTable(comment = "储值卡支付记录")
@Accessors(chain = true)
@TableName(value = "pay_voucher_payment",autoResultMap = true)
@TableName(value = "pay_voucher_pay_order",autoResultMap = true)
public class VoucherPayOrder extends BasePayOrder implements EntityBaseFunction<VoucherPayOrderDto> {
/** 扣款储值卡 */

View File

@@ -1,14 +1,16 @@
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.redis.RedisClient;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.CallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.PayCallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
import cn.bootx.platform.daxpay.service.func.AbsPayCallbackStrategy;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.enums.SignType;
@@ -16,11 +18,13 @@ import com.ijpay.core.kit.WxPayKit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static cn.bootx.platform.daxpay.service.code.WeChatPayCode.APPID;
import static cn.bootx.platform.daxpay.service.code.WeChatPayCode.TIME_END;
/**
@@ -34,7 +38,7 @@ import static cn.bootx.platform.daxpay.service.code.WeChatPayCode.APPID;
public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
private final WeChatPayConfigService weChatPayConfigService;
public WeChatPayCallbackService(RedisClient redisClient, CallbackRecordManager callbackRecordManager,
public WeChatPayCallbackService(RedisClient redisClient, PayCallbackRecordManager callbackRecordManager,
PayCallbackService payCallbackService, WeChatPayConfigService weChatPayConfigService) {
super(redisClient, callbackRecordManager, payCallbackService);
this.weChatPayConfigService = weChatPayConfigService;
@@ -101,7 +105,16 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
@Override
public void initContext() {
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
// 订单号
PaymentContextLocal.get().getAsyncPayInfo().setTradeNo(callbackParam.get(WeChatPayCode.TRANSACTION_ID));
// 支付时间
String timeEnd = callbackParam.get(TIME_END);
if (StrUtil.isNotBlank(timeEnd)) {
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(time);
} else {
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(LocalDateTime.now());
}
}
/**

View File

@@ -1,9 +1,12 @@
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.WxPayKit;
@@ -13,6 +16,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
@@ -42,7 +46,7 @@ public class WeChatPaySyncService {
try {
String xmlResult = WxPayApi.orderQuery(params);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
syncResult.setJson(JSONUtil.toJsonStr(result));
syncResult.setSyncInfo(JSONUtil.toJsonStr(result));
// 查询失败
if (!WxPayKit.codeIsOk(result.get(WeChatPayCode.RETURN_CODE))) {
log.warn("查询微信订单失败:{}", result);
@@ -56,8 +60,10 @@ public class WeChatPaySyncService {
}
String tradeStatus = result.get(WeChatPayCode.TRADE_STATE);
// 支付完成
if (Objects.equals(tradeStatus, WeChatPayCode.TRADE_SUCCESS)
|| Objects.equals(tradeStatus, WeChatPayCode.TRADE_ACCEPT)) {
if (Objects.equals(tradeStatus, WeChatPayCode.TRADE_SUCCESS) || Objects.equals(tradeStatus, WeChatPayCode.TRADE_ACCEPT)) {
String timeEnd = result.get(WeChatPayCode.TIME_END);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
PaymentContextLocal.get().getAsyncPayInfo().setPayTime(time);
return syncResult.setSyncStatus(PaySyncStatusEnum.PAY_SUCCESS);
}
// 待支付
@@ -79,7 +85,7 @@ public class WeChatPaySyncService {
}
catch (RuntimeException e) {
log.error("查询订单失败:", e);
syncResult.setMsg(e.getMessage());
syncResult.setErrorMsg(e.getMessage());
}
return syncResult;
}

View File

@@ -1,14 +1,17 @@
package cn.bootx.platform.daxpay.service.core.payment.close.service;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.common.entity.OrderRefundableInfo;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.payment.close.factory.PayCloseStrategyFactory;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.bootx.platform.daxpay.param.pay.PayCloseParam;
import cn.bootx.platform.daxpay.service.common.entity.OrderRefundableInfo;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.payment.close.factory.PayCloseStrategyFactory;
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
import cn.bootx.platform.daxpay.service.core.record.close.service.PayCloseRecordService;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.hutool.core.collection.CollectionUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -29,6 +32,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class PayCloseService {
private final PayOrderService payOrderService;
private final PayCloseRecordService payCloseRecordService;
/**
* 关闭支付
@@ -48,7 +52,7 @@ public class PayCloseService {
}
/**
* 取消支付记录
* 关闭支付记录
*/
private void close(PayOrder payOrder) {
// 状态检查, 只有支付中可以进行取消支付
@@ -76,8 +80,9 @@ public class PayCloseService {
// 4.执行关闭策略
payCloseStrategies.forEach(AbsPayCloseStrategy::doCloseHandler);
}
catch (Exception e) {
// TODO 记录关闭失败的记录
catch (PayFailureException e) {
// 记录关闭失败的记录
this.saveRecord(payOrder,false,e.getMessage());
throw e;
}
@@ -92,5 +97,27 @@ public class PayCloseService {
// 取消订单
payOrder.setStatus(PayStatusEnum.CLOSE.getCode());
payOrderService.updateById(payOrder);
this.saveRecord(payOrder,true,null);
}
/**
* 保存关闭记录
*/
private void saveRecord(PayOrder payOrder, boolean closed, String errMsg){
String clientIp = PaymentContextLocal.get()
.getRequest()
.getClientIp();
String reqId = PaymentContextLocal.get()
.getRequest()
.getReqId();
PayCloseRecord record = new PayCloseRecord()
.setPaymentId(payOrder.getId())
.setAsyncChannel(payOrder.getAsyncChannel())
.setClosed(closed)
.setErrorMsg(errMsg)
.setClientIp(clientIp)
.setReqId(reqId);
payCloseRecordService.saveRecord(record);
}
}

View File

@@ -52,7 +52,7 @@ public class PaymentAssistService {
private void initRequest(PayCommonParam payCommonParam){
RequestLocal request = PaymentContextLocal.get().getRequest();
request.setClientIp(payCommonParam.getClientIp())
.setExtraParam(payCommonParam.getExtraParam())
.setAttach(payCommonParam.getAttach())
.setSign(payCommonParam.getSign())
.setVersion(payCommonParam.getVersion())
.setReqTime(payCommonParam.getReqTime())

View File

@@ -4,10 +4,14 @@ import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.pay.PayParam;
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
import cn.bootx.platform.daxpay.service.common.context.AsyncPayLocal;
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
import cn.bootx.platform.daxpay.service.core.record.pay.builder.PaymentBuilder;
import cn.bootx.platform.daxpay.service.core.record.pay.dao.PayOrderChannelManager;
import cn.bootx.platform.daxpay.service.core.record.pay.dao.PayOrderExtraManager;
@@ -15,9 +19,6 @@ import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrderChannel;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.pay.PayParam;
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
import cn.bootx.platform.daxpay.service.util.PayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
@@ -40,6 +41,8 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class PayAssistService {
private final PaySyncService paySyncService;
private final PayOrderService payOrderService;
private final PayOrderExtraManager payOrderExtraManager;
private final PayOrderChannelManager payOrderChannelManager;
@@ -167,9 +170,22 @@ public class PayAssistService {
// 根据订单查询支付记录
PayOrder payOrder = payOrderService.findByBusinessNo(businessNo).orElse(null);
if (Objects.nonNull(payOrder)) {
// 待支付
if (Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())){
// 如果支付超时, 触发订单同步操作, 同时抛出异常
if (Objects.nonNull(payOrder.getExpiredTime()) && LocalDateTimeUtil.ge(LocalDateTime.now(), payOrder.getExpiredTime())) {
paySyncService.syncPayOrder(payOrder);
throw new PayFailureException("支付已超时,请重新确认支付状态");
}
return payOrder;
}
// 已经支付状态
if (PayStatusEnum.SUCCESS.getCode().equals(payOrder.getStatus())) {
throw new PayFailureException("已经支付成功,请勿重新支付");
}
// 支付失败类型状态
List<String> tradesStatus = Arrays.asList(PayStatusEnum.FAIL.getCode(), PayStatusEnum.CANCEL.getCode(),
PayStatusEnum.CLOSE.getCode());
PayStatusEnum.CLOSE.getCode(), PayStatusEnum.TIMEOUT.getCode());
if (tradesStatus.contains(payOrder.getStatus())) {
throw new PayFailureException("支付失败或已经被关闭");
}
@@ -178,13 +194,10 @@ public class PayAssistService {
if (tradesStatus.contains(payOrder.getStatus())) {
throw new PayFailureException("退款中");
}
// 支付超时状态
if (Objects.nonNull(payOrder.getExpiredTime())
&& LocalDateTimeUtil.ge(LocalDateTime.now(), payOrder.getExpiredTime())) {
throw new PayFailureException("支付已超时");
// 其他状态直接抛出兜底异常
throw new PayFailureException("订单不是待支付状态,请重新确认订单状态");
}
}
return payOrder;
return null;
}
}

View File

@@ -55,7 +55,7 @@ public class PayService {
// 异步支付方式检查
PayUtil.validationAsyncPay(payParam);
// 获取并校验支付订单状态
// 获取并校验支付订单状态, 如果超时, 触发支付单同步和修复动作
PayOrder payOrder = payAssistService.getOrderAndCheck(payParam.getBusinessNo());
// 初始化上下文

View File

@@ -108,7 +108,7 @@ public class PayRefundAssistService {
* 保存退款记录 成不成功都记录
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveRefundOrder(RefundParam refundParam, PayOrder payOrder){
public void saveOrder(RefundParam refundParam, PayOrder payOrder){
AsyncRefundLocal asyncRefundInfo = PaymentContextLocal.get().getAsyncRefundInfo();
// 退款金额
Integer amount = refundParam.getRefundChannels()
@@ -119,15 +119,15 @@ public class PayRefundAssistService {
PayRefundOrder refundOrder = new PayRefundOrder()
.setRefundRequestNo(asyncRefundInfo.getRefundNo())
.setAmount(amount)
.setClientIp(refundParam.getClientIp())
.setPaymentId(payOrder.getId())
.setBusinessNo(payOrder.getBusinessNo())
.setRefundTime(LocalDateTime.now())
.setTitle(payOrder.getTitle())
.setErrorMsg(asyncRefundInfo.getErrorMsg())
.setErrorCode(asyncRefundInfo.getErrorCode())
.setStatus(Objects.isNull(asyncRefundInfo.getErrorCode()) ? PayRefundStatusEnum.SUCCESS.getCode()
: PayRefundStatusEnum.FAIL.getCode());
.setStatus(Objects.isNull(asyncRefundInfo.getErrorCode()) ? PayRefundStatusEnum.SUCCESS.getCode() : PayRefundStatusEnum.FAIL.getCode())
.setClientIp(refundParam.getClientIp())
.setReqId(PaymentContextLocal.get().getRequest().getReqId());
payRefundOrderManager.save(refundOrder);
}
}

View File

@@ -107,7 +107,7 @@ public class PayRefundService {
}
catch (Exception e) {
// 记录退款失败的记录
payRefundAssistService.saveRefundOrder(refundParam,payOrder);
payRefundAssistService.saveOrder(refundParam,payOrder);
throw e;
}
@@ -137,6 +137,6 @@ public class PayRefundService {
}
payOrder.setRefundableBalance(refundableBalance);
payOrderService.updateById(payOrder);
payRefundAssistService.saveRefundOrder(refundParam,payOrder);
payRefundAssistService.saveOrder(refundParam,payOrder);
}
}

View File

@@ -0,0 +1,19 @@
package cn.bootx.platform.daxpay.service.core.payment.repair.result;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 修复结果
* @author xxm
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class RepairResult {
/** 修复前状态 */
private PayStatusEnum oldStatus;
/** 修复后状态 */
private PayStatusEnum repairStatus;
}

View File

@@ -2,8 +2,10 @@ package cn.bootx.platform.daxpay.service.core.payment.repair.service;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.common.entity.OrderRefundableInfo;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.payment.repair.factory.PayRepairStrategyFactory;
import cn.bootx.platform.daxpay.service.core.payment.repair.param.PayRepairParam;
import cn.bootx.platform.daxpay.service.core.payment.repair.result.RepairResult;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.func.AbsPayRepairStrategy;
@@ -32,7 +34,7 @@ public class PayRepairService {
* 修复支付单
*/
@Transactional(rollbackFor = Exception.class )
public void repair(PayOrder order, PayRepairParam repairParam){
public RepairResult repair(PayOrder order, PayRepairParam repairParam){
// 从退款记录中获取支付通道 退款记录中的支付通道跟支付时关联的支付通道一致
List<String> channels = order.getRefundableInfos()
.stream()
@@ -41,16 +43,20 @@ public class PayRepairService {
// 初始化修复参数
List<AbsPayRepairStrategy> repairStrategies = PayRepairStrategyFactory.createAsyncLast(channels);
repairStrategies.forEach(repairStrategy -> repairStrategy.initRepairParam(order, repairParam.getRepairSource()));
RepairResult repairResult = new RepairResult().setOldStatus(PayStatusEnum.findByCode(order.getStatus()));
// 根据不同的类型执行对应的修复逻辑
switch (repairParam.getRepairType()) {
case SUCCESS:
this.success(order, repairStrategies);
repairResult.setRepairStatus(PayStatusEnum.SUCCESS);
break;
case CLOSE:
this.close(order, repairStrategies);
repairResult.setRepairStatus(PayStatusEnum.CLOSE);
break;
case TIMEOUT:
this.timeout(order, repairStrategies);
repairResult.setRepairStatus(PayStatusEnum.TIMEOUT);
break;
case REFUND:
this.refund(order, repairStrategies);
@@ -58,6 +64,7 @@ public class PayRepairService {
default:
break;
}
return repairResult;
}
/**
@@ -66,6 +73,9 @@ public class PayRepairService {
* 回调: 将异步支付状态修改为成功
*/
private void success(PayOrder payment, List<AbsPayRepairStrategy> strategies) {
LocalDateTime payTime = PaymentContextLocal.get()
.getAsyncPayInfo()
.getPayTime();
// 执行个通道的成功处理方法
strategies.forEach(AbsPayRepairStrategy::doSuccessHandler);
@@ -73,7 +83,7 @@ public class PayRepairService {
// 修改订单支付状态为成功
payment.setStatus(PayStatusEnum.SUCCESS.getCode());
// TODO 读取支付网关中的时间
payment.setPayTime(LocalDateTime.now());
payment.setPayTime(payTime);
payOrderService.updateById(payment);
}

View File

@@ -4,10 +4,10 @@ import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import static cn.bootx.platform.daxpay.code.PaySyncStatusEnum.NOT_SYNC;
import static cn.bootx.platform.daxpay.code.PaySyncStatusEnum.FAIL;
/**
* 支付网关同步状态记录对象
* 支付网关同步结果
*
* @author xxm
* @since 2021/4/21
@@ -17,15 +17,15 @@ import static cn.bootx.platform.daxpay.code.PaySyncStatusEnum.NOT_SYNC;
public class GatewaySyncResult {
/**
* 支付网关同步状态
* @see PaySyncStatusEnum#NOT_SYNC
* 支付网关订单状态
* @see PaySyncStatusEnum
*/
private PaySyncStatusEnum syncStatus = NOT_SYNC;
private PaySyncStatusEnum syncStatus = FAIL;
/** 网关返回对象json字符串 */
private String json;
/** 网关返回对象, 序列化为json字符串 */
private String syncInfo;
/** 错误提示 */
private String msg;
private String errorMsg;
}

View File

@@ -9,20 +9,24 @@ import cn.bootx.platform.daxpay.param.pay.PaySyncParam;
import cn.bootx.platform.daxpay.result.pay.PaySyncResult;
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
import cn.bootx.platform.daxpay.service.code.PayRepairTypeEnum;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.payment.repair.param.PayRepairParam;
import cn.bootx.platform.daxpay.service.core.payment.repair.service.PayRepairService;
import cn.bootx.platform.daxpay.service.core.payment.sync.factory.PaySyncStrategyFactory;
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.record.sync.service.PaySyncOrderService;
import cn.bootx.platform.daxpay.service.core.record.sync.entity.PaySyncRecord;
import cn.bootx.platform.daxpay.service.core.record.sync.service.PaySyncRecordService;
import cn.bootx.platform.daxpay.service.func.AbsPaySyncStrategy;
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.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -37,13 +41,14 @@ import java.util.Objects;
public class PaySyncService {
private final PayOrderService payOrderService;
private final PaySyncOrderService syncOrderService;
private final PaySyncRecordService paySyncRecordService;
private final PayRepairService repairService;
/**
* 支付同步
* 支付同步, 开启一个新的事务, 不受外部抛出异常的影响
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public PaySyncResult sync(PaySyncParam param) {
PayOrder payOrder = null;
if (Objects.nonNull(param.getPaymentId())){
@@ -62,28 +67,49 @@ public class PaySyncService {
return this.syncPayOrder(payOrder);
}
/**
* 同步支付状态
* 同步支付状态, 开启一个新的事务, 不受外部抛出异常的影响
* 1. 如果状态一致, 不进行处理
* 2. 如果状态不一致, 调用修复逻辑进行修复
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public PaySyncResult syncPayOrder(PayOrder order) {
// 获取同步策略类
AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(order.getAsyncChannel());
syncPayStrategy.initPayParam(order);
// 获取网关支付状态
// 记录支付单同步前后的状态
String oldStatus = order.getStatus();
String repairStatus = null;
// 执行同步操作, 获取支付网关同步的结果
GatewaySyncResult syncResult = syncPayStrategy.doSyncStatus();
// 判断是否同步成功
if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
// 同步失败, 返回失败响应, 同时记录失败的日志
this.saveRecord(order, syncResult, true, oldStatus, null, syncResult.getErrorMsg());
return new PaySyncResult().setErrorMsg(syncResult.getErrorMsg());
}
// 判断网关状态是否和支付单一致, 同时更新网关同步状态
boolean statusSync = this.checkStatusSync(syncResult,order);
try {
// 状态不一致,执行支付单修复逻辑
if (!statusSync){
// 根据同步记录对支付单进行处理处理
this.resultHandler(syncResult, order);
repairStatus = order.getStatus();
}
// 记录同步的结果
syncOrderService.saveRecord(syncResult,order);
} catch (Exception e) {
// 同步失败, 返回失败响应, 同时记录失败的日志 TODO 后面异常范围能这么宽泛
syncResult.setSyncStatus(PaySyncStatusEnum.FAIL);
this.saveRecord(order, syncResult, false, oldStatus, null, e.getMessage());
return new PaySyncResult().setErrorMsg(e.getMessage());
}
// 同步成功记录日志
this.saveRecord( order, syncResult, !statusSync, oldStatus, repairStatus, null);
return new PaySyncResult()
.setSuccess(true)
.setRepair(!statusSync)
.setRepairStatus(repairStatus)
.setSyncStatus(syncResult.getSyncStatus().getCode());
}
@@ -97,9 +123,8 @@ public class PaySyncService {
if (orderStatus.equals(PayStatusEnum.SUCCESS.getCode()) && syncStatus.equals(PaySyncStatusEnum.PAY_SUCCESS)){
return true;
}
// 待支付比对 网关忽略和支付中都代表待支付, 需要处理订单超时的情况
List<PaySyncStatusEnum> enums = Arrays.asList(PaySyncStatusEnum.PAY_WAIT, PaySyncStatusEnum.IGNORE);
// 待支付比对 支付中都代表待支付, 需要处理订单超时的情况
List<PaySyncStatusEnum> enums = Collections.singletonList(PaySyncStatusEnum.PAY_WAIT);
if (orderStatus.equals(PayStatusEnum.PROGRESS.getCode()) && enums.contains(syncStatus)){
// 判断支付单是否支付超时, 如果待支付状态下触发超时
if (LocalDateTimeUtil.le(order.getExpiredTime(), LocalDateTime.now())){
@@ -153,9 +178,6 @@ public class PaySyncService {
repairService.repair(payOrder, repairParam);
break;
}
// 不需要进行处理
case IGNORE:
break;
// 调用出错
case TIMEOUT:
repairParam.setRepairType(PayRepairTypeEnum.TIMEOUT);
@@ -166,10 +188,34 @@ public class PaySyncService {
log.warn("支付状态同步接口调用出错");
break;
}
case NOT_SYNC:
default: {
throw new BizException("代码有问题");
}
}
}
/**
* 保存同步记录
* @param payOrder 支付单
* @param syncResult 同步结果
* @param repair 是否修复
* @param oldStatus 修复前的状态
* @param repairStatus 修复后的状态
* @param errorMsg 错误信息
*/
private void saveRecord(PayOrder payOrder,GatewaySyncResult syncResult, boolean repair, String oldStatus, String repairStatus, String errorMsg){
PaySyncRecord paySyncRecord = new PaySyncRecord()
.setPaymentId(payOrder.getId())
.setChannel(payOrder.getAsyncChannel())
.setSyncInfo(syncResult.getSyncInfo())
.setSyncStatus(syncResult.getSyncStatus().getCode())
.setRepairOrder(repair)
.setOldStatus(oldStatus)
.setRepairStatus(repairStatus)
.setErrorMsg(errorMsg)
.setClientIp(PaymentContextLocal.get().getRequest().getClientIp())
.setReqId(PaymentContextLocal.get().getRequest().getReqId());
paySyncRecordService.saveRecord(paySyncRecord);
}
}

View File

@@ -1,14 +0,0 @@
package cn.bootx.platform.daxpay.service.core.record.callback.convert;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 回调通知转换
* @author xxm
* @since 2023/12/18
*/
@Mapper
public interface CallbackRecordMConvert {
CallbackRecordMConvert CONVERT = Mappers.getMapper(CallbackRecordMConvert.class);
}

View File

@@ -0,0 +1,18 @@
package cn.bootx.platform.daxpay.service.core.record.callback.convert;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.PayCallbackRecord;
import cn.bootx.platform.daxpay.service.dto.record.callback.PayCallbackRecordDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 回调通知转换
* @author xxm
* @since 2023/12/18
*/
@Mapper
public interface PayCallbackRecordConvert {
PayCallbackRecordConvert CONVERT = Mappers.getMapper(PayCallbackRecordConvert.class);
PayCallbackRecordDto convert(PayCallbackRecord in);
}

View File

@@ -1,7 +1,7 @@
package cn.bootx.platform.daxpay.service.core.record.callback.dao;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.CallbackRecord;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.PayCallbackRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
@@ -12,5 +12,5 @@ import org.springframework.stereotype.Repository;
*/
@Slf4j
@Repository
public class CallbackRecordManager extends BaseManager<CallbackRecordMapper, CallbackRecord> {
public class PayCallbackRecordManager extends BaseManager<PayCallbackRecordMapper, PayCallbackRecord> {
}

View File

@@ -1,6 +1,6 @@
package cn.bootx.platform.daxpay.service.core.record.callback.dao;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.CallbackRecord;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.PayCallbackRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@@ -10,5 +10,5 @@ import org.apache.ibatis.annotations.Mapper;
* @since 2023/12/18
*/
@Mapper
public interface CallbackRecordMapper extends BaseMapper<CallbackRecord> {
public interface PayCallbackRecordMapper extends BaseMapper<PayCallbackRecord> {
}

View File

@@ -1,11 +1,16 @@
package cn.bootx.platform.daxpay.service.core.record.callback.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.core.record.callback.convert.PayCallbackRecordConvert;
import cn.bootx.platform.daxpay.service.dto.record.callback.PayCallbackRecordDto;
import cn.bootx.table.modify.annotation.DbComment;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@@ -20,7 +25,9 @@ import java.time.LocalDateTime;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class CallbackRecord extends MpCreateEntity {
@DbTable(comment = "网关回调通知")
@TableName("pay_callback_record")
public class PayCallbackRecord extends MpCreateEntity implements EntityBaseFunction<PayCallbackRecordDto> {
/** 支付记录id */
@DbComment("支付记录id")
private Long paymentId;
@@ -46,7 +53,6 @@ public class CallbackRecord extends MpCreateEntity {
/**
* 回调处理状态
* @see
*/
@DbComment("回调处理状态")
private String status;
@@ -58,4 +64,12 @@ public class CallbackRecord extends MpCreateEntity {
/** 回调时间 */
@DbComment("回调时间")
private LocalDateTime notifyTime;
/**
* 转换
*/
@Override
public PayCallbackRecordDto toDto() {
return PayCallbackRecordConvert.CONVERT.convert(this);
}
}

View File

@@ -1,16 +0,0 @@
package cn.bootx.platform.daxpay.service.core.record.callback.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 接收到的支付回调通知
* @author xxm
* @since 2023/12/18
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CallbackRecordService {
}

View File

@@ -0,0 +1,29 @@
package cn.bootx.platform.daxpay.service.core.record.callback.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.PayCallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.PayCallbackRecord;
import cn.bootx.platform.daxpay.service.dto.record.callback.PayCallbackRecordDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 接收到的支付回调通知
* @author xxm
* @since 2023/12/18
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PayCallbackRecordService {
private final PayCallbackRecordManager callbackRecordManager;
/**
* 根据id查询
*/
public PayCallbackRecordDto findById(Long id) {
return callbackRecordManager.findById(id).map(PayCallbackRecord::toDto).orElseThrow(DataNotExistException::new);
}
}

View File

@@ -0,0 +1,21 @@
package cn.bootx.platform.daxpay.service.core.record.close.convert;
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
import cn.bootx.platform.daxpay.service.dto.record.close.PayCloseRecordDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author xxm
* @since 2024/1/4
*/
@Mapper
public interface PayCloseRecordConvert {
PayCloseRecordConvert CONVERT = Mappers.getMapper(PayCloseRecordConvert.class);
/**
* 转换
*/
PayCloseRecordDto convert(PayCloseRecord in);
}

View File

@@ -0,0 +1,20 @@
package cn.bootx.platform.daxpay.service.core.record.close.dao;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
/**
*
* @author xxm
* @since 2024/1/4
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class PayCloseRecordManager extends BaseManager<PayCloseRecordMapper, PayCloseRecord> {
}

View File

@@ -0,0 +1,14 @@
package cn.bootx.platform.daxpay.service.core.record.close.dao;
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
* @author xxm
* @since 2024/1/4
*/
@Mapper
public interface PayCloseRecordMapper extends BaseMapper<PayCloseRecord> {
}

View File

@@ -0,0 +1,63 @@
package cn.bootx.platform.daxpay.service.core.record.close.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.record.close.convert.PayCloseRecordConvert;
import cn.bootx.platform.daxpay.service.dto.record.close.PayCloseRecordDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbComment;
import cn.bootx.table.modify.annotation.DbTable;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 支付关闭记录
* @author xxm
* @since 2024/1/4
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@DbTable(comment = "支付关闭记录")
@TableName("pay_close_record")
public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction<PayCloseRecordDto> {
/** 支付记录id */
@DbComment("支付记录id")
private Long paymentId;
/**
* 关闭的异步支付通道, 可以为空
* @see PayChannelEnum#getCode()
*/
@DbComment("关闭的异步支付通道")
private String asyncChannel;
/**
* 是否关闭成功
*/
@DbComment("是否关闭成功")
private boolean closed;
@DbComment("错误消息")
private String errorMsg;
/** 客户端IP */
@DbColumn(comment = "客户端IP")
private String clientIp;
/** 请求链路ID */
@DbColumn(comment = "请求链路ID")
private String reqId;
/**
* 转换
*/
@Override
public PayCloseRecordDto toDto() {
return PayCloseRecordConvert.CONVERT.convert(this);
}
}

View File

@@ -0,0 +1,26 @@
package cn.bootx.platform.daxpay.service.core.record.close.service;
import cn.bootx.platform.daxpay.service.core.record.close.dao.PayCloseRecordManager;
import cn.bootx.platform.daxpay.service.core.record.close.entity.PayCloseRecord;
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;
/**
* 支付关闭记录
* @author xxm
* @since 2024/1/4
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PayCloseRecordService {
private final PayCloseRecordManager manager;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveRecord(PayCloseRecord record){
manager.save(record);
}
}

View File

@@ -1,7 +1,7 @@
package cn.bootx.platform.daxpay.service.core.record.refund.convert;
import cn.bootx.platform.daxpay.service.core.record.refund.entity.PayRefundOrder;
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.refund.PayRefundOrderDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -5,7 +5,7 @@ import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.daxpay.service.core.record.refund.entity.PayRefundOrder;
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.refund.PayRefundOrderDto;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

View File

@@ -6,7 +6,9 @@ import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;
import cn.bootx.platform.daxpay.service.common.entity.OrderRefundableInfo;
import cn.bootx.platform.daxpay.service.common.typehandler.RefundableInfoTypeHandler;
import cn.bootx.platform.daxpay.service.core.record.refund.convert.RefundConvert;
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.refund.PayRefundOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -27,39 +29,54 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@DbTable(comment = "退款订单")
@TableName(value = "pay_refund_order", autoResultMap = true)
public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<PayRefundOrderDto> {
/** 支付单号 */
@DbColumn(comment = "关联的业务号")
private Long paymentId;
/** 关联的业务号 */
@DbColumn(comment = "关联的业务号")
private String businessNo;
/** 异步方式关联退款请求号(部分退款情况) */
@DbColumn(comment = "异步方式关联退款请求号(部分退款情况)")
private String refundRequestNo;
/** 标题 */
@DbColumn(comment = "标题")
private String title;
/** 退款金额 */
@DbColumn(comment = "退款金额")
private Integer amount;
/** 剩余可退 */
@DbColumn(comment = "剩余可退")
private Integer refundableBalance;
/** 请求链路ID */
@DbColumn(comment = "请求链路ID")
private String reqId;
/** 退款终端ip */
@DbColumn(comment = "退款终端ip")
private String clientIp;
/** 退款原因 */
@DbColumn(comment = "退款原因")
private String reason;
/** 退款时间 */
@DbColumn(comment = "退款时间")
private LocalDateTime refundTime;
/**
* 退款信息列表
*/
@DbColumn(comment = "退款信息列表")
@TableField(typeHandler = RefundableInfoTypeHandler.class)
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
private List<OrderRefundableInfo> refundableInfo;
@@ -68,12 +85,15 @@ public class PayRefundOrder extends MpBaseEntity implements EntityBaseFunction<P
* 退款状态
* @see PayRefundStatusEnum
*/
@DbColumn(comment = "退款状态")
private String status;
/** 错误码 */
@DbColumn(comment = "错误码")
private String errorCode;
/** 错误信息 */
@DbColumn(comment = "错误信息")
private String errorMsg;
@Override

View File

@@ -6,7 +6,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.daxpay.service.core.record.refund.dao.PayRefundOrderManager;
import cn.bootx.platform.daxpay.service.core.record.refund.entity.PayRefundOrder;
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.refund.PayRefundOrderDto;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -25,6 +25,10 @@ public class PayRefundRecordService {
private final PayRefundOrderManager refundRecordManager;
// TODO 记录退款记录
/**
* 分页查询
*/

View File

@@ -1,7 +1,7 @@
package cn.bootx.platform.daxpay.service.core.record.sync.convert;
import cn.bootx.platform.daxpay.service.core.record.sync.entity.PaySyncRecord;
import cn.bootx.platform.daxpay.service.dto.order.sync.PaySyncRecordDto;
import cn.bootx.platform.daxpay.service.dto.record.sync.PaySyncRecordDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -5,7 +5,7 @@ import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.daxpay.service.core.record.sync.entity.PaySyncRecord;
import cn.bootx.platform.daxpay.service.dto.order.sync.PaySyncRecordDto;
import cn.bootx.platform.daxpay.service.dto.record.sync.PaySyncRecordDto;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -28,7 +28,7 @@ public class PaySyncRecordManager extends BaseManager<PaySyncRecordMapper, PaySy
return lambdaQuery().orderByDesc(MpIdEntity::getId)
.like(Objects.nonNull(param.getPaymentId()), PaySyncRecord::getPaymentId, param.getPaymentId())
.eq(Objects.nonNull(param.getChannel()), PaySyncRecord::getChannel, param.getChannel())
.eq(Objects.nonNull(param.getStatus()), PaySyncRecord::getStatus, param.getStatus())
.eq(Objects.nonNull(param.getStatus()), PaySyncRecord::getSyncStatus, param.getStatus())
.page(mpPage);
}

View File

@@ -5,7 +5,8 @@ import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.platform.daxpay.service.core.record.sync.convert.PaySyncRecordConvert;
import cn.bootx.platform.daxpay.service.dto.order.sync.PaySyncRecordDto;
import cn.bootx.platform.daxpay.service.dto.record.sync.PaySyncRecordDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbComment;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
@@ -15,8 +16,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 支付同步订单
* @author xxm
@@ -33,7 +32,6 @@ public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction<
@DbComment("支付记录id")
private Long paymentId;
/**
* 支付通道
* @see PayChannelEnum#getCode()
@@ -51,19 +49,32 @@ public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction<
* @see PaySyncStatusEnum
*/
@DbComment("同步状态")
private String status;
private String syncStatus;
/**
* 支付单如果状态不一致, 是否修复成功
*/
@DbComment("是否进行修复")
private boolean repairOrder;
@DbComment("错误消息")
private String msg;
/** 支付单修复前状态 */
@DbComment("支付单修复前状态")
private String oldStatus;
/** 支付单修复后状态 */
/** 同步时间 */
@DbComment("同步时间")
private LocalDateTime syncTime;
@DbComment("支付单修复后状态")
private String repairStatus;
@DbComment("错误消息")
private String errorMsg;
/** 客户端IP */
@DbColumn(comment = "客户端IP")
private String clientIp;
/** 请求链路ID */
@DbColumn(comment = "请求链路ID")
private String reqId;
/**
* 转换

View File

@@ -4,11 +4,9 @@ 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.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.sync.dao.PaySyncRecordManager;
import cn.bootx.platform.daxpay.service.core.record.sync.entity.PaySyncRecord;
import cn.bootx.platform.daxpay.service.core.payment.sync.result.GatewaySyncResult;
import cn.bootx.platform.daxpay.service.dto.order.sync.PaySyncRecordDto;
import cn.bootx.platform.daxpay.service.dto.record.sync.PaySyncRecordDto;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -16,8 +14,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
/**
* 支付同步记录
* @author xxm
@@ -26,21 +22,14 @@ import java.time.LocalDateTime;
@Slf4j
@Service
@RequiredArgsConstructor
public class PaySyncOrderService {
public class PaySyncRecordService {
private final PaySyncRecordManager orderManager;
/**
* 记录同步记录
* 记录同步记录 同步支付单的不进行记录
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveRecord(GatewaySyncResult paySyncResult, PayOrder payment){
PaySyncRecord paySyncRecord = new PaySyncRecord()
.setPaymentId(payment.getId())
.setChannel(payment.getAsyncChannel())
.setSyncInfo(paySyncResult.getJson())
.setStatus(paySyncResult.getSyncStatus().getCode())
.setMsg(paySyncResult.getMsg())
.setSyncTime(LocalDateTime.now());
public void saveRecord(PaySyncRecord paySyncRecord){
orderManager.save(paySyncRecord);
}

View File

@@ -1,6 +1,6 @@
package cn.bootx.platform.daxpay.service.dto.channel.alipay;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.pay.PayOrderDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@@ -1,6 +1,6 @@
package cn.bootx.platform.daxpay.service.dto.channel.voucher;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.pay.PayOrderDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@@ -1,6 +1,6 @@
package cn.bootx.platform.daxpay.service.dto.channel.wallet;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.pay.PayOrderDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@@ -1,6 +1,6 @@
package cn.bootx.platform.daxpay.service.dto.channel.wechat;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto;
import cn.bootx.platform.daxpay.service.dto.record.pay.PayOrderDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@@ -0,0 +1,19 @@
package cn.bootx.platform.daxpay.service.dto.record.callback;
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/1/4
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "回调记录")
public class PayCallbackRecordDto extends BaseDto {
}

View File

@@ -0,0 +1,19 @@
package cn.bootx.platform.daxpay.service.dto.record.close;
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/1/4
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "支付关闭记录")
public class PayCloseRecordDto extends BaseDto {
}

View File

@@ -1,4 +1,4 @@
package cn.bootx.platform.daxpay.service.dto.order.pay;
package cn.bootx.platform.daxpay.service.dto.record.pay;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayStatusEnum;

View File

@@ -1,4 +1,4 @@
package cn.bootx.platform.daxpay.service.dto.order.refund;
package cn.bootx.platform.daxpay.service.dto.record.refund;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayRefundStatusEnum;

View File

@@ -1,8 +1,9 @@
package cn.bootx.platform.daxpay.service.dto.order.sync;
package cn.bootx.platform.daxpay.service.dto.record.sync;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.table.modify.annotation.DbComment;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -33,7 +34,7 @@ public class PaySyncRecordDto extends BaseDto {
private String channel;
/** 通知消息 */
@Schema(description = "通知消息")
@Schema(description = "同步消息")
private String syncInfo;
/**
@@ -43,10 +44,20 @@ public class PaySyncRecordDto extends BaseDto {
@Schema(description = "同步状态")
private String status;
/**
* 支付单如果状态不一致, 是否修复成功
*/
@DbComment("是否进行修复")
private boolean repairOrder;
@Schema(description = "错误消息")
private String msg;
/** 同步时间 */
@Schema(description = "同步时间")
private LocalDateTime syncTime;
/** 客户端IP */
@Schema(description = "客户端IP")
private String clientIp;
}

View File

@@ -3,8 +3,8 @@ package cn.bootx.platform.daxpay.service.func;
import cn.bootx.platform.common.redis.RedisClient;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.CallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.CallbackRecord;
import cn.bootx.platform.daxpay.service.core.record.callback.dao.PayCallbackRecordManager;
import cn.bootx.platform.daxpay.service.core.record.callback.entity.PayCallbackRecord;
import cn.bootx.platform.daxpay.service.core.payment.callback.result.PayCallbackResult;
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
import cn.hutool.json.JSONUtil;
@@ -26,7 +26,7 @@ public abstract class AbsPayCallbackStrategy implements PayStrategy {
private final RedisClient redisClient;
private final CallbackRecordManager callbackRecordManager;
private final PayCallbackRecordManager callbackRecordManager;
private final PayCallbackService payCallbackService;
@@ -100,7 +100,7 @@ public abstract class AbsPayCallbackStrategy implements PayStrategy {
*/
public void saveNotifyRecord(PayCallbackResult result) {
Map<String, String> callbackParam = PaymentContextLocal.get().getCallbackParam();
CallbackRecord payNotifyRecord = new CallbackRecord()
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
.setNotifyInfo(JSONUtil.toJsonStr(callbackParam))
.setNotifyTime(LocalDateTime.now())
.setPaymentId(this.getPaymentId())