Răsfoiți Sursa

新增订单退款公共模块

mac 2 ani în urmă
părinte
comite
099b7d3bc9
17 a modificat fișierele cu 413 adăugiri și 136 ștergeri
  1. 3 7
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/handlers/PayEventHandlers.java
  2. 1 1
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/PayRequest.java
  3. 30 0
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/RefundRequest.java
  4. 39 0
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/RefundResponse.java
  5. 10 8
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/PayService.java
  6. 102 59
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/ali/AliPayService.java
  7. 6 6
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/wechat/WxPayService.java
  8. 19 11
      kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/yue/YuePayService.java
  9. 23 33
      kxs-product/kxs-product-biz/src/main/java/com/kxs/product/biz/service/impl/KxsShopOrderServiceImpl.java
  10. 30 0
      kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/dto/kxsapp/userAccount/RefundRequestDTO.java
  11. 13 2
      kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/feign/RemoteYuePayService.java
  12. 38 0
      kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/vo/kxsapp/userAccount/RefundResVO.java
  13. 1 1
      kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/constant/enums/YuePayStatusEnum.java
  14. 20 3
      kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/controller/kxsapp/UserAccountController.java
  15. 7 1
      kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/KxsUserAmountService.java
  16. 40 4
      kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/impl/KxsUserAmountServiceImpl.java
  17. 31 0
      kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/impl/KxsUserServiceImpl.java

+ 3 - 7
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/handlers/PayEventHandlers.java

@@ -1,6 +1,5 @@
 package com.kxs.common.pay.handlers;
 
-import com.alipay.api.AlipayApiException;
 import com.kxs.common.pay.factory.PaymentFactory;
 import com.kxs.common.pay.service.PayService;
 import jakarta.servlet.http.HttpServletRequest;
@@ -25,12 +24,9 @@ public class PayEventHandlers {
 
     @RequestMapping(value = "payBack/{platform}")
     public String payBack(HttpServletRequest request, @PathVariable String platform) {
-        try {
-            PayService payService = paymentFactory.getPayService(platform);
-            return payService.payBack(request);
-        } catch (AlipayApiException e) {
-            throw new RuntimeException(e);
-        }
+
+        PayService payService = paymentFactory.getPayService(platform);
+        return payService.payBack(request);
     }
 
 }

+ 1 - 1
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/PayRequest.java

@@ -38,7 +38,7 @@ public class PayRequest {
     private String goodsDetail;
 
     /**
-     * 公用回传参数
+     * 公用回传参数 后期可区分多个支付线的回调
      */
     private String passbackParams;
 }

+ 30 - 0
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/RefundRequest.java

@@ -0,0 +1,30 @@
+package com.kxs.common.pay.model;
+
+import com.kxs.common.pay.enums.PayPlatformEnum;
+import lombok.Data;
+
+/**
+ * 退款请求
+ *
+ * @author 没秃顶的码农
+ * @date 2024-04-24
+ */
+@Data
+public class RefundRequest {
+
+    /**
+     * 支付类型枚举
+     */
+    private PayPlatformEnum payTypeEnum;
+
+    /**
+     * 商户网站唯一订单号
+     */
+    private String outTradeNo;
+
+    /**
+     * 退款原因
+     */
+    private String refundReason;
+
+}

+ 39 - 0
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/model/RefundResponse.java

@@ -0,0 +1,39 @@
+package com.kxs.common.pay.model;
+
+import com.kxs.common.pay.enums.PayPlatformEnum;
+import com.kxs.common.pay.enums.PayStatusCommEnum;
+import lombok.Builder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 退款响应公共类
+ *
+ * @author 没秃顶的码农
+ * @date 2024-04-24
+ */
+@Data
+@Builder
+public class RefundResponse {
+
+    /**
+     * 支付平台枚举
+     */
+    private PayPlatformEnum payPlatformEnum;
+
+    /**
+     * 商户网站唯一订单号
+     */
+    private String outTradeNo;
+
+    /**
+     * 交易号
+     */
+    private String tradeNo;
+
+    /**
+     * 交易的订单金额 元
+     */
+    private BigDecimal refundFee;
+}

+ 10 - 8
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/PayService.java

@@ -1,14 +1,10 @@
 package com.kxs.common.pay.service;
 
 import cn.hutool.extra.spring.SpringUtil;
-import com.alipay.api.AlipayApiException;
 import com.kxs.common.core.exception.GlobalCustomerException;
 import com.kxs.common.pay.enums.PayPlatformEnum;
 import com.kxs.common.pay.handlers.PayMessageHandler;
-import com.kxs.common.pay.model.PayRequest;
-import com.kxs.common.pay.model.PayResponse;
-import com.kxs.common.pay.model.QueryRequest;
-import com.kxs.common.pay.model.QueryResponse;
+import com.kxs.common.pay.model.*;
 import jakarta.servlet.http.HttpServletRequest;
 import org.springframework.core.Ordered;
 
@@ -27,17 +23,23 @@ public interface PayService {
     /**
      * 支付
      */
-    PayResponse appPay(PayRequest payReq) throws AlipayApiException;
+    PayResponse appPay(PayRequest payReq);
 
     /**
      * 查询
      */
-    QueryResponse query(QueryRequest queryReq) throws AlipayApiException;
+    QueryResponse query(QueryRequest queryReq);
+
+    /**
+     * 退款
+     */
+    RefundResponse refund(RefundRequest queryReq);
+
 
     /**
      * 回调
      */
-    String payBack(HttpServletRequest request) throws AlipayApiException;
+    String payBack(HttpServletRequest request);
 
     /**
      * 获取支付回调handler

+ 102 - 59
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/ali/AliPayService.java

@@ -4,16 +4,18 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.spring.SpringUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
 import com.alipay.api.domain.AlipayTradeQueryModel;
+import com.alipay.api.domain.AlipayTradeRefundModel;
 import com.alipay.api.internal.util.AlipaySignature;
 import com.alipay.api.request.AlipayTradeAppPayRequest;
 import com.alipay.api.request.AlipayTradeQueryRequest;
+import com.alipay.api.request.AlipayTradeRefundRequest;
 import com.alipay.api.response.AlipayTradeAppPayResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.alipay.api.response.AlipayTradeRefundResponse;
 import com.kxs.common.core.exception.GlobalCustomerException;
 import com.kxs.common.pay.config.AliPayAccountConfig;
 import com.kxs.common.pay.enums.PayConstants;
@@ -25,13 +27,11 @@ import com.kxs.common.pay.service.PayService;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.core.Ordered;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
 
 /**
  * 支付宝支付服务
@@ -48,75 +48,118 @@ public class AliPayService implements PayService {
     private final AliPayAccountConfig aliPayAccountConfig;
 
     @Override
-    public PayResponse appPay(PayRequest payReq) throws AlipayApiException {
-
-        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
-        //回掉地址
-        request.setNotifyUrl(aliPayAccountConfig.getNotifyUrl());
-        JSONObject bizContent = new JSONObject();
-        //支付信息
-        bizContent.put("out_trade_no", payReq.getOutTradeNo());
-        bizContent.put("total_amount", payReq.getTotalAmount());
-        bizContent.put("subject", payReq.getSubject());
-        bizContent.put("product_code", "QUICK_MSECURITY_PAY");
-        bizContent.put("time_expire", LocalDateTimeUtil.format(LocalDateTime.now().plusMinutes(20), DatePattern.NORM_DATETIME_PATTERN));
-        //商品信息
-        if(StrUtil.isNotBlank(payReq.getGoodsDetail())){
-            bizContent.put("goods_detail", payReq.getPassbackParams());
-        }
-        //扩展参数
-        if(StrUtil.isNotBlank(payReq.getPassbackParams())){
-            bizContent.put("passback_params", payReq.getPassbackParams());
+    public PayResponse appPay(PayRequest payReq){
+        try {
+            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
+            //回掉地址
+            request.setNotifyUrl(aliPayAccountConfig.getNotifyUrl());
+            JSONObject bizContent = new JSONObject();
+            //支付信息
+            bizContent.put("out_trade_no", payReq.getOutTradeNo());
+            bizContent.put("total_amount", payReq.getTotalAmount());
+            bizContent.put("subject", payReq.getSubject());
+            bizContent.put("product_code", "QUICK_MSECURITY_PAY");
+            bizContent.put("time_expire", LocalDateTimeUtil.format(LocalDateTime.now().plusMinutes(20), DatePattern.NORM_DATETIME_PATTERN));
+            //商品信息
+            if(StrUtil.isNotBlank(payReq.getGoodsDetail())){
+                bizContent.put("goods_detail", payReq.getPassbackParams());
+            }
+            //扩展参数
+            if(StrUtil.isNotBlank(payReq.getPassbackParams())){
+                bizContent.put("passback_params", payReq.getPassbackParams());
+            }
+            request.setBizContent(bizContent.toString());
+
+            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
+            String orderStr = response.getBody();
+            if(response.isSuccess()){
+                return PayResponse.builder()
+                        .result(orderStr)
+                        .payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+            }
+            return PayResponse.builder().payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+        } catch (AlipayApiException e) {
+            log.error("支付宝支付异常:{}", payReq.getOutTradeNo(), e);
+            throw new GlobalCustomerException("支付宝参数异常");
         }
-        request.setBizContent(bizContent.toString());
-        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
-        String orderStr = response.getBody();
-        if(response.isSuccess()){
-            return PayResponse.builder()
-                    .result(orderStr)
-                    .payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+    }
+
+    @Override
+    public QueryResponse query(QueryRequest queryReq){
+        try {
+            // 构造请求参数以调用接口
+            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
+
+            // 设置订单支付时传入的商户订单号
+            model.setOutTradeNo(queryReq.getOutTradeNo());
+
+            request.setBizModel(model);
+
+            AlipayTradeQueryResponse response = alipayClient.execute(request);
+            if (response.isSuccess()) {
+                return QueryResponse.builder()
+                        .outTradeNo(response.getOutTradeNo())
+                        .tradeNo(response.getTradeNo())
+                        .buyerLogonId(response.getBuyerLogonId())
+                        .tradeStatus(PayStatusCommEnum.valueOf(response.getTradeStatus()))
+                        .payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+            }
+        } catch (AlipayApiException e) {
+            log.error("支付宝查询异常:{}", queryReq.getOutTradeNo(), e);
+            throw new GlobalCustomerException("支付宝查询异常");
         }
-        return PayResponse.builder().payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+        return null;
     }
 
     @Override
-    public QueryResponse query(QueryRequest queryReq) throws AlipayApiException {
-        // 构造请求参数以调用接口
-        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
-        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
-
-        // 设置订单支付时传入的商户订单号
-        model.setOutTradeNo(queryReq.getOutTradeNo());
-
-        request.setBizModel(model);
-        AlipayTradeQueryResponse response = alipayClient.execute(request);
-        if (response.isSuccess()) {
-            return QueryResponse.builder()
-                    .outTradeNo(response.getOutTradeNo())
-                    .tradeNo(response.getTradeNo())
-                    .buyerLogonId(response.getBuyerLogonId())
-                    .tradeStatus(PayStatusCommEnum.valueOf(response.getTradeStatus()))
-                    .payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+    public RefundResponse refund(RefundRequest refundReq) {
+        try {
+            // 构造请求参数以调用接口
+            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
+
+            // 设置订单支付时传入的商户订单号
+            model.setOutTradeNo(refundReq.getOutTradeNo());
+
+            request.setBizModel(model);
+
+            AlipayTradeRefundResponse response = alipayClient.execute(request);
+            if (response.isSuccess()) {
+                return RefundResponse.builder()
+                        .outTradeNo(response.getOutTradeNo())
+                        .tradeNo(response.getTradeNo())
+                        .refundFee(new BigDecimal(response.getRefundFee()))
+                        .payPlatformEnum(PayPlatformEnum.ALIPAY).build();
+            }
+        } catch (AlipayApiException e) {
+            log.error("支付宝查询异常:{}", refundReq.getOutTradeNo(), e);
+            throw new GlobalCustomerException("支付宝查询异常");
         }
         return null;
     }
 
 
     @Override
-    public String payBack(HttpServletRequest request) throws AlipayApiException {
+    public String payBack(HttpServletRequest request){
+        try {
 
-        Map<String, String> noticeParams = getNoticeParams(request);
+            Map<String, String> noticeParams = getNoticeParams(request);
 
-        boolean signVerified = AlipaySignature.rsaCheckV2(noticeParams, aliPayAccountConfig.getAliPayPublicKey(), "UTF-8", aliPayAccountConfig.getSignType());
-        if (!signVerified) {
-            log.error("alipay notifies that signature verification failed");
-            return PayConstants.ALI_PAY_FAIL;
+            boolean signVerified = AlipaySignature.rsaCheckV2(noticeParams, aliPayAccountConfig.getAliPayPublicKey(), "UTF-8", aliPayAccountConfig.getSignType());
+            if (!signVerified) {
+                log.error("alipay notifies that signature verification failed");
+                return PayConstants.ALI_PAY_FAIL;
+            }
+            AliPayMessage aliPayMessage = BeanUtil.toBean(noticeParams, AliPayMessage.class);
+            aliPayMessage.setPayMessage(noticeParams);
+            aliPayMessage.setPayType(PayPlatformEnum.ALIPAY);
+            PayMessageHandler payMessageHandler = getPayMessageHandler(PayPlatformEnum.ALIPAY);
+
+            return payMessageHandler.handle(aliPayMessage, this);
+        } catch (AlipayApiException e) {
+            throw new GlobalCustomerException("支付宝回调异常");
         }
-        AliPayMessage aliPayMessage = BeanUtil.toBean(noticeParams, AliPayMessage.class);
-        aliPayMessage.setPayMessage(noticeParams);
-        aliPayMessage.setPayType(PayPlatformEnum.ALIPAY);
-        PayMessageHandler payMessageHandler = getPayMessageHandler(PayPlatformEnum.ALIPAY);
-        return payMessageHandler.handle(aliPayMessage, this);
     }
 
 

+ 6 - 6
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/wechat/WxPayService.java

@@ -1,12 +1,7 @@
 package com.kxs.common.pay.service.wechat;
 
 import com.kxs.common.pay.config.WechatAccountConfig;
-import com.kxs.common.pay.enums.PayPlatformEnum;
-import com.kxs.common.pay.handlers.PayMessageHandler;
-import com.kxs.common.pay.model.PayRequest;
-import com.kxs.common.pay.model.PayResponse;
-import com.kxs.common.pay.model.QueryRequest;
-import com.kxs.common.pay.model.QueryResponse;
+import com.kxs.common.pay.model.*;
 import com.kxs.common.pay.service.PayService;
 import com.lly835.bestpay.config.WxPayConfig;
 import jakarta.servlet.http.HttpServletRequest;
@@ -36,6 +31,11 @@ public class WxPayService implements PayService {
         return null;
     }
 
+    @Override
+    public RefundResponse refund(RefundRequest refundReq) {
+        return null;
+    }
+
     @Override
     public String payBack(HttpServletRequest request) {
         return null;

+ 19 - 11
kxs-common/kxs-common-pay/src/main/java/com/kxs/common/pay/service/yue/YuePayService.java

@@ -1,28 +1,19 @@
 package com.kxs.common.pay.service.yue;
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.extra.spring.SpringUtil;
 import com.alibaba.fastjson.JSON;
-import com.kxs.common.core.constant.enums.ErrorTypeEnum;
+import com.kxs.common.core.constant.SecurityConstants;
 import com.kxs.common.core.exception.GlobalCustomerException;
 import com.kxs.common.core.util.R;
-import com.kxs.common.core.util.RetOps;
-import com.kxs.common.pay.config.WechatAccountConfig;
 import com.kxs.common.pay.enums.PayPlatformEnum;
-import com.kxs.common.pay.handlers.PayMessageHandler;
 import com.kxs.common.pay.model.*;
 import com.kxs.common.pay.service.PayService;
 import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
-import com.kxs.user.api.feign.RemoteKxsUserService;
+import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
 import com.kxs.user.api.feign.RemoteYuePayService;
-import com.kxs.user.api.model.KxsUser;
-import com.lly835.bestpay.config.WxPayConfig;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
-import org.springframework.core.Ordered;
 
-import java.util.Comparator;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -60,6 +51,23 @@ public class YuePayService implements PayService {
         return null;
     }
 
+    @Override
+    public RefundResponse refund(RefundRequest refundReq) {
+
+        RefundRequestDTO refundRequestDTO = new RefundRequestDTO();
+        BeanUtil.copyProperties(refundReq, refundRequestDTO);
+        R result = remoteYuePayService.refund(refundRequestDTO, SecurityConstants.FROM_IN);
+        if (result.getStatus() != 1) {
+            throw new GlobalCustomerException(result.getMsg());
+        }
+        RefundResponse refundResponse = BeanUtil.toBean(result.getData(), RefundResponse.class);
+
+        Optional.ofNullable(refundResponse).orElseThrow(() -> new GlobalCustomerException("yue refund is empty"));
+
+        return refundResponse;
+
+    }
+
     @Override
     public String payBack(HttpServletRequest request) {
         return null;

+ 23 - 33
kxs-product/kxs-product-biz/src/main/java/com/kxs/product/biz/service/impl/KxsShopOrderServiceImpl.java

@@ -330,27 +330,22 @@ public class KxsShopOrderServiceImpl extends ServiceImpl<KxsShopOrderMapper, Kxs
     @Override
     public void changeTimeoutOrder(KxsShopOrder order) {
 
-        try {
-
-            order.setStatus(KxsShopEnum.ORDER_CANCEL.getType());
+        order.setStatus(KxsShopEnum.ORDER_CANCEL.getType());
 
-            QueryResponse query = null;
-            QueryRequest queryReq = QueryRequest.builder()
-                    .outTradeNo(order.getOrderSn())
-                    .build();
-            if (order.getPayType().equals(KxsShopEnum.ALI_PAY.getType())) {
-                query = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).query(queryReq);
-            }
-            if (order.getPayType().equals(KxsShopEnum.WECHAT_PAY.getType())) {
-                query = paymentFactory.getPayService(PayPlatformEnum.WX.getType()).query(queryReq);
-            }
-            if (query != null) {
-                order.setStatus(PayStatusCommEnum.TRADE_SUCCESS == query.getTradeStatus() ? KxsShopEnum.ORDER_NO_SEND.getType() : KxsShopEnum.ORDER_CANCEL.getType());
-            }
-            updateById(order);
-        } catch (AlipayApiException e) {
-            throw new RuntimeException(e);
+        QueryResponse query = null;
+        QueryRequest queryReq = QueryRequest.builder()
+                .outTradeNo(order.getOrderSn())
+                .build();
+        if (order.getPayType().equals(KxsShopEnum.ALI_PAY.getType())) {
+            query = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).query(queryReq);
         }
+        if (order.getPayType().equals(KxsShopEnum.WECHAT_PAY.getType())) {
+            query = paymentFactory.getPayService(PayPlatformEnum.WX.getType()).query(queryReq);
+        }
+        if (query != null) {
+            order.setStatus(PayStatusCommEnum.TRADE_SUCCESS == query.getTradeStatus() ? KxsShopEnum.ORDER_NO_SEND.getType() : KxsShopEnum.ORDER_CANCEL.getType());
+        }
+        updateById(order);
     }
 
     /**
@@ -463,22 +458,17 @@ public class KxsShopOrderServiceImpl extends ServiceImpl<KxsShopOrderMapper, Kxs
      */
     private R aliPay(KxsShopOrder param, String subject) {
 
-        try {
-            PayRequest payReq = new PayRequest();
-            payReq.setPayTypeEnum(PayPlatformEnum.ALIPAY);
-            payReq.setOutTradeNo(param.getOrderSn());
-            payReq.setSubject(subject);
-            payReq.setTotalAmount(param.getPayPrice().doubleValue());
-            //扩展参数
-            payReq.setPassbackParams(CommonConstants.SHOP_ORDER_FLAG);
+        PayRequest payReq = new PayRequest();
+        payReq.setPayTypeEnum(PayPlatformEnum.ALIPAY);
+        payReq.setOutTradeNo(param.getOrderSn());
+        payReq.setSubject(subject);
+        payReq.setTotalAmount(param.getPayPrice().doubleValue());
+        //扩展参数
+        payReq.setPassbackParams(CommonConstants.SHOP_ORDER_FLAG);
 
-            PayResponse payResponse = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).appPay(payReq);
+        PayResponse payResponse = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).appPay(payReq);
 
-            return R.ok(payResponse);
-        } catch (AlipayApiException e) {
-            log.error("支付宝支付异常:{}", param.getOrderSn(), e);
-            throw new GlobalCustomerException("支付宝参数异常");
-        }
+        return R.ok(payResponse);
     }
 
 

+ 30 - 0
kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/dto/kxsapp/userAccount/RefundRequestDTO.java

@@ -0,0 +1,30 @@
+package com.kxs.user.api.dto.kxsapp.userAccount;
+
+import lombok.Data;
+
+/**
+ * 退款请求
+ *
+ * @author 没秃顶的码农
+ * @date 2024-04-24
+ */
+@Data
+public class RefundRequestDTO {
+
+
+    /**
+     * 商户网站唯一订单号
+     */
+    private String outTradeNo;
+
+    /**
+     * 公用回传参数
+     */
+    private String passbackParams;
+
+    /**
+     * 退款原因
+     */
+    private String refundReason;
+
+}

+ 13 - 2
kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/feign/RemoteYuePayService.java

@@ -1,13 +1,14 @@
 
 package com.kxs.user.api.feign;
 
+import com.kxs.common.core.constant.SecurityConstants;
 import com.kxs.common.core.util.R;
 import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
+import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.service.annotation.PostExchange;
 
-import java.util.Map;
-
 /**
  * @author Lxq
  * @date 2023/6/22
@@ -19,4 +20,14 @@ public interface RemoteYuePayService {
 	 */
 	@PostExchange("/userAccount/yuePay")
 	R yuePay(@RequestBody PayRequestDTO payReq);
+
+	/**
+	 * 余额退款
+	 *
+	 * @param refundReq 退款要求
+	 * @return {@link R}
+	 */
+	@PostExchange("userAccount/refund")
+	R refund(RefundRequestDTO refundReq, @RequestHeader(SecurityConstants.FROM) String from);
+
 }

+ 38 - 0
kxs-user/kxs-user-api/src/main/java/com/kxs/user/api/vo/kxsapp/userAccount/RefundResVO.java

@@ -0,0 +1,38 @@
+package com.kxs.user.api.vo.kxsapp.userAccount;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 退款响应
+ *
+ * @author 没秃顶的码农
+ * @date 2024-04-24
+ */
+@Data
+@Builder
+public class RefundResVO {
+
+
+    /**
+     * 商户网站唯一订单号
+     */
+    private String outTradeNo;
+
+    /**
+     * 交易号
+     */
+    private String tradeNo;
+
+    /**
+     * 交易的订单金额 元
+     */
+    private BigDecimal refundFee;
+
+    /**
+     * 公用回传参数
+     */
+    private String passbackParams;
+}

+ 1 - 1
kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/constant/enums/YuePayStatusEnum.java

@@ -16,7 +16,7 @@ public enum YuePayStatusEnum {
 
 
     SUCCESS(1, "支付成功"),
-    RETURN(-1, "退款");
+    REFUND(-1, "退款");
 
     /**
      * 类型

+ 20 - 3
kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/controller/kxsapp/UserAccountController.java

@@ -3,8 +3,10 @@ package com.kxs.user.biz.controller.kxsapp;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.kxs.common.core.util.R;
+import com.kxs.common.security.annotation.Inner;
 import com.kxs.common.security.util.SecurityUtils;
 import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
+import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
 import com.kxs.user.api.dto.kxsapp.userAccount.UserAmountVariationListDTO;
 import com.kxs.user.api.dto.kxsapp.userAccount.WithdrawDepositDTO;
 import com.kxs.user.api.model.KxsUserAdvance;
@@ -191,13 +193,28 @@ public class UserAccountController {
      * 内部调用
      * 余额支付
      *
-     * @param payReq 支付参数
+     * @param req 支付参数
      * @return {@link R}
      */
+    @Inner
     @PostMapping("/yuePay")
-    public R yuePay(@RequestBody PayRequestDTO payReq){
+    public R yuePay(@RequestBody PayRequestDTO req){
 
-        return kxsUserAmountService.yuePay(payReq);
+        return kxsUserAmountService.yuePay(req);
+    }
+
+    /**
+     * 内部调用
+     * 余额退款
+     *
+     * @param req 支付参数
+     * @return {@link R}
+     */
+    @Inner
+    @PostMapping("/refund")
+    public R refund(@RequestBody RefundRequestDTO req){
+
+        return kxsUserAmountService.refund(req);
     }
 
 

+ 7 - 1
kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/KxsUserAmountService.java

@@ -3,6 +3,7 @@ package com.kxs.user.biz.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.kxs.common.core.util.R;
 import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
+import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
 import com.kxs.user.api.model.KxsUserAmount;
 import com.kxs.user.api.model.KxsUserAmountLog;
 import com.kxs.user.api.vo.kxsapp.userAccount.MyAccountVO;
@@ -33,6 +34,11 @@ public interface KxsUserAmountService extends IService<KxsUserAmount> {
     /**
      * 余额支付
      */
-    R yuePay(PayRequestDTO payReq);
+    R yuePay(PayRequestDTO req);
+
+    /**
+     * 退款
+     */
+    R refund(RefundRequestDTO req);
 }
 

+ 40 - 4
kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/impl/KxsUserAmountServiceImpl.java

@@ -9,12 +9,15 @@ import com.kxs.common.core.util.R;
 import com.kxs.common.core.util.SysUtils;
 import com.kxs.common.mybatis.handler.MonthTableNameHandler;
 import com.kxs.common.security.util.SecurityUtils;
+import com.kxs.system.api.util.ParamResolver;
 import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
+import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
 import com.kxs.user.api.model.KxsUserAdvance;
 import com.kxs.user.api.model.KxsUserAmount;
 import com.kxs.user.api.model.KxsUserAmountLog;
 import com.kxs.user.api.model.KxsUserYuepay;
 import com.kxs.user.api.vo.kxsapp.userAccount.MyAccountVO;
+import com.kxs.user.api.vo.kxsapp.userAccount.RefundResVO;
 import com.kxs.user.biz.constant.enums.YuePayStatusEnum;
 import com.kxs.user.biz.mapper.KxsUserAdvanceMapper;
 import com.kxs.user.biz.mapper.KxsUserAmountMapper;
@@ -22,14 +25,12 @@ import com.kxs.user.biz.service.KxsUserAmountLogService;
 import com.kxs.user.biz.service.KxsUserAmountService;
 import com.kxs.user.biz.service.KxsUserYuepayService;
 import lombok.RequiredArgsConstructor;
-import lombok.Synchronized;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.util.Objects;
-import java.util.UUID;
 
 /**
  * 用户账户表(KxsUserAmount)表服务实现类
@@ -61,7 +62,7 @@ public class KxsUserAmountServiceImpl extends ServiceImpl<KxsUserAmountMapper, K
                 .select("IFNULL(SUM(amount), 0) as amount")
                 .eq("user_id", SecurityUtils.getUser().getId())
                 .eq("status", UserAdvanceStatusEnum.ADVANCE_NOT_CHARGED.getType()));
-        if(advance != null){
+        if (advance != null) {
             //余额减去预扣款金额
             myAccountVO.setUseAmount(NumberUtil.sub(userAmount.getAmount(), advance.getAmount()));
         }
@@ -115,7 +116,7 @@ public class KxsUserAmountServiceImpl extends ServiceImpl<KxsUserAmountMapper, K
         kxsUserAmountLog.setAmount(BigDecimal.valueOf(payReq.getTotalAmount()));
         kxsUserAmountLog.setUserId(userId.intValue());
         //余额支付
-        kxsUserAmountLog.setVariationType(20);
+        kxsUserAmountLog.setVariationType(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 20));
         kxsUserAmountLog.setRemark("购买" + payReq.getSubject());
         kxsUserAmountLog.setKind(KindTypeEnum.SUB.getType());
         Boolean b = this.userAmountChange(kxsUserAmountLog);
@@ -137,6 +138,41 @@ public class KxsUserAmountServiceImpl extends ServiceImpl<KxsUserAmountMapper, K
         return R.ok(kxsUserYuepay);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R refund(RefundRequestDTO req) {
+
+        KxsUserYuepay trade = kxsUserYuepayService.getOne(Wrappers.<KxsUserYuepay>lambdaQuery().eq(KxsUserYuepay::getOutTradeNo, req.getOutTradeNo()));
+        if (trade == null) {
+            return R.failed("订单号不存在");
+        }
+        if (!Objects.equals(trade.getTradeStatus(), YuePayStatusEnum.SUCCESS.getType())) {
+            return R.failed("订单号已退款");
+        }
+        trade.setTradeStatus(YuePayStatusEnum.REFUND.getType());
+        kxsUserYuepayService.updateById(trade);
+
+        //退回到余额
+        KxsUserAmount userAmount = this.getOne(Wrappers.<KxsUserAmount>lambdaQuery()
+                .eq(KxsUserAmount::getUserId, trade.getUserId()));
+        KxsUserAmountLog kxsUserAmountLog = new KxsUserAmountLog();
+        kxsUserAmountLog.setAmount(trade.getTradeAmount());
+        kxsUserAmountLog.setUserId(userAmount.getUserId());
+        //余额支付
+        kxsUserAmountLog.setVariationType(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 519));
+        kxsUserAmountLog.setRemark(req.getRefundReason());
+        kxsUserAmountLog.setKind(KindTypeEnum.ADD.getType());
+        Boolean b = this.userAmountChange(kxsUserAmountLog);
+        if (!b) {
+            return R.failed("退款失败");
+        }
+        return R.ok(RefundResVO.builder()
+                .outTradeNo(req.getOutTradeNo())
+                .passbackParams(req.getPassbackParams())
+                .tradeNo(trade.getTradeNo())
+                .refundFee(trade.getTradeAmount()).build());
+    }
+
 
 }
 

+ 31 - 0
kxs-user/kxs-user-biz/src/main/java/com/kxs/user/biz/service/impl/KxsUserServiceImpl.java

@@ -9,6 +9,9 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.SecureUtil;
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kxs.common.core.constant.CacheConstants;
@@ -49,6 +52,7 @@ import com.kxs.user.biz.service.KxsUserService;
 import com.kxs.user.biz.util.SmsUtils;
 import io.seata.spring.annotation.GlobalTransactional;
 import lombok.RequiredArgsConstructor;
+import nonapi.io.github.classgraph.json.JSONUtils;
 import org.checkerframework.checker.units.qual.K;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
@@ -630,6 +634,28 @@ public class KxsUserServiceImpl extends ServiceImpl<KxsUserMapper, KxsUser> impl
         return R.ok();
     }
 
+    private Boolean httpCheckReal(RealUserDTO param){
+        String query = "bankcard=" + param.getBankCode() + "&idcard=" + param.getIdCard() + "&name=" + param.getRealName();
+        String url = "https://bankcard3c.shumaidata.com/bankcard3c?" + query;
+        //调用三要素认证
+        String result = HttpRequest.get(url)
+                .header("Authorization", "APPCODE " + "8e5704921ca3422f80f0deb935a7ddc6")
+                .timeout(20000)
+                .execute().body();
+        JSONObject jsonObject = JSON.parseObject(result);
+        if(jsonObject == null){
+            return Boolean.FALSE;
+        }
+        if (!"200".equals(jsonObject.getString("code"))){
+            return Boolean.FALSE;
+        }
+        JSONObject data = jsonObject.getObject("data", JSONObject.class);
+        if(data != null && !"0".equals(data.getString("result"))){
+            throw new GlobalCustomerException(data.getString("desc"));
+        }
+        return Boolean.TRUE;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public R realUser(RealUserDTO param) {
@@ -639,6 +665,11 @@ public class KxsUserServiceImpl extends ServiceImpl<KxsUserMapper, KxsUser> impl
         }
         Long userId = SecurityUtils.getUser().getId();
         KxsUser user = this.getById(userId);
+
+        if(!httpCheckReal(param)){
+            return R.failed("实名信息验证不通过");
+        }
+
         //查询实名信息
         KxsUserReal userReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>lambdaQuery().eq(KxsUserReal::getUserId, user.getId()));
         if (userReal != null) {