shoc-backend/SeaHaven.Services/Implementation/WorkOrderBoardService.cs

163 lines
6.8 KiB
C#

using System.Security.Claims;
using Data.SeaHavenIndustries.Enums;
using SeaHaven.DataServices.Helpers;
using SeaHaven.DataServices.Interfaces;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Helpers;
using SeaHaven.Services.Interfaces;
namespace SeaHaven.Services.Implementation
{
public class WorkOrderBoardService : IWorkOrderBoardService
{
private readonly IWorkOrderBoardDataService _boardDataService;
private readonly IWorkOrderAccountResolver _accountResolver;
public WorkOrderBoardService(
IWorkOrderBoardDataService boardDataService,
IWorkOrderAccountResolver accountResolver)
{
_boardDataService = boardDataService;
_accountResolver = accountResolver;
}
public async Task<WorkOrderBoardResponseDto> GetBoardAsync(
WorkOrderBoardQueryDto query,
ClaimsPrincipal user,
string? currentUserId,
CancellationToken cancellationToken = default)
{
var accountId = _accountResolver.ResolveAccountFilter(user);
var weekStart = query.WeekStart;
var weekEnd = query.WeekEnd ?? weekStart.AddDays(4);
var validationError = WorkOrderOperationalWeek.ValidateWeekWindow(weekStart, weekEnd);
if (validationError != null)
throw new ArgumentException(validationError);
var dataQuery = new WorkOrderBoardQuery(
weekStart,
weekEnd,
query.Dispatchers,
query.MyWorkOrders,
query.Types,
query.Overdue,
query.Search,
currentUserId,
accountId);
var result = await _boardDataService.GetBoardRowsAsync(dataQuery, cancellationToken);
var utcNow = DateTime.UtcNow;
return new WorkOrderBoardResponseDto
{
WeekStart = weekStart,
WeekEnd = weekEnd,
Counts = new WorkOrderBoardCountsDto
{
Total = result.ScheduledTotalBeforeSearch,
Returned = result.ScheduledRows.Count
},
Scheduled = result.ScheduledRows.Select(r => MapRawRow(r, utcNow)).ToList(),
Unscheduled = result.UnscheduledRows.Select(r => MapRawRow(r, utcNow)).ToList()
};
}
public async Task<IReadOnlyList<DispatcherLookupDto>> GetDispatcherLookupsAsync()
{
var rows = await _boardDataService.GetDispatcherLookupsAsync();
return rows.Select(r => new DispatcherLookupDto
{
Id = r.Id,
Name = FormatName(r.FirstName, r.LastName),
Initials = r.Initials,
Color = r.Color
}).ToList();
}
public async Task<WorkOrderBoardRowDto?> GetBoardRowAsync(int workOrderId, ClaimsPrincipal user)
{
var accountId = _accountResolver.ResolveAccountFilter(user);
var raw = await _boardDataService.GetBoardRowByIdAsync(workOrderId, accountId);
return raw == null ? null : MapRawRow(raw, DateTime.UtcNow);
}
public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, DateTime utcNow)
{
// Appt column: date prefers dispatch appointment (vendor slot), then WO ScheduledDate.
// Time prefers WO ScheduledStart/End (dispatcher window), then dispatch datetime.
var apptStart = row.ScheduledStart ?? row.DispatchApptDate;
var apptEnd = row.ScheduledEnd;
var (vendorId, vendorName) = WorkOrderBoardDispatchAssignment.LiveVendor(
row.VendorId,
row.VendorName,
row.PrimaryDispatchStatus);
return new WorkOrderBoardRowDto
{
Id = row.Id,
WoNumber = row.InternalWONumber,
RescheduleCount = row.RescheduleCount,
CarriedOver = row.CarriedOver,
IsAddOn = row.IsAddOn,
WorkOrderType = row.WorkOrderType,
IsPastDue = WorkOrderDerivedFields.IsPastDue(row.ScheduledDate, row.LifecycleStatus, utcNow),
SiteCode = row.SiteCode,
LocationName = row.LocationName,
PocName = row.PocName,
PocPhone = row.PocPhone,
PocNotes = row.PocNotes,
LifecycleStatus = row.LifecycleStatus,
LifecycleStatusLabel = WorkOrderDerivedFields.GetLifecycleStatusLabel(row.LifecycleStatus),
LegacyStatus = row.LegacyStatus,
DispatcherId = row.AssignTo,
DispatcherName = FormatName(row.DispatcherFirstName, row.DispatcherLastName),
Initials = row.Initials,
Color = row.Color,
DueDate = row.DueDate,
ScheduledDate = row.ScheduledDate,
TargetWeek = row.TargetWeek,
ScheduleWeekOnly = row.ScheduleWeekOnly,
DayGroup = WorkOrderDerivedFields.GetDayGroup(row.ScheduledDate),
VendorId = vendorId,
VendorName = vendorName,
PrimaryDispatchStatus = row.PrimaryDispatchStatus,
TechName = row.TechName,
TechPhone = row.TechPhone,
ApptDate = row.DispatchApptDate ?? row.ScheduledDate,
ApptTime = WorkOrderDerivedFields.FormatApptTime(apptStart, apptEnd),
Pm = row.Trade ?? row.Problem,
ServiceNotes = row.ServiceNotes,
ExtraServices = ParseExtraServices(row.ExtraServices),
AdditionalContacts = WorkOrderAdditionalContactsMapper.ParseJson(row.AdditionalContacts),
DocStatus = row.DocStatus,
CompletedDate = row.CompletedDate,
FlagColor = row.FlagColor,
PrimaryDispatchId = row.PrimaryDispatchId,
RowVersion = row.RowVersion,
DispatchRowVersion = row.DispatchRowVersion,
PendingUpliftCount = row.PendingUpliftCount,
UpliftSummary = WorkOrderUpliftContractMapper.MapSummary(row)
};
}
private static string FormatName(string? firstName, string? lastName)
=> $"{firstName ?? ""} {lastName ?? ""}".Trim();
private static List<string>? ParseExtraServices(string? json)
{
if (string.IsNullOrWhiteSpace(json))
return null;
try
{
var list = System.Text.Json.JsonSerializer.Deserialize<List<string>>(json);
return list is { Count: > 0 } ? list : null;
}
catch (System.Text.Json.JsonException)
{
return null;
}
}
}
}