using MediatR; using Microsoft.Extensions.Logging; using System.Text.Json; using TakeoutSaaS.Application.App.Subscriptions.Commands; using TakeoutSaaS.Domain.Tenants.Entities; using TakeoutSaaS.Domain.Tenants.Enums; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Ids; namespace TakeoutSaaS.Application.App.Subscriptions.Handlers; /// /// 批量延期订阅命令处理器。 /// public sealed class BatchExtendSubscriptionsCommandHandler( ISubscriptionRepository subscriptionRepository, IIdGenerator idGenerator, ILogger logger) : IRequestHandler { /// public async Task Handle(BatchExtendSubscriptionsCommand request, CancellationToken cancellationToken) { var successCount = 0; var failures = new List(); // 验证参数 if (!request.DurationDays.HasValue && !request.DurationMonths.HasValue) { throw new InvalidOperationException("必须指定延期天数或延期月数"); } // 计算延期时间 var extendDays = request.DurationDays ?? 0; var extendMonths = request.DurationMonths ?? 0; // 查询所有订阅 var subscriptions = await subscriptionRepository.FindByIdsAsync( request.SubscriptionIds, cancellationToken); foreach (var subscriptionId in request.SubscriptionIds) { try { var subscription = subscriptions.FirstOrDefault(s => s.Id == subscriptionId); if (subscription == null) { failures.Add(new BatchFailureItem { SubscriptionId = subscriptionId, Reason = "订阅不存在" }); continue; } // 记录原始到期时间 var originalEffectiveTo = subscription.EffectiveTo; // 计算新的到期时间 var newEffectiveTo = subscription.EffectiveTo; if (extendMonths > 0) { newEffectiveTo = newEffectiveTo.AddMonths(extendMonths); } if (extendDays > 0) { newEffectiveTo = newEffectiveTo.AddDays(extendDays); } subscription.EffectiveTo = newEffectiveTo; // 更新备注 if (!string.IsNullOrWhiteSpace(request.Notes)) { subscription.Notes = request.Notes; } // 记录变更历史 var history = new TenantSubscriptionHistory { Id = idGenerator.NextId(), TenantId = subscription.TenantId, TenantSubscriptionId = subscription.Id, FromPackageId = subscription.TenantPackageId, ToPackageId = subscription.TenantPackageId, ChangeType = SubscriptionChangeType.Renew, EffectiveFrom = originalEffectiveTo, EffectiveTo = newEffectiveTo, Amount = null, Currency = null, Notes = request.Notes ?? $"批量延期: {(extendMonths > 0 ? $"{extendMonths}个月" : "")}{(extendDays > 0 ? $"{extendDays}天" : "")}" }; await subscriptionRepository.AddHistoryAsync(history, cancellationToken); await subscriptionRepository.UpdateAsync(subscription, cancellationToken); successCount++; } catch (Exception ex) { logger.LogError(ex, "批量延期订阅失败: SubscriptionId={SubscriptionId}", subscriptionId); failures.Add(new BatchFailureItem { SubscriptionId = subscriptionId, Reason = $"处理失败: {ex.Message}" }); } } // 记录操作日志 var operationLog = new OperationLog { Id = idGenerator.NextId(), OperationType = "BatchExtend", TargetType = "Subscription", TargetIds = JsonSerializer.Serialize(request.SubscriptionIds), Parameters = JsonSerializer.Serialize(new { request.DurationDays, request.DurationMonths, request.Notes }), Result = JsonSerializer.Serialize(new { SuccessCount = successCount, FailureCount = failures.Count }), Success = failures.Count == 0, CreatedAt = DateTime.UtcNow }; await subscriptionRepository.AddOperationLogAsync(operationLog, cancellationToken); // 保存所有更改 await subscriptionRepository.SaveChangesAsync(cancellationToken); return new BatchExtendResult { SuccessCount = successCount, FailureCount = failures.Count, Failures = failures }; } }