mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 04:53:11 +00:00
Add dispatcher verification as final dispatch gate
- VerifiedBy and VerifiedAt fields on Dispatch model - VerifyDispatch endpoint validates all checklist items complete + both signoffs present - Returns missing items list if validation fails - Sets status to Verified, logs to audit trail - GetDispatchById includes verifiedBy and verifiedAt - Migration for new fields
This commit is contained in:
parent
81472bf729
commit
575e8ab6fc
5 changed files with 2919 additions and 0 deletions
|
|
@ -1235,6 +1235,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
x.EmailSent,
|
||||
x.WorkOrderId,
|
||||
x.AcknowledgedAt,
|
||||
x.VerifiedBy,
|
||||
x.VerifiedAt,
|
||||
woNumber = x.WorkOrder != null ? x.WorkOrder.InternalWONumber : "",
|
||||
woTitle = x.WorkOrder != null ? x.WorkOrder.WorkerOrderTitle : "",
|
||||
vendorName = x.Vendor != null ? x.Vendor.CompanyName : "",
|
||||
|
|
@ -1386,6 +1388,67 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
return match.Success ? match.Groups[1].Value : null;
|
||||
}
|
||||
|
||||
[HttpPost("VerifyDispatch")]
|
||||
public async Task<IActionResult> VerifyDispatch(int dispatchId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dispatch = await _db.Dispatches.FindAsync(dispatchId);
|
||||
if (dispatch == null)
|
||||
return BadRequest(new Response { Status = "Error", Message = "Dispatch not found" });
|
||||
|
||||
var incompleteItems = await _db.DispatchChecklistItems
|
||||
.Where(c => c.DispatchId == dispatchId && !c.IsCompleted)
|
||||
.CountAsync();
|
||||
|
||||
var signoffCount = await _db.DispatchSignoffs
|
||||
.Where(s => s.DispatchId == dispatchId)
|
||||
.CountAsync();
|
||||
|
||||
var missing = new List<string>();
|
||||
if (incompleteItems > 0)
|
||||
missing.Add($"{incompleteItems} checklist item(s) incomplete");
|
||||
if (signoffCount < 2)
|
||||
{
|
||||
var existingTypes = await _db.DispatchSignoffs
|
||||
.Where(s => s.DispatchId == dispatchId)
|
||||
.Select(s => s.SignoffType)
|
||||
.ToListAsync();
|
||||
if (!existingTypes.Contains("Customer")) missing.Add("Missing Customer sign-off");
|
||||
if (!existingTypes.Contains("Vendor")) missing.Add("Missing Vendor sign-off");
|
||||
}
|
||||
|
||||
if (missing.Count > 0)
|
||||
return BadRequest(new { status = "Error", message = "Cannot verify", missing });
|
||||
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var user = userId != null ? await _db.Users.FindAsync(userId) : null;
|
||||
var userName = user != null ? (user.FirstName + " " + user.LastName).Trim() : "";
|
||||
|
||||
dispatch.Status = "Verified";
|
||||
dispatch.VerifiedBy = userName;
|
||||
dispatch.VerifiedAt = DateTime.UtcNow;
|
||||
|
||||
_db.WorkOrderAuditLogs.Add(new WorkOrderAuditLog
|
||||
{
|
||||
WorkOrderId = dispatch.WorkOrderId ?? 0,
|
||||
UserId = userId,
|
||||
FieldName = $"Dispatch {dispatch.DispatchNumber}",
|
||||
OldValue = dispatch.Status ?? "",
|
||||
NewValue = "Verified",
|
||||
Action = "dispatch_verified",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { message = "Dispatch verified", verifiedBy = userName, verifiedAt = dispatch.VerifiedAt });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("AddDispatchSignoff")]
|
||||
public async Task<IActionResult> AddDispatchSignoff([FromBody] DispatchSignoff_DTO model)
|
||||
{
|
||||
|
|
|
|||
2809
Data.SeaHavenIndustries/Migrations/20260417195316_AddDispatchVerification.Designer.cs
generated
Normal file
2809
Data.SeaHavenIndustries/Migrations/20260417195316_AddDispatchVerification.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Data.SeaHavenIndustries.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDispatchVerification : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "VerifiedAt",
|
||||
table: "Dispatches",
|
||||
type: "datetime2",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "VerifiedBy",
|
||||
table: "Dispatches",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "VerifiedAt",
|
||||
table: "Dispatches");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "VerifiedBy",
|
||||
table: "Dispatches");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -697,6 +697,12 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.Property<int>("VendorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("VerifiedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("VerifiedBy")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("WorkOrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ namespace Data.SeaHavenIndustries
|
|||
public bool EmailSent { get; set; }
|
||||
public string? ReplyToAddress { get; set; }
|
||||
public string? AcceptToken { get; set; }
|
||||
public string? VerifiedBy { get; set; }
|
||||
public DateTime? VerifiedAt { get; set; }
|
||||
public ICollection<Comments>? Comments { get; set; }
|
||||
public ICollection<DispatchWorkOrder>? DispatchWorkOrders { get; set; }
|
||||
public ICollection<DispatchChecklistItem>? ChecklistItems { get; set; }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue