mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 08:23:12 +00:00
567 lines
23 KiB
C#
567 lines
23 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using FluentAssertions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using SeaHaven.DataServices.Implementation;
|
|
using SeaHaven.DataServices.Models;
|
|
using Xunit;
|
|
|
|
namespace Api.SeaHavenIndustries.Tests;
|
|
|
|
public class VendorDataServiceTests
|
|
{
|
|
private static ApplicationDbContext NewContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
|
.Options;
|
|
return new ApplicationDbContext(options);
|
|
}
|
|
|
|
private static ApplicationDbContext NewSqlServerContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
|
.UseSqlServer("Server=(local);Database=TranslationOnly;Trusted_Connection=True;TrustServerCertificate=True")
|
|
.Options;
|
|
return new ApplicationDbContext(options);
|
|
}
|
|
|
|
private static Vendor VendorWithJobs(
|
|
string company,
|
|
string city,
|
|
string state,
|
|
string trades,
|
|
int jobCount,
|
|
bool isActive = true)
|
|
{
|
|
return new Vendor
|
|
{
|
|
CompanyName = company,
|
|
ContactName = $"{company} Technician",
|
|
City = city,
|
|
State = state,
|
|
TradeSpecialties = trades,
|
|
IsActive = isActive,
|
|
IsDeleted = false,
|
|
Dispatches = Enumerable.Range(1, jobCount)
|
|
.Select(workOrderId => new Dispatch { WorkOrderId = workOrderId })
|
|
.ToList()
|
|
};
|
|
}
|
|
|
|
private static async Task SeedBoundaryVendors(ApplicationDbContext context)
|
|
{
|
|
context.Vendors.AddRange(
|
|
VendorWithJobs("Under Co", "Chicago", "IL", "Plumbing, HVAC", 49),
|
|
VendorWithJobs("Fifty Co", "Chicago", "IL", "Electrical", 50),
|
|
VendorWithJobs("Hundred Co", "Dallas", "TX", "Plumbing", 100),
|
|
VendorWithJobs("One Fifty Co", "Dallas", "TX", "Roofing", 150));
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("under-50", "Under Co")]
|
|
[InlineData("50-99", "Fifty Co")]
|
|
[InlineData("100-149", "Hundred Co")]
|
|
[InlineData("150-plus", "One Fifty Co")]
|
|
public async Task GetPagedAsync_AppliesExactJobBucketBoundaries(
|
|
string bucket,
|
|
string expectedCompany)
|
|
{
|
|
await using var context = NewContext();
|
|
await SeedBoundaryVendors(context);
|
|
var service = new VendorDataService(context);
|
|
|
|
var (items, totalCount) = await service.GetPagedAsync(
|
|
1,
|
|
12,
|
|
isActive: true,
|
|
jobBuckets: new[] { bucket });
|
|
|
|
totalCount.Should().Be(1);
|
|
items.Single().CompanyName.Should().Be(expectedCompany);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_UsesOrWithinFacetAndAndAcrossFacets()
|
|
{
|
|
await using var context = NewContext();
|
|
await SeedBoundaryVendors(context);
|
|
var service = new VendorDataService(context);
|
|
|
|
var (items, totalCount) = await service.GetPagedAsync(
|
|
1,
|
|
12,
|
|
isActive: true,
|
|
companies: new[] { "Under Co", "Hundred Co" },
|
|
trades: new[] { "HVAC", "Plumbing" },
|
|
locations: new[] { "Chicago, IL" },
|
|
jobBuckets: new[] { "under-50", "100-149" });
|
|
|
|
totalCount.Should().Be(1);
|
|
items.Single().CompanyName.Should().Be("Under Co");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_StatusAndCountAreIndependentOfInactiveHistory()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
VendorWithJobs("Active Co", "Chicago", "IL", "Plumbing", 1),
|
|
VendorWithJobs("Inactive Co", "Chicago", "IL", "Plumbing", 1, false));
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var active = await service.GetPagedAsync(1, 1, isActive: true);
|
|
var inactive = await service.GetPagedAsync(1, 1, isActive: false);
|
|
|
|
active.TotalCount.Should().Be(1);
|
|
inactive.TotalCount.Should().Be(1);
|
|
active.Items.Single().CompanyName.Should().Be("Active Co");
|
|
inactive.Items.Single().CompanyName.Should().Be("Inactive Co");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_LocationFacetMatchesCityStateAndFullLabels()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
new Vendor { CompanyName = "CityOnly", City = "Austin", State = null, TradeSpecialties = "Plumbing", IsActive = true, IsDeleted = false },
|
|
new Vendor { CompanyName = "StateOnly", City = null, State = "TX", TradeSpecialties = "Plumbing", IsActive = true, IsDeleted = false },
|
|
new Vendor { CompanyName = "FullLoc", City = "Austin", State = "TX", TradeSpecialties = "Plumbing", IsActive = true, IsDeleted = false });
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var cityOnly = await service.GetPagedAsync(1, 12, isActive: true, locations: new[] { "Austin" });
|
|
cityOnly.TotalCount.Should().Be(1);
|
|
cityOnly.Items.Single().CompanyName.Should().Be("CityOnly");
|
|
|
|
var stateOnly = await service.GetPagedAsync(1, 12, isActive: true, locations: new[] { "TX" });
|
|
stateOnly.TotalCount.Should().Be(1);
|
|
stateOnly.Items.Single().CompanyName.Should().Be("StateOnly");
|
|
|
|
var full = await service.GetPagedAsync(1, 12, isActive: true, locations: new[] { "Austin, TX" });
|
|
full.TotalCount.Should().Be(1);
|
|
full.Items.Single().CompanyName.Should().Be("FullLoc");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_TradeFacetMatchesExactTokensNotSubstrings()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
new Vendor { CompanyName = "HvacOnly", City = "Chicago", State = "IL", TradeSpecialties = "HVAC", IsActive = true, IsDeleted = false },
|
|
new Vendor { CompanyName = "HvacControls", City = "Chicago", State = "IL", TradeSpecialties = "HVAC Controls", IsActive = true, IsDeleted = false },
|
|
new Vendor { CompanyName = "PlumbingCo", City = "Chicago", State = "IL", TradeSpecialties = "Plumbing", IsActive = true, IsDeleted = false });
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var hvac = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "HVAC" });
|
|
hvac.TotalCount.Should().Be(1);
|
|
hvac.Items.Single().CompanyName.Should().Be("HvacOnly");
|
|
|
|
var hvacControls = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "HVAC Controls" });
|
|
hvacControls.TotalCount.Should().Be(1);
|
|
hvacControls.Items.Single().CompanyName.Should().Be("HvacControls");
|
|
|
|
var plumb = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "Plumb" });
|
|
plumb.TotalCount.Should().Be(0);
|
|
plumb.Items.Should().BeEmpty();
|
|
|
|
var plumbing = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "Plumbing" });
|
|
plumbing.TotalCount.Should().Be(1);
|
|
plumbing.Items.Single().CompanyName.Should().Be("PlumbingCo");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_TradeFacetMatchesTokenInCommaDelimitedList()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
new Vendor { CompanyName = "Multi", City = "Chicago", State = "IL", TradeSpecialties = "Plumbing, HVAC", IsActive = true, IsDeleted = false },
|
|
new Vendor { CompanyName = "Middle", City = "Chicago", State = "IL", TradeSpecialties = "Electrical, Plumbing, Roofing", IsActive = true, IsDeleted = false });
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var plumbing = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "Plumbing" });
|
|
plumbing.TotalCount.Should().Be(2);
|
|
plumbing.Items.Select(v => v.CompanyName).Should().BeEquivalentTo("Multi", "Middle");
|
|
|
|
var roofing = await service.GetPagedAsync(1, 12, isActive: true, trades: new[] { "Roofing" });
|
|
roofing.TotalCount.Should().Be(1);
|
|
roofing.Items.Single().CompanyName.Should().Be("Middle");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_CountsDistinctDirectAndLinkedWorkOrders()
|
|
{
|
|
await using var context = NewContext();
|
|
var vendor = new Vendor
|
|
{
|
|
CompanyName = "History Co",
|
|
IsActive = true,
|
|
IsDeleted = false,
|
|
Dispatches = new List<Dispatch>
|
|
{
|
|
new()
|
|
{
|
|
WorkOrderId = 100,
|
|
DispatchWorkOrders = new List<DispatchWorkOrder>
|
|
{
|
|
new() { WorkOrderId = 100 },
|
|
new() { WorkOrderId = 101 }
|
|
}
|
|
},
|
|
new() { WorkOrderId = 101 }
|
|
}
|
|
};
|
|
context.Vendors.Add(vendor);
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
var result = await service.GetPagedAsync(1, 12, isActive: true);
|
|
|
|
result.Items.Single().TotalJobs.Should().Be(2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetByIdAsync_ReturnsTrackedVendorWithoutLoadingDispatchGraph()
|
|
{
|
|
await using var context = NewContext();
|
|
var vendor = VendorWithJobs("Lean Co", "Chicago", "IL", "Plumbing", 2);
|
|
context.Vendors.Add(vendor);
|
|
await context.SaveChangesAsync();
|
|
context.ChangeTracker.Clear();
|
|
|
|
var service = new VendorDataService(context);
|
|
var result = await service.GetByIdAsync(vendor.Id);
|
|
|
|
result.Should().NotBeNull();
|
|
context.Entry(result!).State.Should().Be(EntityState.Unchanged);
|
|
context.Entry(result!).Collection(nameof(Vendor.Dispatches)).IsLoaded.Should().BeFalse();
|
|
result!.Dispatches.Should().BeNull();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("trade")]
|
|
[InlineData("location")]
|
|
[InlineData("job-bucket")]
|
|
public void BuildDirectoryQuery_TranslatesRepresentativeFiltersForSqlServer(string filter)
|
|
{
|
|
using var context = NewSqlServerContext();
|
|
var service = new VendorDataService(context);
|
|
|
|
var query = filter switch
|
|
{
|
|
"trade" => service.BuildDirectoryQuery(trades: new[] { "Plumbing" }),
|
|
"location" => service.BuildDirectoryQuery(locations: new[] { "Chicago, IL" }),
|
|
_ => service.BuildDirectoryQuery(jobBuckets: new[] { "50-99" })
|
|
};
|
|
|
|
var sql = query.ToQueryString();
|
|
|
|
sql.Should().Contain("SELECT");
|
|
if (filter == "trade")
|
|
sql.Should().Contain("TradeSpecialties");
|
|
if (filter == "location")
|
|
sql.Should().Contain("City");
|
|
if (filter == "job-bucket")
|
|
sql.Should().Contain("UNION");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildLinkedWorkOrdersQuery_TranslatesForSqlServerWithoutClientEvaluation()
|
|
{
|
|
using var context = NewSqlServerContext();
|
|
var service = new VendorDataService(context);
|
|
|
|
var sql = service.BuildLinkedWorkOrdersQuery(60).ToQueryString();
|
|
|
|
sql.Should().Contain("SELECT");
|
|
sql.Should().Contain("Dispatches");
|
|
sql.Should().Contain("DispatchWorkOrders");
|
|
sql.Should().Contain("workOrders");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetLinkedWorkOrdersAsync_DedupsToOneRecordPerWorkOrderAcrossDirectAndMultiLinks()
|
|
{
|
|
await using var context = NewContext();
|
|
var vendor = new Vendor { Id = 60, CompanyName = "Linked Co", IsActive = true };
|
|
context.Vendors.Add(vendor);
|
|
context.workOrders.AddRange(
|
|
new WorkOrder
|
|
{
|
|
Id = 701,
|
|
WorkerOrderNumber = "WO-701",
|
|
WorkerOrderTitle = "Direct And Multi",
|
|
Status = "Scheduled",
|
|
LifecycleStatus = LifecycleStatus.Scheduled
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 702,
|
|
WorkerOrderNumber = "WO-702",
|
|
WorkerOrderTitle = "Multi Only",
|
|
Status = "Scheduled",
|
|
LifecycleStatus = LifecycleStatus.Scheduled
|
|
});
|
|
|
|
var directDispatch = new Dispatch { Id = 7001, VendorId = 60, WorkOrderId = 701, Vendor = vendor };
|
|
var multiDispatch = new Dispatch { Id = 7002, VendorId = 60, WorkOrderId = null, Vendor = vendor };
|
|
context.Dispatches.AddRange(directDispatch, multiDispatch);
|
|
context.DispatchWorkOrders.AddRange(
|
|
new DispatchWorkOrder { DispatchId = 7002, Dispatch = multiDispatch, WorkOrderId = 702 },
|
|
new DispatchWorkOrder { DispatchId = 7002, Dispatch = multiDispatch, WorkOrderId = 701 });
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
var result = await service.GetLinkedWorkOrdersAsync(60);
|
|
|
|
result.Should().HaveCount(2);
|
|
result.Select(x => x.WorkOrderId).Should().BeEquivalentTo(new[] { 701, 702 });
|
|
result.Select(x => x.WorkOrderId).Should().OnlyHaveUniqueItems();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetDirectoryPagedAsync_IncludesCompanyOnlyRowsAndPreservesTechnicianRows()
|
|
{
|
|
await using var context = NewContext();
|
|
var soloCompany = new VendorCompany { Name = "Solo Co", NormalizedName = "solo co", Notes = "company notes" };
|
|
var techCompany = new VendorCompany { Name = "Tech Co", NormalizedName = "tech co" };
|
|
context.VendorCompanies.AddRange(soloCompany, techCompany);
|
|
context.Vendors.AddRange(
|
|
new Vendor
|
|
{
|
|
CompanyName = "Tech Co",
|
|
ContactName = "Pat",
|
|
City = "Austin",
|
|
State = "TX",
|
|
IsActive = true,
|
|
IsDeleted = false,
|
|
Company = techCompany
|
|
},
|
|
new Vendor
|
|
{
|
|
CompanyName = "Other",
|
|
ContactName = "No Company Tech",
|
|
IsActive = true,
|
|
IsDeleted = false,
|
|
CompanyId = null
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
var (items, totalCount) = await service.GetDirectoryPagedAsync(1, 50, isActive: true);
|
|
|
|
totalCount.Should().Be(3);
|
|
var companyOnly = items.Single(i => i.CompanyName == "Solo Co");
|
|
companyOnly.VendorId.Should().BeNull();
|
|
companyOnly.CompanyId.Should().Be(soloCompany.Id);
|
|
companyOnly.Notes.Should().Be("company notes");
|
|
|
|
items.Should().Contain(i => i.ContactName == "Pat" && i.VendorId != null && i.CompanyId == techCompany.Id);
|
|
items.Should().Contain(i => i.ContactName == "No Company Tech" && i.VendorId != null);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("trade")]
|
|
[InlineData("location")]
|
|
[InlineData("job-bucket")]
|
|
public void BuildDirectoryUnionQuery_TranslatesToSqlServerUnion(string filter)
|
|
{
|
|
using var context = NewSqlServerContext();
|
|
var service = new VendorDataService(context);
|
|
|
|
var query = filter switch
|
|
{
|
|
"trade" => service.BuildDirectoryUnionQuery(trades: new[] { "Plumbing" }),
|
|
"location" => service.BuildDirectoryUnionQuery(locations: new[] { "Chicago, IL" }),
|
|
_ => service.BuildDirectoryUnionQuery(jobBuckets: new[] { "under-50" })
|
|
};
|
|
|
|
var sql = query.ToQueryString();
|
|
|
|
sql.Should().Contain("SELECT");
|
|
sql.Should().Contain("UNION");
|
|
if (filter == "trade")
|
|
sql.Should().Contain("TradeSpecialties");
|
|
if (filter == "location")
|
|
sql.Should().Contain("City");
|
|
if (filter == "job-bucket")
|
|
sql.Should().Contain("TotalJobs");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetCompaniesForFacetsAsync_IncludesZeroTechnicianCompanyForActiveAndNullStatus()
|
|
{
|
|
await using var context = NewContext();
|
|
var rosterService = new VendorCompanyRosterDataService(context);
|
|
await rosterService.CreateRosterAsync(new VendorCompanyRosterWriteModel
|
|
{
|
|
Name = "Solo Co",
|
|
Email = "solo@example.com",
|
|
ActorUserId = "42",
|
|
Technicians = new List<RosterTechnicianWriteModel>()
|
|
}, CancellationToken.None);
|
|
|
|
var techCompany = new VendorCompany { Name = "Tech Co", NormalizedName = "tech co" };
|
|
context.VendorCompanies.Add(techCompany);
|
|
context.Vendors.Add(new Vendor
|
|
{
|
|
CompanyName = "Tech Co",
|
|
ContactName = "Pat",
|
|
IsActive = true,
|
|
IsDeleted = false,
|
|
Company = techCompany
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
|
|
var active = await service.GetCompaniesForFacetsAsync(true, CancellationToken.None);
|
|
active.Select(c => c.Name).Should().BeEquivalentTo(new[] { "Solo Co", "Tech Co" });
|
|
|
|
var noStatus = await service.GetCompaniesForFacetsAsync(null, CancellationToken.None);
|
|
noStatus.Select(c => c.Name).Should().BeEquivalentTo(new[] { "Solo Co", "Tech Co" });
|
|
|
|
var inactive = await service.GetCompaniesForFacetsAsync(false, CancellationToken.None);
|
|
inactive.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetCompaniesForFacetsAsync_InactiveStatusReturnsOnlyCompaniesWithInactiveTechnicians()
|
|
{
|
|
await using var context = NewContext();
|
|
var activeOnlyCo = new VendorCompany { Name = "Active Only Co", NormalizedName = "active only co" };
|
|
var inactiveOnlyCo = new VendorCompany { Name = "Inactive Only Co", NormalizedName = "inactive only co" };
|
|
var mixedCo = new VendorCompany { Name = "Mixed Co", NormalizedName = "mixed co" };
|
|
context.VendorCompanies.AddRange(activeOnlyCo, inactiveOnlyCo, mixedCo);
|
|
context.Vendors.AddRange(
|
|
new Vendor { CompanyName = "Active Only Co", IsActive = true, IsDeleted = false, Company = activeOnlyCo },
|
|
new Vendor { CompanyName = "Inactive Only Co", IsActive = false, IsDeleted = false, Company = inactiveOnlyCo },
|
|
new Vendor { CompanyName = "Mixed Co", IsActive = true, IsDeleted = false, Company = mixedCo },
|
|
new Vendor { CompanyName = "Mixed Co", IsActive = false, IsDeleted = false, Company = mixedCo });
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
|
|
var inactive = await service.GetCompaniesForFacetsAsync(false, CancellationToken.None);
|
|
inactive.Select(c => c.Name).Should().BeEquivalentTo(new[] { "Inactive Only Co", "Mixed Co" });
|
|
|
|
var active = await service.GetCompaniesForFacetsAsync(true, CancellationToken.None);
|
|
active.Select(c => c.Name).Should().BeEquivalentTo(new[] { "Active Only Co", "Mixed Co" });
|
|
|
|
var noStatus = await service.GetCompaniesForFacetsAsync(null, CancellationToken.None);
|
|
noStatus.Select(c => c.Name).Should().BeEquivalentTo(new[] { "Active Only Co", "Inactive Only Co", "Mixed Co" });
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetCompaniesForFacetsAsync_TreatsCompanyWithOnlyDeletedTechniciansAsZeroTechnician()
|
|
{
|
|
await using var context = NewContext();
|
|
var company = new VendorCompany { Name = "Ghost Co", NormalizedName = "ghost co" };
|
|
context.VendorCompanies.Add(company);
|
|
context.Vendors.Add(new Vendor
|
|
{
|
|
CompanyName = "Ghost Co",
|
|
IsActive = true,
|
|
IsDeleted = true,
|
|
Company = company
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = new VendorDataService(context);
|
|
|
|
var active = await service.GetCompaniesForFacetsAsync(true, CancellationToken.None);
|
|
active.Single().Name.Should().Be("Ghost Co");
|
|
|
|
var inactive = await service.GetCompaniesForFacetsAsync(false, CancellationToken.None);
|
|
inactive.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetActiveTradesAsync_ReturnsEmptyOnEmptyDatabase()
|
|
{
|
|
await using var context = NewContext();
|
|
var service = new VendorDataService(context);
|
|
|
|
var trades = await service.GetActiveTradesAsync(CancellationToken.None);
|
|
|
|
trades.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetActiveTradesAsync_FiltersInactiveAndOrdersBySortOrderThenName()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Trades.AddRange(
|
|
new Trade { Name = "Janitorial", NormalizedName = "janitorial", SortOrder = 7 },
|
|
new Trade { Name = "Plumbing", NormalizedName = "plumbing", SortOrder = 1 },
|
|
new Trade { Name = "Electrical", NormalizedName = "electrical", SortOrder = 2 },
|
|
new Trade { Name = "Retired Trade", NormalizedName = "retired trade", SortOrder = 0, IsActive = false });
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var trades = await service.GetActiveTradesAsync(CancellationToken.None);
|
|
|
|
trades.Select(t => t.Name).Should().Equal("Plumbing", "Electrical", "Janitorial");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPagedAsync_TradeFilterStillMatchesLegacyFreeTextValues()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
VendorWithJobs("Legacy Co", "Chicago", "IL", "Backflow Testing, Plumbing", 3),
|
|
VendorWithJobs("Canonical Co", "Chicago", "IL", "Plumbing", 5));
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
// SH-249: stored TradeSpecialties stay free text; filtering by a legacy
|
|
// value that is not in the canonical catalog must keep matching.
|
|
var (items, totalCount) = await service.GetPagedAsync(
|
|
1,
|
|
12,
|
|
isActive: true,
|
|
trades: new[] { "Backflow Testing" });
|
|
|
|
totalCount.Should().Be(1);
|
|
items.Single().CompanyName.Should().Be("Legacy Co");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetDirectoryPagedAsync_TradeFilterStillMatchesLegacyFreeTextValues()
|
|
{
|
|
await using var context = NewContext();
|
|
context.Vendors.AddRange(
|
|
VendorWithJobs("Legacy Co", "Chicago", "IL", "Backflow Testing, Plumbing", 3),
|
|
VendorWithJobs("Canonical Co", "Chicago", "IL", "Plumbing", 5));
|
|
await context.SaveChangesAsync();
|
|
var service = new VendorDataService(context);
|
|
|
|
var (items, totalCount) = await service.GetDirectoryPagedAsync(
|
|
1,
|
|
12,
|
|
isActive: true,
|
|
trades: new[] { "Backflow Testing" });
|
|
|
|
totalCount.Should().Be(1);
|
|
items.Single().CompanyName.Should().Be("Legacy Co");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
[InlineData(null)]
|
|
public void BuildCompaniesForFacetsQuery_TranslatesToSqlServerWithoutClientEvaluation(bool? isActive)
|
|
{
|
|
using var context = NewSqlServerContext();
|
|
var service = new VendorDataService(context);
|
|
|
|
var sql = service.BuildCompaniesForFacetsQuery(isActive).ToQueryString();
|
|
|
|
sql.Should().Contain("SELECT");
|
|
sql.Should().Contain("VendorCompanies");
|
|
}
|
|
}
|