package com.gxwebsoft.payment.service; import com.gxwebsoft.payment.constants.PaymentConstants; import com.gxwebsoft.payment.exception.PaymentException; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.service.ShopOrderService; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.notification.NotificationConfig; import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.core.notification.RequestParam; import com.wechat.pay.java.service.payments.model.Transaction; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Map; /** * 微信支付回调通知处理服务 * 负责处理微信支付的异步通知回调 * * @author 科技小王子 * @since 2025-01-26 */ @Slf4j @Service public class WxPayNotifyService { @Resource private WxPayConfigService wxPayConfigService; @Resource private ShopOrderService shopOrderService; /** * 处理微信支付回调通知 * * @param headers 请求头 * @param body 请求体 * @param tenantId 租户ID * @return 处理结果响应 */ public String handlePaymentNotify(Map headers, String body, Integer tenantId) { log.info("{}, 租户ID: {}", PaymentConstants.LogMessage.NOTIFY_START, tenantId); try { // 参数验证 validateNotifyParams(headers, body, tenantId); // 获取微信支付配置 Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); // 解析并验证回调数据 Transaction transaction = parseAndVerifyNotification(headers, body, wxPayConfig); // 处理支付结果 processPaymentResult(transaction, tenantId); log.info("{}, 租户ID: {}, 订单号: {}", PaymentConstants.LogMessage.NOTIFY_SUCCESS, tenantId, transaction.getOutTradeNo()); return "SUCCESS"; } catch (Exception e) { log.error("{}, 租户ID: {}, 错误: {}", PaymentConstants.LogMessage.NOTIFY_FAILED, tenantId, e.getMessage(), e); return "FAIL"; } } /** * 验证回调通知参数 */ private void validateNotifyParams(Map headers, String body, Integer tenantId) throws PaymentException { if (tenantId == null) { throw PaymentException.paramError("租户ID不能为空"); } if (headers == null || headers.isEmpty()) { throw PaymentException.paramError("请求头不能为空"); } if (!StringUtils.hasText(body)) { throw PaymentException.paramError("请求体不能为空"); } // 验证必要的微信支付头部信息 String signature = headers.get("Wechatpay-Signature"); String timestamp = headers.get("Wechatpay-Timestamp"); String nonce = headers.get("Wechatpay-Nonce"); String serial = headers.get("Wechatpay-Serial"); if (!StringUtils.hasText(signature)) { throw PaymentException.paramError("微信支付签名不能为空"); } if (!StringUtils.hasText(timestamp)) { throw PaymentException.paramError("微信支付时间戳不能为空"); } if (!StringUtils.hasText(nonce)) { throw PaymentException.paramError("微信支付随机数不能为空"); } if (!StringUtils.hasText(serial)) { throw PaymentException.paramError("微信支付序列号不能为空"); } log.debug("回调通知参数验证通过, 租户ID: {}", tenantId); } /** * 解析并验证回调通知 */ private Transaction parseAndVerifyNotification(Map headers, String body, Config wxPayConfig) throws PaymentException { if (wxPayConfig == null) { throw PaymentException.systemError("微信支付配置为空", null); } try { // 构建请求参数 RequestParam requestParam = new RequestParam.Builder() .serialNumber(headers.get("Wechatpay-Serial")) .nonce(headers.get("Wechatpay-Nonce")) .signature(headers.get("Wechatpay-Signature")) .timestamp(headers.get("Wechatpay-Timestamp")) .body(body) .build(); // 创建通知解析器 NotificationParser parser = new NotificationParser((NotificationConfig) wxPayConfig); // 解析并验证通知 Transaction transaction = parser.parse(requestParam, Transaction.class); if (transaction == null) { throw PaymentException.systemError("解析回调通知失败:transaction为空", null); } log.debug("回调通知解析成功, 订单号: {}, 交易状态: {}", transaction.getOutTradeNo(), transaction.getTradeState()); return transaction; } catch (Exception e) { if (e instanceof PaymentException) { throw e; } throw PaymentException.systemError("解析回调通知失败: " + e.getMessage(), e); } } /** * 处理支付结果 */ private void processPaymentResult(Transaction transaction, Integer tenantId) throws PaymentException { String outTradeNo = transaction.getOutTradeNo(); String tradeState = String.valueOf(transaction.getTradeState()); if (!StringUtils.hasText(outTradeNo)) { throw PaymentException.paramError("商户订单号不能为空"); } // 查询订单 ShopOrder order = shopOrderService.getByOutTradeNo(outTradeNo); if (order == null) { throw PaymentException.systemError("订单不存在: " + outTradeNo, null); } // 验证租户ID if (!tenantId.equals(order.getTenantId())) { throw PaymentException.paramError("订单租户ID不匹配"); } // 验证订单状态 - 使用Boolean类型的payStatus字段 if (Boolean.TRUE.equals(order.getPayStatus())) { log.info("订单已支付,跳过处理, 订单号: {}", outTradeNo); return; } // 根据交易状态处理 switch (tradeState) { case "SUCCESS": handlePaymentSuccess(order, transaction); break; case "REFUND": handlePaymentRefund(order, transaction); break; case "CLOSED": case "REVOKED": case "PAYERROR": handlePaymentFailed(order, transaction); break; default: log.warn("未处理的交易状态: {}, 订单号: {}", tradeState, outTradeNo); break; } } /** * 处理支付成功 */ private void handlePaymentSuccess(ShopOrder order, Transaction transaction) throws PaymentException { try { // 验证金额 validateAmount(order, transaction); // 更新订单状态 order.setPayStatus(true); // 使用Boolean类型 order.setTransactionId(transaction.getTransactionId()); order.setPayTime(LocalDateTime.parse(transaction.getSuccessTime())); // 使用专门的更新方法,会触发支付成功后的业务逻辑 shopOrderService.updateByOutTradeNo(order); // 推送支付结果通知 pushPaymentNotification(order, transaction); log.info("支付成功处理完成, 订单号: {}, 微信交易号: {}", order.getOrderNo(), transaction.getTransactionId()); } catch (Exception e) { throw PaymentException.systemError("处理支付成功回调失败: " + e.getMessage(), e); } } /** * 处理支付退款 */ private void handlePaymentRefund(ShopOrder order, Transaction transaction) throws PaymentException { try { log.info("处理支付退款, 订单号: {}, 微信交易号: {}", order.getOrderNo(), transaction.getTransactionId()); // 这里可以添加退款相关的业务逻辑 // 例如:更新订单状态、处理库存、发送通知等 } catch (Exception e) { throw PaymentException.systemError("处理支付退款回调失败: " + e.getMessage(), e); } } /** * 处理支付失败 */ private void handlePaymentFailed(ShopOrder order, Transaction transaction) throws PaymentException { try { log.info("处理支付失败, 订单号: {}, 交易状态: {}", order.getOrderNo(), transaction.getTradeState()); // 这里可以添加支付失败相关的业务逻辑 // 例如:释放库存、发送通知等 } catch (Exception e) { throw PaymentException.systemError("处理支付失败回调失败: " + e.getMessage(), e); } } /** * 验证支付金额 */ private void validateAmount(ShopOrder order, Transaction transaction) throws PaymentException { if (transaction.getAmount() == null || transaction.getAmount().getTotal() == null) { throw PaymentException.amountError("回调通知中金额信息为空"); } // 将订单金额转换为分 BigDecimal orderAmount = order.getMoney(); if (orderAmount == null) { throw PaymentException.amountError("订单金额为空"); } int orderAmountFen = orderAmount.multiply(new BigDecimal(100)).intValue(); int callbackAmountFen = transaction.getAmount().getTotal(); if (orderAmountFen != callbackAmountFen) { throw PaymentException.amountError( String.format("订单金额不匹配,订单金额: %d分, 回调金额: %d分", orderAmountFen, callbackAmountFen)); } log.debug("金额验证通过, 订单号: {}, 金额: {}分", order.getOrderNo(), orderAmountFen); } /** * 推送支付结果通知 */ private void pushPaymentNotification(ShopOrder order, Transaction transaction) { try { log.info("开始推送支付成功通知, 订单号: {}, 交易号: {}, 用户ID: {}", order.getOrderNo(), transaction.getTransactionId(), order.getUserId()); // 1. 记录支付成功日志 logPaymentSuccess(order, transaction); // 2. 发送支付成功通知(可扩展) sendPaymentSuccessNotification(order, transaction); // 3. 触发其他业务逻辑(可扩展) triggerPostPaymentActions(order, transaction); log.info("支付结果通知推送完成, 订单号: {}, 交易号: {}", order.getOrderNo(), transaction.getTransactionId()); } catch (Exception e) { log.warn("支付结果通知推送失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); // 推送失败不影响主流程,只记录日志 } } /** * 记录支付成功日志 */ private void logPaymentSuccess(ShopOrder order, Transaction transaction) { try { log.info("=== 支付成功详细信息 ==="); log.info("订单号: {}", order.getOrderNo()); log.info("微信交易号: {}", transaction.getTransactionId()); log.info("支付金额: {}元", order.getPayPrice()); log.info("支付时间: {}", transaction.getSuccessTime()); log.info("用户ID: {}", order.getUserId()); log.info("租户ID: {}", order.getTenantId()); log.info("订单标题: {}", order.getTitle()); log.info("========================"); } catch (Exception e) { log.warn("记录支付成功日志失败: {}", e.getMessage()); } } /** * 发送支付成功通知 */ private void sendPaymentSuccessNotification(ShopOrder order, Transaction transaction) { try { // TODO: 实现具体的通知逻辑 // 1. 发送邮件通知 // 2. 发送短信通知 // 3. 站内消息通知 // 4. 微信模板消息通知 log.debug("支付成功通知发送完成, 订单号: {}", order.getOrderNo()); } catch (Exception e) { log.warn("发送支付成功通知失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); } } /** * 触发支付成功后的其他业务逻辑 */ private void triggerPostPaymentActions(ShopOrder order, Transaction transaction) { try { // TODO: 根据业务需求实现 // 1. 开通网站服务 // 2. 激活会员权益 // 3. 发放积分奖励 // 4. 触发营销活动 log.debug("支付后业务逻辑触发完成, 订单号: {}", order.getOrderNo()); } catch (Exception e) { log.warn("触发支付后业务逻辑失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); } } }