mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
Add dispatch detail modal backend + vendor reply sync
- Add DispatchNumber and CompletedDate to Dispatch model - Add DispatchId to Comments for per-dispatch vendor threads - GetDispatchById endpoint with vendor communication thread - UpdateDispatch endpoint for status, NTE, dates, description - AddDispatchComment endpoint — saves comment + sends email to vendor with sender name - BackfillDispatchNumbers endpoint for existing dispatches - SyncVendorReplies endpoint — pulls from DynamoDB VendorReplies table - Fix reply-to address to include dispatch number - Include sender name in dispatch and comment emails
This commit is contained in:
parent
17590daf9d
commit
63f76e9b2c
8 changed files with 2884 additions and 6 deletions
|
|
@ -16,6 +16,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
private readonly AmazonDynamoDBClient _dynamo;
|
||||
private const string WO_TABLE = "WorkOrders";
|
||||
private const string COMMENTS_TABLE = "WorkOrderComments";
|
||||
private const string VENDOR_REPLIES_TABLE = "VendorReplies";
|
||||
|
||||
public SyncController(ApplicationDbContext db)
|
||||
{
|
||||
|
|
@ -239,6 +240,104 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
return Ok(new { updated = wosMissing.Count });
|
||||
}
|
||||
|
||||
[HttpPost("BackfillDispatchNumbers")]
|
||||
public async Task<IActionResult> BackfillDispatchNumbers()
|
||||
{
|
||||
var missing = await _db.Dispatches
|
||||
.Where(d => d.DispatchNumber == null || d.DispatchNumber == "")
|
||||
.OrderBy(d => d.Id)
|
||||
.ToListAsync();
|
||||
if (missing.Count == 0) return Ok(new { updated = 0 });
|
||||
|
||||
int next = 1;
|
||||
var last = await _db.Dispatches
|
||||
.Where(d => d.DispatchNumber != null && d.DispatchNumber != "")
|
||||
.OrderByDescending(d => d.DispatchNumber)
|
||||
.Select(d => d.DispatchNumber)
|
||||
.FirstOrDefaultAsync();
|
||||
if (last != null && last.StartsWith("DSP-") && int.TryParse(last.Substring(4), out var n))
|
||||
next = n + 1;
|
||||
|
||||
foreach (var d in missing)
|
||||
{
|
||||
d.DispatchNumber = $"DSP-{next:D5}";
|
||||
next++;
|
||||
}
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { updated = missing.Count });
|
||||
}
|
||||
|
||||
[HttpPost("VendorReplies")]
|
||||
public async Task<IActionResult> SyncVendorReplies()
|
||||
{
|
||||
var synced = 0;
|
||||
var created = 0;
|
||||
var skipped = 0;
|
||||
Dictionary<string, AttributeValue>? lastKey = null;
|
||||
|
||||
do
|
||||
{
|
||||
var request = new ScanRequest
|
||||
{
|
||||
TableName = VENDOR_REPLIES_TABLE,
|
||||
Limit = 100,
|
||||
ExclusiveStartKey = lastKey
|
||||
};
|
||||
|
||||
var response = await _dynamo.ScanAsync(request);
|
||||
|
||||
foreach (var item in response.Items)
|
||||
{
|
||||
var replyId = GetString(item, "reply_id");
|
||||
var woNumber = GetString(item, "internal_wo_number");
|
||||
var dispatchNumber = GetString(item, "dispatch_number");
|
||||
|
||||
if (string.IsNullOrEmpty(replyId) || string.IsNullOrEmpty(woNumber))
|
||||
continue;
|
||||
|
||||
var alreadyExists = await _db.Comments
|
||||
.AnyAsync(c => c.ExternalCommentId == replyId);
|
||||
if (alreadyExists) { skipped++; synced++; continue; }
|
||||
|
||||
var workOrder = await _db.workOrders
|
||||
.FirstOrDefaultAsync(w => w.InternalWONumber == woNumber);
|
||||
if (workOrder == null) { skipped++; continue; }
|
||||
|
||||
int? dispatchId = null;
|
||||
if (!string.IsNullOrWhiteSpace(dispatchNumber))
|
||||
{
|
||||
var dispatch = await _db.Dispatches
|
||||
.FirstOrDefaultAsync(d => d.DispatchNumber == dispatchNumber && d.WorkOrderId == workOrder.Id);
|
||||
dispatchId = dispatch?.Id;
|
||||
}
|
||||
|
||||
var comment = new Comments
|
||||
{
|
||||
ExternalCommentId = replyId,
|
||||
WorkerOrderId = workOrder.Id,
|
||||
DispatchId = dispatchId,
|
||||
Commenttext = GetString(item, "reply_text"),
|
||||
Commenter = GetString(item, "sender_email"),
|
||||
CommentType = "vendor",
|
||||
RecordType = "vendor_reply",
|
||||
CreatedDate = ParseDate(GetString(item, "received_at")) ?? DateTime.UtcNow,
|
||||
};
|
||||
|
||||
_db.Comments.Add(comment);
|
||||
created++;
|
||||
synced++;
|
||||
|
||||
if (synced % 50 == 0)
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
lastKey = response.LastEvaluatedKey;
|
||||
} while (lastKey != null && lastKey.Count > 0);
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { synced, created, skipped });
|
||||
}
|
||||
|
||||
[HttpPost("BackfillCommentTypes")]
|
||||
public async Task<IActionResult> BackfillCommentTypes()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -672,15 +672,18 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
}).ToList(),
|
||||
dispatches = s.Dispatches.Select(d => new {
|
||||
d.Id,
|
||||
d.DispatchNumber,
|
||||
d.PONumber,
|
||||
d.NTEAmount,
|
||||
d.Description,
|
||||
d.Status,
|
||||
d.ScheduledDate,
|
||||
d.CompletedDate,
|
||||
d.DispatchedAt,
|
||||
d.EmailSent,
|
||||
vendorName = d.Vendor != null ? d.Vendor.CompanyName : "",
|
||||
vendorEmail = d.Vendor != null ? d.Vendor.Email : ""
|
||||
vendorEmail = d.Vendor != null ? d.Vendor.Email : "",
|
||||
vendorId = d.VendorId
|
||||
}).ToList()
|
||||
}).FirstOrDefaultAsync();
|
||||
if (exist == null)
|
||||
|
|
@ -1042,7 +1045,18 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
if (lastPO != null && lastPO.StartsWith("VPO-") && int.TryParse(lastPO.Substring(4), out var lastNum))
|
||||
nextPO = lastNum + 1;
|
||||
|
||||
var lastDSP = await _db.Dispatches
|
||||
.Where(d => d.DispatchNumber != null)
|
||||
.OrderByDescending(d => d.DispatchNumber)
|
||||
.Select(d => d.DispatchNumber)
|
||||
.FirstOrDefaultAsync();
|
||||
int nextDSP = 1;
|
||||
if (lastDSP != null && lastDSP.StartsWith("DSP-") && int.TryParse(lastDSP.Substring(4), out var lastDspNum))
|
||||
nextDSP = lastDspNum + 1;
|
||||
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var currentUser = userId != null ? await _db.Users.FindAsync(userId) : null;
|
||||
var senderName = currentUser != null ? (currentUser.FirstName + " " + currentUser.LastName).Trim() : "";
|
||||
var dispatches = new List<object>();
|
||||
|
||||
foreach (var vendorId in model.VendorIds)
|
||||
|
|
@ -1052,13 +1066,16 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
|
||||
var poNumber = $"VPO-{nextPO:D5}";
|
||||
nextPO++;
|
||||
var dispatchNumber = $"DSP-{nextDSP:D5}";
|
||||
nextDSP++;
|
||||
|
||||
var replyTo = $"wo-{workOrder.InternalWONumber}@int.seahaven.com";
|
||||
var replyTo = $"wo-{workOrder.InternalWONumber}-{dispatchNumber}@int.seahaven.com";
|
||||
|
||||
var dispatch = new Dispatch
|
||||
{
|
||||
WorkOrderId = model.WorkOrderId,
|
||||
VendorId = vendorId,
|
||||
DispatchNumber = dispatchNumber,
|
||||
PONumber = poNumber,
|
||||
NTEAmount = model.NTEAmount,
|
||||
Description = model.Description,
|
||||
|
|
@ -1068,7 +1085,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
ReplyToAddress = replyTo
|
||||
};
|
||||
|
||||
var subject = $"[WO-{workOrder.InternalWONumber}] {workOrder.WorkerOrderTitle}";
|
||||
var subject = $"[WO-{workOrder.InternalWONumber}-{dispatchNumber}] {workOrder.WorkerOrderTitle}";
|
||||
var locationName = workOrder.Locations?.Name ?? "";
|
||||
var locationAddr = workOrder.Locations?.Address ?? "";
|
||||
|
||||
|
|
@ -1089,7 +1106,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
<h3>Description</h3>
|
||||
<p>{model.Description ?? workOrder.Description}</p>
|
||||
<hr/>
|
||||
<p style='color:#999;font-size:12px;'>Reply to this email to communicate about this work order.</p>";
|
||||
<br/><p style='color:#666;font-size:13px;'>{senderName}<br/>Sea Haven Industries</p>
|
||||
<hr/><p style='color:#999;font-size:12px;'>Reply to this email to communicate about this work order.</p>";
|
||||
|
||||
var emailSent = await _sendMessage.SendDispatchEmail(vendor.Email, subject, html, replyTo);
|
||||
dispatch.EmailSent = emailSent;
|
||||
|
|
@ -1107,7 +1125,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
dispatches.Add(new { dispatch.Id, poNumber, vendorName = vendor.CompanyName, dispatch.Status });
|
||||
dispatches.Add(new { dispatch.Id, dispatchNumber, poNumber, vendorName = vendor.CompanyName, dispatch.Status });
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
|
|
@ -1129,19 +1147,158 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
.Select(d => new
|
||||
{
|
||||
d.Id,
|
||||
d.DispatchNumber,
|
||||
d.PONumber,
|
||||
d.NTEAmount,
|
||||
d.Description,
|
||||
d.Status,
|
||||
d.ScheduledDate,
|
||||
d.CompletedDate,
|
||||
d.DispatchedAt,
|
||||
d.EmailSent,
|
||||
vendorName = d.Vendor != null ? d.Vendor.CompanyName : "",
|
||||
vendorEmail = d.Vendor != null ? d.Vendor.Email : ""
|
||||
vendorEmail = d.Vendor != null ? d.Vendor.Email : "",
|
||||
vendorId = d.VendorId
|
||||
})
|
||||
.ToListAsync();
|
||||
return Ok(data);
|
||||
}
|
||||
|
||||
[HttpGet("GetDispatch/{id}")]
|
||||
public async Task<IActionResult> GetDispatchById(int id)
|
||||
{
|
||||
var d = await _db.Dispatches
|
||||
.Include(x => x.Vendor)
|
||||
.Include(x => x.WorkOrder)
|
||||
.Where(x => x.Id == id)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.DispatchNumber,
|
||||
x.PONumber,
|
||||
x.NTEAmount,
|
||||
x.Description,
|
||||
x.Status,
|
||||
x.ScheduledDate,
|
||||
x.CompletedDate,
|
||||
x.DispatchedAt,
|
||||
x.EmailSent,
|
||||
x.WorkOrderId,
|
||||
woNumber = x.WorkOrder != null ? x.WorkOrder.InternalWONumber : "",
|
||||
woTitle = x.WorkOrder != null ? x.WorkOrder.WorkerOrderTitle : "",
|
||||
vendorName = x.Vendor != null ? x.Vendor.CompanyName : "",
|
||||
vendorEmail = x.Vendor != null ? x.Vendor.Email : "",
|
||||
vendorId = x.VendorId,
|
||||
comments = _db.Comments
|
||||
.Where(c => c.DispatchId == x.Id)
|
||||
.OrderBy(c => c.CreatedDate)
|
||||
.Select(c => new
|
||||
{
|
||||
c.Id,
|
||||
c.CreatedDate,
|
||||
c.Commenttext,
|
||||
c.Commenter,
|
||||
c.CommentType,
|
||||
userName = c.ApplicationUser != null ? c.ApplicationUser.FirstName + " " + c.ApplicationUser.LastName : ""
|
||||
}).ToList()
|
||||
}).FirstOrDefaultAsync();
|
||||
|
||||
if (d == null)
|
||||
return NotFound(new Response { Status = "Error", Message = "Dispatch not found" });
|
||||
return Ok(d);
|
||||
}
|
||||
|
||||
[HttpPost("UpdateDispatch")]
|
||||
public async Task<IActionResult> UpdateDispatch([FromBody] UpdateDispatch_DTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dispatch = await _db.Dispatches.FindAsync(model.Id);
|
||||
if (dispatch == null)
|
||||
return BadRequest(new Response { Status = "Error", Message = "Dispatch not found" });
|
||||
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
|
||||
if (dispatch.Status != model.Status)
|
||||
{
|
||||
_db.WorkOrderAuditLogs.Add(new WorkOrderAuditLog
|
||||
{
|
||||
WorkOrderId = dispatch.WorkOrderId,
|
||||
UserId = userId,
|
||||
FieldName = $"Dispatch {dispatch.DispatchNumber} Status",
|
||||
OldValue = dispatch.Status ?? "",
|
||||
NewValue = model.Status ?? "",
|
||||
Action = "dispatch_status_change",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
||||
dispatch.Status = model.Status;
|
||||
dispatch.NTEAmount = model.NTEAmount;
|
||||
dispatch.ScheduledDate = model.ScheduledDate;
|
||||
dispatch.CompletedDate = model.CompletedDate;
|
||||
dispatch.Description = model.Description;
|
||||
|
||||
if (model.Status == "Completed" && dispatch.CompletedDate == null)
|
||||
dispatch.CompletedDate = DateTime.UtcNow;
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { message = "Dispatch updated" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("AddDispatchComment")]
|
||||
public async Task<IActionResult> AddDispatchComment([FromBody] DispatchComment_DTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dispatch = await _db.Dispatches.Include(d => d.Vendor).Include(d => d.WorkOrder)
|
||||
.FirstOrDefaultAsync(d => d.Id == model.DispatchId);
|
||||
if (dispatch == null)
|
||||
return BadRequest(new Response { Status = "Error", Message = "Dispatch not found" });
|
||||
|
||||
var userId = _httpContext?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? "";
|
||||
|
||||
var comment = new Comments
|
||||
{
|
||||
CreatedDate = DateTime.UtcNow,
|
||||
UserId = userId,
|
||||
WorkerOrderId = dispatch.WorkOrderId,
|
||||
DispatchId = dispatch.Id,
|
||||
Commenttext = model.Text,
|
||||
CommentType = "vendor",
|
||||
};
|
||||
_db.Comments.Add(comment);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
var user = await _db.Users.FindAsync(userId);
|
||||
var senderName = user != null ? (user.FirstName + " " + user.LastName).Trim() : "";
|
||||
|
||||
if (model.SendEmail && dispatch.Vendor?.Email != null && dispatch.WorkOrder != null)
|
||||
{
|
||||
var subject = $"[WO-{dispatch.WorkOrder.InternalWONumber}-{dispatch.DispatchNumber}] {dispatch.WorkOrder.WorkerOrderTitle}";
|
||||
var html = $"<p>{model.Text}</p><br/><p style='color:#666;font-size:13px;'>{senderName}<br/>Sea Haven Industries</p><hr/><p style='color:#999;font-size:12px;'>Reply to this email to respond.</p>";
|
||||
await _sendMessage.SendDispatchEmail(dispatch.Vendor.Email, subject, html, dispatch.ReplyToAddress);
|
||||
}
|
||||
return Ok(new
|
||||
{
|
||||
comment.Id,
|
||||
comment.CreatedDate,
|
||||
comment.Commenttext,
|
||||
comment.CommentType,
|
||||
userName = user != null ? (user.FirstName + " " + user.LastName).Trim() : ""
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
private static string? ExtractZip(string? address)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address)) return null;
|
||||
|
|
|
|||
19
Api.SeaHavenIndustries/DTOs/UpdateDispatch_DTO.cs
Normal file
19
Api.SeaHavenIndustries/DTOs/UpdateDispatch_DTO.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
namespace Api.SeaHavenIndustries.DTOs
|
||||
{
|
||||
public class UpdateDispatch_DTO
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public decimal? NTEAmount { get; set; }
|
||||
public DateTime? ScheduledDate { get; set; }
|
||||
public DateTime? CompletedDate { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
|
||||
public class DispatchComment_DTO
|
||||
{
|
||||
public int DispatchId { get; set; }
|
||||
public string? Text { get; set; }
|
||||
public bool SendEmail { get; set; } = true;
|
||||
}
|
||||
}
|
||||
2504
Data.SeaHavenIndustries/Migrations/20260417171152_AddDispatchNumberAndCommentDispatchId.Designer.cs
generated
Normal file
2504
Data.SeaHavenIndustries/Migrations/20260417171152_AddDispatchNumberAndCommentDispatchId.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 AddDispatchNumberAndCommentDispatchId : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "CompletedDate",
|
||||
table: "Dispatches",
|
||||
type: "datetime2",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "DispatchNumber",
|
||||
table: "Dispatches",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "DispatchId",
|
||||
table: "Comments",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Comments_DispatchId",
|
||||
table: "Comments",
|
||||
column: "DispatchId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Comments_Dispatches_DispatchId",
|
||||
table: "Comments",
|
||||
column: "DispatchId",
|
||||
principalTable: "Dispatches",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Comments_Dispatches_DispatchId",
|
||||
table: "Comments");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Comments_DispatchId",
|
||||
table: "Comments");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CompletedDate",
|
||||
table: "Dispatches");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DispatchNumber",
|
||||
table: "Dispatches");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DispatchId",
|
||||
table: "Comments");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -394,6 +394,9 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("DispatchId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Documents")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
|
|
@ -423,6 +426,8 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DispatchId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("WorkerOrderId");
|
||||
|
|
@ -635,6 +640,9 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("CompletedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("CreatedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
|
|
@ -647,6 +655,9 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.Property<string>("Description")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DispatchNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("DispatchedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
|
|
@ -2021,6 +2032,11 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.Comments", b =>
|
||||
{
|
||||
b.HasOne("Data.SeaHavenIndustries.Dispatch", "Dispatch")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("DispatchId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.HasOne("Data.SeaHavenIndustries.ApplicationUser", "ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
|
|
@ -2033,6 +2049,8 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
b.Navigation("ApplicationUser");
|
||||
|
||||
b.Navigation("Dispatch");
|
||||
|
||||
b.Navigation("WorkOrder");
|
||||
});
|
||||
|
||||
|
|
@ -2422,6 +2440,11 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
b.Navigation("Employees");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.Dispatch", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Data.SeaHavenIndustries.Employee", b =>
|
||||
{
|
||||
b.Navigation("Address");
|
||||
|
|
|
|||
|
|
@ -18,5 +18,8 @@ namespace Data.SeaHavenIndustries
|
|||
public int? WorkerOrderId { get; set; }
|
||||
[ForeignKey(nameof(WorkerOrderId))]
|
||||
public virtual WorkOrder? WorkOrder { get; set; }
|
||||
public int? DispatchId { get; set; }
|
||||
[ForeignKey(nameof(DispatchId))]
|
||||
public virtual Dispatch? Dispatch { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,16 @@ namespace Data.SeaHavenIndustries
|
|||
[ForeignKey(nameof(VendorId))]
|
||||
public virtual Vendor? Vendor { get; set; }
|
||||
|
||||
public string? DispatchNumber { get; set; }
|
||||
public string? PONumber { get; set; }
|
||||
public decimal? NTEAmount { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public DateTime? ScheduledDate { get; set; }
|
||||
public DateTime? CompletedDate { get; set; }
|
||||
public DateTime? DispatchedAt { get; set; }
|
||||
public bool EmailSent { get; set; }
|
||||
public string? ReplyToAddress { get; set; }
|
||||
public ICollection<Comments>? Comments { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue