diff --git a/SeaHaven.DataServices/Helpers/WorkOrderBoardQueryFilters.cs b/SeaHaven.DataServices/Helpers/WorkOrderBoardQueryFilters.cs
index 3d877e0..7ff26ba 100644
--- a/SeaHaven.DataServices/Helpers/WorkOrderBoardQueryFilters.cs
+++ b/SeaHaven.DataServices/Helpers/WorkOrderBoardQueryFilters.cs
@@ -176,10 +176,15 @@ namespace SeaHaven.DataServices.Helpers
///
/// Restricts to unscheduled rows. A null ScheduledDate is the canonical
/// unscheduled representation; replaces the date-range filter when the
- /// unscheduled-only search mode is active.
+ /// unscheduled-only search mode is active. Mirrors the undated branch of
+ /// : completed and canceled rows are
+ /// excluded so both modes agree on the protected unscheduled semantics.
///
public static IQueryable ApplyUnscheduledOnlyFilter(IQueryable query)
- => query.Where(w => w.ScheduledDate == null);
+ => query.Where(w =>
+ w.ScheduledDate == null
+ && w.LifecycleStatus != LifecycleStatus.Completed
+ && w.LifecycleStatus != LifecycleStatus.Canceled);
public static IQueryable ApplyDateRangeFilter(
IQueryable query,
diff --git a/SeaHavenIndustries.Tests/WorkOrderBoardSearchTests.cs b/SeaHavenIndustries.Tests/WorkOrderBoardSearchTests.cs
index d1d4890..721291a 100644
--- a/SeaHavenIndustries.Tests/WorkOrderBoardSearchTests.cs
+++ b/SeaHavenIndustries.Tests/WorkOrderBoardSearchTests.cs
@@ -1425,4 +1425,67 @@ public class WorkOrderAdvancedSearchServiceTests
Assert.Empty(page0.Items.Select(i => i.Id).Intersect(page1.Items.Select(i => i.Id)));
Assert.Equal(new[] { 1, 2, 3 }, page0.Items.Concat(page1.Items).Select(i => i.Id).OrderBy(id => id).ToArray());
}
+
+ [Fact]
+ public async Task SearchAsync_UnscheduledOnly_ExcludesCompletedAndCanceledUndatedRows()
+ {
+ await using var context = CreateContext();
+
+ context.workOrders.AddRange(
+ new WorkOrder
+ {
+ Id = 1,
+ ScheduledDate = null,
+ LifecycleStatus = LifecycleStatus.Incomplete,
+ InternalWONumber = "10000000001",
+ istemplate = false
+ },
+ new WorkOrder
+ {
+ Id = 2,
+ ScheduledDate = null,
+ LifecycleStatus = LifecycleStatus.Completed,
+ InternalWONumber = "10000000002",
+ istemplate = false
+ },
+ new WorkOrder
+ {
+ Id = 3,
+ ScheduledDate = null,
+ LifecycleStatus = LifecycleStatus.Canceled,
+ InternalWONumber = "10000000003",
+ istemplate = false
+ },
+ new WorkOrder
+ {
+ Id = 4,
+ ScheduledDate = new DateTime(2026, 6, 23),
+ LifecycleStatus = LifecycleStatus.Completed,
+ InternalWONumber = "10000000004",
+ istemplate = false
+ });
+
+ await context.SaveChangesAsync();
+
+ var dataService = new WorkOrderAdvancedSearchDataService(context);
+ var service = new SeaHaven.Services.Implementation.WorkOrderAdvancedSearchService(
+ dataService,
+ WorkOrderAccountTestHelpers.Resolver(context));
+
+ var result = await service.SearchAsync(new SeaHaven.Services.DTOs.WorkOrderAdvancedSearchQueryDto
+ {
+ DatePreset = SeaHaven.Services.Helpers.WorkOrderAdvancedSearchDatePreset.Custom,
+ DateFrom = new DateOnly(2026, 6, 22),
+ DateTo = new DateOnly(2026, 6, 26),
+ UnscheduledOnly = true
+ }, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
+
+ Assert.Equal(1, result.TotalCount);
+ Assert.Single(result.Items);
+ Assert.Equal(1, result.Items.Single().Id);
+ Assert.Null(result.Items.Single().ScheduledDate);
+ Assert.DoesNotContain(result.Items, i => i.Id == 2);
+ Assert.DoesNotContain(result.Items, i => i.Id == 3);
+ Assert.DoesNotContain(result.Items, i => i.Id == 4);
+ }
}