mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 08:23:12 +00:00
The manual POC "follow the site" clear-rule compared the edit against every live Site contact. A work order only ever displays one of them, so editing to a different live contact (Site has Alice primary and Bob; WO shows Alice; edit to Bob) matched, cleared the override, and left the row showing Alice with no audit row written — the SH-379 symptom on a different input. A work order with a linked WorkOrderContacts POC hit the same bug when the dispatcher typed the Site's primary: the override cleared and the linked contact showed instead. Compare the edit against the single contact the work order actually follows — the linked WorkOrderContacts POC, or else the Site primary (ResolvePrimary) — matching the board projection's override -> linked -> site precedence, and store the override whenever the edit differs from it. The create path in WorkOrderBoardCreateService had the same any-contact rule and gets the same fix; a supplied PocContactId that is not a live Site contact leaves no follow target, so the typed POC is stored. Replaces MatchesAnySiteContact with Matches(name, phone, contact); comment and PR-body wording updated to state the followed-contact rule. Adds tests for the second-site-contact edit, the linked-contact-differs edit, and the second-site-contact create case.
641 lines
25 KiB
C#
641 lines
25 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using SeaHaven.DataServices.Implementation;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Exceptions;
|
|
using SeaHaven.Services.Helpers;
|
|
using SeaHaven.Services.Implementation;
|
|
using SeaHaven.Services.Interfaces;
|
|
using SeaHaven.Services.Validation;
|
|
|
|
namespace SeaHavenIndustries.Tests;
|
|
|
|
public class WorkOrderPocServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task ManualOverridePersistsIsAuditedAndLocks()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var row = await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", "Call first", workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Equal("Manual POC", persisted.PocName);
|
|
Assert.Equal("312-555-0001", persisted.PocPhone);
|
|
Assert.Equal("Call first", persisted.PocNotes);
|
|
Assert.Equal("Manual POC", row.PocName);
|
|
Assert.Equal("312-555-0001", row.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
|
|
var auditName = await context.WorkOrderAuditLogs.SingleAsync(a =>
|
|
a.WorkOrderId == workOrder.Id && a.FieldName == "PocName");
|
|
Assert.Equal("Alice Site", auditName.OldValue);
|
|
Assert.Equal("Manual POC", auditName.NewValue);
|
|
Assert.Equal("FieldChanged", auditName.Action);
|
|
Assert.True(await context.WorkOrderFieldLocks.AnyAsync(l =>
|
|
l.WorkOrderId == workOrder.Id && l.FieldName == "PocName"));
|
|
Assert.True(await context.WorkOrderFieldLocks.AnyAsync(l =>
|
|
l.WorkOrderId == workOrder.Id && l.FieldName == "PocPhone"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ManualOverrideSurvivesCompleteAndLaterSiteChanges()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
workOrder.LifecycleStatus = LifecycleStatus.Scheduled;
|
|
workOrder.ScheduledDate = DateTime.UtcNow.Date.AddDays(1);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var updateService = CreateUpdateService(context);
|
|
var completed = await updateService.PatchFieldAsync(
|
|
workOrder.Id,
|
|
Patch(WorkOrderBoardFieldNames.LifecycleStatus, "Complete", workOrder),
|
|
"actor-1");
|
|
Assert.Equal("Manual POC", completed.PocName);
|
|
|
|
var siteContact = await context.Contacts.SingleAsync(c => c.FirstName == "Alice");
|
|
siteContact.FirstName = "Changed";
|
|
siteContact.PhoneNumber = "999-555-0100";
|
|
await context.SaveChangesAsync();
|
|
|
|
var row = await CreateBoardService(context).GetBoardRowAsync(
|
|
workOrder.Id, WorkOrderAccountTestHelpers.AccountUser());
|
|
Assert.Equal("Manual POC", row!.PocName);
|
|
Assert.Equal("312-555-0001", row.PocPhone);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SiteContactUpdateDoesNotOverwriteManualOverride()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
var siteContact = await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
siteContact.FirstName = "Rotated";
|
|
siteContact.PhoneNumber = "999-555-0100";
|
|
await context.SaveChangesAsync();
|
|
|
|
var row = await CreateBoardService(context).GetBoardRowAsync(
|
|
workOrder.Id, WorkOrderAccountTestHelpers.AccountUser());
|
|
Assert.Equal("Manual POC", row!.PocName);
|
|
Assert.Equal("312-555-0001", row.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UnlockedWorkOrderFollowsSiteContact()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
var primary = await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100", order: 0);
|
|
await SeedSiteContactAsync(context, firstName: "Bob", lastName: "Backup", phone: "312-555-0200", order: 1);
|
|
await context.SaveChangesAsync();
|
|
|
|
var boardService = CreateBoardService(context);
|
|
var before = await boardService.GetBoardRowAsync(workOrder.Id, WorkOrderAccountTestHelpers.AccountUser());
|
|
Assert.Equal("Alice Site", before!.PocName);
|
|
Assert.Equal("312-555-0100", before.PocPhone);
|
|
Assert.False(before.PocCustomized);
|
|
|
|
primary.PhoneNumber = "312-555-0999";
|
|
await context.SaveChangesAsync();
|
|
|
|
var after = await boardService.GetBoardRowAsync(workOrder.Id, WorkOrderAccountTestHelpers.AccountUser());
|
|
Assert.Equal("Alice Site", after!.PocName);
|
|
Assert.Equal("312-555-0999", after.PocPhone);
|
|
Assert.False(after.PocCustomized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EditEqualToSiteContactDoesNotLock()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var row = await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Alice Site", "312-555-0100", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Null(persisted.PocName);
|
|
Assert.Null(persisted.PocPhone);
|
|
Assert.Equal("Alice Site", row.PocName);
|
|
Assert.Equal("312-555-0100", row.PocPhone);
|
|
Assert.False(row.PocCustomized);
|
|
|
|
var auditName = await context.WorkOrderAuditLogs.Where(a =>
|
|
a.WorkOrderId == workOrder.Id && a.FieldName == "PocName")
|
|
.OrderByDescending(a => a.Id)
|
|
.FirstAsync();
|
|
Assert.Equal("Manual POC", auditName.OldValue);
|
|
Assert.Equal("Alice Site", auditName.NewValue);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ClearingBothFieldsFollowsSiteAgain()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", "keep notes", workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
var row = await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc(null, null, null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Null(persisted.PocName);
|
|
Assert.Null(persisted.PocPhone);
|
|
Assert.Equal("Alice Site", row.PocName);
|
|
Assert.False(row.PocCustomized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CrossTenantUpdateIsRejected()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context, accountId: 2);
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var ex = await Assert.ThrowsAsync<WorkOrderBoardValidationException>(() =>
|
|
service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(accountId: 1),
|
|
"actor-1"));
|
|
|
|
Assert.Equal("NotFound", ex.Code);
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Null(persisted.PocName);
|
|
Assert.Empty(await context.WorkOrderAuditLogs.ToListAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task MissingAccountScopeIsForbidden()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var ex = await Assert.ThrowsAsync<WorkOrderBoardValidationException>(() =>
|
|
service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.MissingScope(),
|
|
"actor-1"));
|
|
|
|
Assert.Equal("Forbidden", ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CompletedWorkOrderIsReadOnly()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
workOrder.LifecycleStatus = LifecycleStatus.Completed;
|
|
workOrder.CompletedDate = DateTime.UtcNow;
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var ex = await Assert.ThrowsAsync<WorkOrderBoardValidationException>(() =>
|
|
service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1"));
|
|
|
|
Assert.Equal("ReadOnly", ex.Code);
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Null(persisted.PocName);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CanceledWorkOrderIsReadOnly()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
workOrder.LifecycleStatus = LifecycleStatus.Canceled;
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var ex = await Assert.ThrowsAsync<WorkOrderBoardValidationException>(() =>
|
|
service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Manual POC", "312-555-0001", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1"));
|
|
|
|
Assert.Equal("CanceledReadOnly", ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task StaleVersionThrowsConflict()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreatePocService(context);
|
|
var stale = new WorkOrderPocUpdateRequestDto
|
|
{
|
|
PocName = "Manual POC",
|
|
PocPhone = "312-555-0001",
|
|
WorkOrderVersion = Convert.ToBase64String(new byte[] { 9, 9, 9, 9 })
|
|
};
|
|
|
|
await Assert.ThrowsAsync<WorkOrderBoardConcurrencyException>(() =>
|
|
service.UpdatePocAsync(workOrder.Id, stale, WorkOrderAccountTestHelpers.AccountUser(), "actor-1"));
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Null(persisted.PocName);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CompletionFreezesSiteContactWhenNoOverrideOrLink()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
workOrder.LifecycleStatus = LifecycleStatus.Scheduled;
|
|
workOrder.ScheduledDate = DateTime.UtcNow.Date.AddDays(1);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100");
|
|
await context.SaveChangesAsync();
|
|
|
|
var updateService = CreateUpdateService(context);
|
|
var completed = await updateService.PatchFieldAsync(
|
|
workOrder.Id,
|
|
Patch(WorkOrderBoardFieldNames.LifecycleStatus, "Complete", workOrder),
|
|
"actor-1");
|
|
|
|
Assert.Equal(LifecycleStatus.Completed, completed.LifecycleStatus);
|
|
Assert.Equal("Alice Site", completed.PocName);
|
|
Assert.Equal("312-555-0100", completed.PocPhone);
|
|
|
|
var contact = await context.Contacts.SingleAsync();
|
|
contact.PhoneNumber = "999-555-0100";
|
|
await context.SaveChangesAsync();
|
|
|
|
var row = await CreateBoardService(context).GetBoardRowAsync(
|
|
workOrder.Id, WorkOrderAccountTestHelpers.AccountUser());
|
|
Assert.Equal("Alice Site", row!.PocName);
|
|
Assert.Equal("312-555-0100", row.PocPhone);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BoardCreateWithPocEqualToSiteContactFollowsSite()
|
|
{
|
|
await using var context = CreateContext();
|
|
WorkOrderAccountTestHelpers.SeedBoardCreateScope(context);
|
|
context.Contacts.Add(new Contacts
|
|
{
|
|
FirstName = "Alice",
|
|
LastName = "Site",
|
|
PhoneNumber = "312-555-0100",
|
|
LocationId = 1,
|
|
SiteContactOrder = 0
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreateCreateService(context);
|
|
var row = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
|
{
|
|
WorkOrderType = WorkOrderType.PM,
|
|
SiteCode = "BK5",
|
|
LocationId = 1,
|
|
PocName = "Alice Site",
|
|
PocPhone = "312-555-0100"
|
|
}, WorkOrderAccountTestHelpers.AccountUser(), "actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == row.Id);
|
|
Assert.Null(persisted.PocName);
|
|
Assert.Null(persisted.PocPhone);
|
|
Assert.Equal("Alice Site", row.PocName);
|
|
Assert.False(row.PocCustomized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BoardCreateWithPocAwayFromSiteContactIsStored()
|
|
{
|
|
await using var context = CreateContext();
|
|
WorkOrderAccountTestHelpers.SeedBoardCreateScope(context);
|
|
context.Contacts.Add(new Contacts
|
|
{
|
|
FirstName = "Alice",
|
|
LastName = "Site",
|
|
PhoneNumber = "312-555-0100",
|
|
LocationId = 1,
|
|
SiteContactOrder = 0
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var service = CreateCreateService(context);
|
|
var row = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
|
{
|
|
WorkOrderType = WorkOrderType.PM,
|
|
SiteCode = "BK5",
|
|
LocationId = 1,
|
|
PocName = "Manual POC",
|
|
PocPhone = "312-555-0001"
|
|
}, WorkOrderAccountTestHelpers.AccountUser(), "actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == row.Id);
|
|
Assert.Equal("Manual POC", persisted.PocName);
|
|
Assert.Equal("312-555-0001", persisted.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EditToSecondSiteContactStoresOverride()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100", order: 0);
|
|
await SeedSiteContactAsync(context, firstName: "Bob", lastName: "Backup", phone: "312-555-0200", order: 1);
|
|
await context.SaveChangesAsync();
|
|
|
|
// The WO follows the Site primary (Alice). Editing to the second live Site
|
|
// contact (Bob) is a change away from what the board shows and must be
|
|
// stored and locked, not silently cleared back to Alice.
|
|
var service = CreatePocService(context);
|
|
var row = await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Bob Backup", "312-555-0200", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Equal("Bob Backup", persisted.PocName);
|
|
Assert.Equal("312-555-0200", persisted.PocPhone);
|
|
Assert.Equal("Bob Backup", row.PocName);
|
|
Assert.Equal("312-555-0200", row.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
|
|
var auditName = await context.WorkOrderAuditLogs.SingleAsync(a =>
|
|
a.WorkOrderId == workOrder.Id && a.FieldName == "PocName");
|
|
Assert.Equal("Alice Site", auditName.OldValue);
|
|
Assert.Equal("Bob Backup", auditName.NewValue);
|
|
Assert.True(await context.WorkOrderFieldLocks.AnyAsync(l =>
|
|
l.WorkOrderId == workOrder.Id && l.FieldName == "PocName"));
|
|
Assert.True(await context.WorkOrderFieldLocks.AnyAsync(l =>
|
|
l.WorkOrderId == workOrder.Id && l.FieldName == "PocPhone"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EditToSitePrimaryWhenLinkedContactDiffersStoresOverride()
|
|
{
|
|
await using var context = CreateContext();
|
|
await SeedScopeAsync(context);
|
|
var workOrder = NewWorkOrder(context);
|
|
await SeedSiteContactAsync(context, firstName: "Alice", lastName: "Site", phone: "312-555-0100", order: 0);
|
|
var linked = new Contacts
|
|
{
|
|
FirstName = "Carol",
|
|
LastName = "Linked",
|
|
PhoneNumber = "312-555-0300"
|
|
};
|
|
context.Contacts.Add(linked);
|
|
await context.SaveChangesAsync();
|
|
context.WorkOrderContacts.Add(new WorkOrderContacts
|
|
{
|
|
WorkorderId = workOrder.Id,
|
|
ContactId = linked.Id
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
// The WO follows its linked contact (Carol). Typing the Site's primary
|
|
// (Alice) is a change away from what the board shows and must be stored,
|
|
// not cleared back to Carol.
|
|
var service = CreatePocService(context);
|
|
var row = await service.UpdatePocAsync(
|
|
workOrder.Id,
|
|
Poc("Alice Site", "312-555-0100", null, workOrder),
|
|
WorkOrderAccountTestHelpers.AccountUser(),
|
|
"actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == workOrder.Id);
|
|
Assert.Equal("Alice Site", persisted.PocName);
|
|
Assert.Equal("312-555-0100", persisted.PocPhone);
|
|
Assert.Equal("Alice Site", row.PocName);
|
|
Assert.Equal("312-555-0100", row.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
|
|
var auditName = await context.WorkOrderAuditLogs.SingleAsync(a =>
|
|
a.WorkOrderId == workOrder.Id && a.FieldName == "PocName");
|
|
Assert.Equal("Carol Linked", auditName.OldValue);
|
|
Assert.Equal("Alice Site", auditName.NewValue);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BoardCreateWithPocEqualToSecondSiteContactIsStored()
|
|
{
|
|
await using var context = CreateContext();
|
|
WorkOrderAccountTestHelpers.SeedBoardCreateScope(context);
|
|
context.Contacts.Add(new Contacts
|
|
{
|
|
FirstName = "Alice",
|
|
LastName = "Site",
|
|
PhoneNumber = "312-555-0100",
|
|
LocationId = 1,
|
|
SiteContactOrder = 0
|
|
});
|
|
context.Contacts.Add(new Contacts
|
|
{
|
|
FirstName = "Bob",
|
|
LastName = "Backup",
|
|
PhoneNumber = "312-555-0200",
|
|
LocationId = 1,
|
|
SiteContactOrder = 1
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
// Create-time POC equal to the second Site contact (Bob) is not the contact
|
|
// the WO would follow (the primary, Alice), so it must be stored.
|
|
var service = CreateCreateService(context);
|
|
var row = await service.CreateAsync(new WorkOrderBoardCreateRequestDto
|
|
{
|
|
WorkOrderType = WorkOrderType.PM,
|
|
SiteCode = "BK5",
|
|
LocationId = 1,
|
|
PocName = "Bob Backup",
|
|
PocPhone = "312-555-0200"
|
|
}, WorkOrderAccountTestHelpers.AccountUser(), "actor-1");
|
|
|
|
var persisted = await context.workOrders.AsNoTracking().SingleAsync(w => w.Id == row.Id);
|
|
Assert.Equal("Bob Backup", persisted.PocName);
|
|
Assert.Equal("312-555-0200", persisted.PocPhone);
|
|
Assert.True(row.PocCustomized);
|
|
}
|
|
|
|
private static ApplicationDbContext CreateContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
|
.Options;
|
|
return new ApplicationDbContext(options);
|
|
}
|
|
|
|
private static async Task SeedScopeAsync(ApplicationDbContext context)
|
|
{
|
|
WorkOrderAccountTestHelpers.SeedBoardCreateScope(context);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static WorkOrder NewWorkOrder(ApplicationDbContext context, int accountId = 1)
|
|
{
|
|
var location = context.Locations.Local.Single(l => l.Id == 1);
|
|
var workOrder = new WorkOrder
|
|
{
|
|
Id = 1,
|
|
InternalWONumber = "00000012345",
|
|
SiteCode = "BK5",
|
|
LocationId = location.Id,
|
|
Locations = location,
|
|
AccountId = accountId,
|
|
LifecycleStatus = LifecycleStatus.Incomplete,
|
|
RowVersion = Version()
|
|
};
|
|
context.workOrders.Add(workOrder);
|
|
return workOrder;
|
|
}
|
|
|
|
private static async Task<Contacts> SeedSiteContactAsync(
|
|
ApplicationDbContext context,
|
|
string firstName,
|
|
string lastName,
|
|
string phone,
|
|
int order = 0)
|
|
{
|
|
var contact = new Contacts
|
|
{
|
|
FirstName = firstName,
|
|
LastName = lastName,
|
|
PhoneNumber = phone,
|
|
LocationId = 1,
|
|
SiteContactOrder = order
|
|
};
|
|
context.Contacts.Add(contact);
|
|
await context.SaveChangesAsync();
|
|
return contact;
|
|
}
|
|
|
|
private static WorkOrderPocService CreatePocService(ApplicationDbContext context)
|
|
=> new(
|
|
new WorkOrderPocDataService(context),
|
|
new WorkOrderBoardMutationDataService(context),
|
|
CreateBoardService(context),
|
|
new WorkOrderAuditService(
|
|
new WorkOrderAuditDataService(context),
|
|
new WorkOrderFieldLockService(new WorkOrderFieldLockDataService(context))),
|
|
WorkOrderAccountTestHelpers.Resolver(context));
|
|
|
|
private static WorkOrderBoardService CreateBoardService(ApplicationDbContext context)
|
|
=> new(
|
|
new WorkOrderBoardDataService(context),
|
|
WorkOrderAccountTestHelpers.Resolver(context));
|
|
|
|
private static WorkOrderBoardUpdateService CreateUpdateService(ApplicationDbContext context)
|
|
{
|
|
var fieldLocks = new WorkOrderFieldLockService(new WorkOrderFieldLockDataService(context));
|
|
return new WorkOrderBoardUpdateService(
|
|
new WorkOrderBoardDataService(context),
|
|
new WorkOrderBoardMutationDataService(context),
|
|
new WorkOrderAuditService(new WorkOrderAuditDataService(context), fieldLocks));
|
|
}
|
|
|
|
private static WorkOrderBoardCreateService CreateCreateService(ApplicationDbContext context)
|
|
=> new(
|
|
new WorkOrderBoardDataService(context),
|
|
new WorkOrderBoardMutationDataService(context),
|
|
CreateBoardService(context),
|
|
new WorkOrderAuditService(
|
|
new WorkOrderAuditDataService(context),
|
|
new WorkOrderFieldLockService(new WorkOrderFieldLockDataService(context))),
|
|
new WorkOrderBoardCreateValidation(),
|
|
WorkOrderAccountTestHelpers.Resolver(context),
|
|
new WorkOrderPocDataService(context));
|
|
|
|
private static WorkOrderPocUpdateRequestDto Poc(
|
|
string? name,
|
|
string? phone,
|
|
string? notes,
|
|
WorkOrder workOrder)
|
|
=> new()
|
|
{
|
|
PocName = name,
|
|
PocPhone = phone,
|
|
PocNotes = notes,
|
|
WorkOrderVersion = Convert.ToBase64String(workOrder.RowVersion ?? Version())
|
|
};
|
|
|
|
private static WorkOrderBoardPatchRequestDto Patch(
|
|
string field,
|
|
string value,
|
|
WorkOrder workOrder)
|
|
=> new()
|
|
{
|
|
Field = field,
|
|
Value = value,
|
|
WorkOrderVersion = Convert.ToBase64String(workOrder.RowVersion ?? Version())
|
|
};
|
|
|
|
private static byte[] Version() => new byte[] { 1, 0, 0, 0, 0, 0, 0, 1 };
|
|
}
|