mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 20:03:11 +00:00
fix(work-orders): persist WO identity before staging create audit and locks
This commit is contained in:
parent
e5bda0714a
commit
9dc17d4255
4 changed files with 108 additions and 8 deletions
|
|
@ -123,19 +123,17 @@ namespace SeaHaven.Services.Implementation
|
|||
}
|
||||
|
||||
_context.workOrders.Add(workOrder);
|
||||
|
||||
_auditService.StageCreated(workOrder.Id, actorId, woNumber);
|
||||
StageChanges(workOrder.Id, changes, actorId, dispatch);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
if (dispatch != null && workOrder.PrimaryDispatchId == null)
|
||||
{
|
||||
workOrder.PrimaryDispatchId = dispatch.Id;
|
||||
dispatch.WorkOrderId = workOrder.Id;
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
_auditService.StageCreated(workOrder.Id, actorId, woNumber);
|
||||
StageChanges(workOrder.Id, changes, actorId, dispatch);
|
||||
|
||||
if (request.PocContactId.HasValue)
|
||||
{
|
||||
_context.WorkOrderContacts.Add(new WorkOrderContacts
|
||||
|
|
@ -144,9 +142,10 @@ namespace SeaHaven.Services.Implementation
|
|||
ContactId = request.PocContactId,
|
||||
Notes = string.IsNullOrWhiteSpace(request.PocNotes) ? null : request.PocNotes.Trim()
|
||||
});
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var row = await _boardService.GetBoardRowAsync(workOrder.Id);
|
||||
return row ?? throw new WorkOrderBoardValidationException("NotFound", "Work order was created but could not be loaded.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
using Data.SeaHavenIndustries;
|
||||
using Data.SeaHavenIndustries.Enums;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SeaHaven.DataServices.Implementation;
|
||||
using SeaHaven.Services.DTOs;
|
||||
using SeaHaven.Services.Implementation;
|
||||
using SeaHaven.Services.Validation;
|
||||
|
||||
namespace SeaHavenIndustries.Tests;
|
||||
|
||||
public class WorkOrderBoardCreateRelationalTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Create_AuditAndFieldLocks_UseGeneratedWorkOrderId()
|
||||
{
|
||||
await using var connection = new SqliteConnection("DataSource=:memory:");
|
||||
await connection.OpenAsync();
|
||||
|
||||
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options;
|
||||
|
||||
await using var context = new SqliteBoardTestDbContext(options);
|
||||
await context.Database.EnsureCreatedAsync();
|
||||
|
||||
const string actorId = "actor-1";
|
||||
context.Users.Add(new ApplicationUser
|
||||
{
|
||||
Id = actorId,
|
||||
UserName = "actor-1",
|
||||
NormalizedUserName = "ACTOR-1",
|
||||
Email = "actor@test.local",
|
||||
NormalizedEmail = "ACTOR@TEST.LOCAL"
|
||||
});
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var boardData = new WorkOrderBoardDataService(context);
|
||||
var boardService = new WorkOrderBoardService(boardData);
|
||||
var fieldLocks = new WorkOrderFieldLockService(context);
|
||||
var audit = new WorkOrderAuditService(context, fieldLocks);
|
||||
var service = new WorkOrderBoardCreateService(
|
||||
context,
|
||||
boardData,
|
||||
boardService,
|
||||
audit,
|
||||
new WorkOrderBoardCreateValidation());
|
||||
|
||||
var result = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
||||
{
|
||||
WorkOrderType = WorkOrderType.PM,
|
||||
SiteCode = "BK5",
|
||||
Description = "Relational create"
|
||||
}, actorId);
|
||||
|
||||
Assert.True(result.Id > 0);
|
||||
|
||||
var logs = await context.WorkOrderAuditLogs.AsNoTracking().ToListAsync();
|
||||
var locks = await context.WorkOrderFieldLocks.AsNoTracking().ToListAsync();
|
||||
|
||||
Assert.NotEmpty(logs);
|
||||
Assert.NotEmpty(locks);
|
||||
Assert.Contains(logs, l => l.Action == "Create");
|
||||
Assert.All(logs, l => Assert.Equal(result.Id, l.WorkOrderId));
|
||||
Assert.All(locks, l => Assert.Equal(result.Id, l.WorkOrderId));
|
||||
Assert.DoesNotContain(logs, l => l.WorkOrderId == 0);
|
||||
Assert.DoesNotContain(locks, l => l.WorkOrderId == 0);
|
||||
}
|
||||
|
||||
private sealed class SqliteBoardTestDbContext : ApplicationDbContext
|
||||
{
|
||||
public SqliteBoardTestDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
|
||||
// SQL Server filtered index syntax is invalid on SQLite.
|
||||
foreach (var index in builder.Model.GetEntityTypes().SelectMany(e => e.GetIndexes()))
|
||||
{
|
||||
if (index.GetFilter() != null)
|
||||
index.SetFilter(null);
|
||||
}
|
||||
|
||||
// SQLite has no rowversion type; treat as plain nullable blobs.
|
||||
foreach (var entityType in new[] { typeof(WorkOrder), typeof(Dispatch) })
|
||||
{
|
||||
var property = builder.Entity(entityType).Property("RowVersion").Metadata;
|
||||
property.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.Never;
|
||||
property.IsConcurrencyToken = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +149,7 @@ public class WorkOrderBoardCreateServiceTests
|
|||
{
|
||||
var (context, service) = CreateSut();
|
||||
|
||||
await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
||||
var result = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
||||
{
|
||||
WorkOrderType = WorkOrderType.PM,
|
||||
SiteCode = "BK5",
|
||||
|
|
@ -160,6 +160,7 @@ public class WorkOrderBoardCreateServiceTests
|
|||
Assert.Contains(locks, l => l.FieldName == "SiteCode");
|
||||
Assert.Contains(locks, l => l.FieldName == "WorkOrderType");
|
||||
Assert.Contains(locks, l => l.FieldName == "Description");
|
||||
Assert.All(locks, l => Assert.Equal(result.Id, l.WorkOrderId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -167,7 +168,7 @@ public class WorkOrderBoardCreateServiceTests
|
|||
{
|
||||
var (context, service) = CreateSut();
|
||||
|
||||
await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
||||
var result = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
||||
{
|
||||
WorkOrderType = WorkOrderType.PM,
|
||||
SiteCode = "BK5"
|
||||
|
|
@ -176,5 +177,7 @@ public class WorkOrderBoardCreateServiceTests
|
|||
var logs = await context.WorkOrderAuditLogs.ToListAsync();
|
||||
Assert.Contains(logs, l => l.Action == "Create");
|
||||
Assert.Contains(logs, l => l.Action == "FieldChanged" && l.FieldName == "SiteCode");
|
||||
Assert.All(logs, l => Assert.Equal(result.Id, l.WorkOrderId));
|
||||
Assert.True(result.Id > 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue