package com.doumee.api.web; import com.doumee.config.wx.WxMiniConfig; import com.doumee.config.wx.WxPayV3Service; import com.doumee.core.constants.Constants; import com.doumee.core.utils.ID; import com.doumee.dao.business.OrdersRefundMapper; import com.doumee.dao.business.OrdersMapper; import com.doumee.dao.business.model.Notice; import com.doumee.dao.business.model.Orders; import com.doumee.dao.business.model.OrdersRefund; import com.doumee.service.business.NoticeService; import com.doumee.service.business.OrdersService; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.wechat.pay.java.service.payments.model.Transaction; import com.wechat.pay.java.service.refund.model.RefundNotification; import com.wechat.pay.java.service.refund.model.Status; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; /** * 支付回调 * * @Author : Rk * @create 2023/3/24 16:57 */ @Slf4j @RestController @CrossOrigin public class PaymentCallback extends ApiController { @Autowired private OrdersService ordersService; @Autowired private WxPayV3Service wxPayV3Service; @Autowired private OrdersRefundMapper ordersRefundMapper; @Autowired private OrdersMapper ordersMapper; @Autowired private NoticeService noticeService; // ==================== V2 回调 ==================== @PostMapping("/web/api/wxPayNotify") public String wxPay_notify(@RequestBody String xmlResult) { String wxId = ID.nextGUID(); log.info("V2支付回调信息(" + wxId + ") => " + xmlResult); if (StringUtils.isEmpty(xmlResult)) { return null; } try { WxPayOrderNotifyResult result = WxMiniConfig.wxPayService.parseOrderNotifyResult(xmlResult); String outTradeNo = result.getOutTradeNo(); String paymentNo = result.getTransactionId(); if (Constants.SUCCESS.equals(result.getReturnCode())) { switch (result.getAttach()) { case "storageOrder": { ordersService.handleStorageOrderPayNotify(outTradeNo, paymentNo); break; } case "shopDeposit": { ordersService.handleShopDepositPayNotify(outTradeNo, paymentNo); break; } case "overdueFee": { ordersService.handleOverdueFeePayNotify(outTradeNo, paymentNo); break; } } return WxPayNotifyResponse.success("处理成功!"); } return WxPayNotifyResponse.fail(result.getReturnMsg()); } catch (Exception e) { e.printStackTrace(); log.error("V2微信回调结果异常,异常原因{}", e.getLocalizedMessage()); return WxPayNotifyResponse.fail(e.getMessage()); } } // ==================== V3 回调 ==================== /** * V3支付回调 */ @PostMapping("/web/api/wxPayV3Notify") public Map wxPayV3Notify( @RequestHeader("Wechatpay-Serial") String serialNumber, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestBody String body) { String wxId = ID.nextGUID(); log.info("V3支付回调信息({}) => {}", wxId, body); try { Transaction transaction = wxPayV3Service.parsePayNotify( serialNumber, timestamp, nonce, signature, body); String outTradeNo = transaction.getOutTradeNo(); String paymentNo = transaction.getTransactionId(); if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) { String attach = transaction.getAttach(); if (StringUtils.isNotBlank(attach)) { switch (attach) { case "storageOrder": ordersService.handleStorageOrderPayNotify(outTradeNo, paymentNo); break; case "shopDeposit": ordersService.handleShopDepositPayNotify(outTradeNo, paymentNo); break; case "overdueFee": ordersService.handleOverdueFeePayNotify(outTradeNo, paymentNo); break; } } } Map response = new HashMap<>(); response.put("code", "SUCCESS"); response.put("message", "处理成功"); return response; } catch (Exception e) { log.error("V3支付回调异常,异常原因{}", e.getLocalizedMessage()); Map response = new HashMap<>(); response.put("code", "FAIL"); response.put("message", e.getMessage()); return response; } } /** * V3退款回调 */ @PostMapping("/web/api/wxRefundV3Notify") public Map wxRefundV3Notify( @RequestHeader("Wechatpay-Serial") String serialNumber, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestBody String body) { String wxId = ID.nextGUID(); log.info("V3退款回调信息({}) => {}", wxId, body); try { RefundNotification refundNotification = wxPayV3Service.parseRefundNotify( serialNumber, timestamp, nonce, signature, body); log.info("V3退款回调结果, outTradeNo={}, outRefundNo={}, refundStatus={}", refundNotification.getOutTradeNo(), refundNotification.getOutRefundNo(), refundNotification.getRefundStatus()); // 根据退款单号更新退款记录状态 String outRefundNo = refundNotification.getOutRefundNo(); OrdersRefund refundRecord = ordersRefundMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper().lambda() .eq(OrdersRefund::getRefundCode, outRefundNo) .eq(OrdersRefund::getDeleted, Constants.ZERO) .last("limit 1")); if (refundRecord != null) { Status refundStatus = refundNotification.getRefundStatus(); if (Status.SUCCESS.equals(refundStatus)) { refundRecord.setStatus(Constants.ONE); // 退款成功 refundRecord.setRefundTime(new java.util.Date()); } else if (Status.CLOSED.equals(refundStatus) || Status.ABNORMAL.equals(refundStatus)) { refundRecord.setStatus(Constants.TWO); // 退款失败 } ordersRefundMapper.updateById(refundRecord); log.info("退款记录状态已更新, refundRecordId={}, status={}", refundRecord.getId(), refundRecord.getStatus()); // 退款成功 → 通知会员 if (Status.SUCCESS.equals(refundStatus) && refundRecord.getOrderId() != null) { Orders refundOrder = ordersMapper.selectById(refundRecord.getOrderId()); if (refundOrder != null) { Notice notice = new Notice(); notice.setUserType(0); notice.setUserId(refundOrder.getMemberId()); notice.setTitle(Constants.MemberOrderNotify.REFUNDED.getTitle()); notice.setContent(Constants.MemberOrderNotify.REFUNDED.format( "orderNo", refundOrder.getCode(), "amount", String.valueOf(Constants.getFormatMoney(refundOrder.getRefundAmount() != null ? refundOrder.getRefundAmount() : 0L)))); notice.setObjId(refundOrder.getId()); notice.setObjType(0); notice.setStatus(0); notice.setIsdeleted(Constants.ZERO); notice.setCreateDate(new java.util.Date()); noticeService.create(notice); } } } Map response = new HashMap<>(); response.put("code", "SUCCESS"); response.put("message", "处理成功"); return response; } catch (Exception e) { log.error("V3退款回调异常,异常原因{}", e.getLocalizedMessage()); Map response = new HashMap<>(); response.put("code", "FAIL"); response.put("message", e.getMessage()); return response; } } }