using System.Text.Json;
using MiAssessment.Core.Interfaces;
using MiAssessment.Model.Data;
using MiAssessment.Model.Entities;
using MiAssessment.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace MiAssessment.Core.Services;
///
/// 支付回调服务实现
/// 负责处理微信支付回调通知,验证签名,记录通知
/// 业务处理逻辑由具体业务模块实现
///
public class PaymentNotifyService : IPaymentNotifyService
{
private readonly MiAssessmentDbContext _dbContext;
private readonly IWechatPayService _wechatPayService;
private readonly IWechatPayV3Service _wechatPayV3Service;
private readonly IWechatPayConfigService _wechatPayConfigService;
private readonly ILogger _logger;
public PaymentNotifyService(
MiAssessmentDbContext dbContext,
IWechatPayService wechatPayService,
IWechatPayV3Service wechatPayV3Service,
IWechatPayConfigService wechatPayConfigService,
ILogger logger)
{
_dbContext = dbContext;
_wechatPayService = wechatPayService;
_wechatPayV3Service = wechatPayV3Service;
_wechatPayConfigService = wechatPayConfigService;
_logger = logger;
}
///
public async Task HandleWechatNotifyAsync(string notifyBody, WechatPayNotifyHeaders? headers = null)
{
// 自动识别回调格式
var version = _wechatPayV3Service.DetectNotifyVersion(notifyBody);
_logger.LogInformation("检测到微信支付回调版本: {Version}", version);
return version switch
{
NotifyVersion.V3 when headers != null => await HandleWechatV3NotifyAsync(notifyBody, headers),
NotifyVersion.V3 => new NotifyResult
{
Success = false,
Message = "V3 回调缺少请求头",
JsonResponse = JsonSerializer.Serialize(new WechatPayV3NotifyResponse { Code = "FAIL", Message = "缺少请求头" })
},
NotifyVersion.V2 => await HandleWechatV2NotifyAsync(notifyBody),
_ => new NotifyResult
{
Success = false,
Message = "无法识别的回调格式",
XmlResponse = _wechatPayService.GenerateNotifyResponseXml("FAIL", "无法识别的回调格式")
}
};
}
///
public async Task HandleWechatV2NotifyAsync(string xmlData)
{
var successResponse = _wechatPayService.GenerateNotifyResponseXml("SUCCESS", "OK");
var failResponse = _wechatPayService.GenerateNotifyResponseXml("FAIL", "处理失败");
try
{
// 1. 检查XML数据是否为空
if (string.IsNullOrEmpty(xmlData))
{
_logger.LogWarning("微信支付 V2 回调数据为空");
return new NotifyResult
{
Success = false,
Message = "回调数据为空",
XmlResponse = failResponse
};
}
// 2. 解析XML数据
var notifyData = _wechatPayService.ParseNotifyXml(xmlData);
if (notifyData == null || string.IsNullOrEmpty(notifyData.OutTradeNo))
{
_logger.LogWarning("解析微信支付 V2 回调XML失败");
return new NotifyResult
{
Success = false,
Message = "解析回调数据失败",
XmlResponse = failResponse
};
}
var orderNo = notifyData.OutTradeNo;
var attach = notifyData.Attach;
_logger.LogInformation("收到微信支付 V2 回调: OrderNo={OrderNo}, Attach={Attach}, TotalFee={TotalFee}",
orderNo, attach, notifyData.TotalFee);
// 3. 验证签名
if (!_wechatPayService.VerifyNotifySign(notifyData))
{
_logger.LogWarning("微信支付 V2 回调签名验证失败: OrderNo={OrderNo}", orderNo);
return new NotifyResult
{
Success = false,
Message = "签名验证失败",
XmlResponse = failResponse
};
}
// 4. 检查返回状态
if (notifyData.ReturnCode != "SUCCESS" || notifyData.ResultCode != "SUCCESS")
{
_logger.LogWarning("微信支付回调状态异常: OrderNo={OrderNo}, ReturnCode={ReturnCode}, ResultCode={ResultCode}",
orderNo, notifyData.ReturnCode, notifyData.ResultCode);
// 即使支付失败,也返回成功响应,避免微信重复通知
return new NotifyResult
{
Success = true,
Message = "支付未成功",
XmlResponse = successResponse
};
}
// 5. 幂等性检查 - 检查订单是否已处理
if (await IsOrderProcessedAsync(orderNo))
{
_logger.LogInformation("订单已处理,跳过重复回调: OrderNo={OrderNo}", orderNo);
return new NotifyResult
{
Success = true,
Message = "订单已处理",
XmlResponse = successResponse
};
}
// 6. 记录回调通知
await RecordNotifyAsync(orderNo, notifyData);
// 7. 返回成功,业务处理由具体业务模块实现
_logger.LogInformation("微信支付 V2 回调记录成功: OrderNo={OrderNo}, Attach={Attach}", orderNo, attach);
return new NotifyResult
{
Success = true,
Message = "处理成功",
XmlResponse = successResponse,
OrderNo = orderNo,
Attach = attach,
NotifyData = notifyData
};
}
catch (Exception ex)
{
_logger.LogError(ex, "处理微信支付回调异常");
// 异常情况也返回成功,避免微信重复通知
return new NotifyResult
{
Success = false,
Message = $"处理异常: {ex.Message}",
XmlResponse = successResponse
};
}
}
///
public async Task HandleWechatV3NotifyAsync(string jsonData, WechatPayNotifyHeaders headers)
{
var successResponse = JsonSerializer.Serialize(new WechatPayV3NotifyResponse { Code = "SUCCESS", Message = "成功" });
var failResponse = JsonSerializer.Serialize(new WechatPayV3NotifyResponse { Code = "FAIL", Message = "处理失败" });
try
{
// 1. 检查数据是否为空
if (string.IsNullOrEmpty(jsonData))
{
_logger.LogWarning("微信支付 V3 回调数据为空");
return new NotifyResult
{
Success = false,
Message = "回调数据为空",
JsonResponse = failResponse
};
}
// 2. 验证签名
if (!_wechatPayV3Service.VerifyNotifySignature(
headers.Timestamp,
headers.Nonce,
jsonData,
headers.Signature,
headers.Serial))
{
_logger.LogWarning("微信支付 V3 回调签名验证失败");
return new NotifyResult
{
Success = false,
Message = "签名验证失败",
JsonResponse = failResponse
};
}
// 3. 解析回调通知
var notification = JsonSerializer.Deserialize(jsonData);
if (notification == null || notification.Resource == null)
{
_logger.LogWarning("解析微信支付 V3 回调数据失败");
return new NotifyResult
{
Success = false,
Message = "解析回调数据失败",
JsonResponse = failResponse
};
}
_logger.LogInformation("收到微信支付 V3 回调: Id={Id}, EventType={EventType}",
notification.Id, notification.EventType);
// 4. 获取商户配置并解密数据
var merchantConfig = _wechatPayConfigService.GetDefaultConfig();
if (string.IsNullOrEmpty(merchantConfig.ApiV3Key))
{
_logger.LogError("APIv3 密钥未配置");
return new NotifyResult
{
Success = false,
Message = "APIv3 密钥未配置",
JsonResponse = failResponse
};
}
var decryptedJson = _wechatPayV3Service.DecryptNotifyResource(
notification.Resource.Ciphertext,
notification.Resource.Nonce,
notification.Resource.AssociatedData,
merchantConfig.ApiV3Key);
_logger.LogDebug("V3 回调解密成功: {DecryptedJson}", decryptedJson);
// 5. 解析支付结果
var paymentResult = JsonSerializer.Deserialize(decryptedJson);
if (paymentResult == null || string.IsNullOrEmpty(paymentResult.OutTradeNo))
{
_logger.LogWarning("解析 V3 支付结果失败");
return new NotifyResult
{
Success = false,
Message = "解析支付结果失败",
JsonResponse = failResponse
};
}
var orderNo = paymentResult.OutTradeNo;
var attach = paymentResult.Attach;
_logger.LogInformation("V3 支付结果: OrderNo={OrderNo}, TradeState={TradeState}, Attach={Attach}",
orderNo, paymentResult.TradeState, attach);
// 6. 检查支付状态
if (paymentResult.TradeState != WechatPayV3TradeState.Success)
{
_logger.LogWarning("V3 支付状态非成功: OrderNo={OrderNo}, TradeState={TradeState}",
orderNo, paymentResult.TradeState);
// 即使支付失败,也返回成功响应,避免微信重复通知
return new NotifyResult
{
Success = true,
Message = "支付未成功",
JsonResponse = successResponse
};
}
// 7. 幂等性检查 - 检查订单是否已处理
if (await IsOrderProcessedAsync(orderNo))
{
_logger.LogInformation("订单已处理,跳过重复回调: OrderNo={OrderNo}", orderNo);
return new NotifyResult
{
Success = true,
Message = "订单已处理",
JsonResponse = successResponse
};
}
// 8. 记录回调通知(转换为 V2 格式以复用现有逻辑)
var notifyData = ConvertV3ToV2NotifyData(paymentResult);
await RecordNotifyAsync(orderNo, notifyData);
// 9. 返回成功,业务处理由具体业务模块实现
_logger.LogInformation("微信支付 V3 回调记录成功: OrderNo={OrderNo}, Attach={Attach}", orderNo, attach);
return new NotifyResult
{
Success = true,
Message = "处理成功",
JsonResponse = successResponse,
OrderNo = orderNo,
Attach = attach,
NotifyData = notifyData
};
}
catch (InvalidOperationException ex)
{
_logger.LogError(ex, "V3 回调解密失败");
return new NotifyResult
{
Success = false,
Message = $"解密失败: {ex.Message}",
JsonResponse = failResponse
};
}
catch (Exception ex)
{
_logger.LogError(ex, "处理微信支付 V3 回调异常");
// 异常情况也返回成功,避免微信重复通知
return new NotifyResult
{
Success = false,
Message = $"处理异常: {ex.Message}",
JsonResponse = successResponse
};
}
}
///
/// 将 V3 支付结果转换为 V2 格式(复用现有处理逻辑)
///
private static WechatNotifyData ConvertV3ToV2NotifyData(WechatPayV3PaymentResult v3Result)
{
return new WechatNotifyData
{
ReturnCode = "SUCCESS",
ResultCode = v3Result.TradeState == WechatPayV3TradeState.Success ? "SUCCESS" : "FAIL",
OutTradeNo = v3Result.OutTradeNo,
TransactionId = v3Result.TransactionId,
TotalFee = v3Result.Amount.Total,
OpenId = v3Result.Payer.OpenId,
Attach = v3Result.Attach,
NonceStr = Guid.NewGuid().ToString("N")[..32]
};
}
///
public async Task IsOrderProcessedAsync(string orderNo)
{
var notify = await _dbContext.OrderNotifies
.FirstOrDefaultAsync(n => n.OrderNo == orderNo && n.Status == 1);
return notify != null;
}
///
public async Task RecordNotifyAsync(string orderNo, WechatNotifyData notifyData)
{
try
{
// 检查是否已存在记录
var existingNotify = await _dbContext.OrderNotifies
.FirstOrDefaultAsync(n => n.OrderNo == orderNo);
if (existingNotify != null)
{
// 更新现有记录
existingNotify.TransactionId = notifyData.TransactionId;
existingNotify.PayTime = DateTime.Now;
existingNotify.PayAmount = notifyData.TotalFee / 100m;
existingNotify.RawData = null; // 可选:存储原始XML
existingNotify.UpdateTime = DateTime.Now;
}
else
{
// 创建新记录
var notify = new OrderNotify
{
OrderNo = orderNo,
TransactionId = notifyData.TransactionId,
NonceStr = notifyData.NonceStr,
PayTime = DateTime.Now,
PayAmount = notifyData.TotalFee / 100m,
Status = 0, // 待处理
Attach = notifyData.Attach,
OpenId = notifyData.OpenId,
RawData = null,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now
};
_dbContext.OrderNotifies.Add(notify);
}
await _dbContext.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "记录支付回调通知失败: {OrderNo}", orderNo);
return false;
}
}
///
public async Task UpdateNotifyStatusAsync(string orderNo, byte status, string? message = null)
{
try
{
var notify = await _dbContext.OrderNotifies
.FirstOrDefaultAsync(n => n.OrderNo == orderNo);
if (notify != null)
{
notify.Status = status;
notify.ErrorMessage = message;
notify.UpdateTime = DateTime.Now;
await _dbContext.SaveChangesAsync();
return true;
}
_logger.LogWarning("更新订单通知状态失败,未找到记录: OrderNo={OrderNo}", orderNo);
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "更新订单通知状态异常: OrderNo={OrderNo}", orderNo);
return false;
}
}
}