mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
SH-338: filter unscheduled work orders before pagination (#116)
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
* fix(work-orders): filter unscheduled search server-side * fix(work-orders): preserve unscheduled status scope
This commit is contained in:
parent
13ce4b7e88
commit
802b7a414e
6 changed files with 479 additions and 11 deletions
|
|
@ -173,6 +173,19 @@ namespace SeaHaven.DataServices.Helpers
|
|||
|| (w.Problem ?? "").ToLower().Contains(pm)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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. Mirrors the undated branch of
|
||||
/// <see cref="ApplyDateRangeFilter"/>: completed and canceled rows are
|
||||
/// excluded so both modes agree on the protected unscheduled semantics.
|
||||
/// </summary>
|
||||
public static IQueryable<WorkOrder> ApplyUnscheduledOnlyFilter(IQueryable<WorkOrder> query)
|
||||
=> query.Where(w =>
|
||||
w.ScheduledDate == null
|
||||
&& w.LifecycleStatus != LifecycleStatus.Completed
|
||||
&& w.LifecycleStatus != LifecycleStatus.Canceled);
|
||||
|
||||
public static IQueryable<WorkOrder> ApplyDateRangeFilter(
|
||||
IQueryable<WorkOrder> query,
|
||||
DateOnly dateFrom,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ namespace SeaHaven.DataServices.Implementation
|
|||
var baseQuery = WorkOrderBoardQueryFilters.ApplyBaseScope(_context.workOrders.AsNoTracking());
|
||||
if (query.AccountId.HasValue)
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyAccountScope(baseQuery, query.AccountId.Value);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDateRangeFilter(baseQuery, query.DateFrom, query.DateTo);
|
||||
if (query.UnscheduledOnly)
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyUnscheduledOnlyFilter(baseQuery);
|
||||
else
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDateRangeFilter(baseQuery, query.DateFrom, query.DateTo);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplySiteFilter(baseQuery, query.Sites);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyTypeFilter(baseQuery, query.Types, query.Overdue);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDispatcherFilter(
|
||||
|
|
@ -61,14 +64,14 @@ namespace SeaHaven.DataServices.Implementation
|
|||
return field switch
|
||||
{
|
||||
"wonumber" or "woNumber" => descending
|
||||
? query.OrderByDescending(w => w.InternalWONumber)
|
||||
: query.OrderBy(w => w.InternalWONumber),
|
||||
? query.OrderByDescending(w => w.InternalWONumber).ThenBy(w => w.Id)
|
||||
: query.OrderBy(w => w.InternalWONumber).ThenBy(w => w.Id),
|
||||
"duedate" or "dueDate" => descending
|
||||
? query.OrderByDescending(w => w.DueDate).ThenBy(w => w.InternalWONumber)
|
||||
: query.OrderBy(w => w.DueDate).ThenBy(w => w.InternalWONumber),
|
||||
? query.OrderByDescending(w => w.DueDate).ThenBy(w => w.InternalWONumber).ThenBy(w => w.Id)
|
||||
: query.OrderBy(w => w.DueDate).ThenBy(w => w.InternalWONumber).ThenBy(w => w.Id),
|
||||
_ => descending
|
||||
? query.OrderByDescending(w => w.ScheduledDate).ThenByDescending(w => w.InternalWONumber)
|
||||
: query.OrderBy(w => w.ScheduledDate).ThenBy(w => w.InternalWONumber)
|
||||
? query.OrderByDescending(w => w.ScheduledDate).ThenByDescending(w => w.InternalWONumber).ThenBy(w => w.Id)
|
||||
: query.OrderBy(w => w.ScheduledDate).ThenBy(w => w.InternalWONumber).ThenBy(w => w.Id)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace SeaHaven.DataServices.Interfaces
|
|||
string? Search,
|
||||
DateOnly DateFrom,
|
||||
DateOnly DateTo,
|
||||
bool UnscheduledOnly,
|
||||
IReadOnlyList<string>? Sites,
|
||||
IReadOnlyList<WorkOrderType>? Types,
|
||||
bool Overdue,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ namespace SeaHaven.Services.DTOs
|
|||
public WorkOrderAdvancedSearchDatePreset? DatePreset { get; set; }
|
||||
public DateOnly? DateFrom { get; set; }
|
||||
public DateOnly? DateTo { get; set; }
|
||||
/// <summary>
|
||||
/// When true, only unscheduled rows (ScheduledDate is null) are returned.
|
||||
/// Takes precedence over DatePreset/DateFrom/DateTo for the scheduled-date
|
||||
/// filter; every other facet still applies.
|
||||
/// </summary>
|
||||
public bool UnscheduledOnly { get; set; }
|
||||
public List<string>? Sites { get; set; }
|
||||
public List<WorkOrderType>? Types { get; set; }
|
||||
/// <summary>When true, include past-due (isPastDue) rows. Combined with Types via OR.</summary>
|
||||
|
|
|
|||
|
|
@ -32,10 +32,14 @@ namespace SeaHaven.Services.Implementation
|
|||
var page = query.Page < 0 ? 0 : query.Page;
|
||||
var pageSize = query.PageSize < 1 ? DefaultPageSize : Math.Min(query.PageSize, MaxPageSize);
|
||||
|
||||
var dateRange = WorkOrderSearchDateRangeResolver.Resolve(
|
||||
query.DatePreset,
|
||||
query.DateFrom,
|
||||
query.DateTo);
|
||||
// Unscheduled-only mode ignores the scheduled-date range entirely;
|
||||
// the inert wide range keeps the data contract satisfied.
|
||||
var dateRange = query.UnscheduledOnly
|
||||
? new WorkOrderSearchDateRange(DateOnly.MinValue, DateOnly.MaxValue)
|
||||
: WorkOrderSearchDateRangeResolver.Resolve(
|
||||
query.DatePreset,
|
||||
query.DateFrom,
|
||||
query.DateTo);
|
||||
|
||||
var sortBy = WorkOrderBoardSortFields.NormalizeOrThrow(query.SortBy);
|
||||
|
||||
|
|
@ -43,6 +47,7 @@ namespace SeaHaven.Services.Implementation
|
|||
WorkOrderBoardSearchFilter.NormalizeSearch(query.Search),
|
||||
dateRange.From,
|
||||
dateRange.To,
|
||||
query.UnscheduledOnly,
|
||||
query.Sites,
|
||||
query.Types,
|
||||
query.Overdue,
|
||||
|
|
|
|||
|
|
@ -1048,4 +1048,444 @@ public class WorkOrderAdvancedSearchServiceTests
|
|||
Assert.Equal(1, result.Items.Single().Id);
|
||||
Assert.True(result.Items.Single().AvetaRequired);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_ReturnsOnlyUndatedRows()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
var weekStart = new DateOnly(2026, 6, 22);
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000002",
|
||||
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 = weekStart,
|
||||
DateTo = weekStart.AddDays(4),
|
||||
UnscheduledOnly = true
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Single(result.Items);
|
||||
Assert.Equal(2, result.Items.Single().Id);
|
||||
Assert.Null(result.Items.Single().ScheduledDate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnlyFalse_MatchesDefaultRangeSearch()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
var weekStart = new DateOnly(2026, 6, 22);
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
ScheduledDate = new DateTime(2026, 8, 4),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000002",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 3,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000003",
|
||||
istemplate = false
|
||||
});
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var dataService = new WorkOrderAdvancedSearchDataService(context);
|
||||
var service = new SeaHaven.Services.Implementation.WorkOrderAdvancedSearchService(
|
||||
dataService,
|
||||
WorkOrderAccountTestHelpers.Resolver(context));
|
||||
|
||||
var withFlagFalse = await service.SearchAsync(new SeaHaven.Services.DTOs.WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = SeaHaven.Services.Helpers.WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = weekStart,
|
||||
DateTo = weekStart.AddDays(4),
|
||||
UnscheduledOnly = false
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
var withFlagAbsent = await service.SearchAsync(new SeaHaven.Services.DTOs.WorkOrderAdvancedSearchQueryDto
|
||||
{
|
||||
DatePreset = SeaHaven.Services.Helpers.WorkOrderAdvancedSearchDatePreset.Custom,
|
||||
DateFrom = weekStart,
|
||||
DateTo = weekStart.AddDays(4)
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(withFlagAbsent.TotalCount, withFlagFalse.TotalCount);
|
||||
Assert.Equal(
|
||||
withFlagAbsent.Items.Select(i => i.Id).ToList(),
|
||||
withFlagFalse.Items.Select(i => i.Id).ToList());
|
||||
Assert.Equal(2, 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 == 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_IgnoresScheduledDateRange()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
var weekStart = new DateOnly(2026, 6, 22);
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000002",
|
||||
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 = weekStart,
|
||||
DateTo = weekStart.AddDays(4),
|
||||
UnscheduledOnly = true
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Single(result.Items);
|
||||
Assert.Equal(2, result.Items.Single().Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_CustomPresetWithoutDates_DoesNotThrow()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
|
||||
context.workOrders.Add(new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000001",
|
||||
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,
|
||||
UnscheduledOnly = true
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Equal(1, result.Items.Single().Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_ComposesWithAccountScopeAndSiteFacet()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
await WorkOrderAccountTestHelpers.EnsureAccountAsync(context, 1, "A");
|
||||
await WorkOrderAccountTestHelpers.EnsureAccountAsync(context, 2, "B");
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
AccountId = 1,
|
||||
SiteCode = "BK5",
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
AccountId = 2,
|
||||
SiteCode = "BK5",
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000002",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 3,
|
||||
AccountId = 1,
|
||||
SiteCode = "BK6",
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000003",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 4,
|
||||
AccountId = 1,
|
||||
SiteCode = "BK5",
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
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,
|
||||
Sites = new List<string> { "BK5" }
|
||||
}, WorkOrderAccountTestHelpers.AccountUser("disp-1", 1, "Dispatcher"), "disp-1");
|
||||
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Single(result.Items);
|
||||
Assert.Equal(1, result.Items.Single().Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_NoUndatedRows_ReturnsEmptyPage()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
ScheduledDate = new DateTime(2026, 6, 24),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000002",
|
||||
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(2000, 1, 1),
|
||||
DateTo = new DateOnly(2099, 12, 31),
|
||||
UnscheduledOnly = true,
|
||||
Page = 0,
|
||||
PageSize = 25
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(0, result.TotalCount);
|
||||
Assert.Empty(result.Items);
|
||||
Assert.Equal(0, result.Page);
|
||||
Assert.Equal(25, result.PageSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_UnscheduledOnly_PaginatesStableOrderWithoutDuplicates()
|
||||
{
|
||||
await using var context = CreateContext();
|
||||
|
||||
context.workOrders.AddRange(
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 1,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000003",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 2,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000001",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 3,
|
||||
ScheduledDate = null,
|
||||
LifecycleStatus = LifecycleStatus.Incomplete,
|
||||
InternalWONumber = "10000000002",
|
||||
istemplate = false
|
||||
},
|
||||
new WorkOrder
|
||||
{
|
||||
Id = 4,
|
||||
ScheduledDate = new DateTime(2026, 6, 23),
|
||||
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||
InternalWONumber = "10000000000",
|
||||
istemplate = false
|
||||
});
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var dataService = new WorkOrderAdvancedSearchDataService(context);
|
||||
var service = new SeaHaven.Services.Implementation.WorkOrderAdvancedSearchService(
|
||||
dataService,
|
||||
WorkOrderAccountTestHelpers.Resolver(context));
|
||||
|
||||
var page0 = 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,
|
||||
Page = 0,
|
||||
PageSize = 2
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
var page1 = 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,
|
||||
Page = 1,
|
||||
PageSize = 2
|
||||
}, WorkOrderAccountTestHelpers.OrgWideAdmin(), null);
|
||||
|
||||
Assert.Equal(3, page0.TotalCount);
|
||||
Assert.Equal(2, page0.Items.Count());
|
||||
Assert.Equal(new[] { 2, 3 }, page0.Items.Select(i => i.Id).ToArray());
|
||||
|
||||
Assert.Equal(3, page1.TotalCount);
|
||||
Assert.Single(page1.Items);
|
||||
Assert.Equal(1, page1.Items.Single().Id);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue