提交 21c4dadf authored 作者: hzh's avatar hzh

微信退款功能部分实现

上级 df38e8f4
...@@ -53,5 +53,10 @@ public class WechatPayConfiguration { ...@@ -53,5 +53,10 @@ public class WechatPayConfiguration {
* 回调函数的接口路径 * 回调函数的接口路径
*/ */
private String notify; private String notify;
/**
* 退款回调函数的接口路径
*/
private String refundNotify;
} }
package org.dromara.common.pay.domain;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author hzh
* @date 2024-12-31
* @desc jsapi退款回调模型
**/
@Data
@Accessors(chain = true)
public class JsapiRefundNotifyModel {
}
...@@ -3,6 +3,7 @@ package org.dromara.common.pay.service; ...@@ -3,6 +3,7 @@ package org.dromara.common.pay.service;
import com.ijpay.wxpay.model.v3.RefundModel; import com.ijpay.wxpay.model.v3.RefundModel;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel; import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import org.dromara.common.pay.domain.JsapiNotifyModel; import org.dromara.common.pay.domain.JsapiNotifyModel;
import org.dromara.common.pay.domain.JsapiRefundNotifyModel;
/** /**
* @author wenhe * @author wenhe
...@@ -55,13 +56,32 @@ public interface IWxPayService { ...@@ -55,13 +56,32 @@ public interface IWxPayService {
*/ */
JsapiNotifyModel notify(String timestamp, String nonce, String serialNo, String signature, String result); JsapiNotifyModel notify(String timestamp, String nonce, String serialNo, String signature, String result);
/**
* 退款回调
*
* @param timestamp 时间搓
* @param nonce nonce
* @param serialNo serialNo
* @param signature 签名
* @param result 支付通知密文
* @return 退款通知明文
*/
JsapiRefundNotifyModel refundNotify(String timestamp, String nonce, String serialNo, String signature, String result);
/** /**
* 退款 * 退款
*
* @param model model * @param model model
* @return 退款结果 * @return 退款结果
* @throws Exception 异常 * @throws Exception 异常
*/ */
org.dromara.common.pay.domain.RefundModel refund(RefundModel model) throws Exception; org.dromara.common.pay.domain.RefundModel refund(RefundModel model) throws Exception;
/**
* 退款查询
*
* @param outRefundNo 退款单号
* @return 退款结果
*/
JsapiRefundNotifyModel refundQuery(String outRefundNo);
} }
...@@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; ...@@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dromara.common.pay.config.WechatPayConfiguration; import org.dromara.common.pay.config.WechatPayConfiguration;
import org.dromara.common.pay.domain.JsapiNotifyModel; import org.dromara.common.pay.domain.JsapiNotifyModel;
import org.dromara.common.pay.domain.JsapiRefundNotifyModel;
import org.dromara.common.pay.service.IWxPayService; import org.dromara.common.pay.service.IWxPayService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -228,6 +229,29 @@ public class WxPayServiceImpl implements IWxPayService { ...@@ -228,6 +229,29 @@ public class WxPayServiceImpl implements IWxPayService {
} }
} }
@Override
public JsapiRefundNotifyModel refundNotify(String timestamp, String nonce, String serialNo, String signature, String result) {
log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
log.info("退款通知密文 {}", result);
try {
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
String plainText = WxPayKit.verifyNotify(
serialNo,
result,
signature,
nonce,
timestamp,
config.getApiKey3(),
config.getPlatformCertPath()
);
log.info("退款通知明文 {}", plainText);
return JSON.parseObject(plainText, JsapiRefundNotifyModel.class);
} catch (Exception e) {
log.error("系统异常", e);
throw new RuntimeException("系统异常!");
}
}
@Override @Override
public JsapiNotifyModel query(String outTradeNo) { public JsapiNotifyModel query(String outTradeNo) {
try { try {
...@@ -262,6 +286,37 @@ public class WxPayServiceImpl implements IWxPayService { ...@@ -262,6 +286,37 @@ public class WxPayServiceImpl implements IWxPayService {
} }
} }
@Override
public JsapiRefundNotifyModel refundQuery(String outRefundNo) {
try {
log.info("退款订单查询,退款单号:{}", outRefundNo);
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
String.format(BasePayApiEnum.REFUND_QUERY_BY_OUT_REFUND_NO.toString(), outRefundNo),
config.getMchId(),
getSerialNumber(),
null,
config.getKeyPath(),
Collections.emptyMap());
log.info("查询退款单:{} 查询响应 {}", outRefundNo, response);
if (response.getStatus() == IJPayConstants.CODE_200) {
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, config.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
//验签成功
if (verifySignature) {
JSONObject result = JSONUtil.parseObj(response.getBody());
return JSON.parseObject(JSON.toJSONString(result), JsapiRefundNotifyModel.class);
}
}
throw new RuntimeException("退款单:" + outRefundNo + "查询失败!");
} catch (Exception e) {
log.error("系统异常", e);
throw new RuntimeException("退款单:" + outRefundNo + "查询失败!");
}
}
@Override @Override
public Boolean close(String outTradeNo) { public Boolean close(String outTradeNo) {
try { try {
...@@ -291,7 +346,7 @@ public class WxPayServiceImpl implements IWxPayService { ...@@ -291,7 +346,7 @@ public class WxPayServiceImpl implements IWxPayService {
@Override @Override
public org.dromara.common.pay.domain.RefundModel refund(RefundModel model) throws Exception { public org.dromara.common.pay.domain.RefundModel refund(RefundModel model) throws Exception {
model.setNotify_url(config.getNotify()); model.setNotify_url(config.getDomain() + config.getRefundNotify());
log.info("统一退款参数 {}", JSONUtil.toJsonStr(model)); log.info("统一退款参数 {}", JSONUtil.toJsonStr(model));
IJPayHttpResponse response = WxPayApi.v3( IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST, RequestMethodEnum.POST,
......
...@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -50,20 +51,46 @@ public class OrderController extends BaseController { ...@@ -50,20 +51,46 @@ public class OrderController extends BaseController {
Map<String, String> map = new HashMap<>(12); Map<String, String> map = new HashMap<>(12);
try { try {
log.info("微信回调开始"); log.info("微信支付回调开始");
//获取请求参数
ImmutableMap<String, String> builder = getParams();
boolean result = orderPayService.notify(JSON.toJSONString(new HashMap<>(builder)));
//设置响应参数
setResponse(result, response, map);
} catch (Exception e) {
log.error("系统异常", e);
}
}
/**
* 获取请求参数
*
* @return ImmutableMap<String, String> 请求参数
*/
private ImmutableMap<String, String> getParams() {
jakarta.servlet.http.HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); jakarta.servlet.http.HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
ImmutableMap<String, String> builder = ImmutableMap.<String, String>builder() return ImmutableMap.<String, String>builder()
.put("timestamp", request.getHeader("Wechatpay-Timestamp")) .put("timestamp", request.getHeader("Wechatpay-Timestamp"))
.put("nonce", request.getHeader("Wechatpay-Nonce")) .put("nonce", request.getHeader("Wechatpay-Nonce"))
.put("serialNo", request.getHeader("Wechatpay-Serial")) .put("serialNo", request.getHeader("Wechatpay-Serial"))
.put("signature", request.getHeader("Wechatpay-Signature")) .put("signature", request.getHeader("Wechatpay-Signature"))
.put("result", CustomHttpKit.readData(request)) .put("result", CustomHttpKit.readData(request))
.build(); .build();
}
boolean result = orderPayService.notify(JSON.toJSONString(new HashMap<>(builder))); /**
* 设置响应参数
*
* @param result result
* @param response response
* @param map map
* @throws IOException IOException 异常信息
*/
private void setResponse(boolean result, HttpServletResponse response, Map<String, String> map) throws IOException {
if (result) { if (result) {
response.setStatus(200); response.setStatus(200);
map.put("code", "SUCCESS"); map.put("code", "SUCCESS");
...@@ -77,6 +104,25 @@ public class OrderController extends BaseController { ...@@ -77,6 +104,25 @@ public class OrderController extends BaseController {
response.setHeader("Content-type", ContentType.JSON.toString()); response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8)); response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer(); response.flushBuffer();
}
/**
* 退款函数
*
* @param response response
*/
@RequestMapping(value = "/v3/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
public void refundNotify(HttpServletResponse response) {
Map<String, String> map = new HashMap<>(12);
try {
log.info("微信退款回调开始");
//获取请求参数
ImmutableMap<String, String> builder = getParams();
boolean result = orderPayService.refundNotify(JSON.toJSONString(new HashMap<>(builder)));
setResponse(result, response, map);
} catch (Exception e) { } catch (Exception e) {
log.error("系统异常", e); log.error("系统异常", e);
} }
......
package org.dromara.order.service; package org.dromara.order.service;
import org.dromara.common.pay.domain.JsapiNotifyModel; import org.dromara.common.pay.domain.JsapiNotifyModel;
import org.dromara.common.pay.domain.JsapiRefundNotifyModel;
/** /**
* @author hzh * @author hzh
...@@ -16,11 +17,27 @@ public interface IOrderPayService { ...@@ -16,11 +17,27 @@ public interface IOrderPayService {
*/ */
boolean notify(String body); boolean notify(String body);
/**
* 退款回调
*
* @param body 回调参数
* @return 回调结果
*/
boolean refundNotify(String body);
/** /**
* 微信支付查询 * 微信支付查询
*
* @param outTradeNo 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。 * @param outTradeNo 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
* @return 支付结果 * @return 支付结果
*/ */
JsapiNotifyModel query(String outTradeNo); JsapiNotifyModel query(String outTradeNo);
/**
* 退款查询
* @param outRefundNo 商户申请退款时传入的商户系统内部退款单号。
* @return 退款结果
*/
JsapiRefundNotifyModel refundQuery(String outRefundNo);
} }
...@@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; ...@@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.pay.domain.JsapiNotifyModel; import org.dromara.common.pay.domain.JsapiNotifyModel;
import org.dromara.common.pay.domain.JsapiRefundNotifyModel;
import org.dromara.common.pay.service.IWxPayService; import org.dromara.common.pay.service.IWxPayService;
import org.dromara.order.api.enums.OrderStatus; import org.dromara.order.api.enums.OrderStatus;
import org.dromara.order.constant.WechatTradeState; import org.dromara.order.constant.WechatTradeState;
...@@ -70,6 +71,40 @@ public class WeChatOrderPayServiceImpl implements IOrderPayService { ...@@ -70,6 +71,40 @@ public class WeChatOrderPayServiceImpl implements IOrderPayService {
} }
} }
@GlobalTransactional(rollbackFor = Exception.class)
@Override
public boolean refundNotify(String body) {
log.info("微信退款回调参数:{}", body);
JSONObject bodyJson = JSONObject.parseObject(body);
try {
JsapiRefundNotifyModel model = wxPayService.refundNotify(
bodyJson.getString("timestamp"),
bodyJson.getString("nonce"),
bodyJson.getString("serialNo"),
bodyJson.getString("signature"),
bodyJson.getString("result")
);
//处理订单
dealRefundOrder(model);
return true;
} catch (Exception e) {
log.error("系统异常", e);
return false;
}
}
/**
* 处理退款订单
*
* @param model 退款回调参数
*/
private void dealRefundOrder(JsapiRefundNotifyModel model) {
}
@GlobalTransactional(rollbackFor = Exception.class) @GlobalTransactional(rollbackFor = Exception.class)
@Override @Override
public JsapiNotifyModel query(String outTradeNo) { public JsapiNotifyModel query(String outTradeNo) {
...@@ -79,6 +114,15 @@ public class WeChatOrderPayServiceImpl implements IOrderPayService { ...@@ -79,6 +114,15 @@ public class WeChatOrderPayServiceImpl implements IOrderPayService {
return model; return model;
} }
@GlobalTransactional(rollbackFor = Exception.class)
@Override
public JsapiRefundNotifyModel refundQuery(String outRefundNo) {
JsapiRefundNotifyModel model = wxPayService.refundQuery(outRefundNo);
//处理退款订单
dealRefundOrder(model);
return model;
}
private void dealOrder(JsapiNotifyModel model) { private void dealOrder(JsapiNotifyModel model) {
//支付订单号 //支付订单号
String orderPayNo = model.getOut_trade_no(); String orderPayNo = model.getOut_trade_no();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论