mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-06 11:12:08 +00:00
merge: sync Phase 1 board review fixes into Phase 2
Resolve conflicts in WorkOrderController and WorkOrderBoardService so Phase 2 merges cleanly into the Phase 1 base.
This commit is contained in:
commit
88f9245fbf
12 changed files with 42 additions and 67 deletions
|
|
@ -18,6 +18,7 @@ using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
using SeaHaven.Services.Interfaces;
|
using SeaHaven.Services.Interfaces;
|
||||||
using SeaHaven.Services.DTOs;
|
using SeaHaven.Services.DTOs;
|
||||||
using SeaHaven.Services.Exceptions;
|
using SeaHaven.Services.Exceptions;
|
||||||
|
using SeaHaven.Services.Helpers;
|
||||||
using SeaHaven.DataServices.Interfaces;
|
using SeaHaven.DataServices.Interfaces;
|
||||||
|
|
||||||
namespace Api.SeaHavenIndustries.Controllers
|
namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
@ -93,6 +94,11 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
[FromQuery] List<WorkOrderType>? types = null,
|
[FromQuery] List<WorkOrderType>? types = null,
|
||||||
[FromQuery] string? search = null)
|
[FromQuery] string? search = null)
|
||||||
{
|
{
|
||||||
|
var resolvedWeekEnd = weekEnd ?? weekStart.AddDays(4);
|
||||||
|
var weekValidationError = WorkOrderOperationalWeek.ValidateWeekWindow(weekStart, resolvedWeekEnd);
|
||||||
|
if (weekValidationError != null)
|
||||||
|
return BadRequest(weekValidationError);
|
||||||
|
|
||||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
var query = new WorkOrderBoardQueryDto
|
var query = new WorkOrderBoardQueryDto
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace SeaHaven.DataServices.Board
|
|
||||||
{
|
|
||||||
public static class WorkOrderBoardConstants
|
|
||||||
{
|
|
||||||
public const int ClientSideThreshold = 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
namespace SeaHaven.DataServices.DTOs
|
|
||||||
{
|
|
||||||
public record WorkOrderBoardQuery(
|
|
||||||
DateOnly ScheduledFrom,
|
|
||||||
DateOnly ScheduledTo,
|
|
||||||
string? Search,
|
|
||||||
IReadOnlyList<string>? AssigneeIds,
|
|
||||||
IReadOnlyList<string>? DbStatuses,
|
|
||||||
int? LocationId);
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
namespace SeaHaven.DataServices.DTOs
|
|
||||||
{
|
|
||||||
public record WorkOrderBoardRowData(
|
|
||||||
int Id,
|
|
||||||
string? WoNumber,
|
|
||||||
string? SiteCode,
|
|
||||||
string? LocationLabel,
|
|
||||||
DateTime? ScheduledDate,
|
|
||||||
DateTime? ScheduledStart,
|
|
||||||
DateTime? DueDate,
|
|
||||||
string? WorkOrderType,
|
|
||||||
string? ServiceType,
|
|
||||||
string? AssigneeId,
|
|
||||||
string? AssigneeName,
|
|
||||||
string? VendorCompany,
|
|
||||||
string? VendorTechnician,
|
|
||||||
string? Status,
|
|
||||||
string? PocName,
|
|
||||||
string? PocPhone);
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
namespace SeaHaven.DataServices.Exceptions
|
|
||||||
{
|
|
||||||
public class BoardQueryException : Exception
|
|
||||||
{
|
|
||||||
public BoardQueryException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace SeaHaven.DataServices.Helpers
|
||||||
Name = c.POC != null
|
Name = c.POC != null
|
||||||
? ((c.POC.FirstName ?? "") + " " + (c.POC.LastName ?? "")).Trim()
|
? ((c.POC.FirstName ?? "") + " " + (c.POC.LastName ?? "")).Trim()
|
||||||
: null,
|
: null,
|
||||||
c.POC!.PhoneNumber,
|
PhoneNumber = c.POC != null ? c.POC.PhoneNumber : null,
|
||||||
c.Notes
|
c.Notes
|
||||||
})
|
})
|
||||||
.FirstOrDefault(),
|
.FirstOrDefault(),
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ namespace SeaHaven.DataServices.Helpers
|
||||||
return query.Where(w => w.WorkOrderType != null && types.Contains(w.WorkOrderType.Value));
|
return query.Where(w => w.WorkOrderType != null && types.Contains(w.WorkOrderType.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Phase 2 filter helpers (not wired in Phase 1 board API)
|
||||||
|
|
||||||
public static IQueryable<WorkOrder> ApplySiteFilter(
|
public static IQueryable<WorkOrder> ApplySiteFilter(
|
||||||
IQueryable<WorkOrder> query,
|
IQueryable<WorkOrder> query,
|
||||||
IReadOnlyList<string>? sites)
|
IReadOnlyList<string>? sites)
|
||||||
|
|
@ -135,6 +137,8 @@ namespace SeaHaven.DataServices.Helpers
|
||||||
&& w.TargetWeek <= dateTo));
|
&& w.TargetWeek <= dateTo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public static IQueryable<WorkOrder> ApplySearchFilter(IQueryable<WorkOrder> query, string? search)
|
public static IQueryable<WorkOrder> ApplySearchFilter(IQueryable<WorkOrder> query, string? search)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(search))
|
if (string.IsNullOrWhiteSpace(search))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
namespace SeaHaven.DataServices.Interfaces
|
|
||||||
{
|
|
||||||
public record PrimaryDispatchProjection(
|
|
||||||
int WorkOrderId,
|
|
||||||
int? DispatchId,
|
|
||||||
string? VendorName,
|
|
||||||
DateTime? ApptDate,
|
|
||||||
string? DispatchStatus);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
namespace SeaHaven.Services.Board
|
namespace SeaHaven.Services.Board
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shared board constants for Phase 2+ features. Not referenced in Phase 1.
|
||||||
|
/// </summary>
|
||||||
public static class WorkOrderBoardConstants
|
public static class WorkOrderBoardConstants
|
||||||
{
|
{
|
||||||
public const int MaxWindowDays = 90;
|
public const int MaxWindowDays = 90;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@ namespace SeaHaven.Services.Helpers
|
||||||
return DateOnly.FromDateTime(workOrder.ScheduledDate.Value.Date) < today;
|
return DateOnly.FromDateTime(workOrder.ScheduledDate.Value.Date) < today;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Board read-model past-due check. Phase 1 compares UTC calendar dates;
|
||||||
|
/// business/location timezone support is planned for a later phase.
|
||||||
|
/// </summary>
|
||||||
public static bool IsPastDue(
|
public static bool IsPastDue(
|
||||||
DateTime? scheduledDate,
|
DateTime? scheduledDate,
|
||||||
LifecycleStatus? lifecycleStatus,
|
LifecycleStatus? lifecycleStatus,
|
||||||
|
|
@ -66,6 +70,10 @@ namespace SeaHaven.Services.Helpers
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps scheduled date to Mon–Fri board column. Phase 1 uses the stored
|
||||||
|
/// date's day-of-week (UTC); timezone-aware grouping is planned for a later phase.
|
||||||
|
/// </summary>
|
||||||
public static string? GetDayGroup(DateTime? scheduledDate)
|
public static string? GetDayGroup(DateTime? scheduledDate)
|
||||||
{
|
{
|
||||||
if (!scheduledDate.HasValue)
|
if (!scheduledDate.HasValue)
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,20 @@ namespace SeaHaven.Services.Helpers
|
||||||
|
|
||||||
public static string BuildWeekCorrelationId(DateOnly sourceWeekStart)
|
public static string BuildWeekCorrelationId(DateOnly sourceWeekStart)
|
||||||
=> $"week:{sourceWeekStart:yyyy-MM-dd}";
|
=> $"week:{sourceWeekStart:yyyy-MM-dd}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a validation error message when the week window is invalid; otherwise null.
|
||||||
|
/// </summary>
|
||||||
|
public static string? ValidateWeekWindow(DateOnly weekStart, DateOnly weekEnd)
|
||||||
|
{
|
||||||
|
if (weekEnd < weekStart)
|
||||||
|
return "weekEnd must be on or after weekStart.";
|
||||||
|
|
||||||
|
var spanDays = weekEnd.DayNumber - weekStart.DayNumber;
|
||||||
|
if (spanDays > 6)
|
||||||
|
return "Week window cannot exceed 7 days.";
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,9 @@ namespace SeaHaven.Services.Implementation
|
||||||
var weekStart = query.WeekStart;
|
var weekStart = query.WeekStart;
|
||||||
var weekEnd = query.WeekEnd ?? weekStart.AddDays(4);
|
var weekEnd = query.WeekEnd ?? weekStart.AddDays(4);
|
||||||
|
|
||||||
ValidateWeekWindow(weekStart, weekEnd);
|
var validationError = WorkOrderOperationalWeek.ValidateWeekWindow(weekStart, weekEnd);
|
||||||
|
if (validationError != null)
|
||||||
|
throw new ArgumentException(validationError);
|
||||||
|
|
||||||
var dataQuery = new WorkOrderBoardQuery(
|
var dataQuery = new WorkOrderBoardQuery(
|
||||||
weekStart,
|
weekStart,
|
||||||
|
|
@ -68,18 +70,10 @@ namespace SeaHaven.Services.Implementation
|
||||||
return raw == null ? null : MapRawRow(raw, DateTime.UtcNow);
|
return raw == null ? null : MapRawRow(raw, DateTime.UtcNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateWeekWindow(DateOnly weekStart, DateOnly weekEnd)
|
|
||||||
{
|
|
||||||
if (weekEnd < weekStart)
|
|
||||||
throw new ArgumentException("weekEnd must be on or after weekStart.");
|
|
||||||
|
|
||||||
var spanDays = weekEnd.DayNumber - weekStart.DayNumber;
|
|
||||||
if (spanDays > 6)
|
|
||||||
throw new ArgumentException("Week window cannot exceed 7 days.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, 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 apptStart = row.ScheduledStart ?? row.DispatchApptDate;
|
||||||
var apptEnd = row.ScheduledEnd;
|
var apptEnd = row.ScheduledEnd;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue