package com.ruoyi.payment.application.service;
|
|
import com.alibaba.fastjson.JSON;
|
import com.ruoyi.payment.domain.model.NotifyLog;
|
import com.ruoyi.payment.domain.model.PaymentOrder;
|
import com.ruoyi.payment.domain.model.PaymentTransaction;
|
import com.ruoyi.payment.infrastructure.persistence.mapper.NotifyLogMapper;
|
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentOrderMapper;
|
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentTransactionMapper;
|
import com.ruoyi.payment.infrastructure.util.SnowflakeIdGenerator;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.LocalDateTime;
|
import java.util.Map;
|
|
/**
|
* 支付回调处理服务
|
*
|
* @author ruoyi
|
*/
|
@Slf4j
|
@Service
|
public class PaymentNotifyService {
|
|
@Autowired
|
private PaymentOrderMapper paymentOrderMapper;
|
|
@Autowired
|
private PaymentTransactionMapper paymentTransactionMapper;
|
|
@Autowired
|
private NotifyLogMapper notifyLogMapper;
|
|
@Autowired
|
private BizCallbackService bizCallbackService;
|
|
/**
|
* 处理微信支付回调
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public void processWechatNotify(Map<String, String> params, String rawXml) {
|
String outTradeNo = params.get("out_trade_no"); // 商户订单号
|
String transactionId = params.get("transaction_id"); // 微信交易号
|
String resultCode = params.get("result_code");
|
String returnCode = params.get("return_code");
|
|
log.info("处理微信回调,商户订单号: {}, 微信交易号: {}, 结果: {}", outTradeNo, transactionId, resultCode);
|
|
// 检查幂等性
|
if (isNotifyProcessed("WECHAT", transactionId)) {
|
log.info("微信回调已处理过,交易号: {}", transactionId);
|
return;
|
}
|
|
// 记录回调日志
|
NotifyLog notifyLog = saveNotifyLog("WECHAT", transactionId, rawXml, true);
|
|
try {
|
// 通信成功且业务成功
|
if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
|
// 查询订单和交易(使用业务订单号查询)
|
PaymentOrder order = paymentOrderMapper.selectByBizOrderIdAndChannel(outTradeNo, "WECHAT");
|
if (order == null) {
|
log.error("订单不存在: {}", outTradeNo);
|
updateNotifyLog(notifyLog.getId(), false, "订单不存在");
|
return;
|
}
|
|
PaymentTransaction transaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
|
if (transaction == null) {
|
log.error("待支付交易不存在,订单ID: {}", order.getId());
|
updateNotifyLog(notifyLog.getId(), false, "交易不存在");
|
return;
|
}
|
|
// 更新交易状态
|
transaction.setStatus("SUCCEEDED");
|
transaction.setChannelTradeNo(transactionId);
|
transaction.setPaidAt(LocalDateTime.now());
|
transaction.setResponseSnapshot(JSON.toJSONString(params));
|
paymentTransactionMapper.update(transaction);
|
|
// 更新订单状态
|
order.setStatus("SUCCEEDED");
|
order.setChannelTradeNo(transactionId);
|
order.setPaidAt(LocalDateTime.now());
|
order.setLatestTransactionId(transaction.getId());
|
paymentOrderMapper.update(order);
|
|
// 更新通知日志
|
notifyLog.setOrderId(order.getId());
|
notifyLog.setTransactionId(transaction.getId());
|
updateNotifyLog(notifyLog.getId(), true, "处理成功");
|
|
// 触发业务回调
|
bizCallbackService.triggerCallback(order, transaction);
|
|
log.info("微信支付回调处理成功,订单ID: {}, 交易ID: {}", order.getId(), transaction.getId());
|
} else {
|
log.warn("微信支付失败,returnCode: {}, resultCode: {}", returnCode, resultCode);
|
updateNotifyLog(notifyLog.getId(), true, "支付失败");
|
}
|
} catch (Exception e) {
|
log.error("处理微信回调异常", e);
|
updateNotifyLog(notifyLog.getId(), false, "处理异常: " + e.getMessage());
|
throw e;
|
}
|
}
|
|
/**
|
* 处理支付宝回调
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public void processAlipayNotify(Map<String, String> params) {
|
String outTradeNo = params.get("out_trade_no"); // 商户订单号
|
String tradeNo = params.get("trade_no"); // 支付宝交易号
|
String tradeStatus = params.get("trade_status");
|
|
log.info("处理支付宝回调,商户订单号: {}, 支付宝交易号: {}, 状态: {}", outTradeNo, tradeNo, tradeStatus);
|
|
// 检查幂等性
|
if (isNotifyProcessed("ALIPAY", tradeNo)) {
|
log.info("支付宝回调已处理过,交易号: {}", tradeNo);
|
return;
|
}
|
|
// 记录回调日志
|
NotifyLog notifyLog = saveNotifyLog("ALIPAY", tradeNo, JSON.toJSONString(params), true);
|
|
try {
|
// 交易成功
|
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
|
// 查询订单和交易(使用业务订单号查询)
|
PaymentOrder order = paymentOrderMapper.selectByBizOrderIdAndChannel(outTradeNo, "ALIPAY");
|
if (order == null) {
|
log.error("订单不存在: {}", outTradeNo);
|
updateNotifyLog(notifyLog.getId(), false, "订单不存在");
|
return;
|
}
|
|
PaymentTransaction transaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
|
if (transaction == null) {
|
log.error("待支付交易不存在,订单ID: {}", order.getId());
|
updateNotifyLog(notifyLog.getId(), false, "交易不存在");
|
return;
|
}
|
|
// 更新交易状态
|
transaction.setStatus("SUCCEEDED");
|
transaction.setChannelTradeNo(tradeNo);
|
transaction.setPaidAt(LocalDateTime.now());
|
transaction.setResponseSnapshot(JSON.toJSONString(params));
|
paymentTransactionMapper.update(transaction);
|
|
// 更新订单状态
|
order.setStatus("SUCCEEDED");
|
order.setChannelTradeNo(tradeNo);
|
order.setPaidAt(LocalDateTime.now());
|
order.setLatestTransactionId(transaction.getId());
|
paymentOrderMapper.update(order);
|
|
// 更新通知日志
|
notifyLog.setOrderId(order.getId());
|
notifyLog.setTransactionId(transaction.getId());
|
updateNotifyLog(notifyLog.getId(), true, "处理成功");
|
|
// 触发业务回调
|
bizCallbackService.triggerCallback(order, transaction);
|
|
log.info("支付宝回调处理成功,订单ID: {}, 交易ID: {}", order.getId(), transaction.getId());
|
} else {
|
log.warn("支付宝交易状态异常: {}", tradeStatus);
|
updateNotifyLog(notifyLog.getId(), true, "状态: " + tradeStatus);
|
}
|
} catch (Exception e) {
|
log.error("处理支付宝回调异常", e);
|
updateNotifyLog(notifyLog.getId(), false, "处理异常: " + e.getMessage());
|
throw e;
|
}
|
}
|
|
/**
|
* 检查通知是否已处理(幂等性)
|
*/
|
private boolean isNotifyProcessed(String channel, String notifyId) {
|
return notifyLogMapper.selectProcessedCount(channel, notifyId) > 0;
|
}
|
|
/**
|
* 保存通知日志
|
*/
|
private NotifyLog saveNotifyLog(String channel, String notifyId, String payload, boolean verified) {
|
NotifyLog log = new NotifyLog();
|
log.setId(SnowflakeIdGenerator.generateId());
|
log.setChannel(channel);
|
log.setNotifyIdOrSerial(notifyId);
|
log.setPayload(payload);
|
log.setVerified(verified);
|
log.setProcessed(false);
|
log.setCreatedAt(LocalDateTime.now());
|
notifyLogMapper.insert(log);
|
return log;
|
}
|
|
/**
|
* 更新通知日志
|
*/
|
private void updateNotifyLog(Long id, boolean processed, String result) {
|
NotifyLog log = new NotifyLog();
|
log.setId(id);
|
log.setProcessed(processed);
|
log.setResult(result);
|
notifyLogMapper.update(log);
|
}
|
}
|