using MediatR; using TakeoutSaaS.Application.App.Billings.Commands; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; namespace TakeoutSaaS.Application.App.Billings.Handlers; /// /// 批量更新账单状态处理器。 /// public sealed class BatchUpdateStatusCommandHandler( ITenantBillingRepository billingRepository) : IRequestHandler { /// /// 处理批量更新账单状态请求。 /// /// 批量更新状态命令。 /// 取消标记。 /// 成功更新的账单数量。 public async Task Handle(BatchUpdateStatusCommand request, CancellationToken cancellationToken) { // 1. 参数验证 if (request.BillingIds.Length == 0) { throw new BusinessException(ErrorCodes.BadRequest, "账单 ID 列表不能为空"); } // 2. 查询所有账单 var billings = await billingRepository.GetByIdsAsync(request.BillingIds, cancellationToken); if (billings.Count == 0) { throw new BusinessException(ErrorCodes.NotFound, "未找到任何匹配的账单"); } // 3. 批量更新状态 var now = DateTime.UtcNow; var updatedCount = 0; foreach (var billing in billings) { // 业务规则检查:某些状态转换可能不允许 if (CanTransitionStatus(billing.Status, request.NewStatus)) { billing.Status = request.NewStatus; billing.UpdatedAt = now; if (!string.IsNullOrWhiteSpace(request.Notes)) { billing.Notes = string.IsNullOrWhiteSpace(billing.Notes) ? $"[批量操作] {request.Notes}" : $"{billing.Notes}\n[批量操作] {request.Notes}"; } await billingRepository.UpdateAsync(billing, cancellationToken); updatedCount++; } } // 4. 持久化变更 await billingRepository.SaveChangesAsync(cancellationToken); return updatedCount; } /// /// 检查状态转换是否允许。 /// private static bool CanTransitionStatus( TakeoutSaaS.Domain.Tenants.Enums.TenantBillingStatus currentStatus, TakeoutSaaS.Domain.Tenants.Enums.TenantBillingStatus newStatus) { // 已支付的账单不能改为其他状态 if (currentStatus == TakeoutSaaS.Domain.Tenants.Enums.TenantBillingStatus.Paid && newStatus != TakeoutSaaS.Domain.Tenants.Enums.TenantBillingStatus.Paid) { return false; } // 已取消的账单不能改为其他状态 if (currentStatus == TakeoutSaaS.Domain.Tenants.Enums.TenantBillingStatus.Cancelled) { return false; } return true; } }