退款提现

This commit is contained in:
zengtao01
2024-07-26 14:33:43 +08:00
parent 82eb8b56ce
commit 1de2f8a6b7
41 changed files with 1038 additions and 119 deletions

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -125,4 +127,13 @@ public interface PayClient {
PayDivideRespDto unifiedDivideFreeze(PayDivideUnifiedDto reqDTO);
/**
* 分账回退
*
* @param reqDTO 分账参数
* @return 分账
*/
PayDivideBackRespDto unifiedDivideback(PayDivideBackUnifiedDto reqDTO);
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.divide;
import lombok.Data;
/**
* @author zt
* @description <description class purpose>
* @since 2024/7/17
*/
@Data
public class PayDivideBackRespDto {
private String subMchId;
private String orderId;
private String outOrderNo;
private String outReturnNo;
private String returnId;
private String returnMchid;
private Long amount;
private String description;
private String result;
private String failReason;
private String createTime;
private String finishTime;
private String channelErrorCode;
/**
* 调用渠道报错时,错误信息
*/
private String channelErrorMsg;
/**
* 原始的异步通知结果
*/
private Object rawData;
/**
* 创建【FAILURE】状态的退款返回
*/
public static PayDivideBackRespDto failureOf(String channelErrorCode, String channelErrorMsg,
String transactionId, Object rawData) {
PayDivideBackRespDto respDTO = new PayDivideBackRespDto();
//respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus();
respDTO.channelErrorCode = channelErrorCode;
respDTO.channelErrorMsg = channelErrorMsg;
// 相对通用的字段
respDTO.orderId = transactionId;
respDTO.rawData = rawData;
return respDTO;
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.divide;
import lombok.Data;
/**
* @author zt
* @description <description class purpose>
* @since 2024/7/17
*/
@Data
public class PayDivideBackUnifiedDto {
/**
* 应用ID
*/
private String appid;
/**
* 微信分账单号
*/
private String orderId;
/**
* 商户分账单号
*/
private String outOrderNo;
/**
* 商户回退单号
*/
private String outReturnNo;
/**
* 回退商户号
*/
private String returnMchid;
/**
* 回退金额
*/
private Long amount;
/**
* 回退描述
*/
private String description;
}

View File

@ -28,9 +28,12 @@ public class PayRefundUnifiedReqDTO {
*
* 对应 PayOrderExtensionDO 的 no 字段
*/
@NotEmpty(message = "外部订单编号不能为空")
//@NotEmpty(message = "外部订单编号不能为空")
private String outTradeNo;
@NotEmpty(message = "微信订单编号不能为空")
private String transactionId;
/**
* 外部退款号
*

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -313,4 +315,26 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
}
protected abstract PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO)
throws Throwable;
@Override
public PayDivideBackRespDto unifiedDivideback(PayDivideBackUnifiedDto reqDTO) {
ValidationUtils.validate(reqDTO);
// 执行统一下单
PayDivideBackRespDto resp;
try {
resp = doUnifiedDivideback(reqDTO);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
// 系统异常,则包装成 PayException 异常抛出
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
getId(), toJsonString(reqDTO), ex);
throw buildPayException(ex);
}
return resp;
}
protected abstract PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO)
throws Throwable;
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -73,4 +75,9 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -99,4 +101,9 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -83,4 +85,9 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -80,4 +82,9 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -73,4 +75,9 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.mock;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -94,4 +96,9 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
return null;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -8,6 +8,8 @@ import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideBackUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
@ -23,8 +25,10 @@ import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReturnV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingUnfreezeV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingReturnV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingUnfreezeV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
@ -314,7 +318,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
WxPayRefundV3Request request = new WxPayRefundV3Request()
.setOutTradeNo(reqDTO.getOutTradeNo())
.setTransactionId(reqDTO.getTransactionId())
.setOutRefundNo(reqDTO.getOutRefundNo())
.setAmount(new WxPayRefundV3Request.Amount().setRefund(reqDTO.getRefundPrice())
.setTotal(reqDTO.getPayPrice()).setCurrency("CNY"))
@ -610,4 +614,44 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
BeanUtil.copyProperties(response,payDivideRespDto);
return payDivideRespDto;
}
@Override
protected PayDivideBackRespDto doUnifiedDivideback(PayDivideBackUnifiedDto reqDTO) throws Throwable {
try {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doUnifiedDividebackV2(reqDTO);
case WxPayClientConfig.API_VERSION_V3:
return doUnifiedDividebackV3(reqDTO);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
} catch (WxPayException e) {
String errorCode = getErrorCode(e);
String errorMessage = getErrorMessage(e);
return PayDivideBackRespDto.failureOf(errorCode, errorMessage,
reqDTO.getOrderId(), e.getXmlString());
}
}
private PayDivideBackRespDto doUnifiedDividebackV2(PayDivideBackUnifiedDto reqDTO) throws Throwable {
throw new UnsupportedOperationException("待实现");
}
private PayDivideBackRespDto doUnifiedDividebackV3(PayDivideBackUnifiedDto reqDTO) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
ProfitSharingReturnV3Request request = new ProfitSharingReturnV3Request();
request.setOrderId(reqDTO.getOrderId());
request.setOutOrderNo(reqDTO.getOutOrderNo());
request.setOutReturnNo(reqDTO.getOutReturnNo());
request.setReturnMchid(reqDTO.getReturnMchid());
request.setAmount(reqDTO.getAmount());
request.setDescription(reqDTO.getDescription());
// 2.1 执行请求
ProfitSharingReturnV3Result response = client.getProfitSharingService().profitSharingReturnV3(request);
PayDivideBackRespDto payDivideRespDto = new PayDivideBackRespDto();
BeanUtil.copyProperties(response,payDivideRespDto);
return payDivideRespDto;
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.pay.core.enums.divide;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 渠道的退款状态枚举
*
* @author jason
*/
@Getter
@AllArgsConstructor
public enum PayDivideRefundStatusRespEnum {
PROCESSING("10", "退款处理中"),
SUCCESS("20", "退款成功"),
CLOSED("30", "退款关闭"),
ABNORMAL("40", "退款异常"),
;
private final String status;
private final String name;
}

View File

@ -16,6 +16,8 @@ public enum PayDivideStatusRespEnum {
PROGRESS("10", "分账进行中"),
COMPLETE("20", "分账完成"),
FINISH("30", "分账结束"),
CASH("40", "提现"),
;
private final String status;