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