using FluentAssertions; using Moq; using SeaHaven.DataServices.Dto; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; using SeaHaven.Services.Validation; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class DispatchServiceTests { private static DispatchService NewService(Mock data) => new(data.Object, new CreateDispatchValidation(), new UpdateDispatchValidation()); [Fact] public async Task GetDispatchListAsync_MapsDataReadModelToServiceDtoPreservingFields() { var data = new Mock(); var source = new DispatchListResult { Total = 1, Page = 2, PageSize = 25, Items = new List { new() { Id = 7, DispatchNumber = "DISP-7", PONumber = "PO-1", NTEAmount = 200m, Status = "Pending", VendorId = 9, VendorName = "Acme", WorkOrderId = 3, PrimaryWOInternalNumber = "WO-3", PrimaryWOTitle = "Fix AC", LocationName = "Site A", WorkOrderCount = 2, PendingUpliftCount = 1 } } }; data.Setup(d => d.GetListAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(source); var result = await NewService(data).GetDispatchListAsync("a", "Pending", 9, null, null, "ponumber", "asc", 2, 25, CancellationToken.None); result.Should().BeOfType(); result.Total.Should().Be(1); result.Page.Should().Be(2); result.PageSize.Should().Be(25); var row = result.Items.Single(); row.Id.Should().Be(7); row.DispatchNumber.Should().Be("DISP-7"); row.PONumber.Should().Be("PO-1"); row.NTEAmount.Should().Be(200m); row.Status.Should().Be("Pending"); row.VendorId.Should().Be(9); row.VendorName.Should().Be("Acme"); row.WorkOrderId.Should().Be(3); row.PrimaryWOInternalNumber.Should().Be("WO-3"); row.PrimaryWOTitle.Should().Be("Fix AC"); row.LocationName.Should().Be("Site A"); row.WorkOrderCount.Should().Be(2); row.PendingUpliftCount.Should().Be(1); } [Fact] public async Task GetDispatchDetailAsync_MapsNestedCollectionsPreservingShape() { var data = new Mock(); var detail = new DispatchDetailDTO { Id = 42, DispatchNumber = "DISP-42", PONumber = "PO-9", NTEAmount = 500m, Status = "Dispatched", Description = "desc", WorkOrderId = 11, EmailSent = true, Vendor = new DispatchDetailVendorDTO { Id = 1, CompanyName = "VendorCo", Email = "v@x.com" }, PrimaryLocation = new DispatchPrimaryLocationDTO { Id = 5, Name = "Loc", City = "Austin" }, WorkOrders = new List { new() { WorkOrderId = 11, Title = "T", Priority = "High" } }, Checklist = new List { new() { Id = 1, ItemText = "Check", IsCompleted = true, SortOrder = 1 } }, Signoffs = new List { new() { Id = 1, SignoffType = "Vendor", Name = "J" } }, Comments = new List { new() { Id = 1, Commenttext = "Hi", UserName = "Sara" } }, UpliftRequests = new List { new() { Id = 1, RequestedNTE = 600m, CurrentNTE = 500m, Delta = 100m, Status = "Pending" } }, AuditLog = new List { new() { Id = 1, Action = "Updated", FieldName = "DISP-42:Status" } } }; data.Setup(d => d.GetDetailAsync(42, It.IsAny())).ReturnsAsync(detail); data.Setup(d => d.GetDetailAsync(999, It.IsAny())).ReturnsAsync((DispatchDetailDTO?)null); var service = NewService(data); var found = await service.GetDispatchDetailAsync(42, CancellationToken.None); var missing = await service.GetDispatchDetailAsync(999, CancellationToken.None); missing.Should().BeNull(); found.Should().BeOfType(); found!.Id.Should().Be(42); found.DispatchNumber.Should().Be("DISP-42"); found.EmailSent.Should().BeTrue(); found.Vendor!.CompanyName.Should().Be("VendorCo"); found.PrimaryLocation!.Name.Should().Be("Loc"); found.WorkOrders.Single().Title.Should().Be("T"); found.Checklist.Single().IsCompleted.Should().BeTrue(); found.Signoffs.Single().Name.Should().Be("J"); found.Comments.Single().UserName.Should().Be("Sara"); found.UpliftRequests.Single().Delta.Should().Be(100m); found.AuditLog.Single().Action.Should().Be("Updated"); } }