using Data.SeaHavenIndustries.Enums; using SeaHaven.Services.Exceptions; namespace SeaHaven.Services.Helpers { /// /// SH-169 manual transition guard for the board lifecycleStatus PATCH. /// Incomplete and Scheduled are derived by the server; a direct request may only /// restate what derivation already produces, never forge a new automatic state. /// Past Due is a read-model overlay (), /// not a value, so it cannot be requested at all. /// public static class WorkOrderBoardPatchLifecycleRules { public const string AutomaticStatusCode = "AutomaticLifecycleStatus"; public static bool IsAutomaticStatus(LifecycleStatus status) => status == LifecycleStatus.Incomplete || status == LifecycleStatus.Scheduled; public static void EnsureRequestAllowed( LifecycleStatus? current, LifecycleStatus requested, DateTime? scheduledDate, bool? scheduleWeekOnly) { if (!IsAutomaticStatus(requested)) return; if (requested == LifecycleStatus.Scheduled && !WorkOrderBoardMutationRules.HasConcreteSchedule(scheduledDate, scheduleWeekOnly)) { throw new WorkOrderBoardValidationException( "ScheduledRequiresDate", "Scheduled requires a concrete scheduledDate when scheduleWeekOnly is not true."); } // why: the board client restates the derived status after a schedule patch; that is a no-op, not a forge. if (current == requested) return; if (requested == LifecycleStatus.Scheduled && WorkOrderBoardMutationRules.ShouldPromoteToScheduled(current, scheduledDate, scheduleWeekOnly)) { return; } throw new WorkOrderBoardValidationException( AutomaticStatusCode, $"{LifecycleStatusMapper.ToFeLabel(requested)} is set automatically and cannot be selected manually."); } } }