feat(work-orders): derive Scheduled from date without assignee

This commit is contained in:
Arthur Bassi 2026-09-08 16:19:50 -03:00
parent 1bdbc12292
commit 335390f746
2 changed files with 83 additions and 9 deletions

View file

@ -46,7 +46,13 @@ namespace SeaHaven.Services.Helpers
=> field.Equals(WorkOrderBoardFieldNames.LifecycleStatus, StringComparison.OrdinalIgnoreCase) && isPastDue;
/// <summary>
/// SHOC rule: Incomplete + specific scheduled date + assignee → Scheduled.
/// 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(
@ -54,10 +60,27 @@ namespace SeaHaven.Services.Helpers
DateTime? scheduledDate,
string? assignTo,
bool? scheduleWeekOnly = null)
=> status == LifecycleStatus.Incomplete
&& scheduleWeekOnly != true
&& scheduledDate.HasValue
&& !string.IsNullOrWhiteSpace(assignTo);
{
_ = 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

View file

@ -27,12 +27,21 @@ public class WorkOrderBoardMutationRulesTests
}
[Fact]
public void ShouldAutoSchedule_WhenIncompleteWithDateAndAssignee()
public void ShouldAutoSchedule_WhenIncompleteWithDate_DoesNotRequireAssignee()
{
Assert.True(WorkOrderBoardMutationRules.ShouldAutoSchedule(
LifecycleStatus.Incomplete,
new DateTime(2026, 6, 25),
"dispatcher-1"));
assignTo: null));
}
[Fact]
public void ShouldAutoSchedule_WhenPendingWithConcreteDate()
{
Assert.True(WorkOrderBoardMutationRules.ShouldAutoSchedule(
LifecycleStatus.Pending,
new DateTime(2026, 6, 25),
assignTo: null));
}
[Fact]
@ -41,7 +50,7 @@ public class WorkOrderBoardMutationRulesTests
Assert.False(WorkOrderBoardMutationRules.ShouldAutoSchedule(
LifecycleStatus.Scheduled,
new DateTime(2026, 6, 25),
"dispatcher-1"));
assignTo: null));
}
[Fact]
@ -50,10 +59,52 @@ public class WorkOrderBoardMutationRulesTests
Assert.False(WorkOrderBoardMutationRules.ShouldAutoSchedule(
LifecycleStatus.Incomplete,
new DateTime(2026, 6, 25),
"dispatcher-1",
assignTo: null,
scheduleWeekOnly: true));
}
[Fact]
public void ShouldAutoSchedule_FalseWhenInProgress()
{
Assert.False(WorkOrderBoardMutationRules.ShouldAutoSchedule(
LifecycleStatus.InProgress,
new DateTime(2026, 6, 25),
assignTo: null));
}
[Fact]
public void ShouldDemoteFromScheduled_WhenDateCleared()
{
Assert.True(WorkOrderBoardMutationRules.ShouldDemoteFromScheduled(
LifecycleStatus.Scheduled,
scheduledDate: null));
}
[Fact]
public void ShouldDemoteFromScheduled_WhenWeekOnly()
{
Assert.True(WorkOrderBoardMutationRules.ShouldDemoteFromScheduled(
LifecycleStatus.Scheduled,
new DateTime(2026, 6, 25),
scheduleWeekOnly: true));
}
[Fact]
public void ShouldDemoteFromScheduled_FalseWhenConcreteDateRemains()
{
Assert.False(WorkOrderBoardMutationRules.ShouldDemoteFromScheduled(
LifecycleStatus.Scheduled,
new DateTime(2026, 6, 25)));
}
[Fact]
public void ShouldDemoteFromScheduled_FalseWhenInProgress()
{
Assert.False(WorkOrderBoardMutationRules.ShouldDemoteFromScheduled(
LifecycleStatus.InProgress,
scheduledDate: null));
}
[Fact]
public void CanPatchBoardField_AllowsOnlyFlagColorWhenCompleted()
{