mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-06 14:42:09 +00:00
Add null safety checks across all API controllers
- Add null checks after FirstOrDefault() before property access - Guard navigation property access (Locations, AssignToUser, ApplicationUser, POC, Contacts) - Null-coalesce string properties in search/filter LINQ queries - Protect Sum() on nullable LineItems collections - Change FirstAsync to FirstOrDefaultAsync with null guard in UserController - Add null check on model.Attachments iteration in EditWorkorder
This commit is contained in:
parent
128ae44a0d
commit
e8c400a20a
6 changed files with 59 additions and 47 deletions
|
|
@ -30,7 +30,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var allUsersQuery = _db.Users
|
var allUsersQuery = _db.Users
|
||||||
.Where(w => w.FirstName.ToLower().Contains(search.ToLower()))
|
.Where(w => (w.FirstName ?? "").ToLower().Contains((search ?? "").ToLower()))
|
||||||
.OrderByDescending(d => d.Id);
|
.OrderByDescending(d => d.Id);
|
||||||
|
|
||||||
var totalCount = allUsersQuery.Count();
|
var totalCount = allUsersQuery.Count();
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var exist = _db.Contacts.Where(w => w.Id == contacts.Id).FirstOrDefault();
|
var exist = _db.Contacts.Where(w => w.Id == contacts.Id).FirstOrDefault();
|
||||||
|
if (exist == null)
|
||||||
|
return BadRequest(new Response { Status = "Error", Message = "Contact not found" });
|
||||||
|
|
||||||
exist.Title = contacts.Title;
|
exist.Title = contacts.Title;
|
||||||
exist.Owner = contacts.Owner;
|
exist.Owner = contacts.Owner;
|
||||||
|
|
@ -260,7 +262,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
public IActionResult GetAddressbook(string? search = "", int page = 1, int pageSize = 10)
|
public IActionResult GetAddressbook(string? search = "", int page = 1, int pageSize = 10)
|
||||||
{
|
{
|
||||||
var totalCount = _db.Locations.Count();
|
var totalCount = _db.Locations.Count();
|
||||||
var data = _db.Locations.Where(w=> w.Name.ToLower().Contains(search.ToLower()) || w.Title.ToLower().Contains(search.ToLower())).Select(n => new
|
var data = _db.Locations.Where(w=> (w.Name ?? "").ToLower().Contains(search.ToLower()) || (w.Title ?? "").ToLower().Contains(search.ToLower())).Select(n => new
|
||||||
{
|
{
|
||||||
n.Id,
|
n.Id,
|
||||||
n.Name,
|
n.Name,
|
||||||
|
|
|
||||||
|
|
@ -158,13 +158,13 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
public IActionResult GetQuotes(string search = "", int page = 1, int pageSize = 10)
|
public IActionResult GetQuotes(string search = "", int page = 1, int pageSize = 10)
|
||||||
{
|
{
|
||||||
var totalCount = _db.Quotes.Count();
|
var totalCount = _db.Quotes.Count();
|
||||||
var data = _db.Quotes.Include(s => s.WorkOrder).AsNoTracking().Where(w => w.QuotId.ToLower().Contains(search.ToLower()) || w.SiteName.ToLower().Contains(search.ToLower()) || w.WorkOrder.WorkerOrderTitle.ToLower().Contains(search.ToLower())).Select(s => new
|
var data = _db.Quotes.Include(s => s.WorkOrder).AsNoTracking().Where(w => (w.QuotId ?? "").ToLower().Contains(search.ToLower()) || (w.SiteName ?? "").ToLower().Contains(search.ToLower()) || (w.WorkOrder != null && (w.WorkOrder.WorkerOrderTitle ?? "").ToLower().Contains(search.ToLower()))).Select(s => new
|
||||||
{
|
{
|
||||||
s.Id,
|
s.Id,
|
||||||
QuoteId = "QO-" + s.QuotId,
|
QuoteId = "QO-" + s.QuotId,
|
||||||
WorkOrder = s.WorkOrder != null ? s.WorkOrder.WorkerOrderNumber : "",
|
WorkOrder = s.WorkOrder != null ? s.WorkOrder.WorkerOrderNumber : "",
|
||||||
s.ProjectName,
|
s.ProjectName,
|
||||||
TotalAmount = "$" + s.LineItems.Sum(s => s.Lineitem.Value).ToString(),
|
TotalAmount = "$" + (s.LineItems != null ? s.LineItems.Sum(l => l.Lineitem ?? 0) : 0).ToString(),
|
||||||
s.SiteName,
|
s.SiteName,
|
||||||
s.SiteId,
|
s.SiteId,
|
||||||
s.PO,
|
s.PO,
|
||||||
|
|
@ -201,8 +201,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
s.Id,
|
s.Id,
|
||||||
s.PO,
|
s.PO,
|
||||||
s.TT,
|
s.TT,
|
||||||
s.Locations.Title,
|
Title = s.Locations != null ? s.Locations.Title : "",
|
||||||
s.Locations.Name
|
Name = s.Locations != null ? s.Locations.Name : ""
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +216,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
s.Id,
|
s.Id,
|
||||||
s.QuotId,
|
s.QuotId,
|
||||||
s.Date,
|
s.Date,
|
||||||
Name = (s.Contacts.FirstName + " " + s.Contacts.LastName).Trim(),
|
Name = s.Contacts != null ? (s.Contacts.FirstName + " " + s.Contacts.LastName).Trim() : "",
|
||||||
s.PO,
|
s.PO,
|
||||||
s.TT,
|
s.TT,
|
||||||
s.SiteName,
|
s.SiteName,
|
||||||
|
|
@ -225,7 +225,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
s.BillingAddress,
|
s.BillingAddress,
|
||||||
s.ShippingAddress,
|
s.ShippingAddress,
|
||||||
lineitems = s.LineItems.Select(q => new { q.Descriptions, q.Lineitem }),
|
lineitems = s.LineItems.Select(q => new { q.Descriptions, q.Lineitem }),
|
||||||
TotalAmount = "$" + s.LineItems.Sum(s => s.Lineitem.Value).ToString()
|
TotalAmount = "$" + (s.LineItems != null ? s.LineItems.Sum(l => l.Lineitem ?? 0) : 0).ToString()
|
||||||
}).FirstOrDefaultAsync();
|
}).FirstOrDefaultAsync();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var exist = _db.Categories.Where(w => w.Id == model.Id).FirstOrDefault();
|
var exist = _db.Categories.Where(w => w.Id == model.Id).FirstOrDefault();
|
||||||
|
if (exist == null)
|
||||||
|
return BadRequest(new Response { Status = "Error", Message = "Category not found" });
|
||||||
exist.Name = model.Name;
|
exist.Name = model.Name;
|
||||||
_db.Categories.Update(exist);
|
_db.Categories.Update(exist);
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
|
|
@ -157,7 +159,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var totalCount = _db.Users.Count();
|
var totalCount = _db.Users.Count();
|
||||||
var allUsers = _db.Users.Where(w => w.FirstName.ToLower().Contains(search.ToLower())).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize)
|
var allUsers = _db.Users.Where(w => (w.FirstName ?? "").ToLower().Contains((search ?? "").ToLower())).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize)
|
||||||
.Take(pageSize);
|
.Take(pageSize);
|
||||||
|
|
||||||
// Calculate the number of pages
|
// Calculate the number of pages
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,9 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
var exist1 = await _userManager.Users.FirstAsync(w => w.Id == model.Id);
|
var exist1 = await _userManager.Users.FirstOrDefaultAsync(w => w.Id == model.Id);
|
||||||
|
if (exist1 == null)
|
||||||
|
return BadRequest(new Response { Status = "Error", Message = "User not found" });
|
||||||
|
|
||||||
var existingRole = await _userManager.GetRolesAsync(exist1);
|
var existingRole = await _userManager.GetRolesAsync(exist1);
|
||||||
|
|
||||||
|
|
@ -134,6 +136,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var exist = _db.Users.Where(w => w.Id == user.Id).FirstOrDefault();
|
var exist = _db.Users.Where(w => w.Id == user.Id).FirstOrDefault();
|
||||||
|
if (exist == null)
|
||||||
|
return BadRequest(new Response { Status = "Error", Message = "User not found" });
|
||||||
exist.FirstName = user.Name;
|
exist.FirstName = user.Name;
|
||||||
exist.EmailConfirmed = true;
|
exist.EmailConfirmed = true;
|
||||||
exist.UserName = user.Email;
|
exist.UserName = user.Email;
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var workOrder = _db.workOrders.Where(w => w.Id == model.Id).FirstOrDefault();
|
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" });
|
||||||
workOrder.WorkerOrderNumber = model.WorkerOrderNumber;
|
workOrder.WorkerOrderNumber = model.WorkerOrderNumber;
|
||||||
workOrder.WorkerOrderTitle = model.WorkerOrderTitle;
|
workOrder.WorkerOrderTitle = model.WorkerOrderTitle;
|
||||||
workOrder.Description = model.Description;
|
workOrder.Description = model.Description;
|
||||||
|
|
@ -227,6 +229,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
||||||
#region Images of workorder
|
#region Images of workorder
|
||||||
workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List<WorkOrderAttachments>() : workOrder.workOrderAttachments;
|
workOrder.workOrderAttachments = workOrder.workOrderAttachments == null ? new List<WorkOrderAttachments>() : workOrder.workOrderAttachments;
|
||||||
|
if (model.Attachments != null)
|
||||||
|
{
|
||||||
foreach (var attachment in model.Attachments)
|
foreach (var attachment in model.Attachments)
|
||||||
{
|
{
|
||||||
string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"');
|
string fileName = ContentDispositionHeaderValue.Parse(attachment.ContentDisposition).FileName.Trim('"');
|
||||||
|
|
@ -237,18 +241,17 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
|
||||||
|
|
||||||
// Copy the file to the server
|
|
||||||
using (var ms = System.IO.File.Create(fullPath))
|
using (var ms = System.IO.File.Create(fullPath))
|
||||||
{
|
{
|
||||||
await attachment.CopyToAsync(ms);
|
await attachment.CopyToAsync(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the user's image URL
|
|
||||||
var request = _httpContext.HttpContext.Request;
|
var request = _httpContext.HttpContext.Request;
|
||||||
var domain = $"{request.Scheme}://{request.Host}";
|
var domain = $"{request.Scheme}://{request.Host}";
|
||||||
var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
|
var imagesPath = domain + "/" + Path.Combine(uploadProfilePath, uniqueFileName);
|
||||||
workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath });
|
workOrder.workOrderAttachments.Add(new WorkOrderAttachments { Attachments = imagesPath });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (model.BeforPhotoAttachment != null)
|
if (model.BeforPhotoAttachment != null)
|
||||||
{
|
{
|
||||||
|
|
@ -455,10 +458,11 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(search))
|
if (!string.IsNullOrEmpty(search))
|
||||||
{
|
{
|
||||||
|
var s = search.ToLower();
|
||||||
query = query.Where(w =>
|
query = query.Where(w =>
|
||||||
w.WorkerOrderTitle.ToLower().Contains(search.ToLower()) ||
|
(w.WorkerOrderTitle ?? "").ToLower().Contains(s) ||
|
||||||
w.WorkerOrderNumber.ToLower().Contains(search.ToLower()) ||
|
(w.WorkerOrderNumber ?? "").ToLower().Contains(s) ||
|
||||||
w.Locations.Title.ToLower().Contains(search.ToLower()));
|
(w.Locations != null && (w.Locations.Title ?? "").ToLower().Contains(s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assignto != null && assignto.Length > 0)
|
if (assignto != null && assignto.Length > 0)
|
||||||
|
|
@ -515,7 +519,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
var pagedData = data
|
var pagedData = data
|
||||||
.Skip((page - 1) * pageSize)
|
.Skip((page - 1) * pageSize)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, s.Locations.Name })
|
.Select(s => new { s.Id, s.WorkerOrderTitle, s.DueDate, s.Status, s.Priority, Name = s.Locations != null ? s.Locations.Name : "" })
|
||||||
.OrderByDescending(d => d.Name)
|
.OrderByDescending(d => d.Name)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
@ -551,16 +555,14 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
title = s.WorkerOrderTitle,
|
title = s.WorkerOrderTitle,
|
||||||
s.DueDate,
|
s.DueDate,
|
||||||
s.Status,
|
s.Status,
|
||||||
assignee = s.AssignToUser.FirstName,
|
assignee = s.AssignToUser != null ? s.AssignToUser.FirstName : "",
|
||||||
location = s.Locations.Name,
|
location = s.Locations != null ? s.Locations.Name : "",
|
||||||
priority = s.Priority,
|
priority = s.Priority,
|
||||||
s.PO,
|
s.PO,
|
||||||
s.TT,
|
s.TT,
|
||||||
poc = s.WorkOrderContacts.Select(s => new { s.Id, name = (s.POC.FirstName + " " + s.POC.LastName).Trim(), email = s.POC.Email, phone = s.POC.PhoneNumber }),
|
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(s => new { s.Id, name = s.Category.Name }),
|
category = s.WorkOrderCategories.Select(c => new { c.Id, name = c.Category != null ? c.Category.Name : "" }),
|
||||||
Attachments = s.workOrderAttachments.Select(s => new { s.Id, attachment = s.Attachments }),
|
Attachments = s.workOrderAttachments.Select(a => new { a.Id, attachment = a.Attachments }),
|
||||||
//category = s.Category.Name,
|
|
||||||
//s.Attachments,
|
|
||||||
s.BeforPhotoIssue,
|
s.BeforPhotoIssue,
|
||||||
s.BeforPhotoAttachment,
|
s.BeforPhotoAttachment,
|
||||||
s.AfterPhotoIssue,
|
s.AfterPhotoIssue,
|
||||||
|
|
@ -568,7 +570,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
s.SignOffName,
|
s.SignOffName,
|
||||||
s.SignOffAttachment,
|
s.SignOffAttachment,
|
||||||
s.SignOffSignature,
|
s.SignOffSignature,
|
||||||
Comments = s.Comments.Select(s => new { s.Id, s.CreatedDate, s.Commenttext, s.Documents, userName = s.ApplicationUser.FirstName }),
|
Comments = s.Comments.Select(c => new { c.Id, c.CreatedDate, c.Commenttext, c.Documents, userName = c.ApplicationUser != null ? c.ApplicationUser.FirstName : "" }),
|
||||||
quotes = s.Quotes.Select(q => new { code = q.QuotId, q.Id })
|
quotes = s.Quotes.Select(q => new { code = q.QuotId, q.Id })
|
||||||
}).FirstOrDefaultAsync();
|
}).FirstOrDefaultAsync();
|
||||||
if (exist == null)
|
if (exist == null)
|
||||||
|
|
@ -615,7 +617,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
|
|
||||||
var currentDate = DateTime.UtcNow.Date;
|
var currentDate = DateTime.UtcNow.Date;
|
||||||
var data = _db.workOrders.Include(w => w.Locations)
|
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.Title.ToLower().Contains(search.ToLower())) &&
|
.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)) &&
|
(assignto.Count() == 0 || assignto.Contains(w.AssignTo)) &&
|
||||||
(location.Count() == 0 || (w.LocationId.HasValue && location.Contains(w.LocationId.Value))) &&
|
(location.Count() == 0 || (w.LocationId.HasValue && location.Contains(w.LocationId.Value))) &&
|
||||||
(priority.Count() == 0 || priority.Contains(w.Priority)) &&
|
(priority.Count() == 0 || priority.Contains(w.Priority)) &&
|
||||||
|
|
@ -647,7 +649,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newdata = data.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)
|
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);
|
.Take(pageSize);
|
||||||
var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize);
|
var totalPages1 = (int)Math.Ceiling(totalCount / (double)pageSize);
|
||||||
|
|
||||||
|
|
@ -672,7 +674,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
s.DueDate,
|
s.DueDate,
|
||||||
s.Status,
|
s.Status,
|
||||||
s.Priority,
|
s.Priority,
|
||||||
s.Locations.Name
|
Name = s.Locations != null ? s.Locations.Name : ""
|
||||||
}).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize)
|
}).OrderByDescending(d => d.Id).ToList().Skip((page - 1) * pageSize)
|
||||||
.Take(pageSize);
|
.Take(pageSize);
|
||||||
|
|
||||||
|
|
@ -711,6 +713,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var data = await _db.workOrders.Where(w => w.Id == id).FirstOrDefaultAsync();
|
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" });
|
||||||
data.Status = status;
|
data.Status = status;
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = data });
|
return Ok(new DataResponse { Message = "Updated Successfully", Status = "200", Data = data });
|
||||||
|
|
@ -770,7 +774,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
{
|
{
|
||||||
s.Id,
|
s.Id,
|
||||||
s.Commenttext,
|
s.Commenttext,
|
||||||
s.ApplicationUser.FirstName,
|
FirstName = s.ApplicationUser != null ? s.ApplicationUser.FirstName : "",
|
||||||
s.Documents
|
s.Documents
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
|
|
@ -784,7 +788,7 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
{
|
{
|
||||||
s.Id,
|
s.Id,
|
||||||
s.Commenttext,
|
s.Commenttext,
|
||||||
s.ApplicationUser.FirstName,
|
FirstName = s.ApplicationUser != null ? s.ApplicationUser.FirstName : "",
|
||||||
s.Documents
|
s.Documents
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
|
|
@ -815,8 +819,8 @@ namespace Api.SeaHavenIndustries.Controllers
|
||||||
WorkerOrderNumber = s.WorkerOrderNumber,
|
WorkerOrderNumber = s.WorkerOrderNumber,
|
||||||
WorkerOrderTitle = s.WorkerOrderTitle,
|
WorkerOrderTitle = s.WorkerOrderTitle,
|
||||||
DueDate = s.DueDate,
|
DueDate = s.DueDate,
|
||||||
AssignToUserName = s.AssignToUser.FirstName,
|
AssignToUserName = s.AssignToUser != null ? s.AssignToUser.FirstName : "",
|
||||||
LocationName = s.Locations.Name,
|
LocationName = s.Locations != null ? s.Locations.Name : "",
|
||||||
LocationId = s.LocationId,
|
LocationId = s.LocationId,
|
||||||
PO = s.PO,
|
PO = s.PO,
|
||||||
TT = s.TT,
|
TT = s.TT,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue