mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 06:23:16 +00:00
183 lines
7.9 KiB
C#
183 lines
7.9 KiB
C#
using System.Security.Claims;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Exceptions;
|
|
using SeaHaven.Services.Helpers;
|
|
using SeaHaven.Services.Interfaces;
|
|
|
|
namespace SeaHaven.Services.Implementation
|
|
{
|
|
public class DashboardService : IDashboardService
|
|
{
|
|
private readonly IDashboardDataService _dataService;
|
|
private readonly IWorkOrderAccountResolver _accountResolver;
|
|
|
|
public DashboardService(
|
|
IDashboardDataService dataService,
|
|
IWorkOrderAccountResolver accountResolver)
|
|
{
|
|
_dataService = dataService;
|
|
_accountResolver = accountResolver;
|
|
}
|
|
|
|
public async Task<DashboardStatsDTO> GetStatsAsync(
|
|
ClaimsPrincipal user,
|
|
DashboardStatsQueryDTO query,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
|
var dispatcherId = user.IsInRole("Dispatcher")
|
|
? user.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
: null;
|
|
if (user.IsInRole("Dispatcher") && string.IsNullOrWhiteSpace(dispatcherId))
|
|
throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required.");
|
|
|
|
var counts = await _dataService.GetWorkOrderCountsAsync(accountId, cancellationToken);
|
|
var workOrders = await _dataService.GetDashboardWorkOrdersAsync(
|
|
accountId,
|
|
dispatcherId,
|
|
query.DateFrom,
|
|
query.DateTo,
|
|
cancellationToken);
|
|
var metrics = DashboardMetrics.Calculate(workOrders, DashboardBusinessTime.Today());
|
|
|
|
var useMetrics = query.DateFrom.HasValue && query.DateTo.HasValue || dispatcherId is not null;
|
|
|
|
return new DashboardStatsDTO
|
|
{
|
|
Total = useMetrics ? metrics.Total : counts.Total,
|
|
Open = useMetrics ? metrics.Open : counts.Open,
|
|
NotDispatched = useMetrics ? metrics.NotDispatched : counts.NotDispatched,
|
|
Completed = useMetrics ? metrics.Completed : counts.Completed,
|
|
Breakdown = metrics.Breakdown,
|
|
DueCount = metrics.DueCount,
|
|
CompletedDueCount = metrics.CompletedDueCount,
|
|
CompletionRate = metrics.CompletionRate,
|
|
AverageResolutionDays = metrics.AverageResolutionDays
|
|
};
|
|
}
|
|
|
|
public async Task<DashboardWorkloadResponseDTO> GetWorkloadAsync(
|
|
ClaimsPrincipal user,
|
|
DashboardStatsQueryDTO query,
|
|
int page,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (page < 1)
|
|
throw new ArgumentOutOfRangeException(nameof(page));
|
|
|
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
|
var dispatcherId = user.IsInRole("Dispatcher")
|
|
? user.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
: null;
|
|
if (user.IsInRole("Dispatcher") && string.IsNullOrWhiteSpace(dispatcherId))
|
|
throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required.");
|
|
|
|
var rows = await _dataService.GetDispatcherWorkloadAsync(
|
|
accountId,
|
|
dispatcherId,
|
|
query.DateFrom,
|
|
query.DateTo,
|
|
cancellationToken);
|
|
var orderedRows = rows
|
|
.OrderByDescending(row => row.OpenCount)
|
|
.ThenBy(row => row.DispatcherName, StringComparer.OrdinalIgnoreCase)
|
|
.ThenBy(row => row.DispatcherId, StringComparer.Ordinal)
|
|
.ToList();
|
|
const int pageSize = 10;
|
|
|
|
return new DashboardWorkloadResponseDTO
|
|
{
|
|
Items = orderedRows.Skip((page - 1) * pageSize).Take(pageSize)
|
|
.Select(row => new DashboardWorkloadRowDTO
|
|
{
|
|
DispatcherId = row.DispatcherId,
|
|
DispatcherName = row.DispatcherName,
|
|
Color = row.Color,
|
|
TotalCount = row.TotalCount,
|
|
OpenCount = row.OpenCount
|
|
}).ToList(),
|
|
Page = page,
|
|
PageSize = pageSize,
|
|
TotalDispatchers = orderedRows.Count
|
|
};
|
|
}
|
|
|
|
public async Task<DashboardPerformanceResponseDTO> GetPerformanceAsync(
|
|
ClaimsPrincipal user,
|
|
DashboardStatsQueryDTO query,
|
|
int page,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (page < 1)
|
|
throw new ArgumentOutOfRangeException(nameof(page));
|
|
|
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
|
var dispatcherId = user.IsInRole("Dispatcher")
|
|
? user.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
: null;
|
|
if (user.IsInRole("Dispatcher") && string.IsNullOrWhiteSpace(dispatcherId))
|
|
throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required.");
|
|
|
|
var directory = await _dataService.GetDispatcherWorkloadAsync(
|
|
accountId, dispatcherId, query.DateFrom, query.DateTo, cancellationToken);
|
|
var workOrders = await _dataService.GetDashboardWorkOrdersAsync(
|
|
accountId, dispatcherId, query.DateFrom, query.DateTo, cancellationToken);
|
|
var today = DashboardBusinessTime.Today();
|
|
var rows = directory.Select(dispatcher =>
|
|
{
|
|
var metrics = DashboardMetrics.Calculate(
|
|
workOrders.Where(workOrder => workOrder.AssignTo == dispatcher.DispatcherId).ToList(),
|
|
today);
|
|
return new DashboardPerformanceRowDTO
|
|
{
|
|
DispatcherId = dispatcher.DispatcherId,
|
|
DispatcherName = dispatcher.DispatcherName,
|
|
Color = dispatcher.Color,
|
|
CompletionRate = metrics.CompletionRate,
|
|
AverageResolutionDays = metrics.AverageResolutionDays
|
|
};
|
|
})
|
|
.OrderByDescending(row => row.CompletionRate)
|
|
.ThenBy(row => row.DispatcherName, StringComparer.OrdinalIgnoreCase)
|
|
.ThenBy(row => row.DispatcherId, StringComparer.Ordinal)
|
|
.ToList();
|
|
const int pageSize = 10;
|
|
|
|
return new DashboardPerformanceResponseDTO
|
|
{
|
|
Items = rows.Skip((page - 1) * pageSize).Take(pageSize).ToList(),
|
|
Page = page,
|
|
PageSize = pageSize,
|
|
TotalDispatchers = rows.Count
|
|
};
|
|
}
|
|
|
|
public async Task<DashboardRegionResponseDTO> GetRegionsAsync(
|
|
ClaimsPrincipal user,
|
|
DashboardStatsQueryDTO query,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
|
var dispatcherId = user.IsInRole("Dispatcher")
|
|
? user.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
: null;
|
|
if (user.IsInRole("Dispatcher") && string.IsNullOrWhiteSpace(dispatcherId))
|
|
throw new WorkOrderBoardValidationException("Forbidden", "Dispatcher identity is required.");
|
|
|
|
var workOrders = await _dataService.GetDashboardWorkOrdersAsync(
|
|
accountId, dispatcherId, query.DateFrom, query.DateTo, cancellationToken);
|
|
var counts = DashboardRegions.Count(workOrders);
|
|
return new DashboardRegionResponseDTO
|
|
{
|
|
Items = DashboardRegions.Names
|
|
.Select(region => new DashboardRegionRowDTO
|
|
{
|
|
Region = region,
|
|
WorkOrderCount = counts[region]
|
|
})
|
|
.ToList()
|
|
};
|
|
}
|
|
}
|
|
}
|