| | |
| | | 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; |
| | |
| | | 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 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 |
| | |
| | | @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); |
| | | |
| | |
| | | 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("成功"); |
| | | } |
| | | |
| | |
| | | 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); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | 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(), |
| | |
| | | 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(), |
| | |
| | | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | } |