Bläddra i källkod

fix 注册账号退款

zoujiajian 3 år sedan
förälder
incheckning
b1ba72e2c9

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/RegisterOrderDon.java

@@ -1,6 +1,5 @@
 package com.cyksj.model.entity;
 
-import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -76,6 +75,7 @@ public class RegisterOrderDon extends BaseEntity{
         hasPayment("已付款"),
         error("注册失败"),
         complete("已完成"),
+        refund("已退款"),
         ;
 
         private String desc;

+ 1 - 6
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -573,7 +573,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					outRefundNo,
 					orderDon.getMoney(),
 					wxOrderRefundReq.getRefundMoney(),
-					weChatConfig.getDomain() + "wx/refund/notify");
+					weChatConfig.getDomain() + "applets/order/wx/refund/notify");
 		}
 		//修改订单状态
 		orderDon.setStatus(OrderDon.Status.refund);
@@ -729,11 +729,6 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	@Override
 	public void wxRefundNotify(Map<String, String> map) throws Exception {
-		boolean f = weChatService.checkSignWithMd5(map, weChatConfig.getShopKey());
-		if (!f) {
-			log.error("回调数据:{}", map);
-			throw BusinessRuntimeException.getInstance("支付成功回调, 校验签名失败.");
-		}
 		// 对退款数据 解密
 		String md5Key = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(weChatConfig.getShopKey()).toHexString();
 		String reqInfoXml = Codec.DoCipher.custom().setAlgorithm(Codec.DoCipher.Trans.AES_ECB_PKCS7Padding).setBase64Data(map.get("req_info")).setStringKey(md5Key).ofDecrypt().toText();

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/register/RegisterOrderDonService.java

@@ -1,9 +1,11 @@
 package com.cyksj.service.register;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.dto.Result;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.RegisterOrderDon;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.WxOrderRefundReq;
 
 import java.util.Map;
 
@@ -20,4 +22,8 @@ public interface RegisterOrderDonService extends IService<RegisterOrderDon> {
     H5JsPayParams pay(Long orderId) throws Exception;
 
     void prepayNotify(Map<String, String> map) throws Exception;
+
+    Result<String> wxRefund(WxOrderRefundReq wxOrderRefundReq) throws Exception;
+
+    void wxRefundNotify(Map<String, String> map) throws Exception;
 }

+ 69 - 0
netflix-service/src/main/java/com/cyksj/service/register/impl/RegisterOrderDonServiceImpl.java

@@ -2,14 +2,18 @@ package com.cyksj.service.register.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.util.Codec;
 import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.Xmls;
 import com.cyksj.config.WeChatConfig;
 import com.cyksj.dto.RedisKey;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.RegisterOrderDonMapper;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.model.dto.H5JsPayParams;
@@ -18,6 +22,7 @@ import com.cyksj.model.entity.SysConfig;
 import com.cyksj.model.entity.User;
 import com.cyksj.model.manage.request.RegisterReq;
 import com.cyksj.model.request.OrderAttach;
+import com.cyksj.model.request.WxOrderRefundReq;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.register.RegisterOrderDonService;
 import com.cyksj.service.register.SpotifyService;
@@ -179,4 +184,68 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
 
         this.updateById(order);
     }
+
+    @Override
+    public Result<String> wxRefund(WxOrderRefundReq wxOrderRefundReq) throws Exception {
+        RegisterOrderDon registerOrderDon = this.getById(wxOrderRefundReq.getOrderId());
+        if (registerOrderDon == null) {
+            throw BusinessRuntimeException.getInstance("该订单不存在");
+        }
+        if (registerOrderDon.getStatus() == RegisterOrderDon.Status.refund) {
+            throw BusinessRuntimeException.getInstance("该订单已退款");
+        }
+        if (registerOrderDon.getStatus() != RegisterOrderDon.Status.error && registerOrderDon.getStatus() != RegisterOrderDon.Status.hasPayment) {
+            throw BusinessRuntimeException.getInstance("该订单状态不允许退款");
+        }
+        if (registerOrderDon.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
+            throw BusinessRuntimeException.getInstance("该订单金额为0,无需退款");
+        }
+        if (!redisService.setNx(String.format("%s", wxOrderRefundReq.getOrderId()), wxOrderRefundReq.getOrderId(), 10l)) {
+            throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中..");
+        }
+        long time = System.currentTimeMillis();
+        //退款订单号
+        String outRefundNo = Codec.DoDigest.custom()
+                .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
+                .setStringData(time + String.valueOf(registerOrderDon.getId()))
+                .toHexString();
+        wxOrderRefundReq.setRefundMoney(registerOrderDon.getMoney());
+        weChatService.refundWxOrder(weChatConfig.getAppid(),
+                registerOrderDon.getTransactionId(),
+                outRefundNo,
+                registerOrderDon.getMoney(),
+                wxOrderRefundReq.getRefundMoney(),
+                weChatConfig.getDomain() + "manage/register/wx/refund/notify");
+        //修改订单状态
+        registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
+        this.updateById(registerOrderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult("退款成功");
+    }
+
+    @Override
+    public void wxRefundNotify(Map<String, String> map) throws Exception {
+        // 对退款数据 解密
+        String md5Key = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(weChatConfig.getShopKey()).toHexString();
+        String reqInfoXml = Codec.DoCipher.custom().setAlgorithm(Codec.DoCipher.Trans.AES_ECB_PKCS7Padding).setBase64Data(map.get("req_info")).setStringKey(md5Key).ofDecrypt().toText();
+        log.info("=== 退款数据解密: \n {}", reqInfoXml);
+        Map<String, String> reqInfoMap = Xmls.toMap(reqInfoXml);
+        // 退款失败
+        if (StrUtil.equals("CHANGE", reqInfoMap.get("refund_status"))) {
+            throw BusinessRuntimeException.getInstance("退款异常.");
+        } else if (StrUtil.equals("REFUNDCLOSE", reqInfoMap.get("refund_status"))) {
+            throw BusinessRuntimeException.getInstance("退款关闭.");
+        }
+        /* 此处处理业务逻辑 */
+        String outRefundNo = reqInfoMap.get("out_refund_no");
+        String transactionId = reqInfoMap.get("transaction_id");
+        RegisterOrderDon registerOrderDon = this.getOne(Wrappers.lambdaQuery(RegisterOrderDon.class).eq(RegisterOrderDon::getTransactionId, transactionId).last("limit 1"));
+        if (registerOrderDon == null) {
+            log.error("退款回调,transactionId:{}订单不存在", transactionId);
+        }
+        if (registerOrderDon.getStatus() != RegisterOrderDon.Status.refund) {
+            registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
+            this.updateById(registerOrderDon);
+        }
+        log.info("微信退款: 退款单号[{}] 退款成功.", outRefundNo);
+    }
 }

+ 41 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/register/CmsRegisterController.java

@@ -1,21 +1,20 @@
 package com.cyksj.web.controller.manage.register;
 
+import cn.hutool.core.util.StrUtil;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.IoKit;
 import com.cyksj.common.util.Xmls;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.RegisterOrderDon;
-import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.WxOrderRefundReq;
 import com.cyksj.service.register.RegisterOrderDonService;
-import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
@@ -52,5 +51,43 @@ public class CmsRegisterController {
     }
 
 
+    /**
+     * 微信订单退款
+     */
+    @PostMapping("/wx/refund")
+    private Result<String> wxRefund(@RequestBody @Validated WxOrderRefundReq wxOrderRefundReq) throws Exception {
+        return registerOrderDonService.wxRefund(wxOrderRefundReq);
+    }
+
+    /**
+     * 微信退款回调
+     */
+    @PostMapping("/wx/refund/notify")
+    public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        String xml = IoKit.toString(request.getInputStream());
+        log.info("=== 注册账号退款成功的回调: \n {}", xml);
+
+        // 解析xml
+        Map<String, String> map = Xmls.toMap(xml);
+
+        // 退款失败
+        if (!StrUtil.equals("SUCCESS", map.get("return_code"))) {
+            throw BusinessRuntimeException.getInstance("退款失败.");
+        }
+
+        registerOrderDonService.wxRefundNotify(map);
+
+        String toWechatXmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+
+        OutputStream out = null;
+        try {
+            out = response.getOutputStream();
+            IoKit.write(toWechatXmlResponse, out);
+        } catch (Throwable e) {
+            throw BusinessRuntimeException.getInstance(e == null ? null : e.getMessage());
+        } finally {
+            IoKit.close(out);
+        }
+    }
 
 }