ics calndar export
parent
f0f9c6dfe5
commit
08f5731867
|
|
@ -1,7 +1,17 @@
|
||||||
import ical, { ICalEventStatus } from "ical-generator";
|
import ical, { ICalEventStatus } from "ical-generator";
|
||||||
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
const timeStringSplitRegex = /[ :-]/;
|
const timeStringSplitRegex = /[ :-]/;
|
||||||
|
function escapeHTML(stringToEscape) {
|
||||||
|
return stringToEscape.replace(/[^\d A-Za-z]/g, (c) => "&#" + c.codePointAt(0) + ";");
|
||||||
|
}
|
||||||
export const handler = (request, response) => {
|
export const handler = (request, response) => {
|
||||||
|
const urlRoot = "http://" +
|
||||||
|
request.hostname +
|
||||||
|
(configFunctions.getProperty("application.httpPort") === 80
|
||||||
|
? ""
|
||||||
|
: ":" + configFunctions.getProperty("application.httpPort")) +
|
||||||
|
configFunctions.getProperty("reverseProxy.urlPrefix");
|
||||||
const workOrderMilestones = getWorkOrderMilestones({
|
const workOrderMilestones = getWorkOrderMilestones({
|
||||||
workOrderMilestoneDateFilter: "recent",
|
workOrderMilestoneDateFilter: "recent",
|
||||||
workOrderTypeIds: request.query.workOrderTypeIds,
|
workOrderTypeIds: request.query.workOrderTypeIds,
|
||||||
|
|
@ -9,21 +19,153 @@ export const handler = (request, response) => {
|
||||||
.workOrderMilestoneTypeIds
|
.workOrderMilestoneTypeIds
|
||||||
}, { includeWorkOrders: true, orderBy: "date" });
|
}, { includeWorkOrders: true, orderBy: "date" });
|
||||||
const calendar = ical({
|
const calendar = ical({
|
||||||
name: "Work Order Milestone Calendar"
|
name: "Work Order Milestone Calendar",
|
||||||
|
url: urlRoot + "/workOrders"
|
||||||
|
});
|
||||||
|
calendar.prodId({
|
||||||
|
company: "cityssm.github.io",
|
||||||
|
product: configFunctions.getProperty("application.applicationName")
|
||||||
});
|
});
|
||||||
for (const milestone of workOrderMilestones) {
|
for (const milestone of workOrderMilestones) {
|
||||||
const milestoneTimePieces = (milestone.workOrderMilestoneDateString +
|
const milestoneTimePieces = (milestone.workOrderMilestoneDateString +
|
||||||
" " +
|
" " +
|
||||||
milestone.workOrderMilestoneTimeString).split(timeStringSplitRegex);
|
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 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));
|
||||||
|
let summary = (milestone.workOrderMilestoneTypeId
|
||||||
|
? milestone.workOrderMilestoneType
|
||||||
|
: milestone.workOrderMilestoneDescription).trim();
|
||||||
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
let occupantCount = 0;
|
||||||
|
for (const lotOccupancy of milestone.workOrder
|
||||||
|
.workOrderLotOccupancies) {
|
||||||
|
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
|
||||||
|
occupantCount += 1;
|
||||||
|
if (occupantCount === 1) {
|
||||||
|
if (summary !== "") {
|
||||||
|
summary += ": ";
|
||||||
|
}
|
||||||
|
summary += occupant.occupantName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (occupantCount > 1) {
|
||||||
|
summary += " plus " + (occupantCount - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const workOrderURL = urlRoot + "/workOrders/" + milestone.workOrderId;
|
||||||
const eventData = {
|
const eventData = {
|
||||||
start: milestoneDate,
|
start: milestoneDate,
|
||||||
|
created: new Date(milestone.recordCreate_timeMillis),
|
||||||
stamp: new Date(milestone.recordCreate_timeMillis),
|
stamp: new Date(milestone.recordCreate_timeMillis),
|
||||||
lastModified: new Date(milestone.recordUpdate_timeMillis),
|
lastModified: new Date(Math.max(milestone.recordUpdate_timeMillis, milestone.workOrder.recordUpdate_timeMillis)),
|
||||||
allDay: !milestone.workOrderMilestoneTime,
|
allDay: !milestone.workOrderMilestoneTime,
|
||||||
summary: milestone.workOrderMilestoneDescription
|
summary,
|
||||||
|
url: workOrderURL
|
||||||
};
|
};
|
||||||
const calendarEvent = calendar.createEvent(eventData);
|
const calendarEvent = calendar.createEvent(eventData);
|
||||||
|
let descriptionHTML = "<h1>Milestone Description</h1>" +
|
||||||
|
"<p>" +
|
||||||
|
escapeHTML(milestone.workOrderMilestoneDescription) +
|
||||||
|
"</p>" +
|
||||||
|
"<h2>Work Order #" +
|
||||||
|
milestone.workOrder.workOrderNumber +
|
||||||
|
"</h2>" +
|
||||||
|
("<p>" +
|
||||||
|
escapeHTML(milestone.workOrder.workOrderDescription) +
|
||||||
|
"</p>") +
|
||||||
|
('<p><a href="' + workOrderURL + '">' + workOrderURL + "</a></p>");
|
||||||
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<h2>Related " +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.occupancies")) +
|
||||||
|
"</h2>" +
|
||||||
|
'<table border="1"><thead><tr>' +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.occupancy")) +
|
||||||
|
" Type</th>") +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.lot")) +
|
||||||
|
"</th>") +
|
||||||
|
"<th>Start Date</th>" +
|
||||||
|
"<th>End Date</th>" +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.occupants")) +
|
||||||
|
"</th>") +
|
||||||
|
"</tr></thead>" +
|
||||||
|
"<tbody>";
|
||||||
|
for (const occupancy of milestone.workOrder
|
||||||
|
.workOrderLotOccupancies) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
'<a href="' +
|
||||||
|
urlRoot +
|
||||||
|
"/lotOccupancies/" +
|
||||||
|
occupancy.lotOccupancyId +
|
||||||
|
'">' +
|
||||||
|
escapeHTML(occupancy.occupancyType) +
|
||||||
|
"</a></td>") +
|
||||||
|
("<td>" +
|
||||||
|
(occupancy.lotName
|
||||||
|
? escapeHTML(occupancy.lotName)
|
||||||
|
: "(Not Set)") +
|
||||||
|
"</td>") +
|
||||||
|
("<td>" + occupancy.occupancyStartDateString + "</td>") +
|
||||||
|
"<td>" +
|
||||||
|
(occupancy.occupancyEndDate
|
||||||
|
? occupancy.occupancyEndDateString
|
||||||
|
: "(No End Date)") +
|
||||||
|
"</td>" +
|
||||||
|
"<td>";
|
||||||
|
for (const occupant of occupancy.lotOccupancyOccupants) {
|
||||||
|
descriptionHTML +=
|
||||||
|
escapeHTML(occupant.occupantName) + "<br />";
|
||||||
|
}
|
||||||
|
descriptionHTML += "</td>" + "</tr>";
|
||||||
|
}
|
||||||
|
descriptionHTML += "</tbody></table>";
|
||||||
|
}
|
||||||
|
if (milestone.workOrder.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>Status</th>" +
|
||||||
|
"</tr></thead>" +
|
||||||
|
"<tbody>";
|
||||||
|
for (const lot of milestone.workOrder.workOrderLots) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
'<a href="' +
|
||||||
|
urlRoot +
|
||||||
|
"/lots/" +
|
||||||
|
lot.lotId +
|
||||||
|
'">' +
|
||||||
|
escapeHTML(lot.lotName) +
|
||||||
|
"</a></td>") +
|
||||||
|
("<td>" + escapeHTML(lot.mapName) + "</td>") +
|
||||||
|
("<td>" + escapeHTML(lot.lotType) + "</td>") +
|
||||||
|
("<td>" + escapeHTML(lot.lotStatus) + "</td>") +
|
||||||
|
"</tr>";
|
||||||
|
}
|
||||||
|
descriptionHTML += "</tbody></table>";
|
||||||
|
}
|
||||||
|
calendarEvent.description({
|
||||||
|
plain: workOrderURL,
|
||||||
|
html: descriptionHTML
|
||||||
|
});
|
||||||
if (milestone.workOrderMilestoneCompletionDate) {
|
if (milestone.workOrderMilestoneCompletionDate) {
|
||||||
calendarEvent.status(ICalEventStatus.CONFIRMED);
|
calendarEvent.status(ICalEventStatus.CONFIRMED);
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +173,9 @@ export const handler = (request, response) => {
|
||||||
calendarEvent.createCategory({
|
calendarEvent.createCategory({
|
||||||
name: milestone.workOrderMilestoneType
|
name: milestone.workOrderMilestoneType
|
||||||
});
|
});
|
||||||
|
calendarEvent.createCategory({
|
||||||
|
name: milestone.workOrder.workOrderType
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (milestone.workOrder.workOrderLots.length > 0) {
|
if (milestone.workOrder.workOrderLots.length > 0) {
|
||||||
const lotNames = [];
|
const lotNames = [];
|
||||||
|
|
@ -40,17 +185,33 @@ export const handler = (request, response) => {
|
||||||
calendarEvent.location(lotNames.join(", "));
|
calendarEvent.location(lotNames.join(", "));
|
||||||
}
|
}
|
||||||
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
let organizerSet = false;
|
||||||
for (const lotOccupancy of milestone.workOrder
|
for (const lotOccupancy of milestone.workOrder
|
||||||
.workOrderLotOccupancies) {
|
.workOrderLotOccupancies) {
|
||||||
for (const occupants of lotOccupancy.lotOccupancyOccupants) {
|
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
|
||||||
|
if (organizerSet) {
|
||||||
calendarEvent.createAttendee({
|
calendarEvent.createAttendee({
|
||||||
name: occupants.occupantName,
|
name: occupant.occupantName,
|
||||||
email: "no-reply@example.com"
|
email: "no-reply@127.0.0.1"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
calendarEvent.organizer({
|
||||||
|
name: occupant.occupantName,
|
||||||
|
email: "no-reply@127.0.0.1"
|
||||||
|
});
|
||||||
|
organizerSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
calendarEvent.organizer({
|
||||||
|
name: milestone.recordCreate_userName,
|
||||||
|
email: "no-reply@127.0.0.1"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
calendar.serve(response);
|
calendar.serve(response);
|
||||||
};
|
};
|
||||||
export default handler;
|
export default handler;
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,26 @@ import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrde
|
||||||
import type { RequestHandler } from "express";
|
import type { RequestHandler } from "express";
|
||||||
import { dateIntegerToString } from "@cityssm/expressjs-server-js/dateTimeFns.js";
|
import { dateIntegerToString } from "@cityssm/expressjs-server-js/dateTimeFns.js";
|
||||||
|
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
|
|
||||||
const timeStringSplitRegex = /[ :-]/;
|
const timeStringSplitRegex = /[ :-]/;
|
||||||
|
|
||||||
|
function escapeHTML(stringToEscape: string) {
|
||||||
|
return stringToEscape.replace(
|
||||||
|
/[^\d A-Za-z]/g,
|
||||||
|
(c) => "&#" + c.codePointAt(0) + ";"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const handler: RequestHandler = (request, response) => {
|
export const handler: RequestHandler = (request, response) => {
|
||||||
|
const urlRoot =
|
||||||
|
"http://" +
|
||||||
|
request.hostname +
|
||||||
|
(configFunctions.getProperty("application.httpPort") === 80
|
||||||
|
? ""
|
||||||
|
: ":" + configFunctions.getProperty("application.httpPort")) +
|
||||||
|
configFunctions.getProperty("reverseProxy.urlPrefix");
|
||||||
|
|
||||||
const workOrderMilestones = getWorkOrderMilestones(
|
const workOrderMilestones = getWorkOrderMilestones(
|
||||||
{
|
{
|
||||||
workOrderMilestoneDateFilter: "recent",
|
workOrderMilestoneDateFilter: "recent",
|
||||||
|
|
@ -21,7 +38,13 @@ export const handler: RequestHandler = (request, response) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const calendar = ical({
|
const calendar = ical({
|
||||||
name: "Work Order Milestone Calendar"
|
name: "Work Order Milestone Calendar",
|
||||||
|
url: urlRoot + "/workOrders"
|
||||||
|
});
|
||||||
|
|
||||||
|
calendar.prodId({
|
||||||
|
company: "cityssm.github.io",
|
||||||
|
product: configFunctions.getProperty("application.applicationName")
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const milestone of workOrderMilestones) {
|
for (const milestone of workOrderMilestones) {
|
||||||
|
|
@ -39,26 +62,200 @@ export const handler: RequestHandler = (request, response) => {
|
||||||
Number.parseInt(milestoneTimePieces[4], 10)
|
Number.parseInt(milestoneTimePieces[4], 10)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Build summary (title in Outlook)
|
||||||
|
|
||||||
|
let summary = (
|
||||||
|
milestone.workOrderMilestoneTypeId
|
||||||
|
? milestone.workOrderMilestoneType
|
||||||
|
: milestone.workOrderMilestoneDescription
|
||||||
|
).trim();
|
||||||
|
|
||||||
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
let occupantCount = 0;
|
||||||
|
|
||||||
|
for (const lotOccupancy of milestone.workOrder
|
||||||
|
.workOrderLotOccupancies) {
|
||||||
|
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
|
||||||
|
occupantCount += 1;
|
||||||
|
|
||||||
|
if (occupantCount === 1) {
|
||||||
|
if (summary !== "") {
|
||||||
|
summary += ": ";
|
||||||
|
}
|
||||||
|
|
||||||
|
summary += occupant.occupantName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (occupantCount > 1) {
|
||||||
|
summary += " plus " + (occupantCount - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build URL
|
||||||
|
|
||||||
|
const workOrderURL = urlRoot + "/workOrders/" + milestone.workOrderId;
|
||||||
|
|
||||||
|
// Create event
|
||||||
|
|
||||||
const eventData: ICalEventData = {
|
const eventData: ICalEventData = {
|
||||||
start: milestoneDate,
|
start: milestoneDate,
|
||||||
|
created: new Date(milestone.recordCreate_timeMillis),
|
||||||
stamp: new Date(milestone.recordCreate_timeMillis),
|
stamp: new Date(milestone.recordCreate_timeMillis),
|
||||||
lastModified: new Date(milestone.recordUpdate_timeMillis),
|
lastModified: new Date(
|
||||||
|
Math.max(
|
||||||
|
milestone.recordUpdate_timeMillis,
|
||||||
|
milestone.workOrder.recordUpdate_timeMillis
|
||||||
|
)
|
||||||
|
),
|
||||||
allDay: !milestone.workOrderMilestoneTime,
|
allDay: !milestone.workOrderMilestoneTime,
|
||||||
summary: milestone.workOrderMilestoneDescription
|
summary,
|
||||||
|
url: workOrderURL
|
||||||
};
|
};
|
||||||
|
|
||||||
const calendarEvent = calendar.createEvent(eventData);
|
const calendarEvent = calendar.createEvent(eventData);
|
||||||
|
|
||||||
|
// Build description
|
||||||
|
|
||||||
|
let descriptionHTML =
|
||||||
|
"<h1>Milestone Description</h1>" +
|
||||||
|
"<p>" +
|
||||||
|
escapeHTML(milestone.workOrderMilestoneDescription) +
|
||||||
|
"</p>" +
|
||||||
|
"<h2>Work Order #" +
|
||||||
|
milestone.workOrder.workOrderNumber +
|
||||||
|
"</h2>" +
|
||||||
|
("<p>" +
|
||||||
|
escapeHTML(milestone.workOrder.workOrderDescription) +
|
||||||
|
"</p>") +
|
||||||
|
('<p><a href="' + workOrderURL + '">' + workOrderURL + "</a></p>");
|
||||||
|
|
||||||
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<h2>Related " +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.occupancies")) +
|
||||||
|
"</h2>" +
|
||||||
|
'<table border="1"><thead><tr>' +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(
|
||||||
|
configFunctions.getProperty("aliases.occupancy")
|
||||||
|
) +
|
||||||
|
" Type</th>") +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(configFunctions.getProperty("aliases.lot")) +
|
||||||
|
"</th>") +
|
||||||
|
"<th>Start Date</th>" +
|
||||||
|
"<th>End Date</th>" +
|
||||||
|
("<th>" +
|
||||||
|
escapeHTML(
|
||||||
|
configFunctions.getProperty("aliases.occupants")
|
||||||
|
) +
|
||||||
|
"</th>") +
|
||||||
|
"</tr></thead>" +
|
||||||
|
"<tbody>";
|
||||||
|
|
||||||
|
for (const occupancy of milestone.workOrder
|
||||||
|
.workOrderLotOccupancies) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
'<a href="' +
|
||||||
|
urlRoot +
|
||||||
|
"/lotOccupancies/" +
|
||||||
|
occupancy.lotOccupancyId +
|
||||||
|
'">' +
|
||||||
|
escapeHTML(occupancy.occupancyType) +
|
||||||
|
"</a></td>") +
|
||||||
|
("<td>" +
|
||||||
|
(occupancy.lotName
|
||||||
|
? escapeHTML(occupancy.lotName)
|
||||||
|
: "(Not Set)") +
|
||||||
|
"</td>") +
|
||||||
|
("<td>" + occupancy.occupancyStartDateString + "</td>") +
|
||||||
|
"<td>" +
|
||||||
|
(occupancy.occupancyEndDate
|
||||||
|
? occupancy.occupancyEndDateString
|
||||||
|
: "(No End Date)") +
|
||||||
|
"</td>" +
|
||||||
|
"<td>";
|
||||||
|
|
||||||
|
for (const occupant of occupancy.lotOccupancyOccupants) {
|
||||||
|
descriptionHTML +=
|
||||||
|
escapeHTML(occupant.occupantName) + "<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptionHTML += "</td>" + "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptionHTML += "</tbody></table>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (milestone.workOrder.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>Status</th>" +
|
||||||
|
"</tr></thead>" +
|
||||||
|
"<tbody>";
|
||||||
|
|
||||||
|
for (const lot of milestone.workOrder.workOrderLots) {
|
||||||
|
descriptionHTML +=
|
||||||
|
"<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
'<a href="' +
|
||||||
|
urlRoot +
|
||||||
|
"/lots/" +
|
||||||
|
lot.lotId +
|
||||||
|
'">' +
|
||||||
|
escapeHTML(lot.lotName) +
|
||||||
|
"</a></td>") +
|
||||||
|
("<td>" + escapeHTML(lot.mapName) + "</td>") +
|
||||||
|
("<td>" + escapeHTML(lot.lotType) + "</td>") +
|
||||||
|
("<td>" + escapeHTML(lot.lotStatus) + "</td>") +
|
||||||
|
"</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptionHTML += "</tbody></table>";
|
||||||
|
}
|
||||||
|
|
||||||
|
calendarEvent.description({
|
||||||
|
plain: workOrderURL,
|
||||||
|
html: descriptionHTML
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set status
|
||||||
|
|
||||||
if (milestone.workOrderMilestoneCompletionDate) {
|
if (milestone.workOrderMilestoneCompletionDate) {
|
||||||
calendarEvent.status(ICalEventStatus.CONFIRMED);
|
calendarEvent.status(ICalEventStatus.CONFIRMED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add categories
|
||||||
|
|
||||||
if (milestone.workOrderMilestoneTypeId) {
|
if (milestone.workOrderMilestoneTypeId) {
|
||||||
calendarEvent.createCategory({
|
calendarEvent.createCategory({
|
||||||
name: milestone.workOrderMilestoneType
|
name: milestone.workOrderMilestoneType
|
||||||
});
|
});
|
||||||
|
|
||||||
|
calendarEvent.createCategory({
|
||||||
|
name: milestone.workOrder.workOrderType
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set location
|
||||||
|
|
||||||
if (milestone.workOrder.workOrderLots.length > 0) {
|
if (milestone.workOrder.workOrderLots.length > 0) {
|
||||||
const lotNames = [];
|
const lotNames = [];
|
||||||
|
|
||||||
|
|
@ -69,17 +266,33 @@ export const handler: RequestHandler = (request, response) => {
|
||||||
calendarEvent.location(lotNames.join(", "));
|
calendarEvent.location(lotNames.join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set organizer / attendees
|
||||||
|
|
||||||
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
if (milestone.workOrder.workOrderLotOccupancies.length > 0) {
|
||||||
|
let organizerSet = false;
|
||||||
for (const lotOccupancy of milestone.workOrder
|
for (const lotOccupancy of milestone.workOrder
|
||||||
.workOrderLotOccupancies) {
|
.workOrderLotOccupancies) {
|
||||||
for (const occupants of lotOccupancy.lotOccupancyOccupants) {
|
for (const occupant of lotOccupancy.lotOccupancyOccupants) {
|
||||||
|
if (organizerSet) {
|
||||||
calendarEvent.createAttendee({
|
calendarEvent.createAttendee({
|
||||||
name: occupants.occupantName,
|
name: occupant.occupantName,
|
||||||
email: "no-reply@example.com"
|
email: "no-reply@127.0.0.1"
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
calendarEvent.organizer({
|
||||||
|
name: occupant.occupantName,
|
||||||
|
email: "no-reply@127.0.0.1"
|
||||||
|
});
|
||||||
|
organizerSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
calendarEvent.organizer({
|
||||||
|
name: milestone.recordCreate_userName,
|
||||||
|
email: "no-reply@127.0.0.1"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calendar.serve(response);
|
calendar.serve(response);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ const baseSQL = "select w.workOrderId," +
|
||||||
" w.workOrderTypeId, t.workOrderType," +
|
" w.workOrderTypeId, t.workOrderType," +
|
||||||
" w.workOrderNumber, w.workOrderDescription," +
|
" w.workOrderNumber, w.workOrderDescription," +
|
||||||
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
|
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
|
||||||
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString" +
|
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString," +
|
||||||
|
" w.recordUpdate_timeMillis" +
|
||||||
" from WorkOrders w" +
|
" from WorkOrders w" +
|
||||||
" left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId" +
|
" left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId" +
|
||||||
" where w.recordDelete_timeMillis is null";
|
" where w.recordDelete_timeMillis is null";
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ const baseSQL =
|
||||||
" w.workOrderTypeId, t.workOrderType," +
|
" w.workOrderTypeId, t.workOrderType," +
|
||||||
" w.workOrderNumber, w.workOrderDescription," +
|
" w.workOrderNumber, w.workOrderDescription," +
|
||||||
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
|
" w.workOrderOpenDate, userFn_dateIntegerToString(w.workOrderOpenDate) as workOrderOpenDateString," +
|
||||||
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString" +
|
" w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString," +
|
||||||
|
" w.recordUpdate_timeMillis" +
|
||||||
" from WorkOrders w" +
|
" from WorkOrders w" +
|
||||||
" left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId" +
|
" left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId" +
|
||||||
" where w.recordDelete_timeMillis is null";
|
" where w.recordDelete_timeMillis is null";
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="panel" id="panel--icsFilters">
|
<div class="panel" id="panel--icsFilters">
|
||||||
|
<h2 class="panel-heading">Outlook Calendar (ICS) Integration</h2>
|
||||||
<div class="panel-block is-block">
|
<div class="panel-block is-block">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue