mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
Merge pull request #172 from Sea-Haven-Industries/fix/ab/sh-391-adv-search-date-range
fix(board-search): make the Advanced Filters date range narrow results (SH-391)
This commit is contained in:
commit
203fc92e4a
8 changed files with 339 additions and 10 deletions
|
|
@ -220,13 +220,26 @@ namespace SeaHaven.DataServices.Helpers
|
|||
&& w.LifecycleStatus != LifecycleStatus.Completed
|
||||
&& w.LifecycleStatus != LifecycleStatus.Canceled);
|
||||
|
||||
/// <summary>
|
||||
/// Narrows to rows whose Schedule On date falls in the range, or, for
|
||||
/// week-only rows, whose Target Week overlaps it: the same date the
|
||||
/// weekly board groups by (SH-391). Rows with no date never match a
|
||||
/// range; they are added only when <paramref name="includeDateless"/>
|
||||
/// is set, which callers send for searches with no date range selected.
|
||||
/// Completed and canceled dateless rows stay out, matching
|
||||
/// <see cref="ApplyUnscheduledOnlyFilter"/>.
|
||||
/// </summary>
|
||||
public static IQueryable<WorkOrder> ApplyDateRangeFilter(
|
||||
IQueryable<WorkOrder> query,
|
||||
DateOnly dateFrom,
|
||||
DateOnly dateTo)
|
||||
DateOnly dateTo,
|
||||
bool includeDateless = false)
|
||||
{
|
||||
var fromDate = dateFrom.ToDateTime(TimeOnly.MinValue).Date;
|
||||
var toDate = dateTo.ToDateTime(TimeOnly.MinValue).Date;
|
||||
// A target week (stored as its Monday) overlaps the range when it
|
||||
// starts by the range end and its Sunday is on or after the range start.
|
||||
var earliestWeekStart = dateFrom.DayNumber >= 6 ? dateFrom.AddDays(-6) : dateFrom;
|
||||
|
||||
return query.Where(w =>
|
||||
(w.ScheduledDate != null
|
||||
|
|
@ -234,9 +247,10 @@ namespace SeaHaven.DataServices.Helpers
|
|||
&& w.ScheduledDate.Value.Date <= toDate)
|
||||
|| (w.ScheduleWeekOnly == true
|
||||
&& w.TargetWeek != null
|
||||
&& w.TargetWeek >= dateFrom
|
||||
&& w.TargetWeek >= earliestWeekStart
|
||||
&& w.TargetWeek <= dateTo)
|
||||
|| (w.ScheduledDate == null
|
||||
|| (includeDateless
|
||||
&& w.ScheduledDate == null
|
||||
&& w.LifecycleStatus != LifecycleStatus.Completed
|
||||
&& w.LifecycleStatus != LifecycleStatus.Canceled));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ namespace SeaHaven.DataServices.Implementation
|
|||
if (query.UnscheduledOnly)
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyUnscheduledOnlyFilter(baseQuery);
|
||||
else
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDateRangeFilter(baseQuery, query.DateFrom, query.DateTo);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDateRangeFilter(
|
||||
baseQuery, query.DateFrom, query.DateTo, query.IncludeDateless);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplySiteFilter(baseQuery, query.Sites);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyRegionFilter(baseQuery, query.Regions);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyTypeFilter(baseQuery, query.Types, query.Overdue);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ namespace SeaHaven.DataServices.Interfaces
|
|||
int PageSize,
|
||||
string SortBy,
|
||||
string SortDir,
|
||||
int? AccountId = null);
|
||||
int? AccountId = null,
|
||||
bool IncludeDateless = false);
|
||||
|
||||
public record WorkOrderAdvancedSearchResult(
|
||||
IReadOnlyList<WorkOrderBoardRawRow> Rows,
|
||||
|
|
|
|||
|
|
@ -87,6 +87,14 @@ namespace SeaHaven.Services.DTOs
|
|||
/// filter; every other facet still applies.
|
||||
/// </summary>
|
||||
public bool UnscheduledOnly { get; set; }
|
||||
/// <summary>
|
||||
/// When true, rows with no date (no Schedule On) are returned alongside
|
||||
/// the in-range rows. Sent for searches with no date range selected; an
|
||||
/// explicit range leaves it unset or false so the range strictly narrows
|
||||
/// (SH-391). When it is omitted, clients that predate the flag keep their
|
||||
/// undated rows: see <see cref="WorkOrderSearchDateRangeResolver.ResolveIncludeDateless"/>.
|
||||
/// </summary>
|
||||
public bool? IncludeDateless { get; set; }
|
||||
public List<string>? Sites { get; set; }
|
||||
public List<string>? Regions { get; set; }
|
||||
public List<WorkOrderType>? Types { get; set; }
|
||||
|
|
|
|||
|
|
@ -15,6 +15,36 @@ namespace SeaHaven.Services.Helpers
|
|||
|
||||
public static class WorkOrderSearchDateRangeResolver
|
||||
{
|
||||
// Widest windows the frontend sends for "every week": the no-range search
|
||||
// (ADVANCED_SEARCH_ALL_WEEKS_FROM/TO, 2000-01-01..2099-12-31) and the pinned
|
||||
// Unassigned queue (UNASSIGNED_QUEUE_DATE_FROM/TO, 1970-01-01..2099-12-31).
|
||||
private static readonly DateOnly AllWeeksFrom = new(2000, 1, 1);
|
||||
private static readonly DateOnly AllWeeksTo = new(2099, 12, 31);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a board search adds open undated rows to its date range (SH-391).
|
||||
/// An explicit <paramref name="includeDateless"/> wins. When it is omitted,
|
||||
/// as by clients that predate the flag, a search with no date input or with
|
||||
/// an all-weeks Custom window still returns undated rows, as before SH-391:
|
||||
/// those requests mean "no range selected". Any other range is strict.
|
||||
/// </summary>
|
||||
public static bool ResolveIncludeDateless(
|
||||
bool? includeDateless,
|
||||
WorkOrderAdvancedSearchDatePreset? preset,
|
||||
DateOnly? dateFrom,
|
||||
DateOnly? dateTo)
|
||||
{
|
||||
if (includeDateless.HasValue)
|
||||
return includeDateless.Value;
|
||||
|
||||
if (!preset.HasValue && !dateFrom.HasValue && !dateTo.HasValue)
|
||||
return true;
|
||||
|
||||
return preset == WorkOrderAdvancedSearchDatePreset.Custom
|
||||
&& dateFrom <= AllWeeksFrom
|
||||
&& dateTo >= AllWeeksTo;
|
||||
}
|
||||
|
||||
public static WorkOrderSearchDateRange Resolve(
|
||||
WorkOrderAdvancedSearchDatePreset? preset,
|
||||
DateOnly? dateFrom,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,12 @@ namespace SeaHaven.Services.Implementation
|
|||
pageSize,
|
||||
sortBy,
|
||||
query.SortDir ?? "asc",
|
||||
accountId);
|
||||
accountId,
|
||||
WorkOrderSearchDateRangeResolver.ResolveIncludeDateless(
|
||||
query.IncludeDateless,
|
||||
query.DatePreset,
|
||||
query.DateFrom,
|
||||
query.DateTo));
|
||||
|
||||
var result = await _searchDataService.SearchAsync(dataQuery);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,264 @@
|
|||
using System.Globalization;
|
||||
using Data.SeaHavenIndustries;
|
||||
using Data.SeaHavenIndustries.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SeaHaven.DataServices.Implementation;
|
||||
using SeaHaven.Services.DTOs;
|
||||
using SeaHaven.Services.Helpers;
|
||||
using SeaHaven.Services.Implementation;
|
||||
|
||||
namespace SeaHavenIndustries.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// SH-391: an Advanced Filters date range narrows GET /board/search to rows
|
||||
/// whose Schedule On (or week-only Target Week) is in the range. Rows with no
|
||||
/// date come back only when the caller asks for them (no range selected).
|
||||
/// </summary>
|
||||
public class WorkOrderAdvancedSearchDateRangeTests
|
||||
{
|
||||
private static readonly DateOnly RangeFrom = new(2026, 9, 21);
|
||||
private static readonly DateOnly RangeTo = new(2026, 9, 25);
|
||||
|
||||
private static ApplicationDbContext CreateContext()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
return new ApplicationDbContext(options);
|
||||
}
|
||||
|
||||
private static WorkOrderAdvancedSearchService CreateService(ApplicationDbContext context)
|
||||
=> new(new WorkOrderAdvancedSearchDataService(context), WorkOrderAccountTestHelpers.Resolver(context));
|
||||
|
||||
private static WorkOrder Wo(
|
||||
int id,
|
||||
DateTime? scheduled,
|
||||
string? assignTo = null,
|
||||
LifecycleStatus status = LifecycleStatus.Scheduled,
|
||||
DateOnly? targetWeek = null,
|
||||
int? accountId = null)
|
||||
=> new()
|
||||
{
|
||||
Id = id,
|
||||
InternalWONumber = $"1000000000{id}",
|
||||
AssignTo = assignTo,
|
||||
ScheduledDate = scheduled,
|
||||
ScheduleWeekOnly = targetWeek.HasValue,
|
||||
TargetWeek = targetWeek,
|
||||
LifecycleStatus = status,
|
||||
AccountId = accountId,
|
||||
istemplate = false
|
||||
};
|
||||
|
||||
private static WorkOrder NotWeekOnly(WorkOrder wo)
|
||||
{
|
||||
wo.ScheduleWeekOnly = false;
|
||||
return wo;
|
||||
}
|
||||
|
||||
private static WorkOrderAdvancedSearchQueryDto UnassignedInRange(bool? includeDateless = null) => new()
|
||||
{
|
||||
DatePreset = WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = RangeFrom,
|
||||
DateTo = RangeTo,
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
IncludeDateless = includeDateless,
|
||||
PageSize = 50
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnassignedWithRange_ReturnsOnlyUnassignedRowsScheduledInRange()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 9, 23)),
|
||||
Wo(2, new DateTime(2026, 8, 4)),
|
||||
Wo(3, null, status: LifecycleStatus.Incomplete),
|
||||
Wo(4, new DateTime(2026, 9, 24), assignTo: "user-a"),
|
||||
Wo(5, new DateTime(2026, 10, 2)));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(
|
||||
UnassignedInRange(), WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Equal(new[] { 1 }, result.Items.Select(i => i.Id).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_RangeWithoutDispatcherFilter_ExcludesUndatedRows()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 9, 22), assignTo: "user-a"),
|
||||
Wo(2, null, assignTo: "user-a", status: LifecycleStatus.Incomplete),
|
||||
Wo(3, new DateTime(2026, 9, 14), assignTo: "user-a", status: LifecycleStatus.Incomplete));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(new WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = RangeFrom,
|
||||
DateTo = RangeTo
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(new[] { 1 }, result.Items.Select(i => i.Id).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_WeekOnlyRow_MatchesRangeThatOverlapsItsTargetWeek()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, null, targetWeek: new DateOnly(2026, 9, 21)),
|
||||
Wo(2, null, targetWeek: new DateOnly(2026, 9, 14)),
|
||||
Wo(3, null, targetWeek: new DateOnly(2026, 9, 28)),
|
||||
// Week-only with a leftover date outside the range: the week decides,
|
||||
// as on the board page (SH-391).
|
||||
Wo(4, new DateTime(2026, 10, 2), targetWeek: new DateOnly(2026, 9, 21)),
|
||||
// Not week-only: its date decides, so a target week does not bring it in.
|
||||
NotWeekOnly(Wo(5, new DateTime(2026, 10, 2), targetWeek: new DateOnly(2026, 9, 21))));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
// Wed–Fri of the week of 9/21: the week-only row for that week overlaps it.
|
||||
var result = await CreateService(context).SearchAsync(new WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = new DateOnly(2026, 9, 23),
|
||||
DateTo = RangeTo,
|
||||
Dispatchers = new List<string> { "__unassigned__" }
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(new[] { 1, 4 }, result.Items.Select(i => i.Id).OrderBy(id => id).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_IncludeDateless_AddsOpenUndatedRowsToTheRange()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 9, 23)),
|
||||
Wo(2, new DateTime(2026, 8, 4)),
|
||||
Wo(3, null, status: LifecycleStatus.Incomplete),
|
||||
Wo(4, null, status: LifecycleStatus.Completed),
|
||||
Wo(5, null, status: LifecycleStatus.Canceled));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(
|
||||
UnassignedInRange(includeDateless: true), WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(new[] { 1, 3 }, result.Items.Select(i => i.Id).OrderBy(id => id).ToArray());
|
||||
}
|
||||
|
||||
// Payloads the frontend sent before includeDateless existed. They must keep
|
||||
// their undated rows so this backend can deploy ahead of the client.
|
||||
[Theory]
|
||||
[InlineData(2000)] // no range selected: ADVANCED_SEARCH_ALL_WEEKS_FROM
|
||||
[InlineData(1970)] // pinned Unassigned queue: UNASSIGNED_QUEUE_DATE_FROM
|
||||
public async Task SearchAsync_AllWeeksWindowWithoutFlag_KeepsOpenUndatedRows(int fromYear)
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 8, 4)),
|
||||
Wo(2, null, status: LifecycleStatus.Incomplete),
|
||||
Wo(3, null, status: LifecycleStatus.Completed));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(new WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = new DateOnly(fromYear, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
PageSize = 50
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(new[] { 1, 2 }, result.Items.Select(i => i.Id).OrderBy(id => id).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_NoDateInputWithoutFlag_KeepsOpenUndatedRows()
|
||||
{
|
||||
// The WO# duplicate lookup sends only the search text and paging.
|
||||
await using var context = CreateContext();
|
||||
var thisWeek = WorkOrderSearchDateRangeResolver.GetIsoWeekStart(DateOnly.FromDateTime(DateTime.UtcNow));
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, thisWeek.ToDateTime(TimeOnly.MinValue)),
|
||||
Wo(2, null, status: LifecycleStatus.Incomplete),
|
||||
Wo(3, thisWeek.AddDays(-7).ToDateTime(TimeOnly.MinValue)));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(
|
||||
new WorkOrderAdvancedSearchQueryDto { PageSize = 100 },
|
||||
WorkOrderAccountTestHelpers.OrgWideAdmin(),
|
||||
null);
|
||||
|
||||
Assert.Equal(new[] { 1, 2 }, result.Items.Select(i => i.Id).OrderBy(id => id).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_AllWeeksWindowWithFlagFalse_ExcludesUndatedRows()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 8, 4)),
|
||||
Wo(2, null, status: LifecycleStatus.Incomplete));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var result = await CreateService(context).SearchAsync(new WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = new DateOnly(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
IncludeDateless = false,
|
||||
PageSize = 50
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(new[] { 1 }, result.Items.Select(i => i.Id).ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null, true)]
|
||||
[InlineData(null, WorkOrderAdvancedSearchDatePreset.Custom, "2000-01-01", "2099-12-31", true)]
|
||||
[InlineData(null, WorkOrderAdvancedSearchDatePreset.Custom, "1970-01-01", "2099-12-31", true)]
|
||||
[InlineData(null, WorkOrderAdvancedSearchDatePreset.Custom, "2000-01-02", "2099-12-31", false)]
|
||||
[InlineData(null, WorkOrderAdvancedSearchDatePreset.Custom, "2026-09-21", "2026-09-25", false)]
|
||||
[InlineData(null, WorkOrderAdvancedSearchDatePreset.ThisWeek, null, null, false)]
|
||||
[InlineData(false, null, null, null, false)]
|
||||
[InlineData(true, WorkOrderAdvancedSearchDatePreset.ThisWeek, null, null, true)]
|
||||
public void ResolveIncludeDateless_InfersOnlyForNoRangeRequests(
|
||||
bool? flag,
|
||||
WorkOrderAdvancedSearchDatePreset? preset,
|
||||
string? from,
|
||||
string? to,
|
||||
bool expected)
|
||||
{
|
||||
Assert.Equal(expected, WorkOrderSearchDateRangeResolver.ResolveIncludeDateless(
|
||||
flag,
|
||||
preset,
|
||||
from is null ? null : DateOnly.Parse(from, CultureInfo.InvariantCulture),
|
||||
to is null ? null : DateOnly.Parse(to, CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_RangeForAccountUser_NeverReturnsAnotherAccountsRows()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
await WorkOrderAccountTestHelpers.EnsureAccountAsync(context, 1, "A");
|
||||
await WorkOrderAccountTestHelpers.EnsureAccountAsync(context, 2, "B");
|
||||
context.workOrders.AddRange(
|
||||
Wo(1, new DateTime(2026, 9, 23), accountId: 1),
|
||||
Wo(2, new DateTime(2026, 9, 23), accountId: 2),
|
||||
Wo(3, null, status: LifecycleStatus.Incomplete, accountId: 2),
|
||||
Wo(4, null, targetWeek: new DateOnly(2026, 9, 21), accountId: 2));
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var user = WorkOrderAccountTestHelpers.AccountUser("disp-1", 1, "Dispatcher");
|
||||
var strict = await CreateService(context).SearchAsync(UnassignedInRange(), user, "disp-1");
|
||||
var withDateless = await CreateService(context).SearchAsync(
|
||||
UnassignedInRange(includeDateless: true), user, "disp-1");
|
||||
|
||||
Assert.Equal(new[] { 1 }, strict.Items.Select(i => i.Id).ToArray());
|
||||
Assert.Equal(new[] { 1 }, withDateless.Items.Select(i => i.Id).ToArray());
|
||||
}
|
||||
}
|
||||
|
|
@ -319,6 +319,7 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
DateFrom = new DateOnly(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
IncludeDateless = true,
|
||||
Page = 0,
|
||||
PageSize = pageSize
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
|
@ -380,6 +381,7 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
DateFrom = new DateOnly(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
IncludeDateless = true,
|
||||
Page = 0,
|
||||
PageSize = 50
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
|
@ -436,6 +438,7 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
DateFrom = new DateOnly(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
IncludeDateless = true,
|
||||
Page = 0,
|
||||
PageSize = 2
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
|
@ -446,6 +449,7 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
DateFrom = new DateOnly(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
Dispatchers = new List<string> { "__unassigned__" },
|
||||
IncludeDateless = true,
|
||||
Page = 1,
|
||||
PageSize = 2
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
|
@ -773,7 +777,7 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_IncludesUnscheduledRows()
|
||||
public async Task SearchAsync_IncludeDateless_IncludesUnscheduledRows()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
var weekStart = new DateOnly(2026, 6, 22);
|
||||
|
|
@ -803,7 +807,8 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
{
|
||||
DatePreset = SeaHaven.Services.Helpers.WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = weekStart,
|
||||
DateTo = weekStart.AddDays(4)
|
||||
DateTo = weekStart.AddDays(4),
|
||||
IncludeDateless = true
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(2, result.TotalCount);
|
||||
|
|
@ -1193,9 +1198,10 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
Assert.Equal(
|
||||
withFlagAbsent.Items.Select(i => i.Id).ToList(),
|
||||
withFlagFalse.Items.Select(i => i.Id).ToList());
|
||||
Assert.Equal(2, withFlagFalse.TotalCount);
|
||||
// SH-391: an explicit range narrows strictly, so the undated row 3 is out.
|
||||
Assert.Equal(1, withFlagFalse.TotalCount);
|
||||
Assert.Contains(withFlagFalse.Items, i => i.Id == 1);
|
||||
Assert.Contains(withFlagFalse.Items, i => i.Id == 3);
|
||||
Assert.DoesNotContain(withFlagFalse.Items, i => i.Id == 3);
|
||||
Assert.DoesNotContain(withFlagFalse.Items, i => i.Id == 2);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue