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; } } }