Files
Yi.Framework/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PremiumPackageManager.cs

181 lines
6.2 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 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;
}
}