diff --git a/SeaHaven.Services/Helpers/WorkOrderDerivedFields.cs b/SeaHaven.Services/Helpers/WorkOrderDerivedFields.cs new file mode 100644 index 0000000..873126d --- /dev/null +++ b/SeaHaven.Services/Helpers/WorkOrderDerivedFields.cs @@ -0,0 +1,55 @@ +using Data.SeaHavenIndustries; +using Data.SeaHavenIndustries.Enums; + +namespace SeaHaven.Services.Helpers +{ + public static class WorkOrderDerivedFields + { + /// + /// Past due overlay — never a WorkOrderType. Matches SHOC board design. + /// + public static bool IsPastDue(WorkOrder workOrder, DateOnly? asOf = null) + { + var today = asOf ?? DateOnly.FromDateTime(DateTime.UtcNow); + if (workOrder.ScheduledDate == null) + return false; + + if (LifecycleStatusMapper.IsTerminal(workOrder.LifecycleStatus)) + return false; + + return DateOnly.FromDateTime(workOrder.ScheduledDate.Value.Date) < today; + } + + /// + /// Sets initial lifecycle on create. New WOs start Incomplete unless auto-scheduled. + /// + public static void SetInitialLifecycleStatus(WorkOrder workOrder) + { + workOrder.LifecycleStatus ??= LifecycleStatus.Incomplete; + ApplyAutoScheduleIfEligible(workOrder); + } + + /// + /// SHOC rule: specific scheduled date + assignee + Incomplete → Scheduled. + /// Week-only targets do not auto-schedule. + /// + public static bool ApplyAutoScheduleIfEligible(WorkOrder workOrder) + { + if (workOrder.LifecycleStatus != LifecycleStatus.Incomplete) + return false; + + if (workOrder.ScheduleWeekOnly == true) + return false; + + if (workOrder.ScheduledDate == null) + return false; + + if (string.IsNullOrWhiteSpace(workOrder.AssignTo)) + return false; + + workOrder.LifecycleStatus = LifecycleStatus.Scheduled; + return true; + } + } +} + \ No newline at end of file diff --git a/SeaHaven.Services/Helpers/WorkOrderTypeMapper.cs b/SeaHaven.Services/Helpers/WorkOrderTypeMapper.cs new file mode 100644 index 0000000..64c355c --- /dev/null +++ b/SeaHaven.Services/Helpers/WorkOrderTypeMapper.cs @@ -0,0 +1,48 @@ +using Data.SeaHavenIndustries.Enums; + +namespace SeaHaven.Services.Helpers +{ + public static class WorkOrderTypeMapper + { + /// Board FE types. Overdue is not a type — use . + public static bool TryParseFeLabel(string? label, out WorkOrderType type) + { + type = default; + if (string.IsNullOrWhiteSpace(label)) return false; + + return label.Trim().ToLowerInvariant() switch + { + "pm" => Set(WorkOrderType.PM, out type), + "reactive" => Set(WorkOrderType.Reactive, out type), + "emergency" => Set(WorkOrderType.Emergency, out type), + "add-on" or "addon" => Set(WorkOrderType.AddOn, out type), + "po" => Set(WorkOrderType.PO, out type), + "project" => Set(WorkOrderType.Project, out type), + "inspection" => Set(WorkOrderType.Inspection, out type), + "other" => Set(WorkOrderType.Other, out type), + "overdue" => false, + _ => Enum.TryParse(label, true, out type) + }; + } + + public static string ToFeLabel(WorkOrderType type) => type switch + { + WorkOrderType.PM => "PM", + WorkOrderType.Reactive => "Reactive", + WorkOrderType.Emergency => "Emergency", + WorkOrderType.AddOn => "Add-On", + WorkOrderType.PO => "PO", + WorkOrderType.Project => "Project", + WorkOrderType.Inspection => "Inspection", + WorkOrderType.Other => "Other", + _ => type.ToString() + }; + + private static bool Set(WorkOrderType value, out WorkOrderType type) + { + type = value; + return true; + } + } +} + \ No newline at end of file