mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
The webhook and reconciliation saves now stage the same pending-uplift cancellation, with its own sync audit row, as the board cancel. The rule and the write live in one data-layer helper so the paths cannot drift.
79 lines
3.4 KiB
C#
79 lines
3.4 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace SeaHaven.DataServices.Helpers
|
|
{
|
|
/// <summary>
|
|
/// The single rule and write for "a work order that becomes Canceled cancels its pending
|
|
/// uplifts in the same action". Every path that can cancel a work order (board update,
|
|
/// the cancel endpoint, CRM webhook and reconciliation) asks <see cref="Applies"/> and
|
|
/// stages the cancellation into its own unit of work, so the uplift change and its own
|
|
/// audit row commit, or roll back, with the work order's status change.
|
|
/// </summary>
|
|
public static class PendingUpliftCancellation
|
|
{
|
|
public const string AuditAction = "uplift_cancel";
|
|
public const string CancelledStatus = "Withdrawn";
|
|
|
|
private static readonly string[] PendingStatuses = { "Pending", "ChangesRequested" };
|
|
|
|
/// <summary>True when a lifecycle change moves a work order into Canceled.</summary>
|
|
public static bool Applies(LifecycleStatus? before, LifecycleStatus? after)
|
|
=> before != LifecycleStatus.Canceled && after == LifecycleStatus.Canceled;
|
|
|
|
/// <summary>
|
|
/// Uplift requests that belong to a work order: on a live dispatch that the work
|
|
/// order owns or is linked to.
|
|
/// </summary>
|
|
internal static IQueryable<DispatchUpliftRequest> ForWorkOrder(ApplicationDbContext context, int workOrderId)
|
|
=> context.DispatchUpliftRequests.Where(u =>
|
|
(u.IsDeleted == null || u.IsDeleted == false)
|
|
&& u.Dispatch != null
|
|
&& (u.Dispatch.IsDeleted == null || u.Dispatch.IsDeleted == false)
|
|
&& (
|
|
u.Dispatch.WorkOrderId == workOrderId
|
|
|| u.Dispatch.DispatchWorkOrders!.Any(link => link.WorkOrderId == workOrderId)));
|
|
|
|
/// <summary>
|
|
/// Stages (does not save) the cancellation of every pending uplift on the work order,
|
|
/// with one audit row per uplift. Returns how many uplifts were cancelled.
|
|
/// </summary>
|
|
internal static async Task<int> StageAsync(
|
|
ApplicationDbContext context,
|
|
int workOrderId,
|
|
string? actorId,
|
|
string actorType,
|
|
DateTime now,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var pending = await ForWorkOrder(context, workOrderId)
|
|
.Include(u => u.Dispatch)
|
|
.Where(u => PendingStatuses.Contains(u.Status))
|
|
.ToListAsync(cancellationToken);
|
|
|
|
foreach (var request in pending)
|
|
{
|
|
var previous = request.Status;
|
|
request.Status = CancelledStatus;
|
|
request.DecidedAt = now;
|
|
request.DecidedByUserId = actorId;
|
|
request.LastModificationTime = now;
|
|
|
|
context.WorkOrderAuditLogs.Add(new WorkOrderAuditLog
|
|
{
|
|
WorkOrderId = workOrderId,
|
|
UserId = actorId,
|
|
FieldName = $"Dispatch {request.Dispatch!.DispatchNumber} Uplift",
|
|
OldValue = previous,
|
|
NewValue = CancelledStatus,
|
|
Action = AuditAction,
|
|
ActorType = actorType,
|
|
CreatedAt = now,
|
|
});
|
|
}
|
|
|
|
return pending.Count;
|
|
}
|
|
}
|
|
}
|