mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
fix(work-orders): complete Phase 1 board indexes, Service DTO and helper wiring
Add AssignTo+ScheduledDate and WorkOrderType indexes, expose service on board rows, and route data access through shared projection/filter helpers.
This commit is contained in:
parent
ff53cb9fa6
commit
8efe4460bb
8 changed files with 69 additions and 165 deletions
|
|
@ -18,6 +18,22 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
BEGIN
|
||||
CREATE INDEX IX_workOrders_ScheduledDate ON workOrders (ScheduledDate);
|
||||
END
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM sys.indexes
|
||||
WHERE name = 'IX_workOrders_AssignTo_ScheduledDate'
|
||||
AND object_id = OBJECT_ID('workOrders'))
|
||||
BEGIN
|
||||
CREATE INDEX IX_workOrders_AssignTo_ScheduledDate ON workOrders (AssignTo, ScheduledDate);
|
||||
END
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM sys.indexes
|
||||
WHERE name = 'IX_workOrders_WorkOrderType'
|
||||
AND object_id = OBJECT_ID('workOrders'))
|
||||
BEGIN
|
||||
CREATE INDEX IX_workOrders_WorkOrderType ON workOrders (WorkOrderType);
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +41,18 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("""
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.indexes
|
||||
WHERE name = 'IX_workOrders_WorkOrderType'
|
||||
AND object_id = OBJECT_ID('workOrders'))
|
||||
DROP INDEX IX_workOrders_WorkOrderType ON workOrders;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.indexes
|
||||
WHERE name = 'IX_workOrders_AssignTo_ScheduledDate'
|
||||
AND object_id = OBJECT_ID('workOrders'))
|
||||
DROP INDEX IX_workOrders_AssignTo_ScheduledDate ON workOrders;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM sys.indexes
|
||||
WHERE name = 'IX_workOrders_ScheduledDate'
|
||||
|
|
|
|||
|
|
@ -2031,12 +2031,16 @@ namespace Data.SeaHavenIndustries.Migrations
|
|||
|
||||
b.HasIndex("AssignTo");
|
||||
|
||||
b.HasIndex("AssignTo", "ScheduledDate");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.HasIndex("PrimaryDispatchId");
|
||||
|
||||
b.HasIndex("ScheduledDate");
|
||||
|
||||
b.HasIndex("WorkOrderType");
|
||||
|
||||
b.ToTable("workOrders");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace SeaHaven.DataServices.Helpers
|
|||
? w.PrimaryDispatch.Vendor.Phone
|
||||
: null,
|
||||
DispatchApptDate = w.PrimaryDispatch != null ? w.PrimaryDispatch.ScheduledDate : null,
|
||||
w.Service,
|
||||
w.Trade,
|
||||
w.Problem,
|
||||
w.DocStatus,
|
||||
|
|
@ -92,8 +93,7 @@ namespace SeaHaven.DataServices.Helpers
|
|||
w.TechName,
|
||||
w.TechPhone,
|
||||
w.DispatchApptDate,
|
||||
w.Trade ?? w.Problem,
|
||||
w.Problem,
|
||||
w.Service ?? w.Trade ?? w.Problem,
|
||||
w.DocStatus,
|
||||
w.RowVersion,
|
||||
isUnscheduled)).ToList();
|
||||
|
|
|
|||
|
|
@ -134,5 +134,24 @@ namespace SeaHaven.DataServices.Helpers
|
|||
&& w.TargetWeek >= dateFrom
|
||||
&& w.TargetWeek <= dateTo));
|
||||
}
|
||||
|
||||
public static IQueryable<WorkOrder> ApplySearchFilter(IQueryable<WorkOrder> query, string? search)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(search))
|
||||
return query;
|
||||
|
||||
var s = search.Trim().ToLower();
|
||||
return query.Where(w =>
|
||||
(w.SiteCode ?? "").ToLower().Contains(s)
|
||||
|| (w.InternalWONumber ?? "").ToLower().Contains(s)
|
||||
|| (w.WorkerOrderNumber ?? "").ToLower().Contains(s)
|
||||
|| (w.Locations != null && (w.Locations.Name ?? "").ToLower().Contains(s))
|
||||
|| (w.AssignToUser != null && ((w.AssignToUser.FirstName ?? "") + " " + (w.AssignToUser.LastName ?? "")).ToLower().Contains(s))
|
||||
|| (w.Service ?? "").ToLower().Contains(s)
|
||||
|| (w.Trade ?? "").ToLower().Contains(s)
|
||||
|| (w.Problem ?? "").ToLower().Contains(s)
|
||||
|| (w.PrimaryDispatch != null && w.PrimaryDispatch.Vendor != null && (w.PrimaryDispatch.Vendor.CompanyName ?? "").ToLower().Contains(s))
|
||||
|| (w.Status ?? "").ToLower().Contains(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Data.SeaHavenIndustries;
|
||||
using Data.SeaHavenIndustries.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SeaHaven.DataServices.Helpers;
|
||||
using SeaHaven.DataServices.Interfaces;
|
||||
|
||||
namespace SeaHaven.DataServices.Implementation
|
||||
|
|
@ -19,12 +20,10 @@ namespace SeaHaven.DataServices.Implementation
|
|||
var weekStartDate = query.WeekStart.ToDateTime(TimeOnly.MinValue);
|
||||
var weekEndDate = query.WeekEnd.ToDateTime(TimeOnly.MinValue);
|
||||
|
||||
var baseQuery = _context.workOrders
|
||||
.AsNoTracking()
|
||||
.Where(w => w.istemplate != true && (w.IsDeleted != true || w.IsDeleted == null));
|
||||
|
||||
baseQuery = ApplyDispatcherFilter(baseQuery, query);
|
||||
baseQuery = ApplyTypeFilter(baseQuery, query);
|
||||
var baseQuery = WorkOrderBoardQueryFilters.ApplyBaseScope(_context.workOrders.AsNoTracking());
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyDispatcherFilter(
|
||||
baseQuery, query.Dispatchers, query.MyWorkOrders, query.CurrentUserId);
|
||||
baseQuery = WorkOrderBoardQueryFilters.ApplyTypeFilter(baseQuery, query.Types);
|
||||
|
||||
var scheduledBase = baseQuery.Where(w =>
|
||||
(w.ScheduledDate != null
|
||||
|
|
@ -41,12 +40,16 @@ namespace SeaHaven.DataServices.Implementation
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
scheduledBase = ApplySearchFilter(scheduledBase, query.Search);
|
||||
unscheduledBase = ApplySearchFilter(unscheduledBase, query.Search);
|
||||
scheduledBase = WorkOrderBoardQueryFilters.ApplySearchFilter(scheduledBase, query.Search);
|
||||
unscheduledBase = WorkOrderBoardQueryFilters.ApplySearchFilter(unscheduledBase, query.Search);
|
||||
}
|
||||
|
||||
var scheduledRows = await ProjectRows(scheduledBase, isUnscheduled: false);
|
||||
var unscheduledRows = await ProjectRows(unscheduledBase, isUnscheduled: true);
|
||||
var scheduledRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
||||
scheduledBase.OrderBy(w => w.ScheduledDate).ThenBy(w => w.InternalWONumber),
|
||||
isUnscheduled: false);
|
||||
var unscheduledRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
||||
unscheduledBase.OrderBy(w => w.InternalWONumber),
|
||||
isUnscheduled: true);
|
||||
|
||||
return new WorkOrderBoardQueryResult(scheduledRows, unscheduledRows, scheduledTotal);
|
||||
}
|
||||
|
|
@ -66,154 +69,5 @@ namespace SeaHaven.DataServices.Implementation
|
|||
u.Color))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
private static IQueryable<WorkOrder> ApplyDispatcherFilter(IQueryable<WorkOrder> query, WorkOrderBoardQuery boardQuery)
|
||||
{
|
||||
if (boardQuery.MyWorkOrders && !string.IsNullOrEmpty(boardQuery.CurrentUserId))
|
||||
return query.Where(w => w.AssignTo == boardQuery.CurrentUserId);
|
||||
|
||||
if (boardQuery.Dispatchers == null || boardQuery.Dispatchers.Count == 0)
|
||||
return query;
|
||||
|
||||
var ids = boardQuery.Dispatchers
|
||||
.Where(d => d != "__unassigned__")
|
||||
.ToList();
|
||||
var includeUnassigned = boardQuery.Dispatchers.Contains("__unassigned__");
|
||||
|
||||
if (includeUnassigned && ids.Count == 0)
|
||||
return query.Where(w => w.AssignTo == null || w.AssignTo == "");
|
||||
|
||||
if (includeUnassigned && ids.Count > 0)
|
||||
{
|
||||
return query.Where(w =>
|
||||
w.AssignTo == null || w.AssignTo == "" || ids.Contains(w.AssignTo));
|
||||
}
|
||||
|
||||
return query.Where(w => w.AssignTo != null && ids.Contains(w.AssignTo));
|
||||
}
|
||||
|
||||
private static IQueryable<WorkOrder> ApplyTypeFilter(IQueryable<WorkOrder> query, WorkOrderBoardQuery boardQuery)
|
||||
{
|
||||
if (boardQuery.Types == null || boardQuery.Types.Count == 0)
|
||||
return query;
|
||||
|
||||
return query.Where(w => w.WorkOrderType != null && boardQuery.Types.Contains(w.WorkOrderType.Value));
|
||||
}
|
||||
|
||||
private static IQueryable<WorkOrder> ApplySearchFilter(IQueryable<WorkOrder> query, string search)
|
||||
{
|
||||
var s = search.Trim().ToLower();
|
||||
return query.Where(w =>
|
||||
(w.SiteCode ?? "").ToLower().Contains(s)
|
||||
|| (w.InternalWONumber ?? "").ToLower().Contains(s)
|
||||
|| (w.WorkerOrderNumber ?? "").ToLower().Contains(s)
|
||||
|| (w.Locations != null && (w.Locations.Name ?? "").ToLower().Contains(s))
|
||||
|| (w.AssignToUser != null && ((w.AssignToUser.FirstName ?? "") + " " + (w.AssignToUser.LastName ?? "")).ToLower().Contains(s))
|
||||
|| (w.Trade ?? "").ToLower().Contains(s)
|
||||
|| (w.Problem ?? "").ToLower().Contains(s)
|
||||
|| (w.PrimaryDispatch != null && w.PrimaryDispatch.Vendor != null && (w.PrimaryDispatch.Vendor.CompanyName ?? "").ToLower().Contains(s))
|
||||
|| (w.Status ?? "").ToLower().Contains(s));
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<WorkOrderBoardRawRow>> ProjectRows(
|
||||
IQueryable<WorkOrder> query,
|
||||
bool isUnscheduled)
|
||||
{
|
||||
var rows = await query
|
||||
.Include(w => w.AssignToUser)
|
||||
.Include(w => w.Locations)
|
||||
.Include(w => w.PrimaryDispatch!)
|
||||
.ThenInclude(d => d!.Vendor)
|
||||
.Include(w => w.WorkOrderContacts!)
|
||||
.ThenInclude(c => c.POC)
|
||||
.OrderBy(w => w.ScheduledDate)
|
||||
.ThenBy(w => w.InternalWONumber)
|
||||
.Select(w => new
|
||||
{
|
||||
w.Id,
|
||||
w.InternalWONumber,
|
||||
w.RescheduleCount,
|
||||
w.CarriedOver,
|
||||
w.WorkOrderType,
|
||||
w.SiteCode,
|
||||
LocationName = w.Locations != null ? w.Locations.Name : null,
|
||||
Poc = w.WorkOrderContacts!
|
||||
.OrderBy(c => c.Id)
|
||||
.Select(c => new
|
||||
{
|
||||
Name = c.POC != null
|
||||
? ((c.POC.FirstName ?? "") + " " + (c.POC.LastName ?? "")).Trim()
|
||||
: null,
|
||||
c.POC!.PhoneNumber,
|
||||
c.Notes
|
||||
})
|
||||
.FirstOrDefault(),
|
||||
w.LifecycleStatus,
|
||||
w.LegacyStatus,
|
||||
w.Status,
|
||||
w.AssignTo,
|
||||
w.AssignToUser!.FirstName,
|
||||
w.AssignToUser!.LastName,
|
||||
w.AssignToUser!.Initials,
|
||||
w.AssignToUser!.Color,
|
||||
w.DueDate,
|
||||
w.ScheduledDate,
|
||||
w.ScheduledStart,
|
||||
w.ScheduledEnd,
|
||||
w.TargetWeek,
|
||||
w.ScheduleWeekOnly,
|
||||
VendorId = w.PrimaryDispatch != null ? (int?)w.PrimaryDispatch.VendorId : null,
|
||||
VendorName = w.PrimaryDispatch != null && w.PrimaryDispatch.Vendor != null
|
||||
? w.PrimaryDispatch.Vendor.CompanyName
|
||||
: null,
|
||||
TechName = w.PrimaryDispatch != null && w.PrimaryDispatch.Vendor != null
|
||||
? w.PrimaryDispatch.Vendor.ContactName
|
||||
: null,
|
||||
TechPhone = w.PrimaryDispatch != null && w.PrimaryDispatch.Vendor != null
|
||||
? w.PrimaryDispatch.Vendor.Phone
|
||||
: null,
|
||||
DispatchApptDate = w.PrimaryDispatch != null ? w.PrimaryDispatch.ScheduledDate : null,
|
||||
w.Trade,
|
||||
w.Problem,
|
||||
w.DocStatus,
|
||||
w.RowVersion
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return rows.Select(w => new WorkOrderBoardRawRow(
|
||||
w.Id,
|
||||
w.InternalWONumber,
|
||||
w.RescheduleCount,
|
||||
w.CarriedOver,
|
||||
w.WorkOrderType,
|
||||
w.SiteCode,
|
||||
w.LocationName,
|
||||
w.Poc?.Name,
|
||||
w.Poc?.PhoneNumber,
|
||||
w.Poc?.Notes,
|
||||
w.LifecycleStatus,
|
||||
w.LegacyStatus ?? w.Status,
|
||||
w.AssignTo,
|
||||
w.FirstName,
|
||||
w.LastName,
|
||||
w.Initials,
|
||||
w.Color,
|
||||
w.DueDate,
|
||||
w.ScheduledDate,
|
||||
w.ScheduledStart,
|
||||
w.ScheduledEnd,
|
||||
w.TargetWeek,
|
||||
w.ScheduleWeekOnly,
|
||||
w.VendorId,
|
||||
w.VendorName,
|
||||
w.TechName,
|
||||
w.TechPhone,
|
||||
w.DispatchApptDate,
|
||||
w.Trade ?? w.Problem,
|
||||
w.Problem,
|
||||
w.DocStatus,
|
||||
w.RowVersion,
|
||||
isUnscheduled)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,7 @@ namespace SeaHaven.DataServices.Interfaces
|
|||
string? TechName,
|
||||
string? TechPhone,
|
||||
DateTime? DispatchApptDate,
|
||||
string? Trade,
|
||||
string? Problem,
|
||||
string? Service,
|
||||
DocStatus? DocStatus,
|
||||
byte[]? RowVersion,
|
||||
bool IsUnscheduled);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ namespace SeaHaven.Services.DTOs
|
|||
public string? TechPhone { get; set; }
|
||||
public DateTime? ApptDate { get; set; }
|
||||
public string? ApptTime { get; set; }
|
||||
public string? Pm { get; set; }
|
||||
public string? Service { get; set; }
|
||||
public DocStatus? DocStatus { get; set; }
|
||||
public byte[]? RowVersion { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ namespace SeaHaven.Services.Implementation
|
|||
TechPhone = row.TechPhone,
|
||||
ApptDate = row.DispatchApptDate ?? row.ScheduledDate,
|
||||
ApptTime = WorkOrderDerivedFields.FormatApptTime(apptStart, apptEnd),
|
||||
Pm = row.Trade ?? row.Problem,
|
||||
Service = row.Service,
|
||||
DocStatus = row.DocStatus,
|
||||
RowVersion = row.RowVersion
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue