From deeb29b512529f241bc79f085a428f59f28ca4ee Mon Sep 17 00:00:00 2001 From: Arthur Bassi Date: Thu, 10 Sep 2026 17:56:00 -0300 Subject: [PATCH] fix(work-orders): allow Complete without a linked site Snapshot whatever Site/Vendor/POC data exists instead of gating completion on Locations. --- .../WorkOrderCompletionSnapshotMapper.cs | 22 ++++++------- .../WorkOrderCompletionFreezeTests.cs | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/SeaHaven.Services/Helpers/WorkOrderCompletionSnapshotMapper.cs b/SeaHaven.Services/Helpers/WorkOrderCompletionSnapshotMapper.cs index cdcfffc..28ef673 100644 --- a/SeaHaven.Services/Helpers/WorkOrderCompletionSnapshotMapper.cs +++ b/SeaHaven.Services/Helpers/WorkOrderCompletionSnapshotMapper.cs @@ -3,7 +3,6 @@ using System.Text.Json; using Data.SeaHavenIndustries; using SeaHaven.DataServices.Helpers; using SeaHaven.Services.DTOs; -using SeaHaven.Services.Exceptions; namespace SeaHaven.Services.Helpers { @@ -13,10 +12,7 @@ namespace SeaHaven.Services.Helpers public static void Capture(WorkOrder workOrder) { - var location = workOrder.Locations - ?? throw new WorkOrderBoardValidationException( - "CompletionSnapshotUnavailable", - "Site details are required before marking the work order Completed."); + var location = workOrder.Locations; var contact = workOrder.WorkOrderContacts? .OrderBy(item => item.Id) @@ -39,14 +35,14 @@ namespace SeaHaven.Services.Helpers new WorkOrderFrozenSite { Code = workOrder.SiteCode, - Label = FirstNotBlank(location.Name, location.Title, workOrder.SiteCode), - Address = JoinAddress(location.Address1, location.Address2), - City = location.City, - State = location.State, - Zip = location.Zip, - Phone = location.PhoneNumber, - Email = location.Email, - Maps = BuildMapsUrl(location) + Label = FirstNotBlank(location?.Name, location?.Title, workOrder.SiteCode), + Address = JoinAddress(location?.Address1, location?.Address2), + City = location?.City, + State = location?.State, + Zip = location?.Zip, + Phone = location?.PhoneNumber, + Email = location?.Email, + Maps = location == null ? null : BuildMapsUrl(location) }, JsonOptions); diff --git a/SeaHavenIndustries.Tests/WorkOrderCompletionFreezeTests.cs b/SeaHavenIndustries.Tests/WorkOrderCompletionFreezeTests.cs index c41d1b7..6589f9f 100644 --- a/SeaHavenIndustries.Tests/WorkOrderCompletionFreezeTests.cs +++ b/SeaHavenIndustries.Tests/WorkOrderCompletionFreezeTests.cs @@ -117,6 +117,38 @@ public class WorkOrderCompletionFreezeTests Assert.Equal("Frozen POC", afterFlag.PocName); } + [Fact] + public async Task FirstCompletedTransitionWithoutSiteStillCapturesAvailableSnapshot() + { + await using var context = CreateContext(); + var service = CreateService(context); + var workOrder = new WorkOrder + { + Id = 1, + InternalWONumber = "00000012345", + SiteCode = "BK5", + LifecycleStatus = LifecycleStatus.Scheduled, + ScheduledDate = DateTime.UtcNow.Date.AddDays(1), + RowVersion = Version() + }; + context.Add(workOrder); + await context.SaveChangesAsync(); + + var completed = await service.PatchFieldAsync( + workOrder.Id, + Patch(WorkOrderBoardFieldNames.LifecycleStatus, "Complete", workOrder), + "actor-1"); + var persisted = await context.workOrders.SingleAsync(); + + Assert.Equal(LifecycleStatus.Completed, completed.LifecycleStatus); + Assert.Equal("BK5", completed.FrozenSite?.Code); + Assert.Equal("BK5", completed.FrozenSite?.Label); + Assert.Null(completed.FrozenSite?.City); + Assert.Null(completed.FrozenCompany); + Assert.False(string.IsNullOrWhiteSpace(persisted.FrozenSite)); + Assert.Null(persisted.FrozenCompany); + } + [Fact] public async Task OpenWorkOrderProjectionKeepsUsingLiveLocation() {