mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 08:23:12 +00:00
101 lines
4.1 KiB
C#
101 lines
4.1 KiB
C#
using Data.SeaHavenIndustries.Enums;
|
|
|
|
namespace SeaHaven.Services.Helpers
|
|
{
|
|
public static class WorkOrderBoardMutationRules
|
|
{
|
|
private static readonly HashSet<LifecycleStatus?> ReadOnlyStatuses =
|
|
LifecycleStatusSets.Terminal.Cast<LifecycleStatus?>().ToHashSet();
|
|
|
|
public static bool IsReadOnly(LifecycleStatus? status) => ReadOnlyStatuses.Contains(status);
|
|
|
|
public static bool IsFullyLocked(LifecycleStatus? status)
|
|
=> status == LifecycleStatus.Canceled;
|
|
|
|
public static bool IsCoreLocked(LifecycleStatus? status)
|
|
=> status == LifecycleStatus.Completed;
|
|
|
|
public static bool CanPatchBoardField(LifecycleStatus? status, string field)
|
|
{
|
|
if (IsFullyLocked(status))
|
|
return false;
|
|
if (!IsCoreLocked(status))
|
|
return true;
|
|
return field.Equals(WorkOrderBoardFieldNames.FlagColor, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static bool CanMutateComments(LifecycleStatus? status)
|
|
=> !IsFullyLocked(status);
|
|
|
|
public static bool CanMutateExtraMedia(LifecycleStatus? status, WorkOrderMediaCategory? category)
|
|
{
|
|
if (IsFullyLocked(status))
|
|
return false;
|
|
if (!IsCoreLocked(status))
|
|
return true;
|
|
return IsExtraDocsFamily(category);
|
|
}
|
|
|
|
public static bool IsExtraDocsFamily(WorkOrderMediaCategory? category)
|
|
{
|
|
var resolved = category ?? WorkOrderMediaCategory.Extra;
|
|
return resolved == WorkOrderMediaCategory.Extra || resolved == WorkOrderMediaCategory.Aveta;
|
|
}
|
|
|
|
public static bool ShouldBlockStatusChangeWhenPastDue(string field, bool isPastDue)
|
|
=> field.Equals(WorkOrderBoardFieldNames.LifecycleStatus, StringComparison.OrdinalIgnoreCase) && isPastDue;
|
|
|
|
/// <summary>
|
|
/// Concrete Schedule On: a calendar day is set and the row is not week-only.
|
|
/// </summary>
|
|
public static bool HasConcreteSchedule(DateTime? scheduledDate, bool? scheduleWeekOnly)
|
|
=> scheduledDate.HasValue && scheduleWeekOnly != true;
|
|
|
|
/// <summary>
|
|
/// Incomplete or Pending + concrete scheduled date → Scheduled. Assignee is not required.
|
|
/// Week-only targets do not auto-schedule (same as <see cref="WorkOrderDerivedFields.ApplyAutoScheduleIfEligible"/>).
|
|
/// </summary>
|
|
public static bool ShouldAutoSchedule(
|
|
LifecycleStatus? status,
|
|
DateTime? scheduledDate,
|
|
string? assignTo,
|
|
bool? scheduleWeekOnly = null)
|
|
{
|
|
_ = assignTo;
|
|
return ShouldPromoteToScheduled(status, scheduledDate, scheduleWeekOnly);
|
|
}
|
|
|
|
public static bool ShouldPromoteToScheduled(
|
|
LifecycleStatus? status,
|
|
DateTime? scheduledDate,
|
|
bool? scheduleWeekOnly = null)
|
|
=> (status == LifecycleStatus.Incomplete || status == LifecycleStatus.Pending)
|
|
&& HasConcreteSchedule(scheduledDate, scheduleWeekOnly);
|
|
|
|
/// <summary>
|
|
/// Scheduled without a concrete date (cleared or week-only) → Pending. Later statuses are ignored.
|
|
/// </summary>
|
|
public static bool ShouldDemoteFromScheduled(
|
|
LifecycleStatus? status,
|
|
DateTime? scheduledDate,
|
|
bool? scheduleWeekOnly = null)
|
|
=> status == LifecycleStatus.Scheduled
|
|
&& !HasConcreteSchedule(scheduledDate, scheduleWeekOnly);
|
|
|
|
public static bool IsReschedule(DateTime? previousDate, DateTime? newDate)
|
|
=> previousDate.HasValue
|
|
&& newDate.HasValue
|
|
&& previousDate.Value.Date != newDate.Value.Date;
|
|
|
|
public static DateOnly? ComputeOriginalWeek(DateTime? scheduledDate)
|
|
=> scheduledDate.HasValue
|
|
? DateOnly.FromDateTime(GetWeekStartMonday(scheduledDate.Value))
|
|
: null;
|
|
|
|
public static DateTime GetWeekStartMonday(DateTime date)
|
|
{
|
|
var diff = (7 + (date.DayOfWeek - DayOfWeek.Monday)) % 7;
|
|
return date.Date.AddDays(-diff);
|
|
}
|
|
}
|
|
}
|