Переглянути джерело

feature 退款代码提交

xiahan 4 місяців тому
батько
коміт
3079a1dfba
15 змінених файлів з 492 додано та 37 видалено
  1. 2 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/config/WeChatAboutApiPara.java
  2. 6 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/dao/SwRefundRequestRecordDao.java
  3. 1 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/service/impl/SwRefundRequestRecordServiceImpl.java
  4. 4 4
      zhsw-common/src/main/java/com/rongwei/zhsw/system/utils/WxPayApi.java
  5. 43 23
      zhsw-common/src/main/java/com/rongwei/zhsw/system/utils/WxRefundApi.java
  6. 17 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/RefundService.java
  7. 1 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/PayMentServiceImpl.java
  8. 1 1
      zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/PaymentRecordServiceImpl.java
  9. 260 0
      zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/RefundServiceImpl.java
  10. 14 0
      zhsw-common/src/main/resources/mybatis/zhsw/SwRefundRequestRecordDao.xml
  11. 17 6
      zhsw-entity/src/main/java/com/rongwe/zhsw/system/domain/SwRefundRequestRecordDO.java
  12. 17 0
      zhsw-entity/src/main/java/com/rongwe/zhsw/system/vo/RefundInitiateVo.java
  13. 57 0
      zhsw-entity/src/main/java/com/rongwe/zhsw/system/vo/WeChatRefundNoticeVo.java
  14. 50 0
      zhsw-server/src/main/java/com/rongwei/zhsw/system/controller/RefundController.java
  15. 2 3
      zhsw-server/src/main/java/com/rongwei/zhsw/system/controller/SwRefundRequestRecordController.java

+ 2 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/config/WeChatAboutApiPara.java

@@ -26,4 +26,6 @@ public class WeChatAboutApiPara {
     private String refreshToken;
 
     private String paymentCallbackUrl;
+
+    private String refundCallbackUrl;
 }

+ 6 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/dao/SwRefundRequestRecordDao.java

@@ -2,6 +2,9 @@ package com.rongwei.zhsw.system.dao;
  
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.rongwe.zhsw.system.domain.SwRefundRequestRecordDO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
 
 
 /**
@@ -11,5 +14,8 @@ import com.rongwe.zhsw.system.domain.SwRefundRequestRecordDO;
  * @since 2025-03-13 17:28:46
  */
 public interface SwRefundRequestRecordDao extends BaseMapper<SwRefundRequestRecordDO> {
+
+    void updateWeChatRefundInfo(@Param("dseKey") String dseKey, @Param("orderNo") String orderNo, @Param("wechatNo") String wechatNo,
+                             @Param("desc") String desc, @Param("successTime") Date successTime,@Param("state")String state);
  
 }

+ 1 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/service/impl/SwRefundRequestRecordServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.rongwe.zhsw.system.domain.*;
 import com.rongwei.rwadmincommon.system.vo.SysUserVo;
 import com.rongwei.rwcommon.base.R;
+import com.rongwei.rwcommon.base.exception.CustomException;
 import com.rongwei.rwcommon.utils.SecurityUtil;
 import com.rongwei.zhsw.system.dao.SwRefundRequestRecordDao;
 import com.rongwei.zhsw.system.service.*;

+ 4 - 4
zhsw-common/src/main/java/com/rongwei/zhsw/system/utils/WxPayApi.java

@@ -16,22 +16,22 @@ public class WxPayApi {
     /**
      * 商户号
      */
-    public String merchantId;
+    private String merchantId;
 
     /**
      * 商户API私钥路径
      */
-    public String privateKeyPath;
+    private String privateKeyPath;
 
     /**
      * 商户证书序列号
      */
-    public String merchantSerialNumber;
+    private String merchantSerialNumber;
 
     /**
      * 商户APIV3密钥
      */
-    public String apiV3Key;
+    private String apiV3Key;
 
     private String appId;
 

+ 43 - 23
zhsw-common/src/main/java/com/rongwei/zhsw/system/utils/WxRefundApi.java

@@ -1,82 +1,102 @@
 package com.rongwei.zhsw.system.utils;
+
 import com.wechat.pay.java.core.Config;
 import com.wechat.pay.java.core.RSAAutoCertificateConfig;
-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.service.refund.RefundService;
 import com.wechat.pay.java.service.refund.model.AmountReq;
 import com.wechat.pay.java.service.refund.model.CreateRequest;
 import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
 import com.wechat.pay.java.service.refund.model.Refund;
-import org.springframework.core.io.ClassPathResource;
+import lombok.SneakyThrows;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 
 public class WxRefundApi {
     /**
      * 商户号
      */
-    public String merchantId = "1711246421";
+    private String merchantId;
 
     /**
      * 商户API私钥路径
      */
-    public String privateKeyPath = "D:\\code\\project\\zhsw\\zhsw_service\\zhsw-server\\src\\main\\resources\\cert\\apiclient_key.pem";
+    private String privateKeyPath;
 
     /**
      * 商户证书序列号
      */
-    public String merchantSerialNumber = "6F46F471C22D410F9ECEDC8B197979A4CA42BC96";
+    private String merchantSerialNumber;
 
     /**
      * 商户APIV3密钥
      */
-    public String apiV3Key = "GBA67AVWJESPJ3TFJ3GT3NLQBEOTO1FW";
+    private String apiV3Key;
+
+    private String notifyUrl;
 
-    public RefundService service;
+    private RefundService service;
+    private static final Logger log = LoggerFactory.getLogger(WxRefundApi.class);
 
+    public WxRefundApi(String merchantId, String privateKeyPath, String merchantSerialNumber, String apiV3Key, String notifyUrl) {
+        this.merchantId = merchantId;
+        this.privateKeyPath = privateKeyPath;
+        this.merchantSerialNumber = merchantSerialNumber;
+        this.apiV3Key = apiV3Key;
+        this.notifyUrl = notifyUrl;
+    }
+
+    @SneakyThrows
     public void initMerchant() {
-        ClassPathResource classPathResource = new ClassPathResource("cert/apiclient_key.pem");
+        String keyPath = WxPayApi.class.getClassLoader().getResource("").getPath() + privateKeyPath + "/apiclient_key.pem";
+        keyPath = URLDecoder.decode(keyPath, StandardCharsets.UTF_8.toString());
         Config config =
                 new RSAAutoCertificateConfig.Builder()
                         .merchantId(merchantId)
                         // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
-                        .privateKeyFromPath(privateKeyPath)
+                        .privateKeyFromPath(keyPath)
                         .merchantSerialNumber(merchantSerialNumber)
                         .apiV3Key(apiV3Key)
                         .build();
         service = new RefundService.Builder().config(config).build();
     }
 
-    /** 退款申请 */
-    public Refund create() {
+    /**
+     * 退款申请
+     */
+    public Refund create(String wxddh, String shddh, long tkje, long yje, String tkyy,
+                         String tkdh, String dsKey) {
         CreateRequest request = new CreateRequest();
-        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
-        // 调用接口
         // 微信支付订单号
-        request.setTransactionId("");
+        request.setTransactionId(wxddh);
         // 商户订单号
-        request.setOutTradeNo("");
+        request.setOutTradeNo(shddh);
         // 商户退款单号
-        request.setOutRefundNo("");
+        request.setOutRefundNo(tkdh);
         // 退款原因
-        request.setReason("");
+        request.setReason(tkyy);
         // 退款结果回调url
-        request.setNotifyUrl("");
+        request.setNotifyUrl(notifyUrl + dsKey);
+        log.error("回调函数地址:{}", notifyUrl + dsKey);
         // 退款资金来源
 //        request.setFundsAccount("AVAILABLE");
         // 金额信息
         AmountReq amount = new AmountReq();
         // 退款金额
-        amount.setRefund(1L);
+        amount.setRefund(tkje);
         // 原订单金额
-        amount.setTotal(1L);
+        amount.setTotal(yje);
         // 退款币种
         amount.setCurrency("CNY");
         request.setAmount(amount);
         return service.create(request);
     }
 
-    /** 查询单笔退款(通过商户退款单号) */
+    /**
+     * 查询单笔退款(通过商户退款单号)
+     */
     public Refund queryByOutRefundNo() {
 
         QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();

+ 17 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/RefundService.java

@@ -0,0 +1,17 @@
+package com.rongwei.zhsw.system.wechat;
+
+import com.rongwe.zhsw.system.vo.PrepayNoticeVo;
+import com.rongwe.zhsw.system.vo.RefundInitiateVo;
+import com.rongwei.rwcommon.base.R;
+
+/**
+ * RefundService class
+ *
+ * @author XH
+ * @date 2025/03/26
+ */
+public interface RefundService {
+    R refundByRecord(RefundInitiateVo vo);
+
+    R refundNotice(PrepayNoticeVo prepayNoticeVo,String dsKey);
+}

+ 1 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/PayMentServiceImpl.java

@@ -157,6 +157,7 @@ public class PayMentServiceImpl implements PayMentService {
             }
         }
         if (StringUtils.isBlank(analysisStr)) {
+            log.error("回调函数解析异常");
             return R.error();
         }
         ObjectMapper mapper = new ObjectMapper();

+ 1 - 1
zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/PaymentRecordServiceImpl.java

@@ -193,7 +193,7 @@ public class PaymentRecordServiceImpl implements PaymentRecordService {
         swBillingRecordDo.setTollcollectorid("");
         swBillingRecordDo.setTollcollectorname("");
         swBillingRecordDo.setOriginalbalance(swUserManagementDo.getAccountbalance());
-
+        swBillingRecordDo.setUsertype(swUserManagementDo.getUsertypeid());
         /******************实缴******************/
         swBillingRecordDo.setPaidin(paymentAmount);
         swBillingRecordService.calculateFees(unpaidDoList, swBillingRecordDo,swUserManagementDo);

+ 260 - 0
zhsw-common/src/main/java/com/rongwei/zhsw/system/wechat/impl/RefundServiceImpl.java

@@ -0,0 +1,260 @@
+package com.rongwei.zhsw.system.wechat.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.rongwe.zhsw.system.domain.SwBillingRecordDo;
+import com.rongwe.zhsw.system.domain.SwEnterpriseConfigInfoDo;
+import com.rongwe.zhsw.system.domain.SwRefundRequestRecordDO;
+import com.rongwe.zhsw.system.vo.PrepayNoticeVo;
+import com.rongwe.zhsw.system.vo.RefundInitiateVo;
+import com.rongwe.zhsw.system.vo.WeChatRefundNoticeVo;
+import com.rongwei.commonservice.service.impl.RedisServiceImpl;
+import com.rongwei.rwadmincommon.system.vo.SysUserVo;
+import com.rongwei.rwcommon.base.BaseDo;
+import com.rongwei.rwcommon.base.R;
+import com.rongwei.rwcommon.base.exception.CustomException;
+import com.rongwei.rwcommon.utils.Constants;
+import com.rongwei.rwcommonentity.commonservers.domain.TenantDo;
+import com.rongwei.zhsw.system.config.WeChatAboutApiPara;
+import com.rongwei.zhsw.system.dao.CommonBusinessDao;
+import com.rongwei.zhsw.system.service.impl.SwBillingRecordServiceImpl;
+import com.rongwei.zhsw.system.service.impl.SwEnterpriseConfigInfoServiceImpl;
+import com.rongwei.zhsw.system.service.impl.SwRefundRequestRecordServiceImpl;
+import com.rongwei.zhsw.system.utils.WxRefundApi;
+import com.rongwei.zhsw.system.utils.ZHSWCommonUtils;
+import com.rongwei.zhsw.system.wechat.RefundService;
+import com.wechat.pay.java.core.exception.ServiceException;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import static com.rongwei.zhsw.system.wechat.impl.PayMentServiceImpl.TAG_LENGTH_BIT;
+
+/**
+ * RefundServiceImppl class
+ *
+ * @author XH
+ * @date 2025/03/26
+ */
+@Service
+public class RefundServiceImpl implements RefundService {
+
+    private static final Logger log = LoggerFactory.getLogger(RefundServiceImpl.class);
+    @Autowired
+    private SwEnterpriseConfigInfoServiceImpl swEnterpriseConfigInfoService;
+    @Autowired
+    private WeChatAboutApiPara weChatAboutApiPara;
+    @Autowired
+    private SwBillingRecordServiceImpl swBillingRecordService;
+    @Autowired
+    private SwRefundRequestRecordServiceImpl swRefundRequestRecordService;
+    @Autowired
+    private RedisServiceImpl redisService;
+    @Autowired
+    private CommonBusinessDao commonBusinessDao;
+
+    @Override
+    public R refundByRecord(RefundInitiateVo vo) {
+        log.info("发起小程序退款申请:{}", vo.getRefundRequestId());
+        String refundRequestId = vo.getRefundRequestId();
+        if (StringUtils.isBlank(refundRequestId)) {
+            log.error("参数异常");
+            throw new CustomException("缴费记录id为空,参数异常");
+        }
+
+        SwEnterpriseConfigInfoDo swEnterpriseConfigInfoDo = swEnterpriseConfigInfoService.getOne(new LambdaQueryWrapper<SwEnterpriseConfigInfoDo>().eq(BaseDo::getDeleted, "0"));
+        if (swEnterpriseConfigInfoDo == null) {
+            log.error("无法获取企业配置信息");
+            throw new CustomException("无法获取企业配置信息");
+        }
+        String enterpriseno = swEnterpriseConfigInfoDo.getEnterpriseno();
+        String merchantid = swEnterpriseConfigInfoDo.getMerchantid();
+        String merchantname = swEnterpriseConfigInfoDo.getMerchantname();
+        String merchantprivatekey = swEnterpriseConfigInfoDo.getMerchantprivatekey();
+        String merchantserialnumber = swEnterpriseConfigInfoDo.getMerchantserialnumber();
+        String merchantsecretkey = swEnterpriseConfigInfoDo.getMerchantsecretkey();
+
+        if (StringUtils.isBlank(enterpriseno)) {
+            log.error("支付参数:企业编号 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        if (StringUtils.isBlank(merchantid)) {
+            log.error("支付参数:商户ID 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        if (StringUtils.isBlank(merchantname)) {
+            log.error("支付参数:商户名称 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        if (StringUtils.isBlank(merchantprivatekey)) {
+            log.error("支付参数:商户私钥 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        if (StringUtils.isBlank(merchantserialnumber)) {
+            log.error("支付参数:商户序列号 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        if (StringUtils.isBlank(merchantsecretkey)) {
+            log.error("支付参数:商户密钥 为空");
+            throw new CustomException("商户支付配置错误,请联系系统管理员!");
+        }
+        // 退款申请
+        SwRefundRequestRecordDO swRefundRequestRecordDO = swRefundRequestRecordService.getById(refundRequestId);
+        if (swRefundRequestRecordDO.getPaymentrecordid() == null) {
+            log.error("无法获取退款申请");
+            throw new CustomException("无法获取退款申请");
+        }
+        if ("3".equals(swRefundRequestRecordDO.getRefundtype())) {
+            log.error("退款成功无法退款");
+            throw new CustomException("退款成功无法退款");
+        }
+        // 缴费记录
+        SwBillingRecordDo swBillingRecordDo = swBillingRecordService.getById(swRefundRequestRecordDO.getPaymentrecordid());
+        if (swBillingRecordDo == null) {
+            log.error("无法获取缴费记录");
+            throw new CustomException("无法获取缴费记录");
+        }
+        String wechatpayordernumber = swBillingRecordDo.getWechatpayordernumber();
+        String merchantpaymentnumber = swBillingRecordDo.getMerchantpaymentnumber();
+        if (StringUtils.isBlank(wechatpayordernumber) || StringUtils.isBlank(merchantpaymentnumber)) {
+            log.error("微信订单号或商户支付编号为空");
+            throw new CustomException("退款申请异常");
+        }
+        SysUserVo currentUser = ZHSWCommonUtils.getCurrentUser();
+        String dskey = currentUser.getTenantDo().getDskey();
+        WxRefundApi wxRefundApi = new WxRefundApi(merchantid, merchantprivatekey, merchantserialnumber, merchantsecretkey,
+                weChatAboutApiPara.getRefundCallbackUrl());
+        wxRefundApi.initMerchant();
+        // 生成订单号 规则
+        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
+        try {
+            wxRefundApi.create(wechatpayordernumber, merchantpaymentnumber,
+                    swRefundRequestRecordDO.getRefundamount().multiply(BigDecimal.valueOf(100)).longValue(),
+                    swRefundRequestRecordDO.getPaidin().multiply(BigDecimal.valueOf(100)).longValue(),
+                    swRefundRequestRecordDO.getRefundreason(),
+                    nonceStr, dskey);
+        } catch (ServiceException e) {
+            if (e.getHttpStatusCode() == 403) {
+                // 获取异常原因
+                String errorMessage = e.getErrorMessage();
+                // 将商户单号保存之退款记录表
+                swRefundRequestRecordService.update(new LambdaUpdateWrapper<SwRefundRequestRecordDO>()
+                        .eq(SwRefundRequestRecordDO::getId, refundRequestId)
+                        .set(SwRefundRequestRecordDO::getRefundstatus, 4)
+                        .set(SwRefundRequestRecordDO::getHasbeenrefunded, errorMessage));
+                return R.error("退款申请失败,原因是:"+errorMessage);
+            }
+        }
+        // 将商户单号保存之退款记录表
+        swRefundRequestRecordService.update(new LambdaUpdateWrapper<SwRefundRequestRecordDO>()
+                .eq(SwRefundRequestRecordDO::getId, refundRequestId)
+                .set(SwRefundRequestRecordDO::getRefundstatus, 2)
+                .set(SwRefundRequestRecordDO::getMerchantrefundnumber, nonceStr));
+        return R.ok("退款申请已提交,请稍后查看退款结果");
+    }
+
+    /**
+     * 退款申请成功回调函数
+     *
+     * @param prepayNoticeVo
+     * @param dsKey
+     * @return
+     */
+    @Override
+    public R refundNotice(PrepayNoticeVo prepayNoticeVo, String dsKey) {
+        log.info("微信退款申请成功回调函数: {},: {}", prepayNoticeVo, dsKey);
+        if (StringUtils.isBlank(dsKey) || StringUtils.isNotBlank(dsKey)) {
+            throw new CustomException("asdasda");
+        }
+        List<String> dsKeys;
+        if (StringUtils.isBlank(dsKey)) {
+            List<TenantDo> tenantList = (List<TenantDo>) redisService.getRedisCatchObj("allTenants");
+            // 获取 所有的主库信息
+            dsKeys = tenantList.stream().map(TenantDo::getDskey).collect(Collectors.toList());
+        } else {
+            dsKeys = Collections.singletonList(dsKey);
+        }
+        dsKeys.remove("incontrol");
+        // 获取所有商户的密钥
+        List<SwEnterpriseConfigInfoDo> secretKeyList = commonBusinessDao.getSecretKey(dsKeys);
+        String analysisStr = null;
+        String deKey = null;
+        for (SwEnterpriseConfigInfoDo swEnterpriseConfigInfoDo : secretKeyList) {
+            try {
+                byte[] apiV3Key = swEnterpriseConfigInfoDo.getMerchantsecretkey().getBytes("UTF8");
+                byte[] nonce = prepayNoticeVo.getResource().getNonce().getBytes("UTF8");
+                String ciphertext = prepayNoticeVo.getResource().getCiphertext();
+                byte[] associatedData = prepayNoticeVo.getResource().getAssociated_data().getBytes("UTF8");
+                Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+                SecretKeySpec key = new SecretKeySpec(apiV3Key, "AES");
+                GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
+                cipher.init(Cipher.DECRYPT_MODE, key, spec);
+                cipher.updateAAD(associatedData);
+                analysisStr = new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
+                deKey = swEnterpriseConfigInfoDo.getTenantid();
+                if (StringUtils.isNotBlank(analysisStr)) {
+                    break;
+                }
+            } catch (Exception e) {
+                log.error("当前租户:{}解密异常", swEnterpriseConfigInfoDo.getTenantid());
+            }
+        }
+        if (StringUtils.isBlank(analysisStr)) {
+            log.error("回调函数解析异常");
+            return R.error();
+        }
+        ObjectMapper mapper = new ObjectMapper();
+        WeChatRefundNoticeVo weChatRefundNoticeVo;
+        try {
+            weChatRefundNoticeVo = mapper.readValue(analysisStr, WeChatRefundNoticeVo.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+            log.error("JSON转换异常");
+            return R.error();
+        }
+
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = attributes.getRequest();
+        // 设置租户信息 自动切库
+        request.setAttribute(Constants.SAAS_LOGIN_TOKEN, deKey);
+
+        String refundId = weChatRefundNoticeVo.getRefundId();
+        String outRefundNo = weChatRefundNoticeVo.getOutRefundNo();
+        SwRefundRequestRecordDO swRefundRequestRecordDO = swRefundRequestRecordService.getOne(new LambdaQueryWrapper<SwRefundRequestRecordDO>()
+                .eq(BaseDo::getDeleted, "0").eq(SwRefundRequestRecordDO::getMerchantrefundnumber, outRefundNo));
+        if (swRefundRequestRecordDO == null) {
+            log.error("退款记录失败");
+            throw new CustomException("退款失败");
+        }
+        if ("SUCCESS".equals(weChatRefundNoticeVo.getRefundStatus())) {
+            log.error("退款失败");
+            // 更新缴费记录相关信息
+            swRefundRequestRecordService.getBaseMapper().updateWeChatRefundInfo(deKey, outRefundNo,
+                    refundId, analysisStr, weChatRefundNoticeVo.getSuccessTime(), "4");
+            return R.ok();
+        }
+        // 更新缴费记录相关信息
+        swRefundRequestRecordService.getBaseMapper().updateWeChatRefundInfo(deKey, outRefundNo,
+                refundId, analysisStr, weChatRefundNoticeVo.getSuccessTime(), "3");
+
+        swRefundRequestRecordService.refundApplication(swRefundRequestRecordDO.getId());
+        return R.ok();
+    }
+}

+ 14 - 0
zhsw-common/src/main/resources/mybatis/zhsw/SwRefundRequestRecordDao.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.rongwei.zhsw.system.dao.SwRefundRequestRecordDao">
+        <update id="updateWeChatRefundInfo">
+            update sw_refund_request_record
+            set WECHATREFUNDORDERNUMBER=#{wechatNo},
+                REFUNDSTATUS=#{state},
+                REFUNDNOTICEDETAILS =#{desc},
+                REFUNDTIME=#{successTime}
+            where MERCHANTREFUNDNUMBER = #{orderNo}
+        </update>
+</mapper>

+ 17 - 6
zhsw-entity/src/main/java/com/rongwe/zhsw/system/domain/SwRefundRequestRecordDO.java

@@ -1,15 +1,15 @@
 package com.rongwe.zhsw.system.domain;
- 
-import java.math.BigDecimal;
-import java.util.Date;
-import java.io.Serializable;
-import com.baomidou.mybatisplus.annotation.TableField;
+
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.rongwei.rwcommon.base.BaseDo;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
 
 /**
  * 退款申请记录(SwRefundRequestRecord)实体类
@@ -90,8 +90,19 @@ public class SwRefundRequestRecordDO extends BaseDo implements Serializable {
     private Date chargedate;
     //是否已退款
     private String hasbeenrefunded;
-    //退款状态 REFUNDSTATUS
     private String refundstatus;
 
+    /**
+     * 微信或支付宝等第三方交易的退款回调通知
+     */
+    private String refundnoticedetails;
+    /**
+     * 商户退款编号
+     */
+    private String merchantrefundnumber;
+    /**
+     * 微信退款订单号
+     */
+    private String wechatrefundordernumber;
 
 }

+ 17 - 0
zhsw-entity/src/main/java/com/rongwe/zhsw/system/vo/RefundInitiateVo.java

@@ -0,0 +1,17 @@
+package com.rongwe.zhsw.system.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * RefundVo class
+ *
+ * @author XH
+ * @date 2025/03/26
+ */
+@Data
+public class RefundInitiateVo {
+    // 退款申请记录ID
+    private String refundRequestId;
+}

+ 57 - 0
zhsw-entity/src/main/java/com/rongwe/zhsw/system/vo/WeChatRefundNoticeVo.java

@@ -0,0 +1,57 @@
+package com.rongwe.zhsw.system.vo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * WeChatRefundVo class
+ *
+ * @author XH
+ * @date 2025/03/26
+ */
+@Data
+public class WeChatRefundNoticeVo {
+    // 商户号
+    private String mchid;
+
+    // 微信支付订单号
+    private String transactionId;
+
+    // 商户系统内部订单号
+    private String outTradeNo;
+
+    // 微信退款单号
+    private String refundId;
+
+    // 商户退款单号
+    private String outRefundNo;
+
+    // 退款状态(SUCCESS/PROCESSING等)
+    private String refundStatus;
+
+    // 退款成功时间(ISO 8601格式)
+    private Date successTime;
+
+    // 收款方账户信息(银行+卡类型+末四位)
+    private String userReceivedAccount;
+
+    // 金额相关嵌套对象
+    private Amount amount;
+
+    @Data
+    // 金额内部类
+    public static class Amount {
+        // 订单总金额(单位:分)
+        private Integer total;
+
+        // 退款金额(单位:分)
+        private Integer refund;
+
+        // 付款方支付总金额(单位:分)
+        private Integer payerTotal;
+
+        // 付款方实退金额(单位:分)
+        private Integer payerRefund;
+    }
+}

+ 50 - 0
zhsw-server/src/main/java/com/rongwei/zhsw/system/controller/RefundController.java

@@ -0,0 +1,50 @@
+package com.rongwei.zhsw.system.controller;
+
+import com.rongwe.zhsw.system.vo.PrepayNoticeVo;
+import com.rongwe.zhsw.system.vo.RefundInitiateVo;
+import com.rongwei.rwcommon.base.R;
+import com.rongwei.zhsw.system.controller.weChat.PayMentController;
+import com.rongwei.zhsw.system.wechat.impl.RefundServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * RefundController class
+ *
+ * @author XH
+ * @date 2025/03/26
+ */
+@RestController
+@RequestMapping("/refund")
+public class RefundController {
+
+    private static final Logger log = LoggerFactory.getLogger(PayMentController.class);
+    @Autowired
+    private RefundServiceImpl refundService;
+
+    /**
+     * 预下单
+     *
+     * @param vo
+     * @return
+     */
+    @PostMapping("/initiate")
+    public R refundByRecord(@RequestBody RefundInitiateVo vo) {
+        return refundService.refundByRecord(vo);
+    }
+
+    /**
+     * 微信支付成功回调函数
+     *
+     * @param prepayNoticeVo
+     * @return
+     */
+    @PostMapping("/notice/{dskey}")
+    public R refundNotice(@RequestBody PrepayNoticeVo prepayNoticeVo, @PathVariable("dskey") String dskey) {
+        return refundService.refundNotice(prepayNoticeVo, dskey);
+    }
+}

+ 2 - 3
zhsw-server/src/main/java/com/rongwei/zhsw/system/controller/SwRefundRequestRecordController.java

@@ -18,8 +18,7 @@ public class SwRefundRequestRecordController {
 
     @PostMapping("/refundApplication")
     @ResponseBody
-    public R refundApplication(@RequestBody Map<String, Object> map) throws Exception {
-        swRefundRequestRecordService.refundApplication(map.get("id").toString());
-        return R.ok();
+    public R refundApplication(@RequestBody Map<String, Object> map) {
+        return swRefundRequestRecordService.refundApplication(map.get("id").toString());
     }
 }