mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-02 02:34:34 +00:00
feat 新增支付撤销, 支付订单增加撤销状态, 删除无关基础模块
This commit is contained in:
24
_doc/Task.md
24
_doc/Task.md
@@ -1,28 +1,22 @@
|
||||
## 单商户
|
||||
2.0.8: 对账完善和系统优化
|
||||
- [ ] 细分各种支付异常类和编码
|
||||
- [ ] 修复功能支付/退款/对账
|
||||
- [ ] 支持撤销接口
|
||||
- [ ] 增加转账接口功能
|
||||
- [ ] 细分各种支付异常类和编码
|
||||
- [ ] 增加对账修复功能拆
|
||||
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
|
||||
- [ ] 管理端界面支持扫码绑定对账接收方功能
|
||||
- [ ] 对账提供外部接口调用
|
||||
- [ ] 下载系统账单
|
||||
- [ ] 分账结果通知处理
|
||||
- [ ] 支付宝通知
|
||||
- [ ] 微信通知
|
||||
- [ ] 通知记录保存
|
||||
- [ ] 增加收单收银台功能
|
||||
- [ ] 增加资金对账单功能
|
||||
- [ ] 支付通道两个独立的配置进行合并为一个
|
||||
- [ ] 支持撤销接口
|
||||
- [ ] 支付和退款达到终态不可以再回退回之前的状态, 只能添加差错单进行处理
|
||||
|
||||
2.0.8: 转账和功能功能优化
|
||||
- [ ] 支持转账操作, 通过支付通道专有参数进行实现, 转账时只能单个通道进行操作
|
||||
- [ ] 支付和退款达到终态不可以再回退回之前的状态
|
||||
- [x] 修复支付关闭参数名称不正确问题
|
||||
2.0.9: 消息通知和功能功能优化
|
||||
- [ ] 将系统通知消息重构为类似支付宝应用通知的方式
|
||||
- [ ] 支付成功回调后, 如果订单已超时, 则进入待退款订单中,提示进行退款,或者自动退款
|
||||
- [ ] 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
|
||||
|
||||
2.1.x 版本内容
|
||||
2.1.x 版本内容
|
||||
- [ ] 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
|
||||
- [ ] 差错单据处理
|
||||
- [ ] 特殊退款接口
|
||||
- [ ] 统计报表功能
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package cn.bootx.platform.baseapi.dto.chinaword;
|
||||
|
||||
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 2023-08-09
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Schema(title = "敏感词")
|
||||
@Accessors(chain = true)
|
||||
public class ChinaWordDto extends BaseDto {
|
||||
|
||||
@Schema(description = "敏感词")
|
||||
private String word;
|
||||
@Schema(description = "分类")
|
||||
private String type;
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
@Schema(description = "是否启用")
|
||||
private Boolean enable;
|
||||
@Schema(description = "是否是白名单名词")
|
||||
private Boolean white;
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package cn.bootx.platform.baseapi.dto.chinaword;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 敏感词验证结果
|
||||
* @author xxm
|
||||
* @since 2023/8/9
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "敏感词验证结果")
|
||||
public class ChinaWordVerifyResult {
|
||||
|
||||
@Schema(description = "是否敏感")
|
||||
private boolean sensitive;
|
||||
@Schema(description = "敏感词数量")
|
||||
private int count;
|
||||
@Schema(description = "去重后的敏感词列表")
|
||||
private Set<String> sensitiveWords;
|
||||
@Schema(description = "脱敏后的文本")
|
||||
private String text;
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package cn.bootx.platform.baseapi.param.chinaword;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 敏感词导入参数
|
||||
* @author xxm
|
||||
* @since 2023/8/12
|
||||
*/
|
||||
@Data
|
||||
public class ChinaWordImportParam {
|
||||
@ExcelProperty(value = "类型")
|
||||
private String type;
|
||||
@ExcelProperty("黑/白名单")
|
||||
private String whiteOrBlack;
|
||||
@ExcelProperty("敏感词")
|
||||
private String word;
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
package cn.bootx.platform.baseapi.param.chinaword;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 敏感词
|
||||
* @author xxm
|
||||
* @since 2023-08-09
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "敏感词")
|
||||
@Accessors(chain = true)
|
||||
public class ChinaWordParam {
|
||||
|
||||
@Schema(description= "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "敏感词")
|
||||
private String word;
|
||||
@Schema(description = "分类")
|
||||
private String type;
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
@Schema(description = "是否启用")
|
||||
private Boolean enable;
|
||||
@Schema(description = "白名单名词")
|
||||
private Boolean white;
|
||||
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package cn.bootx.platform.baseapi.param.chinaword;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 敏感词验证参数类
|
||||
* @author xxm
|
||||
* @since 2023/8/10
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "敏感词验证参数类")
|
||||
public class ChinaWordVerifyParam {
|
||||
@Schema(description = "文本")
|
||||
private String text;
|
||||
|
||||
@Schema(description = "间隔距离")
|
||||
private int skip = 0;
|
||||
|
||||
@Schema(description = "替换字符")
|
||||
private char symbol = '*';
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.daxpay.single.sdk.model.pay;
|
||||
|
||||
import cn.daxpay.single.sdk.net.DaxPayResponseModel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 支付撤销
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(callSuper = true)
|
||||
public class PayCancelModel extends DaxPayResponseModel {
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.daxpay.single.sdk.param.pay;
|
||||
|
||||
import cn.daxpay.single.sdk.model.pay.PayCancelModel;
|
||||
import cn.daxpay.single.sdk.net.DaxPayRequest;
|
||||
import cn.daxpay.single.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 支付撤销参数
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class PayCancelParam extends DaxPayRequest<PayCancelModel> {
|
||||
|
||||
/** 订单号 */
|
||||
private String orderNo;
|
||||
|
||||
/** 商户订单号 */
|
||||
private String bizOrderNo;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/cancel";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<PayCancelModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<PayCancelModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -5,23 +5,22 @@ import cn.daxpay.single.sdk.net.DaxPayRequest;
|
||||
import cn.daxpay.single.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 支付关闭参数
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Getter
|
||||
@Setter
|
||||
public class PayCloseParam extends DaxPayRequest<PayCloseModel> {
|
||||
|
||||
/** 订单号 */
|
||||
private String orderNo;
|
||||
|
||||
/** 商户订单号 */
|
||||
private String bizTradeNo;
|
||||
private String bizOrderNo;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
|
@@ -13,7 +13,6 @@ import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -24,7 +23,6 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(callSuper = true)
|
||||
public class PayParam extends DaxPayRequest<PayModel> {
|
||||
|
||||
/** 商户订单号 */
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package cn.daxpay.single.sdk.payment;
|
||||
|
||||
import cn.daxpay.single.sdk.code.SignTypeEnum;
|
||||
import cn.daxpay.single.sdk.model.pay.PayCancelModel;
|
||||
import cn.daxpay.single.sdk.model.pay.PayCloseModel;
|
||||
import cn.daxpay.single.sdk.net.DaxPayConfig;
|
||||
import cn.daxpay.single.sdk.net.DaxPayKit;
|
||||
import cn.daxpay.single.sdk.param.pay.PayCancelParam;
|
||||
import cn.daxpay.single.sdk.param.pay.PayCloseParam;
|
||||
import cn.daxpay.single.sdk.response.DaxPayResult;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@@ -37,4 +39,13 @@ public class PayCloseOrderTest {
|
||||
DaxPayResult<PayCloseModel> execute = DaxPayKit.execute(param);
|
||||
System.out.println(JSONUtil.toJsonStr(execute));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancel(){
|
||||
PayCancelParam param = new PayCancelParam();
|
||||
param.setOrderNo("DEVP24060518083863000001");
|
||||
param.setClientIp("127.0.0.1");
|
||||
DaxPayResult<PayCancelModel> execute = DaxPayKit.execute(param);
|
||||
System.out.println(JSONUtil.toJsonStr(execute));
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ public enum PayStatusEnum {
|
||||
PROGRESS("progress","支付中"),
|
||||
SUCCESS("success","成功"),
|
||||
CLOSE("close","支付关闭"),
|
||||
CANCEL("cancel","支付撤销"),
|
||||
REFUNDING("refunding","退款中"),
|
||||
PARTIAL_REFUND("partial_refund","部分退款"),
|
||||
REFUNDED("refunded","全部退款"),
|
||||
|
@@ -12,6 +12,8 @@ public interface PaymentApiCode {
|
||||
String REFUND = "refund";
|
||||
/** 关闭订单 */
|
||||
String CLOSE = "close";
|
||||
/** 撤销订单 */
|
||||
String CANCEL = "cancel";
|
||||
/** 分账 */
|
||||
String ALLOCATION = "allocation";
|
||||
/** 转账 */
|
||||
|
@@ -1,25 +0,0 @@
|
||||
package cn.daxpay.single.entity;
|
||||
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 可退款信息(不持久化,直接保存为json)
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RefundableInfo {
|
||||
/**
|
||||
* 通道
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 可退款金额
|
||||
*/
|
||||
private Integer amount;
|
||||
}
|
@@ -16,9 +16,11 @@ import lombok.EqualsAndHashCode;
|
||||
@Schema(title = "支付订单撤销")
|
||||
public class PayCancelParam extends PaymentCommonParam {
|
||||
|
||||
/** 订单号 */
|
||||
@Schema(description = "订单号")
|
||||
private String orderNo;
|
||||
|
||||
/** 商户订单号 */
|
||||
@Schema(description = "商户订单号")
|
||||
private String bizOrderNo;
|
||||
}
|
||||
|
@@ -21,5 +21,5 @@ public class PayCloseParam extends PaymentCommonParam {
|
||||
|
||||
/** 商户订单号 */
|
||||
@Schema(description = "商户订单号")
|
||||
private String bizTradeNo;
|
||||
private String bizOrderNo;
|
||||
}
|
||||
|
@@ -0,0 +1,19 @@
|
||||
package cn.daxpay.single.result.pay;
|
||||
|
||||
import cn.daxpay.single.result.PaymentCommonResult;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付关闭响应参数
|
||||
* @author xxm
|
||||
* @since 2024/4/23
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "支付撤销响应参数")
|
||||
public class PayCancelResult extends PaymentCommonResult {
|
||||
}
|
@@ -2,16 +2,19 @@ package cn.daxpay.single.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.single.code.PaymentApiCode;
|
||||
import cn.daxpay.single.param.payment.pay.PayCancelParam;
|
||||
import cn.daxpay.single.param.payment.pay.PayCloseParam;
|
||||
import cn.daxpay.single.param.payment.pay.PayParam;
|
||||
import cn.daxpay.single.param.payment.refund.RefundParam;
|
||||
import cn.daxpay.single.param.payment.transfer.TransferParam;
|
||||
import cn.daxpay.single.result.DaxResult;
|
||||
import cn.daxpay.single.result.pay.PayCancelResult;
|
||||
import cn.daxpay.single.result.pay.PayCloseResult;
|
||||
import cn.daxpay.single.result.pay.PayResult;
|
||||
import cn.daxpay.single.result.pay.RefundResult;
|
||||
import cn.daxpay.single.service.annotation.PaymentSign;
|
||||
import cn.daxpay.single.service.annotation.InitPaymentContext;
|
||||
import cn.daxpay.single.service.core.payment.cancel.service.PayCancelService;
|
||||
import cn.daxpay.single.service.core.payment.close.service.PayCloseService;
|
||||
import cn.daxpay.single.service.core.payment.pay.service.PayService;
|
||||
import cn.daxpay.single.service.core.payment.refund.service.RefundService;
|
||||
@@ -38,6 +41,7 @@ public class UniPayController {
|
||||
private final PayService payService;
|
||||
private final RefundService refundService;
|
||||
private final PayCloseService payCloseService;
|
||||
private final PayCancelService payCancelService;
|
||||
|
||||
@PaymentSign
|
||||
@InitPaymentContext(PaymentApiCode.PAY)
|
||||
@@ -55,6 +59,14 @@ public class UniPayController {
|
||||
return DaxRes.ok(payCloseService.close(param));
|
||||
}
|
||||
|
||||
@PaymentSign
|
||||
@InitPaymentContext(PaymentApiCode.CANCEL)
|
||||
@Operation(summary = "支付撤销接口")
|
||||
@PostMapping("/cancel")
|
||||
public DaxResult<PayCancelResult> cancel(@RequestBody PayCancelParam param){
|
||||
return DaxRes.ok(payCancelService.cancel(param));
|
||||
}
|
||||
|
||||
@PaymentSign
|
||||
@InitPaymentContext(PaymentApiCode.REFUND)
|
||||
@Operation(summary = "统一退款接口")
|
||||
|
@@ -0,0 +1,25 @@
|
||||
package cn.daxpay.single.service.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 订单关闭类型
|
||||
* @author xxm
|
||||
* @since 2024/6/5
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PayCloseTypeEnum {
|
||||
/**
|
||||
* 订单关闭
|
||||
*/
|
||||
CLOSE("close", "订单关闭"),
|
||||
/**
|
||||
* 订单撤销
|
||||
*/
|
||||
CANCEL("cancel", "订单撤销"),
|
||||
;
|
||||
final String code;
|
||||
final String name;
|
||||
}
|
@@ -1,24 +1,24 @@
|
||||
package cn.daxpay.single.service.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.common.spring.exception.RetryableException;
|
||||
import cn.daxpay.single.code.PaySyncStatusEnum;
|
||||
import cn.daxpay.single.service.code.AliPayCode;
|
||||
import cn.daxpay.single.service.core.payment.sync.result.PayRemoteSyncResult;
|
||||
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
|
||||
import cn.daxpay.single.exception.pay.PayFailureException;
|
||||
import cn.daxpay.single.service.code.AliPayCode;
|
||||
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
|
||||
import cn.daxpay.single.service.core.payment.sync.result.PayRemoteSyncResult;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayTradeCancelModel;
|
||||
import com.alipay.api.domain.AlipayTradeCloseModel;
|
||||
import com.alipay.api.response.AlipayTradeCancelResponse;
|
||||
import com.alipay.api.response.AlipayTradeCloseResponse;
|
||||
import com.ijpay.alipay.AliPayApi;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付宝支付取消和支付关闭
|
||||
* 支付宝支付撤销和支付关闭
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/4/20
|
||||
@@ -30,15 +30,13 @@ public class AliPayCloseService {
|
||||
private final AliPaySyncService aliPaySyncService;
|
||||
|
||||
/**
|
||||
* 关闭支付 此处使用交易关闭接口, 支付宝支持 交易关闭 和 交易撤销 两种关闭订单的方式, 区别如下
|
||||
* 关闭支付 此处使用交易关闭接口
|
||||
* 交易关闭: 只有订单在未支付的状态下才可以进行关闭, 商户不需要额外申请就有此接口的权限
|
||||
* 交易撤销: 如果用户支付成功,会将此订单资金退还给用户. 限制时间为1天,过了24小时,该接口无法再使用。可以视为一个特殊的接口, 需要专门签约这个接口的权限
|
||||
* <p>
|
||||
* 1. 如果未查询到支付单,视为支付关闭,
|
||||
* 2. 如果返回"当前交易状态不支持此操作", 同步网关支付状态, 判断网关是否已经被关闭
|
||||
*
|
||||
*/
|
||||
@Retryable(value = RetryableException.class)
|
||||
public void close(PayOrder payOrder) {
|
||||
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
|
||||
model.setOutTradeNo(payOrder.getOrderNo());
|
||||
@@ -65,6 +63,38 @@ public class AliPayCloseService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易撤销: 如果用户支付成功,会将此订单资金退还给用户. 限制时间为1天,过了24小时,该接口无法再使用。
|
||||
* 可以视为一个特殊的接口, 需要专门签约这个接口的权限
|
||||
*/
|
||||
public void cancel(PayOrder payOrder) {
|
||||
AlipayTradeCancelModel model = new AlipayTradeCancelModel();
|
||||
model.setOutTradeNo(payOrder.getOrderNo());
|
||||
|
||||
try {
|
||||
AlipayTradeCancelResponse response = AliPayApi.tradeCancelToResponse(model);
|
||||
if (!Objects.equals(AliPayCode.SUCCESS, response.getCode())) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("关闭订单失败:", e);
|
||||
throw new PayFailureException("关闭订单失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关闭失败后, 获取支付网关的状态, 如果是关闭返回true, 其他情况抛出异常
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package cn.daxpay.single.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.spring.exception.RetryableException;
|
||||
import cn.daxpay.single.exception.pay.PayFailureException;
|
||||
import cn.daxpay.single.service.code.WeChatPayCode;
|
||||
import cn.daxpay.single.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
@@ -12,9 +12,9 @@ import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.CloseOrderModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,6 @@ public class WeChatPayCloseService {
|
||||
/**
|
||||
* 关闭支付, 微信对已经关闭的支付单也可以重复关闭
|
||||
*/
|
||||
@Retryable(value = RetryableException.class)
|
||||
public void close(PayOrder payOrder, WeChatPayConfig weChatPayConfig) {
|
||||
// 只有部分需要调用微信网关进行关闭
|
||||
Map<String, String> params = CloseOrderModel.builder()
|
||||
@@ -47,6 +46,32 @@ public class WeChatPayCloseService {
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销接口
|
||||
*/
|
||||
public void cancel(PayOrder payOrder, WeChatPayConfig weChatPayConfig){
|
||||
// 只有部分需要调用微信网关进行关闭
|
||||
Map<String, String> params = CloseOrderModel.builder()
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.out_trade_no(payOrder.getOrderNo())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
|
||||
// 获取证书文件
|
||||
if (StrUtil.isBlank(weChatPayConfig.getP12())){
|
||||
String errorMsg = "微信p.12证书未配置,无法进行退款";
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
byte[] fileBytes = Base64.decode(weChatPayConfig.getP12());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
|
||||
// 证书密码为 微信商户号
|
||||
String xmlResult = WxPayApi.orderReverse(params,inputStream,weChatPayConfig.getWxMchId());
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证错误信息
|
||||
*/
|
||||
|
@@ -2,6 +2,7 @@ package cn.daxpay.single.service.core.order.pay.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.daxpay.single.code.PayMethodEnum;
|
||||
import cn.daxpay.single.code.PayOrderAllocStatusEnum;
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import cn.daxpay.single.code.PayStatusEnum;
|
||||
@@ -71,6 +72,7 @@ public class PayOrder extends MpBaseEntity implements EntityBaseFunction<PayOrde
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
* @see PayMethodEnum
|
||||
*/
|
||||
@DbColumn(comment = "支付方式")
|
||||
private String method;
|
||||
|
@@ -28,7 +28,10 @@ public class PayOrderService {
|
||||
private final PayExpiredTimeService expiredTimeService;
|
||||
|
||||
// 支付完成常量集合
|
||||
private final List<String> ORDER_FINISH = Arrays.asList(PayStatusEnum.CLOSE.getCode(), PayStatusEnum.SUCCESS.getCode());
|
||||
private final List<String> ORDER_FINISH = Arrays.asList(
|
||||
PayStatusEnum.CLOSE.getCode(),
|
||||
PayStatusEnum.CANCEL.getCode(),
|
||||
PayStatusEnum.SUCCESS.getCode());
|
||||
|
||||
/**
|
||||
* 查询
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package cn.daxpay.single.service.core.payment.cancel.factory;
|
||||
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
|
||||
import cn.daxpay.single.service.core.payment.cancel.strategy.AliPayCancelStrategy;
|
||||
import cn.daxpay.single.service.core.payment.cancel.strategy.WeChatPayCancelStrategy;
|
||||
import cn.daxpay.single.service.func.AbsPayCancelStrategy;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* 订单撤销策略工厂
|
||||
* @author xxm
|
||||
* @since 2024/6/5
|
||||
*/
|
||||
@UtilityClass
|
||||
public class PayCancelStrategyFactory {
|
||||
|
||||
/**
|
||||
* 根据传入的支付通道创建策略
|
||||
* @return 支付策略
|
||||
*/
|
||||
public static AbsPayCancelStrategy create(String channel) {
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channel);
|
||||
AbsPayCancelStrategy strategy;
|
||||
switch (channelEnum) {
|
||||
case ALI:
|
||||
strategy = SpringUtil.getBean(AliPayCancelStrategy.class);
|
||||
break;
|
||||
case WECHAT:
|
||||
strategy = SpringUtil.getBean(WeChatPayCancelStrategy.class);
|
||||
break;
|
||||
default:
|
||||
throw new PayUnsupportedMethodException();
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
package cn.daxpay.single.service.core.payment.cancel.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.daxpay.single.code.PayStatusEnum;
|
||||
import cn.daxpay.single.exception.pay.PayFailureException;
|
||||
import cn.daxpay.single.param.payment.pay.PayCancelParam;
|
||||
import cn.daxpay.single.result.pay.PayCancelResult;
|
||||
import cn.daxpay.single.service.code.PayCloseTypeEnum;
|
||||
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;
|
||||
import cn.daxpay.single.service.core.order.pay.service.PayOrderService;
|
||||
import cn.daxpay.single.service.core.payment.cancel.factory.PayCancelStrategyFactory;
|
||||
import cn.daxpay.single.service.core.payment.notice.service.ClientNoticeService;
|
||||
import cn.daxpay.single.service.core.record.close.entity.PayCloseRecord;
|
||||
import cn.daxpay.single.service.core.record.close.service.PayCloseRecordService;
|
||||
import cn.daxpay.single.service.func.AbsPayCancelStrategy;
|
||||
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 2023/12/18
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayCancelService {
|
||||
private final PayOrderService payOrderService;
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
private final PayCloseRecordService payCloseRecordService;
|
||||
private final ClientNoticeService clientsService;;
|
||||
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
/**
|
||||
* 撤销支付
|
||||
*/
|
||||
public PayCancelResult cancel(PayCancelParam param){
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizOrderNo())
|
||||
.orElseThrow(() -> new PayFailureException("支付订单不存在"));
|
||||
LockInfo lock = lockTemplate.lock("payment:cancel:" + payOrder.getId(),10000, 50);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("支付订单已在撤销中,请勿重复发起");
|
||||
}
|
||||
try {
|
||||
PayCancelResult result = new PayCancelResult();
|
||||
// 状态检查, 只有支付中可以进行撤销支付
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())) {
|
||||
throw new PayFailureException("订单不是支付中, 无法进行撤销订单");
|
||||
}
|
||||
try {
|
||||
AbsPayCancelStrategy strategy = PayCancelStrategyFactory.create(payOrder.getChannel());
|
||||
// 设置支付订单
|
||||
strategy.setOrder(payOrder);
|
||||
// 撤销前准备
|
||||
strategy.doBeforeCancelHandler();
|
||||
// 执行撤销策略
|
||||
strategy.doCancelHandler();
|
||||
// 成功处理
|
||||
this.successHandler(payOrder);
|
||||
// 返回结果
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("撤销订单失败, id: {}:", payOrder.getId());
|
||||
log.error("撤销订单失败:", e);
|
||||
// 记录撤销失败的记录
|
||||
this.saveRecord(payOrder, false, e.getMessage());
|
||||
throw new PayFailureException("撤销订单失败");
|
||||
}
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功后处理方法
|
||||
*/
|
||||
private void successHandler(PayOrder payOrder){
|
||||
// 撤销订单
|
||||
payOrder.setStatus(PayStatusEnum.CANCEL.getCode())
|
||||
.setCloseTime(LocalDateTime.now());
|
||||
payOrderService.updateById(payOrder);
|
||||
// 发送通知
|
||||
clientsService.registerPayNotice(payOrder,null);
|
||||
this.saveRecord(payOrder,true,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存撤销记录
|
||||
*/
|
||||
private void saveRecord(PayOrder payOrder, boolean closed, String errMsg){
|
||||
String clientIp = PaymentContextLocal.get()
|
||||
.getRequestInfo()
|
||||
.getClientIp();
|
||||
PayCloseRecord record = new PayCloseRecord()
|
||||
.setOrderNo(payOrder.getOrderNo())
|
||||
.setBizOrderNo(payOrder.getBizOrderNo())
|
||||
.setChannel(payOrder.getChannel())
|
||||
.setCloseType(PayCloseTypeEnum.CANCEL.getCode())
|
||||
.setClosed(closed)
|
||||
.setErrorMsg(errMsg)
|
||||
.setClientIp(clientIp);
|
||||
payCloseRecordService.saveRecord(record);
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package cn.daxpay.single.service.core.payment.cancel.strategy;
|
||||
|
||||
import cn.daxpay.single.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.AbsPayCancelStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 支付宝撤销策略
|
||||
* @author xxm
|
||||
* @since 2024/6/5
|
||||
*/
|
||||
@Slf4j
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AliPayCancelStrategy extends AbsPayCancelStrategy {
|
||||
|
||||
private final AliPayConfigService alipayConfigService;
|
||||
|
||||
private final AliPayCloseService aliPayCloseService;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭前的处理方式
|
||||
*/
|
||||
@Override
|
||||
public void doBeforeCancelHandler() {
|
||||
AliPayConfig config = alipayConfigService.getConfig();
|
||||
alipayConfigService.initConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
@Override
|
||||
public void doCancelHandler() {
|
||||
aliPayCloseService.cancel(this.getOrder());
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package cn.daxpay.single.service.core.payment.cancel.strategy;
|
||||
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import cn.daxpay.single.code.PayMethodEnum;
|
||||
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.AbsPayCancelStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
* 微信支付关闭策略
|
||||
* @author xxm
|
||||
* @since 2023/12/30
|
||||
*/
|
||||
@Slf4j
|
||||
@Scope(SCOPE_PROTOTYPE)
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayCancelStrategy extends AbsPayCancelStrategy {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
private final WeChatPayCloseService weChatPayCloseService;
|
||||
|
||||
private WeChatPayConfig weChatPayConfig;
|
||||
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭前的处理方式
|
||||
*/
|
||||
@Override
|
||||
public void doBeforeCancelHandler() {
|
||||
// 非当面付订单不可以关闭
|
||||
if (!Objects.equals(this.getOrder().getMethod(), PayMethodEnum.BARCODE.getCode())) {
|
||||
throw new RuntimeException("微信当面付订单才可以被撤销");
|
||||
}
|
||||
this.weChatPayConfig = weChatPayConfigService.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭操作
|
||||
*/
|
||||
@Override
|
||||
public void doCancelHandler() {
|
||||
weChatPayCloseService.cancel(this.getOrder(), weChatPayConfig);
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ import cn.daxpay.single.code.PayStatusEnum;
|
||||
import cn.daxpay.single.exception.pay.PayFailureException;
|
||||
import cn.daxpay.single.param.payment.pay.PayCloseParam;
|
||||
import cn.daxpay.single.result.pay.PayCloseResult;
|
||||
import cn.daxpay.single.service.code.PayCloseTypeEnum;
|
||||
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;
|
||||
@@ -43,7 +44,7 @@ public class PayCloseService {
|
||||
* 关闭支付
|
||||
*/
|
||||
public PayCloseResult close(PayCloseParam param){
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizTradeNo())
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getOrderNo(), param.getBizOrderNo())
|
||||
.orElseThrow(() -> new PayFailureException("支付订单不存在"));
|
||||
LockInfo lock = lockTemplate.lock("payment:close:" + payOrder.getId(),10000, 50);
|
||||
if (Objects.isNull(lock)){
|
||||
@@ -83,7 +84,6 @@ public class PayCloseService {
|
||||
// 记录关闭失败的记录
|
||||
this.saveRecord(payOrder, false, e.getMessage());
|
||||
throw new PayFailureException("关闭订单失败");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ public class PayCloseService {
|
||||
.setOrderNo(payOrder.getOrderNo())
|
||||
.setBizOrderNo(payOrder.getBizOrderNo())
|
||||
.setChannel(payOrder.getChannel())
|
||||
.setCloseType(PayCloseTypeEnum.CLOSE.getCode())
|
||||
.setClosed(closed)
|
||||
.setErrorMsg(errMsg)
|
||||
.setClientIp(clientIp);
|
||||
|
@@ -200,7 +200,7 @@ public class PayAssistService {
|
||||
throw new PayFailureException("已经支付成功,请勿重新支付");
|
||||
}
|
||||
// 支付失败类型状态
|
||||
List<String> tradesStatus = Arrays.asList(FAIL.getCode(), CLOSE.getCode());
|
||||
List<String> tradesStatus = Arrays.asList(FAIL.getCode(), CLOSE.getCode(), CANCEL.getCode());
|
||||
if (tradesStatus.contains(payOrder.getStatus())) {
|
||||
throw new PayFailureException("支付失败或已经被关闭");
|
||||
}
|
||||
|
@@ -83,6 +83,7 @@ public class RefundAssistService {
|
||||
List<String> tradesStatus = Arrays.asList(
|
||||
PayStatusEnum.PROGRESS.getCode(),
|
||||
PayStatusEnum.CLOSE.getCode(),
|
||||
PayStatusEnum.CANCEL.getCode(),
|
||||
PayStatusEnum.REFUNDED.getCode(),
|
||||
PayStatusEnum.REFUNDING.getCode(),
|
||||
PayStatusEnum.FAIL.getCode());
|
||||
|
@@ -74,8 +74,7 @@ public class PayRepairService {
|
||||
repairResult.setAfterPayStatus(PayStatusEnum.CLOSE);
|
||||
break;
|
||||
case PROGRESS:
|
||||
this.waitPay(order);
|
||||
repairResult.setAfterPayStatus(PayStatusEnum.PROGRESS);
|
||||
// TODO 保存为异常订单
|
||||
break;
|
||||
case CLOSE_GATEWAY:
|
||||
this.closeRemote(order, repairStrategy);
|
||||
@@ -93,17 +92,6 @@ public class PayRepairService {
|
||||
return repairResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 变更未待支付
|
||||
* TODO 后期保存为异常订单
|
||||
*/
|
||||
private void waitPay(PayOrder order) {
|
||||
// 修改订单支付状态为待支付
|
||||
order.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
.setPayTime(null)
|
||||
.setCloseTime(null);
|
||||
payOrderService.updateById(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 变更为已支付
|
||||
|
@@ -33,7 +33,6 @@ 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;
|
||||
|
||||
@@ -163,7 +162,7 @@ public class PaySyncService {
|
||||
未找到订单可能是发起支付用户未操作、支付已关闭、交易未找到三种情况
|
||||
所以需要根据本地订单不同的状态进行特殊处理, 此处视为支付已关闭、交易未找到这两种, 处理方式相同, 都作为支付关闭处理
|
||||
*/
|
||||
List<String> payCloseEnums = Collections.singletonList(PayStatusEnum.CLOSE.getCode());
|
||||
List<String> payCloseEnums = Arrays.asList(PayStatusEnum.CLOSE.getCode(), PayStatusEnum.CANCEL.getCode());
|
||||
List<PaySyncStatusEnum> syncClose = Arrays.asList(CLOSED, NOT_FOUND, NOT_FOUND_UNKNOWN);
|
||||
if (payCloseEnums.contains(orderStatus) && syncClose.contains(syncStatus)){
|
||||
return true;
|
||||
|
@@ -3,6 +3,7 @@ package cn.daxpay.single.service.core.record.close.entity;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import cn.daxpay.single.service.code.PayCloseTypeEnum;
|
||||
import cn.daxpay.single.service.core.record.close.convert.PayCloseRecordConvert;
|
||||
import cn.daxpay.single.service.dto.record.close.PayCloseRecordDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
@@ -39,6 +40,13 @@ public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction
|
||||
@DbColumn(comment = "关闭的支付通道")
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 关闭类型 关闭/撤销
|
||||
* @see PayCloseTypeEnum
|
||||
*/
|
||||
@DbColumn(comment = "关闭类型")
|
||||
private String closeType;
|
||||
|
||||
/**
|
||||
* 是否关闭成功
|
||||
*/
|
||||
|
@@ -3,6 +3,7 @@ package cn.daxpay.single.service.dto.record.close;
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.daxpay.single.code.PayChannelEnum;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.daxpay.single.service.code.PayCloseTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -34,6 +35,13 @@ public class PayCloseRecordDto extends BaseDto {
|
||||
@DbColumn(comment = "关闭的异步支付通道")
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 关闭类型 关闭/撤销
|
||||
* @see PayCloseTypeEnum
|
||||
*/
|
||||
@DbColumn(comment = "关闭类型")
|
||||
private String closeType;
|
||||
|
||||
/**
|
||||
* 是否关闭成功
|
||||
*/
|
||||
|
@@ -0,0 +1,28 @@
|
||||
package cn.daxpay.single.service.func;
|
||||
|
||||
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 支付订单撤销接口
|
||||
* @author xxm
|
||||
* @since 2024/6/5
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class AbsPayCancelStrategy implements PayStrategy {
|
||||
/** 支付订单 */
|
||||
private PayOrder order = null;
|
||||
|
||||
|
||||
/**
|
||||
* 撤销前的处理方式
|
||||
*/
|
||||
public void doBeforeCancelHandler() {}
|
||||
|
||||
/**
|
||||
* 撤销操作
|
||||
*/
|
||||
public abstract void doCancelHandler();
|
||||
}
|
@@ -38,7 +38,7 @@ public class PayCloseRecordQuery extends QueryOrder {
|
||||
* 是否关闭成功
|
||||
*/
|
||||
@DbColumn(comment = "是否关闭成功")
|
||||
private boolean closed;
|
||||
private Boolean closed;
|
||||
|
||||
/** 错误码 */
|
||||
@DbColumn(comment = "错误码")
|
||||
|
Reference in New Issue
Block a user