reduce work order milestone queries

deepsource-autofix-76c6eb20
Dan Gowans 2022-09-27 14:08:36 -04:00
parent 62a4506a49
commit d9666c3e2a
15 changed files with 276 additions and 279 deletions

View File

@ -14,23 +14,24 @@ export const handler = (request, response) => {
configFunctions.getProperty("reverseProxy.urlPrefix");
const workOrderMilestoneFilters = {
workOrderTypeIds: request.query.workOrderTypeIds,
workOrderMilestoneTypeIds: request.query
.workOrderMilestoneTypeIds
workOrderMilestoneTypeIds: request.query.workOrderMilestoneTypeIds
};
if (request.query.workOrderId) {
workOrderMilestoneFilters.workOrderId = request.query
.workOrderId;
workOrderMilestoneFilters.workOrderId = request.query.workOrderId;
}
else {
workOrderMilestoneFilters.workOrderMilestoneDateFilter = "recent";
}
const workOrderMilestones = getWorkOrderMilestones(workOrderMilestoneFilters, { includeWorkOrders: true, orderBy: "date" });
const workOrderMilestones = getWorkOrderMilestones(workOrderMilestoneFilters, {
includeWorkOrders: true,
orderBy: "date"
});
const calendar = ical({
name: "Work Order Milestone Calendar",
url: urlRoot + "/workOrders"
});
if (request.query.workOrderId && workOrderMilestones.length > 0) {
calendar.name("Work Order #" + workOrderMilestones[0].workOrder.workOrderNumber);
calendar.name("Work Order #" + workOrderMilestones[0].workOrderNumber);
calendar.url(urlRoot + "/workOrders/" + workOrderMilestones[0].workOrderId);
}
calendar.prodId({
@ -42,13 +43,14 @@ export const handler = (request, response) => {
" " +
milestone.workOrderMilestoneTimeString).split(timeStringSplitRegex);
const milestoneDate = new Date(Number.parseInt(milestoneTimePieces[0], 10), Number.parseInt(milestoneTimePieces[1], 10) - 1, Number.parseInt(milestoneTimePieces[2], 10), Number.parseInt(milestoneTimePieces[3], 10), Number.parseInt(milestoneTimePieces[4], 10));
const milestoneEndDate = new Date(milestoneDate.getTime());
milestoneEndDate.setHours(milestoneEndDate.getHours() + 1);
let summary = (milestone.workOrderMilestoneTypeId
? milestone.workOrderMilestoneType
: milestone.workOrderMilestoneDescription).trim();
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
let occupantCount = 0;
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
occupantCount += 1;
if (occupantCount === 1) {
@ -68,24 +70,25 @@ export const handler = (request, response) => {
start: milestoneDate,
created: new Date(milestone.recordCreate_timeMillis),
stamp: new Date(milestone.recordCreate_timeMillis),
lastModified: new Date(Math.max(milestone.recordUpdate_timeMillis, milestone.workOrder.recordUpdate_timeMillis)),
lastModified: new Date(Math.max(milestone.recordUpdate_timeMillis, milestone.workOrderRecordUpdate_timeMillis)),
allDay: !milestone.workOrderMilestoneTime,
summary,
url: workOrderURL
};
if (!eventData.allDay) {
eventData.end = milestoneEndDate;
}
const calendarEvent = calendar.createEvent(eventData);
let descriptionHTML = "<h1>Milestone Description</h1>" +
"<p>" +
escapeHTML(milestone.workOrderMilestoneDescription) +
"</p>" +
"<h2>Work Order #" +
milestone.workOrder.workOrderNumber +
milestone.workOrderNumber +
"</h2>" +
("<p>" +
escapeHTML(milestone.workOrder.workOrderDescription) +
"</p>") +
("<p>" + escapeHTML(milestone.workOrderDescription) + "</p>") +
('<p><a href="' + workOrderURL + '">' + workOrderURL + "</a></p>");
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
descriptionHTML +=
"<h2>Related " +
escapeHTML(configFunctions.getProperty("aliases.occupancies")) +
@ -94,18 +97,13 @@ export const handler = (request, response) => {
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.occupancy")) +
" Type</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.lot")) + "</th>") +
"<th>Start Date</th>" +
"<th>End Date</th>" +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.occupants")) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + "</th>") +
"</tr></thead>" +
"<tbody>";
for (const occupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const occupancy of milestone.workOrderLotOccupancies) {
descriptionHTML +=
"<tr>" +
("<td>" +
@ -117,9 +115,7 @@ export const handler = (request, response) => {
escapeHTML(occupancy.occupancyType) +
"</a></td>") +
("<td>" +
(occupancy.lotName
? escapeHTML(occupancy.lotName)
: "(Not Set)") +
(occupancy.lotName ? escapeHTML(occupancy.lotName) : "(Not Set)") +
"</td>") +
("<td>" + occupancy.occupancyStartDateString + "</td>") +
"<td>" +
@ -129,25 +125,20 @@ export const handler = (request, response) => {
"</td>" +
"<td>";
for (const occupant of occupancy.lotOccupancyOccupants) {
descriptionHTML +=
escapeHTML(occupant.occupantName) + "<br />";
descriptionHTML += escapeHTML(occupant.occupantName) + "<br />";
}
descriptionHTML += "</td>" + "</tr>";
}
descriptionHTML += "</tbody></table>";
}
if (milestone.workOrder.workOrderLots.length > 0) {
if (milestone.workOrderLots.length > 0) {
descriptionHTML +=
"<h2>Related " +
escapeHTML(configFunctions.getProperty("aliases.lots")) +
"</h2>" +
'<table border="1"><thead><tr>' +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
" Type</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.map")) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.map")) + "</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
" Type" +
@ -155,7 +146,7 @@ export const handler = (request, response) => {
"<th>Status</th>" +
"</tr></thead>" +
"<tbody>";
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
descriptionHTML +=
"<tr>" +
("<td>" +
@ -185,20 +176,19 @@ export const handler = (request, response) => {
name: milestone.workOrderMilestoneType
});
calendarEvent.createCategory({
name: milestone.workOrder.workOrderType
name: milestone.workOrderType
});
}
if (milestone.workOrder.workOrderLots.length > 0) {
if (milestone.workOrderLots.length > 0) {
const lotNames = [];
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
lotNames.push(lot.mapName + ": " + lot.lotName);
}
calendarEvent.location(lotNames.join(", "));
}
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
let organizerSet = false;
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
if (organizerSet) {
calendarEvent.createAttendee({

View File

@ -14,10 +14,7 @@ import * as configFunctions from "../../helpers/functions.config.js";
const timeStringSplitRegex = /[ :-]/;
function escapeHTML(stringToEscape: string) {
return stringToEscape.replace(
/[^\d A-Za-z]/g,
(c) => "&#" + c.codePointAt(0) + ";"
);
return stringToEscape.replace(/[^\d A-Za-z]/g, (c) => "&#" + c.codePointAt(0) + ";");
}
export const handler: RequestHandler = (request, response) => {
@ -31,21 +28,19 @@ export const handler: RequestHandler = (request, response) => {
const workOrderMilestoneFilters: WorkOrderMilestoneFilters = {
workOrderTypeIds: request.query.workOrderTypeIds as string,
workOrderMilestoneTypeIds: request.query
.workOrderMilestoneTypeIds as string
workOrderMilestoneTypeIds: request.query.workOrderMilestoneTypeIds as string
};
if (request.query.workOrderId) {
workOrderMilestoneFilters.workOrderId = request.query
.workOrderId as string;
workOrderMilestoneFilters.workOrderId = request.query.workOrderId as string;
} else {
workOrderMilestoneFilters.workOrderMilestoneDateFilter = "recent";
}
const workOrderMilestones = getWorkOrderMilestones(
workOrderMilestoneFilters,
{ includeWorkOrders: true, orderBy: "date" }
);
const workOrderMilestones = getWorkOrderMilestones(workOrderMilestoneFilters, {
includeWorkOrders: true,
orderBy: "date"
});
const calendar = ical({
name: "Work Order Milestone Calendar",
@ -53,7 +48,7 @@ export const handler: RequestHandler = (request, response) => {
});
if (request.query.workOrderId && workOrderMilestones.length > 0) {
calendar.name("Work Order #" + workOrderMilestones[0].workOrder.workOrderNumber);
calendar.name("Work Order #" + workOrderMilestones[0].workOrderNumber);
calendar.url(urlRoot + "/workOrders/" + workOrderMilestones[0].workOrderId);
}
@ -77,6 +72,9 @@ export const handler: RequestHandler = (request, response) => {
Number.parseInt(milestoneTimePieces[4], 10)
);
const milestoneEndDate = new Date(milestoneDate.getTime());
milestoneEndDate.setHours(milestoneEndDate.getHours() + 1);
// Build summary (title in Outlook)
let summary = (
@ -85,11 +83,10 @@ export const handler: RequestHandler = (request, response) => {
: milestone.workOrderMilestoneDescription
).trim();
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
let occupantCount = 0;
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
occupantCount += 1;
@ -121,7 +118,7 @@ export const handler: RequestHandler = (request, response) => {
lastModified: new Date(
Math.max(
milestone.recordUpdate_timeMillis,
milestone.workOrder.recordUpdate_timeMillis
milestone.workOrderRecordUpdate_timeMillis
)
),
allDay: !milestone.workOrderMilestoneTime,
@ -129,6 +126,10 @@ export const handler: RequestHandler = (request, response) => {
url: workOrderURL
};
if (!eventData.allDay) {
eventData.end = milestoneEndDate;
}
const calendarEvent = calendar.createEvent(eventData);
// Build description
@ -139,39 +140,28 @@ export const handler: RequestHandler = (request, response) => {
escapeHTML(milestone.workOrderMilestoneDescription) +
"</p>" +
"<h2>Work Order #" +
milestone.workOrder.workOrderNumber +
milestone.workOrderNumber +
"</h2>" +
("<p>" +
escapeHTML(milestone.workOrder.workOrderDescription) +
"</p>") +
("<p>" + escapeHTML(milestone.workOrderDescription) + "</p>") +
('<p><a href="' + workOrderURL + '">' + workOrderURL + "</a></p>");
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
descriptionHTML +=
"<h2>Related " +
escapeHTML(configFunctions.getProperty("aliases.occupancies")) +
"</h2>" +
'<table border="1"><thead><tr>' +
("<th>" +
escapeHTML(
configFunctions.getProperty("aliases.occupancy")
) +
escapeHTML(configFunctions.getProperty("aliases.occupancy")) +
" Type</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.lot")) + "</th>") +
"<th>Start Date</th>" +
"<th>End Date</th>" +
("<th>" +
escapeHTML(
configFunctions.getProperty("aliases.occupants")
) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + "</th>") +
"</tr></thead>" +
"<tbody>";
for (const occupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const occupancy of milestone.workOrderLotOccupancies) {
descriptionHTML +=
"<tr>" +
("<td>" +
@ -183,9 +173,7 @@ export const handler: RequestHandler = (request, response) => {
escapeHTML(occupancy.occupancyType) +
"</a></td>") +
("<td>" +
(occupancy.lotName
? escapeHTML(occupancy.lotName)
: "(Not Set)") +
(occupancy.lotName ? escapeHTML(occupancy.lotName) : "(Not Set)") +
"</td>") +
("<td>" + occupancy.occupancyStartDateString + "</td>") +
"<td>" +
@ -196,8 +184,7 @@ export const handler: RequestHandler = (request, response) => {
"<td>";
for (const occupant of occupancy.lotOccupancyOccupants) {
descriptionHTML +=
escapeHTML(occupant.occupantName) + "<br />";
descriptionHTML += escapeHTML(occupant.occupantName) + "<br />";
}
descriptionHTML += "</td>" + "</tr>";
@ -206,18 +193,14 @@ export const handler: RequestHandler = (request, response) => {
descriptionHTML += "</tbody></table>";
}
if (milestone.workOrder.workOrderLots.length > 0) {
if (milestone.workOrderLots.length > 0) {
descriptionHTML +=
"<h2>Related " +
escapeHTML(configFunctions.getProperty("aliases.lots")) +
"</h2>" +
'<table border="1"><thead><tr>' +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
" Type</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.map")) +
"</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type</th>") +
("<th>" + escapeHTML(configFunctions.getProperty("aliases.map")) + "</th>") +
("<th>" +
escapeHTML(configFunctions.getProperty("aliases.lot")) +
" Type" +
@ -226,7 +209,7 @@ export const handler: RequestHandler = (request, response) => {
"</tr></thead>" +
"<tbody>";
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
descriptionHTML +=
"<tr>" +
("<td>" +
@ -265,16 +248,16 @@ export const handler: RequestHandler = (request, response) => {
});
calendarEvent.createCategory({
name: milestone.workOrder.workOrderType
name: milestone.workOrderType
});
}
// Set location
if (milestone.workOrder.workOrderLots.length > 0) {
if (milestone.workOrderLots.length > 0) {
const lotNames = [];
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
lotNames.push(lot.mapName + ": " + lot.lotName);
}
@ -283,20 +266,23 @@ export const handler: RequestHandler = (request, response) => {
// Set organizer / attendees
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
if (milestone.workOrderLotOccupancies.length > 0) {
let organizerSet = false;
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
if (organizerSet) {
calendarEvent.createAttendee({
name: occupant.occupantName,
email: configFunctions.getProperty("settings.workOrders.calendarEmailAddress")
email: configFunctions.getProperty(
"settings.workOrders.calendarEmailAddress"
)
});
} else {
calendarEvent.organizer({
name: occupant.occupantName,
email: configFunctions.getProperty("settings.workOrders.calendarEmailAddress")
email: configFunctions.getProperty(
"settings.workOrders.calendarEmailAddress"
)
});
organizerSet = true;
}

View File

@ -22,9 +22,7 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
}
}
if (filters.occupantName) {
const occupantNamePieces = filters.occupantName
.toLowerCase()
.split(" ");
const occupantNamePieces = filters.occupantName.toLowerCase().split(" ");
for (const occupantNamePiece of occupantNamePieces) {
sqlWhereClause +=
" and o.lotOccupancyId in (select oo.lotOccupancyId from LotOccupancyOccupants oo where oo.recordDelete_timeMillis is null and instr(lower(oo.occupantName), ?))";
@ -80,14 +78,17 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
" and o.lotOccupancyId not in (select lotOccupancyId from WorkOrderLotOccupancies where recordDelete_timeMillis is null and workOrderId = ?)";
sqlParameters.push(filters.notWorkOrderId);
}
const count = database
.prepare("select count(*) as recordCount" +
" from LotOccupancies o" +
" left join Lots l on o.lotId = l.lotId" +
sqlWhereClause)
.get(sqlParameters).recordCount;
let count;
if (options.limit !== -1) {
count = database
.prepare("select count(*) as recordCount" +
" from LotOccupancies o" +
" left join Lots l on o.lotId = l.lotId" +
sqlWhereClause)
.get(sqlParameters).recordCount;
}
let lotOccupancies = [];
if (count > 0) {
if (options.limit === -1 || count > 0) {
lotOccupancies = database
.prepare("select o.lotOccupancyId," +
" o.occupancyTypeId, t.occupancyType," +
@ -102,12 +103,12 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
sqlWhereClause +
" order by o.occupancyStartDate desc, ifnull(o.occupancyEndDate, 99999999) desc, l.lotName, o.lotId" +
(options.limit !== -1
? " limit " +
options.limit +
" offset " +
options.offset
? " limit " + options.limit + " offset " + options.offset
: ""))
.all(sqlParameters);
if (options.limit === -1) {
count = lotOccupancies.length;
}
if (options.includeOccupants) {
for (const lotOccupancy of lotOccupancies) {
lotOccupancy.lotOccupancyOccupants = getLotOccupancyOccupants(lotOccupancy.lotOccupancyId, database);

View File

@ -65,9 +65,7 @@ export const getLotOccupancies = (
}
if (filters.occupantName) {
const occupantNamePieces = filters.occupantName
.toLowerCase()
.split(" ");
const occupantNamePieces = filters.occupantName.toLowerCase().split(" ");
for (const occupantNamePiece of occupantNamePieces) {
sqlWhereClause +=
" and o.lotOccupancyId in (select oo.lotOccupancyId from LotOccupancyOccupants oo where oo.recordDelete_timeMillis is null and instr(lower(oo.occupantName), ?))";
@ -104,9 +102,7 @@ export const getLotOccupancies = (
if (filters.occupancyStartDateString) {
sqlWhereClause += " and o.occupancyStartDate = ?";
sqlParameters.push(
dateStringToInteger(filters.occupancyStartDateString)
);
sqlParameters.push(dateStringToInteger(filters.occupancyStartDateString));
}
if (filters.occupancyEffectiveDateString) {
@ -140,18 +136,22 @@ export const getLotOccupancies = (
sqlParameters.push(filters.notWorkOrderId);
}
const count: number = database
.prepare(
"select count(*) as recordCount" +
" from LotOccupancies o" +
" left join Lots l on o.lotId = l.lotId" +
sqlWhereClause
)
.get(sqlParameters).recordCount;
let count: number;
if (options.limit !== -1) {
count = database
.prepare(
"select count(*) as recordCount" +
" from LotOccupancies o" +
" left join Lots l on o.lotId = l.lotId" +
sqlWhereClause
)
.get(sqlParameters).recordCount;
}
let lotOccupancies: recordTypes.LotOccupancy[] = [];
if (count > 0) {
if (options.limit === -1 || count > 0) {
lotOccupancies = database
.prepare(
"select o.lotOccupancyId," +
@ -167,14 +167,15 @@ export const getLotOccupancies = (
sqlWhereClause +
" order by o.occupancyStartDate desc, ifnull(o.occupancyEndDate, 99999999) desc, l.lotName, o.lotId" +
(options.limit !== -1
? " limit " +
options.limit +
" offset " +
options.offset
? " limit " + options.limit + " offset " + options.offset
: "")
)
.all(sqlParameters);
if (options.limit === -1) {
count = lotOccupancies.length;
}
if (options.includeOccupants) {
for (const lotOccupancy of lotOccupancies) {
lotOccupancy.lotOccupancyOccupants = getLotOccupancyOccupants(

View File

@ -9,7 +9,7 @@ interface GetLotsFilters {
workOrderId?: number | string;
}
interface GetLotsOptions {
limit: number;
limit: -1 | number;
offset: number;
}
export declare const getLots: (filters: GetLotsFilters, options: GetLotsOptions, connectedDatabase?: sqlite.Database) => {

View File

@ -43,24 +43,27 @@ export const getLots = (filters, options, connectedDatabase) => {
sqlParameters.push(filters.workOrderId);
}
const currentDate = dateToInteger(new Date());
const count = database
.prepare("select count(*) as recordCount" +
" from Lots l" +
(" left join (" +
"select lotId, count(lotOccupancyId) as lotOccupancyCount" +
" from LotOccupancies" +
" where recordDelete_timeMillis is null" +
" and occupancyStartDate <= " +
currentDate +
" and (occupancyEndDate is null or occupancyEndDate >= " +
currentDate +
")" +
" group by lotId" +
") o on l.lotId = o.lotId") +
sqlWhereClause)
.get(sqlParameters).recordCount;
let count;
if (options.limit !== -1) {
count = database
.prepare("select count(*) as recordCount" +
" from Lots l" +
(" left join (" +
"select lotId, count(lotOccupancyId) as lotOccupancyCount" +
" from LotOccupancies" +
" where recordDelete_timeMillis is null" +
" and occupancyStartDate <= " +
currentDate +
" and (occupancyEndDate is null or occupancyEndDate >= " +
currentDate +
")" +
" group by lotId" +
") o on l.lotId = o.lotId") +
sqlWhereClause)
.get(sqlParameters).recordCount;
}
let lots = [];
if (count > 0) {
if (options.limit === -1 || count > 0) {
database.function("userFn_lotNameSortName", configFunctions.getProperty("settings.lot.lotNameSortNameFunction"));
lots = database
.prepare("select l.lotId, l.lotName," +
@ -92,6 +95,9 @@ export const getLots = (filters, options, connectedDatabase) => {
options.offset
: ""))
.all(sqlParameters);
if (options.limit === -1) {
count = lots.length;
}
}
if (!connectedDatabase) {
database.close();

View File

@ -18,7 +18,7 @@ interface GetLotsFilters {
}
interface GetLotsOptions {
limit: number;
limit: -1 | number;
offset: number;
}
@ -79,7 +79,10 @@ export const getLots = (
const currentDate = dateToInteger(new Date());
const count: number = database
let count: number;
if (options.limit !== -1) {
count = database
.prepare(
"select count(*) as recordCount" +
" from Lots l" +
@ -97,10 +100,11 @@ export const getLots = (
sqlWhereClause
)
.get(sqlParameters).recordCount;
}
let lots: recordTypes.Lot[] = [];
if (count > 0) {
if (options.limit === -1 || count > 0) {
database.function(
"userFn_lotNameSortName",
configFunctions.getProperty("settings.lot.lotNameSortNameFunction")
@ -138,6 +142,10 @@ export const getLots = (
: "")
)
.all(sqlParameters);
if (options.limit === -1) {
count = lots.length;
}
}
if (!connectedDatabase) {

View File

@ -1,8 +1,9 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import { getWorkOrder } from "./getWorkOrder.js";
import { dateIntegerToString, dateStringToInteger, dateToInteger, timeIntegerToString } from "@cityssm/expressjs-server-js/dateTimeFns.js";
import * as configFunctions from "../functions.config.js";
import { getLots } from "./getLots.js";
import { getLotOccupancies } from "./getLotOccupancies.js";
const commaSeparatedNumbersRegex = /^\d+(,\d+)*$/;
export const getWorkOrderMilestones = (filters, options, connectedDatabase) => {
const database = connectedDatabase ||
@ -42,17 +43,13 @@ export const getWorkOrderMilestones = (filters, options, connectedDatabase) => {
sqlWhereClause += " and m.workOrderMilestoneDate = ?";
sqlParameters.push(dateStringToInteger(filters.workOrderMilestoneDateString));
}
if (filters.workOrderTypeIds &&
commaSeparatedNumbersRegex.test(filters.workOrderTypeIds)) {
sqlWhereClause +=
" and w.workOrderTypeId in (" + filters.workOrderTypeIds + ")";
if (filters.workOrderTypeIds && commaSeparatedNumbersRegex.test(filters.workOrderTypeIds)) {
sqlWhereClause += " and w.workOrderTypeId in (" + filters.workOrderTypeIds + ")";
}
if (filters.workOrderMilestoneTypeIds &&
commaSeparatedNumbersRegex.test(filters.workOrderMilestoneTypeIds)) {
sqlWhereClause +=
" and m.workOrderMilestoneTypeId in (" +
filters.workOrderMilestoneTypeIds +
")";
" and m.workOrderMilestoneTypeId in (" + filters.workOrderMilestoneTypeIds + ")";
}
let orderByClause = "";
switch (options.orderBy) {
@ -68,29 +65,45 @@ export const getWorkOrderMilestones = (filters, options, connectedDatabase) => {
" order by m.workOrderMilestoneDate, case when m.workOrderMilestoneTime = 0 then 9999 else m.workOrderMilestoneTime end," +
" t.orderNumber, m.workOrderId, m.workOrderMilestoneId";
}
const workOrderMilestones = database
.prepare("select m.workOrderId, m.workOrderMilestoneId," +
const sql = "select m.workOrderMilestoneId," +
" m.workOrderMilestoneTypeId, t.workOrderMilestoneType," +
" m.workOrderMilestoneDate, userFn_dateIntegerToString(m.workOrderMilestoneDate) as workOrderMilestoneDateString," +
" m.workOrderMilestoneTime, userFn_timeIntegerToString(m.workOrderMilestoneTime) as workOrderMilestoneTimeString," +
" m.workOrderMilestoneDescription," +
" m.workOrderMilestoneCompletionDate, userFn_dateIntegerToString(m.workOrderMilestoneCompletionDate) as workOrderMilestoneCompletionDateString," +
" m.workOrderMilestoneCompletionTime, userFn_timeIntegerToString(m.workOrderMilestoneCompletionTime) as workOrderMilestoneCompletionTimeString," +
(options.includeWorkOrders
? " m.workOrderId, w.workOrderNumber, wt.workOrderType, w.workOrderDescription," +
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString," +
" w.recordUpdate_timeMillis as workOrderRecordUpdate_timeMillis,"
: "") +
" m.recordCreate_userName, m.recordCreate_timeMillis," +
" m.recordUpdate_userName, m.recordUpdate_timeMillis" +
" from WorkOrderMilestones m" +
" left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId" +
" left join WorkOrders w on m.workOrderId = w.workOrderId" +
" left join WorkOrderTypes wt on w.workOrderTypeId = wt.workOrderTypeId" +
sqlWhereClause +
orderByClause)
orderByClause;
const workOrderMilestones = database
.prepare(sql)
.all(sqlParameters);
if (options.includeWorkOrders) {
for (const workOrderMilestone of workOrderMilestones) {
workOrderMilestone.workOrder = getWorkOrder(workOrderMilestone.workOrderId, {
includeLotsAndLotOccupancies: true,
includeComments: false,
includeMilestones: false
}, database);
workOrderMilestone.workOrderLots = getLots({
workOrderId: workOrderMilestone.workOrderId
}, {
limit: -1,
offset: 0
}, database).lots;
workOrderMilestone.workOrderLotOccupancies = getLotOccupancies({
workOrderId: workOrderMilestone.workOrderId
}, {
limit: -1,
offset: 0,
includeOccupants: true
}, database).lotOccupancies;
}
}
if (!connectedDatabase) {

View File

@ -2,8 +2,6 @@ import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import { getWorkOrder } from "./getWorkOrder.js";
import {
dateIntegerToString,
dateStringToInteger,
@ -13,6 +11,9 @@ import {
import * as configFunctions from "../functions.config.js";
import { getLots } from "./getLots.js";
import { getLotOccupancies } from "./getLotOccupancies.js";
import type * as recordTypes from "../../types/recordTypes";
export interface WorkOrderMilestoneFilters {
@ -46,7 +47,8 @@ export const getWorkOrderMilestones = (
// Filters
let sqlWhereClause = " where m.recordDelete_timeMillis is null and w.recordDelete_timeMillis is null";
let sqlWhereClause =
" where m.recordDelete_timeMillis is null and w.recordDelete_timeMillis is null";
const sqlParameters = [];
if (filters.workOrderId) {
@ -71,9 +73,7 @@ export const getWorkOrderMilestones = (
configFunctions.getProperty(
"settings.workOrders.workOrderMilestoneDateRecentBeforeDays"
) +
configFunctions.getProperty(
"settings.workOrders.workOrderMilestoneDateRecentAfterDays"
)
configFunctions.getProperty("settings.workOrders.workOrderMilestoneDateRecentAfterDays")
);
const recentAfterDateNumber = dateToInteger(date);
@ -94,17 +94,11 @@ export const getWorkOrderMilestones = (
if (filters.workOrderMilestoneDateString) {
sqlWhereClause += " and m.workOrderMilestoneDate = ?";
sqlParameters.push(
dateStringToInteger(filters.workOrderMilestoneDateString)
);
sqlParameters.push(dateStringToInteger(filters.workOrderMilestoneDateString));
}
if (
filters.workOrderTypeIds &&
commaSeparatedNumbersRegex.test(filters.workOrderTypeIds)
) {
sqlWhereClause +=
" and w.workOrderTypeId in (" + filters.workOrderTypeIds + ")";
if (filters.workOrderTypeIds && commaSeparatedNumbersRegex.test(filters.workOrderTypeIds)) {
sqlWhereClause += " and w.workOrderTypeId in (" + filters.workOrderTypeIds + ")";
}
if (
@ -112,9 +106,7 @@ export const getWorkOrderMilestones = (
commaSeparatedNumbersRegex.test(filters.workOrderMilestoneTypeIds)
) {
sqlWhereClause +=
" and m.workOrderMilestoneTypeId in (" +
filters.workOrderMilestoneTypeIds +
")";
" and m.workOrderMilestoneTypeId in (" + filters.workOrderMilestoneTypeIds + ")";
}
// Order By
@ -138,36 +130,57 @@ export const getWorkOrderMilestones = (
// Query
const sql =
"select m.workOrderMilestoneId," +
" m.workOrderMilestoneTypeId, t.workOrderMilestoneType," +
" m.workOrderMilestoneDate, userFn_dateIntegerToString(m.workOrderMilestoneDate) as workOrderMilestoneDateString," +
" m.workOrderMilestoneTime, userFn_timeIntegerToString(m.workOrderMilestoneTime) as workOrderMilestoneTimeString," +
" m.workOrderMilestoneDescription," +
" m.workOrderMilestoneCompletionDate, userFn_dateIntegerToString(m.workOrderMilestoneCompletionDate) as workOrderMilestoneCompletionDateString," +
" m.workOrderMilestoneCompletionTime, userFn_timeIntegerToString(m.workOrderMilestoneCompletionTime) as workOrderMilestoneCompletionTimeString," +
(options.includeWorkOrders
? " m.workOrderId, w.workOrderNumber, wt.workOrderType, w.workOrderDescription," +
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString," +
" w.recordUpdate_timeMillis as workOrderRecordUpdate_timeMillis,"
: "") +
" m.recordCreate_userName, m.recordCreate_timeMillis," +
" m.recordUpdate_userName, m.recordUpdate_timeMillis" +
" from WorkOrderMilestones m" +
" left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId" +
" left join WorkOrders w on m.workOrderId = w.workOrderId" +
" left join WorkOrderTypes wt on w.workOrderTypeId = wt.workOrderTypeId" +
sqlWhereClause +
orderByClause;
const workOrderMilestones: recordTypes.WorkOrderMilestone[] = database
.prepare(
"select m.workOrderId, m.workOrderMilestoneId," +
" m.workOrderMilestoneTypeId, t.workOrderMilestoneType," +
" m.workOrderMilestoneDate, userFn_dateIntegerToString(m.workOrderMilestoneDate) as workOrderMilestoneDateString," +
" m.workOrderMilestoneTime, userFn_timeIntegerToString(m.workOrderMilestoneTime) as workOrderMilestoneTimeString," +
" m.workOrderMilestoneDescription," +
" m.workOrderMilestoneCompletionDate, userFn_dateIntegerToString(m.workOrderMilestoneCompletionDate) as workOrderMilestoneCompletionDateString," +
" m.workOrderMilestoneCompletionTime, userFn_timeIntegerToString(m.workOrderMilestoneCompletionTime) as workOrderMilestoneCompletionTimeString," +
" m.recordCreate_userName, m.recordCreate_timeMillis," +
" m.recordUpdate_userName, m.recordUpdate_timeMillis" +
" from WorkOrderMilestones m" +
" left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId" +
" left join WorkOrders w on m.workOrderId = w.workOrderId" +
sqlWhereClause +
orderByClause
)
.prepare(sql)
.all(sqlParameters);
if (options.includeWorkOrders) {
for (const workOrderMilestone of workOrderMilestones) {
workOrderMilestone.workOrder = getWorkOrder(
workOrderMilestone.workOrderId,
workOrderMilestone.workOrderLots = getLots(
{
includeLotsAndLotOccupancies: true,
includeComments: false,
includeMilestones: false
workOrderId: workOrderMilestone.workOrderId
},
{
limit: -1,
offset: 0
},
database
);
).lots;
workOrderMilestone.workOrderLotOccupancies = getLotOccupancies(
{
workOrderId: workOrderMilestone.workOrderId
},
{
limit: -1,
offset: 0,
includeOccupants: true
},
database
).lotOccupancies;
}
}

View File

@ -16,7 +16,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
return;
}
milestoneCalendarContainerElement.innerHTML = "";
let currentDate = cityssm.dateToString(new Date());
const currentDate = cityssm.dateToString(new Date());
let currentPanelElement;
let currentPanelDateString = "";
for (const milestone of workOrderMilestones) {
@ -27,18 +27,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
currentPanelElement = document.createElement("div");
currentPanelElement.className = "panel";
currentPanelElement.innerHTML =
'<h2 class="panel-heading">' +
milestone.workOrderMilestoneDateString +
"</h2>";
'<h2 class="panel-heading">' + milestone.workOrderMilestoneDateString + "</h2>";
currentPanelDateString = milestone.workOrderMilestoneDateString;
}
const panelBlockElement = document.createElement("div");
panelBlockElement.className = "panel-block is-block";
if (!milestone.workOrderMilestoneCompletionDate && milestone.workOrderMilestoneDateString < currentDate) {
if (!milestone.workOrderMilestoneCompletionDate &&
milestone.workOrderMilestoneDateString < currentDate) {
panelBlockElement.classList.add("has-background-warning-light");
}
let lotOccupancyHTML = "";
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
lotOccupancyHTML +=
'<i class="fas fa-vector-square" aria-label="' +
cityssm.escapeHTML(exports.aliases.lot) +
@ -46,8 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
cityssm.escapeHTML(lot.lotName) +
"<br />";
}
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
if (lotOccupancy.lotOccupancyOccupants.length > 0) {
lotOccupancyHTML +=
'<i class="fas fa-user" aria-label="' +
@ -80,21 +78,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
"</span>" +
"</div>") +
('<div class="column">' +
"<i class=\"fas fa-circle\" style=\"color:" + los.getRandomColor(milestone.workOrder.workOrderNumber) + "\" aria-hidden=\"true\"></i>" +
'<i class="fas fa-circle" style="color:' +
los.getRandomColor(milestone.workOrderNumber) +
'" aria-hidden="true"></i>' +
' <a class="has-text-weight-bold" href="' +
urlPrefix +
"/workOrders/" +
milestone.workOrderId +
'">' +
cityssm.escapeHTML(milestone.workOrder.workOrderNumber) +
cityssm.escapeHTML(milestone.workOrderNumber) +
"</a><br />" +
'<span class="is-size-7">' +
cityssm.escapeHTML(milestone.workOrder.workOrderDescription) +
cityssm.escapeHTML(milestone.workOrderDescription) +
"</span>" +
"</div>") +
('<div class="column is-size-7">' +
lotOccupancyHTML +
"</div>") +
('<div class="column is-size-7">' + lotOccupancyHTML + "</div>") +
"</div>";
currentPanelElement.append(panelBlockElement);
}

View File

@ -15,23 +15,19 @@ declare const cityssm: cityssmGlobal;
"#form--searchFilters"
) as HTMLFormElement;
const workOrderMilestoneDateFilterElement =
workOrderSearchFiltersFormElement.querySelector(
"#searchFilter--workOrderMilestoneDateFilter"
) as HTMLSelectElement;
const workOrderMilestoneDateFilterElement = workOrderSearchFiltersFormElement.querySelector(
"#searchFilter--workOrderMilestoneDateFilter"
) as HTMLSelectElement;
const workOrderMilestoneDateStringElement =
workOrderSearchFiltersFormElement.querySelector(
"#searchFilter--workOrderMilestoneDateString"
) as HTMLInputElement;
const workOrderMilestoneDateStringElement = workOrderSearchFiltersFormElement.querySelector(
"#searchFilter--workOrderMilestoneDateString"
) as HTMLInputElement;
const milestoneCalendarContainerElement = document.querySelector(
"#container--milestoneCalendar"
) as HTMLElement;
const renderMilestones = (
workOrderMilestones: recordTypes.WorkOrderMilestone[]
) => {
const renderMilestones = (workOrderMilestones: recordTypes.WorkOrderMilestone[]) => {
if (workOrderMilestones.length === 0) {
milestoneCalendarContainerElement.innerHTML =
'<div class="message is-info">' +
@ -42,7 +38,7 @@ declare const cityssm: cityssmGlobal;
milestoneCalendarContainerElement.innerHTML = "";
let currentDate = cityssm.dateToString(new Date());
const currentDate = cityssm.dateToString(new Date());
let currentPanelElement: HTMLElement;
let currentPanelDateString = "";
@ -50,33 +46,32 @@ declare const cityssm: cityssmGlobal;
for (const milestone of workOrderMilestones) {
if (currentPanelDateString !== milestone.workOrderMilestoneDateString) {
if (currentPanelElement) {
milestoneCalendarContainerElement.append(
currentPanelElement
);
milestoneCalendarContainerElement.append(currentPanelElement);
}
currentPanelElement = document.createElement("div");
currentPanelElement.className = "panel";
currentPanelElement.innerHTML =
'<h2 class="panel-heading">' +
milestone.workOrderMilestoneDateString +
"</h2>";
'<h2 class="panel-heading">' + milestone.workOrderMilestoneDateString + "</h2>";
currentPanelDateString = milestone.workOrderMilestoneDateString;
currentPanelDateString = milestone.workOrderMilestoneDateString;
}
const panelBlockElement = document.createElement("div");
panelBlockElement.className = "panel-block is-block";
if (!milestone.workOrderMilestoneCompletionDate && milestone.workOrderMilestoneDateString < currentDate) {
if (
!milestone.workOrderMilestoneCompletionDate &&
milestone.workOrderMilestoneDateString < currentDate
) {
panelBlockElement.classList.add("has-background-warning-light");
}
let lotOccupancyHTML = "";
for (const lot of milestone.workOrder.workOrderLots) {
for (const lot of milestone.workOrderLots) {
lotOccupancyHTML +=
'<i class="fas fa-vector-square" aria-label="' +
cityssm.escapeHTML(exports.aliases.lot) +
@ -85,16 +80,13 @@ declare const cityssm: cityssmGlobal;
"<br />";
}
for (const lotOccupancy of milestone.workOrder
.workOrderLotOccupancies) {
for (const lotOccupancy of milestone.workOrderLotOccupancies) {
if (lotOccupancy.lotOccupancyOccupants.length > 0) {
lotOccupancyHTML +=
'<i class="fas fa-user" aria-label="' +
cityssm.escapeHTML(exports.aliases.lotOccupancy) +
'"></i> ' +
cityssm.escapeHTML(
lotOccupancy.lotOccupancyOccupants[0].occupantName
) +
cityssm.escapeHTML(lotOccupancy.lotOccupancyOccupants[0].occupantName) +
"<br />";
}
}
@ -118,29 +110,25 @@ declare const cityssm: cityssmGlobal;
"</strong><br />"
: "") +
'<span class="is-size-7">' +
cityssm.escapeHTML(
milestone.workOrderMilestoneDescription
) +
cityssm.escapeHTML(milestone.workOrderMilestoneDescription) +
"</span>" +
"</div>") +
('<div class="column">' +
"<i class=\"fas fa-circle\" style=\"color:" + los.getRandomColor(milestone.workOrder.workOrderNumber) + "\" aria-hidden=\"true\"></i>" +
'<i class="fas fa-circle" style="color:' +
los.getRandomColor(milestone.workOrderNumber) +
'" aria-hidden="true"></i>' +
' <a class="has-text-weight-bold" href="' +
urlPrefix +
"/workOrders/" +
milestone.workOrderId +
'">' +
cityssm.escapeHTML(milestone.workOrder.workOrderNumber) +
cityssm.escapeHTML(milestone.workOrderNumber) +
"</a><br />" +
'<span class="is-size-7">' +
cityssm.escapeHTML(
milestone.workOrder.workOrderDescription
) +
cityssm.escapeHTML(milestone.workOrderDescription) +
"</span>" +
"</div>") +
('<div class="column is-size-7">' +
lotOccupancyHTML +
"</div>") +
('<div class="column is-size-7">' + lotOccupancyHTML + "</div>") +
"</div>";
currentPanelElement.append(panelBlockElement);
@ -163,9 +151,7 @@ declare const cityssm: cityssmGlobal;
cityssm.postJSON(
urlPrefix + "/workOrders/doGetWorkOrderMilestones",
workOrderSearchFiltersFormElement,
(responseJSON: {
workOrderMilestones: recordTypes.WorkOrderMilestone[];
}) => {
(responseJSON: { workOrderMilestones: recordTypes.WorkOrderMilestone[] }) => {
renderMilestones(responseJSON.workOrderMilestones);
}
);
@ -177,10 +163,7 @@ declare const cityssm: cityssmGlobal;
getMilestones();
});
workOrderMilestoneDateStringElement.addEventListener(
"change",
getMilestones
);
workOrderMilestoneDateStringElement.addEventListener("change", getMilestones);
workOrderSearchFiltersFormElement.addEventListener("submit", getMilestones);
getMilestones();

View File

@ -1 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,r=document.querySelector("main").dataset.urlPrefix,s=document.querySelector("#form--searchFilters"),a=s.querySelector("#searchFilter--workOrderMilestoneDateFilter"),t=s.querySelector("#searchFilter--workOrderMilestoneDateString"),i=document.querySelector("#container--milestoneCalendar"),o=a=>{a&&a.preventDefault(),i.innerHTML='<div class="has-text-grey has-text-centered"><i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />Loading Milestones...</div>',cityssm.postJSON(r+"/workOrders/doGetWorkOrderMilestones",s,s=>{(s=>{if(0===s.length)return void(i.innerHTML='<div class="message is-info"><p class="message-body">There are no milestones that meet the search criteria.</p></div>');i.innerHTML="";let a,t=cityssm.dateToString(new Date),o="";for(const n of s){o!==n.workOrderMilestoneDateString&&(a&&i.append(a),(a=document.createElement("div")).className="panel",a.innerHTML='<h2 class="panel-heading">'+n.workOrderMilestoneDateString+"</h2>",o=n.workOrderMilestoneDateString);const s=document.createElement("div");s.className="panel-block is-block",!n.workOrderMilestoneCompletionDate&&n.workOrderMilestoneDateString<t&&s.classList.add("has-background-warning-light");let c="";for(const e of n.workOrder.workOrderLots)c+='<i class="fas fa-vector-square" aria-label="'+cityssm.escapeHTML(exports.aliases.lot)+'"></i> '+cityssm.escapeHTML(e.lotName)+"<br />";for(const e of n.workOrder.workOrderLotOccupancies)e.lotOccupancyOccupants.length>0&&(c+='<i class="fas fa-user" aria-label="'+cityssm.escapeHTML(exports.aliases.lotOccupancy)+'"></i> '+cityssm.escapeHTML(e.lotOccupancyOccupants[0].occupantName)+"<br />");s.innerHTML='<div class="columns"><div class="column is-narrow"><span class="icon is-small">'+(n.workOrderMilestoneCompletionDate?'<i class="fas fa-check" aria-label="Completed"></i>':'<i class="far fa-square has-text-grey" aria-label="Incomplete"></i>')+'</span></div><div class="column">'+(0===n.workOrderMilestoneTime?"":n.workOrderMilestoneTimeString+"<br />")+(n.workOrderMilestoneTypeId?"<strong>"+cityssm.escapeHTML(n.workOrderMilestoneType)+"</strong><br />":"")+'<span class="is-size-7">'+cityssm.escapeHTML(n.workOrderMilestoneDescription)+'</span></div><div class="column"><i class="fas fa-circle" style="color:'+e.getRandomColor(n.workOrder.workOrderNumber)+'" aria-hidden="true"></i> <a class="has-text-weight-bold" href="'+r+"/workOrders/"+n.workOrderId+'">'+cityssm.escapeHTML(n.workOrder.workOrderNumber)+'</a><br /><span class="is-size-7">'+cityssm.escapeHTML(n.workOrder.workOrderDescription)+'</span></div><div class="column is-size-7">'+c+"</div></div>",a.append(s)}i.append(a)})(s.workOrderMilestones)})};a.addEventListener("change",()=>{t.disabled="date"!==a.value,o()}),t.addEventListener("change",o),s.addEventListener("submit",o),o()})();
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,s=document.querySelector("main").dataset.urlPrefix,r=document.querySelector("#form--searchFilters"),a=r.querySelector("#searchFilter--workOrderMilestoneDateFilter"),t=r.querySelector("#searchFilter--workOrderMilestoneDateString"),i=document.querySelector("#container--milestoneCalendar"),o=a=>{a&&a.preventDefault(),i.innerHTML='<div class="has-text-grey has-text-centered"><i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />Loading Milestones...</div>',cityssm.postJSON(s+"/workOrders/doGetWorkOrderMilestones",r,r=>{(r=>{if(0===r.length)return void(i.innerHTML='<div class="message is-info"><p class="message-body">There are no milestones that meet the search criteria.</p></div>');i.innerHTML="";const a=cityssm.dateToString(new Date);let t,o="";for(const n of r){o!==n.workOrderMilestoneDateString&&(t&&i.append(t),(t=document.createElement("div")).className="panel",t.innerHTML='<h2 class="panel-heading">'+n.workOrderMilestoneDateString+"</h2>",o=n.workOrderMilestoneDateString);const r=document.createElement("div");r.className="panel-block is-block",!n.workOrderMilestoneCompletionDate&&n.workOrderMilestoneDateString<a&&r.classList.add("has-background-warning-light");let c="";for(const e of n.workOrderLots)c+='<i class="fas fa-vector-square" aria-label="'+cityssm.escapeHTML(exports.aliases.lot)+'"></i> '+cityssm.escapeHTML(e.lotName)+"<br />";for(const e of n.workOrderLotOccupancies)e.lotOccupancyOccupants.length>0&&(c+='<i class="fas fa-user" aria-label="'+cityssm.escapeHTML(exports.aliases.lotOccupancy)+'"></i> '+cityssm.escapeHTML(e.lotOccupancyOccupants[0].occupantName)+"<br />");r.innerHTML='<div class="columns"><div class="column is-narrow"><span class="icon is-small">'+(n.workOrderMilestoneCompletionDate?'<i class="fas fa-check" aria-label="Completed"></i>':'<i class="far fa-square has-text-grey" aria-label="Incomplete"></i>')+'</span></div><div class="column">'+(0===n.workOrderMilestoneTime?"":n.workOrderMilestoneTimeString+"<br />")+(n.workOrderMilestoneTypeId?"<strong>"+cityssm.escapeHTML(n.workOrderMilestoneType)+"</strong><br />":"")+'<span class="is-size-7">'+cityssm.escapeHTML(n.workOrderMilestoneDescription)+'</span></div><div class="column"><i class="fas fa-circle" style="color:'+e.getRandomColor(n.workOrderNumber)+'" aria-hidden="true"></i> <a class="has-text-weight-bold" href="'+s+"/workOrders/"+n.workOrderId+'">'+cityssm.escapeHTML(n.workOrderNumber)+'</a><br /><span class="is-size-7">'+cityssm.escapeHTML(n.workOrderDescription)+'</span></div><div class="column is-size-7">'+c+"</div></div>",t.append(r)}i.append(t)})(r.workOrderMilestones)})};a.addEventListener("change",()=>{t.disabled="date"!==a.value,o()}),t.addEventListener("change",o),r.addEventListener("submit",o),o()})();

View File

@ -206,10 +206,8 @@ export interface WorkOrderComment extends Record {
workOrderCommentTimeString?: string;
workOrderComment?: string;
}
export interface WorkOrderMilestone extends Record {
export interface WorkOrderMilestone extends Record, WorkOrder {
workOrderMilestoneId?: number;
workOrderId?: number;
workOrder?: WorkOrder;
workOrderMilestoneTypeId?: number;
workOrderMilestoneType?: string;
workOrderMilestoneDate?: number;
@ -221,6 +219,7 @@ export interface WorkOrderMilestone extends Record {
workOrderMilestoneCompletionDateString?: string;
workOrderMilestoneCompletionTime?: number;
workOrderMilestoneCompletionTimeString?: string;
workOrderRecordUpdate_timeMillis?: number;
}
export interface WorkOrder extends Record {
workOrderId?: number;

View File

@ -277,12 +277,9 @@ export interface WorkOrderComment extends Record {
workOrderComment?: string;
}
export interface WorkOrderMilestone extends Record {
export interface WorkOrderMilestone extends Record, WorkOrder {
workOrderMilestoneId?: number;
workOrderId?: number;
workOrder?: WorkOrder;
workOrderMilestoneTypeId?: number;
workOrderMilestoneType?: string;
@ -299,6 +296,8 @@ export interface WorkOrderMilestone extends Record {
workOrderMilestoneCompletionTime?: number;
workOrderMilestoneCompletionTimeString?: string;
workOrderRecordUpdate_timeMillis?: number;
}
export interface WorkOrder extends Record {

View File

@ -29,18 +29,18 @@
<strong><%= milestone.workOrderMilestoneType %></strong><br />
<% } %>
<span class="is-size-7">
<i class="fas fa-hard-hat" aria-label="Work Order"></i> <%= milestone.workOrder.workOrderNumber %><br />
<i class="fas fa-hard-hat" aria-label="Work Order"></i> <%= milestone.workOrderNumber %><br />
<%
if (milestone.workOrder.workOrderLots.length > 0) {
for (const lot of milestone.workOrder.workOrderLots) {
if (milestone.workOrderLots.length > 0) {
for (const lot of milestone.workOrderLots) {
%>
<i class="fas fa-vector-square" aria-label="<%= configFunctions.getProperty("aliases.lot") %>"></i> <%= lot.lotName %><br />
<%
}
}
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
for (const occupancy of milestone.workOrder.workOrderLotOccupancies) {
if (milestone.workOrderLotOccupancies.length > 0) {
for (const occupancy of milestone.workOrderLotOccupancies) {
for (const occupant of occupancy.lotOccupancyOccupants) {
%>
<i class="fas fa-user" aria-label="<%= configFunctions.getProperty("aliases.occupancy") %>"></i> <%= occupant.occupantName %><br />