fix(workorders): preserve completed service snapshots

This commit is contained in:
Alexandre Brandizzi 2026-09-30 17:04:46 -03:00
parent aede3148d1
commit 0894b20e59
3 changed files with 73 additions and 7 deletions

View file

@ -8,6 +8,8 @@ namespace SeaHaven.DataServices.Helpers
{ {
public static class WorkOrderBoardProjection public static class WorkOrderBoardProjection
{ {
private static readonly string[] CompletedLegacyStatuses = { "completed", "complete", "done", "closed" };
private static readonly JsonSerializerOptions SnapshotJsonOptions = private static readonly JsonSerializerOptions SnapshotJsonOptions =
new(JsonSerializerDefaults.Web); new(JsonSerializerDefaults.Web);
@ -37,11 +39,15 @@ namespace SeaHaven.DataServices.Helpers
w.ServiceId, w.ServiceId,
w.ServiceNameSnapshot, w.ServiceNameSnapshot,
ServiceDisplayName = w.ServiceId.HasValue ServiceDisplayName = w.ServiceId.HasValue
? (w.ServiceDefinition != null ? (w.LifecycleStatus == LifecycleStatus.Completed
&& w.ServiceDefinition.IsActive || (w.LifecycleStatus == null
&& w.ServiceDefinition.IsDeleted != true && CompletedLegacyStatuses.Contains(((w.LegacyStatus ?? w.Status) ?? "").Trim().ToLower()))
? w.ServiceDefinition.Name ? w.ServiceNameSnapshot ?? w.Trade ?? w.Problem
: w.ServiceNameSnapshot ?? w.Trade ?? w.Problem) : (w.ServiceDefinition != null
&& w.ServiceDefinition.IsActive
&& w.ServiceDefinition.IsDeleted != true
? w.ServiceDefinition.Name
: w.ServiceNameSnapshot ?? w.Trade ?? w.Problem))
: w.Trade ?? w.Problem, : w.Trade ?? w.Problem,
w.SiteCode, w.SiteCode,
LocationName = w.Locations != null ? w.Locations.Name : null, LocationName = w.Locations != null ? w.Locations.Name : null,

View file

@ -5,6 +5,8 @@ namespace SeaHaven.DataServices.Helpers
{ {
public static class WorkOrderBoardQueryFilters public static class WorkOrderBoardQueryFilters
{ {
private static readonly string[] CompletedLegacyStatuses = { "completed", "complete", "done", "closed" };
/// <summary> /// <summary>
/// The window the Work Orders board searches when no date range is selected /// The window the Work Orders board searches when no date range is selected
/// (client ADVANCED_SEARCH_ALL_WEEKS_FROM/TO), used with includeDateless. /// (client ADVANCED_SEARCH_ALL_WEEKS_FROM/TO), used with includeDateless.
@ -268,6 +270,9 @@ namespace SeaHaven.DataServices.Helpers
? (w.ServiceDefinition != null ? (w.ServiceDefinition != null
&& w.ServiceDefinition.IsActive && w.ServiceDefinition.IsActive
&& w.ServiceDefinition.IsDeleted != true && w.ServiceDefinition.IsDeleted != true
&& !(w.LifecycleStatus == LifecycleStatus.Completed
|| (w.LifecycleStatus == null
&& CompletedLegacyStatuses.Contains(((w.LegacyStatus ?? w.Status) ?? "").Trim().ToLower())))
? (w.ServiceDefinition.Name ?? "").ToLower().Contains(pm) ? (w.ServiceDefinition.Name ?? "").ToLower().Contains(pm)
: ((w.ServiceDefinition != null : ((w.ServiceDefinition != null
&& (w.ServiceDefinition.Name ?? "").ToLower().Contains(pm)) && (w.ServiceDefinition.Name ?? "").ToLower().Contains(pm))

View file

@ -1,4 +1,5 @@
using Data.SeaHavenIndustries; using Data.SeaHavenIndustries;
using Data.SeaHavenIndustries.Enums;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SeaHaven.DataServices.Helpers; using SeaHaven.DataServices.Helpers;
@ -9,7 +10,7 @@ namespace SeaHavenIndustries.Tests;
public sealed class WorkOrderServiceRegistryFilterRelationalTests public sealed class WorkOrderServiceRegistryFilterRelationalTests
{ {
[Fact] [Fact]
public async Task ServiceDisplayAndFilter_UseCurrentActiveNameAndKeepHistoricalAndLegacyLabels() public async Task ServiceDisplayAndFilter_RespectCompletedSnapshotsAndKeepCurrentAliases()
{ {
await using var connection = new SqliteConnection("Data Source=:memory:;Foreign Keys=True"); await using var connection = new SqliteConnection("Data Source=:memory:;Foreign Keys=True");
await connection.OpenAsync(); await connection.OpenAsync();
@ -59,6 +60,22 @@ public sealed class WorkOrderServiceRegistryFilterRelationalTests
Id = 3, Id = 3,
Trade = "Legacy Cooling", Trade = "Legacy Cooling",
Problem = "Legacy Leak" Problem = "Legacy Leak"
},
new WorkOrder
{
Id = 4,
ServiceId = 10,
ServiceNameSnapshot = "Completed Archive Alpha",
Trade = "Completed Archive Alpha",
LifecycleStatus = LifecycleStatus.Completed
},
new WorkOrder
{
Id = 5,
ServiceId = 10,
ServiceNameSnapshot = "Completed Archive Beta",
Trade = "Completed Archive Beta",
Status = "Done"
}); });
await context.SaveChangesAsync(); await context.SaveChangesAsync();
@ -87,6 +104,18 @@ public sealed class WorkOrderServiceRegistryFilterRelationalTests
isUnscheduled: true); isUnscheduled: true);
var legacyDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(legacyRows), DateTime.UtcNow); var legacyDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(legacyRows), DateTime.UtcNow);
var completedRows = await WorkOrderBoardProjection.ProjectRowsAsync(
context,
context.workOrders.AsNoTracking().Where(w => w.Id == 4),
isUnscheduled: true);
var completedDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(completedRows), DateTime.UtcNow);
var legacyCompletedRows = await WorkOrderBoardProjection.ProjectRowsAsync(
context,
context.workOrders.AsNoTracking().Where(w => w.Id == 5),
isUnscheduled: true);
var legacyCompletedDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(legacyCompletedRows), DateTime.UtcNow);
var currentActiveNameMatches = await WorkOrderBoardQueryFilters var currentActiveNameMatches = await WorkOrderBoardQueryFilters
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Active Name" }) .ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Active Name" })
.Select(w => w.Id) .Select(w => w.Id)
@ -102,6 +131,22 @@ public sealed class WorkOrderServiceRegistryFilterRelationalTests
.Select(w => w.Id) .Select(w => w.Id)
.ToListAsync(); .ToListAsync();
var completedSnapshotMatches = await WorkOrderBoardQueryFilters
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Completed Archive Alpha" })
.Select(w => w.Id)
.ToListAsync();
var legacyCompletedSnapshotMatches = await WorkOrderBoardQueryFilters
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Completed Archive Beta" })
.Select(w => w.Id)
.ToListAsync();
var currentNameAliasMatches = await WorkOrderBoardQueryFilters
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Active Name" })
.Select(w => w.Id)
.OrderBy(id => id)
.ToListAsync();
var legacyTradeMatches = await WorkOrderBoardQueryFilters var legacyTradeMatches = await WorkOrderBoardQueryFilters
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Legacy Cooling" }) .ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Legacy Cooling" })
.Select(w => w.Id) .Select(w => w.Id)
@ -117,9 +162,14 @@ public sealed class WorkOrderServiceRegistryFilterRelationalTests
$"active-display={activeDisplay.Pm}", $"active-display={activeDisplay.Pm}",
$"inactive-display={inactiveDisplay.Pm}", $"inactive-display={inactiveDisplay.Pm}",
$"legacy-display={legacyDisplay.Pm}", $"legacy-display={legacyDisplay.Pm}",
$"completed-display={completedDisplay.Pm}",
$"legacy-completed-display={legacyCompletedDisplay.Pm}",
$"active-filter={string.Join(',', currentActiveNameMatches)}", $"active-filter={string.Join(',', currentActiveNameMatches)}",
$"inactive-snapshot-filter={string.Join(',', historicalInactiveNameMatches)}", $"inactive-snapshot-filter={string.Join(',', historicalInactiveNameMatches)}",
$"inactive-current-name-filter={string.Join(',', inactiveRegistryNameMatches)}", $"inactive-current-name-filter={string.Join(',', inactiveRegistryNameMatches)}",
$"completed-snapshot-filter={string.Join(',', completedSnapshotMatches)}",
$"legacy-completed-snapshot-filter={string.Join(',', legacyCompletedSnapshotMatches)}",
$"current-name-alias-filter={string.Join(',', currentNameAliasMatches)}",
$"legacy-trade-filter={string.Join(',', legacyTradeMatches)}", $"legacy-trade-filter={string.Join(',', legacyTradeMatches)}",
$"legacy-problem-filter={string.Join(',', legacyProblemMatches)}" $"legacy-problem-filter={string.Join(',', legacyProblemMatches)}"
}); });
@ -128,9 +178,14 @@ public sealed class WorkOrderServiceRegistryFilterRelationalTests
"active-display=Current Active Name", "active-display=Current Active Name",
"inactive-display=Historical Inactive Name", "inactive-display=Historical Inactive Name",
"legacy-display=Legacy Cooling", "legacy-display=Legacy Cooling",
"active-filter=1", "completed-display=Completed Archive Alpha",
"legacy-completed-display=Completed Archive Beta",
"active-filter=1,4,5",
"inactive-snapshot-filter=2", "inactive-snapshot-filter=2",
"inactive-current-name-filter=2", "inactive-current-name-filter=2",
"completed-snapshot-filter=4",
"legacy-completed-snapshot-filter=5",
"current-name-alias-filter=1,4,5",
"legacy-trade-filter=3", "legacy-trade-filter=3",
"legacy-problem-filter=3" "legacy-problem-filter=3"
}); });