diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/massageController/RefoundController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/massageController/RefoundController.java
new file mode 100644
index 0000000..a372739
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/massageController/RefoundController.java
@@ -0,0 +1,61 @@
+package org.jeecg.modules.api.massageController;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.apiService.WxMiniappPayService;
+import org.jeecg.modules.wxUtils.RefundOrderReq;
+import org.jeecg.modules.wxUtils.Response;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+@Api(tags="退款-退款相关接口")
+@RestController
+@RequestMapping("/massage/refound")
+@Slf4j
+public class RefoundController {
+ @Resource
+ private WxMiniappPayService wxMiniappPayService;
+
+ /**
+ * 退款申请
+ * @param orderId
+ * @return
+ */
+ @ApiOperation(
+ value="退款",
+ notes="退款")
+ @PostMapping("/refund")
+ public Response> refund(@RequestHeader("X-Access-Token") String token, String orderId) {
+ log.info("------微信支付退款------");
+ return wxMiniappPayService.refund(token, orderId);
+ }
+
+// /**
+// * 查询单笔退款(通过商户退款单号)
+// * @param outRefundNo 商户退款单号
+// * @return
+// */
+// @ApiOperation(
+// value="查询单笔退款(通过商户退款单号)",
+// notes="查询单笔退款(通过商户退款单号)")
+// @GetMapping("/queryByOutRefundNo")
+// public Response> queryByOutRefundNo(String outRefundNo) {
+// log.info("------微信支付查询单笔退款------");
+// return wxMiniappPayService.queryByOutRefundNo(outRefundNo);
+// }
+
+ /**
+ * 微信小程序退款回调
+ * @param request
+ * @return
+ * @throws Exception
+ */
+ @PostMapping("/refundNotify")
+ public String refundNotify(HttpServletRequest request) throws Exception {
+ log.info("------微信支付微信小程序退款回调------");
+ return wxMiniappPayService.refundNotify(request);
+ }
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/WxMiniappPayService.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/WxMiniappPayService.java
new file mode 100644
index 0000000..39ab7dd
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/WxMiniappPayService.java
@@ -0,0 +1,29 @@
+package org.jeecg.modules.apiService;
+
+import org.jeecg.modules.wxUtils.RefundOrderReq;
+import org.jeecg.modules.wxUtils.Response;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface WxMiniappPayService {
+ /**
+ * 退款
+ * @param orderId
+ * @return
+ */
+ Response> refund(String token, String orderId);
+
+ /**
+ * 查询单笔退款(通过商户退款单号)
+ * @param outRefundNo 商户退款单号
+ * @return
+ */
+ Response> queryByOutRefundNo(String outRefundNo);
+
+ /**
+ * 微信小程序退款回调
+ * @param request
+ * @return
+ */
+ String refundNotify(HttpServletRequest request);
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/impl/WxMiniappPayServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/impl/WxMiniappPayServiceImpl.java
new file mode 100644
index 0000000..6d7d0d3
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/apiService/impl/WxMiniappPayServiceImpl.java
@@ -0,0 +1,422 @@
+package org.jeecg.modules.apiService.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.exception.HttpException;
+import com.wechat.pay.java.core.exception.MalformedMessageException;
+import com.wechat.pay.java.core.exception.ServiceException;
+import com.wechat.pay.java.core.exception.ValidationException;
+import com.wechat.pay.java.core.notification.NotificationConfig;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
+import com.wechat.pay.java.service.refund.RefundService;
+import com.wechat.pay.java.service.refund.model.*;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.config.shiro.ShiroRealm;
+import org.jeecg.modules.apiService.WxMiniappPayService;
+import org.jeecg.modules.apiUtils.CommonUtils;
+import org.jeecg.modules.hanHaiMember.entity.HanHaiMember;
+import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService;
+import org.jeecg.modules.massageOrder.entity.MassageOrder;
+import org.jeecg.modules.massageOrder.service.IMassageOrderService;
+import org.jeecg.modules.massageRefoundLog.entity.MassageRefoundLog;
+import org.jeecg.modules.massageRefoundLog.service.IMassageRefoundLogService;
+import org.jeecg.modules.wxUtils.HttpServletUtils;
+import org.jeecg.modules.wxUtils.RefundOrderReq;
+import org.jeecg.modules.wxUtils.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class WxMiniappPayServiceImpl implements WxMiniappPayService {
+
+ /**
+ * 微信小程序的 AppID
+ */
+ @Value("${wx.miniapp.appid}")
+ private String appid;
+
+ /**
+ * 微信小程序的密钥
+ */
+ @Value("${wx.miniapp.secret}")
+ private String secret;
+
+ /**
+ * 商户号
+ */
+ @Value("${wx.miniapp.merchantId}")
+ private String merchantId;
+
+ /**
+ * 商户API私钥路径
+ */
+ @Value("${wx.miniapp.privateKeyPath}")
+ private String privateKeyPath;
+
+ /**
+ * 商户证书序列号
+ */
+ @Value("${wx.miniapp.merchantSerialNumber}")
+ private String merchantSerialNumber;
+
+ /**
+ * 商户APIV3密钥
+ */
+ @Value("${wx.miniapp.apiV3Key}")
+ private String apiV3Key;
+
+ /**
+ * 支付通知地址
+ */
+ @Value("${wx.miniapp.payNotifyUrl}")
+ private String payNotifyUrl;
+
+ /**
+ * 退款通知地址
+ */
+ @Value("${wx.miniapp.refundNotifyUrl}")
+ private String refundNotifyUrl;
+
+
+ @Autowired
+ @Qualifier("rsaAutoCertificateConfig")
+ private Config config;
+ @Autowired
+ @Qualifier("rsaAutoCertificateConfig")
+ private Config notificationConfig;
+
+
+// @Autowired
+// private IPopularizeOrderService popularizeOrderService;
+//
+// @Autowired
+// private IPopularizeOrderTuiLogService popularizeOrderTuiLogService;
+
+ //权限验证
+ @Resource
+ private ShiroRealm shiroRealm;
+
+ //退款记录
+ @Autowired
+ private IHanHaiMemberService hanHaiMemberService;
+
+ //订单信息
+ @Autowired
+ private IMassageOrderService massageOrderService;
+
+ //退款记录
+ @Autowired
+ private IMassageRefoundLogService massageRefoundLogService;
+
+
+ /**
+ * 退款
+ *
+ * 交易时间超过一年的订单无法提交退款(按支付成功时间+365天计算)
+ * 微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
+ * 请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次
+ * 每个支付订单的部分退款次数不能超过50次
+ * 如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败
+ * 申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果
+ * 错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
+ * 一个月之前的订单申请退款频率限制为:5000/min
+ * 同一笔订单多次退款的请求需相隔1分钟
+ *
+ *
+ * @param orderId
+ * @return
+ */
+ @Override
+ public Response refund(String token, String orderId) {
+ //权限验证
+ HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);
+ //HanHaiMember hanHaiMember = hanHaiMemberService.getById("1919297392365035521");
+
+ // 初始化服务
+ RefundService service = new RefundService.Builder().config(config).build();
+
+ //根据订单标识查询订单
+ MassageOrder payOrder = massageOrderService.lambdaQuery()
+ .eq(MassageOrder::getId, orderId)
+ .eq(MassageOrder::getUserId, hanHaiMember.getId())
+ .one();
+ if (payOrder == null) {
+ return Response.error("订单不存在");
+ }
+
+ //查询订单是否已经退款过
+ MassageRefoundLog check = massageRefoundLogService
+ .lambdaQuery()
+ .eq(MassageRefoundLog::getOrderId, orderId)
+ .eq(MassageRefoundLog::getUserId, hanHaiMember.getId())
+ .one();
+ if(null != check){
+ return Response.error("该订单已经退款过:"+orderId);
+ }
+ //添加退款记录
+ MassageRefoundLog massageRefoundLog = new MassageRefoundLog();
+ massageRefoundLog.setStatus("0");//退款状态
+ massageRefoundLog.setOrderId(orderId);//退款订单号
+ massageRefoundLog.setRefoundAmount(payOrder.getAmount());//退款金额
+ massageRefoundLog.setUserId(hanHaiMember.getId());//退款用户
+ massageRefoundLogService.save(massageRefoundLog);
+// if (payOrder.getAmount().compareTo(req.getRefundAmount()) < 0) {
+// return Response.error("退款金额不能大于支付金额");
+// }
+
+ CreateRequest request = new CreateRequest();
+ // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+ request.setOutTradeNo(orderId);
+ request.setOutRefundNo("REFUND_" + orderId);
+ AmountReq amount = new AmountReq();
+ // 订单总金额,单位为分,只能为整数,详见支付金额
+ amount.setTotal(decimalToLong(payOrder.getAmount()));
+ // 退款金额,单位为分,只能为整数,不能超过支付总额
+ amount.setRefund(decimalToLong(payOrder.getAmount()));
+ amount.setCurrency("CNY");
+
+ request.setAmount(amount);
+ request.setNotifyUrl(refundNotifyUrl);
+ // 调用接口
+ Refund refund = null;
+ try {
+ refund = service.create(request);
+ } catch (HttpException e) {
+ log.error("退款申请失败,发送HTTP请求失败:", e);
+ return Response.error("退款失败");
+ } catch (MalformedMessageException e) {
+ log.error("退款申请失败,解析微信支付应答或回调报文异常,返回信息:", e);
+ return Response.error("退款失败");
+ } catch (ValidationException e) {
+ log.error("退款申请失败,验证签名失败,返回信息:", e);
+ return Response.error("验证签名失败");
+ } catch (ServiceException e) {
+ log.error("退款申请失败,发送HTTP请求成功,返回异常,返回码:{},返回信息:", e.getErrorCode(), e);
+ return Response.error("退款失败:" + e.getErrorMessage());
+ } catch (Exception e) {
+ log.error("退款申请失败,异常:", e);
+ return Response.error("退款失败");
+ }
+ if (Status.SUCCESS.equals(refund.getStatus())) {
+ log.info("退款成功!-订单号:{}", payOrder.getId());
+
+ //修改退款记录订单状态
+ MassageRefoundLog refoundLog = massageRefoundLogService.lambdaQuery()
+ .eq(MassageRefoundLog::getOrderId, payOrder.getId())
+ .one();
+
+ refoundLog.setRefoundTime(CommonUtils.getCurrentTime());
+ refoundLog.setStatus("1");
+ massageRefoundLogService.updateById(refoundLog);
+
+ return Response.success("退款成功");
+ } else if (Status.CLOSED.equals(refund.getStatus())) {
+ log.info("退款关闭!-订单号:{}", payOrder.getId());
+ return Response.error("退款关闭");
+ } else if (Status.PROCESSING.equals(refund.getStatus())) {
+ log.info("退款处理中!-订单号:{}", payOrder.getId());
+ return Response.error("退款处理中");
+ } else if (Status.ABNORMAL.equals(refund.getStatus())) {
+ log.info("退款异常!-订单号:{}", payOrder.getId());
+ return Response.error("退款异常");
+ }
+ return Response.error("退款失败");
+ }
+
+ /**
+ * 查询单笔退款(通过商户退款单号)
+ *
+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,建议查询退款状态在提交退款申请后1分钟发起,一般来说零钱支付的退款5分钟内到账,银行卡支付的退款1-3个工作日到账。
+ *
+ *
+ * @param outRefundNo 商户退款单号
+ * @return
+ */
+ @Override
+ public Response queryByOutRefundNo(String outRefundNo) {
+ // 初始化服务
+ RefundService service = new RefundService.Builder().config(config).build();
+ QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
+ // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+ request.setOutRefundNo(outRefundNo.trim());
+ // 调用接口
+ Refund refund = null;
+ try {
+ refund = service.queryByOutRefundNo(request);
+ log.info("退款查询结果:{}", JSONObject.toJSONString(refund));
+ //【退款状态】退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台(pay.weixin.qq.com)-交易中心,手动处理此笔退款。可选取值:SUCCESS:退款成功CLOSED:退款关闭PROCESSING:退款处理中ABNORMAL:退款异常【退款状态】退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台(pay.weixin.qq.com)-交易中心,手动处理此笔退款。可选取值:SUCCESS:退款成功CLOSED:退款关闭PROCESSING:退款处理中ABNORMAL:退款异常
+ if (Status.SUCCESS.equals(refund.getStatus())) {
+ log.info("退款成功!-订单号:{}", outRefundNo);
+ return Response.success("退款成功");
+ } else if (Status.CLOSED.equals(refund.getStatus())) {
+ log.info("退款关闭!-订单号:{}", outRefundNo);
+ return Response.error("退款关闭");
+ } else if (Status.PROCESSING.equals(refund.getStatus())) {
+ log.info("退款处理中!-订单号:{}", outRefundNo);
+ return Response.success("退款处理中");
+ } else if (Status.ABNORMAL.equals(refund.getStatus())) {
+ log.info("退款异常!-订单号:{}", outRefundNo);
+ return Response.error("退款异常");
+ }
+ } catch (HttpException e) {
+ log.error("退款查询失败,发送HTTP请求失败:", e);
+ return Response.error("退款查询失败");
+ } catch (MalformedMessageException e) {
+ log.error("退款查询失败,解析微信支付应答或回调报文异常,返回信息:", e);
+ return Response.error("退款查询失败");
+ } catch (ValidationException e) {
+ log.error("退款查询失败,验证签名失败,返回信息:", e);
+ return Response.error("退款查询失败");
+ } catch (ServiceException e) {
+ log.error("退款查询失败,发送HTTP请求成功,返回异常,返回码:{},返回信息:", e.getErrorCode(), e);
+ return Response.error("退款查询失败");
+ } catch (Exception e) {
+ log.error("退款查询失败,异常:", e);
+ return Response.error("退款查询失败");
+ }
+
+ return Response.success(refund);
+ }
+
+ /**
+ * 微信小程序退款回调
+ *
+ * 注意:
+ * 对后台通知交互时,如果微信收到应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功
+ *
+ * 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
+ * 如果在所有通知频率后没有收到微信侧回调。商户应调用查询订单接口确认订单状态。
+ *
+ *
+ * @param request
+ * @return
+ */
+ @Override
+ public String refundNotify(HttpServletRequest request) {
+ Map returnMap = new HashMap<>(2);
+ returnMap.put("code", "FAIL");
+ returnMap.put("message", "失败");
+ try {
+ // 请求头Wechatpay-Signature
+ String signature = request.getHeader("Wechatpay-Signature");
+ // 请求头Wechatpay-nonce
+ String nonce = request.getHeader("Wechatpay-Nonce");
+ // 请求头Wechatpay-Timestamp
+ String timestamp = request.getHeader("Wechatpay-Timestamp");
+ // 微信支付证书序列号
+ String serial = request.getHeader("Wechatpay-Serial");
+ // 签名方式
+ String signType = request.getHeader("Wechatpay-Signature-Type");
+ // 构造解析器和请求参数
+ NotificationParser parser = new NotificationParser((NotificationConfig) notificationConfig);
+ RequestParam requestParam = new RequestParam.Builder()
+ .serialNumber(serial)
+ .nonce(nonce)
+ .signature(signature)
+ .timestamp(timestamp)
+ .signType(signType)
+ .body(HttpServletUtils.getRequestBody(request))
+ .build();
+ log.info("微信小程序支付退款回调验签参数: {}", JSON.toJSONString(requestParam));
+ // 解析通知
+ RefundNotification notification = null;
+ try {
+ notification = parser.parse(requestParam, RefundNotification.class);
+ } catch (MalformedMessageException e) {
+ log.error("微信小程序支付退款回调:回调通知参数不正确、解析通知数据失败:", e);
+ returnMap.put("message", "回调通知参数不正确");
+ return JSONObject.toJSONString(returnMap);
+ } catch (ValidationException e) {
+ log.error("微信小程序支付退款回调:签名验证失败 ", e);
+ returnMap.put("message", "签名验证失败");
+ return JSONObject.toJSONString(returnMap);
+ } catch (Exception e) {
+ log.error("微信小程序支付退款回调:未知异常 ", e);
+ returnMap.put("message", "未知异常");
+ return JSONObject.toJSONString(returnMap);
+ }
+ log.info("微信小程序支付退款回调解析成功: {}", JSON.toJSONString(notification));
+ // 根据退款状态处理
+ Status refundStatus = notification.getRefundStatus();
+ switch (refundStatus) {
+ case SUCCESS:
+ // TODO 退款成功逻辑
+
+ returnMap.put("code", "SUCCESS");
+ returnMap.put("message", "退款成功");
+
+ //修改订单退款状态
+ MassageOrder order = massageOrderService
+ .lambdaQuery()
+ .eq(MassageOrder::getId, notification.getOutTradeNo())
+ .eq(MassageOrder::getIsRefound, "0")
+ .one();
+ if(null != order){
+ order.setStatus("3");
+ order.setIsRefound("1");
+ massageOrderService.updateById(order);
+ }
+
+ //修改退款记录状态
+ MassageRefoundLog refoundLog = massageRefoundLogService
+ .lambdaQuery()
+ .eq(MassageRefoundLog::getOrderId, notification.getOutTradeNo())
+ .eq(MassageRefoundLog::getStatus, "0")
+ .one();
+ if(null != refoundLog){
+ refoundLog.setStatus("1");
+ refoundLog.setRefoundTime(CommonUtils.getCurrentTime());
+ massageRefoundLogService.updateById(refoundLog);
+ }
+
+
+ return JSONObject.toJSONString(returnMap);
+ case PROCESSING:
+ log.warn("退款处理中: {}", notification);
+ returnMap.put("message", "退款处理中,请稍后查询");
+ return JSONObject.toJSONString(returnMap);
+ case ABNORMAL:
+ log.error("退款异常: {}", notification);
+ returnMap.put("message", "退款异常,请联系客服");
+ return JSONObject.toJSONString(returnMap);
+ case CLOSED:
+ log.warn("退款已关闭: {}", notification);
+ returnMap.put("message", "退款已关闭,操作失败");
+ return JSONObject.toJSONString(returnMap);
+ default:
+ log.error("未知退款状态: {}", refundStatus);
+ returnMap.put("message", "未知退款状态");
+ return JSONObject.toJSONString(returnMap);
+ }
+ } catch (Exception e) {
+ log.error("退款回调处理异常", e);
+ returnMap.put("message", "退款处理异常");
+ return JSONObject.toJSONString(returnMap);
+ }
+ }
+
+
+ /**
+ * 金额转换
+ *
+ * @param money
+ * @return
+ */
+ private static long decimalToLong(BigDecimal money) {
+ return money.multiply(BigDecimal.valueOf(100)).longValue();
+ }
+
+
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/CreateOrderReq.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/CreateOrderReq.java
new file mode 100644
index 0000000..8cfe775
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/CreateOrderReq.java
@@ -0,0 +1,8 @@
+package org.jeecg.modules.wxUtils;
+
+public class CreateOrderReq {
+ /**
+ * 微信用户openid(前端不用传参)
+ */
+ private String wxOpenId;
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/HttpServletUtils.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/HttpServletUtils.java
new file mode 100644
index 0000000..ab49815
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/HttpServletUtils.java
@@ -0,0 +1,47 @@
+package org.jeecg.modules.wxUtils;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ *
+ * HttpServletRequest 获取请求体
+ *
+ *
+ * @author songfayuan
+ * @date 2024/9/30 19:11
+ */
+public class HttpServletUtils {
+
+ /**
+ * 获取请求体
+ *
+ * @param request
+ * @return
+ * @throws IOException
+ */
+ public static String getRequestBody(HttpServletRequest request) throws IOException {
+ ServletInputStream stream = null;
+ BufferedReader reader = null;
+ StringBuffer sb = new StringBuffer();
+ try {
+ stream = request.getInputStream();
+ // 获取响应
+ reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ } catch (IOException e) {
+ throw new IOException("读取返回支付接口数据流出现异常!");
+ } finally {
+ reader.close();
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/PayOrderInfo.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/PayOrderInfo.java
new file mode 100644
index 0000000..6936a91
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/PayOrderInfo.java
@@ -0,0 +1,31 @@
+package org.jeecg.modules.wxUtils;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ *
+ * 支付订单信息
+ *
+ *
+ * @author songfayuan
+ * @date 2024/9/30 17:46
+ */
+@Data
+public class PayOrderInfo {
+ /**
+ * 订单标题
+ */
+ private String description;
+ /**
+ * 商户订单号
+ * 只能是数字、大小写字母_-*且在同一个商户号下唯一。
+ */
+ private String outTradeNo;
+ /**
+ * 支付金额,单位:元
+ */
+ private BigDecimal amount;
+}
+
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/QueryOrderReq.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/QueryOrderReq.java
new file mode 100644
index 0000000..686b26b
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/QueryOrderReq.java
@@ -0,0 +1,23 @@
+package org.jeecg.modules.wxUtils;
+
+import lombok.Data;
+
+/**
+ *
+ * 订单查询请求
+ *
+ *
+ * @author songfayuan
+ * @date 2024/9/30 19:19
+ */
+@Data
+public class QueryOrderReq {
+ /**
+ * 订单号:业务侧的订单号
+ */
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ private String outTradeNo;
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/RefundOrderReq.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/RefundOrderReq.java
new file mode 100644
index 0000000..bf0ceca
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/RefundOrderReq.java
@@ -0,0 +1,36 @@
+package org.jeecg.modules.wxUtils;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ *
+ * 退款订单请求参数
+ *
+ *
+ * @author songfayuan
+ * @date 2024/9/30 19:19
+ */
+@Data
+public class RefundOrderReq {
+ /**
+ * 订单号:业务侧的订单号
+ */
+ private String transactionId;
+ /**
+ * 商户订单号
+ */
+ private String outTradeNo;
+
+ /**
+ * 原订单金额 说明:原支付交易的订单总金额,这里单位为元。
+ */
+ private BigDecimal totalAmount;
+
+ /**
+ * 退款金额 说明:退款金额,这里单位为元,不能超过原订单支付金额。
+ */
+ private BigDecimal refundAmount;
+}
+
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/Response.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/Response.java
new file mode 100644
index 0000000..92b12cb
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/Response.java
@@ -0,0 +1,164 @@
+package org.jeecg.modules.wxUtils;
+
+import lombok.Data;
+
+/**
+ * 返回参数封装类
+ *
+ * @param
+ * @author songfayuan
+ */
+
+@Data
+public class Response {
+ /**
+ * 状态码
+ */
+ protected int code;
+
+ /**
+ * 提示信息
+ */
+ protected String msg;
+
+ /**
+ * 数据
+ */
+ protected T data;
+
+ /**
+ * 成功时状态码
+ */
+ private static final int SUCCESS_CODE = 200;
+
+ /**
+ * 成功时提示信息
+ */
+ private static final String SUCCESS_MSG = "success";
+
+ /**
+ * 异常、错误信息状态码
+ */
+ private static final int ERROR_CODE = 500;
+
+ /**
+ * 异常、错误提示信息
+ */
+ private static final String ERROR_MSG = "服务器内部异常,请联系技术人员!";
+
+ /**
+ * 返回成功消息
+ *
+ * @param
+ * @return
+ */
+ public static Response success() {
+ Response resp = new Response();
+ resp.code = (SUCCESS_CODE);
+ resp.msg = (SUCCESS_MSG);
+ return resp;
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @param
+ * @param msg
+ * @return
+ */
+ public static Response successResponse(String msg) {
+ Response resp = new Response();
+ resp.code = SUCCESS_CODE;
+ resp.msg = msg;
+ return resp;
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param
+ * @return
+ */
+ public static Response error() {
+ Response resp = new Response();
+ resp.code = (ERROR_CODE);
+ resp.msg = (ERROR_MSG);
+ return resp;
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param
+ * @param msg
+ * @return
+ */
+ public static Response errorResponse(String msg) {
+ Response resp = new Response();
+ resp.code = ERROR_CODE;
+ resp.msg = msg;
+ return resp;
+ }
+
+ /**
+ * 自定义状态码、提示信息
+ *
+ * @param
+ * @param code 状态码
+ * @param msg 提示信息
+ * @return
+ */
+ public static Response response(int code, String msg) {
+ Response resp = new Response();
+ resp.code = (code);
+ resp.msg = (msg);
+ return resp;
+ }
+
+ /**
+ * 自定义状态码、提示信息、业务数据
+ *
+ * @param
+ * @param code 状态码
+ * @param msg 提示信息
+ * @param data 业务数据
+ * @return
+ */
+ public static Response response(int code, String msg, T data) {
+ Response resp = new Response<>();
+ resp.code = (code);
+ resp.msg = (msg);
+ resp.data = data;
+ return resp;
+ }
+
+ /**
+ * 返回成功数据
+ *
+ * @param
+ * @param data 业务数据
+ * @return
+ */
+ public static Response success(T data) {
+ Response resp = new Response<>();
+ resp.code = (SUCCESS_CODE);
+ resp.msg = (SUCCESS_MSG);
+ resp.data = data;
+ return resp;
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param
+ * @param data 业务数据
+ * @return
+ */
+ public static Response error(T data) {
+ Response resp = new Response<>();
+ resp.code = (ERROR_CODE);
+ resp.msg = (ERROR_MSG);
+ resp.data = data;
+ return resp;
+ }
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayAutoCertificateConfig.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayAutoCertificateConfig.java
new file mode 100644
index 0000000..0a7df7d
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayAutoCertificateConfig.java
@@ -0,0 +1,113 @@
+package org.jeecg.modules.wxUtils;
+
+
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.RSAPublicKeyConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Slf4j
+@Configuration
+public class WxPayAutoCertificateConfig {
+
+ /**
+ * 微信小程序的 AppID
+ */
+ @Value("${wx.miniapp.appid}")
+ private String appid;
+
+ /**
+ * 微信小程序的密钥
+ */
+ @Value("${wx.miniapp.secret}")
+ private String secret;
+
+ /**
+ * 商户号
+ */
+ @Value("${wx.miniapp.merchantId}")
+ private String merchantId;
+
+ /**
+ * 商户API私钥路径
+ */
+ @Value("${wx.miniapp.privateKeyPath}")
+ private String privateKeyPath;
+
+ /**
+ * 商户API公钥路径
+ */
+ @Value("${wx.miniapp.publicKeyPath}")
+ private String publicKeyPath;
+
+ /**
+ * 公钥
+ */
+ @Value("${wx.miniapp.publicKeyId}")
+ private String publicKeyId;
+
+ /**
+ * 商户证书序列号
+ */
+ @Value("${wx.miniapp.merchantSerialNumber}")
+ private String merchantSerialNumber;
+
+ /**
+ * 商户APIV3密钥
+ */
+ @Value("${wx.miniapp.apiV3Key}")
+ private String apiV3Key;
+
+ /**
+ * 支付通知地址
+ */
+ @Value("${wx.miniapp.payNotifyUrl}")
+ private String payNotifyUrl;
+
+ /**
+ * 退款通知地址
+ */
+ @Value("${wx.miniapp.refundNotifyUrl}")
+ private String refundNotifyUrl;
+
+ /**
+ * 初始化商户配置
+ * @return
+ */
+ @Bean
+ public Config rsaAutoCertificateConfig() {
+ // 这里把Config作为配置Bean是为了避免多次创建资源,一般项目运行的时候这些东西都确定了
+ // 具体的参数改为申请的数据,可以通过读配置文件的形式获取
+// Config config = new RSAAutoCertificateConfig.Builder()
+// .merchantId("1659066870")
+// .privateKeyFromPath("E:\\git_java\\api_java\\popularize-admin\\popularize-admin\\popularize-admin\\module-pay\\src\\main\\resources\\apiclient_key.pem")
+// .merchantSerialNumber("7BE56DC695B2B612BD1C6C710A7FBFA1AC46B10F")
+// .apiV3Key("vtribevtribevtribevtribevtribe12")
+// .build();
+
+ Config config = new RSAPublicKeyConfig.Builder()
+ .merchantId(merchantId)
+ .privateKeyFromPath(privateKeyPath)
+ .publicKeyFromPath(publicKeyPath)
+ .publicKeyId(publicKeyId)
+ .merchantSerialNumber(merchantSerialNumber)
+ .apiV3Key(apiV3Key)
+ .build();
+
+
+// Config config = new RSAAutoCertificateConfig.Builder()
+// .merchantId(merchantId)
+// .privateKeyFromPath(privateKeyPath)
+// .merchantSerialNumber(merchantSerialNumber)
+// .apiV3Key(apiV3Key)
+// .build();
+
+ log.info("初始化微信支付商户配置完成...");
+ return config;
+ }
+
+
+}
diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayConfig.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayConfig.java
new file mode 100644
index 0000000..e5393b7
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/wxUtils/WxPayConfig.java
@@ -0,0 +1,13 @@
+package org.jeecg.modules.wxUtils;
+import lombok.Data;
+import org.springframework.stereotype.Component;
+
+
+@Data
+@Component
+public class WxPayConfig {
+
+
+
+}
+
diff --git a/jeecg-boot-module-system/src/main/resources/apiclient_key.pem b/jeecg-boot-module-system/src/main/resources/apiclient_key.pem
new file mode 100644
index 0000000..ca53b76
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/resources/apiclient_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8an3vcCIsBgcy
+wG+H5tZZ0/qZJIEeqFHYDvKxqs69slnT4pUxG7wir66o+SQP7bPBpHDh7OGghuhP
+8KTSYMnG100k44Rfm7Ch+P2/mdexfgu4aC2CBFf6ziOjopBzBfc3TEOuwCdPTcFL
+4G3yZ65xldiO+stiDdeXa5EQrD9LFWL4YADOkd8RPxUGFQaWWWnUR+7VdWCHsYZ7
+J1qrwmyVsNXsbcWAdQKwiXy7fws6IOyRUj4p8tUc/GDqz1vwCTZQJ6Km3b+nCLqb
+SDbZ82XhSJJzZRzGzcY/IqdeQT9Lrb0SYWs3HDmN5/NngU2cihiUqw4LrzWy/ui0
++Fvt46AVAgMBAAECggEBAJbphO0fF3/DZEiWMb7ceZuBWhsHThRMJSG091auxODT
+1XcM6QpoeIwfwvm8c9H+Rhg3qeKLZTy6UaCV0q5er77/+94sDX62qQdS84tfoY+c
+sa6GYszcxcsxCQKr1p8KjDRSdXOmnNW8JbKsk+Owf9yidM4wum5TP/ccRRjhneB4
+YmN+cw93bl+5yqebvaRwC1S7WcUspj2lmaSLE/IvFOBU91Wnn6XvjkAU7QnuUxlV
+0NVWgJqhykng6E/lsXkEB6Akk5fZXHDvJCgP6zCDHZs0LC8MTl984fDtr1CB1lnw
+n/B6gQEYhVnqlvGxLhjGwZbfYzFuPZqgnDkVbBWflYECgYEA99s7k74edmVkOriI
+KYuYctDkU22HsoKHaB+VhKfeaZWWr25RPpWk0yQWNr1SxkdEJopzxVMuCoxrGy6F
+MUpgM0By6QBoU3WFZONSzDalqFJANIVj+o3/RCnI5w4na6MAaw4t/hMd2avxSje/
+k1A2CeBYm7eN7bYaFXe+hwFGyz0CgYEAwptLctRG3R35beRBXMccuvvxjXmSNfpW
+qIBCnNn0KzBu7r8JyxHVI8mIdA5jD8C0G91wFnm0hG+fcZ+9eFpLZCaHbfVI55GS
+NsOBwkO5WrOj2LcWd9yi4cKPxFceOLrEBKmxTXFGnoeVoA4468ec8kEQywG96dvb
+QKFZ4JM11bkCgYEAhRA9u+Ollwp39M58y1EWVw2uhtuWrk9FQrEyJDW7QhP9AdHH
+7EGKa5BEHL8nYSuBeu95l8ZAQYmBNuaSuxOi8eD3z/9YAvZk1vTzzo7IAMWnkorK
+UglJsd587Q68Ox0XbGIAbxb0P5f/wkiLoRq+6C55Y5/3olbRShUvRGt7BkECgYBw
+zuCvkcn6R3PddeFFzM4kvgNKBVzyGUm+p4r1rYpStuK3Vtpwcsfg1ORakjRuX0CI
+npZpEOfJlYMRtI16hK0LQyJiZTt7sPDW+gHwAJ4jq9qgt5E4rhdlUwlPwUhtjiYu
+pcd3ouBS6Tmc7GGmm7Go5Hq9kybpt16jWmTlP7CHUQKBgGaJwRKkIjJsvpGEkxcx
+ReFyK5avL+ky/q/Q/TyCmEr8uVZGe1kEXdDk53+VR1YzwX/K+7Bjx0vlH3T57Z9J
+vv1fiJZimmLy17mkRQurREvWfICTH/WJxzMF5ALJLpqGzr451fzaupMNhI04Ln/e
+dTDkCyho1MMaRP+2a12AIEex
+-----END PRIVATE KEY-----
diff --git a/jeecg-boot-module-system/src/main/resources/application-dev.yml b/jeecg-boot-module-system/src/main/resources/application-dev.yml
index e31fff9..5b5a2c3 100644
--- a/jeecg-boot-module-system/src/main/resources/application-dev.yml
+++ b/jeecg-boot-module-system/src/main/resources/application-dev.yml
@@ -329,3 +329,31 @@ third-app:
client-secret: ??
agent-id: ??
+## 微信商户
+wx:
+ miniapp:
+ appid: wx77ba4c7131677a74 # 微信小程序appid
+ secret: fb915d623f92d455f2e70934f75fb96c # 微信小程序密钥
+ merchantId: 1712378227 # 商户号
+ privateKeyPath: jeecg-boot-module-system/src/main/resources/apiclient_key.pem #本地私钥路径
+ publicKeyPath: jeecg-boot-module-system/src/main/resources/pub_key.pem #本地公钥路径
+# privateKeyPath: /root/massage/cerFile/apiclient_key.pem #线上私钥路径
+# publicKeyPath: /root/massage/cerFile/pub_key.pem #线上公钥路径
+ publicKeyId: PUB_KEY_ID_0117123782272025033100396400002931 #公钥
+ merchantSerialNumber: 33E9FE8076531A7C7AD401DC34E053DBD7C28E22 # 商户API证书序列号
+ apiV3Key: 0fdb77429ffdf206c151af76a663041c # 商户APIV3密钥
+ payNotifyUrl: https://www.yurangongfang.com/massage-admin/massage/order/payOrderNotify/ # 支付通知地址(测试环境)
+ refundNotifyUrl: https://www.yurangongfang.com/massage-admin/massage/refound/refundNotify/ # 退款通知地址(正式环境)
+# refundNotifyUrl: http://augcl.natapp1.cc/massage-admin/massage/refound/refundNotify/ # 退款通知地址(测试环境)
+
+### 微信商户
+#wx:
+# miniapp:
+# appid: wx797abcfb479c75ec # 微信小程序appid
+# secret: c4565acc18698a7000be1b2bb748be81 # 微信小程序密钥
+# merchantId: 1659066870 # 商户号
+# privateKeyPath: jeecg-boot-module-system/src/main/resources/apiclient_key.pem
+# merchantSerialNumber: 7BE56DC695B2B612BD1C6C710A7FBFA1AC46B10F # 商户API证书序列号
+# apiV3Key: vtribevtribevtribevtribevtribe12 # 商户APIV3密钥
+# payNotifyUrl: http://h5.xzaiyp.top/popularize-admin/order_pay/refundNotify # 支付通知地址(测试环境)
+# refundNotifyUrl: http://h5.xzaiyp.top/popularize-admin/order_pay/refundNotify # 退款通知地址(测试环境)
\ No newline at end of file
diff --git a/jeecg-boot-module-system/src/main/resources/pub_key.pem b/jeecg-boot-module-system/src/main/resources/pub_key.pem
new file mode 100644
index 0000000..bd7b4f5
--- /dev/null
+++ b/jeecg-boot-module-system/src/main/resources/pub_key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6xCzq1CjrZYTqtE52f7t
+4AU9rgRZYKNn94tmkIuYa1wGX13gWNIlo1muExV/Ejg4H9Xe0RCQwNNJieeyfhU7
+Vl/qms4Ukj8sqIrvKqw9j81AVHK2BSk87aRs0ha+gvV1tDDmcCLHrY8SeGcJ2U2z
+I9iu5X1kLdkXNiojWrMngGslki2FSfJelftoZUDk30mf18AoG5iBzIPJ4/Gy5Rh0
+U+FDwpWzERR7XjMoAZ7YiRYUdV/SpQkx6CrM4Em3AKxmpxvwSVg7NiMDoTljfgq+
+6ZHB9DMQPbeqkQ9qkCMg0sVjpB/aI9tObE0mtU8zP/mBg7TDTs0qa2SXFem5ZTDg
+JQIDAQAB
+-----END PUBLIC KEY-----