@plusscommunities/pluss-maintenance-aws 2.1.21 → 2.1.22
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/integration/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const getString = require("@plusscommunities/pluss-core-aws/db/strings/getString");
|
|
2
2
|
const { getRowId, log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
3
3
|
const ArchibusStrategy = require("./archibus/ArchibusStrategy");
|
|
4
|
+
const SeeStuffStrategy = require("./seestuff/SeeStuffStrategy");
|
|
4
5
|
const IntegrationStrategy = require("./IntegrationStrategy");
|
|
5
6
|
const { values } = require("../values.config");
|
|
6
7
|
|
|
@@ -16,6 +17,8 @@ exports.getStrategy = async (site) => {
|
|
|
16
17
|
switch (importConfig.Strategy) {
|
|
17
18
|
case "Archibus":
|
|
18
19
|
return new ArchibusStrategy(importConfig);
|
|
20
|
+
case "SeeStuff":
|
|
21
|
+
return new SeeStuffStrategy(importConfig);
|
|
19
22
|
default:
|
|
20
23
|
return new IntegrationStrategy();
|
|
21
24
|
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const moment = require("moment");
|
|
3
|
+
const _ = require("lodash");
|
|
4
|
+
const IntegrationStrategy = require("../IntegrationStrategy");
|
|
5
|
+
const { log, getRowId } = require("@plusscommunities/pluss-core-aws/helper");
|
|
6
|
+
const editRef = require("@plusscommunities/pluss-core-aws/db/common/editRef");
|
|
7
|
+
const updateRef = require("@plusscommunities/pluss-core-aws/db/common/updateRef");
|
|
8
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
9
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
10
|
+
const { values } = require("../../values.config");
|
|
11
|
+
|
|
12
|
+
class SeeStuffStrategy extends IntegrationStrategy {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
super();
|
|
15
|
+
this.baseUrl = config.BaseUrl; // base URL for the API
|
|
16
|
+
this.apiKeyHeader = config.APIKeyHeader; // header to use for API key
|
|
17
|
+
this.apiKey = config.APIKey; // API key
|
|
18
|
+
|
|
19
|
+
const url = new URL(this.baseUrl);
|
|
20
|
+
this.host = url.host;
|
|
21
|
+
|
|
22
|
+
this.siteMap = config.SiteMap ?? {};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the entity type for the integration
|
|
27
|
+
*
|
|
28
|
+
* @returns {String} The entity type for the integration
|
|
29
|
+
*/
|
|
30
|
+
getEntityType = () => {
|
|
31
|
+
return `${values.serviceKey}_SeeStuff`;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Validates the integration
|
|
36
|
+
*
|
|
37
|
+
* @returns {Boolean} Whether the integration is valid
|
|
38
|
+
*/
|
|
39
|
+
isValidIntegration = () => {
|
|
40
|
+
return true;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Gets the refresh interval for the SeeStuff system
|
|
45
|
+
*
|
|
46
|
+
* @returns {Number} The refresh interval in milliseconds
|
|
47
|
+
*/
|
|
48
|
+
getRefreshInterval = () => {
|
|
49
|
+
return Number.MAX_SAFE_INTEGER; // should never refresh
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates a request in the SeeStuff system
|
|
54
|
+
*
|
|
55
|
+
* @param {Object} request - Request definition on Pluss
|
|
56
|
+
* @param {Object} mockResponse - Mock response from SeeStuff to simulate response
|
|
57
|
+
* @returns {Boolean} Whether the request was created on SeeStuff
|
|
58
|
+
*/
|
|
59
|
+
createRequest = async (request, mockResponse = null) => {
|
|
60
|
+
const logId = log("SeeStuff:CreateRequest", "Start", request);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Get user details for room/address and CRMID
|
|
64
|
+
let userRoom = request.room || "";
|
|
65
|
+
let crmResidentId = "";
|
|
66
|
+
|
|
67
|
+
// Map site to location code if available
|
|
68
|
+
const location = this.siteMap[request.site];
|
|
69
|
+
if (!location) {
|
|
70
|
+
log("SeeStuff:CreateRequest", "LocationNotFound", request.site, logId);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (request.userID) {
|
|
75
|
+
try {
|
|
76
|
+
// Look up user from users table
|
|
77
|
+
const user = await getRef("users", "Id", request.userID);
|
|
78
|
+
log("SeeStuff:CreateRequest", "User", user, logId);
|
|
79
|
+
|
|
80
|
+
if (user) {
|
|
81
|
+
// Get user's address/room
|
|
82
|
+
if (user.unit) {
|
|
83
|
+
userRoom = user.unit;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Get CRMID from user fields
|
|
87
|
+
try {
|
|
88
|
+
const crmIdField = await getRef(
|
|
89
|
+
"userfields",
|
|
90
|
+
"RowId",
|
|
91
|
+
getRowId(request.userID, "CRMID")
|
|
92
|
+
);
|
|
93
|
+
if (crmIdField && crmIdField.Value) {
|
|
94
|
+
crmResidentId = crmIdField.Value;
|
|
95
|
+
}
|
|
96
|
+
log("SeeStuff:CreateRequest", "CRMID", crmResidentId, logId);
|
|
97
|
+
} catch (fieldError) {
|
|
98
|
+
log(
|
|
99
|
+
"SeeStuff:CreateRequest",
|
|
100
|
+
"CRMIDLookupError",
|
|
101
|
+
fieldError,
|
|
102
|
+
logId
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} catch (userError) {
|
|
107
|
+
log("SeeStuff:CreateRequest", "UserLookupError", userError, logId);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Format description similar to Archibus
|
|
112
|
+
const description = `${request.title}${
|
|
113
|
+
_.isEmpty(request.description) ? "" : `\n\n${request.description}`
|
|
114
|
+
}${_.isEmpty(request.room) ? "" : `\n\nLocation: ${request.room}`}${
|
|
115
|
+
_.isEmpty(request.userName) ? "" : `\n\nName: ${request.userName}`
|
|
116
|
+
}${_.isEmpty(request.phone) ? "" : `\n\nPhone: ${request.phone}`}${
|
|
117
|
+
_.isEmpty(request.type) ? "" : `\n\nJob Type: ${request.type}`
|
|
118
|
+
}${
|
|
119
|
+
_.isEmpty(request.images)
|
|
120
|
+
? ""
|
|
121
|
+
: `\n\nImages: ${request.images.join("\n")}`
|
|
122
|
+
}`;
|
|
123
|
+
|
|
124
|
+
// Format date_reported
|
|
125
|
+
const dateReported = moment().format("YYYY-MM-DD HH:mm:ss");
|
|
126
|
+
|
|
127
|
+
// Build payload
|
|
128
|
+
const data = {
|
|
129
|
+
externalId: request.id,
|
|
130
|
+
description: description,
|
|
131
|
+
priority: "P3",
|
|
132
|
+
location: location,
|
|
133
|
+
room: userRoom,
|
|
134
|
+
date_reported: dateReported,
|
|
135
|
+
crmResidentId: crmResidentId,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
log("SeeStuff:CreateRequest", "Request", data, logId);
|
|
139
|
+
|
|
140
|
+
const response =
|
|
141
|
+
mockResponse ??
|
|
142
|
+
(await axios({
|
|
143
|
+
method: "POST",
|
|
144
|
+
url: `${this.baseUrl}/assetmgmt/servicerequests`,
|
|
145
|
+
timeout: 30000,
|
|
146
|
+
headers: {
|
|
147
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
148
|
+
"Content-Type": "application/json",
|
|
149
|
+
Host: this.host,
|
|
150
|
+
},
|
|
151
|
+
data,
|
|
152
|
+
}));
|
|
153
|
+
|
|
154
|
+
log("SeeStuff:CreateRequest", "Response", response.data, logId);
|
|
155
|
+
|
|
156
|
+
return true;
|
|
157
|
+
} catch (e) {
|
|
158
|
+
log("SeeStuff:CreateRequest", "Error", e, logId);
|
|
159
|
+
|
|
160
|
+
// Add history entry for failed integration
|
|
161
|
+
try {
|
|
162
|
+
const failedJob = await getRef(
|
|
163
|
+
values.tableNameMaintenance,
|
|
164
|
+
"id",
|
|
165
|
+
request.id
|
|
166
|
+
);
|
|
167
|
+
if (!failedJob.history) failedJob.history = [];
|
|
168
|
+
failedJob.history.push({
|
|
169
|
+
timestamp: moment.utc().valueOf(),
|
|
170
|
+
action: "ExternalIDSetFailed",
|
|
171
|
+
user: {
|
|
172
|
+
displayName: "SeeStuff Integration",
|
|
173
|
+
id: "system",
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await editRef(values.tableNameMaintenance, "id", request.id, {
|
|
178
|
+
history: failedJob.history,
|
|
179
|
+
});
|
|
180
|
+
} catch (historyError) {
|
|
181
|
+
log("SeeStuff:CreateRequest", "HistoryError", historyError, logId);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Fetches a request from the SeeStuff system
|
|
189
|
+
* Not implemented yet
|
|
190
|
+
*
|
|
191
|
+
* @param {String} externalId - Id of the request on SeeStuff
|
|
192
|
+
* @returns {Object} The request as it exists on SeeStuff
|
|
193
|
+
*/
|
|
194
|
+
getRequest = async (externalId) => {
|
|
195
|
+
return null;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Refreshes a request from the SeeStuff system
|
|
200
|
+
* Not implemented yet
|
|
201
|
+
*
|
|
202
|
+
* @param {String} requestId - Id of the request on Pluss
|
|
203
|
+
* @param {String} externalId - Id of the request on SeeStuff
|
|
204
|
+
* @param {Object} trackedData - The set of fields tracked
|
|
205
|
+
* @returns {Boolean} Whether the request had any changes on SeeStuff
|
|
206
|
+
*/
|
|
207
|
+
refreshFromSource = async (requestId, externalId, trackedData) => {
|
|
208
|
+
return false;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get SeeStuff Id of the request
|
|
213
|
+
* Queries externalentities table to find the external ID
|
|
214
|
+
*
|
|
215
|
+
* @param {Object} request - Request definition on Pluss
|
|
216
|
+
* @returns {String} Id of the request on SeeStuff
|
|
217
|
+
*/
|
|
218
|
+
getExternalId = async (request) => {
|
|
219
|
+
const logId = log("SeeStuff:GetExternalId", "Start", { Id: request.id });
|
|
220
|
+
|
|
221
|
+
// get external id
|
|
222
|
+
const externalEntityQuery = await indexQuery("externalentities", {
|
|
223
|
+
IndexName: "InternalIdIndex",
|
|
224
|
+
KeyConditionExpression:
|
|
225
|
+
"EntityType = :entityType AND InternalId = :internalId",
|
|
226
|
+
ExpressionAttributeValues: {
|
|
227
|
+
":entityType": this.getEntityType(),
|
|
228
|
+
":internalId": request.id,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
log(
|
|
233
|
+
"SeeStuff:GetExternalId",
|
|
234
|
+
"ExternalLength",
|
|
235
|
+
externalEntityQuery.Items.length,
|
|
236
|
+
logId
|
|
237
|
+
);
|
|
238
|
+
if (_.isEmpty(externalEntityQuery.Items)) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const externalId = externalEntityQuery.Items[0].ExternalId;
|
|
243
|
+
log("SeeStuff:GetExternalId", "ExternalId", externalId, logId);
|
|
244
|
+
|
|
245
|
+
return externalId;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Perform actions when a task's status has changed
|
|
250
|
+
* Not implemented yet
|
|
251
|
+
*
|
|
252
|
+
* @param {Object} request - Request definition on Pluss
|
|
253
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
254
|
+
*/
|
|
255
|
+
onStatusChanged = async (request) => {
|
|
256
|
+
return true;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Perform actions when a comment has been added to a task
|
|
261
|
+
* Not implemented yet
|
|
262
|
+
*
|
|
263
|
+
* @param {Object} request - Request definition on Pluss
|
|
264
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
265
|
+
*/
|
|
266
|
+
onCommentAdded = async (request) => {
|
|
267
|
+
return true;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Perform actions when a note has been added to a task
|
|
272
|
+
* Not implemented yet
|
|
273
|
+
*
|
|
274
|
+
* @param {Object} request - Request definition on Pluss
|
|
275
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
276
|
+
*/
|
|
277
|
+
onNotesAdded = async (request) => {
|
|
278
|
+
return true;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Perform completion actions when a task is completed
|
|
283
|
+
* Not implemented yet
|
|
284
|
+
*
|
|
285
|
+
* @param {Object} request - Request definition on Pluss
|
|
286
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
287
|
+
*/
|
|
288
|
+
onCompleteRequest = async (request) => {
|
|
289
|
+
return true;
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = SeeStuffStrategy;
|
package/package-lock.json
CHANGED
package/package.json
CHANGED