test: pin add-on across week-only toggles and date-less edits

Keep the add-on recalculation on the week-only toggle so a future schedule
side effect cannot leave a stale tag, and cover that a toggle and an edit
without Schedule On leave Add-On unchanged.
This commit is contained in:
Alexandre Brandizzi 2026-10-01 16:19:13 -03:00
parent 2c918b0f6a
commit efe4f5f0b9
3 changed files with 71 additions and 2 deletions

View file

@ -823,12 +823,15 @@ namespace SeaHaven.Services.Implementation
return changes;
}
// Toggling week-only mode keeps the scheduled week, so Add-On is unchanged (SH-412).
private static List<FieldChange> ApplyScheduleWeekOnly(WorkOrder workOrder, string? value, string auditField)
private List<FieldChange> ApplyScheduleWeekOnly(WorkOrder workOrder, string? value, string auditField)
{
var previousDate = workOrder.ScheduledDate;
var previousTargetWeek = workOrder.TargetWeek;
var change = ApplyBoolField(value, auditField, v => workOrder.ScheduleWeekOnly = v, () => workOrder.ScheduleWeekOnly);
var changes = new List<FieldChange> { change };
changes.AddRange(ApplyAutoScheduleSideEffects(workOrder));
if (change.HasChanged)
AppendIsAddOnRecalculation(workOrder, previousDate, previousTargetWeek, changes);
return changes;
}

View file

@ -2267,6 +2267,42 @@ public class WorkOrderBoardUpdateServiceTests
Assert.True(persisted.IsAddOn);
}
[Theory]
[InlineData(true, "true")]
[InlineData(false, "true")]
[InlineData(true, "false")]
[InlineData(false, "false")]
public async Task PatchField_ScheduleWeekOnlyToggle_KeepsIsAddOn(bool isAddOn, string weekOnly)
{
var (context, service) = CreateSut(new FixedTimeProvider());
var wo = new WorkOrder
{
Id = 1,
LifecycleStatus = weekOnly == "true" ? LifecycleStatus.Scheduled : LifecycleStatus.Pending,
WorkOrderType = WorkOrderType.PM,
ScheduledDate = new DateTime(2026, 6, 25),
ScheduleWeekOnly = weekOnly != "true",
CreatedDate = new DateTime(2026, 6, 1, 0, 0, 0, DateTimeKind.Utc),
IsAddOn = isAddOn,
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.ScheduleWeekOnly,
Value = weekOnly,
WorkOrderVersion = ToVersion(wo)
}, "actor-1");
Assert.Equal(isAddOn, result.IsAddOn);
var persisted = await context.workOrders.SingleAsync(w => w.Id == 1);
Assert.Equal(new DateTime(2026, 6, 25), persisted.ScheduledDate);
Assert.Equal(isAddOn, persisted.IsAddOn);
Assert.Empty(await context.WorkOrderAuditLogs.Where(a => a.FieldName == "IsAddOn").ToListAsync());
}
[Theory]
[InlineData("2026-07-08", false, "2026-06-25", true)] // into the current week, past its cutoff
[InlineData("2026-06-24", true, "2026-07-01", false)] // into next week, before its cutoff

View file

@ -129,6 +129,36 @@ public sealed class WorkOrderEditAddonRescheduleTests
Assert.DoesNotContain("IsAddOn", audit.FieldName);
}
[Fact]
public async Task EditWorkorder_WithoutScheduledDate_LeavesScheduleAndAddOnUntouched()
{
// The edit form sends only changed fields: a null Schedule On means "not sent", never
// "clear". Clearing happens through the board patch, which turns Add-On off.
await using var context = CreateContext();
context.workOrders.Add(new WorkOrder
{
Id = 1,
CreatedDate = new DateTime(2026, 6, 23, 0, 0, 0, DateTimeKind.Utc),
ScheduledDate = new DateTime(2026, 6, 24),
IsAddOn = true
});
await context.SaveChangesAsync();
var result = await CreateController(context, new FixedTimeProvider()).Editworkorder(new EditWorkorder_DTO
{
Id = 1,
DueDate = new DateTime(2026, 6, 30)
});
Assert.IsType<OkObjectResult>(result);
var persisted = await context.workOrders.SingleAsync(x => x.Id == 1);
Assert.Equal(new DateTime(2026, 6, 24), persisted.ScheduledDate);
Assert.True(persisted.IsAddOn);
Assert.DoesNotContain(
await context.WorkOrderAuditLogs.Where(x => x.WorkOrderId == 1).ToListAsync(),
x => x.FieldName?.Contains("IsAddOn", StringComparison.Ordinal) == true);
}
[Fact]
public async Task EditWorkorder_FirstSchedule_SetsOriginalWeekAndPromotesIncomplete()
{