mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-07 13:10:44 +00:00
ref 回调相关逻辑调整, 去除继承关系. 补充签名
This commit is contained in:
@@ -31,6 +31,11 @@ public class CallbackLocal {
|
||||
*/
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 通道
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 三方支付系统返回状态
|
||||
* @see PayStatusEnum 支付状态
|
||||
|
@@ -4,11 +4,15 @@ import cn.bootx.platform.common.core.util.CertUtil;
|
||||
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.service.code.PayCallbackStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsCallbackStrategy;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.callback.service.RefundCallbackService;
|
||||
import cn.bootx.platform.daxpay.service.core.record.callback.service.PayCallbackRecordService;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -16,11 +20,11 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayConstants;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -35,25 +39,65 @@ import static cn.bootx.platform.daxpay.service.code.AliPayCode.*;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
@RequiredArgsConstructor
|
||||
public class AliPayCallbackService {
|
||||
|
||||
@Resource
|
||||
private AliPayConfigService aliasConfigService;
|
||||
private final AliPayConfigService aliPayConfigService;
|
||||
|
||||
private final PayCallbackRecordService callbackService;
|
||||
|
||||
private final PayCallbackService payCallbackService;
|
||||
|
||||
private final RefundCallbackService refundCallbackService;
|
||||
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
* 回调处理入口
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.ALI;
|
||||
public String callback(Map<String, String> params){
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
try {
|
||||
// 将参数写入到上下文中
|
||||
callbackInfo.getCallbackParam().putAll(params);
|
||||
|
||||
// 判断并保存回调类型
|
||||
PaymentTypeEnum callbackType = this.getCallbackType();
|
||||
callbackInfo.setCallbackType(callbackType)
|
||||
.setChannel(PayChannelEnum.ALI.getCode());
|
||||
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("验证信息格式不通过");
|
||||
// 消息有问题, 保存记录并返回
|
||||
callbackService.saveCallbackRecord();
|
||||
return null;
|
||||
}
|
||||
// 提前设置订单修复的来源
|
||||
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
|
||||
|
||||
if (callbackType == PaymentTypeEnum.PAY){
|
||||
// 解析支付数据并放处理
|
||||
this.resolvePayData();
|
||||
payCallbackService.payCallback();
|
||||
} else {
|
||||
// 解析退款数据并放处理
|
||||
this.resolveRefundData();
|
||||
refundCallbackService.refundCallback();
|
||||
}
|
||||
callbackService.saveCallbackRecord();
|
||||
return this.getReturnMsg();
|
||||
} catch (Exception e) {
|
||||
log.error("回调处理失败", e);
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("回调处理失败: "+e.getMessage());
|
||||
callbackService.saveCallbackRecord();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证信息格式是否合法
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
Map<String, String> params =PaymentContextLocal.get().getCallbackInfo().getCallbackParam();
|
||||
String callReq = JSONUtil.toJsonStr(params);
|
||||
@@ -63,7 +107,7 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
log.error("支付宝回调报文appId为空");
|
||||
return false;
|
||||
}
|
||||
AliPayConfig alipayConfig = aliasConfigService.getConfig();
|
||||
AliPayConfig alipayConfig = aliPayConfigService.getConfig();
|
||||
if (Objects.isNull(alipayConfig)) {
|
||||
log.error("支付宝支付配置不存在");
|
||||
return false;
|
||||
@@ -84,7 +128,6 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 解析支付数据并放到上下文中
|
||||
*/
|
||||
@Override
|
||||
public void resolvePayData() {
|
||||
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callback.getCallbackParam();
|
||||
@@ -112,7 +155,6 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
* 解析退款回调数据并放到上下文中
|
||||
* 注意: 支付宝退款没有网关订单号, 网关订单号是支付单的
|
||||
*/
|
||||
@Override
|
||||
public void resolveRefundData() {
|
||||
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callback.getCallbackParam();
|
||||
@@ -138,7 +180,6 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
*
|
||||
* @see PaymentTypeEnum
|
||||
*/
|
||||
@Override
|
||||
public PaymentTypeEnum getCallbackType() {
|
||||
CallbackLocal callback = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callback.getCallbackParam();
|
||||
@@ -152,9 +193,8 @@ public class AliPayCallbackService extends AbsCallbackStrategy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回响应结果
|
||||
* 返回值
|
||||
*/
|
||||
@Override
|
||||
public String getReturnMsg() {
|
||||
return "success";
|
||||
}
|
||||
|
@@ -4,11 +4,16 @@ 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.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayCallbackStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.UnionPayCode;
|
||||
import cn.bootx.platform.daxpay.service.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.callback.service.PayCallbackService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.callback.service.RefundCallbackService;
|
||||
import cn.bootx.platform.daxpay.service.core.record.callback.service.PayCallbackRecordService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsCallbackStrategy;
|
||||
import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
@@ -35,15 +40,62 @@ import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*;
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
public class UnionPayCallbackService {
|
||||
|
||||
@Resource
|
||||
private UnionPayConfigService unionPayConfigService;
|
||||
private final UnionPayConfigService unionPayConfigService;
|
||||
|
||||
private final PayCallbackRecordService callbackService;
|
||||
|
||||
private final PayCallbackService payCallbackService;
|
||||
|
||||
private final RefundCallbackService refundCallbackService;
|
||||
|
||||
/**
|
||||
* 回调处理入口
|
||||
*/
|
||||
public String callback(Map<String, String> params){
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
try {
|
||||
// 将参数写入到上下文中
|
||||
callbackInfo.getCallbackParam().putAll(params);
|
||||
|
||||
// 判断并保存回调类型
|
||||
PaymentTypeEnum callbackType = this.getCallbackType();
|
||||
callbackInfo.setCallbackType(callbackType)
|
||||
.setChannel(PayChannelEnum.ALI.getCode());
|
||||
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("验证信息格式不通过");
|
||||
// 消息有问题, 保存记录并返回
|
||||
callbackService.saveCallbackRecord();
|
||||
return null;
|
||||
}
|
||||
// 提前设置订单修复的来源
|
||||
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
|
||||
|
||||
if (callbackType == PaymentTypeEnum.PAY){
|
||||
// 解析支付数据并放处理
|
||||
this.resolvePayData();
|
||||
payCallbackService.payCallback();
|
||||
} else {
|
||||
// 解析退款数据并放处理
|
||||
this.resolveRefundData();
|
||||
refundCallbackService.refundCallback();
|
||||
}
|
||||
callbackService.saveCallbackRecord();
|
||||
return this.getReturnMsg();
|
||||
} catch (Exception e) {
|
||||
log.error("回调处理失败", e);
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("回调处理失败: "+e.getMessage());
|
||||
callbackService.saveCallbackRecord();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证信息格式
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> params = callbackInfo.getCallbackParam();
|
||||
@@ -64,7 +116,6 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
*
|
||||
* @see PaymentTypeEnum
|
||||
*/
|
||||
@Override
|
||||
public PaymentTypeEnum getCallbackType() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> params = callbackInfo.getCallbackParam();
|
||||
@@ -79,7 +130,6 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 解析支付回调数据并放到上下文中
|
||||
*/
|
||||
@Override
|
||||
public void resolvePayData() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
@@ -107,7 +157,6 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 解析退款回调数据并放到上下文中
|
||||
*/
|
||||
@Override
|
||||
public void resolveRefundData() {
|
||||
// 云闪付需要延迟半秒再进行处理, 不然会出现业务未处理完, 但回调已经到达的情况
|
||||
ThreadUtil.sleep(100);
|
||||
@@ -139,16 +188,8 @@ public class UnionPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 返回响应结果
|
||||
*/
|
||||
@Override
|
||||
public String getReturnMsg() {
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.UNION_PAY;
|
||||
}
|
||||
}
|
||||
|
@@ -4,16 +4,23 @@ 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.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayCallbackStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
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.core.payment.callback.service.RefundCallbackService;
|
||||
import cn.bootx.platform.daxpay.service.core.record.callback.service.PayCallbackRecordService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsCallbackStrategy;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -34,22 +41,59 @@ import static cn.bootx.platform.daxpay.service.code.WeChatPayCode.*;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatPayCallbackService extends AbsCallbackStrategy {
|
||||
@Resource
|
||||
private WeChatPayConfigService weChatPayConfigService;
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayCallbackService {
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
private final PayCallbackRecordService callbackService;
|
||||
|
||||
private final PayCallbackService payCallbackService;
|
||||
|
||||
private final RefundCallbackService refundCallbackService;
|
||||
|
||||
/**
|
||||
* 策略标识
|
||||
* 回调处理入口
|
||||
*/
|
||||
@Override
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
public String callback(Map<String, String> params){
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
try {
|
||||
// 将参数写入到上下文中
|
||||
callbackInfo.getCallbackParam().putAll(params);
|
||||
|
||||
// 判断并保存回调类型
|
||||
PaymentTypeEnum callbackType = this.getCallbackType();
|
||||
callbackInfo.setCallbackType(callbackType)
|
||||
.setChannel(PayChannelEnum.ALI.getCode());
|
||||
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("验证信息格式不通过");
|
||||
// 消息有问题, 保存记录并返回
|
||||
callbackService.saveCallbackRecord();
|
||||
return null;
|
||||
}
|
||||
// 提前设置订单修复的来源
|
||||
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
|
||||
|
||||
if (callbackType == PaymentTypeEnum.PAY){
|
||||
// 解析支付数据并放处理
|
||||
this.resolvePayData();
|
||||
payCallbackService.payCallback();
|
||||
} else {
|
||||
// 解析退款数据并放处理
|
||||
this.resolveRefundData();
|
||||
refundCallbackService.refundCallback();
|
||||
}
|
||||
callbackService.saveCallbackRecord();
|
||||
return this.getReturnMsg();
|
||||
} catch (Exception e) {
|
||||
log.error("回调处理失败", e);
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("回调处理失败: "+e.getMessage());
|
||||
callbackService.saveCallbackRecord();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证回调消息
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> params = callbackInfo.getCallbackParam();
|
||||
@@ -79,7 +123,6 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 解析支付数据放到上下文中
|
||||
*/
|
||||
@Override
|
||||
public void resolvePayData() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
@@ -105,7 +148,6 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 解析退款回调数据并放到上下文中, 微信退款通知返回的数据需要进行解密
|
||||
*/
|
||||
@Override
|
||||
public void resolveRefundData() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
@@ -145,7 +187,6 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
|
||||
*
|
||||
* @see PaymentTypeEnum
|
||||
*/
|
||||
@Override
|
||||
public PaymentTypeEnum getCallbackType() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
Map<String, String> callbackParam = callbackInfo.getCallbackParam();
|
||||
@@ -159,7 +200,6 @@ public class WeChatPayCallbackService extends AbsCallbackStrategy {
|
||||
/**
|
||||
* 返回响应结果
|
||||
*/
|
||||
@Override
|
||||
public String getReturnMsg() {
|
||||
Map<String, String> xml = new HashMap<>(4);
|
||||
xml.put(RETURN_CODE, "SUCCESS");
|
||||
|
@@ -1,15 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.convert;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@Mapper
|
||||
public interface RefundOrderChannelConvert {
|
||||
RefundOrderChannelConvert CONVERT = Mappers.getMapper(RefundOrderChannelConvert.class);
|
||||
|
||||
}
|
@@ -2,7 +2,9 @@ package cn.bootx.platform.daxpay.service.core.order.refund.convert;
|
||||
|
||||
import cn.bootx.platform.daxpay.result.order.RefundOrderResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderExtraDto;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@@ -17,6 +19,8 @@ public interface RefundOrderConvert {
|
||||
|
||||
RefundOrderDto convert(RefundOrder in);
|
||||
|
||||
RefundOrderExtraDto convert(RefundOrderExtra in);
|
||||
|
||||
RefundOrderResult convertResult(RefundOrder in);
|
||||
|
||||
|
||||
|
@@ -1,9 +1,12 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.refund.entity;
|
||||
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WeChatPayParam;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderExtraDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
@@ -25,7 +28,7 @@ import java.time.LocalDateTime;
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_refund_order_extra")
|
||||
@DbTable(comment = "退款订单扩展信息")
|
||||
public class RefundOrderExtra extends MpBaseEntity {
|
||||
public class RefundOrderExtra extends MpBaseEntity implements EntityBaseFunction<RefundOrderExtraDto> {
|
||||
|
||||
/** 异步通知地址 */
|
||||
@DbColumn(comment = "异步通知地址")
|
||||
@@ -54,4 +57,8 @@ public class RefundOrderExtra extends MpBaseEntity {
|
||||
@DbColumn(comment = "支付终端ip")
|
||||
private String clientIp;
|
||||
|
||||
@Override
|
||||
public RefundOrderExtraDto toDto() {
|
||||
return RefundOrderConvert.CONVERT.convert(this);
|
||||
}
|
||||
}
|
||||
|
@@ -8,9 +8,12 @@ import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.param.payment.refund.QueryRefundParam;
|
||||
import cn.bootx.platform.daxpay.result.order.RefundOrderResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.convert.RefundOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderExtraManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderExtraDto;
|
||||
import cn.bootx.platform.daxpay.service.param.order.RefundOrderQuery;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -31,7 +34,7 @@ import java.util.Optional;
|
||||
@RequiredArgsConstructor
|
||||
public class RefundOrderQueryService {
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
|
||||
private final RefundOrderExtraManager refundOrderExtraManager;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
@@ -49,6 +52,14 @@ public class RefundOrderQueryService {
|
||||
.orElseThrow(() -> new DataNotExistException("退款订单不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id查询扩展信息
|
||||
*/
|
||||
public RefundOrderExtraDto findExtraById(Long id) {
|
||||
return refundOrderExtraManager.findById(id).map(RefundOrderExtra::toDto)
|
||||
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据退款号和商户退款号查询
|
||||
*/
|
||||
|
@@ -6,6 +6,7 @@ import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.payment.pay.PayCloseParam;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayCloseResult;
|
||||
import cn.bootx.platform.daxpay.result.pay.PayResult;
|
||||
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.order.pay.entity.PayOrder;
|
||||
@@ -65,12 +66,12 @@ public class PayCloseService {
|
||||
* 关闭支付记录
|
||||
*/
|
||||
private PayCloseResult close(PayOrder payOrder) {
|
||||
PayCloseResult result = new PayCloseResult();
|
||||
try {
|
||||
// 状态检查, 只有支付中可以进行取消支付
|
||||
if (!Objects.equals(payOrder.getStatus(), PayStatusEnum.PROGRESS.getCode())) {
|
||||
throw new PayFailureException("订单不是支付中, 无法进行关闭订单");
|
||||
}
|
||||
|
||||
AbsPayCloseStrategy strategy = PayCloseStrategyFactory.create(payOrder.getChannel());
|
||||
// 设置支付订单
|
||||
strategy.setOrder(payOrder);
|
||||
@@ -78,15 +79,18 @@ public class PayCloseService {
|
||||
strategy.doBeforeCloseHandler();
|
||||
// 执行关闭策略
|
||||
strategy.doCloseHandler();
|
||||
// 成功处理
|
||||
this.successHandler(payOrder);
|
||||
// 签名
|
||||
this.sign(result);
|
||||
// 返回结果
|
||||
return this.sign(new PayCloseResult());
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
// 记录关闭失败的记录
|
||||
this.saveRecord(payOrder, false, e.getMessage());
|
||||
PayCloseResult payCloseResult = new PayCloseResult();
|
||||
payCloseResult.setCode("1").setMsg(e.getMessage());
|
||||
return this.sign(payCloseResult);
|
||||
result.setCode("1").setMsg(e.getMessage());
|
||||
this.sign(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +127,7 @@ public class PayCloseService {
|
||||
/**
|
||||
* 对返回结果进行签名
|
||||
*/
|
||||
private PayCloseResult sign(PayCloseResult result){
|
||||
private void sign(PayCloseResult result){
|
||||
PlatformLocal platformInfo = PaymentContextLocal.get()
|
||||
.getPlatformInfo();
|
||||
String signType = platformInfo.getSignType();
|
||||
@@ -134,6 +138,5 @@ public class PayCloseService {
|
||||
} else {
|
||||
throw new PayFailureException("未获取到签名方式,请检查");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ public class PaymentSignService {
|
||||
private final PaymentAssistService paymentAssistService;;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
* 入参签名校验
|
||||
*/
|
||||
public void verifySign(PaymentCommonParam param) {
|
||||
// 先触发上下文的初始化
|
||||
|
@@ -245,11 +245,19 @@ public class PayAssistService {
|
||||
payResult.setStatus(payOrder.getStatus());
|
||||
|
||||
// 设置支付参数
|
||||
PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo();;
|
||||
PayLocal asyncPayInfo = PaymentContextLocal.get()
|
||||
.getPayInfo();
|
||||
if (StrUtil.isNotBlank(asyncPayInfo.getPayBody())) {
|
||||
payResult.setPayBody(asyncPayInfo.getPayBody());
|
||||
}
|
||||
|
||||
// 签名
|
||||
this.sign(payResult);
|
||||
return payResult;
|
||||
}
|
||||
/**
|
||||
* 对返回
|
||||
*/
|
||||
public void sign(PayResult payResult) {
|
||||
// 进行签名
|
||||
PlatformLocal platformInfo = PaymentContextLocal.get()
|
||||
.getPlatformInfo();
|
||||
@@ -261,6 +269,5 @@ public class PayAssistService {
|
||||
} else {
|
||||
throw new PayFailureException("未获取到签名方式,请检查");
|
||||
}
|
||||
return payResult;
|
||||
}
|
||||
}
|
||||
|
@@ -86,7 +86,7 @@ public class PayService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次支付
|
||||
* 首次支付 无事务
|
||||
* 拆分为多阶段,1. 保存订单记录信息 2 调起支付 3. 支付成功后操作
|
||||
*/
|
||||
public PayResult firstPay(PayParam payParam){
|
||||
@@ -104,6 +104,7 @@ public class PayService {
|
||||
payStrategy.doPayHandler();
|
||||
} catch (Exception e) {
|
||||
payOrder.setErrorMsg(e.getMessage());
|
||||
// 这个方法没有事务, 所以可以正常更新
|
||||
payOrderService.updateById(payOrder);
|
||||
throw e;
|
||||
}
|
||||
@@ -182,7 +183,6 @@ public class PayService {
|
||||
payOrderService.updateById(payOrder);
|
||||
// 如果支付完成 发送通知
|
||||
if (Objects.equals(payOrder.getStatus(), SUCCESS.getCode())){
|
||||
// 查询通道订单
|
||||
clientNoticeService.registerPayNotice(payOrder, payOrderExtra);
|
||||
}
|
||||
return payAssistService.buildResult(payOrder);
|
||||
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.core.payment.refund.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
@@ -13,12 +14,15 @@ import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderExtraManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.notice.service.ClientNoticeService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.refund.factory.RefundStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsRefundStrategy;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -52,26 +56,31 @@ public class RefundService {
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
|
||||
private final LockTemplate lockTemplate;
|
||||
private final RefundOrderExtraManager refundOrderExtraManager;
|
||||
|
||||
/**
|
||||
* 分支付通道进行退款
|
||||
* 1. 创建退款订单和通道订单并保存(单独事务)
|
||||
* 1. 创建退款订单(单独事务)
|
||||
* 2. 调用API发起退款(异步退款)
|
||||
* 3. 根据API返回信息更新退款订单信息
|
||||
*/
|
||||
public RefundResult refund(RefundParam param){
|
||||
RefundResult result = new RefundResult()
|
||||
.setRefundNo(param.getBizRefundNo())
|
||||
.setBizRefundNo(param.getBizRefundNo());
|
||||
// 参数校验
|
||||
ValidationUtil.validateParam(param);
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("payment:refund:" + param.getBizRefundNo(),10000,200);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("退款处理中,请勿重复操作");
|
||||
result.setMsg("退款处理中,请勿重复操作");
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
// 判断是否是首次发起退款
|
||||
Optional<RefundOrder> refund = refundOrderManager.findByBizRefundNo(param.getBizRefundNo());
|
||||
if (refund.isPresent()){
|
||||
return this.repeatRefund(refund.get());
|
||||
return this.repeatRefund(refund.get(),param);
|
||||
} else {
|
||||
return this.firstRefund(param);
|
||||
}
|
||||
@@ -90,26 +99,24 @@ public class RefundService {
|
||||
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
|
||||
// 检查退款参数
|
||||
refundAssistService.checkAndParam(param, payOrder);
|
||||
|
||||
// ----------------------------- 发起退款操作 --------------------------------------------
|
||||
|
||||
// 通过退款参数获取退款策略
|
||||
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(payOrder.getChannel());
|
||||
// 设置支付订单数据
|
||||
refundStrategy.setPayOrder(payOrder);
|
||||
// 进行退款前预处理
|
||||
refundStrategy.doBeforeRefundHandler();
|
||||
// 退款操作的预处理, 使用独立的新事物进行发起, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
|
||||
// 退款操作的预处理, 对支付订单进行预扣款, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
|
||||
RefundOrder refundOrder = SpringUtil.getBean(this.getClass()).preRefundMethod(param, payOrder);
|
||||
try {
|
||||
// 3.2 执行退款策略
|
||||
// 执行退款策略
|
||||
refundStrategy.doRefundHandler();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 5. 失败处理, 所有记录都会回滚, 可以调用重新
|
||||
// 记录处理失败状态
|
||||
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
|
||||
// 记录退款失败的记录
|
||||
// 更新退款失败的记录
|
||||
refundAssistService.updateOrderByError(refundOrder);
|
||||
return refundAssistService.buildResult(refundOrder);
|
||||
}
|
||||
SpringUtil.getBean(this.getClass()).successHandler(refundOrder, payOrder);
|
||||
return refundAssistService.buildResult(refundOrder);
|
||||
@@ -133,31 +140,37 @@ public class RefundService {
|
||||
/**
|
||||
* 重新发起退款处理
|
||||
* 1. 查出相关退款订单
|
||||
* 2. 构建退款策略, 发起退款
|
||||
* 2. 更新退款扩展参数
|
||||
* 3. 构建退款策略, 发起退款
|
||||
*/
|
||||
public RefundResult repeatRefund(RefundOrder refundOrder){
|
||||
public RefundResult repeatRefund(RefundOrder refundOrder, RefundParam param){
|
||||
// 退款失败才可以重新发起退款, 重新发起退款
|
||||
if (!Objects.equals(refundOrder.getStatus(), RefundStatusEnum.FAIL.getCode())){
|
||||
throw new PayFailureException("只有失败状态的才可以重新发起退款");
|
||||
}
|
||||
|
||||
// 获取支付订单
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(refundOrder.getOrderNo(), refundOrder.getBizOrderNo())
|
||||
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
|
||||
RefundOrderExtra refundOrderExtra = refundOrderExtraManager.findById(refundOrder.getId())
|
||||
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
|
||||
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(refundOrder.getRefundNo());
|
||||
// 设置退款订单对象
|
||||
refundStrategy.setRefundOrder(refundOrder);
|
||||
// 退款前准备操作
|
||||
refundStrategy.doBeforeRefundHandler();
|
||||
// 进行发起退款前的操作, 更新扩展记录信息
|
||||
this.updateExtra(refundOrderExtra, param);
|
||||
try {
|
||||
// 执行退款策略
|
||||
refundStrategy.doRefundHandler();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 失败处理, 所有记录都会回滚, 可以调用退款重试
|
||||
// 记录处理失败状态
|
||||
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
|
||||
// 记录退款失败的记录
|
||||
refundAssistService.updateOrderByError(refundOrder);
|
||||
// 返回错误响应对象
|
||||
return refundAssistService.buildResult(refundOrder);
|
||||
}
|
||||
// 退款发起成功处理
|
||||
SpringUtil.getBean(this.getClass()).successHandler(refundOrder, payOrder);
|
||||
@@ -165,7 +178,21 @@ public class RefundService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功处理, 更新退款订单, 退款通道订单, 支付订单, 支付通道订单
|
||||
* 更新退款订单扩展信息
|
||||
*/
|
||||
private void updateExtra(RefundOrderExtra refundOrderExtra, RefundParam param){
|
||||
refundOrderExtra.setAttach(param.getAttach())
|
||||
.setClientIp(param.getClientIp())
|
||||
.setNotifyUrl(param.getNotifyUrl())
|
||||
.setReqTime(param.getReqTime());
|
||||
if (CollUtil.isNotEmpty(param.getExtraParam())){
|
||||
refundOrderExtra.setExtraParam(JSONUtil.toJsonStr(param.getExtraParam()));
|
||||
}
|
||||
refundOrderExtraManager.updateById(refundOrderExtra);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功处理, 更新退款订单, 支付订单,
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void successHandler(RefundOrder refundOrder, PayOrder payOrder) {
|
||||
@@ -182,7 +209,7 @@ public class RefundService {
|
||||
}
|
||||
payOrderService.updateById(payOrder);
|
||||
|
||||
// 更新退款订单和相关通道订单
|
||||
// 更新退款订单
|
||||
refundAssistService.updateOrder(refundOrder);
|
||||
|
||||
// 发送通知
|
||||
|
@@ -4,14 +4,17 @@ import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.payment.pay.PaySyncParam;
|
||||
import cn.bootx.platform.daxpay.result.CommonResult;
|
||||
import cn.bootx.platform.daxpay.result.pay.SyncResult;
|
||||
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PayRepairWayEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RepairLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
@@ -24,6 +27,7 @@ import cn.bootx.platform.daxpay.service.core.payment.sync.result.PaySyncResult;
|
||||
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 cn.bootx.platform.daxpay.util.PaySignUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -64,21 +68,16 @@ public class PaySyncService {
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public SyncResult sync(PaySyncParam param) {
|
||||
PayOrder payOrder = null;
|
||||
if (Objects.nonNull(param.getOrderNo())){
|
||||
payOrder = payOrderQueryService.findByOrderNo(param.getOrderNo())
|
||||
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
|
||||
}
|
||||
if (Objects.isNull(payOrder)){
|
||||
payOrder = payOrderQueryService.findByBizOrderNo(param.getBizOrderNo())
|
||||
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
|
||||
}
|
||||
SyncResult syncResult = new SyncResult();
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrOrderNo(param.getBizOrderNo(), param.getOrderNo())
|
||||
.orElseThrow(() -> new BizException("支付订单不存在"));
|
||||
// 钱包支付直接返回结果
|
||||
if (PayChannelEnum.WALLET.getCode().equals(payOrder.getChannel())){
|
||||
throw new PayFailureException("订单没有异步支付方式,不需要同步");
|
||||
}
|
||||
// 执行订单同步逻辑
|
||||
return this.syncPayOrder(payOrder);
|
||||
syncResult = this.syncPayOrder(payOrder);
|
||||
return syncResult;
|
||||
}
|
||||
/**
|
||||
* 同步支付状态, 开启一个新的事务, 不受外部抛出异常的影响
|
||||
@@ -138,7 +137,7 @@ public class PaySyncService {
|
||||
return new SyncResult()
|
||||
.setGatewayStatus(syncResult.getSyncStatus().getCode())
|
||||
.setRepair(!statusSync)
|
||||
.setRepairOrderNo(repairResult.getRepairNo());
|
||||
.setRepairNo(repairResult.getRepairNo());
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
@@ -260,4 +259,20 @@ public class PaySyncService {
|
||||
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
|
||||
paySyncRecordService.saveRecord(paySyncRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private void sign(CommonResult result){
|
||||
PlatformLocal platformInfo = PaymentContextLocal.get()
|
||||
.getPlatformInfo();
|
||||
String signType = platformInfo.getSignType();
|
||||
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
|
||||
result.setSign(PaySignUtil.hmacSha256Sign(result, platformInfo.getSignSecret()));
|
||||
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
|
||||
result.setSign(PaySignUtil.md5Sign(result, platformInfo.getSignSecret()));
|
||||
} else {
|
||||
throw new PayFailureException("未获取到签名方式,请检查");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -121,7 +121,7 @@ public class RefundSyncService {
|
||||
return new SyncResult()
|
||||
.setGatewayStatus(syncResult.getSyncStatus().getCode())
|
||||
.setRepair(!statusSync)
|
||||
.setRepairOrderNo(repairResult.getRepairNo());
|
||||
.setRepairNo(repairResult.getRepairNo());
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
|
@@ -4,10 +4,13 @@ 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.common.context.CallbackLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
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 cn.bootx.platform.daxpay.service.param.record.PayCallbackRecordQuery;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -43,7 +46,17 @@ public class PayCallbackRecordService {
|
||||
* 保存回调记录
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void save(PayCallbackRecord record) {
|
||||
callbackRecordManager.save(record);
|
||||
public void saveCallbackRecord() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
|
||||
.setTradeNo(callbackInfo.getTradeNo())
|
||||
.setOutTradeNo(callbackInfo.getOutTradeNo())
|
||||
.setChannel(callbackInfo.getChannel())
|
||||
.setNotifyInfo(JSONUtil.toJsonStr(callbackInfo.getCallbackParam()))
|
||||
.setCallbackType(callbackInfo.getCallbackType().getCode())
|
||||
.setRepairOrderNo(callbackInfo.getRepairNo())
|
||||
.setStatus(callbackInfo.getCallbackStatus().getCode())
|
||||
.setMsg(callbackInfo.getMsg());
|
||||
callbackRecordManager.save(payNotifyRecord);
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.pay;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付订单和扩展信息
|
||||
* @author xxm
|
||||
* @since 2024/4/26
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "支付订单和扩展信息")
|
||||
public class PayOrderDetailDto {
|
||||
@Schema(description = "支付订单")
|
||||
private PayOrderDto payOrder;
|
||||
@Schema(description = "支付订单扩展信息")
|
||||
private PayOrderExtraDto payOrderExtra;
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ public class PayOrderDto extends BaseDto {
|
||||
|
||||
/**
|
||||
* 异步支付通道
|
||||
* @see PayChannelEnum#ASYNC_TYPE_CODE
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Schema(description = "异步支付通道")
|
||||
private String asyncChannel;
|
||||
|
@@ -1,48 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.refund;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付退款通道订单
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "支付退款通道订单")
|
||||
public class RefundChannelOrderDto extends BaseDto {
|
||||
|
||||
@Schema(description = "关联退款id")
|
||||
private Long refundId;
|
||||
|
||||
@Schema(description = "通道")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "通道支付单id")
|
||||
private Long payChannelId;
|
||||
|
||||
@Schema(description = "异步支付方式")
|
||||
private boolean async;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private Integer orderAmount;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private Integer amount;
|
||||
|
||||
@Schema(description = "剩余可退余额")
|
||||
private Integer refundableAmount;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see RefundStatusEnum
|
||||
*/
|
||||
@Schema(description = "退款状态")
|
||||
private String status;
|
||||
}
|
@@ -41,7 +41,7 @@ public class RefundOrderDto extends BaseDto {
|
||||
|
||||
/**
|
||||
* 异步通道
|
||||
* @see PayChannelEnum#ASYNC_TYPE_CODE
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@Schema(description = "异步通道")
|
||||
private String asyncChannel;
|
||||
|
@@ -0,0 +1,47 @@
|
||||
package cn.bootx.platform.daxpay.service.dto.order.refund;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.WeChatPayParam;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 退款订单扩展信息
|
||||
* @author xxm
|
||||
* @since 2024/4/26
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "退款订单扩展信息")
|
||||
public class RefundOrderExtraDto extends BaseDto {
|
||||
|
||||
/** 异步通知地址 */
|
||||
private String notifyUrl;
|
||||
|
||||
/** 商户扩展参数,回调时会原样返回, 以最后一次为准 */
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 附加参数 以最后一次为准
|
||||
* @see AliPayParam
|
||||
* @see WeChatPayParam
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
private String extraParam;
|
||||
|
||||
/** 请求时间,时间戳转时间 */
|
||||
private LocalDateTime reqTime;
|
||||
|
||||
/** 终端ip */
|
||||
private String clientIp;
|
||||
}
|
@@ -22,96 +22,6 @@ import java.util.Map;
|
||||
* @since 2021/6/21
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
public abstract class AbsCallbackStrategy implements PayStrategy {
|
||||
@Resource
|
||||
private PayCallbackRecordService callbackRecordService;
|
||||
@Resource
|
||||
private PayCallbackService payCallbackService;
|
||||
@Resource
|
||||
private RefundCallbackService refundCallbackService;
|
||||
|
||||
/**
|
||||
* 回调处理入口
|
||||
*/
|
||||
public String callback(Map<String, String> params) {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
try {
|
||||
// 将参数写入到上下文中
|
||||
callbackInfo.getCallbackParam().putAll(params);
|
||||
|
||||
// 判断并保存回调类型
|
||||
PaymentTypeEnum callbackType = this.getCallbackType();
|
||||
callbackInfo.setCallbackType(callbackType);
|
||||
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("验证信息格式不通过");
|
||||
// 消息有问题, 保存记录并返回
|
||||
this.saveCallbackRecord();
|
||||
return null;
|
||||
}
|
||||
// 提前设置订单修复的来源
|
||||
PaymentContextLocal.get().getRepairInfo().setSource(PayRepairSourceEnum.CALLBACK);
|
||||
|
||||
if (callbackType == PaymentTypeEnum.PAY){
|
||||
// 解析支付数据并放处理
|
||||
this.resolvePayData();
|
||||
payCallbackService.payCallback();
|
||||
} else {
|
||||
// 解析退款数据并放处理
|
||||
this.resolveRefundData();
|
||||
refundCallbackService.refundCallback();
|
||||
}
|
||||
this.saveCallbackRecord();
|
||||
return this.getReturnMsg();
|
||||
} catch (Exception e) {
|
||||
log.error("回调处理失败", e);
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.FAIL).setMsg("回调处理失败: "+e.getMessage());
|
||||
this.saveCallbackRecord();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证信息格式
|
||||
*/
|
||||
public abstract boolean verifyNotify();
|
||||
|
||||
/**
|
||||
* 判断类型 支付回调/退款回调
|
||||
* @see PaymentTypeEnum
|
||||
*/
|
||||
public abstract PaymentTypeEnum getCallbackType();
|
||||
|
||||
/**
|
||||
* 解析支付回调数据并放到上下文中
|
||||
*/
|
||||
public abstract void resolvePayData();
|
||||
|
||||
/**
|
||||
* 解析退款回调数据并放到上下文中
|
||||
*/
|
||||
public abstract void resolveRefundData();
|
||||
|
||||
/**
|
||||
* 返回响应结果
|
||||
*/
|
||||
public abstract String getReturnMsg();
|
||||
|
||||
/**
|
||||
* 保存回调记录
|
||||
*/
|
||||
public void saveCallbackRecord() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
|
||||
.setTradeNo(callbackInfo.getTradeNo())
|
||||
.setOutTradeNo(callbackInfo.getOutTradeNo())
|
||||
.setChannel(this.getChannel().getCode())
|
||||
.setNotifyInfo(JSONUtil.toJsonStr(callbackInfo.getCallbackParam()))
|
||||
.setCallbackType(callbackInfo.getCallbackType().getCode())
|
||||
.setRepairOrderNo(callbackInfo.getRepairNo())
|
||||
.setStatus(callbackInfo.getCallbackStatus().getCode())
|
||||
.setMsg(callbackInfo.getMsg());
|
||||
callbackRecordService.save(payNotifyRecord);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,36 @@
|
||||
package cn.bootx.platform.daxpay.service.handler.exception;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.result.CommonResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 过滤SaTokenException,需要运行在 RestExceptionHandler 之前
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/8/5
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 2)
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class PaymentExceptionHandler {
|
||||
|
||||
/**
|
||||
* 支付异常
|
||||
*/
|
||||
@ExceptionHandler({PayFailureException.class})
|
||||
public ResResult<CommonResult> handleBusinessException(PayFailureException ex) {
|
||||
log.info(ex.getMessage(), ex);
|
||||
CommonResult commonResult = new CommonResult();
|
||||
commonResult.setMsg(ex.getMessage());
|
||||
return Res.ok(commonResult);
|
||||
}
|
||||
}
|
@@ -47,7 +47,7 @@ public class PayOrderQuery extends QueryOrder {
|
||||
|
||||
/**
|
||||
* 异步支付通道
|
||||
* @see PayChannelEnum#ASYNC_TYPE_CODE
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
@QueryParam(type = QueryParam.CompareTypeEnum.EQ)
|
||||
@Schema(description = "异步支付通道")
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.param.reconcile;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.QueryParam;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@@ -22,7 +24,7 @@ public class ReconcileOrderQuery {
|
||||
private String batchNo;
|
||||
|
||||
@Schema(description = "日期")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATE_PATTERN)
|
||||
private LocalDate date;
|
||||
|
||||
@Schema(description = "通道")
|
||||
|
Reference in New Issue
Block a user