From 8444084e6aa11efa23287e7f82474ac22378a5c4 Mon Sep 17 00:00:00 2001 From: Pu Zhibing <393733352@qq.com> Date: 星期二, 01 四月 2025 16:03:19 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java | 203 ++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 170 insertions(+), 33 deletions(-) diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java index 775d9da..6574ab5 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java @@ -1,5 +1,6 @@ package com.ruoyi.order.controller.miniapp; +import com.alibaba.fastjson.JSONObject; import com.github.binarywang.wxpay.bean.ecommerce.*; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Response; import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingNotifyData; @@ -11,13 +12,25 @@ import com.github.binarywang.wxpay.v3.util.AesUtils; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.order.domain.dto.WechatPaymentRefundDto; +import com.ruoyi.order.domain.dto.WeixinPaymentNotifyDto; +import com.ruoyi.order.domain.pojo.account.OrderRefund; import com.ruoyi.order.domain.vo.ProfitSharingNotifyNewResult; +import com.ruoyi.order.domain.vo.WeixinPaymentNotifyVo; +import com.ruoyi.order.domain.vo.WeixinPaymentRefundVo; +import com.ruoyi.order.enums.RefundStatusEnum; import com.ruoyi.order.enums.WxPayNotifyEventTypeEnum; +import com.ruoyi.order.enums.dict.IDict; import com.ruoyi.order.service.account.BackMessageService; +import com.ruoyi.order.service.account.OrderRefundService; import com.ruoyi.order.service.order.OrderService; +import com.ruoyi.order.util.HuiFuTianXiaUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -25,10 +38,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.PrintWriter; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.util.Collection; +import java.util.Enumeration; import java.util.Map; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * @program: ruoyi @@ -39,6 +57,7 @@ @Api(value = "微信通知控制", tags = "微信通知控制", description = "微信通知控制") @RestController @RequestMapping("/app/notify") +@Log4j2 public class NotifyController extends BaseController { public static final String WECHAT_PAY_SERIAL = "Wechatpay-Serial"; @@ -51,44 +70,57 @@ @Resource private OrderService orderService; - @Autowired + @Resource private WxPayService wxService; @Resource private BackMessageService backMessageService; + + @Resource + private OrderRefundService orderRefundService; + + @Resource + private RedisService redisService; @PostMapping(value = "/payNotify") @ApiOperation(value = "微信支付/退款通知") public String payNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException { // 获取请求头 - SignatureHeader signatureHeader = getSignatureHeader(response); + SignatureHeader signatureHeader = getSignatureHeader(request); + + log.info("微信支付/退款通知: {}", notifyData); NotifyResponse responseData = GSON.fromJson(notifyData, NotifyResponse.class); String eventType = responseData.getEventType(); int resultType = 1; - String resultMessage = ""; - if(WxPayNotifyEventTypeEnum.TRANSACTION_SUCCESS.getCode().equals(eventType)){ - PartnerTransactionsNotifyResult notifyResult = wxService.getEcommerceService().parsePartnerNotifyResult(notifyData, signatureHeader); - PartnerTransactionsResult result = notifyResult.getResult(); - // 支付通知回调 - if("SUCCESS".equals(result.getTradeState())){ - orderService.payBack(result); - } - resultMessage = GSON.toJson(notifyResult); - } else if(WxPayNotifyEventTypeEnum.REFUND_SUCCESS.getCode().equals(eventType) - || WxPayNotifyEventTypeEnum.REFUND_ABNORMAL.getCode().equals(eventType) - || WxPayNotifyEventTypeEnum.REFUND_CLOSED.getCode().equals(eventType)){ + String resultMessage = notifyData; - RefundNotifyResult result = wxService.getEcommerceService().parseRefundNotifyResult(notifyData, signatureHeader); - orderService.orderRefundBack(result); - resultType = 2; - resultMessage = GSON.toJson(result); + try { + if (WxPayNotifyEventTypeEnum.TRANSACTION_SUCCESS.getCode().equals(eventType)) { + PartnerTransactionsNotifyResult notifyResult = wxService.getEcommerceService().parsePartnerNotifyResult(notifyData, signatureHeader); + PartnerTransactionsResult result = notifyResult.getResult(); + // 支付通知回调 + if ("SUCCESS".equals(result.getTradeState())) { + orderService.payBack(result, BigDecimal.ONE); + } + resultMessage = GSON.toJson(notifyResult); + } else if (WxPayNotifyEventTypeEnum.REFUND_SUCCESS.getCode().equals(eventType) + || WxPayNotifyEventTypeEnum.REFUND_ABNORMAL.getCode().equals(eventType) + || WxPayNotifyEventTypeEnum.REFUND_CLOSED.getCode().equals(eventType)) { + + RefundNotifyResult result = this.parseRefundNotifyResult(notifyData, signatureHeader); + orderService.orderRefundBack(result); + resultType = 2; + resultMessage = GSON.toJson(result); + } + + }catch (Exception e){ + e.printStackTrace(); + log.info("微信支付/退款通知异常: {}", e.getMessage()); } // 保存支付/退款回调信息 backMessageService.saveBackMessage(resultType, resultMessage); - - return WxPayNotifyV3Response.success("成功"); } @@ -97,21 +129,26 @@ public String profitSharingNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException { ProfitSharingV3Service sharingV3Service = wxService.getProfitSharingV3Service(); // ProfitSharingNotifyResult + log.info("微信分账通知: {}", notifyData); // 获取请求头 - SignatureHeader signatureHeader = getSignatureHeader(response); - + SignatureHeader signatureHeader = getSignatureHeader(request); ProfitSharingNotifyNewResult notifyResult = getProfitSharingNotifyData(notifyData, signatureHeader); ProfitSharingNotifyResult result = notifyResult.getResult(); + String eventType = "-1"; + String resultMessage = notifyData; + try { + eventType = notifyResult.getRawData().getEventType(); + if (WxPayNotifyEventTypeEnum.PROFIT_SHARING_SUCCESS.getCode().equals(eventType)) { + // 分账通知回调 + orderService.profitSharingBack(result); + } - String eventType = notifyResult.getRawData().getEventType(); - if(WxPayNotifyEventTypeEnum.PROFIT_SHARING_SUCCESS.getCode().equals(eventType)){ - // 分账通知回调 - orderService.profitSharingBack(result); + resultMessage = GSON.toJson(notifyResult); + }catch (Exception e){ + log.info("微信分账通知通知异常: {}", e.getMessage()); } - - String resultMessage = GSON.toJson(notifyResult); // 保存记录分账回调信息 backMessageService.saveBackMessage(3, resultMessage); @@ -149,6 +186,24 @@ } } + private RefundNotifyResult parseRefundNotifyResult(String notifyData, SignatureHeader header) throws WxPayException { + + NotifyResponse response = GSON.fromJson(notifyData, NotifyResponse.class); + NotifyResponse.Resource resource = response.getResource(); + String cipherText = resource.getCiphertext(); + String associatedData = resource.getAssociatedData(); + String nonce = resource.getNonce(); + String apiV3Key = this.wxService.getConfig().getApiV3Key(); + try { + String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key); + RefundNotifyResult notifyResult = GSON.fromJson(result, RefundNotifyResult.class); + notifyResult.setRawData(response); + return notifyResult; + } catch (GeneralSecurityException | IOException e) { + throw new WxPayException("解析报文异常!", e); + } + } + private boolean verifyNotifySign(SignatureHeader header, String data) throws WxPayException { String beforeSign = String.format("%s\n%s\n%s\n", header.getTimeStamp(), @@ -162,12 +217,94 @@ beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned()); } - private SignatureHeader getSignatureHeader(HttpServletResponse response){ + private SignatureHeader getSignatureHeader(HttpServletRequest request){ SignatureHeader signatureHeader = new SignatureHeader(); - signatureHeader.setSerialNo(response.getHeader(WECHAT_PAY_SERIAL)); - signatureHeader.setSigned(response.getHeader(WECHAT_PAY_SIGNATURE)); - signatureHeader.setNonce(response.getHeader(WECHAT_PAY_NONCE)); - signatureHeader.setTimeStamp(response.getHeader(WECHAT_PAY_TIMESTAMP)); + signatureHeader.setSerialNo(request.getHeader(WECHAT_PAY_SERIAL)); + signatureHeader.setSigned(request.getHeader(WECHAT_PAY_SIGNATURE)); + signatureHeader.setNonce(request.getHeader(WECHAT_PAY_NONCE)); + signatureHeader.setTimeStamp(request.getHeader(WECHAT_PAY_TIMESTAMP)); + + log.info("timeStamp:{} nonce : {} signed:{} serialNo:{}", + signatureHeader.getTimeStamp(), + signatureHeader.getNonce(), + signatureHeader.getSigned(), + signatureHeader.getSerialNo()); + return signatureHeader; } + + + + @RequestMapping(value = "/wechatPaymentCallback", method = RequestMethod.POST) + @ApiOperation(value = "微信支付通知(汇付天下)") + public void wechatPaymentCallback(WeixinPaymentNotifyDto dto, HttpServletResponse response){ + R<WeixinPaymentNotifyVo> r = HuiFuTianXiaUtil.weixinPaymentNotify(dto); + if(r.getCode() == 200){ + WeixinPaymentNotifyVo data = r.getData(); + String transStat = data.getTransStat(); + if("S".equals(transStat)){ + PartnerTransactionsResult transaction = new PartnerTransactionsResult(); + transaction.setOutTradeNo(data.getReqSeqId()); + + //防止回调频繁导致时间处理异常 + Object cacheObject = redisService.getCacheObject(data.getReqSeqId()); + if(null == cacheObject){ + redisService.setCacheObject(data.getReqSeqId(), "", 10L, TimeUnit.SECONDS); + }else{ + return; + } + //开始处理业务数据 + orderService.payBack(transaction, data.getFeeFlag() == 1 ? BigDecimal.ZERO : new BigDecimal(data.getFeeAmount())); + + response.setStatus(200); + PrintWriter out = null; + try { + out = response.getWriter(); + out.print("RECV_ORD_ID_" + data.getReqSeqId()); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + }finally { + out.close(); + } + + } + } + } + + + + @RequestMapping(value = "/wechatPaymentRefundCallback", method = RequestMethod.POST) + @ApiOperation(value = "微信支付退款通知(汇付天下)") + public void wechatPaymentRefundCallback(WechatPaymentRefundDto dto, HttpServletResponse response){ + R<WeixinPaymentRefundVo> r = HuiFuTianXiaUtil.weixinPaymentRefundNotify(dto); + if(r.getCode() == 200){ + WeixinPaymentRefundVo data = r.getData(); + String transStat = data.getTransStat(); + if("S".equals(transStat)){ + //开始处理业务数据 + String reqSeqId = data.getReqSeqId(); + OrderRefund orderRefund = orderRefundService.getById(reqSeqId); + if(null != orderRefund && orderRefund.getRefundStatus() != 2){ + orderRefund.setWxRefundId(data.getPartyOrderId()); + orderRefund.setBackTime(data.getTransDate() + data.getTransTime()); + orderRefund.setRefundStatus(2); + orderRefundService.saveOrUpdate(orderRefund); + } + + response.setStatus(200); + PrintWriter out = null; + try { + out = response.getWriter(); + out.print("RECV_ORD_ID_" + data.getReqSeqId()); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + }finally { + out.close(); + } + + } + } + } } -- Gitblit v1.7.1