mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
Add dispatch checklist items with template support
- DispatchChecklistItem model (DispatchId, WorkOrderId, ItemText, IsCompleted, CompletedBy, CompletedAt) - DispatchToVendor copies template items when TaskListTemplateId provided - Supports custom checklist items alongside template items - UpdateChecklistItem endpoint to toggle completion with user name - AddChecklistItem endpoint for ad-hoc items - GetDispatchById includes checklist items in response - Migration for DispatchChecklistItems table
This commit is contained in:
parent
be190836a4
commit
3a25fa8559
8 changed files with 2989 additions and 0 deletions
|
|
@ -1090,6 +1090,26 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
DispatchWorkOrders = workOrders.Select(wo => new DispatchWorkOrder { WorkOrderId = wo.Id }).ToList()
|
||||
};
|
||||
|
||||
var checklistItems = new List<DispatchChecklistItem>();
|
||||
if (model.TaskListTemplateId.HasValue)
|
||||
{
|
||||
var template = await _db.TaskListTemplates
|
||||
.Include(t => t.Items)
|
||||
.FirstOrDefaultAsync(t => t.Id == model.TaskListTemplateId.Value);
|
||||
if (template?.Items != null)
|
||||
{
|
||||
checklistItems.AddRange(template.Items.OrderBy(i => i.SortOrder).Select((i, idx) =>
|
||||
new DispatchChecklistItem { ItemText = i.ItemText, SortOrder = idx }));
|
||||
}
|
||||
}
|
||||
if (model.CustomChecklistItems != null)
|
||||
{
|
||||
var startIdx = checklistItems.Count;
|
||||
checklistItems.AddRange(model.CustomChecklistItems.Select((text, idx) =>
|
||||
new DispatchChecklistItem { ItemText = text, SortOrder = startIdx + idx }));
|
||||
}
|
||||
dispatch.ChecklistItems = checklistItems;
|
||||
|
||||
var woListHtml = string.Join("", workOrders.Select(wo =>
|
||||
$"<tr><td style='padding:6px 8px;border:1px solid #ddd;'>{wo.InternalWONumber}</td>" +
|
||||
$"<td style='padding:6px 8px;border:1px solid #ddd;'>{wo.WorkerOrderTitle}</td>" +
|
||||
|
|
@ -1223,6 +1243,18 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
woNumber = dwo.WorkOrder != null ? dwo.WorkOrder.InternalWONumber : "",
|
||||
woTitle = dwo.WorkOrder != null ? dwo.WorkOrder.WorkerOrderTitle : ""
|
||||
}).ToList(),
|
||||
checklistItems = _db.DispatchChecklistItems
|
||||
.Where(ci => ci.DispatchId == x.Id)
|
||||
.OrderBy(ci => ci.SortOrder)
|
||||
.Select(ci => new {
|
||||
ci.Id,
|
||||
ci.ItemText,
|
||||
ci.IsCompleted,
|
||||
ci.CompletedBy,
|
||||
ci.CompletedAt,
|
||||
ci.SortOrder,
|
||||
ci.WorkOrderId
|
||||
}).ToList(),
|
||||
comments = _db.Comments
|
||||
.Where(c => c.DispatchId == x.Id)
|
||||
.OrderBy(c => c.CreatedDate)
|
||||
|
|
@ -1340,6 +1372,41 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
return match.Success ? match.Groups[1].Value : null;
|
||||
}
|
||||
|
||||
[HttpPost("UpdateChecklistItem")]
|
||||
public async Task<IActionResult> UpdateChecklistItem([FromBody] ChecklistItemUpdate_DTO model)
|
||||
{
|
||||
var item = await _db.DispatchChecklistItems.FindAsync(model.Id);
|
||||
if (item == null)
|
||||
return NotFound(new Response { Status = "Error", Message = "Checklist item not found" });
|
||||
|
||||
item.IsCompleted = model.IsCompleted;
|
||||
item.CompletedBy = model.IsCompleted ? model.CompletedBy : null;
|
||||
item.CompletedAt = model.IsCompleted ? DateTime.UtcNow : null;
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { message = "Updated", item.Id, item.IsCompleted, item.CompletedBy, item.CompletedAt });
|
||||
}
|
||||
|
||||
[HttpPost("AddChecklistItem")]
|
||||
public async Task<IActionResult> AddChecklistItem([FromBody] AddChecklistItem_DTO model)
|
||||
{
|
||||
var maxSort = await _db.DispatchChecklistItems
|
||||
.Where(c => c.DispatchId == model.DispatchId)
|
||||
.MaxAsync(c => (int?)c.SortOrder) ?? -1;
|
||||
|
||||
var item = new DispatchChecklistItem
|
||||
{
|
||||
DispatchId = model.DispatchId,
|
||||
WorkOrderId = model.WorkOrderId,
|
||||
ItemText = model.ItemText,
|
||||
SortOrder = maxSort + 1,
|
||||
IsCompleted = false
|
||||
};
|
||||
_db.DispatchChecklistItems.Add(item);
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { item.Id, item.ItemText, item.SortOrder, item.IsCompleted });
|
||||
}
|
||||
|
||||
private async Task<string> GenerateInternalWONumber()
|
||||
{
|
||||
var lastWO = await _db.workOrders
|
||||
|
|
|
|||
|
|
@ -7,5 +7,21 @@ namespace Api.SeaHavenIndustries.DTOs
|
|||
public decimal? NTEAmount { get; set; }
|
||||
public DateTime? ScheduledDate { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? TaskListTemplateId { get; set; }
|
||||
public List<string>? CustomChecklistItems { get; set; }
|
||||
}
|
||||
|
||||
public class ChecklistItemUpdate_DTO
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool IsCompleted { get; set; }
|
||||
public string? CompletedBy { get; set; }
|
||||
}
|
||||
|
||||
public class AddChecklistItem_DTO
|
||||
{
|
||||
public int DispatchId { get; set; }
|
||||
public int? WorkOrderId { get; set; }
|
||||
public string? ItemText { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace Data.SeaHavenIndustries
|
|||
public DbSet<Vendor> Vendors { get; set; }
|
||||
public DbSet<Dispatch> Dispatches { get; set; }
|
||||
public DbSet<DispatchWorkOrder> DispatchWorkOrders { get; set; }
|
||||
public DbSet<DispatchChecklistItem> DispatchChecklistItems { get; set; }
|
||||
public DbSet<TaskListTemplate> TaskListTemplates { get; set; }
|
||||
public DbSet<TaskListTemplateItem> TaskListTemplateItems { get; set; }
|
||||
|
||||
|
|
|
|||
2736
Data.SeaHavenIndustries/Migrations/20260417192012_AddDispatchChecklist.Designer.cs
generated
Normal file
2736
Data.SeaHavenIndustries/Migrations/20260417192012_AddDispatchChecklist.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Data.SeaHavenIndustries.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDispatchChecklist : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DispatchChecklistItems",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
DispatchId = table.Column<int>(type: "int", nullable: false),
|
||||
WorkOrderId = table.Column<int>(type: "int", nullable: true),
|
||||
ItemText = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
IsCompleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
CompletedBy = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
CompletedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
SortOrder = table.Column<int>(type: "int", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: true),
|
||||
createdby = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
DeleterUserId = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierUserId = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DispatchChecklistItems", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_DispatchChecklistItems_Dispatches_DispatchId",
|
||||
column: x => x.DispatchId,
|
||||
principalTable: "Dispatches",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_DispatchChecklistItems_workOrders_WorkOrderId",
|
||||
column: x => x.WorkOrderId,
|
||||
principalTable: "workOrders",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DispatchChecklistItems_DispatchId",
|
||||
table: "DispatchChecklistItems",
|
||||
column: "DispatchId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DispatchChecklistItems_WorkOrderId",
|
||||
table: "DispatchChecklistItems",
|
||||
column: "WorkOrderId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "DispatchChecklistItems");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -712,6 +712,65 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.ToTable("Dispatches");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.DispatchChecklistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("CompletedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("CompletedBy")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("CreatedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DeleterUserId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("DispatchId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsCompleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool?>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("ItemText")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("LastModifierUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("WorkOrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("createdby")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DispatchId");
|
||||
|
||||
b.HasIndex("WorkOrderId");
|
||||
|
||||
b.ToTable("DispatchChecklistItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.DispatchWorkOrder", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
|
@ -2217,6 +2276,24 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.Navigation("WorkOrder");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.DispatchChecklistItem", b =>
|
||||
{
|
||||
b.HasOne("Data.SeaHavenIndustries.Dispatch", "Dispatch")
|
||||
.WithMany("ChecklistItems")
|
||||
.HasForeignKey("DispatchId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Data.SeaHavenIndustries.WorkOrder", "WorkOrder")
|
||||
.WithMany()
|
||||
.HasForeignKey("WorkOrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Dispatch");
|
||||
|
||||
b.Navigation("WorkOrder");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.DispatchWorkOrder", b =>
|
||||
{
|
||||
b.HasOne("Data.SeaHavenIndustries.Dispatch", "Dispatch")
|
||||
|
|
@ -2588,6 +2665,8 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.Dispatch", b =>
|
||||
{
|
||||
b.Navigation("ChecklistItems");
|
||||
|
||||
b.Navigation("Comments");
|
||||
|
||||
b.Navigation("DispatchWorkOrders");
|
||||
|
|
|
|||
|
|
@ -26,5 +26,6 @@ namespace Data.SeaHavenIndustries
|
|||
public string? AcceptToken { get; set; }
|
||||
public ICollection<Comments>? Comments { get; set; }
|
||||
public ICollection<DispatchWorkOrder>? DispatchWorkOrders { get; set; }
|
||||
public ICollection<DispatchChecklistItem>? ChecklistItems { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
Data.SeaHavenIndustries/Models/DispatchChecklistItem.cs
Normal file
19
Data.SeaHavenIndustries/Models/DispatchChecklistItem.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.SeaHavenIndustries
|
||||
{
|
||||
public class DispatchChecklistItem : FullAuditEntity
|
||||
{
|
||||
public int DispatchId { get; set; }
|
||||
[ForeignKey(nameof(DispatchId))]
|
||||
public virtual Dispatch? Dispatch { get; set; }
|
||||
public int? WorkOrderId { get; set; }
|
||||
[ForeignKey(nameof(WorkOrderId))]
|
||||
public virtual WorkOrder? WorkOrder { get; set; }
|
||||
public string? ItemText { get; set; }
|
||||
public bool IsCompleted { get; set; }
|
||||
public string? CompletedBy { get; set; }
|
||||
public DateTime? CompletedAt { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue