mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
fix(dashboard): resolve region zones from full state names (SH-348)
Locations store State as either a two-letter postal code or a full state name (the location list filter expands codes to both forms via UsStateCodes.ExpandStorageValues, and dev fixtures carry State = "indiana"). DashboardRegions.Resolve only matched the two-letter key, so every location stored as a full name fell into Unmapped/Other and the East/Central/West/ California bars undercounted. Normalise the stored value through a new UsStateCodes.ToCode, which accepts a code or a full name and returns the canonical postal code, before the zone lookup. Extend the region test with full-name storage forms and add an invariant asserting every US state and its full-name form resolves to a canonical bucket.
This commit is contained in:
parent
d4afcced87
commit
22308f21f6
3 changed files with 53 additions and 4 deletions
|
|
@ -309,11 +309,17 @@ public class DashboardServiceTests
|
|||
ctx.Locations.AddRange(
|
||||
new Locations { Id = 1, State = "NY" },
|
||||
new Locations { Id = 2, State = "ca" },
|
||||
new Locations { Id = 3, State = "XX" });
|
||||
new Locations { Id = 3, State = "XX" },
|
||||
new Locations { Id = 4, State = "indiana" },
|
||||
new Locations { Id = 5, State = "NEW YORK" },
|
||||
new Locations { Id = 6, State = "California" });
|
||||
ctx.workOrders.AddRange(
|
||||
new WorkOrder { AccountId = 1, LocationId = 1 },
|
||||
new WorkOrder { AccountId = 1, LocationId = 2 },
|
||||
new WorkOrder { AccountId = 1, LocationId = 3 },
|
||||
new WorkOrder { AccountId = 1, LocationId = 4 },
|
||||
new WorkOrder { AccountId = 1, LocationId = 5 },
|
||||
new WorkOrder { AccountId = 1, LocationId = 6 },
|
||||
new WorkOrder { AccountId = 1, LocationId = null });
|
||||
await ctx.SaveChangesAsync();
|
||||
|
||||
|
|
@ -322,6 +328,27 @@ public class DashboardServiceTests
|
|||
|
||||
result.Items.Select(row => row.Region).Should().Equal(
|
||||
"East", "Central", "West", "California", "Unmapped/Other");
|
||||
result.Items.Select(row => row.WorkOrderCount).Should().Equal(1, 0, 0, 1, 2);
|
||||
// NY + "NEW YORK" -> East; "indiana" -> Central; "ca" + "California" -> California;
|
||||
// "XX" + unassigned location -> Unmapped/Other. Full-name storage forms must not
|
||||
// fall through to Unmapped/Other (SH-348 review).
|
||||
result.Items.Select(row => row.WorkOrderCount).Should().Equal(2, 1, 0, 2, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Resolve_MapsEveryUsStateAndItsFullNameToACanonicalBucket()
|
||||
{
|
||||
foreach (var code in UsStateCodes.All)
|
||||
{
|
||||
var byCode = DashboardRegions.Resolve(code);
|
||||
byCode.Should().NotBe(
|
||||
"Unmapped/Other",
|
||||
$"state code {code} must belong to a canonical region");
|
||||
|
||||
var fullName = UsStateCodes.ExpandStorageValues(new[] { code })
|
||||
.First(value => value != code);
|
||||
DashboardRegions.Resolve(fullName).Should().Be(
|
||||
byCode,
|
||||
$"the full-name storage form of {code} must resolve to the same region as the code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ public static class DashboardRegions
|
|||
|
||||
public static string Resolve(string? state)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(state))
|
||||
var code = UsStateCodes.ToCode(state);
|
||||
if (code is null)
|
||||
return "Unmapped/Other";
|
||||
|
||||
return StateToRegion.TryGetValue(state.Trim().ToUpperInvariant(), out var region)
|
||||
return StateToRegion.TryGetValue(code, out var region)
|
||||
? region
|
||||
: "Unmapped/Other";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,29 @@ namespace SeaHaven.Services.Helpers
|
|||
["WY"] = "WYOMING"
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyDictionary<string, string> CodesByName =
|
||||
Names.ToDictionary(pair => pair.Value, pair => pair.Key, StringComparer.Ordinal);
|
||||
|
||||
public static IReadOnlySet<string> All { get; } = new HashSet<string>(Names.Keys, StringComparer.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// Normalises a stored state value to its two-letter postal code. Accepts either a
|
||||
/// postal code ("IN") or a full state name ("Indiana"), case-insensitively, matching
|
||||
/// the storage forms produced by <see cref="ExpandStorageValues"/>. Returns null when
|
||||
/// the value is blank or is not a recognised US state.
|
||||
/// </summary>
|
||||
public static string? ToCode(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return null;
|
||||
|
||||
var normalized = value.Trim().ToUpperInvariant();
|
||||
if (All.Contains(normalized))
|
||||
return normalized;
|
||||
|
||||
return CodesByName.TryGetValue(normalized, out var code) ? code : null;
|
||||
}
|
||||
|
||||
public static IReadOnlyCollection<string> ExpandStorageValues(IEnumerable<string> codes)
|
||||
{
|
||||
return codes
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue