181 lines
6.2 KiB
C#
181 lines
6.2 KiB
C#
using Microsoft.Extensions.Logging;
|
||
using Volo.Abp.Domain.Services;
|
||
using Yi.Framework.AiHub.Domain.Entities;
|
||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||
|
||
namespace Yi.Framework.AiHub.Domain.Managers;
|
||
|
||
/// <summary>
|
||
/// 尊享包管理器
|
||
/// </summary>
|
||
public class PremiumPackageManager : DomainService
|
||
{
|
||
private readonly ISqlSugarRepository<PremiumPackageAggregateRoot, Guid> _premiumPackageRepository;
|
||
private readonly ILogger<PremiumPackageManager> _logger;
|
||
|
||
public PremiumPackageManager(
|
||
ISqlSugarRepository<PremiumPackageAggregateRoot, Guid> premiumPackageRepository,
|
||
ILogger<PremiumPackageManager> logger)
|
||
{
|
||
_premiumPackageRepository = premiumPackageRepository;
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 为用户创建尊享包
|
||
/// </summary>
|
||
/// <param name="userId">用户ID</param>
|
||
/// <param name="goodsType">商品类型</param>
|
||
/// <param name="totalAmount">支付金额</param>
|
||
/// <param name="expireMonths">过期月数,0或null表示永久</param>
|
||
/// <returns></returns>
|
||
public async Task<PremiumPackageAggregateRoot> CreatePremiumPackageAsync(
|
||
Guid userId,
|
||
GoodsTypeEnum goodsType,
|
||
decimal totalAmount,
|
||
int? expireMonths = null)
|
||
{
|
||
if (!goodsType.IsPremiumPackage())
|
||
{
|
||
throw new UserFriendlyException($"商品类型 {goodsType} 不是尊享包商品");
|
||
}
|
||
|
||
var tokenAmount = goodsType.GetTokenAmount();
|
||
var packageName = goodsType.GetDisplayName();
|
||
|
||
var premiumPackage = new PremiumPackageAggregateRoot(userId, tokenAmount, packageName)
|
||
{
|
||
PurchaseAmount = totalAmount
|
||
};
|
||
|
||
// 设置到期时间
|
||
if (expireMonths.HasValue && expireMonths.Value > 0)
|
||
{
|
||
premiumPackage.SetExpireDateTime(DateTime.Now.AddMonths(expireMonths.Value));
|
||
}
|
||
|
||
await _premiumPackageRepository.InsertAsync(premiumPackage);
|
||
|
||
_logger.LogInformation(
|
||
$"用户 {userId} 购买尊享包成功: {packageName}, Token数量: {tokenAmount}, 金额: {totalAmount}");
|
||
|
||
return premiumPackage;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 消耗用户尊享包的Token
|
||
/// </summary>
|
||
/// <param name="userId">用户ID</param>
|
||
/// <param name="tokenCount">需要消耗的Token数量</param>
|
||
/// <returns>是否消耗成功</returns>
|
||
public async Task<bool> ConsumeTokensAsync(Guid userId, long tokenCount)
|
||
{
|
||
// 获取用户所有可用的尊享包,按剩余token升序排列(优先消耗快用完的)
|
||
var availablePackages = await _premiumPackageRepository._DbQueryable
|
||
.Where(x => x.UserId == userId && x.IsActive)
|
||
.OrderBy(x => x.RemainingTokens)
|
||
.ToListAsync();
|
||
|
||
if (!availablePackages.Any())
|
||
{
|
||
_logger.LogWarning($"用户 {userId} 没有可用的尊享包");
|
||
return false;
|
||
}
|
||
|
||
// 过滤掉已过期的包
|
||
var validPackages = availablePackages
|
||
.Where(p => p.IsAvailable())
|
||
.ToList();
|
||
|
||
if (!validPackages.Any())
|
||
{
|
||
_logger.LogWarning($"用户 {userId} 的尊享包已全部过期");
|
||
return false;
|
||
}
|
||
|
||
// 计算总可用Token
|
||
var totalAvailableTokens = validPackages.Sum(p => p.RemainingTokens);
|
||
if (totalAvailableTokens < tokenCount)
|
||
{
|
||
_logger.LogWarning(
|
||
$"用户 {userId} 尊享包Token不足,需要: {tokenCount}, 可用: {totalAvailableTokens},将扣减到负数");
|
||
}
|
||
|
||
// 从可用的包中逐个扣除Token,允许扣减到负数
|
||
var remainingToConsume = tokenCount;
|
||
foreach (var package in validPackages)
|
||
{
|
||
if (remainingToConsume <= 0)
|
||
break;
|
||
|
||
// 直接扣除剩余需要消耗的token,允许扣减到负数
|
||
var toConsume = remainingToConsume;
|
||
if (package.ConsumeTokens(toConsume))
|
||
{
|
||
await _premiumPackageRepository.UpdateAsync(package);
|
||
remainingToConsume -= toConsume;
|
||
|
||
_logger.LogInformation(
|
||
$"用户 {userId} 从尊享包 {package.Id} 消耗 {toConsume} tokens, 剩余: {package.RemainingTokens}");
|
||
}
|
||
}
|
||
|
||
return remainingToConsume == 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取用户可用的尊享包总Token数
|
||
/// </summary>
|
||
/// <param name="userId">用户ID</param>
|
||
/// <returns>可用Token总数</returns>
|
||
public async Task<long> GetAvailableTokensAsync(Guid userId)
|
||
{
|
||
return await _premiumPackageRepository._DbQueryable
|
||
.Where(x => x.UserId == userId && x.IsActive && x.RemainingTokens > 0)
|
||
.Where(p => p.IsAvailable())
|
||
.SumAsync(p => p.RemainingTokens);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取用户的所有尊享包
|
||
/// </summary>
|
||
/// <param name="userId">用户ID</param>
|
||
/// <returns>尊享包列表</returns>
|
||
public async Task<List<PremiumPackageAggregateRoot>> GetUserPremiumPackagesAsync(Guid userId)
|
||
{
|
||
return await _premiumPackageRepository._DbQueryable
|
||
.Where(x => x.UserId == userId)
|
||
.OrderByDescending(x => x.CreationTime)
|
||
.ToListAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停用过期的尊享包
|
||
/// </summary>
|
||
/// <returns>停用的包数量</returns>
|
||
public async Task<int> DeactivateExpiredPackagesAsync()
|
||
{
|
||
_logger.LogInformation("开始执行尊享包过期自动停用任务");
|
||
|
||
var now = DateTime.Now;
|
||
var expiredPackages = await _premiumPackageRepository._DbQueryable
|
||
.Where(x => x.IsActive && x.ExpireDateTime.HasValue && x.ExpireDateTime.Value < now)
|
||
.ToListAsync();
|
||
|
||
if (!expiredPackages.Any())
|
||
{
|
||
_logger.LogInformation("没有找到过期的尊享包");
|
||
return 0;
|
||
}
|
||
|
||
foreach (var package in expiredPackages)
|
||
{
|
||
package.Deactivate();
|
||
await _premiumPackageRepository.UpdateAsync(package);
|
||
}
|
||
|
||
_logger.LogInformation($"成功停用 {expiredPackages.Count} 个过期的尊享包");
|
||
return expiredPackages.Count;
|
||
}
|
||
} |