mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13: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 readonly AmazonDynamoDBClient _dynamo;
|
||||||
private const string WO_TABLE = "WorkOrders";
|
private const string WO_TABLE = "WorkOrders";
|
||||||
private const string COMMENTS_TABLE = "WorkOrderComments";
|
private const string COMMENTS_TABLE = "WorkOrderComments";
|
||||||
|
private const string VENDOR_REPLIES_TABLE = "VendorReplies";
|
||||||
|
|
||||||
public SyncController(ApplicationDbContext db)
|
public SyncController(ApplicationDbContext db)
|
||||||
{
|
{
|
||||||
|
|
@ -239,6 +240,104 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
return Ok(new { updated = wosMissing.Count });
|
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")]
|
[HttpPost("BackfillCommentTypes")]
|
||||||
public async Task<IActionResult> BackfillCommentTypes()
|
public async Task<IActionResult> BackfillCommentTypes()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -672,15 +672,18 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
dispatches = s.Dispatches.Select(d => new {
|
dispatches = s.Dispatches.Select(d => new {
|
||||||
d.Id,
|
d.Id,
|
||||||
|
d.DispatchNumber,
|
||||||
d.PONumber,
|
d.PONumber,
|
||||||
d.NTEAmount,
|
d.NTEAmount,
|
||||||
d.Description,
|
d.Description,
|
||||||
d.Status,
|
d.Status,
|
||||||
d.ScheduledDate,
|
d.ScheduledDate,
|
||||||
|
d.CompletedDate,
|
||||||
d.DispatchedAt,
|
d.DispatchedAt,
|
||||||
d.EmailSent,
|
d.EmailSent,
|
||||||
vendorName = d.Vendor != null ? d.Vendor.CompanyName : "",
|
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()
|
}).ToList()
|
||||||
}).FirstOrDefaultAsync();
|
}).FirstOrDefaultAsync();
|
||||||
if (exist == null)
|
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))
|
if (lastPO != null && lastPO.StartsWith("VPO-") && int.TryParse(lastPO.Substring(4), out var lastNum))
|
||||||
nextPO = lastNum + 1;
|
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 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>();
|
var dispatches = new List<object>();
|
||||||
|
|
||||||
foreach (var vendorId in model.VendorIds)
|
foreach (var vendorId in model.VendorIds)
|
||||||
|
|
@ -1052,13 +1066,16 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
||||||
var poNumber = $"VPO-{nextPO:D5}";
|
var poNumber = $"VPO-{nextPO:D5}";
|
||||||
nextPO++;
|
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
|
var dispatch = new Dispatch
|
||||||
{
|
{
|
||||||
WorkOrderId = model.WorkOrderId,
|
WorkOrderId = model.WorkOrderId,
|
||||||
VendorId = vendorId,
|
VendorId = vendorId,
|
||||||
|
DispatchNumber = dispatchNumber,
|
||||||
PONumber = poNumber,
|
PONumber = poNumber,
|
||||||
NTEAmount = model.NTEAmount,
|
NTEAmount = model.NTEAmount,
|
||||||
Description = model.Description,
|
Description = model.Description,
|
||||||
|
|
@ -1068,7 +1085,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
ReplyToAddress = replyTo
|
ReplyToAddress = replyTo
|
||||||
};
|
};
|
||||||
|
|
||||||
var subject = $"[WO-{workOrder.InternalWONumber}] {workOrder.WorkerOrderTitle}";
|
var subject = $"[WO-{workOrder.InternalWONumber}-{dispatchNumber}] {workOrder.WorkerOrderTitle}";
|
||||||
var locationName = workOrder.Locations?.Name ?? "";
|
var locationName = workOrder.Locations?.Name ?? "";
|
||||||
var locationAddr = workOrder.Locations?.Address ?? "";
|
var locationAddr = workOrder.Locations?.Address ?? "";
|
||||||
|
|
||||||
|
|
@ -1089,7 +1106,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>{model.Description ?? workOrder.Description}</p>
|
<p>{model.Description ?? workOrder.Description}</p>
|
||||||
<hr/>
|
<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);
|
var emailSent = await _sendMessage.SendDispatchEmail(vendor.Email, subject, html, replyTo);
|
||||||
dispatch.EmailSent = emailSent;
|
dispatch.EmailSent = emailSent;
|
||||||
|
|
@ -1107,7 +1125,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
CreatedAt = DateTime.UtcNow
|
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();
|
await _db.SaveChangesAsync();
|
||||||
|
|
@ -1129,19 +1147,158 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
.Select(d => new
|
.Select(d => new
|
||||||
{
|
{
|
||||||
d.Id,
|
d.Id,
|
||||||
|
d.DispatchNumber,
|
||||||
d.PONumber,
|
d.PONumber,
|
||||||
d.NTEAmount,
|
d.NTEAmount,
|
||||||
d.Description,
|
d.Description,
|
||||||
d.Status,
|
d.Status,
|
||||||
|
d.ScheduledDate,
|
||||||
|
d.CompletedDate,
|
||||||
d.DispatchedAt,
|
d.DispatchedAt,
|
||||||
d.EmailSent,
|
d.EmailSent,
|
||||||
vendorName = d.Vendor != null ? d.Vendor.CompanyName : "",
|
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();
|
.ToListAsync();
|
||||||
return Ok(data);
|
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)
|
private static string? ExtractZip(string? address)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(address)) return null;
|
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")
|
b.Property<DateTime?>("DeletionTime")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<int?>("DispatchId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("Documents")
|
b.Property<string>("Documents")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
|
@ -423,6 +426,8 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DispatchId");
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.HasIndex("WorkerOrderId");
|
b.HasIndex("WorkerOrderId");
|
||||||
|
|
@ -635,6 +640,9 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
|
|
||||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime?>("CompletedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
b.Property<DateTime?>("CreatedDate")
|
b.Property<DateTime?>("CreatedDate")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
|
@ -647,6 +655,9 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("DispatchNumber")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<DateTime?>("DispatchedAt")
|
b.Property<DateTime?>("DispatchedAt")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
|
@ -2021,6 +2032,11 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("Data.SeaHavenIndustries.Comments", b =>
|
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")
|
b.HasOne("Data.SeaHavenIndustries.ApplicationUser", "ApplicationUser")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
|
|
@ -2033,6 +2049,8 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
|
|
||||||
b.Navigation("ApplicationUser");
|
b.Navigation("ApplicationUser");
|
||||||
|
|
||||||
|
b.Navigation("Dispatch");
|
||||||
|
|
||||||
b.Navigation("WorkOrder");
|
b.Navigation("WorkOrder");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2422,6 +2440,11 @@ namespace Data.SeaHavenIndustries.Migrations
|
||||||
b.Navigation("Employees");
|
b.Navigation("Employees");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Data.SeaHavenIndustries.Dispatch", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Data.SeaHavenIndustries.Employee", b =>
|
modelBuilder.Entity("Data.SeaHavenIndustries.Employee", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Address");
|
b.Navigation("Address");
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,8 @@ namespace Data.SeaHavenIndustries
|
||||||
public int? WorkerOrderId { get; set; }
|
public int? WorkerOrderId { get; set; }
|
||||||
[ForeignKey(nameof(WorkerOrderId))]
|
[ForeignKey(nameof(WorkerOrderId))]
|
||||||
public virtual WorkOrder? WorkOrder { get; set; }
|
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))]
|
[ForeignKey(nameof(VendorId))]
|
||||||
public virtual Vendor? Vendor { get; set; }
|
public virtual Vendor? Vendor { get; set; }
|
||||||
|
|
||||||
|
public string? DispatchNumber { get; set; }
|
||||||
public string? PONumber { get; set; }
|
public string? PONumber { get; set; }
|
||||||
public decimal? NTEAmount { get; set; }
|
public decimal? NTEAmount { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public string? Status { get; set; }
|
public string? Status { get; set; }
|
||||||
public DateTime? ScheduledDate { get; set; }
|
public DateTime? ScheduledDate { get; set; }
|
||||||
|
public DateTime? CompletedDate { get; set; }
|
||||||
public DateTime? DispatchedAt { get; set; }
|
public DateTime? DispatchedAt { get; set; }
|
||||||
public bool EmailSent { get; set; }
|
public bool EmailSent { get; set; }
|
||||||
public string? ReplyToAddress { get; set; }
|
public string? ReplyToAddress { get; set; }
|
||||||
|
public ICollection<Comments>? Comments { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue