mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-29 18:51:53 +08:00
code review 退款逻辑
This commit is contained in:
parent
d49ce4c81f
commit
bcc2ff0f5b
@ -1,25 +0,0 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付通用 Core Service
|
|
||||||
*
|
|
||||||
* @author jason
|
|
||||||
*/
|
|
||||||
public interface PayCommonCoreService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证是否是渠道通知
|
|
||||||
* @param notifyData 通知数据
|
|
||||||
*/
|
|
||||||
void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付宝的支付回调通知,和退款回调通知 地址是同一个
|
|
||||||
* 是否是退款回调通知
|
|
||||||
* @param notifyData 通知数据
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData);
|
|
||||||
}
|
|
@ -47,6 +47,4 @@ public interface PayOrderCoreService {
|
|||||||
*/
|
*/
|
||||||
void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,21 @@ import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付退款订单 ,渠道返回后 后置处理
|
* 支付退款订单 ,渠道返回后 后置处理
|
||||||
|
*
|
||||||
* @author jason
|
* @author jason
|
||||||
*/
|
*/
|
||||||
public interface PayRefundChannelPostHandler {
|
public interface PayRefundChannelPostHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持的渠道返回值
|
* 支持的渠道返回值
|
||||||
|
*
|
||||||
* @return 支持的渠道返回值数组
|
* @return 支持的渠道返回值数组
|
||||||
*/
|
*/
|
||||||
PayChannelRespEnum[] supportHandleResp();
|
PayChannelRespEnum[] supportHandleResp();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据渠道返回, 处理支付退款单
|
* 根据渠道返回,处理支付退款单
|
||||||
|
*
|
||||||
* @param respBO
|
* @param respBO
|
||||||
*/
|
*/
|
||||||
void handleRefundChannelResp(PayRefundPostReqBO respBO);
|
void handleRefundChannelResp(PayRefundPostReqBO respBO);
|
||||||
|
@ -11,23 +11,22 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
|||||||
*/
|
*/
|
||||||
public interface PayRefundCoreService {
|
public interface PayRefundCoreService {
|
||||||
|
|
||||||
|
// TODO @jason:方法名改成,submitRefundOrder,发起退款订单。这样和发起支付单,保持一致
|
||||||
/**
|
/**
|
||||||
* 提交退款申请
|
* 提交退款申请
|
||||||
|
*
|
||||||
* @param reqDTO 退款申请信息
|
* @param reqDTO 退款申请信息
|
||||||
* @return 退款申请返回信息
|
* @return 退款申请返回信息
|
||||||
*/
|
*/
|
||||||
PayRefundRespBO refund(PayRefundReqBO reqDTO);
|
PayRefundRespBO refund(PayRefundReqBO reqDTO);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渠道的退款通知
|
* 渠道的退款通知
|
||||||
|
*
|
||||||
* @param channelId 渠道编号
|
* @param channelId 渠道编号
|
||||||
* @param notifyData 通知数据
|
* @param notifyData 通知数据
|
||||||
* @throws Exception 退款通知异常
|
* @throws Exception 退款通知异常
|
||||||
*/
|
*/
|
||||||
void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
// TODO @jason:改到 dto 哈。我们项目,统一使用 DTO
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@Builder
|
@Builder
|
||||||
|
@ -5,6 +5,8 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
// TODO @jason:改到 dto 哈。我们项目,统一使用 DTO
|
||||||
/**
|
/**
|
||||||
* 退款申请单 Request DTO
|
* 退款申请单 Request DTO
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
// TODO @jason:改到 dto 哈。我们项目,统一使用 DTO
|
||||||
/**
|
/**
|
||||||
* 退款申请单 Response DTO
|
* 退款申请单 Response DTO
|
||||||
*/
|
*/
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
|
|
||||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_NOTIFY_VERIFY_FAILED;
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付通用 Core Service 实现类
|
|
||||||
*
|
|
||||||
* @author jason
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class PayCommonCoreServiceImpl implements PayCommonCoreService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PayChannelCoreService payChannelCoreService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PayClientFactory payClientFactory;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData) {
|
|
||||||
// 校验支付渠道是否有效
|
|
||||||
PayChannelDO channel = payChannelCoreService.validPayChannel(channelId);
|
|
||||||
// 校验支付客户端是否正确初始化
|
|
||||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
|
||||||
if (client == null) {
|
|
||||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
|
||||||
}
|
|
||||||
boolean verifyResult = client.verifyNotifyData(notifyData);
|
|
||||||
if(!verifyResult){
|
|
||||||
//渠道通知验证失败
|
|
||||||
throw exception(PAY_CHANNEL_NOTIFY_VERIFY_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData) {
|
|
||||||
// 校验支付渠道是否有效
|
|
||||||
PayChannelDO channel = payChannelCoreService.validPayChannel(channelId);
|
|
||||||
// 校验支付客户端是否正确初始化
|
|
||||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
|
||||||
if (client == null) {
|
|
||||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
|
||||||
}
|
|
||||||
return client.isRefundNotify(notifyData);
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,18 +50,17 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderCoreMapper payOrderCoreMapper;
|
private PayOrderCoreMapper payOrderCoreMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayRefundCoreMapper payRefundCoreMapper;
|
private PayRefundCoreMapper payRefundCoreMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderExtensionCoreMapper payOrderExtensionCoreMapper;
|
private PayOrderExtensionCoreMapper payOrderExtensionCoreMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayAppCoreService payAppCoreService;
|
private PayAppCoreService payAppCoreService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayChannelCoreService payChannelCoreService;
|
private PayChannelCoreService payChannelCoreService;
|
||||||
|
@Resource
|
||||||
|
private PayNotifyCoreService payNotifyCoreService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayClientFactory payClientFactory;
|
private PayClientFactory payClientFactory;
|
||||||
@ -72,25 +71,18 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
@Resource
|
@Resource
|
||||||
private List<PayRefundChannelPostHandler> handlerList;
|
private List<PayRefundChannelPostHandler> handlerList;
|
||||||
|
|
||||||
@Resource
|
// TODO @json:mapHandlers
|
||||||
private PayNotifyCoreService payNotifyCoreService;
|
|
||||||
|
|
||||||
|
|
||||||
private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandler = new EnumMap<>(PayChannelRespEnum.class);
|
private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandler = new EnumMap<>(PayChannelRespEnum.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init(){
|
public void init(){
|
||||||
|
|
||||||
if (Objects.nonNull(handlerList)) {
|
if (Objects.nonNull(handlerList)) {
|
||||||
handlerList.forEach(t->{
|
handlerList.forEach(handler -> {
|
||||||
for (PayChannelRespEnum item : t.supportHandleResp()) {
|
for (PayChannelRespEnum item : handler.supportHandleResp()) {
|
||||||
mapHandler.put(item, t);
|
mapHandler.put(item, handler);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,16 +105,16 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
//校验退款的条件
|
// 校验退款的条件
|
||||||
validatePayRefund(reqBO, order);
|
validatePayRefund(reqBO, order);
|
||||||
|
|
||||||
//退款类型
|
// 退款类型
|
||||||
PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
|
PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
|
||||||
if (Objects.equals(reqBO.getAmount(), order.getAmount())) {
|
if (Objects.equals(reqBO.getAmount(), order.getAmount())) {
|
||||||
refundType = PayRefundTypeEnum.ALL;
|
refundType = PayRefundTypeEnum.ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//退款单入库 退款单状态:生成, 没有和渠道产生交互
|
// 退款单入库 退款单状态:生成, 没有和渠道产生交互
|
||||||
PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
|
PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
|
||||||
PayRefundDO refundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
|
PayRefundDO refundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
|
||||||
.appId(order.getAppId())
|
.appId(order.getAppId())
|
||||||
@ -144,9 +136,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
.reqNo(PaySeqUtils.genRefundReqNo())
|
.reqNo(PaySeqUtils.genRefundReqNo())
|
||||||
.type(refundType.getStatus())
|
.type(refundType.getStatus())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
payRefundCoreMapper.insert(refundDO);
|
payRefundCoreMapper.insert(refundDO);
|
||||||
|
|
||||||
|
// TODO @jason:可以把“调用渠道进行退款"写到这里,这样分块更明确
|
||||||
PayRefundUnifiedReqDTO unifiedReqDTO = PayRefundUnifiedReqDTO.builder()
|
PayRefundUnifiedReqDTO unifiedReqDTO = PayRefundUnifiedReqDTO.builder()
|
||||||
.userIp(reqBO.getUserIp())
|
.userIp(reqBO.getUserIp())
|
||||||
.channelOrderNo(refundDO.getChannelOrderNo())
|
.channelOrderNo(refundDO.getChannelOrderNo())
|
||||||
@ -156,13 +148,14 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
.reason(refundDO.getReason())
|
.reason(refundDO.getReason())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
//调用渠道进行退款
|
// 调用渠道进行退款
|
||||||
PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
|
PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
|
||||||
|
|
||||||
//根据渠道返回,获取退款后置处理,由postHandler 进行处理
|
// TODO @jason:下面这块,是一整块逻辑,不要空开。不然阅读的时候,会以为不是一块逻辑
|
||||||
|
// 根据渠道返回,获取退款后置处理,由postHandler 进行处理
|
||||||
PayRefundChannelPostHandler payRefundChannelPostHandler = mapHandler.get(refundUnifiedRespDTO.getRespEnum());
|
PayRefundChannelPostHandler payRefundChannelPostHandler = mapHandler.get(refundUnifiedRespDTO.getRespEnum());
|
||||||
|
|
||||||
if(Objects.isNull(payRefundChannelPostHandler)){
|
if (Objects.isNull(payRefundChannelPostHandler)) {
|
||||||
throw exception(PAY_REFUND_POST_HANDLER_NOT_FOUND);
|
throw exception(PAY_REFUND_POST_HANDLER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,11 +185,12 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
//解析渠道退款通知数据, 统一处理
|
// 解析渠道退款通知数据, 统一处理
|
||||||
PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData);
|
PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData);
|
||||||
|
|
||||||
if(Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){
|
// TODO @jason:抽一个 notifyPayRefundSuccess 方法
|
||||||
//退款成功。 支付宝只有退款成功才会发通知
|
if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){
|
||||||
|
// 退款成功。 支付宝只有退款成功才会发通知
|
||||||
PayRefundDO refundDO = payRefundCoreMapper.selectByReqNo(refundNotify.getReqNo());
|
PayRefundDO refundDO = payRefundCoreMapper.selectByReqNo(refundNotify.getReqNo());
|
||||||
if (refundDO == null) {
|
if (refundDO == null) {
|
||||||
log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());
|
log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());
|
||||||
@ -208,9 +202,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
if(PayRefundTypeEnum.ALL.getStatus().equals(type)){
|
if(PayRefundTypeEnum.ALL.getStatus().equals(type)){
|
||||||
orderStatus = PayOrderStatusEnum.CLOSED;
|
orderStatus = PayOrderStatusEnum.CLOSED;
|
||||||
}
|
}
|
||||||
//更新支付订单
|
// 更新支付订单
|
||||||
PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
|
PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
|
||||||
//需更新已退金额
|
// 需更新已退金额
|
||||||
Long refundedAmount = payOrderDO.getRefundAmount();
|
Long refundedAmount = payOrderDO.getRefundAmount();
|
||||||
PayOrderDO updateOrderDO = new PayOrderDO();
|
PayOrderDO updateOrderDO = new PayOrderDO();
|
||||||
updateOrderDO.setId(refundDO.getOrderId())
|
updateOrderDO.setId(refundDO.getOrderId())
|
||||||
@ -219,7 +213,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
.setRefundStatus(type);
|
.setRefundStatus(type);
|
||||||
payOrderCoreMapper.updateById(updateOrderDO);
|
payOrderCoreMapper.updateById(updateOrderDO);
|
||||||
|
|
||||||
//跟新退款订单
|
// 跟新退款订单
|
||||||
PayRefundDO updateRefundDO = new PayRefundDO();
|
PayRefundDO updateRefundDO = new PayRefundDO();
|
||||||
updateRefundDO.setId(refundDO.getId())
|
updateRefundDO.setId(refundDO.getId())
|
||||||
.setSuccessTime(refundNotify.getRefundSuccessTime())
|
.setSuccessTime(refundNotify.getRefundSuccessTime())
|
||||||
@ -233,10 +227,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
// TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
|
// TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
|
||||||
payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||||
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
|
||||||
}else{
|
} else {
|
||||||
//TODO 退款失败
|
//TODO 退款失败
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,7 +238,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
* @param order 原始支付订单信息
|
* @param order 原始支付订单信息
|
||||||
*/
|
*/
|
||||||
private void validatePayRefund(PayRefundReqBO reqBO, PayOrderDO order) {
|
private void validatePayRefund(PayRefundReqBO reqBO, PayOrderDO order) {
|
||||||
|
|
||||||
// 校验状态,必须是支付状态
|
// 校验状态,必须是支付状态
|
||||||
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
||||||
throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
||||||
@ -258,10 +250,11 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|||||||
if(reqBO.getAmount() + order.getRefundAmount() > order.getAmount()){
|
if(reqBO.getAmount() + order.getRefundAmount() > order.getAmount()){
|
||||||
throw exception(PAY_REFUND_AMOUNT_EXCEED);
|
throw exception(PAY_REFUND_AMOUNT_EXCEED);
|
||||||
}
|
}
|
||||||
//校验渠道订单号
|
// 校验渠道订单号
|
||||||
if (StrUtil.isEmpty(order.getChannelOrderNo())) {
|
if (StrUtil.isEmpty(order.getChannelOrderNo())) {
|
||||||
throw exception(PAY_REFUND_CHN_ORDER_NO_IS_NULL);
|
throw exception(PAY_REFUND_CHN_ORDER_NO_IS_NULL);
|
||||||
}
|
}
|
||||||
//TODO 退款的期限 退款次数的控制
|
//TODO 退款的期限 退款次数的控制
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
@ -34,7 +34,6 @@ public interface PayClient {
|
|||||||
*/
|
*/
|
||||||
PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception;
|
PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用支付渠道,进行退款
|
* 调用支付渠道,进行退款
|
||||||
* @param reqDTO 统一退款请求信息
|
* @param reqDTO 统一退款请求信息
|
||||||
@ -49,22 +48,26 @@ public interface PayClient {
|
|||||||
*/
|
*/
|
||||||
PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData);
|
PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData);
|
||||||
|
|
||||||
|
// TODO @芋艿:后续改成非 default,避免不知道去实现
|
||||||
/**
|
/**
|
||||||
* 验证是否渠道通知
|
* 验证是否渠道通知
|
||||||
|
*
|
||||||
* @param notifyData 通知数据
|
* @param notifyData 通知数据
|
||||||
* @return 默认是 true
|
* @return 默认是 true
|
||||||
*/
|
*/
|
||||||
default boolean verifyNotifyData(PayNotifyDataDTO notifyData){
|
default boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @芋艿:后续改成非 default,避免不知道去实现
|
||||||
/**
|
/**
|
||||||
* 是否退款通知
|
* 判断是否为退款通知
|
||||||
|
*
|
||||||
* @param notifyData 通知数据
|
* @param notifyData 通知数据
|
||||||
* @return 默认是 false
|
* @return 默认是 false
|
||||||
*/
|
*/
|
||||||
default boolean isRefundNotify(PayNotifyDataDTO notifyData){
|
default boolean isRefundNotify(PayNotifyDataDTO notifyData){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,27 @@ package cn.iocoder.yudao.userserver.modules.pay.controller.order;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService;
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
|
||||||
import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitReqVO;
|
import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitReqVO;
|
||||||
import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitRespVO;
|
import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitRespVO;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||||
|
|
||||||
@ -35,11 +35,11 @@ public class PayOrderController {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderCoreService payOrderCoreService;
|
private PayOrderCoreService payOrderCoreService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayRefundCoreService payRefundCoreService;
|
private PayRefundCoreService payRefundCoreService;
|
||||||
|
|
||||||
@Resource PayCommonCoreService commonCoreService;
|
@Resource
|
||||||
|
private PayClientFactory payClientFactory;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/submit")
|
@PostMapping("/submit")
|
||||||
@ -81,11 +81,12 @@ public class PayOrderController {
|
|||||||
public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){
|
public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){
|
||||||
//TODO 可以根据渠道和 app_id 返回不同的页面
|
//TODO 可以根据渠道和 app_id 返回不同的页面
|
||||||
log.info("app_id is {}", params.get("app_id"));
|
log.info("app_id is {}", params.get("app_id"));
|
||||||
return String.format("渠道[%s]支付成功", String.valueOf(channelId));
|
return String.format("渠道[%s]支付成功", channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一的渠道支付回调,支付宝的退款回调
|
* 统一的渠道支付回调,支付宝的退款回调
|
||||||
|
*
|
||||||
* @param channelId 渠道编号
|
* @param channelId 渠道编号
|
||||||
* @param params form 参数
|
* @param params form 参数
|
||||||
* @param originData http request body
|
* @param originData http request body
|
||||||
@ -94,20 +95,27 @@ public class PayOrderController {
|
|||||||
@PostMapping(value = "/notify/{channelId}")
|
@PostMapping(value = "/notify/{channelId}")
|
||||||
@ApiOperation("渠道统一的支付成功,或退款成功 通知url")
|
@ApiOperation("渠道统一的支付成功,或退款成功 通知url")
|
||||||
public String notifyChannelPay(@PathVariable("channelId") Long channelId,
|
public String notifyChannelPay(@PathVariable("channelId") Long channelId,
|
||||||
@RequestParam Map<String, String> params,
|
@RequestParam Map<String, String> params,
|
||||||
@RequestBody String originData) throws Exception {
|
@RequestBody String originData) throws Exception {
|
||||||
//校验是否是渠道回调
|
// 校验支付渠道是否存在
|
||||||
commonCoreService.verifyNotifyData(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
|
PayClient payClient = payClientFactory.getPayClient(channelId);
|
||||||
//支付宝退款交易也会触发支付回调接口
|
if (payClient == null) {
|
||||||
//参考 https://opensupport.alipay.com/support/helpcenter/193/201602484851
|
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
||||||
//判断是否为退款通知
|
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||||
if(commonCoreService.isRefundNotify(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build())) {
|
|
||||||
//退款通知
|
|
||||||
payRefundCoreService.notifyPayRefund(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build());
|
|
||||||
}else{
|
|
||||||
//支付通知
|
|
||||||
payOrderCoreService.notifyPayOrder(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 校验通知数据是否合法
|
||||||
|
PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(originData).build();
|
||||||
|
payClient.verifyNotifyData(notifyData);
|
||||||
|
|
||||||
|
// 如果是退款,则发起退款通知
|
||||||
|
if (payClient.isRefundNotify(notifyData)) {
|
||||||
|
payRefundCoreService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果非退款,则发起支付通知
|
||||||
|
payOrderCoreService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public class PayRefundController {
|
|||||||
|
|
||||||
@PostMapping("/refund")
|
@PostMapping("/refund")
|
||||||
@ApiOperation("提交退款订单")
|
@ApiOperation("提交退款订单")
|
||||||
public CommonResult<PayRefundRespVO> refund(@RequestBody PayRefundReqVO reqVO){
|
public CommonResult<PayRefundRespVO> refund(@RequestBody PayRefundReqVO reqVO){
|
||||||
PayRefundReqBO reqBO = PayRefundConvert.INSTANCE.convert(reqVO);
|
PayRefundReqBO reqBO = PayRefundConvert.INSTANCE.convert(reqVO);
|
||||||
reqBO.setUserIp(getClientIP());
|
reqBO.setUserIp(getClientIP());
|
||||||
//TODO 测试暂时模拟生成商户退款订单
|
//TODO 测试暂时模拟生成商户退款订单
|
||||||
@ -40,4 +40,5 @@ public class PayRefundController {
|
|||||||
//reqBO.setMerchantRefundNo("MO202111210814084370000");
|
//reqBO.setMerchantRefundNo("MO202111210814084370000");
|
||||||
return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.refund(reqBO)));
|
return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.refund(reqBO)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user