mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 11:53:12 +00:00
feat(vendors): record deactivations confirmed past open work orders
SH-44's user story is about not silently orphaning active work. The confirmation dialog tells the operator, but nothing told the system, so a deactivation that left work orders open was indistinguishable from one that had none. VendorService now takes an ILogger and writes a warning naming the vendor, the user and the number of work orders left open whenever the guard is cleared by confirmation. Both the update and delete paths are covered; nothing is logged when there was nothing to leave open.
This commit is contained in:
parent
7a0856ddf7
commit
6c16ce7047
2 changed files with 35 additions and 6 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Data.SeaHavenIndustries;
|
||||
using Data.SeaHavenIndustries.Enums;
|
||||
using FluentAssertions;
|
||||
|
|
@ -27,7 +28,8 @@ public class VendorServiceTests
|
|||
Microsoft.Extensions.Options.Options.Create(new FrontendOptions()),
|
||||
new CreateVendorValidation(),
|
||||
new UpdateVendorValidation(),
|
||||
new WorkOrderVendorUpdateValidation());
|
||||
new WorkOrderVendorUpdateValidation(),
|
||||
Mock.Of<ILogger<VendorService>>());
|
||||
|
||||
[Fact]
|
||||
public async Task CreateVendor_PersistsCompleteProfile()
|
||||
|
|
@ -758,7 +760,8 @@ public class VendorServiceTests
|
|||
Microsoft.Extensions.Options.Options.Create(new FrontendOptions()),
|
||||
new CreateVendorValidation(),
|
||||
new UpdateVendorValidation(),
|
||||
new WorkOrderVendorUpdateValidation());
|
||||
new WorkOrderVendorUpdateValidation(),
|
||||
Mock.Of<ILogger<VendorService>>());
|
||||
|
||||
var facets = await service.GetFacetsAsync(null, CancellationToken.None);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using Data.SeaHavenIndustries;
|
|||
using Data.SeaHavenIndustries.Enums;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SeaHaven.DataServices.Interfaces;
|
||||
using SeaHaven.DataServices.Models;
|
||||
|
|
@ -25,6 +26,7 @@ namespace SeaHaven.Services.Implementation
|
|||
private readonly ICreateVendorValidation _createValidator;
|
||||
private readonly IUpdateVendorValidation _updateValidator;
|
||||
private readonly IWorkOrderVendorUpdateValidation _workOrderUpdateValidator;
|
||||
private readonly ILogger<VendorService> _logger;
|
||||
|
||||
public VendorService(
|
||||
IVendorDataService vendorDataService,
|
||||
|
|
@ -33,7 +35,8 @@ namespace SeaHaven.Services.Implementation
|
|||
IOptions<FrontendOptions> frontendOptions,
|
||||
ICreateVendorValidation createValidator,
|
||||
IUpdateVendorValidation updateValidator,
|
||||
IWorkOrderVendorUpdateValidation workOrderUpdateValidator)
|
||||
IWorkOrderVendorUpdateValidation workOrderUpdateValidator,
|
||||
ILogger<VendorService> logger)
|
||||
{
|
||||
_vendorDataService = vendorDataService;
|
||||
_vendorTokenService = vendorTokenService;
|
||||
|
|
@ -42,6 +45,7 @@ namespace SeaHaven.Services.Implementation
|
|||
_createValidator = createValidator;
|
||||
_updateValidator = updateValidator;
|
||||
_workOrderUpdateValidator = workOrderUpdateValidator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<VendorDTO?> GetVendorByIdAsync(int id)
|
||||
|
|
@ -193,8 +197,13 @@ namespace SeaHaven.Services.Implementation
|
|||
if (vendor == null)
|
||||
throw new InvalidOperationException($"Vendor with ID {id} not found");
|
||||
|
||||
if (dto.IsActive.HasValue && !dto.IsActive.Value && !dto.ConfirmOpenWorkOrders)
|
||||
await AssertNoOpenLinkedWorkOrdersAsync(id);
|
||||
if (dto.IsActive.HasValue && !dto.IsActive.Value)
|
||||
{
|
||||
if (dto.ConfirmOpenWorkOrders)
|
||||
await LogConfirmedDeactivationAsync(id, userId);
|
||||
else
|
||||
await AssertNoOpenLinkedWorkOrdersAsync(id);
|
||||
}
|
||||
|
||||
if (dto.Name != null) vendor.CompanyName = dto.Name;
|
||||
if (dto.ContactName != null) vendor.ContactName = dto.ContactName;
|
||||
|
|
@ -230,7 +239,9 @@ namespace SeaHaven.Services.Implementation
|
|||
if (vendor == null)
|
||||
throw new InvalidOperationException($"Vendor with ID {id} not found");
|
||||
|
||||
if (!confirmOpenWorkOrders)
|
||||
if (confirmOpenWorkOrders)
|
||||
await LogConfirmedDeactivationAsync(id, userId);
|
||||
else
|
||||
await AssertNoOpenLinkedWorkOrdersAsync(id);
|
||||
|
||||
vendor.IsActive = false;
|
||||
|
|
@ -503,6 +514,21 @@ namespace SeaHaven.Services.Implementation
|
|||
dto.CompanyPhone = VendorPhoneNormalizer.NormalizeToCanonical(dto.CompanyPhone);
|
||||
}
|
||||
|
||||
// SH-44's story is about not *silently* orphaning active work. When the caller
|
||||
// confirms past the guard, the work orders it chose to leave open are recorded.
|
||||
private async Task LogConfirmedDeactivationAsync(int vendorId, string userId)
|
||||
{
|
||||
var linked = await _vendorDataService.GetLinkedWorkOrdersAsync(vendorId);
|
||||
var openCount = linked.Count(wo => !IsTerminalWorkOrderStatus(wo.LifecycleStatus, wo.Status));
|
||||
if (openCount == 0) return;
|
||||
|
||||
_logger.LogWarning(
|
||||
"Vendor {VendorId} deactivated by user {UserId} with {OpenWorkOrderCount} open work orders, confirmed by the caller.",
|
||||
vendorId,
|
||||
userId,
|
||||
openCount);
|
||||
}
|
||||
|
||||
// Guard for the unconfirmed path only. SH-44 and SH-82 left "blocks or requires
|
||||
// explicit confirmation" to be settled with the team; SH-254 settles it as
|
||||
// explicit confirmation, so a caller that has not confirmed is still blocked.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue