using MediatR;
using TakeoutSaaS.Application.App.QuotaPackages.Commands;
using TakeoutSaaS.Application.App.QuotaPackages.Dto;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Ids;
namespace TakeoutSaaS.Application.App.QuotaPackages.Handlers;
///
/// 购买配额包命令处理器。
///
public sealed class PurchaseQuotaPackageCommandHandler(
IQuotaPackageRepository quotaPackageRepository,
ITenantQuotaUsageHistoryRepository quotaUsageHistoryRepository,
IIdGenerator idGenerator)
: IRequestHandler
{
///
public async Task Handle(PurchaseQuotaPackageCommand request, CancellationToken cancellationToken)
{
// 1. 查找配额包
var quotaPackage = await quotaPackageRepository.FindByIdAsync(request.QuotaPackageId, cancellationToken);
if (quotaPackage == null)
{
throw new InvalidOperationException("配额包不存在");
}
// 2. 创建购买记录
var purchase = new TenantQuotaPackagePurchase
{
Id = idGenerator.NextId(),
TenantId = request.TenantId,
QuotaPackageId = request.QuotaPackageId,
QuotaValue = quotaPackage.QuotaValue,
Price = quotaPackage.Price,
PurchasedAt = DateTime.UtcNow,
ExpiredAt = request.ExpiredAt,
Notes = request.Notes,
CreatedAt = DateTime.UtcNow
};
// 3. 保存购买记录
await quotaPackageRepository.AddPurchaseAsync(purchase, cancellationToken);
// 4. 更新租户配额(根据配额类型更新对应配额)
var quotaUsage = await quotaPackageRepository.FindUsageAsync(request.TenantId, quotaPackage.QuotaType, cancellationToken);
if (quotaUsage != null)
{
var beforeLimit = quotaUsage.LimitValue;
quotaUsage.LimitValue += quotaPackage.QuotaValue;
await quotaPackageRepository.UpdateUsageAsync(quotaUsage, cancellationToken);
// 4.1 记录配额变更历史(购买配额包视为“剩余增加”)
await quotaUsageHistoryRepository.AddAsync(new TenantQuotaUsageHistory
{
TenantId = request.TenantId,
QuotaType = quotaPackage.QuotaType,
UsedValue = quotaUsage.UsedValue,
LimitValue = quotaUsage.LimitValue,
RecordedAt = DateTime.UtcNow,
ChangeType = TenantQuotaUsageHistoryChangeType.Increase,
ChangeAmount = quotaUsage.LimitValue - beforeLimit,
ChangeReason = $"购买配额包:{quotaPackage.Name}"
}, cancellationToken);
}
await quotaPackageRepository.SaveChangesAsync(cancellationToken);
// 5. 返回 DTO
return new TenantQuotaPurchaseDto
{
Id = purchase.Id,
TenantId = purchase.TenantId,
QuotaPackageId = purchase.QuotaPackageId,
QuotaPackageName = quotaPackage.Name,
QuotaType = quotaPackage.QuotaType,
QuotaValue = purchase.QuotaValue,
Price = purchase.Price,
PurchasedAt = purchase.PurchasedAt,
ExpiredAt = purchase.ExpiredAt,
Notes = purchase.Notes
};
}
}