diff --git a/SeaHaven.Services/Helpers/WorkOrderAddonCutoff.cs b/SeaHaven.Services/Helpers/WorkOrderAddonCutoff.cs
index db81e62..886b095 100644
--- a/SeaHaven.Services/Helpers/WorkOrderAddonCutoff.cs
+++ b/SeaHaven.Services/Helpers/WorkOrderAddonCutoff.cs
@@ -3,6 +3,7 @@ namespace SeaHaven.Services.Helpers
///
/// Server-side Add-On cutoff: Saturday 23:59:59 UTC of the week prior to the schedule week.
/// SH-184: recalculated whenever scheduling is set, changed, or cleared; audited on change.
+ /// At creation the WO arrives when it is created; on a reschedule it arrives when it is moved.
/// Create may accept a client hint when unscheduled; schedule present ignores override.
///
public static class WorkOrderAddonCutoff
@@ -36,14 +37,40 @@ namespace SeaHaven.Services.Helpers
}
///
- /// SH-184 authoritative recalc after schedule set/change/clear. No manual override on patch.
- /// Cleared schedule yields false.
+ /// SH-412: a reschedule into another week makes the WO arrive in that week at the moment
+ /// of the reschedule, so Add-On compares (not the
+ /// creation time) with the new week's cutoff. A move within the same week keeps the
+ /// current value; a cleared schedule yields false. Matches the prototype's reschedule rule.
///
- public static bool RecalculateIsAddOnFromSchedule(
- DateTime createdAtUtc,
+ public static bool RecalculateIsAddOnOnReschedule(
+ bool currentIsAddOn,
+ DateTime? previousScheduledDate,
+ DateOnly? previousTargetWeek,
DateTime? scheduledDate,
- DateOnly? targetWeek)
- => ComputeFromScheduleAnchor(createdAtUtc, scheduledDate, targetWeek, manualOverride: false);
+ DateOnly? targetWeek,
+ DateTime rescheduledAtUtc)
+ {
+ var anchor = ScheduleAnchor(scheduledDate, targetWeek);
+ if (!anchor.HasValue)
+ return false;
+
+ var previousAnchor = ScheduleAnchor(previousScheduledDate, previousTargetWeek);
+ if (previousAnchor.HasValue
+ && WorkOrderBoardMutationRules.GetWeekStartMonday(previousAnchor.Value)
+ == WorkOrderBoardMutationRules.GetWeekStartMonday(anchor.Value))
+ return currentIsAddOn;
+
+ return NormalizeUtc(rescheduledAtUtc) > GetAddonCutoffUtc(anchor.Value);
+ }
+
+ private static DateTime? ScheduleAnchor(DateTime? scheduledDate, DateOnly? targetWeek)
+ {
+ if (scheduledDate.HasValue)
+ return scheduledDate.Value;
+ if (targetWeek.HasValue)
+ return targetWeek.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
+ return null;
+ }
private static bool ComputeFromScheduleAnchor(
DateTime createdAtUtc,
@@ -51,12 +78,7 @@ namespace SeaHaven.Services.Helpers
DateOnly? targetWeek,
bool? manualOverride)
{
- DateTime? anchor = null;
- if (scheduledDate.HasValue)
- anchor = scheduledDate.Value;
- else if (targetWeek.HasValue)
- anchor = targetWeek.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
-
+ var anchor = ScheduleAnchor(scheduledDate, targetWeek);
if (!anchor.HasValue)
return manualOverride ?? false;
diff --git a/SeaHaven.Services/Implementation/WorkOrderBoardUpdateService.cs b/SeaHaven.Services/Implementation/WorkOrderBoardUpdateService.cs
index 25e56de..72b26ed 100644
--- a/SeaHaven.Services/Implementation/WorkOrderBoardUpdateService.cs
+++ b/SeaHaven.Services/Implementation/WorkOrderBoardUpdateService.cs
@@ -19,6 +19,7 @@ namespace SeaHaven.Services.Implementation
private readonly IWorkOrderUpliftService _upliftService;
private readonly IUpliftDataService _upliftData;
private readonly IServicesRegistryService? _servicesRegistryService;
+ private readonly TimeProvider _timeProvider;
public WorkOrderBoardUpdateService(
IWorkOrderBoardDataService boardDataService,
@@ -26,7 +27,8 @@ namespace SeaHaven.Services.Implementation
IWorkOrderAuditService auditService,
IWorkOrderUpliftService upliftService,
IUpliftDataService upliftData,
- IServicesRegistryService? servicesRegistryService = null)
+ IServicesRegistryService? servicesRegistryService = null,
+ TimeProvider? timeProvider = null)
{
_boardDataService = boardDataService;
_mutationData = mutationData;
@@ -34,6 +36,7 @@ namespace SeaHaven.Services.Implementation
_upliftService = upliftService;
_upliftData = upliftData;
_servicesRegistryService = servicesRegistryService;
+ _timeProvider = timeProvider ?? TimeProvider.System;
}
public async Task PatchFieldAsync(
@@ -753,9 +756,10 @@ namespace SeaHaven.Services.Implementation
return FieldChange.ForField(auditField, old, newVal);
}
- private static List ApplyScheduledDate(WorkOrder workOrder, string? value, string auditField)
+ private List ApplyScheduledDate(WorkOrder workOrder, string? value, string auditField)
{
var previousDate = workOrder.ScheduledDate;
+ var previousTargetWeek = workOrder.TargetWeek;
DateTime? parsed = null;
if (!string.IsNullOrWhiteSpace(value))
{
@@ -790,12 +794,14 @@ namespace SeaHaven.Services.Implementation
}
changes.AddRange(ApplyAutoScheduleSideEffects(workOrder));
- AppendIsAddOnRecalculation(workOrder, changes);
+ AppendIsAddOnRecalculation(workOrder, previousDate, previousTargetWeek, changes);
return changes;
}
- private static List ApplyTargetWeek(WorkOrder workOrder, string? value, string auditField)
+ private List ApplyTargetWeek(WorkOrder workOrder, string? value, string auditField)
{
+ var previousDate = workOrder.ScheduledDate;
+ var previousTargetWeek = workOrder.TargetWeek;
DateOnly? parsed = null;
if (!string.IsNullOrWhiteSpace(value))
{
@@ -813,28 +819,33 @@ namespace SeaHaven.Services.Implementation
changes.Add(FieldChange.ForField(auditField, old, newVal));
}
- AppendIsAddOnRecalculation(workOrder, changes);
+ AppendIsAddOnRecalculation(workOrder, previousDate, previousTargetWeek, changes);
return changes;
}
+ // Toggling week-only mode keeps the scheduled week, so Add-On is unchanged (SH-412).
private static List ApplyScheduleWeekOnly(WorkOrder workOrder, string? value, string auditField)
{
var change = ApplyBoolField(value, auditField, v => workOrder.ScheduleWeekOnly = v, () => workOrder.ScheduleWeekOnly);
var changes = new List { change };
- if (change.HasChanged)
- AppendIsAddOnRecalculation(workOrder, changes);
changes.AddRange(ApplyAutoScheduleSideEffects(workOrder));
return changes;
}
- private static void AppendIsAddOnRecalculation(WorkOrder workOrder, List changes)
+ private void AppendIsAddOnRecalculation(
+ WorkOrder workOrder,
+ DateTime? previousScheduledDate,
+ DateOnly? previousTargetWeek,
+ List changes)
{
- var createdAt = workOrder.CreatedDate ?? DateTime.UtcNow;
var oldValue = workOrder.IsAddOn.ToString();
- var newIsAddOn = WorkOrderAddonCutoff.RecalculateIsAddOnFromSchedule(
- createdAt,
+ var newIsAddOn = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ workOrder.IsAddOn,
+ previousScheduledDate,
+ previousTargetWeek,
workOrder.ScheduledDate,
- workOrder.TargetWeek);
+ workOrder.TargetWeek,
+ _timeProvider.GetUtcNow().UtcDateTime);
if (workOrder.IsAddOn == newIsAddOn)
return;
diff --git a/SeaHaven.Services/Implementation/WorkOrderService.cs b/SeaHaven.Services/Implementation/WorkOrderService.cs
index 132cbe5..3670ad2 100644
--- a/SeaHaven.Services/Implementation/WorkOrderService.cs
+++ b/SeaHaven.Services/Implementation/WorkOrderService.cs
@@ -22,6 +22,7 @@ namespace SeaHaven.Services.Implementation
private readonly ICreateWorkOrderValidation _createValidator;
private readonly IUpdateWorkOrderValidation _updateValidator;
private readonly IWorkOrderAccountResolver _accountResolver;
+ private readonly TimeProvider _timeProvider;
public WorkOrderService(
IWorkOrderDataService workOrderDataService,
@@ -31,7 +32,8 @@ namespace SeaHaven.Services.Implementation
IFileStoragePort fileStorage,
ICreateWorkOrderValidation createValidator,
IUpdateWorkOrderValidation updateValidator,
- IWorkOrderAccountResolver accountResolver)
+ IWorkOrderAccountResolver accountResolver,
+ TimeProvider? timeProvider = null)
{
_workOrderDataService = workOrderDataService;
_commentDataService = commentDataService;
@@ -41,6 +43,7 @@ namespace SeaHaven.Services.Implementation
_createValidator = createValidator;
_updateValidator = updateValidator;
_accountResolver = accountResolver;
+ _timeProvider = timeProvider ?? TimeProvider.System;
}
public async Task GetWorkOrderByIdAsync(int id)
@@ -116,6 +119,8 @@ namespace SeaHaven.Services.Implementation
var scheduledDateChanged = dto.ScheduledDate.HasValue
&& dto.ScheduledDate.Value.Date != existingWorkOrder.ScheduledDate?.Date;
var previousIsAddOn = existingWorkOrder.IsAddOn;
+ var previousScheduledDate = existingWorkOrder.ScheduledDate;
+ var previousTargetWeek = existingWorkOrder.TargetWeek;
UpdateWorkOrderDTO.UpdateEntity(dto, existingWorkOrder);
if (scheduledDateChanged)
{
@@ -126,10 +131,13 @@ namespace SeaHaven.Services.Implementation
changes.AddRange(scheduleChanges
.Where(c => c.HasChanged && c.FieldName != WorkOrderBoardFieldNames.ScheduledDate)
.Select(c => $"{c.FieldName}: {c.OldValue} → {c.NewValue}"));
- existingWorkOrder.IsAddOn = WorkOrderAddonCutoff.RecalculateIsAddOnFromSchedule(
- existingWorkOrder.CreatedDate ?? DateTime.UtcNow,
+ existingWorkOrder.IsAddOn = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ previousIsAddOn,
+ previousScheduledDate,
+ previousTargetWeek,
existingWorkOrder.ScheduledDate,
- existingWorkOrder.TargetWeek);
+ existingWorkOrder.TargetWeek,
+ _timeProvider.GetUtcNow().UtcDateTime);
if (existingWorkOrder.IsAddOn != previousIsAddOn)
changes.Add($"IsAddOn: {previousIsAddOn} → {existingWorkOrder.IsAddOn}");
}
diff --git a/SeaHavenIndustries.Tests/WorkOrderAccountTestHelpers.cs b/SeaHavenIndustries.Tests/WorkOrderAccountTestHelpers.cs
index 040e235..9c33645 100644
--- a/SeaHavenIndustries.Tests/WorkOrderAccountTestHelpers.cs
+++ b/SeaHavenIndustries.Tests/WorkOrderAccountTestHelpers.cs
@@ -19,14 +19,16 @@ internal static class WorkOrderAccountTestHelpers
public static WorkOrderBoardUpdateService BoardUpdateService(
ApplicationDbContext context,
IWorkOrderAuditService audit,
- IServicesRegistryService? servicesRegistry = null)
+ IServicesRegistryService? servicesRegistry = null,
+ TimeProvider? timeProvider = null)
=> new(
new WorkOrderBoardDataService(context),
new WorkOrderBoardMutationDataService(context),
audit,
UpliftService(context),
new UpliftDataService(context),
- servicesRegistry);
+ servicesRegistry,
+ timeProvider);
public static WorkOrderUpliftService UpliftService(ApplicationDbContext context)
=> new(
diff --git a/SeaHavenIndustries.Tests/WorkOrderAddonCutoffTests.cs b/SeaHavenIndustries.Tests/WorkOrderAddonCutoffTests.cs
index d860482..91b4623 100644
--- a/SeaHavenIndustries.Tests/WorkOrderAddonCutoffTests.cs
+++ b/SeaHavenIndustries.Tests/WorkOrderAddonCutoffTests.cs
@@ -114,21 +114,78 @@ public class WorkOrderAddonCutoffTests
Assert.True(result);
}
+ // Rescheduled on Wed 2026-06-24: the week of 06-22 is past its cutoff (Sat 06-20 23:59:59),
+ // the week of 06-29 is not (cutoff Sat 06-27 23:59:59).
+ private static readonly DateTime RescheduledAt = new(2026, 6, 24, 10, 0, 0, DateTimeKind.Utc);
+
[Fact]
- public void RecalculateIsAddOnFromSchedule_NoSchedule_ReturnsFalse()
+ public void RecalculateOnReschedule_NoSchedule_ReturnsFalse()
{
- var created = new DateTime(2026, 6, 21, 0, 0, 0, DateTimeKind.Utc);
- Assert.False(WorkOrderAddonCutoff.RecalculateIsAddOnFromSchedule(created, null, null));
+ Assert.False(WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ currentIsAddOn: true,
+ previousScheduledDate: new DateTime(2026, 6, 24),
+ previousTargetWeek: null,
+ scheduledDate: null,
+ targetWeek: null,
+ RescheduledAt));
}
[Fact]
- public void RecalculateIsAddOnFromSchedule_AfterCutoff_ReturnsTrue()
+ public void RecalculateOnReschedule_IntoWeekPastCutoff_TurnsOnForWorkOrderCreatedLongBefore()
{
- var created = new DateTime(2026, 6, 21, 0, 0, 0, DateTimeKind.Utc);
- var result = WorkOrderAddonCutoff.RecalculateIsAddOnFromSchedule(
- created,
- scheduledDate: new DateTime(2026, 6, 24),
- targetWeek: null);
+ // SH-412: the WO was created weeks earlier; it arrives in the current week at the
+ // moment of the reschedule, which is already past that week's cutoff.
+ var result = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ currentIsAddOn: false,
+ previousScheduledDate: new DateTime(2026, 7, 8),
+ previousTargetWeek: null,
+ scheduledDate: new DateTime(2026, 6, 25),
+ targetWeek: null,
+ RescheduledAt);
+
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void RecalculateOnReschedule_IntoWeekBeforeCutoff_TurnsOff()
+ {
+ var result = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ currentIsAddOn: true,
+ previousScheduledDate: new DateTime(2026, 6, 24),
+ previousTargetWeek: null,
+ scheduledDate: new DateTime(2026, 7, 1),
+ targetWeek: null,
+ RescheduledAt);
+
+ Assert.False(result);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void RecalculateOnReschedule_WithinSameWeek_KeepsCurrentValue(bool currentIsAddOn)
+ {
+ var result = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ currentIsAddOn,
+ previousScheduledDate: new DateTime(2026, 6, 22),
+ previousTargetWeek: null,
+ scheduledDate: new DateTime(2026, 6, 26),
+ targetWeek: null,
+ RescheduledAt);
+
+ Assert.Equal(currentIsAddOn, result);
+ }
+
+ [Fact]
+ public void RecalculateOnReschedule_FirstScheduleIntoWeekPastCutoff_TurnsOn()
+ {
+ var result = WorkOrderAddonCutoff.RecalculateIsAddOnOnReschedule(
+ currentIsAddOn: false,
+ previousScheduledDate: null,
+ previousTargetWeek: null,
+ scheduledDate: new DateTime(2026, 6, 26),
+ targetWeek: null,
+ RescheduledAt);
Assert.True(result);
}
diff --git a/SeaHavenIndustries.Tests/WorkOrderBoardUpdateServiceTests.cs b/SeaHavenIndustries.Tests/WorkOrderBoardUpdateServiceTests.cs
index 9901e3a..0cf861b 100644
--- a/SeaHavenIndustries.Tests/WorkOrderBoardUpdateServiceTests.cs
+++ b/SeaHavenIndustries.Tests/WorkOrderBoardUpdateServiceTests.cs
@@ -13,7 +13,8 @@ namespace SeaHavenIndustries.Tests;
public class WorkOrderBoardUpdateServiceTests
{
- private static (ApplicationDbContext Context, WorkOrderBoardUpdateService Service) CreateSut()
+ private static (ApplicationDbContext Context, WorkOrderBoardUpdateService Service) CreateSut(
+ TimeProvider? timeProvider = null)
{
var options = new DbContextOptionsBuilder()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
@@ -23,10 +24,16 @@ public class WorkOrderBoardUpdateServiceTests
var mutationData = new WorkOrderBoardMutationDataService(context);
var fieldLocks = new WorkOrderFieldLockService(new WorkOrderFieldLockDataService(context));
var audit = new WorkOrderAuditService(new WorkOrderAuditDataService(context), fieldLocks);
- var service = WorkOrderAccountTestHelpers.BoardUpdateService(context, audit);
+ var service = WorkOrderAccountTestHelpers.BoardUpdateService(context, audit, timeProvider: timeProvider);
return (context, service);
}
+ // Wed 2026-06-24: the week of 06-22 is past its cutoff, the week of 06-29 is not.
+ private sealed class FixedTimeProvider : TimeProvider
+ {
+ public override DateTimeOffset GetUtcNow() => new(2026, 6, 24, 10, 0, 0, TimeSpan.Zero);
+ }
+
private static string ToVersion(WorkOrder workOrder)
=> Convert.ToBase64String(workOrder.RowVersion ?? new byte[] { 1, 0, 0, 0, 0, 0, 0, 1 });
@@ -2260,6 +2267,46 @@ public class WorkOrderBoardUpdateServiceTests
Assert.True(persisted.IsAddOn);
}
+ [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
+ [InlineData("2026-07-06", false, "2026-07-09", false)] // same week: unchanged
+ [InlineData("2026-06-22", true, "2026-06-26", true)] // same week: unchanged
+ public async Task PatchField_ScheduledDate_RecalculatesIsAddOnAtRescheduleTime(
+ string from,
+ bool isAddOn,
+ string to,
+ bool expectedIsAddOn)
+ {
+ var (context, service) = CreateSut(new FixedTimeProvider());
+ var wo = new WorkOrder
+ {
+ Id = 1,
+ LifecycleStatus = LifecycleStatus.Scheduled,
+ WorkOrderType = WorkOrderType.PM,
+ ScheduledDate = DateTime.Parse(from),
+ // Created weeks before any of these cutoffs: creation time must not decide (SH-412).
+ 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.ScheduledDate,
+ Value = to,
+ WorkOrderVersion = ToVersion(wo)
+ }, "actor-1");
+
+ Assert.Equal(expectedIsAddOn, result.IsAddOn);
+ var persisted = await context.workOrders.SingleAsync(w => w.Id == 1);
+ Assert.Equal(expectedIsAddOn, persisted.IsAddOn);
+ var addOnAudits = await context.WorkOrderAuditLogs.Where(a => a.FieldName == "IsAddOn").ToListAsync();
+ Assert.Equal(isAddOn == expectedIsAddOn ? 0 : 1, addOnAudits.Count);
+ }
+
[Fact]
public async Task PatchField_WorkOrderType_DoesNotRecalculateIsAddOn()
{
diff --git a/SeaHavenIndustries.Tests/WorkOrderEditAddonRescheduleTests.cs b/SeaHavenIndustries.Tests/WorkOrderEditAddonRescheduleTests.cs
index 328e4f2..0748c9f 100644
--- a/SeaHavenIndustries.Tests/WorkOrderEditAddonRescheduleTests.cs
+++ b/SeaHavenIndustries.Tests/WorkOrderEditAddonRescheduleTests.cs
@@ -49,6 +49,86 @@ public sealed class WorkOrderEditAddonRescheduleTests
Assert.Contains(audit, x => x.FieldName?.Contains("RescheduleCount: 0 → 1", StringComparison.Ordinal) == true);
}
+ [Fact]
+ public async Task EditWorkorder_RescheduleOlderWorkOrderIntoWeekPastCutoff_EnablesAndAuditsAddOn()
+ {
+ // SH-412 retest: the WO was created weeks before the target week's cutoff, so the
+ // creation-time rule kept Add-On off. It arrives in the week when it is rescheduled.
+ await using var context = CreateContext();
+ context.workOrders.Add(new WorkOrder
+ {
+ Id = 1,
+ CreatedDate = new DateTime(2026, 6, 1, 0, 0, 0, DateTimeKind.Utc),
+ ScheduledDate = new DateTime(2026, 7, 8),
+ IsAddOn = false
+ });
+ await context.SaveChangesAsync();
+
+ var result = await CreateController(context, new FixedTimeProvider()).Editworkorder(new EditWorkorder_DTO
+ {
+ Id = 1,
+ ScheduledDate = new DateTime(2026, 6, 25)
+ });
+
+ Assert.IsType(result);
+ var persisted = await context.workOrders.SingleAsync(x => x.Id == 1);
+ Assert.True(persisted.IsAddOn);
+ var audit = await context.WorkOrderAuditLogs.SingleAsync(x => x.WorkOrderId == 1);
+ Assert.Contains("IsAddOn: False → True", audit.FieldName);
+ }
+
+ [Fact]
+ public async Task EditWorkorder_RescheduleIntoWeekBeforeCutoff_ClearsAndAuditsAddOn()
+ {
+ 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,
+ ScheduledDate = new DateTime(2026, 7, 1)
+ });
+
+ Assert.IsType(result);
+ var persisted = await context.workOrders.SingleAsync(x => x.Id == 1);
+ Assert.False(persisted.IsAddOn);
+ var audit = await context.WorkOrderAuditLogs.SingleAsync(x => x.WorkOrderId == 1);
+ Assert.Contains("IsAddOn: True → False", audit.FieldName);
+ }
+
+ [Fact]
+ public async Task EditWorkorder_RescheduleWithinSameWeek_KeepsAddOn()
+ {
+ await using var context = CreateContext();
+ context.workOrders.Add(new WorkOrder
+ {
+ Id = 1,
+ CreatedDate = new DateTime(2026, 6, 1, 0, 0, 0, DateTimeKind.Utc),
+ ScheduledDate = new DateTime(2026, 7, 6),
+ IsAddOn = false
+ });
+ await context.SaveChangesAsync();
+
+ var result = await CreateController(context, new FixedTimeProvider()).Editworkorder(new EditWorkorder_DTO
+ {
+ Id = 1,
+ ScheduledDate = new DateTime(2026, 7, 9)
+ });
+
+ Assert.IsType(result);
+ var persisted = await context.workOrders.SingleAsync(x => x.Id == 1);
+ Assert.False(persisted.IsAddOn);
+ var audit = await context.WorkOrderAuditLogs.SingleAsync(x => x.WorkOrderId == 1);
+ Assert.DoesNotContain("IsAddOn", audit.FieldName);
+ }
+
[Fact]
public async Task EditWorkorder_FirstSchedule_SetsOriginalWeekAndPromotesIncomplete()
{
@@ -145,7 +225,15 @@ public sealed class WorkOrderEditAddonRescheduleTests
return new ApplicationDbContext(options);
}
- private static WorkOrderController CreateController(ApplicationDbContext context)
+ // Wed 2026-06-24: the week of 06-22 is past its cutoff, the week of 06-29 is not.
+ private sealed class FixedTimeProvider : TimeProvider
+ {
+ public override DateTimeOffset GetUtcNow() => new(2026, 6, 24, 10, 0, 0, TimeSpan.Zero);
+ }
+
+ private static WorkOrderController CreateController(
+ ApplicationDbContext context,
+ TimeProvider? timeProvider = null)
{
var accountResolver = WorkOrderAccountTestHelpers.Resolver(context);
var workOrderService = new WorkOrderService(
@@ -156,7 +244,8 @@ public sealed class WorkOrderEditAddonRescheduleTests
fileStorage: null!,
new CreateWorkOrderValidation(),
new UpdateWorkOrderValidation(),
- accountResolver);
+ accountResolver,
+ timeProvider);
return new WorkOrderController(
workOrderService,
accountResolver,