diff --git a/SeaHaven.DataServices/Implementation/DashboardDataService.cs b/SeaHaven.DataServices/Implementation/DashboardDataService.cs index a56f74f..91c545d 100644 --- a/SeaHaven.DataServices/Implementation/DashboardDataService.cs +++ b/SeaHaven.DataServices/Implementation/DashboardDataService.cs @@ -88,6 +88,70 @@ namespace SeaHaven.DataServices.Implementation .ToListAsync(cancellationToken); } + public async Task GetKpiCountsAsync( + int? accountId, + string? dispatcherId, + DateOnly today, + CancellationToken cancellationToken) + { + var tomorrow = today.AddDays(1); + var dayAfterTomorrow = tomorrow.AddDays(1); + var workOrders = WorkOrderBoardQueryFilters.ApplyBaseScope(_context.workOrders.AsNoTracking()); + if (accountId is int scopedAccountId) + workOrders = WorkOrderBoardQueryFilters.ApplyAccountScope(workOrders, scopedAccountId); + if (dispatcherId != null) + workOrders = workOrders.Where(w => w.AssignTo == dispatcherId); + + var scheduledTomorrow = await workOrders + .Where(w => w.ScheduledDate >= tomorrow.ToDateTime(TimeOnly.MinValue) + && w.ScheduledDate < dayAfterTomorrow.ToDateTime(TimeOnly.MinValue)) + .CountAsync(cancellationToken); + + var avetaPending = await workOrders + .Where(w => w.ScheduledDate >= today.ToDateTime(TimeOnly.MinValue) + && w.ScheduledDate < dayAfterTomorrow.ToDateTime(TimeOnly.MinValue) + && w.AvetaRequired + && w.LifecycleStatus != LifecycleStatus.Completed + && w.LifecycleStatus != LifecycleStatus.Canceled + && (w.LifecycleStatus != null + || ((w.LegacyStatus ?? w.Status) != "Done" + && (w.LegacyStatus ?? w.Status) != "Completed" + && (w.LegacyStatus ?? w.Status) != "Complete" + && (w.LegacyStatus ?? w.Status) != "Closed" + && (w.LegacyStatus ?? w.Status) != "Canceled" + && (w.LegacyStatus ?? w.Status) != "Cancelled")) + && !w.workOrderAttachments!.Any(attachment => + (attachment.IsDeleted == null || attachment.IsDeleted == false) + && attachment.Category == WorkOrderMediaCategory.Aveta)) + .CountAsync(cancellationToken); + + var pendingUplifts = _context.DispatchUpliftRequests + .AsNoTracking() + .Where(request => request.Status == "Pending" + && (request.IsDeleted == null || request.IsDeleted == false) + && request.Dispatch != null + && (request.Dispatch.IsDeleted == null || request.Dispatch.IsDeleted == false)); + if (accountId is int account) + { + pendingUplifts = pendingUplifts.Where(request => + (request.Dispatch!.WorkOrder != null && request.Dispatch.WorkOrder.AccountId == account) + || request.Dispatch.DispatchWorkOrders!.Any(link => + link.WorkOrder != null && link.WorkOrder.AccountId == account)); + } + if (dispatcherId != null) + { + pendingUplifts = pendingUplifts.Where(request => + (request.Dispatch!.WorkOrder != null && request.Dispatch.WorkOrder.AssignTo == dispatcherId) + || request.Dispatch.DispatchWorkOrders!.Any(link => + link.WorkOrder != null && link.WorkOrder.AssignTo == dispatcherId)); + } + + return new DashboardKpiCounts( + scheduledTomorrow, + await pendingUplifts.CountAsync(cancellationToken), + avetaPending); + } + public async Task> GetDispatcherWorkloadAsync( int? accountId, string? dispatcherId, diff --git a/SeaHaven.DataServices/Interfaces/IDashboardDataService.cs b/SeaHaven.DataServices/Interfaces/IDashboardDataService.cs index 5348703..51ef7b5 100644 --- a/SeaHaven.DataServices/Interfaces/IDashboardDataService.cs +++ b/SeaHaven.DataServices/Interfaces/IDashboardDataService.cs @@ -8,6 +8,12 @@ namespace SeaHaven.DataServices.Interfaces int? accountId, CancellationToken cancellationToken); + Task GetKpiCountsAsync( + int? accountId, + string? dispatcherId, + DateOnly today, + CancellationToken cancellationToken); + Task> GetDashboardWorkOrdersAsync( int? accountId, string? dispatcherId, @@ -53,4 +59,9 @@ namespace SeaHaven.DataServices.Interfaces public int NotDispatched { get; set; } public int Completed { get; set; } } + + public sealed record DashboardKpiCounts( + int ScheduledTomorrow, + int PendingUplifts, + int AvetaPending); } diff --git a/SeaHaven.Services/DTOs/DashboardDTOs.cs b/SeaHaven.Services/DTOs/DashboardDTOs.cs index ef5c70d..3544ebb 100644 --- a/SeaHaven.Services/DTOs/DashboardDTOs.cs +++ b/SeaHaven.Services/DTOs/DashboardDTOs.cs @@ -100,6 +100,9 @@ namespace SeaHaven.Services.DTOs public int Open { get; set; } public int NotDispatched { get; set; } public int Completed { get; set; } + public int ScheduledTomorrow { get; set; } + public int PendingUplifts { get; set; } + public int AvetaPending { get; set; } public DashboardBreakdownDTO Breakdown { get; set; } = new(); public int DueCount { get; set; } public int CompletedDueCount { get; set; } diff --git a/SeaHaven.Services/Implementation/DashboardService.cs b/SeaHaven.Services/Implementation/DashboardService.cs index a4bdfce..3193c08 100644 --- a/SeaHaven.Services/Implementation/DashboardService.cs +++ b/SeaHaven.Services/Implementation/DashboardService.cs @@ -35,6 +35,11 @@ namespace SeaHaven.Services.Implementation throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required."); var counts = await _dataService.GetWorkOrderCountsAsync(accountId, cancellationToken); + var kpis = await _dataService.GetKpiCountsAsync( + accountId, + dispatcherId, + DashboardBusinessTime.Today(), + cancellationToken); var workOrders = await _dataService.GetDashboardWorkOrdersAsync( accountId, dispatcherId, @@ -51,6 +56,9 @@ namespace SeaHaven.Services.Implementation Open = useMetrics ? metrics.Open : counts.Open, NotDispatched = useMetrics ? metrics.NotDispatched : counts.NotDispatched, Completed = useMetrics ? metrics.Completed : counts.Completed, + ScheduledTomorrow = kpis.ScheduledTomorrow, + PendingUplifts = kpis.PendingUplifts, + AvetaPending = kpis.AvetaPending, Breakdown = metrics.Breakdown, DueCount = metrics.DueCount, CompletedDueCount = metrics.CompletedDueCount,