shoc-backend/Api.SeaHavenIndustries/Controllers/WorkOrderController.cs
Adam Moussa e1f57d3fb2 Add comment types, audit logging, and WorkOrderAuditLog table
- Add CommentType field to Comments (customer, vendor, internal)
- Add Status field to EditWorkorder_DTO
- Create WorkOrderAuditLog model tracking field-level changes
- Log all field changes on work order edit and status change
- Include commentType and auditLog in GetWorkorderById response
- Set CommentType=customer on synced comments from DynamoDB
- Add BackfillCommentTypes endpoint for existing data
2026-04-16 18:09:57 -04:00

911 lines
44 KiB
C#

using Api.SeaHavenIndustries.DTOs;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualBasic;
using SendGrid.Helpers.Mail;
using System.IO;
using System.Net.Http.Headers;
using System.Security.Claims;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Api.SeaHavenIndustries.Controllers
{
// [Authorize]
[ApiController]
[Route("api/WorkOrder")]
[Route("api/workorders")]
public class WorkOrderController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly ApplicationDbContext _db;
private readonly IWebHostEnvironment _webHostEnvironment;
IHttpContextAccessor _httpContext;
public WorkOrderController(UserManager<ApplicationUser> userManager, ApplicationDbContext db, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContext)
{
_userManager = userManager;
_db = db;
_webHostEnvironment = webHostEnvironment;
_httpContext = httpContext;
}
[HttpPost]
[Route("AddWorkorder")]
public async Task<IActionResult> Addworkorder([FromBody] Workorder_DTO model)
{
try
{
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
WorkOrder workOrder = new WorkOrder();
workOrder.WorkerOrderNumber = model.WorkerOrderNumber;
workOrder.WorkerOrderTitle = model.WorkerOrderTitle;
workOrder.Description = model.Description;
workOrder.TT = model.TT;
workOrder.PO = model.PO;
workOrder.AssignTo = model.AssignTo;
workOrder.DueDate = model.DueDate;
workOrder.Priority = model.Priority;
workOrder.istemplate = model.istemplate;
//workOrder.CategoryId = model.CategoryId;
workOrder.LocationId = model.LocationId;
workOrder.Status = "Open";
workOrder.istemplate = model.istemplate;
workOrder.BeforPhotoIssue = model.BeforPhotoIssue;
workOrder.AfterPhotoIssue = model.AfterPhotoIssue;
workOrder.SignOffName = model.SignOffName;
workOrder.SignOffSignature = model.SignOffSignature;
workOrder.WorkOrderContacts = workOrder.WorkOrderContacts == null ? new List<WorkOrderContacts>() : workOrder.WorkOrderContacts;
List<int> contactIds = model.GetContactIds();
workOrder.WorkOrderCategories = workOrder.WorkOrderCategories == null ? new List<WorkOrderCategories>() : workOrder.WorkOrderCategories;
List<int> categoryIds = model.GetCategoryIds();
// Create new records for the associations (pseudo-code)
foreach (int contactId in contactIds)
{
// Create association with contact
workOrder.WorkOrderContacts.Add(new WorkOrderContacts { ContactId = contactId });
}
foreach (int categoryId in categoryIds)
{
// Create association with category
workOrder.WorkOrderCategories.Add(new WorkOrderCategories { CategoryId = categoryId });
}
#region Images of workorder
workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List<WorkOrderAttachments>() : workOrder.workOrderAttachments;
if (model.Attachments != null)
{
foreach (var attachment in model.Attachments)
{
string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await attachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath });
}
}
if (model.BeforPhotoAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.BeforPhotoAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.BeforPhotoAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.BeforPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
if (model.AfterPhotoAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.AfterPhotoAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.AfterPhotoAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.AfterPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
if (model.SignOffAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.SignOffAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.SignOffAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.SignOffAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
#endregion
_db.Add(workOrder);
_db.SaveChanges();
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
}
}
[HttpPost]
[HttpPut("{id:int}")]
[Route("EditWorkorder")]
public async Task<IActionResult> Editworkorder([FromBody] EditWorkorder_DTO model)
{
try
{
var workOrder = _db.workOrders.Where(w => w.Id == model.Id).FirstOrDefault();
if (workOrder == null)
return BadRequest(new Response { Status = "Error", Message = "Work order not found" });
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var now = DateTime.UtcNow;
void LogChange(string field, string? oldVal, string? newVal)
{
if (oldVal == newVal) return;
_db.WorkOrderAuditLogs.Add(new WorkOrderAuditLog
{
WorkOrderId = workOrder.Id,
UserId = userId,
FieldName = field,
OldValue = oldVal ?? "",
NewValue = newVal ?? "",
Action = "edit",
CreatedAt = now
});
}
LogChange("WorkOrderNumber", workOrder.WorkerOrderNumber, model.WorkerOrderNumber);
LogChange("Title", workOrder.WorkerOrderTitle, model.WorkerOrderTitle);
LogChange("Description", workOrder.Description, model.Description);
LogChange("TT", workOrder.TT, model.TT);
LogChange("PO", workOrder.PO, model.PO);
LogChange("AssignTo", workOrder.AssignTo, model.AssignTo);
LogChange("DueDate", workOrder.DueDate?.ToString("yyyy-MM-dd"), model.DueDate?.ToString("yyyy-MM-dd"));
LogChange("Priority", workOrder.Priority, model.Priority);
LogChange("LocationId", workOrder.LocationId?.ToString(), model.LocationId?.ToString());
LogChange("Status", workOrder.Status, model.Status);
workOrder.WorkerOrderNumber = model.WorkerOrderNumber;
workOrder.WorkerOrderTitle = model.WorkerOrderTitle;
workOrder.Description = model.Description;
workOrder.TT = model.TT;
workOrder.PO = model.PO;
workOrder.AssignTo = model.AssignTo;
workOrder.DueDate = model.DueDate;
workOrder.Priority = model.Priority;
workOrder.LocationId = model.LocationId;
workOrder.Status = model.Status;
workOrder.BeforPhotoIssue = model.BeforPhotoIssue;
workOrder.AfterPhotoIssue = model.AfterPhotoIssue;
workOrder.SignOffName = model.SignOffName;
workOrder.SignOffSignature = model.SignOffSignature;
var existcontact = _db.WorkOrderContacts.Where(w => w.WorkorderId == model.Id).ToList();
if (existcontact.Count() > 0)
{
_db.WorkOrderContacts.RemoveRange(existcontact);
}
var existcategory = _db.workOrderCategories.Where(w => w.WorkorderId == model.Id).ToList();
if (existcategory.Count() > 0)
{
_db.workOrderCategories.RemoveRange(existcategory);
}
workOrder.WorkOrderContacts = workOrder.WorkOrderContacts == null ? new List<WorkOrderContacts>() : workOrder.WorkOrderContacts;
List<int> contactIds = model.GetContactIds();
workOrder.WorkOrderCategories = workOrder.WorkOrderCategories == null ? new List<WorkOrderCategories>() : workOrder.WorkOrderCategories;
List<int> categoryIds = model.GetCategoryIds();
// Create new records for the associations (pseudo-code)
foreach (int contactId in contactIds)
{
// Create association with contact
workOrder.WorkOrderContacts.Add(new WorkOrderContacts { ContactId = contactId });
}
foreach (int categoryId in categoryIds)
{
// Create association with category
workOrder.WorkOrderCategories.Add(new WorkOrderCategories { CategoryId = categoryId });
}
#region Images of workorder
workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List<WorkOrderAttachments>() : workOrder.workOrderAttachments;
if (model.Attachments != null)
{
foreach (var attachment in model.Attachments)
{
string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
using (var ms = System.IO.File.Create(fullPath))
{
await attachment.CopyToAsync(ms);
}
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath });
}
}
if (model.BeforPhotoAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.BeforPhotoAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.BeforPhotoAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.BeforPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
if (model.AfterPhotoAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.AfterPhotoAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.AfterPhotoAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.AfterPhotoAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
if (model.SignOffAttachment != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.SignOffAttachment.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.SignOffAttachment.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
workOrder.SignOffAttachment = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
#endregion
_db.SaveChanges();
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200" });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
}
}
// -----------------------------------
// GET: api/WorkOrder/GetWorkOrderList
// -----------------------------------
[HttpGet("GetWorkOrderList")]
public IActionResult GetWorkOrderList(string? search = "", int page = 1, int pageSize = 12)
{
search ??= "";
var query = _db.workOrders
.Include(w => w.Locations)
.Include(w => w.AssignToUser)
.Where(w => w.istemplate != true);
if (!string.IsNullOrWhiteSpace(search))
{
var s = search.ToLower();
query = query.Where(w =>
(w.WorkerOrderNumber ?? "").ToLower().Contains(s) ||
(w.WorkerOrderTitle ?? "").ToLower().Contains(s) ||
(w.Locations.Title ?? "").ToLower().Contains(s) ||
(w.Locations.Name ?? "").ToLower().Contains(s)
);
}
var totalCount = query.Count();
var data = query
.OrderByDescending(w => w.Id)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(w => new
{
id = w.Id,
workOrderNumber = w.WorkerOrderNumber,
number = w.WorkerOrderNumber,
title = w.WorkerOrderTitle,
location = w.Locations != null ? w.Locations.Name : "",
locationName = w.Locations != null ? w.Locations.Name : "",
priority = w.Priority,
status = w.Status,
createdDate = w.CreatedDate,
dueDate = w.DueDate,
assignedTo = w.AssignToUser != null ? w.AssignToUser.FirstName + " " + w.AssignToUser.LastName : "",
employeeName = w.AssignToUser != null ? w.AssignToUser.FirstName + " " + w.AssignToUser.LastName : ""
})
.ToList();
var viewModel = new Pagination_DTO
{
Data = data,
PageNumber = page,
PageSize = pageSize,
TotalCount = totalCount,
TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize)
};
return Ok(viewModel);
}
[HttpDelete]
[Route("DeleteWorkorder")]
public IActionResult Deleteworkorder([FromBody] EditWorkorder_DTO model)
{
int id = model.Id.HasValue ? model.Id.Value : 0;
if (id == 0)
{
return BadRequest("Id is required");
}
try
{
var exist = _db.workOrders.Where(w => w.Id == id).FirstOrDefault();
if (exist != null)
{
var quotes = _db.Quotes.Where(w => w.WorkorderId == id).ToList();
if (quotes.Count() > 0)
{
foreach (var itm in quotes)
{
var existquotes = _db.Quotes.Where(w => w.Id == itm.Id).FirstOrDefault();
existquotes.WorkorderId = null;
}
}
var attachments = _db.workOrderAttachments.Where(w => w.WorkorderId == id).ToList();
if (attachments.Count() > 0)
{
_db.RemoveRange(attachments);
}
var contacts = _db.WorkOrderContacts.Where(w => w.WorkorderId == id).ToList();
if (contacts.Count() > 0)
{
_db.RemoveRange(contacts);
}
var category = _db.workOrderCategories.Where(w => w.WorkorderId == id).ToList();
if (category.Count() > 0)
{
_db.RemoveRange(category);
}
var comments = _db.Comments.Where(w => w.WorkerOrderId == id).ToList();
if (comments.Count() > 0)
{
_db.RemoveRange(comments);
}
_db.Remove(exist);
}
else
{
return BadRequest("ID not matched!");
}
_db.SaveChanges();
return Ok(new DataResponse { Message = "Removed Successfully", Status = "200" });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
}
}
[HttpGet]
[Route("GetFilteredWorkorder")]
public IActionResult GetFilteredWorkorder(
[FromQuery] string[] assignto,
[FromQuery] int[]? location,
[FromQuery] string[]? priority,
[FromQuery] string[]? status,
[FromQuery] string[]? duedate,
[FromQuery] string search = "",
[FromQuery] string sort = "Sort Order",
[FromQuery] string sortby = "Sort By",
int page = 1,
int pageSize = 10)
{
try
{
IQueryable<WorkOrder> query = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations);
if (!string.IsNullOrEmpty(search))
{
var s = search.ToLower();
query = query.Where(w =>
(w.WorkerOrderTitle ?? "").ToLower().Contains(s) ||
(w.WorkerOrderNumber ?? "").ToLower().Contains(s) ||
(w.Locations != null && (w.Locations.Title ?? "").ToLower().Contains(s)));
}
if (assignto != null && assignto.Length > 0)
{
if (assignto[0] != "" && assignto[0] != null)
query = query.Where(w => assignto.Contains(w.AssignTo));
}
if (location != null && location.Length > 0)
{
if (location[0] != 0)
query = query.Where(w => location.Contains(w.LocationId ?? 0));
}
if (priority != null && priority.Length > 0)
{
if (priority[0] != "" && priority[0] != null)
query = query.Where(w => priority.Contains(w.Priority));
}
if (status != null && status.Length > 0)
{
if (status[0] != "" && status[0] != null)
query = query.Where(w => status.Contains(w.Status));
}
var data = query.ToList();
// Perform client-side filtering for due dates
data = data.Where(w =>
duedate == null || duedate.Length == 0 || duedate[0] == null ||
duedate.Any(dd => w.DueDate.HasValue && CheckDueDate(dd, w.DueDate.Value.Date, DateTime.UtcNow.Date))).ToList();
// Apply sorting
if (!string.IsNullOrEmpty(sort) && !string.IsNullOrEmpty(sortby) && sortby != "")
{
switch (sortby)
{
case "Name":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.WorkerOrderTitle).ToList() : data.OrderByDescending(w => w.WorkerOrderTitle).ToList();
break;
case "Due Date":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.DueDate).ToList() : data.OrderByDescending(w => w.DueDate).ToList();
break;
case "Severity":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.Priority).ToList() : data.OrderByDescending(w => w.Priority).ToList();
break;
default:
// Handle default case or throw an exception
break;
}
}
var totalCount = data.Count();
var pagedData = data
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, Name = s.Locations != null ? s.Locations.Name : "" })
.OrderByDescending(d => d.Name)
.ToList();
var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize);
// Create a view model containing the paged items and pagination metadata
var viewModel = new Pagination_DTO
{
Data = pagedData,
PageNumber = page,
PageSize = pageSize,
TotalCount = totalCount,
TotalPages = totalPages1
};
return Ok(viewModel);
}
catch (Exception ex)
{
// Handle exception and return a default result or an error response
return StatusCode(500, "Internal Server Error");
}
}
[HttpGet("{id:int}")]
[HttpGet("GetWorkorderById")]
public async Task<IActionResult> GetWorkorderById(int id)
{
var exist = await _db.workOrders.Include(w => w.Locations).Include(w => w.Comments).Include(w => w.Quotes).Where(w => w.Id == id).Select(s => new
{
s.Id,
s.WorkerOrderNumber,
title = s.WorkerOrderTitle,
s.Description,
s.CreatedDate,
s.DueDate,
s.Status,
assignee = s.AssignToUser != null ? s.AssignToUser.FirstName : "",
location = s.Locations != null ? s.Locations.Name : "",
locationId = s.LocationId,
priority = s.Priority,
s.PO,
s.TT,
poc = s.WorkOrderContacts.Select(c => new { c.Id, name = c.POC != null ? (c.POC.FirstName + " " + c.POC.LastName).Trim() : "", email = c.POC != null ? c.POC.Email : "", phone = c.POC != null ? c.POC.PhoneNumber : "" }),
category = s.WorkOrderCategories.Select(c => new { c.Id, name = c.Category != null ? c.Category.Name : "" }),
Attachments = s.workOrderAttachments.Select(a => new { a.Id, attachment = a.Attachments }),
s.BeforPhotoIssue,
s.BeforPhotoAttachment,
s.AfterPhotoIssue,
s.AfterPhotoAttachment,
s.SignOffName,
s.SignOffAttachment,
s.SignOffSignature,
Comments = s.Comments.Select(c => new { c.Id, c.CreatedDate, c.Commenttext, c.Commenter, c.RecordType, c.CommentType, c.Documents, userName = c.ApplicationUser != null ? c.ApplicationUser.FirstName : "" }),
quotes = s.Quotes.Select(q => new { code = q.QuotId, q.Id }),
auditLog = _db.WorkOrderAuditLogs
.Where(a => a.WorkOrderId == s.Id)
.OrderByDescending(a => a.CreatedAt)
.Select(a => new {
a.Id,
a.FieldName,
a.OldValue,
a.NewValue,
a.Action,
a.CreatedAt,
userName = a.User != null ? a.User.FirstName + " " + a.User.LastName : ""
}).ToList()
}).FirstOrDefaultAsync();
if (exist == null)
{
return BadRequest(new Response { Status = "Error", Message = "ID not found!" });
}
else
{
return Ok(exist);
}
}
[HttpGet]
[Route("GetFilteredWorkorder2")]
public IActionResult GetFilteredWorkorder2([FromQuery] string[] assignto, [FromQuery] int[]? location, [FromQuery] string[]? priority, [FromQuery] string[]? status, [FromQuery] string[]? duedate, [FromQuery] string search = "", [FromQuery] string sort = "Sort Order", [FromQuery] string sortby = "Sort By", int page = 1, int pageSize = 10)
{
try
{
var totalCount = _db.workOrders.Where(w => w.istemplate != true).Count();
if (sort == "Sort Order" && sortby == "Sort By" && assignto.Count() == 0 && (duedate == null || duedate.Count() == 0) && location.Count() == 0 && (priority == null || priority.Count() == 0) && (status == null || status.Count() == 0) && search == "")
{
var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).ToListAsync();
return Ok(data1);
}
//if (sort == "Sort Order" && sortby == "Sort By" && assignto.Count() == 0 && (duedate == null || duedate.Count() == 0) && location.Count() == 0 && (priority == null || priority.Count() == 0) && (status == null || status.Count() == 0) && search == "")
//{
// var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).Select(s => new {s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, s.Locations.Name }).OrderByDescending(d => d.Name).ToList().Skip((page - 1) * pageSize)
// .Take(pageSize);
// // Calculate the number of pages
// var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
// // Create a view model containing the paged items and pagination metadata
// var viewModel1 = new Pagination_DTO
// {
// Data = data1,
// PageNumber = page,
// PageSize = pageSize,
// TotalCount = totalCount,
// TotalPages = totalPages
// };
// return Ok(viewModel1);
//}
var currentDate = DateTime.UtcNow.Date;
var data = _db.workOrders.Include(w => w.Locations)
.Where(w => w.istemplate != true && (((w.WorkerOrderTitle ?? "").ToLower().Contains(search.ToLower()) || (w.WorkerOrderNumber ?? "").ToLower().Contains(search.ToLower()) || (w.Locations != null && (w.Locations.Title ?? "").ToLower().Contains(search.ToLower()))) &&
(assignto.Count() == 0 || assignto.Contains(w.AssignTo)) &&
(location.Count() == 0 || (w.LocationId.HasValue && location.Contains(w.LocationId.Value))) &&
(priority.Count() == 0 || priority.Contains(w.Priority)) &&
((status.Count() == 0 || status.Contains(w.Status))
)))
.ToList();
// Perform client-side filtering for due dates
data = data.Where(w =>
duedate.Count() == 0 ||
duedate.Any(dd => w.DueDate.HasValue && CheckDueDate(dd, w.DueDate.Value.Date, currentDate))).ToList();
// Apply sorting
if (!string.IsNullOrEmpty(sort) && !string.IsNullOrEmpty(sortby) && sortby != "")
{
switch (sortby)
{
case "Name":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.WorkerOrderTitle).ToList() : data.OrderByDescending(w => w.WorkerOrderTitle).ToList();
break;
case "Due Date":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.DueDate).ToList() : data.OrderByDescending(w => w.DueDate).ToList();
break;
case "Severity":
data = (sort.ToLower() == "ascending") ? data.OrderBy(w => w.Priority).ToList() : data.OrderByDescending(w => w.Priority).ToList();
break;
default:
// Handle default case or throw an exception
break;
}
}
var newdata = data.Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, Name = s.Locations != null ? s.Locations.Name : "" }).OrderByDescending(d => d.Name).ToList().Skip((page - 1) * pageSize)
.Take(pageSize);
var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize);
// Create a view model containing the paged items and pagination metadata
var viewModel = new Pagination_DTO
{
Data = newdata,
PageNumber = page,
PageSize = pageSize,
TotalCount = totalCount,
TotalPages = totalPages1
};
return Ok(viewModel);
}
catch (Exception ex)
{
var totalCount = _db.workOrders.Where(w => w.istemplate != true).Count();
var data1 = _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).Select(s => new
{
s.Id,
s.WorkerOrderTitle,
s.DueDate,
s.Status,
s.Priority,
Name = s.Locations != null ? s.Locations.Name : ""
}).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize)
.Take(pageSize);
// Calculate the number of pages
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
// Create a view model containing the paged items and pagination metadata
var viewModel = new Pagination_DTO
{
Data = data1,
PageNumber = page,
PageSize = pageSize,
TotalCount = totalCount,
TotalPages = totalPages
};
return Ok(viewModel);
}
}
bool CheckDueDate(string dd, DateTime dueDate, DateTime currentDate)
{
return dd switch
{
"Today" => dueDate == currentDate,
"Tomorrow" => dueDate == currentDate.AddDays(1),
"Next Week" => dueDate >= currentDate.AddDays(1) && dueDate <= currentDate.AddDays(7),
"Next Month" => dueDate >= currentDate.AddDays(1) && dueDate <= currentDate.AddMonths(1),
"Over Due" => dueDate < currentDate,
_ => false
};
}
[HttpPost]
[Route("ChangeStatus")]
public async Task<IActionResult> ChangeStatus(int id, string status)
{
try
{
var data = await _db.workOrders.Where(w => w.Id == id).FirstOrDefaultAsync();
if (data == null)
return BadRequest(new Response { Status = "Error", Message = "Work order not found" });
if (data.Status != status)
{
_db.WorkOrderAuditLogs.Add(new WorkOrderAuditLog
{
WorkOrderId = id,
UserId = User.FindFirstValue(ClaimTypes.NameIdentifier),
FieldName = "Status",
OldValue = data.Status ?? "",
NewValue = status,
Action = "status_change",
CreatedAt = DateTime.UtcNow
});
}
data.Status = status;
await _db.SaveChangesAsync();
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = data });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
}
}
[HttpPost]
[Route("AddComment")]
public async Task<IActionResult> AddComment([FromForm] Comments_DTO model)
{
try
{
var userId = _httpContext?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? "";
Comments comments = new Comments();
comments.CreatedDate = DateTime.Now;
comments.UserId = userId;
comments.WorkerOrderId = model.WorkorderId;
comments.Commenttext = model.Text;
comments.CommentType = model.CommentType ?? "vendor";
if (model.Document != null)
{
string fileName = ContentDispositionHeaderValue.Parse(model.Document.ContentDisposition).FileName.Trim('"');
string uniqueFileName = $"{Guid.NewGuid()}_{fileName}";
string uploadProfilePath = Path.Combine("Assets", "Documents");
string fullPath = Path.Combine(_webHostEnvironment.WebRootPath, uploadProfilePath, uniqueFileName);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// Copy the file to the server
using (var ms = System.IO.File.Create(fullPath))
{
await model.Document.CopyToAsync(ms);
}
// Update the user's image URL
var request = _httpContext.HttpContext.Request;
var domain = $"{request.Scheme}://{request.Host}";
comments.Documents = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
}
_db.Comments.Add(comments);
await _db.SaveChangesAsync();
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = comments });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
}
}
[HttpGet]
[Route("GetComments")]
public async Task<IActionResult> GetComments()
{
var data = await _db.Comments.Include(i => i.ApplicationUser).Select(s => new
{
s.Id,
s.Commenttext,
FirstName = s.ApplicationUser != null ? s.ApplicationUser.FirstName : "",
s.Documents
}).ToListAsync();
return Ok(data);
}
[HttpGet]
[Route("GetCommentsByWorkorderId")]
public async Task<IActionResult> GetCommentsByWorkorderId(int woid)
{
var data = await _db.Comments.Where(w => w.WorkerOrderId == woid).Include(i => i.ApplicationUser).Select(s => new
{
s.Id,
s.Commenttext,
FirstName = s.ApplicationUser != null ? s.ApplicationUser.FirstName : "",
s.Documents
}).ToListAsync();
return Ok(data);
}
[HttpGet]
[Route("GetworkordersDD")]
public async Task<IActionResult> GetworkordersDD()
{
_db.ChangeTracker.Clear();
var data = await _db.workOrders.Where(w => w.istemplate != true).Include(w => w.Locations).Include(w => w.AssignToUser).ToListAsync();
return Ok(data);
}
[HttpGet]
[Route("Getworkorders")]
public async Task<IActionResult> Getworkorders()
{
_db.ChangeTracker.Clear();
var data = await _db.workOrders
.Where(w => w.istemplate != true)
.AsSplitQuery()
.Include(w => w.Locations)
.Include(w => w.AssignToUser).Select(s => new WorkorderFilterVM
{
Id = s.Id,
Priority = s.Priority,
Status = s.Status,
WorkerOrderNumber = s.WorkerOrderNumber,
WorkerOrderTitle = s.WorkerOrderTitle,
DueDate = s.DueDate,
AssignToUserName = s.AssignToUser != null ? s.AssignToUser.FirstName : "",
LocationName = s.Locations != null ? s.Locations.Name : "",
LocationId = s.LocationId,
PO = s.PO,
TT = s.TT,
}).ToListAsync();
return Ok(data);
}
public class WorkorderFilterVM
{
public int? Id { get; set; }
public int? LocationId { get; set; }
public string? WorkerOrderNumber { get; set; }
public string? BillingAddress { get; set; } = "Amazon.com Services LLC 410 Terry Ave,North Seattle, Washington, 98109";
public string? WorkerOrderTitle { get; set; }
public string? LocationName { get; set; }
public string? AssignToUserName { get; set; }
public string? Priority { get; set; }
public string? Status { get; set; }
public DateTime? DueDate { get; set; }
public string FormattedDueDate
{
get { return DueDate.HasValue ? DueDate.Value.ToString("MM/dd/yyyy") : ""; }
}
public string? Dispatcher { get; set; }
public string? Scheduler { get; set; }
public string? PO { get; set; }
public string? TT { get; set; }
}
}
}