mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-02 06:13:23 +00:00
Merge pull request #204 from Sea-Haven-Industries/fix/ab/past-due-cancel
fix(workorders): let Cancel through the Past Due status lock
This commit is contained in:
commit
20315f6370
4 changed files with 55 additions and 6 deletions
|
|
@ -42,8 +42,14 @@ namespace SeaHaven.Services.Helpers
|
|||
return resolved == WorkOrderMediaCategory.Extra || resolved == WorkOrderMediaCategory.Aveta;
|
||||
}
|
||||
|
||||
public static bool ShouldBlockStatusChangeWhenPastDue(string field, bool isPastDue)
|
||||
=> field.Equals(WorkOrderBoardFieldNames.LifecycleStatus, StringComparison.OrdinalIgnoreCase) && isPastDue;
|
||||
/// <summary>
|
||||
/// Past Due locks lifecycle progress until Schedule On moves (SH-262). Cancel stays
|
||||
/// available: it is its own action (SH-113), not a status update.
|
||||
/// </summary>
|
||||
public static bool ShouldBlockStatusChangeWhenPastDue(string field, bool isPastDue, LifecycleStatus? requestedStatus)
|
||||
=> field.Equals(WorkOrderBoardFieldNames.LifecycleStatus, StringComparison.OrdinalIgnoreCase)
|
||||
&& isPastDue
|
||||
&& requestedStatus != LifecycleStatus.Canceled;
|
||||
|
||||
/// <summary>
|
||||
/// Concrete Schedule On: a calendar day is set and the row is not week-only.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,10 @@ namespace SeaHaven.Services.Implementation
|
|||
}
|
||||
|
||||
var isPastDue = WorkOrderDerivedFields.IsPastDue(workOrder.ScheduledDate, workOrder.LifecycleStatus);
|
||||
if (WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(canonicalField, isPastDue))
|
||||
if (WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(
|
||||
canonicalField,
|
||||
isPastDue,
|
||||
LifecycleStatusMapper.ParseLifecycleStatus(request.Value)))
|
||||
throw new WorkOrderBoardValidationException("PastDueStatusBlocked", "Status cannot be changed while work order is past due. Update Schedule On first.");
|
||||
|
||||
_mutationData.SetExpectedWorkOrderVersion(workOrder, workOrderVersion);
|
||||
|
|
|
|||
|
|
@ -19,11 +19,21 @@ public class WorkOrderBoardMutationRulesTests
|
|||
public void ShouldBlockStatusChangeWhenPastDue_BlocksOnlyLifecycleStatus()
|
||||
{
|
||||
Assert.True(WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(
|
||||
WorkOrderBoardFieldNames.LifecycleStatus, isPastDue: true));
|
||||
WorkOrderBoardFieldNames.LifecycleStatus, isPastDue: true, LifecycleStatus.InProgress));
|
||||
Assert.False(WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(
|
||||
WorkOrderBoardFieldNames.ScheduledDate, isPastDue: true));
|
||||
WorkOrderBoardFieldNames.ScheduledDate, isPastDue: true, null));
|
||||
Assert.False(WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(
|
||||
WorkOrderBoardFieldNames.DueDate, isPastDue: true));
|
||||
WorkOrderBoardFieldNames.DueDate, isPastDue: true, null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(LifecycleStatus.Canceled, false)]
|
||||
[InlineData(LifecycleStatus.Completed, true)]
|
||||
[InlineData(LifecycleStatus.EnRoute, true)]
|
||||
public void ShouldBlockStatusChangeWhenPastDue_LetsOnlyCancelThrough(LifecycleStatus requested, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, WorkOrderBoardMutationRules.ShouldBlockStatusChangeWhenPastDue(
|
||||
WorkOrderBoardFieldNames.LifecycleStatus, isPastDue: true, requested));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -524,6 +524,36 @@ public class WorkOrderBoardUpdateServiceTests
|
|||
Assert.DoesNotContain("due date", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PatchField_CancelsPastDueWorkOrderWithoutTouchingSchedule()
|
||||
{
|
||||
var (context, service) = CreateSut();
|
||||
var scheduledOn = DateTime.UtcNow.Date.AddDays(-3);
|
||||
var wo = new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
ScheduledDate = scheduledOn,
|
||||
RescheduleCount = 1,
|
||||
RowVersion = new byte[] { 1, 0, 0, 0, 0, 0, 0, 1 }
|
||||
};
|
||||
context.workOrders.Add(wo);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await service.PatchFieldAsync(1, new WorkOrderBoardPatchRequestDto
|
||||
{
|
||||
Field = WorkOrderBoardFieldNames.LifecycleStatus,
|
||||
Value = "Canceled",
|
||||
WorkOrderVersion = ToVersion(wo)
|
||||
}, "actor-1");
|
||||
|
||||
Assert.Equal(LifecycleStatus.Canceled, result.LifecycleStatus);
|
||||
var stored = await context.workOrders.SingleAsync(w => w.Id == 1);
|
||||
Assert.Equal(LifecycleStatus.Canceled, stored.LifecycleStatus);
|
||||
Assert.Equal(scheduledOn, stored.ScheduledDate);
|
||||
Assert.Equal(1, stored.RescheduleCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PatchField_DueDate_DoesNotChangeScheduledDate()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue