支付宝退款申请通知
parent
444ba79822
commit
dfde260ebb
|
@ -1,12 +1,7 @@
|
||||||
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
|
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,5 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
||||||
|
|
||||||
|
default PayRefundDO selectByReqNo(String reqNo) {
|
||||||
|
return selectOne("req_no", reqNo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ public interface PayErrorCodeCoreConstants {
|
||||||
ErrorCode PAY_REFUND_AMOUNT_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
ErrorCode PAY_REFUND_AMOUNT_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
|
||||||
ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
|
ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
|
||||||
ErrorCode PAY_REFUND_CHN_ORDER_NO_IS_NULL = new ErrorCode(1007006002, "该订单的渠道订单为空");
|
ErrorCode PAY_REFUND_CHN_ORDER_NO_IS_NULL = new ErrorCode(1007006002, "该订单的渠道订单为空");
|
||||||
ErrorCode PAY_REFUND_POST_HANDLER_NOT_FOUND = new ErrorCode(1007006002, "未找到对应的退款后置处理类");
|
ErrorCode PAY_REFUND_POST_HANDLER_NOT_FOUND = new ErrorCode(1007006003, "未找到对应的退款后置处理类");
|
||||||
|
ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
|
||||||
// TODO @aquan:下面还两个要合并上去哈。另外一般中英文之间要有空格。例如说, 新建一个 order 数据;这样可读性更好。
|
// TODO @aquan:下面还两个要合并上去哈。另外一般中英文之间要有空格。例如说, 新建一个 order 数据;这样可读性更好。
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.order;
|
||||||
|
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.bo.PayRefundReqBO;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.bo.PayRefundReqBO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.bo.PayRefundRespBO;
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.bo.PayRefundRespBO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款单 Core Service
|
* 退款单 Core Service
|
||||||
|
@ -17,4 +18,17 @@ public interface PayRefundCoreService {
|
||||||
* @return 退款申请返回信息
|
* @return 退款申请返回信息
|
||||||
*/
|
*/
|
||||||
PayRefundRespBO refund(PayRefundReqBO reqDTO);
|
PayRefundRespBO refund(PayRefundReqBO reqDTO);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道的退款通知
|
||||||
|
* @param channelId 渠道编号
|
||||||
|
* @param channelCode 渠道编码
|
||||||
|
* @param notifyData 通知数据
|
||||||
|
* @throws Exception 退款通知异常
|
||||||
|
*/
|
||||||
|
void notifyPayRefund(Long channelId, String channelCode, PayNotifyDataDTO notifyData) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,11 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensionCoreMapper;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensionCoreMapper;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundMapper;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundMapper;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum;
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
|
||||||
|
@ -24,8 +28,10 @@ import cn.iocoder.yudao.coreservice.modules.pay.service.order.bo.PayRefundRespBO
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils;
|
import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
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.PayClientFactory;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -66,6 +72,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
||||||
@Resource
|
@Resource
|
||||||
private List<PayRefundChannelPostHandler> handlerList;
|
private List<PayRefundChannelPostHandler> handlerList;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayNotifyCoreService payNotifyCoreService;
|
||||||
|
|
||||||
|
|
||||||
private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandler = new EnumMap<>(PayChannelRespEnum.class);
|
private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandler = new EnumMap<>(PayChannelRespEnum.class);
|
||||||
|
|
||||||
|
@ -84,7 +93,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PayRefundRespBO refund(PayRefundReqBO reqBO) {
|
public PayRefundRespBO refund(PayRefundReqBO reqBO) {
|
||||||
|
@ -173,6 +181,64 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyPayRefund(Long channelId, String channelCode, PayNotifyDataDTO notifyData) {
|
||||||
|
log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
|
||||||
|
// 校验支付渠道是否有效
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
//解析渠道退款通知数据, 统一处理
|
||||||
|
PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData);
|
||||||
|
|
||||||
|
if(Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){
|
||||||
|
//退款成功。 支付宝只有退款成功才会发通知
|
||||||
|
PayRefundDO refundDO = payRefundMapper.selectByReqNo(refundNotify.getReqNo());
|
||||||
|
if (refundDO == null) {
|
||||||
|
log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());
|
||||||
|
throw exception(PAY_REFUND_NOT_FOUND);
|
||||||
|
}
|
||||||
|
Long refundAmount = refundDO.getRefundAmount();
|
||||||
|
Integer type = refundDO.getType();
|
||||||
|
PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
|
||||||
|
if(PayRefundTypeEnum.ALL.getStatus().equals(type)){
|
||||||
|
orderStatus = PayOrderStatusEnum.CLOSED;
|
||||||
|
}
|
||||||
|
//更新支付订单
|
||||||
|
PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
|
||||||
|
//需更新已退金额
|
||||||
|
Long refundedAmount = payOrderDO.getRefundAmount();
|
||||||
|
PayOrderDO updateOrderDO = new PayOrderDO();
|
||||||
|
updateOrderDO.setId(refundDO.getOrderId())
|
||||||
|
.setRefundAmount(refundedAmount + refundAmount)
|
||||||
|
.setStatus(orderStatus.getStatus())
|
||||||
|
.setRefundStatus(type);
|
||||||
|
payOrderCoreMapper.updateById(updateOrderDO);
|
||||||
|
|
||||||
|
//跟新退款订单
|
||||||
|
PayRefundDO updateRefundDO = new PayRefundDO();
|
||||||
|
updateRefundDO.setId(refundDO.getId())
|
||||||
|
.setSuccessTime(refundNotify.getRefundSuccessTime())
|
||||||
|
.setChannelRefundNo(refundNotify.getChannelOrderNo())
|
||||||
|
.setTradeNo(refundNotify.getTradeNo())
|
||||||
|
.setNotifyTime(new Date())
|
||||||
|
.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
||||||
|
payRefundMapper.updateById(updateRefundDO);
|
||||||
|
|
||||||
|
//插入退款通知记录
|
||||||
|
// TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
|
||||||
|
payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||||
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
|
||||||
|
}else{
|
||||||
|
//TODO 退款失败
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验是否进行退款
|
* 校验是否进行退款
|
||||||
* @param reqBO 退款申请信息
|
* @param reqBO 退款申请信息
|
||||||
|
@ -197,7 +263,5 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
||||||
throw exception(PAY_REFUND_CHN_ORDER_NO_IS_NULL);
|
throw exception(PAY_REFUND_CHN_ORDER_NO_IS_NULL);
|
||||||
}
|
}
|
||||||
//TODO 退款的期限 退款次数的控制
|
//TODO 退款的期限 退款次数的控制
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,4 +42,11 @@ public interface PayClient {
|
||||||
*/
|
*/
|
||||||
PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO);
|
PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析支付退款通知数据
|
||||||
|
* @param notifyData 支付退款通知请求数据
|
||||||
|
* @return 支付退款通知的Notify DTO
|
||||||
|
*/
|
||||||
|
PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单回调,渠道的统一通知请求数据
|
* 支付订单,退款订单回调,渠道的统一通知请求数据
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
@ToString
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package cn.iocoder.yudao.framework.pay.core.client.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从渠道返回数据中解析得到的支付退款通知的Notify DTO
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
@Builder
|
||||||
|
public class PayRefundNotifyDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付渠道编号
|
||||||
|
*/
|
||||||
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易订单号,根据规则生成
|
||||||
|
* 调用支付渠道时,使用该字段作为对接的订单号。
|
||||||
|
* 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no
|
||||||
|
* 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no
|
||||||
|
* 这里对应 pay_extension 里面的 no
|
||||||
|
* 例如说,P202110132239124200055
|
||||||
|
*/
|
||||||
|
private String tradeNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no
|
||||||
|
* https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no
|
||||||
|
* 退款请求号。
|
||||||
|
* 标识一次退款请求,需要保证在交易号下唯一,如需部分退款,则此参数必传。
|
||||||
|
* 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更,
|
||||||
|
* 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
|
||||||
|
* 退款单请求号,根据规则生成
|
||||||
|
*
|
||||||
|
* 例如说,RR202109181134287570000
|
||||||
|
*/
|
||||||
|
private String reqNo;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款是否成功
|
||||||
|
*/
|
||||||
|
private PayNotifyRefundStatusEnum status;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款成功时间
|
||||||
|
*/
|
||||||
|
private Date refundSuccessTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -83,6 +83,12 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||||
|
//TODO 需要实现
|
||||||
|
throw new UnsupportedOperationException("需要实现");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
||||||
//TODO 需要实现
|
//TODO 需要实现
|
||||||
|
|
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.*;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.*;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;
|
||||||
import com.alipay.api.AlipayApiException;
|
import com.alipay.api.AlipayApiException;
|
||||||
import com.alipay.api.AlipayConfig;
|
import com.alipay.api.AlipayConfig;
|
||||||
|
@ -103,7 +104,6 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
||||||
.data(data.getBody()).build();
|
.data(data.getBody()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
|
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
|
||||||
AlipayTradeRefundModel model=new AlipayTradeRefundModel();
|
AlipayTradeRefundModel model=new AlipayTradeRefundModel();
|
||||||
|
@ -119,11 +119,10 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
||||||
AlipayTradeRefundResponse response = client.execute(refundRequest);
|
AlipayTradeRefundResponse response = client.execute(refundRequest);
|
||||||
log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response));
|
log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response));
|
||||||
if (response.isSuccess()) {
|
if (response.isSuccess()) {
|
||||||
//退款成功
|
//退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知,
|
||||||
|
//退款导致触发的异步通知是发送到支付接口中设置的notify_url
|
||||||
//TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?
|
//TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?
|
||||||
respDTO.setRespEnum(PayChannelRespEnum.SYNC_SUCCESS)
|
respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_NOTIFY);
|
||||||
.setChannelRefundNo(response.getTradeNo())
|
|
||||||
.setPayTradeNo(response.getOutTradeNo());
|
|
||||||
}else{
|
}else{
|
||||||
//特殊处理 sub_code ACQ.SYSTEM_ERROR(系统错误), 需要调用重试任务
|
//特殊处理 sub_code ACQ.SYSTEM_ERROR(系统错误), 需要调用重试任务
|
||||||
//沙箱环境返回的貌似是”aop.ACQ.SYSTEM_ERROR“, 用contain
|
//沙箱环境返回的貌似是”aop.ACQ.SYSTEM_ERROR“, 用contain
|
||||||
|
@ -153,12 +152,20 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
||||||
.setChannelErrMsg(e.getErrMsg())
|
.setChannelErrMsg(e.getErrMsg())
|
||||||
.setRespEnum(PayChannelRespEnum.CALL_EXCEPTION);
|
.setRespEnum(PayChannelRespEnum.CALL_EXCEPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
return respDTO;
|
return respDTO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||||
|
Map<String, String> params = notifyData.getParams();
|
||||||
|
PayRefundNotifyDTO notifyDTO = PayRefundNotifyDTO.builder().channelOrderNo(params.get("trade_no"))
|
||||||
|
.tradeNo(params.get("out_trade_no"))
|
||||||
|
.reqNo(params.get("out_biz_no"))
|
||||||
|
.status(PayNotifyRefundStatusEnum.SUCCESS)
|
||||||
|
.refundSuccessTime(DateUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
|
||||||
|
.build();
|
||||||
|
return notifyDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,12 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.data(data.getBody()).build();
|
.data(data.getBody()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||||
|
//TODO 需要实现
|
||||||
|
throw new UnsupportedOperationException("需要实现");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package cn.iocoder.yudao.framework.pay.core.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款通知, 统一的渠道退款状态
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
public enum PayNotifyRefundStatusEnum {
|
||||||
|
/**
|
||||||
|
* 支付宝 中 全额退款 trade_status=TRADE_CLOSED, 部分退款 trade_status=TRADE_SUCCESS
|
||||||
|
* 退款成功
|
||||||
|
*/
|
||||||
|
SUCCESS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付宝退款通知没有这个状态
|
||||||
|
* 退款异常
|
||||||
|
*/
|
||||||
|
ABNORMAL;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ 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.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.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;
|
||||||
|
@ -34,6 +35,9 @@ public class PayOrderController {
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderCoreService payOrderCoreService;
|
private PayOrderCoreService payOrderCoreService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayRefundCoreService payRefundCoreService;
|
||||||
|
|
||||||
@PostMapping("/submit")
|
@PostMapping("/submit")
|
||||||
@ApiOperation("提交支付订单")
|
@ApiOperation("提交支付订单")
|
||||||
// @PreAuthenticated // TODO 暂时不加登陆验证,前端暂时没做好
|
// @PreAuthenticated // TODO 暂时不加登陆验证,前端暂时没做好
|
||||||
|
@ -85,11 +89,21 @@ public class PayOrderController {
|
||||||
public String notifyAliPayWapPayOrder(@PathVariable("channelId") Long channelId,
|
public String notifyAliPayWapPayOrder(@PathVariable("channelId") Long channelId,
|
||||||
@RequestParam Map<String, String> params,
|
@RequestParam Map<String, String> params,
|
||||||
@RequestBody String originData) throws Exception {
|
@RequestBody String originData) throws Exception {
|
||||||
//TODO @jason 校验 是否支付宝调用。 payclient 中加一个校验方法
|
//TODO 校验是否支付宝调用。 payclient 中加一个校验方法
|
||||||
payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), PayNotifyDataDTO.builder().params(params).body(originData).build());
|
//支付宝退款交易也会触发支付回调接口
|
||||||
|
//参考 https://opensupport.alipay.com/support/helpcenter/193/201602484851
|
||||||
|
//判断是否为支付宝的退款交易
|
||||||
|
if(isAliPayRefund(params)) {
|
||||||
|
//退款通知
|
||||||
|
payRefundCoreService.notifyPayRefund(channelId,PayChannelEnum.ALIPAY_WAP.getCode(), PayNotifyDataDTO.builder().params(params).body(originData).build());
|
||||||
|
}else{
|
||||||
|
//支付通知
|
||||||
|
payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), PayNotifyDataDTO.builder().params(params).body(originData).build());
|
||||||
|
}
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E
|
* https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E
|
||||||
* @param channelId 渠道id
|
* @param channelId 渠道id
|
||||||
|
@ -102,6 +116,19 @@ public class PayOrderController {
|
||||||
return "支付成功";
|
return "支付成功";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是支付宝的退款交易
|
||||||
|
* @param params http content-type application/x-www-form-urlencoded 的参数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isAliPayRefund(Map<String, String> params) {
|
||||||
|
if (params.containsKey("refund_fee")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/notify/test")
|
@RequestMapping("/notify/test")
|
||||||
@ApiOperation("通知的测试接口")
|
@ApiOperation("通知的测试接口")
|
||||||
public String notifyTest() {
|
public String notifyTest() {
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class PayRefundController {
|
||||||
reqBO.setUserIp(getClientIP());
|
reqBO.setUserIp(getClientIP());
|
||||||
//TODO 测试暂时模拟生成商户退款订单
|
//TODO 测试暂时模拟生成商户退款订单
|
||||||
reqBO.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo());
|
reqBO.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo());
|
||||||
|
//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