diff --git a/Api.SeaHavenIndustries.Tests/VendorDataServiceTests.cs b/Api.SeaHavenIndustries.Tests/VendorDataServiceTests.cs index 650c911..a7d91f1 100644 --- a/Api.SeaHavenIndustries.Tests/VendorDataServiceTests.cs +++ b/Api.SeaHavenIndustries.Tests/VendorDataServiceTests.cs @@ -364,6 +364,114 @@ public class VendorDataServiceTests items.Should().Contain(i => i.ContactName == "No Company Tech" && i.VendorId != null); } + [Fact] + public async Task GetDirectoryPagedAsync_UsesCanonicalCompanyLocationAndEmailFallback() + { + await using var context = NewContext(); + var company = new VendorCompany + { + Name = "Canonical Co", + NormalizedName = "canonical co", + Email = "dispatch@canonical.example", + City = "Chicago", + State = "IL" + }; + context.VendorCompanies.Add(company); + context.Vendors.AddRange( + new Vendor + { + CompanyName = "Canonical Co", + ContactName = "Company Fallback", + Email = " ", + City = "Stale City", + State = "TX", + IsActive = true, + IsDeleted = false, + Company = company + }, + new Vendor + { + CompanyName = "Canonical Co", + ContactName = "Technician Email", + Email = "technician@canonical.example", + IsActive = true, + IsDeleted = false, + Company = company + }, + new Vendor + { + CompanyName = "Legacy Co", + ContactName = "Unlinked Technician", + Email = "legacy@example.com", + City = "Austin", + State = "TX", + 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 companyFallback = items.Single(i => i.ContactName == "Company Fallback"); + companyFallback.Email.Should().Be("dispatch@canonical.example"); + companyFallback.City.Should().Be("Chicago"); + companyFallback.State.Should().Be("IL"); + + var technicianEmail = items.Single(i => i.ContactName == "Technician Email"); + technicianEmail.Email.Should().Be("technician@canonical.example"); + technicianEmail.City.Should().Be("Chicago"); + technicianEmail.State.Should().Be("IL"); + + var legacy = items.Single(i => i.ContactName == "Unlinked Technician"); + legacy.Email.Should().Be("legacy@example.com"); + legacy.City.Should().Be("Austin"); + legacy.State.Should().Be("TX"); + } + + [Fact] + public async Task GetDirectoryPagedAsync_SearchAndLocationFilterUseCanonicalCompanyLocation() + { + await using var context = NewContext(); + var company = new VendorCompany + { + Name = "Searchable Co", + NormalizedName = "searchable co", + City = "Chicago", + State = null + }; + context.VendorCompanies.Add(company); + context.Vendors.Add(new Vendor + { + CompanyName = "Searchable Co", + ContactName = "Pat", + City = "Stale City", + State = "TX", + IsActive = true, + IsDeleted = false, + Company = company + }); + await context.SaveChangesAsync(); + + var service = new VendorDataService(context); + var search = await service.GetDirectoryPagedAsync(1, 50, search: "chicago", isActive: true); + var location = await service.GetDirectoryPagedAsync( + 1, + 50, + isActive: true, + locations: new[] { "Chicago" }); + + var searchRow = search.Items.Should().ContainSingle(i => i.ContactName == "Pat").Subject; + searchRow.City.Should().Be("Chicago"); + searchRow.State.Should().BeNull(); + + var locationRow = location.Items.Should().ContainSingle(i => i.ContactName == "Pat").Subject; + locationRow.City.Should().Be("Chicago"); + locationRow.State.Should().BeNull(); + } + [Theory] [InlineData("trade")] [InlineData("location")] diff --git a/SeaHaven.DataServices/Implementation/VendorDataService.cs b/SeaHaven.DataServices/Implementation/VendorDataService.cs index 01a5be6..dc09d71 100644 --- a/SeaHaven.DataServices/Implementation/VendorDataService.cs +++ b/SeaHaven.DataServices/Implementation/VendorDataService.cs @@ -191,13 +191,25 @@ namespace SeaHaven.DataServices.Implementation CompanyId = v.CompanyId ?? 0, CompanyName = v.CompanyName, ContactName = v.ContactName, - Email = v.Email, + Email = v.Email != null && v.Email.Trim() != "" + ? v.Email + : v.Company != null + ? v.Company.Email + : v.Email, Phone = v.Phone, CompanyPhone = v.CompanyPhone, PreferredContact = v.PreferredContact, Address = v.Address, - City = v.City, - State = v.State, + City = v.Company != null && + ((v.Company.City != null && v.Company.City.Trim() != "") || + (v.Company.State != null && v.Company.State.Trim() != "")) + ? v.Company.City + : v.City, + State = v.Company != null && + ((v.Company.City != null && v.Company.City.Trim() != "") || + (v.Company.State != null && v.Company.State.Trim() != "")) + ? v.Company.State + : v.State, Zip = v.Zip, TradeSpecialties = v.TradeSpecialties, GoogleMapsUrl = v.GoogleMapsUrl, diff --git a/infra/cdk/package-lock.json b/infra/cdk/package-lock.json index 0ffb1ce..f09bb8f 100644 --- a/infra/cdk/package-lock.json +++ b/infra/cdk/package-lock.json @@ -8,12 +8,12 @@ "name": "shoc-backend-cdk", "version": "0.1.0", "dependencies": { - "aws-cdk-lib": "2.265.0", + "aws-cdk-lib": "2.266.0", "constructs": "10.8.1" }, "devDependencies": { "@types/node": "26.2.0", - "aws-cdk": "2.1137.0", + "aws-cdk": "2.1138.0", "typescript": "7.0.2" }, "engines": { @@ -419,9 +419,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.1137.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1137.0.tgz", - "integrity": "sha512-SRy2df/5cqGvq8ncph1m93rWEh3RGbvP6uwElw+W0x135vZDzTpfbuq2L8oAHwK2yDt3RNS5sb7Phwb7xqQP2g==", + "version": "2.1138.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1138.0.tgz", + "integrity": "sha512-gZ5F8rmh+qc7ZNWsbaXYoV+p7jSYynRRg70s7FAn3VmzRaSkTE31ijpQHYroxCbDEtKSzgN63ORR/WuZmvXAwA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -432,9 +432,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.265.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.265.0.tgz", - "integrity": "sha512-Ur96d/ZW+gqAW4XtqKQp//D9O/jQvyRoXhAqoHGybpV03qjckGIQcLcGkLV68+jv03TX/rOXHCsa2IEFcCXa4w==", + "version": "2.266.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.266.0.tgz", + "integrity": "sha512-sBQU42pEc9ud3yeVU2En2euQRUhCg63eaJIPEVpBtE5aPhJjN3d9MkzQ9eYGLVXP3fnohUE54BiVOdUrkEDUbg==", "bundleDependencies": [ "@aws/cloudformation-validate", "@balena/dockerignore", diff --git a/infra/cdk/package.json b/infra/cdk/package.json index c79b316..7e07795 100644 --- a/infra/cdk/package.json +++ b/infra/cdk/package.json @@ -13,12 +13,12 @@ "deploy": "npm run build && cdk deploy" }, "dependencies": { - "aws-cdk-lib": "2.265.0", + "aws-cdk-lib": "2.266.0", "constructs": "10.8.1" }, "devDependencies": { "@types/node": "26.2.0", - "aws-cdk": "2.1137.0", + "aws-cdk": "2.1138.0", "typescript": "7.0.2" } }