mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
* feat(vendors): add directory filters and details API * fix(vendors): preserve omitted status * fix(vendors): align facet filtering * fix(vendors): address directory review findings
213 lines
7.2 KiB
C#
213 lines
7.2 KiB
C#
using Data.SeaHavenIndustries;
|
|
using FluentAssertions;
|
|
using Moq;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Implementation;
|
|
using SeaHaven.Services.Validation;
|
|
using Xunit;
|
|
|
|
namespace Api.SeaHavenIndustries.Tests;
|
|
|
|
public class VendorServiceTests
|
|
{
|
|
private static VendorService NewService(Mock<IVendorDataService> data) =>
|
|
new(data.Object, new CreateVendorValidation(), new UpdateVendorValidation());
|
|
|
|
[Fact]
|
|
public async Task CreateVendor_PersistsCompleteProfile()
|
|
{
|
|
var data = new Mock<IVendorDataService>();
|
|
Vendor? saved = null;
|
|
data.Setup(x => x.AddAsync(It.IsAny<Vendor>()))
|
|
.ReturnsAsync((Vendor vendor) => { saved = vendor; vendor.Id = 7; return vendor; });
|
|
|
|
var result = await NewService(data).CreateVendorAsync(new CreateVendorDTO
|
|
{
|
|
Name = "Gateway Plumbing",
|
|
ContactName = "Jordan Lee",
|
|
Email = "dispatch@gateway.example",
|
|
Phone = "555-0100",
|
|
CompanyPhone = "555-0199",
|
|
Address = "10 Lake St",
|
|
City = "Chicago",
|
|
State = "IL",
|
|
Zipcode = "60601",
|
|
TradeSpecialties = "Plumbing, Backflow",
|
|
GoogleMapsUrl = "https://maps.google.com/example",
|
|
Notes = "After-hours dispatch available",
|
|
IsActive = true
|
|
}, "42");
|
|
|
|
saved.Should().NotBeNull();
|
|
saved!.ContactName.Should().Be("Jordan Lee");
|
|
saved.TradeSpecialties.Should().Be("Plumbing, Backflow");
|
|
saved.CompanyPhone.Should().Be("555-0199");
|
|
saved.GoogleMapsUrl.Should().Be("https://maps.google.com/example");
|
|
saved.Notes.Should().Be("After-hours dispatch available");
|
|
saved.City.Should().Be("Chicago");
|
|
result.IsActive.Should().BeTrue();
|
|
result.ContactName.Should().Be("Jordan Lee");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateVendor_UpdatesProfileAndActiveState()
|
|
{
|
|
var existing = new Vendor { Id = 8, CompanyName = "Old", IsActive = true };
|
|
var data = new Mock<IVendorDataService>();
|
|
data.Setup(x => x.GetByIdAsync(8)).ReturnsAsync(existing);
|
|
data.Setup(x => x.UpdateAsync(existing)).Returns(Task.CompletedTask);
|
|
|
|
var result = await NewService(data).UpdateVendorAsync(8, new UpdateVendorDTO
|
|
{
|
|
Name = "New",
|
|
ContactName = "Casey",
|
|
TradeSpecialties = "HVAC",
|
|
IsActive = false
|
|
}, "42");
|
|
|
|
existing.CompanyName.Should().Be("New");
|
|
existing.ContactName.Should().Be("Casey");
|
|
existing.TradeSpecialties.Should().Be("HVAC");
|
|
existing.IsActive.Should().BeFalse();
|
|
existing.LastModifierUserId.Should().Be(42);
|
|
result.IsActive.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteVendor_DeactivatesWithoutDeletingHistory()
|
|
{
|
|
var existing = new Vendor { Id = 9, CompanyName = "Keep History", IsActive = true };
|
|
var data = new Mock<IVendorDataService>();
|
|
data.Setup(x => x.GetByIdAsync(9)).ReturnsAsync(existing);
|
|
data.Setup(x => x.UpdateAsync(existing)).Returns(Task.CompletedTask);
|
|
|
|
await NewService(data).DeleteVendorAsync(9, "42");
|
|
|
|
existing.IsActive.Should().BeFalse();
|
|
existing.IsDeleted.Should().NotBeTrue();
|
|
existing.DeletionTime.Should().BeNull();
|
|
existing.LastModificationTime.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetVendorsPaged_RequestsSelectedStatusAndMapsDirectoryFields()
|
|
{
|
|
var data = new Mock<IVendorDataService>();
|
|
data.Setup(x => x.GetPagedAsync(
|
|
1,
|
|
12,
|
|
"chicago",
|
|
false,
|
|
It.IsAny<IReadOnlyCollection<string>?>(),
|
|
It.IsAny<IReadOnlyCollection<string>?>(),
|
|
It.IsAny<IReadOnlyCollection<string>?>(),
|
|
It.IsAny<IReadOnlyCollection<string>?>()))
|
|
.ReturnsAsync((new[]
|
|
{
|
|
new Vendor
|
|
{
|
|
Id = 10,
|
|
CompanyName = "Inactive Vendor",
|
|
ContactName = "Taylor",
|
|
City = "Chicago",
|
|
State = "IL",
|
|
TradeSpecialties = "Electrical",
|
|
IsActive = false
|
|
}
|
|
}.AsEnumerable(), 1));
|
|
|
|
var result = await NewService(data).GetVendorsPagedAsync(1, 12, "chicago", false);
|
|
|
|
result.TotalCount.Should().Be(1);
|
|
result.Items.Single().Should().BeEquivalentTo(new
|
|
{
|
|
Id = 10,
|
|
Name = "Inactive Vendor",
|
|
ContactName = "Taylor",
|
|
City = "Chicago",
|
|
State = "IL",
|
|
TradeSpecialties = "Electrical",
|
|
IsActive = false
|
|
}, options => options.ExcludingMissingMembers());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetVendorById_CountsDistinctHistoricalWorkOrders()
|
|
{
|
|
var vendor = new Vendor
|
|
{
|
|
Id = 11,
|
|
CompanyName = "History Vendor",
|
|
Dispatches = new List<Dispatch>
|
|
{
|
|
new()
|
|
{
|
|
WorkOrderId = 100,
|
|
DispatchWorkOrders = new List<DispatchWorkOrder>
|
|
{
|
|
new() { WorkOrderId = 100 },
|
|
new() { WorkOrderId = 101 }
|
|
}
|
|
},
|
|
new() { WorkOrderId = 101 }
|
|
}
|
|
};
|
|
var data = new Mock<IVendorDataService>();
|
|
data.Setup(x => x.GetByIdWithDetailsAsync(11)).ReturnsAsync(vendor);
|
|
|
|
var result = await NewService(data).GetVendorByIdAsync(11);
|
|
|
|
result.Should().NotBeNull();
|
|
result!.TotalJobs.Should().Be(2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetVendorsPaged_ForwardsFacetFilters()
|
|
{
|
|
var companies = new[] { "Gateway Plumbing", "Roto-Rooter Dallas" };
|
|
var trades = new[] { "Backflow Preventers" };
|
|
var locations = new[] { "Dallas, TX" };
|
|
var jobBuckets = new[] { "100-149" };
|
|
var data = new Mock<IVendorDataService>();
|
|
data.Setup(x => x.GetPagedAsync(
|
|
1,
|
|
25,
|
|
"gateway",
|
|
true,
|
|
companies,
|
|
trades,
|
|
locations,
|
|
jobBuckets))
|
|
.ReturnsAsync((Enumerable.Empty<Vendor>(), 0));
|
|
|
|
await NewService(data).GetVendorsPagedAsync(
|
|
1,
|
|
25,
|
|
"gateway",
|
|
true,
|
|
companies,
|
|
trades,
|
|
locations,
|
|
jobBuckets);
|
|
|
|
data.VerifyAll();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateVendor_RequiresTechnicianNameAndHttpsMapUrl()
|
|
{
|
|
var validator = new CreateVendorValidation();
|
|
|
|
var result = validator.Validate(new CreateVendorDTO
|
|
{
|
|
Name = "Gateway Plumbing",
|
|
ContactName = "",
|
|
GoogleMapsUrl = "http://maps.google.com/gateway"
|
|
});
|
|
|
|
result.IsValid.Should().BeFalse();
|
|
result.Errors.Should().Contain(error => error.PropertyName == nameof(CreateVendorDTO.ContactName));
|
|
result.Errors.Should().Contain(error => error.PropertyName == nameof(CreateVendorDTO.GoogleMapsUrl));
|
|
}
|
|
}
|