微信退款
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.czg;
|
package com.czg;
|
||||||
|
|
||||||
import com.czg.dto.req.PayParamsDto;
|
import com.czg.dto.req.PayParamsDto;
|
||||||
|
import com.czg.dto.req.RefundParamsDto;
|
||||||
import com.czg.exception.CzgException;
|
import com.czg.exception.CzgException;
|
||||||
import com.czg.third.alipay.AlipayIsvPayManager;
|
import com.czg.third.alipay.AlipayIsvPayManager;
|
||||||
import com.czg.third.wechat.WechatPayManager;
|
import com.czg.third.wechat.WechatPayManager;
|
||||||
@@ -49,6 +50,32 @@ public class PayManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询订单状态
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> queryOrderStatus(String platform, String orderNo, String subMerchantId) {
|
||||||
|
if (PayCst.Platform.WECHAT.equals(platform)) {
|
||||||
|
return WechatPayManager.queryOrder(null, orderNo, subMerchantId);
|
||||||
|
} else if (PayCst.Platform.ALIPAY.equals(platform)) {
|
||||||
|
return AlipayIsvPayManager.queryOrder(null, orderNo, subMerchantId);
|
||||||
|
} else {
|
||||||
|
throw new CzgException("不支持的支付平台");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> refund(String platform, RefundParamsDto paramsDto) {
|
||||||
|
if (PayCst.Platform.WECHAT.equals(platform)) {
|
||||||
|
return WechatPayManager.refundOrder(null, paramsDto);
|
||||||
|
} else if (PayCst.Platform.ALIPAY.equals(platform)) {
|
||||||
|
return AlipayIsvPayManager.refundOrder(null, paramsDto);
|
||||||
|
} else {
|
||||||
|
throw new CzgException("不支持的支付平台");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// jsapiPay(new PayParamsDto()
|
// jsapiPay(new PayParamsDto()
|
||||||
// .setPlatform(PayCst.Platform.ALIPAY)
|
// .setPlatform(PayCst.Platform.ALIPAY)
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.czg.dto.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款参数
|
||||||
|
* @author yjjie
|
||||||
|
* @date 2026/1/14 11:37
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class RefundParamsDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 平台
|
||||||
|
* {@link com.czg.PayCst.Platform}
|
||||||
|
*/
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 订单号
|
||||||
|
*/
|
||||||
|
private String orderNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 退款单号
|
||||||
|
*/
|
||||||
|
private String refundOrderNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 退款金额
|
||||||
|
*/
|
||||||
|
private Long refundAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 订单原金额
|
||||||
|
*/
|
||||||
|
private Long orderAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 退款原因
|
||||||
|
*/
|
||||||
|
private String refundReason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【必填】
|
||||||
|
* 退款回调地址
|
||||||
|
*/
|
||||||
|
private String refundNotifyUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【选填】
|
||||||
|
* 微信商户号
|
||||||
|
*/
|
||||||
|
private String merchantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【选填】
|
||||||
|
* 支付宝授权信息
|
||||||
|
*/
|
||||||
|
private String alipayAuthInfo;
|
||||||
|
}
|
||||||
@@ -9,9 +9,9 @@ import com.alipay.v3.model.ExtendParams;
|
|||||||
import com.alipay.v3.util.model.CustomizedParams;
|
import com.alipay.v3.util.model.CustomizedParams;
|
||||||
import com.czg.PayCst;
|
import com.czg.PayCst;
|
||||||
import com.czg.dto.req.PayParamsDto;
|
import com.czg.dto.req.PayParamsDto;
|
||||||
|
import com.czg.dto.req.RefundParamsDto;
|
||||||
import com.czg.exception.CzgException;
|
import com.czg.exception.CzgException;
|
||||||
import com.czg.third.alipay.dto.config.AlipayConfigDto;
|
import com.czg.third.alipay.dto.config.AlipayConfigDto;
|
||||||
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -27,6 +27,7 @@ public class AlipayIsvPayManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* H5支付
|
* H5支付
|
||||||
|
*
|
||||||
* @param configDto 配置
|
* @param configDto 配置
|
||||||
* @param paramsDto 参数
|
* @param paramsDto 参数
|
||||||
*/
|
*/
|
||||||
@@ -64,6 +65,7 @@ public class AlipayIsvPayManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 条码支付
|
* 条码支付
|
||||||
|
*
|
||||||
* @param configDto 配置
|
* @param configDto 配置
|
||||||
* @param paramsDto 参数
|
* @param paramsDto 参数
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +86,11 @@ public class AlipayIsvPayManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Object> queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) {
|
public static Map<String, Object> queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> refundOrder(AlipayConfigDto configDto, RefundParamsDto paramsDto) {
|
||||||
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.czg.PayCst;
|
||||||
import com.czg.dto.req.PayParamsDto;
|
import com.czg.dto.req.PayParamsDto;
|
||||||
|
import com.czg.dto.req.RefundParamsDto;
|
||||||
import com.czg.exception.CzgException;
|
import com.czg.exception.CzgException;
|
||||||
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
|
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
|
||||||
import com.wechat.pay.java.core.Config;
|
import com.wechat.pay.java.core.Config;
|
||||||
import com.wechat.pay.java.core.cipher.Signer;
|
import com.wechat.pay.java.core.cipher.Signer;
|
||||||
import com.wechat.pay.java.core.util.NonceUtil;
|
import com.wechat.pay.java.core.util.NonceUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.apache.bcel.generic.RET;
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.DocumentHelper;
|
import org.dom4j.DocumentHelper;
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
@@ -99,6 +102,7 @@ public class WechatPayManager {
|
|||||||
/**
|
/**
|
||||||
* 条码支付
|
* 条码支付
|
||||||
* 用户付款码规则:18位纯数字,前缀以10、11、12、13、14、15开头
|
* 用户付款码规则:18位纯数字,前缀以10、11、12、13、14、15开头
|
||||||
|
*
|
||||||
* @param configDto 配置
|
* @param configDto 配置
|
||||||
* @param paramsDto 参数
|
* @param paramsDto 参数
|
||||||
*/
|
*/
|
||||||
@@ -197,16 +201,17 @@ public class WechatPayManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询订单
|
* 查询订单
|
||||||
* @param configDto 配置
|
*
|
||||||
* @param orderNo 订单号
|
* @param configDto 配置
|
||||||
|
* @param orderNo 订单号
|
||||||
* @param subMerchantId 子商户号
|
* @param subMerchantId 子商户号
|
||||||
* SUCCESS:支付成功
|
* SUCCESS:支付成功
|
||||||
* REFUND:转入退款
|
* REFUND:转入退款
|
||||||
* NOTPAY:未支付
|
* NOTPAY:未支付
|
||||||
* CLOSED:已关闭
|
* CLOSED:已关闭
|
||||||
* REVOKED:已撤销(仅付款码支付会返回)
|
* REVOKED:已撤销(仅付款码支付会返回)
|
||||||
* USERPAYING:用户支付中(仅付款码支付会返回)
|
* USERPAYING:用户支付中(仅付款码支付会返回)
|
||||||
* PAYERROR:支付失败(仅付款码支付会返回)
|
* PAYERROR:支付失败(仅付款码支付会返回)
|
||||||
*/
|
*/
|
||||||
public static Map<String, Object> queryOrder(WechatPayConfigDto configDto, String orderNo, String subMerchantId) {
|
public static Map<String, Object> queryOrder(WechatPayConfigDto configDto, String orderNo, String subMerchantId) {
|
||||||
try {
|
try {
|
||||||
@@ -242,8 +247,81 @@ public class WechatPayManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款
|
||||||
|
*
|
||||||
|
* @param configDto 配置
|
||||||
|
* @param paramsDto 参数
|
||||||
|
* SUCCESS: 退款成功
|
||||||
|
* CLOSED: 退款关闭
|
||||||
|
* PROCESSING: 退款处理中
|
||||||
|
* ABNORMAL: 退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往服务商平台-交易中心,手动处理此笔退款
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> refundOrder(WechatPayConfigDto configDto, RefundParamsDto paramsDto) {
|
||||||
|
try {
|
||||||
|
if (configDto == null) {
|
||||||
|
configDto = WechatPayConfigDto.getDefaultConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject refundParam = new JSONObject();
|
||||||
|
refundParam.put("sub_mchid", paramsDto.getMerchantId());
|
||||||
|
refundParam.put("out_trade_no", paramsDto.getOrderNo());
|
||||||
|
refundParam.put("out_refund_no", paramsDto.getRefundOrderNo());
|
||||||
|
refundParam.put("reason", paramsDto.getRefundReason());
|
||||||
|
refundParam.put("notify_url", paramsDto.getRefundNotifyUrl());
|
||||||
|
|
||||||
|
JSONObject amount = new JSONObject();
|
||||||
|
amount.put("total", paramsDto.getOrderAmount());
|
||||||
|
amount.put("refund", paramsDto.getRefundAmount());
|
||||||
|
amount.put("currency", "CNY");
|
||||||
|
refundParam.put("amount", amount);
|
||||||
|
|
||||||
|
String resp = WechatReqUtils.postReq(configDto, "/v3/refund/domestic/refunds", refundParam.toJSONString());
|
||||||
|
log.info("微信退款,订单号:{}, 响应:{}", paramsDto.getOrderNo(), resp);
|
||||||
|
|
||||||
|
JSONObject object = JSONObject.parseObject(resp);
|
||||||
|
|
||||||
|
JSONObject res = new JSONObject();
|
||||||
|
res.put("mchRefundNo", object.getString("out_refund_no"));
|
||||||
|
res.put("refundOrderId", object.getString("refund_id"));
|
||||||
|
res.put("oriPayOrderId", object.getString("out_trade_no"));
|
||||||
|
res.put("mercNo", paramsDto.getMerchantId());
|
||||||
|
res.put("refundReason", paramsDto.getRefundReason());
|
||||||
|
res.put("payType", PayCst.Platform.WECHAT);
|
||||||
|
res.put("refundTime", object.getString("success_time"));
|
||||||
|
switch (object.getString("status")) {
|
||||||
|
case "SUCCESS":
|
||||||
|
res.put("status", "SUCCESS");
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
res.put("status", "CLOSED");
|
||||||
|
break;
|
||||||
|
case "PROCESSING":
|
||||||
|
res.put("status", "ING");
|
||||||
|
break;
|
||||||
|
case "ABNORMAL":
|
||||||
|
res.put("status", "INIT");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res.put("status", "FAIL");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
JSONObject resAmount = object.getJSONObject("amount");
|
||||||
|
if (resAmount != null) {
|
||||||
|
res.put("refundAmt", resAmount.getLong("refund"));
|
||||||
|
res.put("oriAmount", resAmount.getLong("total"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("微信退款异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
|
||||||
|
throw new CzgException("微信退款异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将String转换为InputStream
|
* 将String转换为InputStream
|
||||||
|
*
|
||||||
* @param str 待转换的字符串
|
* @param str 待转换的字符串
|
||||||
* @return 转换后的InputStream
|
* @return 转换后的InputStream
|
||||||
*/
|
*/
|
||||||
@@ -288,7 +366,16 @@ public class WechatPayManager {
|
|||||||
// .setClientIp("127.0.0.1")
|
// .setClientIp("127.0.0.1")
|
||||||
// .setBarCode("130013153082460022"));
|
// .setBarCode("130013153082460022"));
|
||||||
|
|
||||||
Map<String, Object> sss1 = queryOrder(null, "sa101293120sss1", "1738216504");
|
// Map<String, Object> sss1 = queryOrder(null, "sa101293120sss1", "1738216504");
|
||||||
System.out.println(sss1);
|
// System.out.println(sss1);
|
||||||
|
|
||||||
|
refundOrder(null, new RefundParamsDto()
|
||||||
|
.setMerchantId("1738216504")
|
||||||
|
.setOrderNo("sa101293120sss1")
|
||||||
|
.setRefundOrderNo("sa101293120sss1")
|
||||||
|
.setOrderAmount(1L)
|
||||||
|
.setRefundAmount(1L)
|
||||||
|
.setRefundReason("测试")
|
||||||
|
.setRefundNotifyUrl("https://www.baidu.com"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user