work order development
- add lot occupancies - add lots - display milestones - complete milestones - reopen milestonesdeepsource-autofix-76c6eb20
parent
ab87f933c7
commit
2b38da7bea
|
|
@ -1,4 +1,4 @@
|
|||
import { getWorkOrderTypes } from "../../helpers/functions.cache.js";
|
||||
import { getLotStatuses, getWorkOrderTypes } from "../../helpers/functions.cache.js";
|
||||
import * as configFunctions from "../../helpers/functions.config.js";
|
||||
import { getWorkOrder } from "../../helpers/lotOccupancyDB/getWorkOrder.js";
|
||||
export const handler = (request, response) => {
|
||||
|
|
@ -9,14 +9,18 @@ export const handler = (request, response) => {
|
|||
}
|
||||
if (workOrder.workOrderCloseDate) {
|
||||
return response.redirect(configFunctions.getProperty("reverseProxy.urlPrefix") +
|
||||
"/workOrders/" + workOrder.workOrderId.toString() + "/?error=workOrderIsClosed");
|
||||
"/workOrders/" +
|
||||
workOrder.workOrderId.toString() +
|
||||
"/?error=workOrderIsClosed");
|
||||
}
|
||||
const workOrderTypes = getWorkOrderTypes();
|
||||
const lotStatuses = getLotStatuses();
|
||||
response.render("workOrder-edit", {
|
||||
headTitle: "Work Order #" + workOrder.workOrderNumber,
|
||||
workOrder,
|
||||
isCreate: false,
|
||||
workOrderTypes
|
||||
workOrderTypes,
|
||||
lotStatuses
|
||||
});
|
||||
};
|
||||
export default handler;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import type { RequestHandler } from "express";
|
||||
import { getWorkOrderTypes } from "../../helpers/functions.cache.js";
|
||||
|
||||
import {
|
||||
getLotStatuses,
|
||||
getWorkOrderTypes
|
||||
} from "../../helpers/functions.cache.js";
|
||||
|
||||
import * as configFunctions from "../../helpers/functions.config.js";
|
||||
|
||||
|
|
@ -18,17 +22,22 @@ export const handler: RequestHandler = (request, response) => {
|
|||
if (workOrder.workOrderCloseDate) {
|
||||
return response.redirect(
|
||||
configFunctions.getProperty("reverseProxy.urlPrefix") +
|
||||
"/workOrders/" + workOrder.workOrderId.toString() + "/?error=workOrderIsClosed"
|
||||
"/workOrders/" +
|
||||
workOrder.workOrderId.toString() +
|
||||
"/?error=workOrderIsClosed"
|
||||
);
|
||||
}
|
||||
|
||||
const workOrderTypes = getWorkOrderTypes();
|
||||
|
||||
const lotStatuses = getLotStatuses();
|
||||
|
||||
response.render("workOrder-edit", {
|
||||
headTitle: "Work Order #" + workOrder.workOrderNumber,
|
||||
workOrder,
|
||||
isCreate: false,
|
||||
workOrderTypes
|
||||
workOrderTypes,
|
||||
lotStatuses
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import type { RequestHandler } from "express";
|
||||
export declare const handler: RequestHandler;
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { addWorkOrderLot } from "../../helpers/lotOccupancyDB/addWorkOrderLot.js";
|
||||
import { getLots } from "../../helpers/lotOccupancyDB/getLots.js";
|
||||
export const handler = async (request, response) => {
|
||||
const success = addWorkOrderLot({
|
||||
workOrderId: request.body.workOrderId,
|
||||
lotId: request.body.lotId
|
||||
}, request.session);
|
||||
const workOrderLots = getLots({
|
||||
workOrderId: request.body.workOrderId
|
||||
}, {
|
||||
limit: -1,
|
||||
offset: 0
|
||||
}).lots;
|
||||
response.json({
|
||||
success,
|
||||
workOrderLots
|
||||
});
|
||||
};
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import type { RequestHandler } from "express";
|
||||
|
||||
import { addWorkOrderLot } from "../../helpers/lotOccupancyDB/addWorkOrderLot.js";
|
||||
import { getLots } from "../../helpers/lotOccupancyDB/getLots.js";
|
||||
|
||||
export const handler: RequestHandler = async (request, response) => {
|
||||
const success = addWorkOrderLot(
|
||||
{
|
||||
workOrderId: request.body.workOrderId,
|
||||
lotId: request.body.lotId
|
||||
},
|
||||
request.session
|
||||
);
|
||||
|
||||
const workOrderLots = getLots(
|
||||
{
|
||||
workOrderId: request.body.workOrderId
|
||||
},
|
||||
{
|
||||
limit: -1,
|
||||
offset: 0
|
||||
}
|
||||
).lots;
|
||||
|
||||
response.json({
|
||||
success,
|
||||
workOrderLots
|
||||
});
|
||||
};
|
||||
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import type { RequestHandler } from "express";
|
||||
export declare const handler: RequestHandler;
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { addWorkOrderLotOccupancy } from "../../helpers/lotOccupancyDB/addWorkOrderLotOccupancy.js";
|
||||
import { getLotOccupancies } from "../../helpers/lotOccupancyDB/getLotOccupancies.js";
|
||||
export const handler = async (request, response) => {
|
||||
const success = addWorkOrderLotOccupancy({
|
||||
workOrderId: request.body.workOrderId,
|
||||
lotOccupancyId: request.body.lotOccupancyId
|
||||
}, request.session);
|
||||
const workOrderLotOccupancies = getLotOccupancies({
|
||||
workOrderId: request.body.workOrderId
|
||||
}, {
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
includeOccupants: true
|
||||
}).lotOccupancies;
|
||||
response.json({
|
||||
success,
|
||||
workOrderLotOccupancies
|
||||
});
|
||||
};
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import type { RequestHandler } from "express";
|
||||
|
||||
import { addWorkOrderLotOccupancy } from "../../helpers/lotOccupancyDB/addWorkOrderLotOccupancy.js";
|
||||
import { getLotOccupancies } from "../../helpers/lotOccupancyDB/getLotOccupancies.js";
|
||||
|
||||
export const handler: RequestHandler = async (request, response) => {
|
||||
const success = addWorkOrderLotOccupancy(
|
||||
{
|
||||
workOrderId: request.body.workOrderId,
|
||||
lotOccupancyId: request.body.lotOccupancyId
|
||||
},
|
||||
request.session
|
||||
);
|
||||
|
||||
const workOrderLotOccupancies = getLotOccupancies(
|
||||
{
|
||||
workOrderId: request.body.workOrderId
|
||||
},
|
||||
{
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
includeOccupants: true
|
||||
}
|
||||
).lotOccupancies;
|
||||
|
||||
response.json({
|
||||
success,
|
||||
workOrderLotOccupancies
|
||||
});
|
||||
};
|
||||
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import type { RequestHandler } from "express";
|
||||
export declare const handler: RequestHandler;
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { completeWorkOrderMilestone } from "../../helpers/lotOccupancyDB/completeWorkOrderMiletstone.js";
|
||||
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
||||
export const handler = async (request, response) => {
|
||||
const success = completeWorkOrderMilestone({
|
||||
workOrderMilestoneId: request.body.workOrderMilestoneId
|
||||
}, request.session);
|
||||
const workOrderMilestones = getWorkOrderMilestones(request.body.workOrderId);
|
||||
response.json({
|
||||
success,
|
||||
workOrderMilestones
|
||||
});
|
||||
};
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import type { RequestHandler } from "express";
|
||||
|
||||
import { completeWorkOrderMilestone } from "../../helpers/lotOccupancyDB/completeWorkOrderMiletstone.js";
|
||||
|
||||
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
||||
|
||||
export const handler: RequestHandler = async (request, response) => {
|
||||
const success = completeWorkOrderMilestone(
|
||||
{
|
||||
workOrderMilestoneId: request.body.workOrderMilestoneId
|
||||
},
|
||||
request.session
|
||||
);
|
||||
|
||||
const workOrderMilestones = getWorkOrderMilestones(
|
||||
request.body.workOrderId
|
||||
);
|
||||
|
||||
response.json({
|
||||
success,
|
||||
workOrderMilestones
|
||||
});
|
||||
};
|
||||
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import type { RequestHandler } from "express";
|
||||
export declare const handler: RequestHandler;
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { reopenWorkOrderMilestone } from "../../helpers/lotOccupancyDB/reopenWorkOrderMilestone.js";
|
||||
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
||||
export const handler = async (request, response) => {
|
||||
const success = reopenWorkOrderMilestone(request.body.workOrderMilestoneId, request.session);
|
||||
const workOrderMilestones = getWorkOrderMilestones(request.body.workOrderId);
|
||||
response.json({
|
||||
success,
|
||||
workOrderMilestones
|
||||
});
|
||||
};
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import type { RequestHandler } from "express";
|
||||
|
||||
import { reopenWorkOrderMilestone } from "../../helpers/lotOccupancyDB/reopenWorkOrderMilestone.js";
|
||||
|
||||
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
||||
|
||||
export const handler: RequestHandler = async (request, response) => {
|
||||
const success = reopenWorkOrderMilestone(
|
||||
request.body.workOrderMilestoneId,
|
||||
request.session
|
||||
);
|
||||
|
||||
const workOrderMilestones = getWorkOrderMilestones(
|
||||
request.body.workOrderId
|
||||
);
|
||||
|
||||
response.json({
|
||||
success,
|
||||
workOrderMilestones
|
||||
});
|
||||
};
|
||||
|
||||
export default handler;
|
||||
|
|
@ -3,14 +3,37 @@ import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
|||
export const addWorkOrderLotOccupancy = (workOrderLotOccupancyForm, requestSession) => {
|
||||
const database = sqlite(databasePath);
|
||||
const rightNowMillis = Date.now();
|
||||
const result = database
|
||||
const row = database
|
||||
.prepare("select recordDelete_timeMillis" +
|
||||
" from WorkOrderLotOccupancies" +
|
||||
" where workOrderId = ?" +
|
||||
" and lotOccupancyId = ?")
|
||||
.get(workOrderLotOccupancyForm.workOrderId, workOrderLotOccupancyForm.lotOccupancyId);
|
||||
if (row) {
|
||||
if (row.recordDelete_timeMillis) {
|
||||
database
|
||||
.prepare("update WorkOrderLotOccupancies" +
|
||||
" set recordCreate_userName = ?," +
|
||||
" recordCreate_timeMillis = ?," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?," +
|
||||
" recordDelete_userName = null," +
|
||||
" recordDelete_timeMillis = null" +
|
||||
" where workOrderId = ?" +
|
||||
" and lotOccupancyId = ?")
|
||||
.run(requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis, workOrderLotOccupancyForm.workOrderId, workOrderLotOccupancyForm.lotOccupancyId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
database
|
||||
.prepare("insert into WorkOrderLotOccupancies (" +
|
||||
"workOrderId, lotOccupancyId," +
|
||||
" recordCreate_userName, recordCreate_timeMillis," +
|
||||
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||
" values (?, ?, ?, ?, ?, ?)")
|
||||
.run(workOrderLotOccupancyForm.workOrderId, workOrderLotOccupancyForm.lotOccupancyId, requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis);
|
||||
}
|
||||
database.close();
|
||||
return result.changes > 0;
|
||||
return true;
|
||||
};
|
||||
export default addWorkOrderLotOccupancy;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,43 @@ export const addWorkOrderLotOccupancy = (
|
|||
|
||||
const rightNowMillis = Date.now();
|
||||
|
||||
const result = database
|
||||
const row: { recordDelete_timeMillis?: number } = database
|
||||
.prepare(
|
||||
"select recordDelete_timeMillis" +
|
||||
" from WorkOrderLotOccupancies" +
|
||||
" where workOrderId = ?" +
|
||||
" and lotOccupancyId = ?"
|
||||
)
|
||||
.get(
|
||||
workOrderLotOccupancyForm.workOrderId,
|
||||
workOrderLotOccupancyForm.lotOccupancyId
|
||||
);
|
||||
|
||||
if (row) {
|
||||
if (row.recordDelete_timeMillis) {
|
||||
database
|
||||
.prepare(
|
||||
"update WorkOrderLotOccupancies" +
|
||||
" set recordCreate_userName = ?," +
|
||||
" recordCreate_timeMillis = ?," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?," +
|
||||
" recordDelete_userName = null," +
|
||||
" recordDelete_timeMillis = null" +
|
||||
" where workOrderId = ?" +
|
||||
" and lotOccupancyId = ?"
|
||||
)
|
||||
.run(
|
||||
requestSession.user.userName,
|
||||
rightNowMillis,
|
||||
requestSession.user.userName,
|
||||
rightNowMillis,
|
||||
workOrderLotOccupancyForm.workOrderId,
|
||||
workOrderLotOccupancyForm.lotOccupancyId
|
||||
);
|
||||
}
|
||||
} else {
|
||||
database
|
||||
.prepare(
|
||||
"insert into WorkOrderLotOccupancies (" +
|
||||
"workOrderId, lotOccupancyId," +
|
||||
|
|
@ -33,10 +69,11 @@ export const addWorkOrderLotOccupancy = (
|
|||
requestSession.user.userName,
|
||||
rightNowMillis
|
||||
);
|
||||
}
|
||||
|
||||
database.close();
|
||||
|
||||
return result.changes > 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
export default addWorkOrderLotOccupancy;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import type * as recordTypes from "../../types/recordTypes";
|
||||
interface CompleteWorkOrderMilestoneForm {
|
||||
workOrderMilestoneId: string | number;
|
||||
workOrderMilestoneCompletionDateString?: string;
|
||||
workOrderMilestoneCompletionTimeString?: string;
|
||||
}
|
||||
export declare const completeWorkOrderMilestone: (milestoneForm: CompleteWorkOrderMilestoneForm, requestSession: recordTypes.PartialSession) => boolean;
|
||||
export default completeWorkOrderMilestone;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import sqlite from "better-sqlite3";
|
||||
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||
import { dateStringToInteger, dateToInteger, dateToTimeInteger, timeStringToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js";
|
||||
export const completeWorkOrderMilestone = (milestoneForm, requestSession) => {
|
||||
const rightNow = new Date();
|
||||
const database = sqlite(databasePath);
|
||||
const result = database
|
||||
.prepare("update WorkOrderMilestones" +
|
||||
" set workOrderMilestoneCompletionDate = ?," +
|
||||
" workOrderMilestoneCompletionTime = ?," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?" +
|
||||
" where workOrderMilestoneId = ?")
|
||||
.run(milestoneForm.workOrderMilestoneCompletionDateString
|
||||
? dateStringToInteger(milestoneForm.workOrderMilestoneCompletionDateString)
|
||||
: dateToInteger(rightNow), milestoneForm.workOrderMilestoneCompletionTimeString
|
||||
? timeStringToInteger(milestoneForm.workOrderMilestoneCompletionTimeString)
|
||||
: dateToTimeInteger(rightNow), requestSession.user.userName, rightNow.getTime(), milestoneForm.workOrderMilestoneId);
|
||||
database.close();
|
||||
return result.changes > 0;
|
||||
};
|
||||
export default completeWorkOrderMilestone;
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import sqlite from "better-sqlite3";
|
||||
|
||||
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||
|
||||
import {
|
||||
dateStringToInteger,
|
||||
dateToInteger,
|
||||
dateToTimeInteger,
|
||||
timeStringToInteger
|
||||
} from "@cityssm/expressjs-server-js/dateTimeFns.js";
|
||||
|
||||
import type * as recordTypes from "../../types/recordTypes";
|
||||
|
||||
interface CompleteWorkOrderMilestoneForm {
|
||||
workOrderMilestoneId: string | number;
|
||||
workOrderMilestoneCompletionDateString?: string;
|
||||
workOrderMilestoneCompletionTimeString?: string;
|
||||
}
|
||||
|
||||
export const completeWorkOrderMilestone = (
|
||||
milestoneForm: CompleteWorkOrderMilestoneForm,
|
||||
requestSession: recordTypes.PartialSession
|
||||
): boolean => {
|
||||
const rightNow = new Date();
|
||||
|
||||
const database = sqlite(databasePath);
|
||||
|
||||
const result = database
|
||||
.prepare(
|
||||
"update WorkOrderMilestones" +
|
||||
" set workOrderMilestoneCompletionDate = ?," +
|
||||
" workOrderMilestoneCompletionTime = ?," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?" +
|
||||
" where workOrderMilestoneId = ?"
|
||||
)
|
||||
.run(
|
||||
milestoneForm.workOrderMilestoneCompletionDateString
|
||||
? dateStringToInteger(
|
||||
milestoneForm.workOrderMilestoneCompletionDateString
|
||||
)
|
||||
: dateToInteger(rightNow),
|
||||
milestoneForm.workOrderMilestoneCompletionTimeString
|
||||
? timeStringToInteger(
|
||||
milestoneForm.workOrderMilestoneCompletionTimeString
|
||||
)
|
||||
: dateToTimeInteger(rightNow),
|
||||
requestSession.user.userName,
|
||||
rightNow.getTime(),
|
||||
milestoneForm.workOrderMilestoneId
|
||||
);
|
||||
|
||||
database.close();
|
||||
|
||||
return result.changes > 0;
|
||||
};
|
||||
|
||||
export default completeWorkOrderMilestone;
|
||||
|
|
@ -4,12 +4,14 @@ interface GetLotOccupanciesFilters {
|
|||
lotId?: number | string;
|
||||
occupancyTime?: "" | "past" | "current" | "future";
|
||||
occupancyStartDateString?: string;
|
||||
occupancyEffectiveDateString?: string;
|
||||
occupantName?: string;
|
||||
occupancyTypeId?: number | string;
|
||||
mapId?: number | string;
|
||||
lotName?: string;
|
||||
lotTypeId?: number | string;
|
||||
workOrderId?: number | string;
|
||||
notWorkOrderId?: number | string;
|
||||
}
|
||||
interface GetLotOccupanciesOptions {
|
||||
limit: -1 | number;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
|
|||
sqlWhereClause += " and o.occupancyStartDate = ?";
|
||||
sqlParameters.push(dateStringToInteger(filters.occupancyStartDateString));
|
||||
}
|
||||
if (filters.occupancyEffectiveDateString) {
|
||||
sqlWhereClause +=
|
||||
" and (o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?))";
|
||||
sqlParameters.push(dateStringToInteger(filters.occupancyEffectiveDateString), dateStringToInteger(filters.occupancyEffectiveDateString));
|
||||
}
|
||||
if (filters.mapId) {
|
||||
sqlWhereClause += " and l.mapId = ?";
|
||||
sqlParameters.push(filters.mapId);
|
||||
|
|
@ -70,6 +75,11 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
|
|||
" and o.lotOccupancyId in (select lotOccupancyId from WorkOrderLotOccupancies where recordDelete_timeMillis is null and workOrderId = ?)";
|
||||
sqlParameters.push(filters.workOrderId);
|
||||
}
|
||||
if (filters.notWorkOrderId) {
|
||||
sqlWhereClause +=
|
||||
" 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" +
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@ interface GetLotOccupanciesFilters {
|
|||
lotId?: number | string;
|
||||
occupancyTime?: "" | "past" | "current" | "future";
|
||||
occupancyStartDateString?: string;
|
||||
occupancyEffectiveDateString?: string;
|
||||
occupantName?: string;
|
||||
occupancyTypeId?: number | string;
|
||||
mapId?: number | string;
|
||||
lotName?: string;
|
||||
lotTypeId?: number | string;
|
||||
workOrderId?: number | string;
|
||||
notWorkOrderId?: number | string;
|
||||
}
|
||||
|
||||
interface GetLotOccupanciesOptions {
|
||||
|
|
@ -107,6 +109,15 @@ export const getLotOccupancies = (
|
|||
);
|
||||
}
|
||||
|
||||
if (filters.occupancyEffectiveDateString) {
|
||||
sqlWhereClause +=
|
||||
" and (o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?))";
|
||||
sqlParameters.push(
|
||||
dateStringToInteger(filters.occupancyEffectiveDateString),
|
||||
dateStringToInteger(filters.occupancyEffectiveDateString)
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.mapId) {
|
||||
sqlWhereClause += " and l.mapId = ?";
|
||||
sqlParameters.push(filters.mapId);
|
||||
|
|
@ -123,6 +134,12 @@ export const getLotOccupancies = (
|
|||
sqlParameters.push(filters.workOrderId);
|
||||
}
|
||||
|
||||
if (filters.notWorkOrderId) {
|
||||
sqlWhereClause +=
|
||||
" and o.lotOccupancyId not in (select lotOccupancyId from WorkOrderLotOccupancies where recordDelete_timeMillis is null and workOrderId = ?)";
|
||||
sqlParameters.push(filters.notWorkOrderId);
|
||||
}
|
||||
|
||||
const count: number = database
|
||||
.prepare(
|
||||
"select count(*) as recordCount" +
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import type * as recordTypes from "../../types/recordTypes";
|
||||
export declare const reopenWorkOrderMilestone: (workOrderMilestoneId: number | string, requestSession: recordTypes.PartialSession) => boolean;
|
||||
export default reopenWorkOrderMilestone;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import sqlite from "better-sqlite3";
|
||||
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||
export const reopenWorkOrderMilestone = (workOrderMilestoneId, requestSession) => {
|
||||
const database = sqlite(databasePath);
|
||||
const rightNowMillis = Date.now();
|
||||
const result = database
|
||||
.prepare("update WorkOrderMilestones" +
|
||||
" set workOrderMilestoneCompletionDate = null," +
|
||||
" workOrderMilestoneCompletionTime = null," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?" +
|
||||
" where workOrderMilestoneId = ?" +
|
||||
" and workOrderMilestoneCompletionDate is not null")
|
||||
.run(requestSession.user.userName, rightNowMillis, workOrderMilestoneId);
|
||||
database.close();
|
||||
return result.changes > 0;
|
||||
};
|
||||
export default reopenWorkOrderMilestone;
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import sqlite from "better-sqlite3";
|
||||
|
||||
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||
|
||||
import type * as recordTypes from "../../types/recordTypes";
|
||||
|
||||
export const reopenWorkOrderMilestone = (
|
||||
workOrderMilestoneId: number | string,
|
||||
requestSession: recordTypes.PartialSession
|
||||
): boolean => {
|
||||
const database = sqlite(databasePath);
|
||||
|
||||
const rightNowMillis = Date.now();
|
||||
|
||||
const result = database
|
||||
.prepare(
|
||||
"update WorkOrderMilestones" +
|
||||
" set workOrderMilestoneCompletionDate = null," +
|
||||
" workOrderMilestoneCompletionTime = null," +
|
||||
" recordUpdate_userName = ?," +
|
||||
" recordUpdate_timeMillis = ?" +
|
||||
" where workOrderMilestoneId = ?" +
|
||||
" and workOrderMilestoneCompletionDate is not null"
|
||||
)
|
||||
.run(
|
||||
requestSession.user.userName,
|
||||
rightNowMillis,
|
||||
workOrderMilestoneId
|
||||
);
|
||||
|
||||
database.close();
|
||||
|
||||
return result.changes > 0;
|
||||
};
|
||||
|
||||
export default reopenWorkOrderMilestone;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
(() => {
|
||||
const los = exports.los;
|
||||
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
||||
const workOrderId = document.querySelector("#workOrderEdit--workOrderId").value;
|
||||
const isCreate = workOrderId === "";
|
||||
|
|
@ -79,8 +80,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
}
|
||||
});
|
||||
};
|
||||
const addLot = (lotId, callbackFunction) => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doAddWorkOrderLot", {
|
||||
workOrderId,
|
||||
lotId
|
||||
}, (responseJSON) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLots = responseJSON.workOrderLots;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Adding " + exports.aliases.lot,
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
if (callbackFunction) {
|
||||
callbackFunction(responseJSON.success);
|
||||
}
|
||||
});
|
||||
};
|
||||
const addLotOccupancy = (lotOccupancyId, callbackFunction) => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doAddWorkOrderLotOccupancy", {
|
||||
workOrderId,
|
||||
lotOccupancyId
|
||||
}, (responseJSON) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLotOccupancies =
|
||||
responseJSON.workOrderLotOccupancies;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Adding " + exports.aliases.occupancy,
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
if (callbackFunction) {
|
||||
callbackFunction(responseJSON.success);
|
||||
}
|
||||
});
|
||||
};
|
||||
const addLotFromLotOccupancy = (clickEvent) => {
|
||||
const lotId = clickEvent.currentTarget.dataset
|
||||
.lotId;
|
||||
addLot(lotId);
|
||||
};
|
||||
const renderRelatedOccupancies = () => {
|
||||
const occupanciesContainerElement = document.querySelector("#relatedTab--lotOccupancies");
|
||||
const occupanciesContainerElement = document.querySelector("#container--lotOccupancies");
|
||||
document.querySelector(".tabs a[href='#relatedTab--lotOccupancies'] .tag").textContent = workOrderLotOccupancies.length.toString();
|
||||
if (workOrderLotOccupancies.length === 0) {
|
||||
occupanciesContainerElement.innerHTML =
|
||||
|
|
@ -114,6 +163,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
lotOccupancy.lotOccupancyId.toString();
|
||||
const isActive = !(lotOccupancy.occupancyEndDate &&
|
||||
lotOccupancy.occupancyEndDateString < currentDateString);
|
||||
const hasLotRecord = lotOccupancy.lotId &&
|
||||
workOrderLots.some((lot) => {
|
||||
return lotOccupancy.lotId === lot.lotId;
|
||||
});
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
(isActive
|
||||
|
|
@ -132,15 +185,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
'">' +
|
||||
cityssm.escapeHTML(lotOccupancy.occupancyType) +
|
||||
"</a>" +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
(lotOccupancy.lotId
|
||||
? cityssm.escapeHTML(lotOccupancy.lotName)
|
||||
: '<span class="has-text-grey">(No ' +
|
||||
"</td>");
|
||||
if (lotOccupancy.lotId) {
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
cityssm.escapeHTML(lotOccupancy.lotName) +
|
||||
(hasLotRecord
|
||||
? ""
|
||||
: ' <button class="button is-small is-light is-success button--addLot"' +
|
||||
' data-lot-id="' +
|
||||
lotOccupancy.lotId +
|
||||
'"' +
|
||||
' data-tooltip="Add ' +
|
||||
cityssm.escapeHTML(exports.aliases.lot) +
|
||||
'"' +
|
||||
' aria-label="Add ' +
|
||||
cityssm.escapeHTML(exports.aliases.lot) +
|
||||
'" type="button">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>") +
|
||||
"</td>");
|
||||
}
|
||||
else {
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
'<span class="has-text-grey">(No ' +
|
||||
exports.aliases.lot +
|
||||
")</span>") +
|
||||
"</td>") +
|
||||
("<td>" + lotOccupancy.occupancyStartDateString + "</td>") +
|
||||
")</span>" +
|
||||
"</td>");
|
||||
}
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
lotOccupancy.occupancyStartDateString +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
(lotOccupancy.occupancyEndDate
|
||||
? lotOccupancy.occupancyEndDateString
|
||||
|
|
@ -155,7 +229,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
.occupantName) +
|
||||
(lotOccupancy.lotOccupancyOccupants.length > 1
|
||||
? " plus " +
|
||||
(lotOccupancy.lotOccupancyOccupants.length -
|
||||
(lotOccupancy.lotOccupancyOccupants
|
||||
.length -
|
||||
1)
|
||||
: "")) +
|
||||
"</td>") +
|
||||
|
|
@ -163,7 +238,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
'<button class="button is-small is-light is-danger button--deleteLotOccupancy" data-tooltip="Delete Relationship" type="button">' +
|
||||
'<i class="fas fa-trash" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>");
|
||||
"</td>"));
|
||||
if (lotOccupancy.lotId && !hasLotRecord) {
|
||||
rowElement
|
||||
.querySelector(".button--addLot")
|
||||
.addEventListener("click", addLotFromLotOccupancy);
|
||||
}
|
||||
rowElement
|
||||
.querySelector(".button--deleteLotOccupancy")
|
||||
.addEventListener("click", deleteLotOccupancy);
|
||||
|
|
@ -180,8 +260,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
lotId
|
||||
}, (responseJSON) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLots =
|
||||
responseJSON.workOrderLots;
|
||||
workOrderLots = responseJSON.workOrderLots;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
}
|
||||
else {
|
||||
|
|
@ -212,7 +291,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
});
|
||||
};
|
||||
const renderRelatedLots = () => {
|
||||
const lotsContainerElement = document.querySelector("#relatedTab--lots");
|
||||
const lotsContainerElement = document.querySelector("#container--lots");
|
||||
document.querySelector(".tabs a[href='#relatedTab--lots'] .tag").textContent = workOrderLots.length.toString();
|
||||
if (workOrderLots.length === 0) {
|
||||
lotsContainerElement.innerHTML =
|
||||
|
|
@ -269,5 +348,398 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
renderRelatedLots();
|
||||
};
|
||||
renderRelatedLotsAndOccupancies();
|
||||
document
|
||||
.querySelector("#button--addLotOccupancy")
|
||||
.addEventListener("click", () => {
|
||||
let searchFormElement;
|
||||
let searchResultsContainerElement;
|
||||
const doAddLotOccupancy = (clickEvent) => {
|
||||
const rowElement = clickEvent.currentTarget.closest("tr");
|
||||
const lotOccupancyId = rowElement.dataset.lotOccupancyId;
|
||||
addLotOccupancy(lotOccupancyId, (success) => {
|
||||
if (success) {
|
||||
rowElement.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
const doSearch = (event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<p class="has-text-centered has-text-grey-dark">' +
|
||||
'<i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />' +
|
||||
"Searching..." +
|
||||
"</p>";
|
||||
cityssm.postJSON(urlPrefix + "/lotOccupancies/doSearchLotOccupancies", searchFormElement, (responseJSON) => {
|
||||
if (responseJSON.lotOccupancies.length === 0) {
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<div class="message is-info">' +
|
||||
'<p class="message-body">There are no records that meet the search criteria.</p>' +
|
||||
"</div>";
|
||||
return;
|
||||
}
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<table class="table is-fullwidth is-striped is-hoverable">' +
|
||||
"<thead>" +
|
||||
"<tr>" +
|
||||
'<th class="has-width-1"></th>' +
|
||||
("<th>" +
|
||||
exports.aliases.occupancy +
|
||||
" Type</th>") +
|
||||
("<th>" + exports.aliases.lot + "</th>") +
|
||||
"<th>Start Date</th>" +
|
||||
"<th>End Date</th>" +
|
||||
("<th>" + exports.aliases.occupants + "</th>") +
|
||||
"</tr>" +
|
||||
"</thead>" +
|
||||
"<tbody></tbody>" +
|
||||
"</table>";
|
||||
for (const lotOccupancy of responseJSON.lotOccupancies) {
|
||||
const rowElement = document.createElement("tr");
|
||||
rowElement.className =
|
||||
"container--lotOccupancy";
|
||||
rowElement.dataset.lotOccupancyId =
|
||||
lotOccupancy.lotOccupancyId.toString();
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
'<button class="button is-small is-success button--addLotOccupancy" data-tooltip="Add" type="button" aria-label="Add">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>" +
|
||||
('<td class="has-text-weight-bold">' +
|
||||
cityssm.escapeHTML(lotOccupancy.occupancyType) +
|
||||
"</td>");
|
||||
if (lotOccupancy.lotId) {
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
cityssm.escapeHTML(lotOccupancy.lotName) +
|
||||
"</td>");
|
||||
}
|
||||
else {
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
'<span class="has-text-grey">(No ' +
|
||||
exports.aliases.lot +
|
||||
")</span>" +
|
||||
"</td>");
|
||||
}
|
||||
rowElement.insertAdjacentHTML("beforeend", "<td>" +
|
||||
lotOccupancy.occupancyStartDateString +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
(lotOccupancy.occupancyEndDate
|
||||
? lotOccupancy.occupancyEndDateString
|
||||
: '<span class="has-text-grey">(No End Date)</span>') +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
(lotOccupancy.lotOccupancyOccupants
|
||||
.length === 0
|
||||
? '<span class="has-text-grey">(No ' +
|
||||
cityssm.escapeHTML(exports.aliases.occupants) +
|
||||
")</span>"
|
||||
: cityssm.escapeHTML(lotOccupancy
|
||||
.lotOccupancyOccupants[0]
|
||||
.occupantName) +
|
||||
(lotOccupancy
|
||||
.lotOccupancyOccupants
|
||||
.length > 1
|
||||
? " plus " +
|
||||
(lotOccupancy
|
||||
.lotOccupancyOccupants
|
||||
.length -
|
||||
1)
|
||||
: "")) +
|
||||
"</td>"));
|
||||
rowElement
|
||||
.querySelector(".button--addLotOccupancy")
|
||||
.addEventListener("click", doAddLotOccupancy);
|
||||
searchResultsContainerElement
|
||||
.querySelector("tbody")
|
||||
.append(rowElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
cityssm.openHtmlModal("workOrder-addLotOccupancy", {
|
||||
onshow: (modalElement) => {
|
||||
los.populateAliases(modalElement);
|
||||
searchFormElement = modalElement.querySelector("form");
|
||||
searchResultsContainerElement =
|
||||
modalElement.querySelector("#resultsContainer--lotOccupancyAdd");
|
||||
modalElement.querySelector("#lotOccupancySearch--notWorkOrderId").value = workOrderId;
|
||||
modalElement.querySelector("#lotOccupancySearch--occupancyEffectiveDateString").value = document.querySelector("#workOrderEdit--workOrderOpenDateString").value;
|
||||
doSearch();
|
||||
},
|
||||
onshown: (modalElement) => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
modalElement
|
||||
.querySelector("#lotOccupancySearch--occupantName")
|
||||
.addEventListener("change", doSearch);
|
||||
modalElement
|
||||
.querySelector("#lotOccupancySearch--lotName")
|
||||
.addEventListener("change", doSearch);
|
||||
searchFormElement.addEventListener("submit", doSearch);
|
||||
},
|
||||
onremoved: () => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
}
|
||||
});
|
||||
});
|
||||
document
|
||||
.querySelector("#button--addLot")
|
||||
.addEventListener("click", () => {
|
||||
let searchFormElement;
|
||||
let searchResultsContainerElement;
|
||||
const doAddLot = (clickEvent) => {
|
||||
const rowElement = clickEvent.currentTarget.closest("tr");
|
||||
const lotId = rowElement.dataset.lotId;
|
||||
addLot(lotId, (success) => {
|
||||
if (success) {
|
||||
rowElement.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
const doSearch = (event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<p class="has-text-centered has-text-grey-dark">' +
|
||||
'<i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />' +
|
||||
"Searching..." +
|
||||
"</p>";
|
||||
cityssm.postJSON(urlPrefix + "/lots/doSearchLots", searchFormElement, (responseJSON) => {
|
||||
if (responseJSON.lots.length === 0) {
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<div class="message is-info">' +
|
||||
'<p class="message-body">There are no records that meet the search criteria.</p>' +
|
||||
"</div>";
|
||||
return;
|
||||
}
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<table class="table is-fullwidth is-striped is-hoverable">' +
|
||||
"<thead>" +
|
||||
"<tr>" +
|
||||
'<th class="has-width-1"></th>' +
|
||||
("<th>" + exports.aliases.lot + "</th>") +
|
||||
("<th>" + exports.aliases.map + "</th>") +
|
||||
("<th>" + exports.aliases.lot + " Type</th>") +
|
||||
"<th>Status</th>" +
|
||||
"</tr>" +
|
||||
"</thead>" +
|
||||
"<tbody></tbody>" +
|
||||
"</table>";
|
||||
for (const lot of responseJSON.lots) {
|
||||
const rowElement = document.createElement("tr");
|
||||
rowElement.className = "container--lot";
|
||||
rowElement.dataset.lotId = lot.lotId.toString();
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
'<button class="button is-small is-success button--addLot" data-tooltip="Add" type="button" aria-label="Add">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>" +
|
||||
('<td class="has-text-weight-bold">' +
|
||||
cityssm.escapeHTML(lot.lotName) +
|
||||
"</td>") +
|
||||
"<td>" +
|
||||
cityssm.escapeHTML(lot.mapName) +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
cityssm.escapeHTML(lot.lotType) +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
cityssm.escapeHTML(lot.lotStatus) +
|
||||
"</td>");
|
||||
rowElement
|
||||
.querySelector(".button--addLot")
|
||||
.addEventListener("click", doAddLot);
|
||||
searchResultsContainerElement
|
||||
.querySelector("tbody")
|
||||
.append(rowElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
cityssm.openHtmlModal("workOrder-addLot", {
|
||||
onshow: (modalElement) => {
|
||||
los.populateAliases(modalElement);
|
||||
searchFormElement = modalElement.querySelector("form");
|
||||
searchResultsContainerElement =
|
||||
modalElement.querySelector("#resultsContainer--lotAdd");
|
||||
modalElement.querySelector("#lotSearch--notWorkOrderId").value = workOrderId;
|
||||
const lotStatusElement = modalElement.querySelector("#lotSearch--lotStatusId");
|
||||
for (const lotStatus of exports.lotStatuses) {
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value =
|
||||
lotStatus.lotStatusId.toString();
|
||||
optionElement.textContent = lotStatus.lotStatus;
|
||||
lotStatusElement.append(optionElement);
|
||||
}
|
||||
doSearch();
|
||||
},
|
||||
onshown: (modalElement) => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
modalElement
|
||||
.querySelector("#lotSearch--lotName")
|
||||
.addEventListener("change", doSearch);
|
||||
modalElement
|
||||
.querySelector("#lotSearch--lotStatusId")
|
||||
.addEventListener("change", doSearch);
|
||||
searchFormElement.addEventListener("submit", doSearch);
|
||||
},
|
||||
onremoved: () => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!isCreate) {
|
||||
let workOrderMilestones = exports.workOrderMilestones;
|
||||
delete exports.workOrderMilestones;
|
||||
const completeMilestone = (clickEvent) => {
|
||||
clickEvent.preventDefault();
|
||||
const workOrderMilestoneId = clickEvent.currentTarget.closest(".container--milestone").dataset.workOrderMilestoneId;
|
||||
const doComplete = () => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doCompleteWorkOrderMilestone", {
|
||||
workOrderId,
|
||||
workOrderMilestoneId
|
||||
}, (responseJSON) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderMilestones = responseJSON.workOrderMilestones;
|
||||
renderMilestones();
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Completing Milestone",
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
bulmaJS.confirm({
|
||||
title: "Complete Milestone",
|
||||
message: "Are you sure you want to complete this milestone?",
|
||||
contextualColorName: "warning",
|
||||
okButton: {
|
||||
text: "Yes, Complete Milestone",
|
||||
callbackFunction: doComplete
|
||||
}
|
||||
});
|
||||
};
|
||||
const reopenMilestone = (clickEvent) => {
|
||||
clickEvent.preventDefault();
|
||||
const workOrderMilestoneId = clickEvent.currentTarget.closest(".container--milestone").dataset.workOrderMilestoneId;
|
||||
const doReopen = () => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doReopenWorkOrderMilestone", {
|
||||
workOrderId,
|
||||
workOrderMilestoneId
|
||||
}, (responseJSON) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderMilestones = responseJSON.workOrderMilestones;
|
||||
renderMilestones();
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Reopening Milestone",
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
bulmaJS.confirm({
|
||||
title: "Reopen Milestone",
|
||||
message: "Are you sure you want to remove the completion status from this milestone, and reopen it?",
|
||||
contextualColorName: "warning",
|
||||
okButton: {
|
||||
text: "Yes, Reopen Milestone",
|
||||
callbackFunction: doReopen
|
||||
}
|
||||
});
|
||||
};
|
||||
const deleteMilestone = (clickEvent) => {
|
||||
clickEvent.preventDefault();
|
||||
};
|
||||
const renderMilestones = () => {
|
||||
const milestonesPanelElement = document.querySelector("#panel--milestones");
|
||||
const panelBlockElementsToDelete = milestonesPanelElement.querySelectorAll(".panel-block");
|
||||
for (const panelBlockToDelete of panelBlockElementsToDelete) {
|
||||
panelBlockToDelete.remove();
|
||||
}
|
||||
for (const milestone of workOrderMilestones) {
|
||||
const panelBlockElement = document.createElement("div");
|
||||
panelBlockElement.className =
|
||||
"panel-block is-block container--milestone";
|
||||
panelBlockElement.dataset.workOrderMilestoneId =
|
||||
milestone.workOrderMilestoneId.toString();
|
||||
panelBlockElement.innerHTML =
|
||||
'<div class="columns">' +
|
||||
('<div class="column is-narrow">' +
|
||||
(milestone.workOrderMilestoneCompletionDate
|
||||
? '<span class="button is-static" data-tooltip="Completed ' +
|
||||
milestone.workOrderMilestoneCompletionDateString +
|
||||
'" aria-label="Completed ' +
|
||||
milestone.workOrderMilestoneCompletionDateString +
|
||||
'">' +
|
||||
'<span class="icon is-small"><i class="fas fa-check" aria-hidden="true"></i></span>' +
|
||||
"</span>"
|
||||
: '<button class="button button--completeMilestone" data-tooltip="Incomplete" type="button" aria-label="Incomplete">' +
|
||||
'<span class="icon is-small"><i class="far fa-square" aria-hidden="true"></i></span>' +
|
||||
"</button>") +
|
||||
"</div>") +
|
||||
('<div class="column">' +
|
||||
(milestone.workOrderMilestoneTypeId
|
||||
? "<strong>" +
|
||||
cityssm.escapeHTML(milestone.workOrderMilestoneType) +
|
||||
"</strong><br />"
|
||||
: "") +
|
||||
milestone.workOrderMilestoneDateString +
|
||||
"<br />" +
|
||||
'<span class="is-size-7">' +
|
||||
cityssm.escapeHTML(milestone.workOrderMilestoneDescription) +
|
||||
"</span>" +
|
||||
"</div>") +
|
||||
('<div class="column is-narrow">' +
|
||||
'<div class="dropdown is-right">' +
|
||||
('<div class="dropdown-trigger">' +
|
||||
'<button class="button is-small" data-tooltip="Options" type="button" aria-label="Options">' +
|
||||
'<i class="fas fa-ellipsis-v" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</div>") +
|
||||
('<div class="dropdown-menu">' +
|
||||
'<div class="dropdown-content">' +
|
||||
(milestone.workOrderMilestoneCompletionDate
|
||||
? '<a class="dropdown-item button--reopenMilestone" href="#">' +
|
||||
'<span class="icon is-small"><i class="fas fa-times" aria-hidden="true"></i></span>' +
|
||||
" <span>Reopen Milestone</span>" +
|
||||
"</a>" +
|
||||
'<hr class="dropdown-divider" />'
|
||||
: "") +
|
||||
'<a class="dropdown-item button--deleteMilestone" href="#">' +
|
||||
'<span class="icon is-small"><i class="fas fa-trash has-text-danger" aria-hidden="true"></i></span>' +
|
||||
" <span>Delete Milestone</span>" +
|
||||
"</a>" +
|
||||
"</div>" +
|
||||
"</div>") +
|
||||
"</div>" +
|
||||
"</div>") +
|
||||
"</div>";
|
||||
if (milestone.workOrderMilestoneCompletionDate) {
|
||||
panelBlockElement
|
||||
.querySelector(".button--reopenMilestone")
|
||||
.addEventListener("click", reopenMilestone);
|
||||
}
|
||||
else {
|
||||
panelBlockElement
|
||||
.querySelector(".button--completeMilestone")
|
||||
.addEventListener("click", completeMilestone);
|
||||
}
|
||||
panelBlockElement
|
||||
.querySelector(".button--deleteMilestone")
|
||||
.addEventListener("click", deleteMilestone);
|
||||
milestonesPanelElement.append(panelBlockElement);
|
||||
}
|
||||
bulmaJS.init(milestonesPanelElement);
|
||||
};
|
||||
renderMilestones();
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,17 @@
|
|||
|
||||
import type { cityssmGlobal } from "@cityssm/bulma-webapp-js/src/types";
|
||||
import type { BulmaJS } from "@cityssm/bulma-js/types";
|
||||
|
||||
import type * as globalTypes from "../types/globalTypes";
|
||||
import type * as recordTypes from "../types/recordTypes";
|
||||
import { response } from "express";
|
||||
|
||||
declare const cityssm: cityssmGlobal;
|
||||
declare const bulmaJS: BulmaJS;
|
||||
|
||||
(() => {
|
||||
const los = exports.los as globalTypes.LOS;
|
||||
|
||||
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
||||
|
||||
const workOrderId = (
|
||||
|
|
@ -124,9 +129,82 @@ declare const bulmaJS: BulmaJS;
|
|||
});
|
||||
};
|
||||
|
||||
const addLot = (
|
||||
lotId: number | string,
|
||||
callbackFunction?: (success?: boolean) => void
|
||||
) => {
|
||||
cityssm.postJSON(
|
||||
urlPrefix + "/workOrders/doAddWorkOrderLot",
|
||||
{
|
||||
workOrderId,
|
||||
lotId
|
||||
},
|
||||
(responseJSON: {
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
workOrderLots?: recordTypes.Lot[];
|
||||
}) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLots = responseJSON.workOrderLots;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Adding " + exports.aliases.lot,
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
|
||||
if (callbackFunction) {
|
||||
callbackFunction(responseJSON.success);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const addLotOccupancy = (
|
||||
lotOccupancyId: number | string,
|
||||
callbackFunction?: (success?: boolean) => void
|
||||
) => {
|
||||
cityssm.postJSON(
|
||||
urlPrefix + "/workOrders/doAddWorkOrderLotOccupancy",
|
||||
{
|
||||
workOrderId,
|
||||
lotOccupancyId
|
||||
},
|
||||
(responseJSON: {
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
workOrderLotOccupancies?: recordTypes.LotOccupancy[];
|
||||
}) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLotOccupancies =
|
||||
responseJSON.workOrderLotOccupancies;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Adding " + exports.aliases.occupancy,
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
|
||||
if (callbackFunction) {
|
||||
callbackFunction(responseJSON.success);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const addLotFromLotOccupancy = (clickEvent: Event) => {
|
||||
const lotId = (clickEvent.currentTarget as HTMLElement).dataset
|
||||
.lotId;
|
||||
addLot(lotId);
|
||||
};
|
||||
|
||||
const renderRelatedOccupancies = () => {
|
||||
const occupanciesContainerElement = document.querySelector(
|
||||
"#relatedTab--lotOccupancies"
|
||||
"#container--lotOccupancies"
|
||||
) as HTMLElement;
|
||||
|
||||
document.querySelector(
|
||||
|
|
@ -173,6 +251,12 @@ declare const bulmaJS: BulmaJS;
|
|||
lotOccupancy.occupancyEndDateString < currentDateString
|
||||
);
|
||||
|
||||
const hasLotRecord =
|
||||
lotOccupancy.lotId &&
|
||||
workOrderLots.some((lot) => {
|
||||
return lotOccupancy.lotId === lot.lotId;
|
||||
});
|
||||
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
(isActive
|
||||
|
|
@ -191,15 +275,45 @@ declare const bulmaJS: BulmaJS;
|
|||
'">' +
|
||||
cityssm.escapeHTML(lotOccupancy.occupancyType) +
|
||||
"</a>" +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
(lotOccupancy.lotId
|
||||
? cityssm.escapeHTML(lotOccupancy.lotName)
|
||||
: '<span class="has-text-grey">(No ' +
|
||||
"</td>");
|
||||
|
||||
if (lotOccupancy.lotId) {
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
cityssm.escapeHTML(lotOccupancy.lotName) +
|
||||
(hasLotRecord
|
||||
? ""
|
||||
: ' <button class="button is-small is-light is-success button--addLot"' +
|
||||
' data-lot-id="' +
|
||||
lotOccupancy.lotId +
|
||||
'"' +
|
||||
' data-tooltip="Add ' +
|
||||
cityssm.escapeHTML(exports.aliases.lot) +
|
||||
'"' +
|
||||
' aria-label="Add ' +
|
||||
cityssm.escapeHTML(exports.aliases.lot) +
|
||||
'" type="button">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>") +
|
||||
"</td>"
|
||||
);
|
||||
} else {
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
'<span class="has-text-grey">(No ' +
|
||||
exports.aliases.lot +
|
||||
")</span>") +
|
||||
"</td>") +
|
||||
("<td>" + lotOccupancy.occupancyStartDateString + "</td>") +
|
||||
")</span>" +
|
||||
"</td>"
|
||||
);
|
||||
}
|
||||
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
lotOccupancy.occupancyStartDateString +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
(lotOccupancy.occupancyEndDate
|
||||
? lotOccupancy.occupancyEndDateString
|
||||
|
|
@ -208,7 +322,9 @@ declare const bulmaJS: BulmaJS;
|
|||
("<td>" +
|
||||
(lotOccupancy.lotOccupancyOccupants.length === 0
|
||||
? '<span class="has-text-grey">(No ' +
|
||||
cityssm.escapeHTML(exports.aliases.occupants) +
|
||||
cityssm.escapeHTML(
|
||||
exports.aliases.occupants
|
||||
) +
|
||||
")</span>"
|
||||
: cityssm.escapeHTML(
|
||||
lotOccupancy.lotOccupancyOccupants[0]
|
||||
|
|
@ -216,7 +332,8 @@ declare const bulmaJS: BulmaJS;
|
|||
) +
|
||||
(lotOccupancy.lotOccupancyOccupants.length > 1
|
||||
? " plus " +
|
||||
(lotOccupancy.lotOccupancyOccupants.length -
|
||||
(lotOccupancy.lotOccupancyOccupants
|
||||
.length -
|
||||
1)
|
||||
: "")) +
|
||||
"</td>") +
|
||||
|
|
@ -224,7 +341,14 @@ declare const bulmaJS: BulmaJS;
|
|||
'<button class="button is-small is-light is-danger button--deleteLotOccupancy" data-tooltip="Delete Relationship" type="button">' +
|
||||
'<i class="fas fa-trash" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>");
|
||||
"</td>")
|
||||
);
|
||||
|
||||
if (lotOccupancy.lotId && !hasLotRecord) {
|
||||
rowElement
|
||||
.querySelector(".button--addLot")
|
||||
.addEventListener("click", addLotFromLotOccupancy);
|
||||
}
|
||||
|
||||
rowElement
|
||||
.querySelector(".button--deleteLotOccupancy")
|
||||
|
|
@ -256,8 +380,7 @@ declare const bulmaJS: BulmaJS;
|
|||
workOrderLots?: recordTypes.Lot[];
|
||||
}) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderLots =
|
||||
responseJSON.workOrderLots;
|
||||
workOrderLots = responseJSON.workOrderLots;
|
||||
renderRelatedLotsAndOccupancies();
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
|
|
@ -293,7 +416,7 @@ declare const bulmaJS: BulmaJS;
|
|||
|
||||
const renderRelatedLots = () => {
|
||||
const lotsContainerElement = document.querySelector(
|
||||
"#relatedTab--lots"
|
||||
"#container--lots"
|
||||
) as HTMLElement;
|
||||
|
||||
document.querySelector(
|
||||
|
|
@ -364,6 +487,348 @@ declare const bulmaJS: BulmaJS;
|
|||
};
|
||||
|
||||
renderRelatedLotsAndOccupancies();
|
||||
|
||||
document
|
||||
.querySelector("#button--addLotOccupancy")
|
||||
.addEventListener("click", () => {
|
||||
let searchFormElement: HTMLFormElement;
|
||||
let searchResultsContainerElement: HTMLElement;
|
||||
|
||||
const doAddLotOccupancy = (clickEvent: Event) => {
|
||||
const rowElement = (
|
||||
clickEvent.currentTarget as HTMLElement
|
||||
).closest("tr");
|
||||
|
||||
const lotOccupancyId = rowElement.dataset.lotOccupancyId;
|
||||
|
||||
addLotOccupancy(lotOccupancyId, (success) => {
|
||||
if (success) {
|
||||
rowElement.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const doSearch = (event?: Event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<p class="has-text-centered has-text-grey-dark">' +
|
||||
'<i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />' +
|
||||
"Searching..." +
|
||||
"</p>";
|
||||
|
||||
cityssm.postJSON(
|
||||
urlPrefix + "/lotOccupancies/doSearchLotOccupancies",
|
||||
searchFormElement,
|
||||
(responseJSON: {
|
||||
lotOccupancies: recordTypes.LotOccupancy[];
|
||||
}) => {
|
||||
if (responseJSON.lotOccupancies.length === 0) {
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<div class="message is-info">' +
|
||||
'<p class="message-body">There are no records that meet the search criteria.</p>' +
|
||||
"</div>";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<table class="table is-fullwidth is-striped is-hoverable">' +
|
||||
"<thead>" +
|
||||
"<tr>" +
|
||||
'<th class="has-width-1"></th>' +
|
||||
("<th>" +
|
||||
exports.aliases.occupancy +
|
||||
" Type</th>") +
|
||||
("<th>" + exports.aliases.lot + "</th>") +
|
||||
"<th>Start Date</th>" +
|
||||
"<th>End Date</th>" +
|
||||
("<th>" + exports.aliases.occupants + "</th>") +
|
||||
"</tr>" +
|
||||
"</thead>" +
|
||||
"<tbody></tbody>" +
|
||||
"</table>";
|
||||
|
||||
for (const lotOccupancy of responseJSON.lotOccupancies) {
|
||||
const rowElement = document.createElement("tr");
|
||||
rowElement.className =
|
||||
"container--lotOccupancy";
|
||||
rowElement.dataset.lotOccupancyId =
|
||||
lotOccupancy.lotOccupancyId.toString();
|
||||
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
'<button class="button is-small is-success button--addLotOccupancy" data-tooltip="Add" type="button" aria-label="Add">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>" +
|
||||
('<td class="has-text-weight-bold">' +
|
||||
cityssm.escapeHTML(
|
||||
lotOccupancy.occupancyType
|
||||
) +
|
||||
"</td>");
|
||||
|
||||
if (lotOccupancy.lotId) {
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
cityssm.escapeHTML(
|
||||
lotOccupancy.lotName
|
||||
) +
|
||||
"</td>"
|
||||
);
|
||||
} else {
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
'<span class="has-text-grey">(No ' +
|
||||
exports.aliases.lot +
|
||||
")</span>" +
|
||||
"</td>"
|
||||
);
|
||||
}
|
||||
|
||||
rowElement.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<td>" +
|
||||
lotOccupancy.occupancyStartDateString +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
(lotOccupancy.occupancyEndDate
|
||||
? lotOccupancy.occupancyEndDateString
|
||||
: '<span class="has-text-grey">(No End Date)</span>') +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
(lotOccupancy.lotOccupancyOccupants
|
||||
.length === 0
|
||||
? '<span class="has-text-grey">(No ' +
|
||||
cityssm.escapeHTML(
|
||||
exports.aliases.occupants
|
||||
) +
|
||||
")</span>"
|
||||
: cityssm.escapeHTML(
|
||||
lotOccupancy
|
||||
.lotOccupancyOccupants[0]
|
||||
.occupantName
|
||||
) +
|
||||
(lotOccupancy
|
||||
.lotOccupancyOccupants
|
||||
.length > 1
|
||||
? " plus " +
|
||||
(lotOccupancy
|
||||
.lotOccupancyOccupants
|
||||
.length -
|
||||
1)
|
||||
: "")) +
|
||||
"</td>")
|
||||
);
|
||||
|
||||
rowElement
|
||||
.querySelector(".button--addLotOccupancy")
|
||||
.addEventListener(
|
||||
"click",
|
||||
doAddLotOccupancy
|
||||
);
|
||||
|
||||
searchResultsContainerElement
|
||||
.querySelector("tbody")
|
||||
.append(rowElement);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
cityssm.openHtmlModal("workOrder-addLotOccupancy", {
|
||||
onshow: (modalElement) => {
|
||||
los.populateAliases(modalElement);
|
||||
|
||||
searchFormElement = modalElement.querySelector("form");
|
||||
searchResultsContainerElement =
|
||||
modalElement.querySelector(
|
||||
"#resultsContainer--lotOccupancyAdd"
|
||||
);
|
||||
|
||||
(
|
||||
modalElement.querySelector(
|
||||
"#lotOccupancySearch--notWorkOrderId"
|
||||
) as HTMLInputElement
|
||||
).value = workOrderId;
|
||||
|
||||
(
|
||||
modalElement.querySelector(
|
||||
"#lotOccupancySearch--occupancyEffectiveDateString"
|
||||
) as HTMLInputElement
|
||||
).value = (
|
||||
document.querySelector(
|
||||
"#workOrderEdit--workOrderOpenDateString"
|
||||
) as HTMLInputElement
|
||||
).value;
|
||||
|
||||
doSearch();
|
||||
},
|
||||
onshown: (modalElement) => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
|
||||
modalElement
|
||||
.querySelector("#lotOccupancySearch--occupantName")
|
||||
.addEventListener("change", doSearch);
|
||||
modalElement
|
||||
.querySelector("#lotOccupancySearch--lotName")
|
||||
.addEventListener("change", doSearch);
|
||||
|
||||
searchFormElement.addEventListener("submit", doSearch);
|
||||
},
|
||||
onremoved: () => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector("#button--addLot")
|
||||
.addEventListener("click", () => {
|
||||
let searchFormElement: HTMLFormElement;
|
||||
let searchResultsContainerElement: HTMLElement;
|
||||
|
||||
const doAddLot = (clickEvent: Event) => {
|
||||
const rowElement = (
|
||||
clickEvent.currentTarget as HTMLElement
|
||||
).closest("tr");
|
||||
|
||||
const lotId = rowElement.dataset.lotId;
|
||||
|
||||
addLot(lotId, (success) => {
|
||||
if (success) {
|
||||
rowElement.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const doSearch = (event?: Event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<p class="has-text-centered has-text-grey-dark">' +
|
||||
'<i class="fas fa-5x fa-circle-notch fa-spin" aria-hidden="true"></i><br />' +
|
||||
"Searching..." +
|
||||
"</p>";
|
||||
|
||||
cityssm.postJSON(
|
||||
urlPrefix + "/lots/doSearchLots",
|
||||
searchFormElement,
|
||||
(responseJSON: { lots: recordTypes.Lot[] }) => {
|
||||
if (responseJSON.lots.length === 0) {
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<div class="message is-info">' +
|
||||
'<p class="message-body">There are no records that meet the search criteria.</p>' +
|
||||
"</div>";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
searchResultsContainerElement.innerHTML =
|
||||
'<table class="table is-fullwidth is-striped is-hoverable">' +
|
||||
"<thead>" +
|
||||
"<tr>" +
|
||||
'<th class="has-width-1"></th>' +
|
||||
("<th>" + exports.aliases.lot + "</th>") +
|
||||
("<th>" + exports.aliases.map + "</th>") +
|
||||
("<th>" + exports.aliases.lot + " Type</th>") +
|
||||
"<th>Status</th>" +
|
||||
"</tr>" +
|
||||
"</thead>" +
|
||||
"<tbody></tbody>" +
|
||||
"</table>";
|
||||
|
||||
for (const lot of responseJSON.lots) {
|
||||
const rowElement = document.createElement("tr");
|
||||
rowElement.className = "container--lot";
|
||||
rowElement.dataset.lotId = lot.lotId.toString();
|
||||
|
||||
rowElement.innerHTML =
|
||||
'<td class="has-text-centered">' +
|
||||
'<button class="button is-small is-success button--addLot" data-tooltip="Add" type="button" aria-label="Add">' +
|
||||
'<i class="fas fa-plus" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</td>" +
|
||||
('<td class="has-text-weight-bold">' +
|
||||
cityssm.escapeHTML(lot.lotName) +
|
||||
"</td>") +
|
||||
"<td>" +
|
||||
cityssm.escapeHTML(lot.mapName) +
|
||||
"</td>" +
|
||||
("<td>" +
|
||||
cityssm.escapeHTML(lot.lotType) +
|
||||
"</td>") +
|
||||
("<td>" +
|
||||
cityssm.escapeHTML(lot.lotStatus) +
|
||||
"</td>");
|
||||
|
||||
rowElement
|
||||
.querySelector(".button--addLot")
|
||||
.addEventListener("click", doAddLot);
|
||||
|
||||
searchResultsContainerElement
|
||||
.querySelector("tbody")
|
||||
.append(rowElement);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
cityssm.openHtmlModal("workOrder-addLot", {
|
||||
onshow: (modalElement) => {
|
||||
los.populateAliases(modalElement);
|
||||
|
||||
searchFormElement = modalElement.querySelector("form");
|
||||
searchResultsContainerElement =
|
||||
modalElement.querySelector(
|
||||
"#resultsContainer--lotAdd"
|
||||
);
|
||||
|
||||
(
|
||||
modalElement.querySelector(
|
||||
"#lotSearch--notWorkOrderId"
|
||||
) as HTMLInputElement
|
||||
).value = workOrderId;
|
||||
|
||||
const lotStatusElement = modalElement.querySelector(
|
||||
"#lotSearch--lotStatusId"
|
||||
) as HTMLSelectElement;
|
||||
|
||||
for (const lotStatus of exports.lotStatuses as recordTypes.LotStatus[]) {
|
||||
const optionElement =
|
||||
document.createElement("option");
|
||||
optionElement.value =
|
||||
lotStatus.lotStatusId.toString();
|
||||
optionElement.textContent = lotStatus.lotStatus;
|
||||
lotStatusElement.append(optionElement);
|
||||
}
|
||||
|
||||
doSearch();
|
||||
},
|
||||
onshown: (modalElement) => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
|
||||
modalElement
|
||||
.querySelector("#lotSearch--lotName")
|
||||
.addEventListener("change", doSearch);
|
||||
|
||||
modalElement
|
||||
.querySelector("#lotSearch--lotStatusId")
|
||||
.addEventListener("change", doSearch);
|
||||
|
||||
searchFormElement.addEventListener("submit", doSearch);
|
||||
},
|
||||
onremoved: () => {
|
||||
bulmaJS.toggleHtmlClipped();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -373,4 +838,193 @@ declare const bulmaJS: BulmaJS;
|
|||
/*
|
||||
* Milestones
|
||||
*/
|
||||
|
||||
if (!isCreate) {
|
||||
let workOrderMilestones =
|
||||
exports.workOrderMilestones as recordTypes.WorkOrderMilestone[];
|
||||
delete exports.workOrderMilestones;
|
||||
|
||||
const completeMilestone = (clickEvent: Event) => {
|
||||
clickEvent.preventDefault();
|
||||
|
||||
const workOrderMilestoneId = (
|
||||
(clickEvent.currentTarget as HTMLElement).closest(
|
||||
".container--milestone"
|
||||
) as HTMLElement
|
||||
).dataset.workOrderMilestoneId;
|
||||
|
||||
const doComplete = () => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doCompleteWorkOrderMilestone", {
|
||||
workOrderId,
|
||||
workOrderMilestoneId
|
||||
},
|
||||
(responseJSON: {success: boolean; errorMessage?: string; workOrderMilestones?: recordTypes.WorkOrderMilestone[];}) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderMilestones = responseJSON.workOrderMilestones;
|
||||
renderMilestones();
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Completing Milestone",
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
bulmaJS.confirm({
|
||||
title: "Complete Milestone",
|
||||
message: "Are you sure you want to complete this milestone?",
|
||||
contextualColorName: "warning",
|
||||
okButton: {
|
||||
text: "Yes, Complete Milestone",
|
||||
callbackFunction: doComplete
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const reopenMilestone = (clickEvent: Event) => {
|
||||
clickEvent.preventDefault();
|
||||
|
||||
const workOrderMilestoneId = (
|
||||
(clickEvent.currentTarget as HTMLElement).closest(
|
||||
".container--milestone"
|
||||
) as HTMLElement
|
||||
).dataset.workOrderMilestoneId;
|
||||
|
||||
const doReopen = () => {
|
||||
cityssm.postJSON(urlPrefix + "/workOrders/doReopenWorkOrderMilestone", {
|
||||
workOrderId,
|
||||
workOrderMilestoneId
|
||||
},
|
||||
(responseJSON: {success: boolean; errorMessage?: string; workOrderMilestones?: recordTypes.WorkOrderMilestone[];}) => {
|
||||
if (responseJSON.success) {
|
||||
workOrderMilestones = responseJSON.workOrderMilestones;
|
||||
renderMilestones();
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
title: "Error Reopening Milestone",
|
||||
message: responseJSON.errorMessage,
|
||||
contextualColorName: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
bulmaJS.confirm({
|
||||
title: "Reopen Milestone",
|
||||
message: "Are you sure you want to remove the completion status from this milestone, and reopen it?",
|
||||
contextualColorName: "warning",
|
||||
okButton: {
|
||||
text: "Yes, Reopen Milestone",
|
||||
callbackFunction: doReopen
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const deleteMilestone = (clickEvent: Event) => {
|
||||
clickEvent.preventDefault();
|
||||
};
|
||||
|
||||
const renderMilestones = () => {
|
||||
// Clear milestones panel
|
||||
|
||||
const milestonesPanelElement = document.querySelector(
|
||||
"#panel--milestones"
|
||||
) as HTMLElement;
|
||||
|
||||
const panelBlockElementsToDelete =
|
||||
milestonesPanelElement.querySelectorAll(".panel-block");
|
||||
|
||||
for (const panelBlockToDelete of panelBlockElementsToDelete) {
|
||||
panelBlockToDelete.remove();
|
||||
}
|
||||
|
||||
for (const milestone of workOrderMilestones) {
|
||||
const panelBlockElement = document.createElement("div");
|
||||
panelBlockElement.className =
|
||||
"panel-block is-block container--milestone";
|
||||
|
||||
panelBlockElement.dataset.workOrderMilestoneId =
|
||||
milestone.workOrderMilestoneId.toString();
|
||||
|
||||
panelBlockElement.innerHTML =
|
||||
'<div class="columns">' +
|
||||
('<div class="column is-narrow">' +
|
||||
(milestone.workOrderMilestoneCompletionDate
|
||||
? '<span class="button is-static" data-tooltip="Completed ' +
|
||||
milestone.workOrderMilestoneCompletionDateString +
|
||||
'" aria-label="Completed ' +
|
||||
milestone.workOrderMilestoneCompletionDateString +
|
||||
'">' +
|
||||
'<span class="icon is-small"><i class="fas fa-check" aria-hidden="true"></i></span>' +
|
||||
"</span>"
|
||||
: '<button class="button button--completeMilestone" data-tooltip="Incomplete" type="button" aria-label="Incomplete">' +
|
||||
'<span class="icon is-small"><i class="far fa-square" aria-hidden="true"></i></span>' +
|
||||
"</button>") +
|
||||
"</div>") +
|
||||
('<div class="column">' +
|
||||
(milestone.workOrderMilestoneTypeId
|
||||
? "<strong>" +
|
||||
cityssm.escapeHTML(
|
||||
milestone.workOrderMilestoneType
|
||||
) +
|
||||
"</strong><br />"
|
||||
: "") +
|
||||
milestone.workOrderMilestoneDateString +
|
||||
"<br />" +
|
||||
'<span class="is-size-7">' +
|
||||
cityssm.escapeHTML(
|
||||
milestone.workOrderMilestoneDescription
|
||||
) +
|
||||
"</span>" +
|
||||
"</div>") +
|
||||
('<div class="column is-narrow">' +
|
||||
'<div class="dropdown is-right">' +
|
||||
('<div class="dropdown-trigger">' +
|
||||
'<button class="button is-small" data-tooltip="Options" type="button" aria-label="Options">' +
|
||||
'<i class="fas fa-ellipsis-v" aria-hidden="true"></i>' +
|
||||
"</button>" +
|
||||
"</div>") +
|
||||
('<div class="dropdown-menu">' +
|
||||
'<div class="dropdown-content">' +
|
||||
(milestone.workOrderMilestoneCompletionDate
|
||||
? '<a class="dropdown-item button--reopenMilestone" href="#">' +
|
||||
'<span class="icon is-small"><i class="fas fa-times" aria-hidden="true"></i></span>' +
|
||||
" <span>Reopen Milestone</span>" +
|
||||
"</a>" +
|
||||
'<hr class="dropdown-divider" />'
|
||||
: "") +
|
||||
'<a class="dropdown-item button--deleteMilestone" href="#">' +
|
||||
'<span class="icon is-small"><i class="fas fa-trash has-text-danger" aria-hidden="true"></i></span>' +
|
||||
" <span>Delete Milestone</span>" +
|
||||
"</a>" +
|
||||
"</div>" +
|
||||
"</div>") +
|
||||
"</div>" +
|
||||
"</div>") +
|
||||
"</div>";
|
||||
|
||||
if (milestone.workOrderMilestoneCompletionDate) {
|
||||
panelBlockElement
|
||||
.querySelector(".button--reopenMilestone")
|
||||
.addEventListener("click", reopenMilestone);
|
||||
} else {
|
||||
panelBlockElement
|
||||
.querySelector(".button--completeMilestone")
|
||||
.addEventListener("click", completeMilestone);
|
||||
}
|
||||
|
||||
panelBlockElement
|
||||
.querySelector(".button--deleteMilestone")
|
||||
.addEventListener("click", deleteMilestone);
|
||||
|
||||
milestonesPanelElement.append(panelBlockElement);
|
||||
}
|
||||
|
||||
bulmaJS.init(milestonesPanelElement);
|
||||
};
|
||||
|
||||
renderMilestones();
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<div class="modal">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-card" style="width:900px">
|
||||
<header class="modal-card-head">
|
||||
<h3 class="modal-card-title">
|
||||
Add Related <span class="alias" data-alias="Lot"></span> to Work Order
|
||||
</h3>
|
||||
<button class="delete is-close-modal-button" aria-label="close" type="button"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<div class="box">
|
||||
<form id="form--lotSearch">
|
||||
<input name="limit" type="hidden" value="100" />
|
||||
<input name="offset" type="hidden" value="0" />
|
||||
<input id="lotSearch--notWorkOrderId" name="notWorkOrderId" type="hidden" value="" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label" for="lotSearch--lotName">
|
||||
<span class="alias" data-alias="Lot"></span>
|
||||
Name
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<input class="input" id="lotSearch--lotName" name="lotName" type="text" />
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label" for="lotSearch--lotStatusId">Status</label>
|
||||
<div class="control has-icons-left">
|
||||
<div class="select is-fullwidth">
|
||||
<select id="lotSearch--lotStatusId" name="lotStatusId">
|
||||
<option value="">(All Statuses)</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="resultsContainer--lotAdd"></div>
|
||||
</section>
|
||||
<footer class="modal-card-foot justify-right">
|
||||
<button class="button is-close-modal-button" type="button">Close</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<div class="modal">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-card" style="width:900px">
|
||||
<header class="modal-card-head">
|
||||
<h3 class="modal-card-title">
|
||||
Add Related <span class="alias" data-alias="Occupancy"></span> to Work Order
|
||||
</h3>
|
||||
<button class="delete is-close-modal-button" aria-label="close" type="button"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<div class="box">
|
||||
<form id="form--lotOccupancySearch">
|
||||
<input name="limit" type="hidden" value="100" />
|
||||
<input name="offset" type="hidden" value="0" />
|
||||
<input id="lotOccupancySearch--notWorkOrderId" name="notWorkOrderId" type="hidden" value="" />
|
||||
<input id="lotOccupancySearch--occupancyEffectiveDateString" name="occupancyEffectiveDateString" type="hidden" value="" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label" for="lotOccupancySearch--occupantName">
|
||||
<span class="alias" data-alias="Occupant"></span>
|
||||
Name
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<input class="input" id="lotOccupancySearch--occupantName" name="occupantName" type="text" />
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label" for="lotOccupancySearch--lotName">
|
||||
<span class="alias" data-alias="Lot"></span>
|
||||
Name
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<input class="input" id="lotOccupancySearch--lotName" name="lotName" type="text" />
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="resultsContainer--lotOccupancyAdd"></div>
|
||||
</section>
|
||||
<footer class="modal-card-foot justify-right">
|
||||
<button class="button is-close-modal-button" type="button">Close</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -6,8 +6,12 @@ import handler_view from "../handlers/workOrders-get/view.js";
|
|||
import handler_doReopenWorkOrder from "../handlers/workOrders-post/doReopenWorkOrder.js";
|
||||
import handler_edit from "../handlers/workOrders-get/edit.js";
|
||||
import handler_doUpdateWorkOrder from "../handlers/workOrders-post/doUpdateWorkOrder.js";
|
||||
import handler_doAddWorkOrderLotOccupancy from "../handlers/workOrders-post/doAddWorkOrderLotOccupancy.js";
|
||||
import handler_doDeleteWorkOrderLotOccupancy from "../handlers/workOrders-post/doDeleteWorkOrderLotOccupancy.js";
|
||||
import handler_doAddWorkOrderLot from "../handlers/workOrders-post/doAddWorkOrderLot.js";
|
||||
import handler_doDeleteWorkOrderLot from "../handlers/workOrders-post/doDeleteWorkOrderLot.js";
|
||||
import handler_doCompleteWorkOrderMilestone from "../handlers/workOrders-post/doCompleteWorkOrderMilestone.js";
|
||||
import handler_doReopenWorkOrderMilestone from "../handlers/workOrders-post/doReopenWorkOrderMilestone.js";
|
||||
export const router = Router();
|
||||
router.get("/", handler_search);
|
||||
router.post("/doSearchWorkOrders", handler_doSearchWorkOrders);
|
||||
|
|
@ -15,6 +19,10 @@ router.get("/:workOrderId", handler_view);
|
|||
router.post("/doReopenWorkOrder", permissionHandlers.updatePostHandler, handler_doReopenWorkOrder);
|
||||
router.get("/:workOrderId/edit", permissionHandlers.updateGetHandler, handler_edit);
|
||||
router.post("/doUpdateWorkOrder", permissionHandlers.updatePostHandler, handler_doUpdateWorkOrder);
|
||||
router.post("/doAddWorkOrderLotOccupancy", permissionHandlers.updatePostHandler, handler_doAddWorkOrderLotOccupancy);
|
||||
router.post("/doDeleteWorkOrderLotOccupancy", permissionHandlers.updatePostHandler, handler_doDeleteWorkOrderLotOccupancy);
|
||||
router.post("/doAddWorkOrderLot", permissionHandlers.updatePostHandler, handler_doAddWorkOrderLot);
|
||||
router.post("/doDeleteWorkOrderLot", permissionHandlers.updatePostHandler, handler_doDeleteWorkOrderLot);
|
||||
router.post("/doCompleteWorkOrderMilestone", permissionHandlers.updatePostHandler, handler_doCompleteWorkOrderMilestone);
|
||||
router.post("/doReopenWorkOrderMilestone", permissionHandlers.updatePostHandler, handler_doReopenWorkOrderMilestone);
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,16 @@ import handler_doReopenWorkOrder from "../handlers/workOrders-post/doReopenWorkO
|
|||
|
||||
import handler_edit from "../handlers/workOrders-get/edit.js";
|
||||
import handler_doUpdateWorkOrder from "../handlers/workOrders-post/doUpdateWorkOrder.js";
|
||||
|
||||
import handler_doAddWorkOrderLotOccupancy from "../handlers/workOrders-post/doAddWorkOrderLotOccupancy.js";
|
||||
import handler_doDeleteWorkOrderLotOccupancy from "../handlers/workOrders-post/doDeleteWorkOrderLotOccupancy.js";
|
||||
|
||||
import handler_doAddWorkOrderLot from "../handlers/workOrders-post/doAddWorkOrderLot.js";
|
||||
import handler_doDeleteWorkOrderLot from "../handlers/workOrders-post/doDeleteWorkOrderLot.js";
|
||||
|
||||
import handler_doCompleteWorkOrderMilestone from "../handlers/workOrders-post/doCompleteWorkOrderMilestone.js";
|
||||
import handler_doReopenWorkOrderMilestone from "../handlers/workOrders-post/doReopenWorkOrderMilestone.js";
|
||||
|
||||
export const router = Router();
|
||||
|
||||
router.get("/", handler_search);
|
||||
|
|
@ -39,16 +46,40 @@ router.post(
|
|||
handler_doUpdateWorkOrder
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doAddWorkOrderLotOccupancy",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doAddWorkOrderLotOccupancy
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doDeleteWorkOrderLotOccupancy",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doDeleteWorkOrderLotOccupancy
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doAddWorkOrderLot",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doAddWorkOrderLot
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doDeleteWorkOrderLot",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doDeleteWorkOrderLot
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doCompleteWorkOrderMilestone",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doCompleteWorkOrderMilestone
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/doReopenWorkOrderMilestone",
|
||||
permissionHandlers.updatePostHandler,
|
||||
handler_doReopenWorkOrderMilestone
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
<% } %>
|
||||
</h1>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<form id="form--workOrderEdit">
|
||||
<input id="workOrderEdit--workOrderId" name="workOrderId" type="hidden" value="<%= workOrder.workOrderId %>" />
|
||||
<div class="panel">
|
||||
|
|
@ -126,25 +128,11 @@
|
|||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<% if (!isCreate) { %>
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h2 class="title has-text-weight-bold is-5">Related <%= configFunctions.getProperty("aliases.lots") %></h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<button class="button is-small is-success" id="button--addWorkOrderLot" type="button">
|
||||
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
|
||||
<span>Add <%= configFunctions.getProperty("aliases.lots") %></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel mt-4">
|
||||
<h2 class="panel-heading">Related <%= configFunctions.getProperty("aliases.lots") %></h2>
|
||||
<div class="panel-block is-block">
|
||||
<%
|
||||
const tabToSelect = (workOrder.workOrderLotOccupancies.length > 0 || workOrder.workOrderLots.length === 0 ? "lotOccupancies" : "lots");
|
||||
|
|
@ -167,14 +155,53 @@
|
|||
</div>
|
||||
<div class="tab-container">
|
||||
<div class="<%= (tabToSelect === "lotOccupancies" ? "" : "is-hidden") %>" id="relatedTab--lotOccupancies">
|
||||
<div class="box has-background-light has-text-right p-3">
|
||||
<button class="button is-success" id="button--addLotOccupancy" type="button">
|
||||
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
|
||||
<span>Add Related <%= configFunctions.getProperty("aliases.occupancy") %></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="container--lotOccupancies"></div>
|
||||
</div>
|
||||
<div class="<%= (tabToSelect === "lots" ? "" : "is-hidden") %>" id="relatedTab--lots">
|
||||
<div class="box has-background-light has-text-right p-3">
|
||||
<button class="button is-success" id="button--addLot" type="button">
|
||||
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
|
||||
<span>Add Related <%= configFunctions.getProperty("aliases.lot") %></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="container--lots"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
</form>
|
||||
</div>
|
||||
<% if (!isCreate) { %>
|
||||
<div class="column is-4">
|
||||
<div class="panel" id="panel--milestones">
|
||||
<div class="panel-heading">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h2 class="title has-text-weight-bold is-5">Milestones</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<button class="button is-small is-success" id="button--addMilestone" type="button">
|
||||
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
|
||||
<span>Add Milestone</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
|
||||
<%- include('_footerA'); -%>
|
||||
|
||||
|
|
@ -183,6 +210,8 @@
|
|||
exports.workOrderLots = <%- JSON.stringify(workOrder.workOrderLots) %>;
|
||||
exports.workOrderLotOccupancies = <%- JSON.stringify(workOrder.workOrderLotOccupancies) %>;
|
||||
exports.workOrderMilestones = <%- JSON.stringify(workOrder.workOrderMilestones) %>;
|
||||
|
||||
exports.lotStatuses = <%- JSON.stringify(lotStatuses) %>;
|
||||
</script>
|
||||
<script src="<% urlPrefix %>/javascripts/workOrderEdit.min.js"></script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue