mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
feat(work-orders): apply schedule lifecycle promote and demote
This commit is contained in:
parent
335390f746
commit
e12b3ea54b
2 changed files with 87 additions and 22 deletions
|
|
@ -50,25 +50,50 @@ namespace SeaHaven.Services.Helpers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SHOC rule: specific scheduled date + assignee + Incomplete → Scheduled.
|
/// Promote Incomplete/Pending to Scheduled, or demote Scheduled to Pending, from Schedule On.
|
||||||
/// Week-only targets do not auto-schedule.
|
/// Assignee is not required. Week-only is not a concrete date.
|
||||||
|
/// </summary>
|
||||||
|
public static List<WorkOrderBoardFieldMutations.BoardFieldChange> ApplyLifecycleFromSchedule(WorkOrder workOrder)
|
||||||
|
{
|
||||||
|
var changes = new List<WorkOrderBoardFieldMutations.BoardFieldChange>();
|
||||||
|
LifecycleStatus? next = null;
|
||||||
|
if (WorkOrderBoardMutationRules.ShouldPromoteToScheduled(
|
||||||
|
workOrder.LifecycleStatus,
|
||||||
|
workOrder.ScheduledDate,
|
||||||
|
workOrder.ScheduleWeekOnly))
|
||||||
|
{
|
||||||
|
next = LifecycleStatus.Scheduled;
|
||||||
|
}
|
||||||
|
else if (WorkOrderBoardMutationRules.ShouldDemoteFromScheduled(
|
||||||
|
workOrder.LifecycleStatus,
|
||||||
|
workOrder.ScheduledDate,
|
||||||
|
workOrder.ScheduleWeekOnly))
|
||||||
|
{
|
||||||
|
next = LifecycleStatus.Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == null || workOrder.LifecycleStatus == next)
|
||||||
|
return changes;
|
||||||
|
|
||||||
|
var old = workOrder.LifecycleStatus?.ToString();
|
||||||
|
workOrder.LifecycleStatus = next;
|
||||||
|
workOrder.Status = GetLifecycleStatusLabel(next);
|
||||||
|
changes.Add(WorkOrderBoardFieldMutations.BoardFieldChange.StatusChanged(
|
||||||
|
"LifecycleStatus",
|
||||||
|
old,
|
||||||
|
next.Value.ToString()));
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies schedule-driven lifecycle (promote or demote). True when the row becomes Scheduled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool ApplyAutoScheduleIfEligible(WorkOrder workOrder)
|
public static bool ApplyAutoScheduleIfEligible(WorkOrder workOrder)
|
||||||
{
|
{
|
||||||
if (workOrder.LifecycleStatus != LifecycleStatus.Incomplete)
|
var before = workOrder.LifecycleStatus;
|
||||||
return false;
|
ApplyLifecycleFromSchedule(workOrder);
|
||||||
|
return before != LifecycleStatus.Scheduled
|
||||||
if (workOrder.ScheduleWeekOnly == true)
|
&& workOrder.LifecycleStatus == LifecycleStatus.Scheduled;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (workOrder.ScheduledDate == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(workOrder.AssignTo))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
workOrder.LifecycleStatus = LifecycleStatus.Scheduled;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -83,19 +83,48 @@ public class WorkOrderDerivedFieldsTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyAutoSchedule_WhenDateAndAssignee_PromotesToScheduled()
|
public void ApplyAutoSchedule_WhenDateWithoutAssignee_PromotesToScheduled()
|
||||||
{
|
{
|
||||||
var wo = new WorkOrder
|
var wo = new WorkOrder
|
||||||
{
|
{
|
||||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||||
ScheduledDate = new DateTime(2026, 6, 25),
|
ScheduledDate = new DateTime(2026, 6, 25)
|
||||||
AssignTo = "dispatcher-1"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.True(WorkOrderDerivedFields.ApplyAutoScheduleIfEligible(wo));
|
Assert.True(WorkOrderDerivedFields.ApplyAutoScheduleIfEligible(wo));
|
||||||
Assert.Equal(LifecycleStatus.Scheduled, wo.LifecycleStatus);
|
Assert.Equal(LifecycleStatus.Scheduled, wo.LifecycleStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyLifecycleFromSchedule_PendingWithDate_PromotesToScheduled()
|
||||||
|
{
|
||||||
|
var wo = new WorkOrder
|
||||||
|
{
|
||||||
|
LifecycleStatus = LifecycleStatus.Pending,
|
||||||
|
ScheduledDate = new DateTime(2026, 6, 25)
|
||||||
|
};
|
||||||
|
|
||||||
|
var changes = WorkOrderDerivedFields.ApplyLifecycleFromSchedule(wo);
|
||||||
|
Assert.Equal(LifecycleStatus.Scheduled, wo.LifecycleStatus);
|
||||||
|
Assert.Single(changes);
|
||||||
|
Assert.Equal(AuditActionType.StatusChanged, changes[0].Action);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyLifecycleFromSchedule_ScheduledWithoutDate_DemotesToPending()
|
||||||
|
{
|
||||||
|
var wo = new WorkOrder
|
||||||
|
{
|
||||||
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||||
|
ScheduledDate = null
|
||||||
|
};
|
||||||
|
|
||||||
|
var changes = WorkOrderDerivedFields.ApplyLifecycleFromSchedule(wo);
|
||||||
|
Assert.Equal(LifecycleStatus.Pending, wo.LifecycleStatus);
|
||||||
|
Assert.Single(changes);
|
||||||
|
Assert.Equal(LifecycleStatus.Pending.ToString(), changes[0].NewValue);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyAutoSchedule_WeekOnly_DoesNotPromote()
|
public void ApplyAutoSchedule_WeekOnly_DoesNotPromote()
|
||||||
{
|
{
|
||||||
|
|
@ -103,7 +132,6 @@ public class WorkOrderDerivedFieldsTests
|
||||||
{
|
{
|
||||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||||
ScheduledDate = new DateTime(2026, 6, 25),
|
ScheduledDate = new DateTime(2026, 6, 25),
|
||||||
AssignTo = "dispatcher-1",
|
|
||||||
ScheduleWeekOnly = true,
|
ScheduleWeekOnly = true,
|
||||||
TargetWeek = new DateOnly(2026, 6, 22)
|
TargetWeek = new DateOnly(2026, 6, 22)
|
||||||
};
|
};
|
||||||
|
|
@ -112,13 +140,25 @@ public class WorkOrderDerivedFieldsTests
|
||||||
Assert.Equal(LifecycleStatus.Incomplete, wo.LifecycleStatus);
|
Assert.Equal(LifecycleStatus.Incomplete, wo.LifecycleStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyLifecycleFromSchedule_InProgress_UnchangedWhenDateCleared()
|
||||||
|
{
|
||||||
|
var wo = new WorkOrder
|
||||||
|
{
|
||||||
|
LifecycleStatus = LifecycleStatus.InProgress,
|
||||||
|
ScheduledDate = null
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.Empty(WorkOrderDerivedFields.ApplyLifecycleFromSchedule(wo));
|
||||||
|
Assert.Equal(LifecycleStatus.InProgress, wo.LifecycleStatus);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SetInitialLifecycleStatus_NewWo_StartsIncompleteThenAutoSchedules()
|
public void SetInitialLifecycleStatus_NewWo_StartsIncompleteThenAutoSchedules()
|
||||||
{
|
{
|
||||||
var wo = new WorkOrder
|
var wo = new WorkOrder
|
||||||
{
|
{
|
||||||
ScheduledDate = new DateTime(2026, 6, 25),
|
ScheduledDate = new DateTime(2026, 6, 25)
|
||||||
AssignTo = "dispatcher-1"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WorkOrderDerivedFields.SetInitialLifecycleStatus(wo);
|
WorkOrderDerivedFields.SetInitialLifecycleStatus(wo);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue