HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/PaymentNotifyService.cs
2026-01-25 20:28:11 +08:00

1151 lines
43 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text.Json;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Lottery;
using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace HoneyBox.Core.Services;
/// <summary>
/// 支付回调服务实现
/// </summary>
public class PaymentNotifyService : IPaymentNotifyService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly IWechatPayService _wechatPayService;
private readonly IWechatPayV3Service _wechatPayV3Service;
private readonly IWechatPayConfigService _wechatPayConfigService;
private readonly IPaymentService _paymentService;
private readonly ILotteryEngine _lotteryEngine;
private readonly ILogger<PaymentNotifyService> _logger;
/// <summary>
/// 一番赏类订单类型列表
/// </summary>
private static readonly string[] LotteryOrderTypes = new[]
{
OrderAttachType.OrderYfs,
OrderAttachType.OrderLts,
OrderAttachType.OrderZzs,
OrderAttachType.OrderFlw,
OrderAttachType.OrderScs
};
/// <summary>
/// 无限赏类订单类型列表
/// </summary>
private static readonly string[] InfiniteOrderTypes = new[]
{
OrderAttachType.OrderWxs,
OrderAttachType.OrderFbs
};
public PaymentNotifyService(
HoneyBoxDbContext dbContext,
IWechatPayService wechatPayService,
IWechatPayV3Service wechatPayV3Service,
IWechatPayConfigService wechatPayConfigService,
IPaymentService paymentService,
ILotteryEngine lotteryEngine,
ILogger<PaymentNotifyService> logger)
{
_dbContext = dbContext;
_wechatPayService = wechatPayService;
_wechatPayV3Service = wechatPayV3Service;
_wechatPayConfigService = wechatPayConfigService;
_paymentService = paymentService;
_lotteryEngine = lotteryEngine;
_logger = logger;
}
/// <inheritdoc />
public async Task<NotifyResult> 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", "无法识别的回调格式")
}
};
}
/// <inheritdoc />
public async Task<NotifyResult> 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. 根据订单类型路由处理
var processResult = await RouteOrderProcessingAsync(orderNo, attach, notifyData);
if (processResult)
{
_logger.LogInformation("微信支付回调处理成功: OrderNo={OrderNo}", orderNo);
return new NotifyResult
{
Success = true,
Message = "处理成功",
XmlResponse = successResponse
};
}
else
{
_logger.LogWarning("微信支付回调处理失败: OrderNo={OrderNo}", orderNo);
// 处理失败也返回成功,避免微信重复通知,后续通过其他机制处理
return new NotifyResult
{
Success = false,
Message = "处理失败",
XmlResponse = successResponse
};
}
}
catch (Exception ex)
{
_logger.LogError(ex, "处理微信支付回调异常");
// 异常情况也返回成功,避免微信重复通知
return new NotifyResult
{
Success = false,
Message = $"处理异常: {ex.Message}",
XmlResponse = successResponse
};
}
}
/// <inheritdoc />
public async Task<NotifyResult> 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<WechatPayV3Notification>(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<WechatPayV3PaymentResult>(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. 根据订单类型路由处理
var processResult = await RouteOrderProcessingAsync(orderNo, attach, notifyData);
if (processResult)
{
_logger.LogInformation("微信支付 V3 回调处理成功: OrderNo={OrderNo}", orderNo);
return new NotifyResult
{
Success = true,
Message = "处理成功",
JsonResponse = successResponse
};
}
else
{
_logger.LogWarning("微信支付 V3 回调处理失败: OrderNo={OrderNo}", orderNo);
// 处理失败也返回成功,避免微信重复通知
return new NotifyResult
{
Success = false,
Message = "处理失败",
JsonResponse = successResponse
};
}
}
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
};
}
}
/// <summary>
/// 将 V3 支付结果转换为 V2 格式(复用现有处理逻辑)
/// </summary>
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]
};
}
/// <summary>
/// 根据订单类型路由到对应的处理方法
/// </summary>
/// <param name="orderNo">订单号</param>
/// <param name="attach">附加数据(订单类型)</param>
/// <param name="notifyData">回调数据</param>
/// <returns>是否处理成功</returns>
private async Task<bool> RouteOrderProcessingAsync(string orderNo, string attach, WechatNotifyData notifyData)
{
try
{
// 获取用户信息
var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.OpenId == notifyData.OpenId);
if (user == null)
{
_logger.LogWarning("未找到用户: OpenId={OpenId}", notifyData.OpenId);
return false;
}
// 记录支付流水
await RecordPaymentAsync(user.Id, orderNo, notifyData.TotalFee / 100m, attach);
// 根据attach类型路由处理
if (attach == OrderAttachType.UserRecharge)
{
// 余额充值
return await ProcessRechargeOrderAsync(orderNo);
}
else if (LotteryOrderTypes.Contains(attach))
{
// 一番赏类订单
return await ProcessLotteryOrderByOrderNoAsync(orderNo);
}
else if (InfiniteOrderTypes.Contains(attach))
{
// 无限赏类订单
return await ProcessInfiniteOrderByOrderNoAsync(orderNo);
}
else if (attach == OrderAttachType.OrderCkj)
{
// 抽卡机订单
return await ProcessCardExtractorOrderByOrderNoAsync(orderNo);
}
else if (attach == OrderAttachType.OrderListSend)
{
// 发货运费订单
return await ProcessShippingFeeOrderAsync(orderNo);
}
else
{
_logger.LogWarning("未知的订单类型: Attach={Attach}, OrderNo={OrderNo}", attach, orderNo);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "路由订单处理异常: OrderNo={OrderNo}, Attach={Attach}", orderNo, attach);
return false;
}
}
/// <summary>
/// 记录支付流水委托给PaymentService
/// </summary>
private async Task RecordPaymentAsync(int userId, string orderNo, decimal amount, string content)
{
// 根据content确定支付说明
var paymentContent = string.IsNullOrEmpty(content) ? "微信支付" : content;
// 委托给PaymentService处理
var result = await _paymentService.RecordPaymentAsync(userId, orderNo, amount, PaymentType.WechatPay, paymentContent);
if (!result)
{
_logger.LogWarning("记录支付流水失败: UserId={UserId}, OrderNo={OrderNo}", userId, orderNo);
}
}
/// <summary>
/// 根据订单号处理一番赏订单
/// </summary>
private async Task<bool> ProcessLotteryOrderByOrderNoAsync(string orderNo)
{
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.OrderNum == orderNo && o.Status == 0);
if (order == null)
{
_logger.LogWarning("未找到待支付的一番赏订单: OrderNo={OrderNo}", orderNo);
return false;
}
return await ProcessLotteryOrderAsync(order.Id, order.UserId, order.GoodsId, order.Num);
}
/// <summary>
/// 根据订单号处理无限赏订单
/// </summary>
private async Task<bool> ProcessInfiniteOrderByOrderNoAsync(string orderNo)
{
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.OrderNum == orderNo && o.Status == 0);
if (order == null)
{
_logger.LogWarning("未找到待支付的无限赏订单: OrderNo={OrderNo}", orderNo);
return false;
}
return await ProcessInfiniteOrderAsync(order.Id, order.UserId, order.GoodsId);
}
/// <summary>
/// 根据订单号处理抽卡机订单
/// </summary>
private async Task<bool> ProcessCardExtractorOrderByOrderNoAsync(string orderNo)
{
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.OrderNum == orderNo && o.Status == 0 && o.OrderType == 4);
if (order == null)
{
_logger.LogWarning("未找到待支付的抽卡机订单: OrderNo={OrderNo}", orderNo);
return false;
}
return await ProcessCardExtractorOrderAsync(order.Id, order.UserId, order.GoodsId);
}
/// <inheritdoc />
public async Task<bool> ProcessLotteryOrderAsync(int orderId, int userId, int goodsId, int num)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 1. 查找订单 - 支持一番赏类订单类型 (1=一番赏, 3=擂台赏, 5=转转赏, 6=福利屋, 11=商城赏, 15=福利屋特殊, 10=商城赏特殊)
var validOrderTypes = new byte[] { 1, 3, 5, 6, 11, 15, 10 };
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.Id == orderId
&& o.UserId == userId
&& o.GoodsId == goodsId
&& o.Num == num
&& o.Status == 0
&& validOrderTypes.Contains(o.OrderType));
if (order == null)
{
_logger.LogWarning("未找到待支付的一番赏订单: OrderId={OrderId}, UserId={UserId}, GoodsId={GoodsId}, Num={Num}",
orderId, userId, goodsId, num);
return false;
}
var goodsTitle = order.GoodsTitle ?? "商品";
var content = $"购买盒子{goodsTitle}";
// 2. 更新订单状态为已支付
order.Status = 1;
order.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
order.UpdatedAt = DateTime.Now;
// 3. 扣减用户资产(余额、积分、哈尼券)
// 扣减余额
if (order.UseMoney > 0)
{
var balanceResult = await _paymentService.DeductBalanceAsync(order.UserId, order.UseMoney, content, order.OrderNum);
if (!balanceResult.Success)
{
_logger.LogWarning("扣减余额失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseMoney, balanceResult.Message);
// 继续处理不中断流程PHP代码也是这样处理的
}
else
{
_logger.LogDebug("扣减余额成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney);
}
}
// 扣减积分(吧唧币)
if (order.UseIntegral > 0)
{
var integralResult = await _paymentService.DeductIntegralAsync(order.UserId, order.UseIntegral, content, order.OrderNum);
if (!integralResult.Success)
{
_logger.LogWarning("扣减积分失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseIntegral, integralResult.Message);
}
else
{
_logger.LogDebug("扣减积分成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseIntegral);
}
}
// 扣减哈尼券
if (order.UseMoney2 > 0)
{
var money2Result = await _paymentService.DeductMoney2Async(order.UserId, order.UseMoney2, content, order.OrderNum);
if (!money2Result.Success)
{
_logger.LogWarning("扣减哈尼券失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseMoney2, money2Result.Message);
}
else
{
_logger.LogDebug("扣减哈尼券成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney2);
}
}
// 4. 更新优惠券状态为已使用
if (order.CouponId.HasValue && order.CouponId.Value > 0)
{
await UpdateCouponStatusAsync(order.CouponId.Value);
}
// 5. 更新订单通知状态
await UpdateOrderNotifyStatusAsync(order.OrderNum, 1, "处理成功");
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("一番赏订单支付处理成功: OrderId={OrderId}, UserId={UserId}, GoodsId={GoodsId}, Num={Num}, OrderType={OrderType}",
orderId, userId, goodsId, num, order.OrderType);
// 6. 执行普通抽奖逻辑
await ExecuteLotteryAsync(userId, orderId, goodsId, order.OrderType, num, order.PrizeNum, order.OrderNum);
return true;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "处理一番赏订单失败: OrderId={OrderId}", orderId);
// 标记订单为卡单状态
await MarkOrderAsStuckAsync(orderId);
return false;
}
}
/// <summary>
/// 执行普通抽奖逻辑(一番赏、擂台赏、转转赏等)
/// </summary>
private async Task ExecuteLotteryAsync(int userId, int orderId, int goodsId, int orderType, int num, int prizeNum, string orderNum)
{
try
{
var drawRequest = new LotteryDrawRequest
{
UserId = userId,
GoodsId = goodsId,
Num = num,
OrderId = orderId,
OrderNum = orderNum,
OrderType = orderType,
Source = 1 // 抽奖获得
};
// 执行多次抽奖
var results = await _lotteryEngine.DrawMultipleAsync(drawRequest, prizeNum);
var successCount = results.Count(r => r.Success);
_logger.LogInformation("普通抽奖完成: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}, Num={Num}, PrizeNum={PrizeNum}, SuccessCount={SuccessCount}",
userId, orderId, goodsId, num, prizeNum, successCount);
if (successCount == 0)
{
_logger.LogWarning("普通抽奖全部失败: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}",
userId, orderId, goodsId);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "执行普通抽奖失败: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}",
userId, orderId, goodsId);
// 抽奖失败不影响支付回调处理,但需要记录日志以便后续处理
}
}
/// <inheritdoc />
public async Task<bool> ProcessInfiniteOrderAsync(int orderId, int userId, int goodsId)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 1. 查找订单 - 支持无限赏类订单类型
// 无限赏订单类型: 2=无限赏, 7=翻倍赏, 8=领主赏, 9=秘宝赏, 10=商城赏, 17=特殊无限赏
var validOrderTypes = new byte[] { 2, 7, 8, 9, 10, 17 };
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.Id == orderId
&& o.UserId == userId
&& o.GoodsId == goodsId
&& o.Status == 0);
// PHP逻辑: 如果num=0找不到订单尝试num=1针对order_type=10的商城赏
if (order == null)
{
_logger.LogWarning("未找到待支付的无限赏订单: OrderId={OrderId}, UserId={UserId}, GoodsId={GoodsId}",
orderId, userId, goodsId);
return false;
}
var goodsTitle = order.GoodsTitle ?? "商品";
var content = $"购买盒子{goodsTitle}";
// 2. 更新订单状态为已支付
order.Status = 1;
order.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
order.UpdatedAt = DateTime.Now;
// 3. 扣减用户资产(余额、积分、哈尼券)
// 扣减余额
if (order.UseMoney > 0)
{
var balanceResult = await _paymentService.DeductBalanceAsync(order.UserId, order.UseMoney, content, order.OrderNum);
if (!balanceResult.Success)
{
_logger.LogWarning("扣减余额失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseMoney, balanceResult.Message);
}
else
{
_logger.LogDebug("扣减余额成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney);
}
}
// 扣减积分(吧唧币)
if (order.UseIntegral > 0)
{
var integralResult = await _paymentService.DeductIntegralAsync(order.UserId, order.UseIntegral, content, order.OrderNum);
if (!integralResult.Success)
{
_logger.LogWarning("扣减积分失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseIntegral, integralResult.Message);
}
else
{
_logger.LogDebug("扣减积分成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseIntegral);
}
}
// 扣减哈尼券
if (order.UseMoney2 > 0)
{
var money2Result = await _paymentService.DeductMoney2Async(order.UserId, order.UseMoney2, content, order.OrderNum);
if (!money2Result.Success)
{
_logger.LogWarning("扣减哈尼券失败: UserId={UserId}, Amount={Amount}, Message={Message}",
order.UserId, order.UseMoney2, money2Result.Message);
}
else
{
_logger.LogDebug("扣减哈尼券成功: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney2);
}
}
// 4. 更新优惠券状态为已使用
if (order.CouponId.HasValue && order.CouponId.Value > 0)
{
await UpdateCouponStatusAsync(order.CouponId.Value);
}
// 5. 更新订单通知状态
await UpdateOrderNotifyStatusAsync(order.OrderNum, 1, "处理成功");
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("无限赏订单支付处理成功: OrderId={OrderId}, UserId={UserId}, GoodsId={GoodsId}, OrderType={OrderType}, PrizeNum={PrizeNum}",
orderId, userId, goodsId, order.OrderType, order.PrizeNum);
// 6. 执行无限赏抽奖逻辑
await ExecuteInfiniteLotteryAsync(userId, orderId, goodsId, order.OrderType, order.PrizeNum, order.OrderNum);
return true;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "处理无限赏订单失败: OrderId={OrderId}", orderId);
// 标记订单为卡单状态
await MarkOrderAsStuckAsync(orderId);
return false;
}
}
/// <summary>
/// 执行无限赏抽奖逻辑
/// </summary>
private async Task ExecuteInfiniteLotteryAsync(int userId, int orderId, int goodsId, int orderType, int prizeNum, string orderNum)
{
try
{
var drawRequest = new LotteryDrawRequest
{
UserId = userId,
GoodsId = goodsId,
Num = 0, // 无限赏固定为0
OrderId = orderId,
OrderNum = orderNum,
OrderType = orderType,
Source = 1 // 抽奖获得
};
// 执行多次抽奖
var results = await _lotteryEngine.DrawInfiniteMultipleAsync(drawRequest, prizeNum);
var successCount = results.Count(r => r.Success);
_logger.LogInformation("无限赏抽奖完成: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}, PrizeNum={PrizeNum}, SuccessCount={SuccessCount}",
userId, orderId, goodsId, prizeNum, successCount);
if (successCount == 0)
{
_logger.LogWarning("无限赏抽奖全部失败: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}",
userId, orderId, goodsId);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "执行无限赏抽奖失败: UserId={UserId}, OrderId={OrderId}, GoodsId={GoodsId}",
userId, orderId, goodsId);
// 抽奖失败不影响支付回调处理,但需要记录日志以便后续处理
}
}
/// <inheritdoc />
public async Task<bool> ProcessRechargeOrderAsync(string orderNo)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 1. 查找充值订单 - 状态为1待支付
var rechargeOrder = await _dbContext.UserRecharges
.FirstOrDefaultAsync(r => r.OrderNum == orderNo && r.Status == 1);
if (rechargeOrder == null)
{
_logger.LogWarning("未找到待支付的充值订单: OrderNo={OrderNo}", orderNo);
return false;
}
var userId = rechargeOrder.UserId;
var money = rechargeOrder.Money;
// 2. 更新充值订单状态为已完成
rechargeOrder.Status = 2; // 2=已完成
rechargeOrder.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// 3. 增加用户余额
var addBalanceResult = await _paymentService.AddBalanceAsync(userId, money, "在线充值", orderNo);
if (!addBalanceResult)
{
_logger.LogWarning("增加用户余额失败: UserId={UserId}, Amount={Amount}, OrderNo={OrderNo}",
userId, money, orderNo);
await transaction.RollbackAsync();
return false;
}
// 4. 记录微信支付流水
var profitPay = new ProfitPay
{
UserId = userId,
OrderNum = orderNo,
ChangeMoney = money,
Content = "微信支付",
PayType = (byte)PaymentType.WechatPay,
CreatedAt = DateTime.Now
};
_dbContext.ProfitPays.Add(profitPay);
// 5. 更新订单通知状态
await UpdateOrderNotifyStatusAsync(orderNo, 1, "处理成功");
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("充值订单处理成功: OrderNo={OrderNo}, UserId={UserId}, Money={Money}",
orderNo, userId, money);
return true;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "处理充值订单失败: OrderNo={OrderNo}", orderNo);
return false;
}
}
/// <inheritdoc />
public async Task<bool> ProcessShippingFeeOrderAsync(string orderNo)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 1. 查找发货记录
var sendRecord = await _dbContext.OrderItemsSends
.FirstOrDefaultAsync(s => s.SendNum == orderNo && s.Status == 0);
if (sendRecord == null)
{
_logger.LogWarning("未找到待支付的发货记录: OrderNo={OrderNo}", orderNo);
return false;
}
// 2. 更新发货记录状态为待发货
sendRecord.Status = 1; // 0待支付 -> 1待发货
sendRecord.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
sendRecord.UpdatedAt = DateTime.Now;
// 3. 更新关联的订单项状态
var orderItems = await _dbContext.OrderItems
.Where(oi => oi.UserId == sendRecord.UserId
&& oi.Status == 0
&& oi.GoodslistType == 1
&& oi.SendNum == sendRecord.SendNum)
.ToListAsync();
foreach (var item in orderItems)
{
item.Status = 2; // 选择发货
item.ChoiceTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
}
// 4. 更新订单通知状态
await UpdateOrderNotifyStatusAsync(orderNo, 1, "处理成功");
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("发货运费订单处理成功: OrderNo={OrderNo}, UserId={UserId}",
orderNo, sendRecord.UserId);
return true;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "处理发货运费订单失败: OrderNo={OrderNo}", orderNo);
return false;
}
}
/// <inheritdoc />
public async Task<bool> ProcessCardExtractorOrderAsync(int orderId, int userId, int goodsId)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 1. 查找订单
var order = await _dbContext.Orders
.FirstOrDefaultAsync(o => o.Id == orderId
&& o.UserId == userId
&& o.GoodsId == goodsId
&& o.Status == 0
&& o.OrderType == 4);
if (order == null)
{
_logger.LogWarning("未找到待支付的抽卡机订单: OrderId={OrderId}, UserId={UserId}", orderId, userId);
return false;
}
// 2. 更新订单状态为已支付
order.Status = 1;
order.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
order.UpdatedAt = DateTime.Now;
// 3. 扣减用户资产
await DeductUserAssetsAsync(order);
// 4. 更新优惠券状态
if (order.CouponId.HasValue && order.CouponId.Value > 0)
{
await UpdateCouponStatusAsync(order.CouponId.Value);
}
// 5. 更新订单通知状态
await UpdateOrderNotifyStatusAsync(order.OrderNum, 1, "处理成功");
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("抽卡机订单处理成功: OrderId={OrderId}, UserId={UserId}", orderId, userId);
// TODO: 触发抽卡机抽奖逻辑
return true;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "处理抽卡机订单失败: OrderId={OrderId}", orderId);
// 标记订单为卡单状态
await MarkOrderAsStuckAsync(orderId);
return false;
}
}
/// <inheritdoc />
public async Task<bool> IsOrderProcessedAsync(string orderNo)
{
var notify = await _dbContext.OrderNotifies
.FirstOrDefaultAsync(n => n.OrderNo == orderNo && n.Status == 1);
return notify != null;
}
/// <inheritdoc />
public async Task<bool> 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.UpdatedAt = 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,
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now
};
_dbContext.OrderNotifies.Add(notify);
}
await _dbContext.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "记录支付回调通知失败: {OrderNo}", orderNo);
return false;
}
}
#region Private Helper Methods
/// <summary>
/// 扣减用户资产(余额、积分、哈尼券)
/// </summary>
private async Task DeductUserAssetsAsync(Order order)
{
var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == order.UserId);
if (user == null)
{
_logger.LogWarning("扣减资产时未找到用户: UserId={UserId}", order.UserId);
return;
}
var goodsTitle = order.GoodsTitle ?? "商品";
var content = $"购买盒子{goodsTitle}";
// 扣减余额
if (order.UseMoney > 0)
{
await _paymentService.DeductBalanceAsync(order.UserId, order.UseMoney, content);
_logger.LogDebug("扣减余额: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney);
}
// 扣减积分(吧唧币)
if (order.UseIntegral > 0)
{
await _paymentService.DeductIntegralAsync(order.UserId, order.UseIntegral, content);
_logger.LogDebug("扣减积分: UserId={UserId}, Amount={Amount}", order.UserId, order.UseIntegral);
}
// 扣减哈尼券
if (order.UseMoney2 > 0)
{
await _paymentService.DeductMoney2Async(order.UserId, order.UseMoney2, content);
_logger.LogDebug("扣减哈尼券: UserId={UserId}, Amount={Amount}", order.UserId, order.UseMoney2);
}
}
/// <summary>
/// 更新优惠券状态为已使用
/// </summary>
private async Task UpdateCouponStatusAsync(int couponId)
{
var coupon = await _dbContext.CouponReceives
.FirstOrDefaultAsync(c => c.Id == couponId && c.Status == 0);
if (coupon != null)
{
coupon.Status = 1; // 已使用
_logger.LogDebug("更新优惠券状态: CouponId={CouponId}", couponId);
}
}
/// <summary>
/// 更新订单通知状态
/// </summary>
private async Task UpdateOrderNotifyStatusAsync(string orderNo, byte status, string? message = null)
{
var notify = await _dbContext.OrderNotifies
.FirstOrDefaultAsync(n => n.OrderNo == orderNo);
if (notify != null)
{
notify.Status = status;
notify.ErrorMessage = message;
notify.UpdatedAt = DateTime.Now;
}
}
/// <summary>
/// 标记订单为卡单状态
/// </summary>
private async Task MarkOrderAsStuckAsync(int orderId)
{
try
{
var order = await _dbContext.Orders.FirstOrDefaultAsync(o => o.Id == orderId);
if (order != null)
{
order.KdIs = 1; // 标记为卡单
order.UpdatedAt = DateTime.Now;
await _dbContext.SaveChangesAsync();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "标记订单卡单状态失败: OrderId={OrderId}", orderId);
}
}
#endregion
}