@plusscommunities/pluss-maintenance-aws-feedback 2.1.15-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/createJob.js +136 -0
- package/createJobType.js +64 -0
- package/db/maintenance/addMaintenanceJob.js +105 -0
- package/db/maintenance/editMaintenanceJob.js +18 -0
- package/db/maintenance/getJobEmail.js +28 -0
- package/deleteJob.js +74 -0
- package/deleteJobType.js +54 -0
- package/editJob.js +83 -0
- package/editJobStatus.js +81 -0
- package/editJobType.js +76 -0
- package/editNote.js +136 -0
- package/feature.config.js +255 -0
- package/getData.js +49 -0
- package/getJob.js +14 -0
- package/getJobType.js +47 -0
- package/getJobTypes.js +85 -0
- package/getJobs.js +63 -0
- package/integration/IntegrationStrategy.js +50 -0
- package/integration/archibus/ArchibusStrategy.js +591 -0
- package/integration/index.js +27 -0
- package/jobChanged.js +127 -0
- package/package-lock.json +7662 -0
- package/package.json +64 -0
- package/requests/assignRequest.js +106 -0
- package/requests/getAssignees.js +40 -0
- package/requests/getRequest.js +89 -0
- package/requests/getRequests.js +106 -0
- package/requests/helper/hasRequestPermission.js +25 -0
- package/requests/helper/isValidAssignee.js +23 -0
- package/requests/updatePriority.js +46 -0
- package/scheduleJobImport.js +81 -0
- package/sendJobEmail.js +153 -0
- package/updateData.js +37 -0
- package/values.config.a.js +27 -0
- package/values.config.default.js +30 -0
- package/values.config.enquiry.js +223 -0
- package/values.config.feedback.js +195 -0
- package/values.config.forms.js +30 -0
- package/values.config.js +195 -0
- package/watchJobs.js +177 -0
package/getJobs.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const config = require("./config.json");
|
|
2
|
+
const { init } = require("@plusscommunities/pluss-core-aws/config");
|
|
3
|
+
const { getBody } = require("@plusscommunities/pluss-core-aws/helper");
|
|
4
|
+
const generateJsonResponse = require("@plusscommunities/pluss-core-aws/helper/generateJsonResponse");
|
|
5
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
6
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
7
|
+
const getSessionUser = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUser");
|
|
8
|
+
const { values } = require("./values.config");
|
|
9
|
+
|
|
10
|
+
module.exports.getJobs = async (event, context, callback) => {
|
|
11
|
+
init(config);
|
|
12
|
+
const data = getBody(event);
|
|
13
|
+
|
|
14
|
+
if (!data.site) {
|
|
15
|
+
return callback(
|
|
16
|
+
null,
|
|
17
|
+
generateJsonResponse(422, {
|
|
18
|
+
error: { message: "User Types fetch -- no site detected." },
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const authorised = await validateMasterAuth(
|
|
25
|
+
event,
|
|
26
|
+
values.permissionMaintenanceTracking
|
|
27
|
+
);
|
|
28
|
+
const userId = authorised
|
|
29
|
+
? null
|
|
30
|
+
: await getSessionUser(event.headers.authkey);
|
|
31
|
+
console.log("getting jobs for user", userId);
|
|
32
|
+
|
|
33
|
+
const query = {
|
|
34
|
+
IndexName: "MaintenanceSiteIndex",
|
|
35
|
+
KeyConditionExpression: "site = :site",
|
|
36
|
+
ExpressionAttributeValues: {
|
|
37
|
+
":site": data.site,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const res = await indexQuery(values.tableNameMaintenance, query);
|
|
43
|
+
let jobs = userId
|
|
44
|
+
? res.Items.filter((job) => job.userID === userId)
|
|
45
|
+
: res.Items;
|
|
46
|
+
if (data.status)
|
|
47
|
+
jobs = jobs.filter((j) => data.status.includes(j.status));
|
|
48
|
+
if (data.type) jobs = jobs.filter((j) => data.type.includes(j.type));
|
|
49
|
+
console.log("jobs count", jobs?.length);
|
|
50
|
+
return callback(null, generateJsonResponse(200, jobs));
|
|
51
|
+
} catch (error1) {
|
|
52
|
+
return callback(
|
|
53
|
+
null,
|
|
54
|
+
generateJsonResponse(200, {
|
|
55
|
+
userFetchFail: true,
|
|
56
|
+
message: "Fail on user query. Please try again.",
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
callback(null, generateJsonResponse(422, { fail: true, error }));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class IntegrationStrategy {
|
|
2
|
+
getEntityType = () => {
|
|
3
|
+
return "maintenance_null";
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
isValidIntegration = () => {
|
|
7
|
+
return false;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
getRefreshInterval = () => {
|
|
11
|
+
return 15 * 60 * 1000; // 15 minutes
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// creates a request on the integrated system
|
|
15
|
+
createRequest = async (request) => {
|
|
16
|
+
return null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// gets a request from the integrated system
|
|
20
|
+
getRequest = async (requestId) => {
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// refreshed a request from the integrated system
|
|
25
|
+
refreshFromSource = async (requestId) => {
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// actions taken when a request's status has changed
|
|
30
|
+
onStatusChanged = async (request) => {
|
|
31
|
+
return null;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// actions taken when a comment has been added to a request
|
|
35
|
+
onCommentAdded = async (request) => {
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// actions taken when a note has been added to a request
|
|
40
|
+
onNotesAdded = async (request) => {
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// actions taken when a request is marked as completed
|
|
45
|
+
onCompleteRequest = async (request) => {
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = IntegrationStrategy;
|
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const moment = require("moment");
|
|
3
|
+
const _ = require("lodash");
|
|
4
|
+
const { encode } = require("base64-arraybuffer");
|
|
5
|
+
const IntegrationStrategy = require("../IntegrationStrategy");
|
|
6
|
+
const { log, getRowId } = require("@plusscommunities/pluss-core-aws/helper");
|
|
7
|
+
const editRef = require("@plusscommunities/pluss-core-aws/db/common/editRef");
|
|
8
|
+
const updateRef = require("@plusscommunities/pluss-core-aws/db/common/updateRef");
|
|
9
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
10
|
+
const publishNotifications = require("@plusscommunities/pluss-core-aws/db/notifications/publishNotifications");
|
|
11
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
12
|
+
const getString = require("@plusscommunities/pluss-core-aws/db/strings/getString");
|
|
13
|
+
const { values } = require("../../values.config");
|
|
14
|
+
|
|
15
|
+
class ArchibusStrategy extends IntegrationStrategy {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super();
|
|
18
|
+
this.baseUrl = config.BaseUrl; // base URL for the API
|
|
19
|
+
this.apiKeyHeader = config.APIKeyHeader; // header to use for API key
|
|
20
|
+
this.apiKey = config.APIKey; // API key
|
|
21
|
+
|
|
22
|
+
const url = new URL(this.baseUrl);
|
|
23
|
+
this.host = url.host;
|
|
24
|
+
|
|
25
|
+
this.statusMap = config.StatusMap;
|
|
26
|
+
this.siteMap = config.SiteMap ?? {};
|
|
27
|
+
this.buildingCodes = [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Gets the entity type for the integration
|
|
32
|
+
*
|
|
33
|
+
* @returns {String} The entity type for the integration
|
|
34
|
+
*/
|
|
35
|
+
getEntityType = () => {
|
|
36
|
+
return `${values.serviceKey}_Archibus`;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Validates the integration
|
|
41
|
+
*
|
|
42
|
+
* @returns {Boolean} Whether the integration is valid
|
|
43
|
+
*/
|
|
44
|
+
isValidIntegration = () => {
|
|
45
|
+
return true;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets the refresh interval for the Archibus system
|
|
50
|
+
*
|
|
51
|
+
* @returns {Number} The refresh interval in milliseconds
|
|
52
|
+
*/
|
|
53
|
+
getRefreshInterval = () => {
|
|
54
|
+
return 15 * 60 * 1000; // 15 minutes
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a request from the Archibus system
|
|
59
|
+
*
|
|
60
|
+
* @param {Object} request - Request definition on Pluss
|
|
61
|
+
* @param {Object} mockResponse - Mock response from Archibus to simulate response
|
|
62
|
+
* @returns {Boolean} Whether the request was created on Archibus
|
|
63
|
+
*/
|
|
64
|
+
createRequest = async (request, mockResponse = null) => {
|
|
65
|
+
const logId = log("Archibus:CreateRequest", "Start", request);
|
|
66
|
+
|
|
67
|
+
let siteId = this.siteMap[request.site];
|
|
68
|
+
let buildingCode = null;
|
|
69
|
+
if (request.room) {
|
|
70
|
+
if (this.buildingCodes.length === 0) {
|
|
71
|
+
this.buildingCodes = await getString(
|
|
72
|
+
getRowId(request.site, `${values.serviceKey}buildingcodes`),
|
|
73
|
+
"plussSpace"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const building = this.buildingCodes.find((b) => {
|
|
77
|
+
const address = request.room.toLowerCase();
|
|
78
|
+
const search = b.SearchString.toLowerCase();
|
|
79
|
+
const name = b.BuildingName.toLowerCase();
|
|
80
|
+
return address.includes(search) || address.includes(name);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (building?.SiteCode) siteId = building.SiteCode.toString();
|
|
84
|
+
buildingCode = building?.BuildingCode;
|
|
85
|
+
}
|
|
86
|
+
if (!siteId) return false;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const data = {
|
|
90
|
+
prob_type: "1.ON-SITE|1. MAINTENANCE",
|
|
91
|
+
requestor: "PLUSS",
|
|
92
|
+
description: `${request.title}${
|
|
93
|
+
_.isEmpty(request.description) ? "" : `\n\n${request.description}`
|
|
94
|
+
}${_.isEmpty(request.room) ? "" : `\n\nLocation: ${request.room}`}${
|
|
95
|
+
_.isEmpty(request.userName) ? "" : `\n\nName: ${request.userName}`
|
|
96
|
+
}${_.isEmpty(request.phone) ? "" : `\n\nPhone: ${request.phone}`}${
|
|
97
|
+
_.isEmpty(request.type) ? "" : `\n\nJob Type: ${request.type}`
|
|
98
|
+
}${
|
|
99
|
+
_.isEmpty(request.images)
|
|
100
|
+
? ""
|
|
101
|
+
: `\n\nImages: ${request.images.join("\n")}`
|
|
102
|
+
}`,
|
|
103
|
+
site_id: siteId,
|
|
104
|
+
};
|
|
105
|
+
if (buildingCode) data.bl_id = buildingCode;
|
|
106
|
+
log("Archibus:CreateRequest", "Request", data, logId);
|
|
107
|
+
|
|
108
|
+
const response =
|
|
109
|
+
mockResponse ??
|
|
110
|
+
(await axios({
|
|
111
|
+
method: "PUT",
|
|
112
|
+
url: `${this.baseUrl}/createWorkRequest`,
|
|
113
|
+
timeout: 30000,
|
|
114
|
+
headers: {
|
|
115
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
Host: this.host,
|
|
118
|
+
},
|
|
119
|
+
data,
|
|
120
|
+
}));
|
|
121
|
+
log("Archibus:CreateRequest", "Response", response.data, logId);
|
|
122
|
+
|
|
123
|
+
// Save the ID to external entities for future reference
|
|
124
|
+
await updateRef("externalentities", {
|
|
125
|
+
RowId: `${this.getEntityType()}_${response.data.wrId}`,
|
|
126
|
+
LastUpdated: moment().valueOf(),
|
|
127
|
+
EntityType: this.getEntityType(),
|
|
128
|
+
InternalId: request.id,
|
|
129
|
+
ExternalId: response.data.wrId,
|
|
130
|
+
TrackedData: {},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Save the Archibus ID as the job number
|
|
134
|
+
await editRef(values.tableNameMaintenance, "id", request.id, {
|
|
135
|
+
jobNo: response.data.wrId,
|
|
136
|
+
jobId: response.data.wrId + "",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// add images
|
|
140
|
+
if (!mockResponse && !_.isEmpty(request.images)) {
|
|
141
|
+
const imagePromises = [];
|
|
142
|
+
request.images.forEach((url) => {
|
|
143
|
+
imagePromises.push(this.addFileToRequest(response.data.wrId, url));
|
|
144
|
+
});
|
|
145
|
+
await Promise.all(imagePromises);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return true;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
log("Archibus:CreateRequest", "Error", e, logId);
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Fetches a request from the Archibus system
|
|
157
|
+
*
|
|
158
|
+
* @param {String} externalId - Id of the request on the Archibus
|
|
159
|
+
* @returns {Object} The request as it exists on Archibus
|
|
160
|
+
*/
|
|
161
|
+
getRequest = async (externalId) => {
|
|
162
|
+
const logId = log("Archibus:GetRequest", "Start", externalId);
|
|
163
|
+
try {
|
|
164
|
+
const response = await axios({
|
|
165
|
+
method: "GET",
|
|
166
|
+
url: `${this.baseUrl}/getWorkRequest/${externalId}`,
|
|
167
|
+
timeout: 30000,
|
|
168
|
+
headers: {
|
|
169
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
170
|
+
"Content-Type": "application/json",
|
|
171
|
+
Host: this.host,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
log("Archibus:GetRequest", "Response", response.data, logId);
|
|
175
|
+
|
|
176
|
+
return response.data;
|
|
177
|
+
} catch (e) {
|
|
178
|
+
log("Archibus:GetRequest", "Error", e, logId);
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Refreshes a request from the Archibus system
|
|
185
|
+
*
|
|
186
|
+
* @param {String} requestId - Id of the request on Pluss.
|
|
187
|
+
* @param {String} externalId - Id of the request on Archibus.
|
|
188
|
+
* @param {Object} trackedData - The set of fields tracked.
|
|
189
|
+
* @returns {Boolean} Whether the request had any changes on Archibus.
|
|
190
|
+
*/
|
|
191
|
+
refreshFromSource = async (requestId, externalId, trackedData) => {
|
|
192
|
+
const logId = log("Archibus:RefreshFromSource", "Start", {
|
|
193
|
+
requestId,
|
|
194
|
+
externalId,
|
|
195
|
+
trackedData,
|
|
196
|
+
});
|
|
197
|
+
const request = await this.getRequest(externalId);
|
|
198
|
+
if (!request) {
|
|
199
|
+
log("Archibus:RefreshFromSource", "Result:NoResponse", false, logId);
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (trackedData && trackedData.status === request.status) {
|
|
204
|
+
log("Archibus:RefreshFromSource", "Result:UnchangedStatus", false, logId);
|
|
205
|
+
// status has not changed
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const statusToUse = this.statusMap[request.status];
|
|
210
|
+
log("Archibus:RefreshFromSource", "UpdatedStatus", statusToUse, logId);
|
|
211
|
+
|
|
212
|
+
if (statusToUse) {
|
|
213
|
+
let plussRequest = await getRef(
|
|
214
|
+
values.tableNameMaintenance,
|
|
215
|
+
"id",
|
|
216
|
+
requestId
|
|
217
|
+
);
|
|
218
|
+
// check how the new status map to what is saved in Pluss
|
|
219
|
+
|
|
220
|
+
if (statusToUse.Status !== plussRequest.status) {
|
|
221
|
+
// save updated status
|
|
222
|
+
|
|
223
|
+
plussRequest = await editRef(
|
|
224
|
+
values.tableNameMaintenance,
|
|
225
|
+
"id",
|
|
226
|
+
requestId,
|
|
227
|
+
{
|
|
228
|
+
status: statusToUse.Status,
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
log(
|
|
232
|
+
"Archibus:RefreshFromSource",
|
|
233
|
+
"SavedStatus",
|
|
234
|
+
statusToUse.Status,
|
|
235
|
+
logId
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
if (statusToUse.Notification) {
|
|
239
|
+
publishNotifications(
|
|
240
|
+
[plussRequest.userID],
|
|
241
|
+
values.activityMaintenanceJobStatusChanged,
|
|
242
|
+
plussRequest.site,
|
|
243
|
+
plussRequest.id,
|
|
244
|
+
plussRequest,
|
|
245
|
+
true
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// save tracked data
|
|
252
|
+
await editRef(
|
|
253
|
+
"externalentities",
|
|
254
|
+
"RowId",
|
|
255
|
+
`${this.getEntityType()}_${externalId}`,
|
|
256
|
+
{
|
|
257
|
+
TrackedData: {
|
|
258
|
+
status: request.status,
|
|
259
|
+
},
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
log("Archibus:RefreshFromSource", "Result", true, logId);
|
|
264
|
+
return true;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Adds a comment to a request in Archibus
|
|
269
|
+
*
|
|
270
|
+
* @param {Number} externalId - Id of the request on Archibus.
|
|
271
|
+
* @param {String} comment - Text to add to Archibus request.
|
|
272
|
+
* @param {moment.Moment} time - The time to save against the comment
|
|
273
|
+
*/
|
|
274
|
+
addCommentToRequest = async (externalId, comment, time) => {
|
|
275
|
+
const logId = log("Archibus:AddComment", "Start", {
|
|
276
|
+
externalId,
|
|
277
|
+
comment,
|
|
278
|
+
time,
|
|
279
|
+
});
|
|
280
|
+
try {
|
|
281
|
+
// Format the time
|
|
282
|
+
const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
|
|
283
|
+
|
|
284
|
+
// Generate the POST data
|
|
285
|
+
const postData = {
|
|
286
|
+
actionTime: timeToUse,
|
|
287
|
+
comments: comment,
|
|
288
|
+
wr_id: externalId,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
log("Archibus:AddComment", "PostData", postData, logId);
|
|
292
|
+
|
|
293
|
+
// Save to Archibus
|
|
294
|
+
const response = await axios({
|
|
295
|
+
method: "POST",
|
|
296
|
+
url: `${this.baseUrl}/addCommentsToWRSteps`,
|
|
297
|
+
data: postData,
|
|
298
|
+
timeout: 30000,
|
|
299
|
+
headers: {
|
|
300
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
301
|
+
"Content-Type": "application/json",
|
|
302
|
+
Host: this.host,
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
log("Archibus:AddComment", "ResponseStatus", response.status, logId);
|
|
307
|
+
|
|
308
|
+
return response;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
log("Archibus:AddComment", "Error", error, logId);
|
|
311
|
+
}
|
|
312
|
+
return false;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Adds a file to a request in Archibus
|
|
317
|
+
*
|
|
318
|
+
* @param {Number} externalId - Id of the request on Archibus.
|
|
319
|
+
* @param {String} fileUrl - URL of the file to attach
|
|
320
|
+
* @param {moment.Moment} time - The time to save against the file
|
|
321
|
+
* @returns
|
|
322
|
+
*/
|
|
323
|
+
addFileToRequest = async (externalId, fileUrl, time) => {
|
|
324
|
+
const logId = log("Archibus:AddFile", "Start", {
|
|
325
|
+
externalId,
|
|
326
|
+
fileUrl,
|
|
327
|
+
time,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// This endpoint is not currently functional. Instead, use the addCommentToRequest method to add a comment with the file URL.
|
|
331
|
+
// return this.addCommentToRequest(externalId, fileUrl, time);
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
// Download the file content from the URL
|
|
335
|
+
const fileResponse = await axios.get(fileUrl, {
|
|
336
|
+
responseType: "arraybuffer",
|
|
337
|
+
});
|
|
338
|
+
log("Archibus:AddFile", "GotFileResponse", fileResponse.status, logId);
|
|
339
|
+
|
|
340
|
+
// Encode the file content in base64
|
|
341
|
+
const fileContentBase64 = encode(fileResponse.data);
|
|
342
|
+
log("Archibus:AddFile", "EncodedFileResponse", true, logId);
|
|
343
|
+
|
|
344
|
+
// Extract file name from the URL
|
|
345
|
+
const fileName = fileUrl.split("/").pop();
|
|
346
|
+
|
|
347
|
+
// Format the time
|
|
348
|
+
const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
|
|
349
|
+
|
|
350
|
+
// Generate the POST data
|
|
351
|
+
const postData = {
|
|
352
|
+
actionTime: timeToUse,
|
|
353
|
+
docName: fileName,
|
|
354
|
+
docUrl: "https://anglicare.plusscommunities.com/",
|
|
355
|
+
fileContent: fileContentBase64,
|
|
356
|
+
fileName: fileName,
|
|
357
|
+
wrId: externalId,
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
log("Archibus:AddFile", "PostData", postData, logId);
|
|
361
|
+
|
|
362
|
+
// Save to Archibus
|
|
363
|
+
const response = await axios({
|
|
364
|
+
method: "POST",
|
|
365
|
+
url: `${this.baseUrl}/addDocumentToWorkRequest`,
|
|
366
|
+
data: postData,
|
|
367
|
+
timeout: 60000,
|
|
368
|
+
headers: {
|
|
369
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
370
|
+
"Content-Type": "application/json",
|
|
371
|
+
Host: this.host,
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
log("Archibus:AddFile", "ResponseStatus", response.status, logId);
|
|
376
|
+
|
|
377
|
+
return response;
|
|
378
|
+
} catch (error) {
|
|
379
|
+
log("Archibus:AddFile", "Error", error, logId);
|
|
380
|
+
}
|
|
381
|
+
return false;
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get Archibus Id of the request
|
|
386
|
+
*
|
|
387
|
+
* @param {Object} request - Request definition on Pluss
|
|
388
|
+
* @returns {Number} Id of the request on Archibus (null if not exists)
|
|
389
|
+
*/
|
|
390
|
+
getExternalId = async (request) => {
|
|
391
|
+
const logId = log("Archibus:GetExternalId", "Start", { Id: request.id });
|
|
392
|
+
|
|
393
|
+
// get external id
|
|
394
|
+
const externalEntityQuery = await indexQuery("externalentities", {
|
|
395
|
+
IndexName: "InternalIdIndex",
|
|
396
|
+
KeyConditionExpression:
|
|
397
|
+
"EntityType = :entityType AND InternalId = :internalId",
|
|
398
|
+
ExpressionAttributeValues: {
|
|
399
|
+
":entityType": this.getEntityType(),
|
|
400
|
+
":internalId": request.id,
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
log(
|
|
405
|
+
"Archibus:GetExternalId",
|
|
406
|
+
"ExternalLength",
|
|
407
|
+
externalEntityQuery.Items.length,
|
|
408
|
+
logId
|
|
409
|
+
);
|
|
410
|
+
if (_.isEmpty(externalEntityQuery.Items)) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const externalId = externalEntityQuery.Items[0].ExternalId;
|
|
415
|
+
log("Archibus:GetExternalId", "ExternalId", externalId, logId);
|
|
416
|
+
|
|
417
|
+
return externalId;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Get latest comment for a request
|
|
422
|
+
*
|
|
423
|
+
* @param {Object} request - Request definition on Pluss
|
|
424
|
+
* @param {String} entityKey - Request entity key (e.g. maintenancerequest)
|
|
425
|
+
* @returns {Object} Latest comment (null if not exists)
|
|
426
|
+
*/
|
|
427
|
+
getLatestComment = async (request, entityKey) => {
|
|
428
|
+
const logId = log("Archibus:GetLatestComment", "Start", { Id: request.id });
|
|
429
|
+
|
|
430
|
+
// get comments
|
|
431
|
+
const commentsQuery = {
|
|
432
|
+
IndexName: "CommentsEntityIdIndex",
|
|
433
|
+
KeyConditionExpression: "EntityId = :groupId",
|
|
434
|
+
ExpressionAttributeValues: {
|
|
435
|
+
":groupId": getRowId(request.id, entityKey),
|
|
436
|
+
},
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const commentsQueryRes = await indexQuery("comments", commentsQuery);
|
|
440
|
+
const comments = _.orderBy(commentsQueryRes.Items, "Timestamp", "desc");
|
|
441
|
+
log(
|
|
442
|
+
"Archibus:GetLatestComment",
|
|
443
|
+
`CommentsLength - ${entityKey}`,
|
|
444
|
+
comments.length,
|
|
445
|
+
logId
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
return comments.length > 0 ? comments[0] : null;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Perform actions when a task's status has changed
|
|
453
|
+
*
|
|
454
|
+
* @param {Object} request - Request definition on Pluss
|
|
455
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
456
|
+
*/
|
|
457
|
+
onStatusChanged = async (request) => {
|
|
458
|
+
const logId = log("Archibus:OnStatusChanged", "Start", { Id: request.id });
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
const externalId = await this.getExternalId(request);
|
|
462
|
+
if (_.isNil(externalId)) return true;
|
|
463
|
+
|
|
464
|
+
const statues = _.orderBy(
|
|
465
|
+
(request.history ?? []).filter(
|
|
466
|
+
(entry) => entry.EntryType !== "assignment"
|
|
467
|
+
),
|
|
468
|
+
"timestamp",
|
|
469
|
+
"desc"
|
|
470
|
+
);
|
|
471
|
+
const latest = statues.length > 0 ? statues[0] : null;
|
|
472
|
+
|
|
473
|
+
if (latest) {
|
|
474
|
+
const time = moment(Number.parseFloat(latest.timestamp + "")).format(
|
|
475
|
+
"D MMM YYYY HH:mm:ss"
|
|
476
|
+
);
|
|
477
|
+
const user = latest.user ? ` by ${latest.user.displayName}` : "";
|
|
478
|
+
const comment = `${time}: Marked ${latest.status}${user}`;
|
|
479
|
+
await this.addCommentToRequest(externalId, comment);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return true;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
log("Archibus:OnStatusChanged", "Error", error.toString(), logId);
|
|
485
|
+
}
|
|
486
|
+
return false;
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Perform actions when a a comment has been added to a task
|
|
491
|
+
*
|
|
492
|
+
* @param {Object} request - Request definition on Pluss
|
|
493
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
494
|
+
*/
|
|
495
|
+
onCommentAdded = async (request) => {
|
|
496
|
+
const logId = log("Archibus:OnCommentAdded", "Start", {
|
|
497
|
+
Id: request.id,
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
try {
|
|
501
|
+
const externalId = await this.getExternalId(request);
|
|
502
|
+
if (_.isNil(externalId)) return true;
|
|
503
|
+
|
|
504
|
+
let comment = await this.getLatestComment(request, values.serviceKey);
|
|
505
|
+
if (!comment)
|
|
506
|
+
comment = await this.getLatestComment(request, values.entityKey);
|
|
507
|
+
|
|
508
|
+
if (comment) {
|
|
509
|
+
const commentText = `${comment.User.displayName}:\n\n${
|
|
510
|
+
comment.Comment
|
|
511
|
+
}${!_.isEmpty(comment.Image) ? `\n\nImage: ${comment.Image}` : ""}}`;
|
|
512
|
+
const commentTime = moment(comment.Timestamp);
|
|
513
|
+
await this.addCommentToRequest(externalId, commentText, commentTime);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return true;
|
|
517
|
+
} catch (error) {
|
|
518
|
+
log("Archibus:OnCommentAdded", "Error", error.toString(), logId);
|
|
519
|
+
}
|
|
520
|
+
return false;
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Perform actions when a note has been added to a task
|
|
525
|
+
*
|
|
526
|
+
* @param {Object} request - Request definition on Pluss
|
|
527
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
528
|
+
*/
|
|
529
|
+
onNotesAdded = async (request) => {
|
|
530
|
+
const logId = log("Archibus:OnNotesAdded", "Start", { Id: request.id });
|
|
531
|
+
|
|
532
|
+
try {
|
|
533
|
+
const externalId = await this.getExternalId(request);
|
|
534
|
+
if (_.isNil(externalId)) return true;
|
|
535
|
+
|
|
536
|
+
const notes = _.orderBy(request.Notes ?? [], "Timestamp", "desc");
|
|
537
|
+
const latest = notes.length > 0 ? notes[0] : null;
|
|
538
|
+
|
|
539
|
+
if (latest) {
|
|
540
|
+
const promises = [];
|
|
541
|
+
|
|
542
|
+
const time = moment(Number.parseFloat(latest.Timestamp + "")).format(
|
|
543
|
+
"YYYY-MM-DD HH:mm:ss"
|
|
544
|
+
);
|
|
545
|
+
const user = latest.User ? latest.User.displayName : "Unknown User";
|
|
546
|
+
const note = latest.Note ? `Note: ${latest.Note}` : "No Note";
|
|
547
|
+
if (!_.isEmpty(latest.Attachments)) {
|
|
548
|
+
latest.Attachments.forEach((att) => {
|
|
549
|
+
promises.push(this.addFileToRequest(externalId, att.Source));
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
const attachments =
|
|
553
|
+
latest.Attachments && latest.Attachments.length > 0
|
|
554
|
+
? `Attachments: ${latest.Attachments.map(
|
|
555
|
+
(att) => `${att.Title} (${att.Source})`
|
|
556
|
+
).join(", ")}`
|
|
557
|
+
: "No Attachments";
|
|
558
|
+
if (!_.isEmpty(latest.Images)) {
|
|
559
|
+
latest.Images.forEach((image) => {
|
|
560
|
+
promises.push(this.addFileToRequest(externalId, image));
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
const images =
|
|
564
|
+
latest.Images && latest.Images.length > 0
|
|
565
|
+
? `Images: ${latest.Images.map((image) => image).join(", ")}`
|
|
566
|
+
: "No Images";
|
|
567
|
+
const comment = `${time} by ${user}\n${note}\n${attachments}\n${images}`;
|
|
568
|
+
promises.push(this.addCommentToRequest(externalId, comment));
|
|
569
|
+
|
|
570
|
+
await Promise.all(promises);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return true;
|
|
574
|
+
} catch (error) {
|
|
575
|
+
log("Archibus:OnNotesAdded", "Error", error.toString(), logId);
|
|
576
|
+
}
|
|
577
|
+
return false;
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Perform completion actions when a task is completed
|
|
582
|
+
*
|
|
583
|
+
* @param {Object} request - Request definition on Pluss
|
|
584
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
585
|
+
*/
|
|
586
|
+
onCompleteRequest = async (request) => {
|
|
587
|
+
return true;
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
module.exports = ArchibusStrategy;
|