dt-common-device 6.2.0 → 6.2.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/dist/alerts/Alert.model.js +58 -11
- package/dist/alerts/Alert.repository.d.ts +1 -1
- package/dist/alerts/Alert.repository.js +11 -24
- package/dist/alerts/Alert.service.d.ts +3 -3
- package/dist/alerts/Alert.service.js +4 -17
- package/dist/alerts/AlertBuilder.d.ts +1 -1
- package/dist/alerts/AlertBuilder.js +1 -1
- package/dist/alerts/AlertService.example.js +1 -1
- package/dist/alerts/alert.types.d.ts +4 -4
- package/dist/events/EventHandler.js +0 -67
- package/dist/issues/Issue.model.js +51 -3
- package/dist/issues/Issue.repository.js +8 -4
- package/dist/issues/Issue.service.d.ts +1 -0
- package/dist/issues/Issue.service.js +15 -1
- package/package.json +1 -1
|
@@ -39,15 +39,9 @@ const alert_types_1 = require("./alert.types");
|
|
|
39
39
|
// Main Alert schema
|
|
40
40
|
const AlertSchema = new mongoose_1.Schema({
|
|
41
41
|
category: {
|
|
42
|
-
type:
|
|
42
|
+
type: String,
|
|
43
43
|
enum: Object.values(alert_types_1.AlertCategory),
|
|
44
44
|
required: true,
|
|
45
|
-
validate: {
|
|
46
|
-
validator: function (categories) {
|
|
47
|
-
return categories && categories.length > 0;
|
|
48
|
-
},
|
|
49
|
-
message: "At least one category is required",
|
|
50
|
-
},
|
|
51
45
|
},
|
|
52
46
|
propertyId: {
|
|
53
47
|
type: String,
|
|
@@ -102,6 +96,7 @@ const AlertSchema = new mongoose_1.Schema({
|
|
|
102
96
|
},
|
|
103
97
|
updatedBy: {
|
|
104
98
|
type: String,
|
|
99
|
+
index: true,
|
|
105
100
|
},
|
|
106
101
|
createdAt: {
|
|
107
102
|
type: Date,
|
|
@@ -114,6 +109,9 @@ const AlertSchema = new mongoose_1.Schema({
|
|
|
114
109
|
}, {
|
|
115
110
|
timestamps: true,
|
|
116
111
|
collection: "dt_alerts",
|
|
112
|
+
toJSON: { virtuals: true },
|
|
113
|
+
toObject: { virtuals: true },
|
|
114
|
+
id: false, // Disable the virtual id field since we're handling it manually
|
|
117
115
|
});
|
|
118
116
|
exports.AlertSchema = AlertSchema;
|
|
119
117
|
// Compound indexes to match Prisma schema
|
|
@@ -157,7 +155,7 @@ AlertSchema.methods.unsnooze = function (updatedBy) {
|
|
|
157
155
|
};
|
|
158
156
|
// Static methods
|
|
159
157
|
AlertSchema.statics.findByCategory = function (category, includeDeleted = false) {
|
|
160
|
-
const query = { category:
|
|
158
|
+
const query = { category: category };
|
|
161
159
|
if (!includeDeleted) {
|
|
162
160
|
query.isDeleted = false;
|
|
163
161
|
}
|
|
@@ -187,8 +185,57 @@ AlertSchema.virtual("isSnoozed").get(function () {
|
|
|
187
185
|
AlertSchema.virtual("isSnoozeExpired").get(function () {
|
|
188
186
|
return this.snoozeUntil && this.snoozeUntil <= new Date();
|
|
189
187
|
});
|
|
190
|
-
//
|
|
191
|
-
AlertSchema.
|
|
192
|
-
|
|
188
|
+
// Virtual for soft delete status (different name to avoid conflict)
|
|
189
|
+
AlertSchema.virtual("isNotDeleted").get(function () {
|
|
190
|
+
return !this.isDeleted;
|
|
191
|
+
});
|
|
192
|
+
// Post middleware to transform all find results to plain objects
|
|
193
|
+
AlertSchema.post(/^find/, function (result) {
|
|
194
|
+
if (!result)
|
|
195
|
+
return;
|
|
196
|
+
// Handle array results (find)
|
|
197
|
+
if (Array.isArray(result)) {
|
|
198
|
+
result.forEach((doc) => {
|
|
199
|
+
if (doc && typeof doc.toObject === "function") {
|
|
200
|
+
const plainDoc = doc.toObject();
|
|
201
|
+
// Transform _id to id and remove __v
|
|
202
|
+
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
|
|
203
|
+
delete plainDoc._id;
|
|
204
|
+
delete plainDoc.__v;
|
|
205
|
+
// Replace the document with plain object
|
|
206
|
+
Object.assign(doc, plainDoc);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// Handle single document results (findOne, findById, etc.)
|
|
211
|
+
else if (result && typeof result.toObject === "function") {
|
|
212
|
+
const plainDoc = result.toObject();
|
|
213
|
+
// Transform _id to id and remove __v
|
|
214
|
+
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
|
|
215
|
+
delete plainDoc._id;
|
|
216
|
+
delete plainDoc.__v;
|
|
217
|
+
// Replace the document with plain object
|
|
218
|
+
Object.assign(result, plainDoc);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// Ensure virtuals are serialized and transform to plain objects
|
|
222
|
+
AlertSchema.set("toJSON", {
|
|
223
|
+
virtuals: true,
|
|
224
|
+
transform: function (doc, ret) {
|
|
225
|
+
ret.id = ret._id ? ret._id.toString() : ret._id;
|
|
226
|
+
delete ret._id;
|
|
227
|
+
delete ret.__v;
|
|
228
|
+
return ret;
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
AlertSchema.set("toObject", {
|
|
232
|
+
virtuals: true,
|
|
233
|
+
transform: function (doc, ret) {
|
|
234
|
+
ret.id = ret._id ? ret._id.toString() : ret._id;
|
|
235
|
+
delete ret._id;
|
|
236
|
+
delete ret.__v;
|
|
237
|
+
return ret;
|
|
238
|
+
},
|
|
239
|
+
});
|
|
193
240
|
// Create and export the model
|
|
194
241
|
exports.AlertModel = mongoose_1.default.model("Alert", AlertSchema);
|
|
@@ -33,7 +33,7 @@ export declare class AlertRepository {
|
|
|
33
33
|
/**
|
|
34
34
|
* Find alerts by category
|
|
35
35
|
*/
|
|
36
|
-
findByCategory(category: AlertCategory
|
|
36
|
+
findByCategory(category: AlertCategory, includeDeleted?: boolean): Promise<IAlertDocument[]>;
|
|
37
37
|
/**
|
|
38
38
|
* Find snoozed alerts
|
|
39
39
|
*/
|
|
@@ -52,14 +52,8 @@ let AlertRepository = (() => {
|
|
|
52
52
|
const query = {};
|
|
53
53
|
if (filters.propertyId)
|
|
54
54
|
query.propertyId = filters.propertyId;
|
|
55
|
-
if (filters.category)
|
|
56
|
-
|
|
57
|
-
query.category = { $in: filters.category };
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
query.category = { $in: [filters.category] };
|
|
61
|
-
}
|
|
62
|
-
}
|
|
55
|
+
if (filters.category)
|
|
56
|
+
query.category = filters.category;
|
|
63
57
|
if (filters.severity)
|
|
64
58
|
query.severity = filters.severity;
|
|
65
59
|
if (filters.entityType)
|
|
@@ -86,7 +80,8 @@ let AlertRepository = (() => {
|
|
|
86
80
|
isActive: true,
|
|
87
81
|
isDeleted: false,
|
|
88
82
|
});
|
|
89
|
-
|
|
83
|
+
const savedAlert = await alert.save();
|
|
84
|
+
return savedAlert.toObject();
|
|
90
85
|
}
|
|
91
86
|
catch (error) {
|
|
92
87
|
throw new Error(`Failed to create alert: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -101,7 +96,8 @@ let AlertRepository = (() => {
|
|
|
101
96
|
if (!includeDeleted) {
|
|
102
97
|
query.isDeleted = false;
|
|
103
98
|
}
|
|
104
|
-
|
|
99
|
+
const result = await Alert_model_1.AlertModel.findOne(query);
|
|
100
|
+
return result ? result.toObject() : null;
|
|
105
101
|
}
|
|
106
102
|
catch (error) {
|
|
107
103
|
throw new Error(`Failed to find alert by ID: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -124,7 +120,8 @@ let AlertRepository = (() => {
|
|
|
124
120
|
queryBuilder.skip(filters.skip);
|
|
125
121
|
if (filters.limit)
|
|
126
122
|
queryBuilder.limit(filters.limit);
|
|
127
|
-
|
|
123
|
+
const results = await queryBuilder.exec();
|
|
124
|
+
return results.map((result) => result.toObject());
|
|
128
125
|
}
|
|
129
126
|
catch (error) {
|
|
130
127
|
throw new Error(`Failed to find alerts: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -135,7 +132,8 @@ let AlertRepository = (() => {
|
|
|
135
132
|
*/
|
|
136
133
|
async update(id, updateData) {
|
|
137
134
|
try {
|
|
138
|
-
|
|
135
|
+
const result = await Alert_model_1.AlertModel.findByIdAndUpdate(id, { ...updateData, updatedAt: new Date() }, { new: true, runValidators: true });
|
|
136
|
+
return result ? result.toObject() : null;
|
|
139
137
|
}
|
|
140
138
|
catch (error) {
|
|
141
139
|
throw new Error(`Failed to update alert: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -186,17 +184,7 @@ let AlertRepository = (() => {
|
|
|
186
184
|
*/
|
|
187
185
|
async findByCategory(category, includeDeleted = false) {
|
|
188
186
|
try {
|
|
189
|
-
|
|
190
|
-
// Use $in operator for array of categories
|
|
191
|
-
const query = { category: { $in: category } };
|
|
192
|
-
if (!includeDeleted) {
|
|
193
|
-
query.isDeleted = false;
|
|
194
|
-
}
|
|
195
|
-
return await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
return await Alert_model_1.AlertModel.findByCategory(category, includeDeleted);
|
|
199
|
-
}
|
|
187
|
+
return await Alert_model_1.AlertModel.findByCategory(category, includeDeleted);
|
|
200
188
|
}
|
|
201
189
|
catch (error) {
|
|
202
190
|
throw new Error(`Failed to find alerts by category: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -246,7 +234,6 @@ let AlertRepository = (() => {
|
|
|
246
234
|
]),
|
|
247
235
|
Alert_model_1.AlertModel.aggregate([
|
|
248
236
|
{ $match: query },
|
|
249
|
-
{ $unwind: "$category" },
|
|
250
237
|
{ $group: { _id: "$category", count: { $sum: 1 } } },
|
|
251
238
|
]),
|
|
252
239
|
]);
|
|
@@ -25,11 +25,11 @@ export declare class AlertService {
|
|
|
25
25
|
/**
|
|
26
26
|
* Create a device-specific alert using AlertBuilder
|
|
27
27
|
*/
|
|
28
|
-
raiseDeviceAlert(deviceId: string, propertyId: string, title: string, description: string, category?: AlertCategory
|
|
28
|
+
raiseDeviceAlert(deviceId: string, propertyId: string, title: string, description: string, category?: AlertCategory, severity?: AlertSeverity, source?: Source): Promise<IAlertDocument>;
|
|
29
29
|
/**
|
|
30
30
|
* Create a hub-specific alert using AlertBuilder
|
|
31
31
|
*/
|
|
32
|
-
raiseHubAlert(hubId: string, propertyId: string, title: string, description: string, category?: AlertCategory
|
|
32
|
+
raiseHubAlert(hubId: string, propertyId: string, title: string, description: string, category?: AlertCategory, severity?: AlertSeverity, createdBy?: string): Promise<IAlertDocument>;
|
|
33
33
|
/**
|
|
34
34
|
* Raise alert for device going offline (OPERATIONAL only)
|
|
35
35
|
*/
|
|
@@ -94,7 +94,7 @@ export declare class AlertService {
|
|
|
94
94
|
/**
|
|
95
95
|
* Get alerts by category with business logic
|
|
96
96
|
*/
|
|
97
|
-
getAlertsByCategory(category: AlertCategory
|
|
97
|
+
getAlertsByCategory(category: AlertCategory, includeDeleted?: boolean): Promise<IAlertDocument[]>;
|
|
98
98
|
/**
|
|
99
99
|
* Get snoozed alerts with business logic
|
|
100
100
|
*/
|
|
@@ -184,25 +184,25 @@ let AlertService = (() => {
|
|
|
184
184
|
* Raise alert for device going offline (OPERATIONAL only)
|
|
185
185
|
*/
|
|
186
186
|
async raiseDeviceOfflineAlert(device, source, reason) {
|
|
187
|
-
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Offline", `Device ${device.name} (${device.deviceId}) has gone offline. ${reason ? `Reason: ${reason}` : ""}`,
|
|
187
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Offline", `Device ${device.name} (${device.deviceId}) has gone offline. ${reason ? `Reason: ${reason}` : ""}`, alert_types_1.AlertCategory.OPERATIONS, alert_types_1.AlertSeverity.HIGH, source);
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* Raise alert for device coming online (OPERATIONAL only)
|
|
191
191
|
*/
|
|
192
192
|
async raiseDeviceOnlineAlert(device, source, reason) {
|
|
193
|
-
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Online", `Device ${device.name} (${device.deviceId}) is now online. ${reason ? `Reason: ${reason}` : ""}`,
|
|
193
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Online", `Device ${device.name} (${device.deviceId}) is now online. ${reason ? `Reason: ${reason}` : ""}`, alert_types_1.AlertCategory.OPERATIONS, alert_types_1.AlertSeverity.INFO, source);
|
|
194
194
|
}
|
|
195
195
|
/**
|
|
196
196
|
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
197
197
|
*/
|
|
198
198
|
async raiseDeviceBatteryAlert(device, batteryLevel, threshold, source) {
|
|
199
|
-
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Battery Low", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`,
|
|
199
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Battery Low", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`, alert_types_1.AlertCategory.ENERGY, alert_types_1.AlertSeverity.MEDIUM, source);
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
202
202
|
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
|
|
203
203
|
*/
|
|
204
204
|
async raiseDeviceIssueAlert(device, issueType, source, reason) {
|
|
205
|
-
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, `Device Issue - ${issueType}`, `Device ${device.name} (${device.deviceId}) has an issue: ${issueType}. ${reason ? `Reason: ${reason}` : ""}`,
|
|
205
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, `Device Issue - ${issueType}`, `Device ${device.name} (${device.deviceId}) has an issue: ${issueType}. ${reason ? `Reason: ${reason}` : ""}`, alert_types_1.AlertCategory.READINESS, alert_types_1.AlertSeverity.HIGH, source);
|
|
206
206
|
}
|
|
207
207
|
/**
|
|
208
208
|
* Create a new alert with business logic validation
|
|
@@ -460,19 +460,6 @@ let AlertService = (() => {
|
|
|
460
460
|
[alert_types_1.AlertCategory.ENERGY]: alert_types_1.AlertSeverity.LOW,
|
|
461
461
|
[alert_types_1.AlertCategory.OTHER]: alert_types_1.AlertSeverity.MEDIUM,
|
|
462
462
|
};
|
|
463
|
-
// If it's an array, use the highest severity category
|
|
464
|
-
if (Array.isArray(category)) {
|
|
465
|
-
const severities = category.map((cat) => categorySeverities[cat] || alert_types_1.AlertSeverity.MEDIUM);
|
|
466
|
-
const severityOrder = [
|
|
467
|
-
alert_types_1.AlertSeverity.CRITICAL,
|
|
468
|
-
alert_types_1.AlertSeverity.HIGH,
|
|
469
|
-
alert_types_1.AlertSeverity.MEDIUM,
|
|
470
|
-
alert_types_1.AlertSeverity.LOW,
|
|
471
|
-
alert_types_1.AlertSeverity.INFO,
|
|
472
|
-
];
|
|
473
|
-
return (severityOrder.find((severity) => severities.includes(severity)) ||
|
|
474
|
-
alert_types_1.AlertSeverity.MEDIUM);
|
|
475
|
-
}
|
|
476
463
|
return categorySeverities[category] || alert_types_1.AlertSeverity.MEDIUM;
|
|
477
464
|
}
|
|
478
465
|
applyBusinessRules(filters) {
|
|
@@ -132,7 +132,7 @@ class AlertServiceExample {
|
|
|
132
132
|
*/
|
|
133
133
|
async createAlertWithLegacyData() {
|
|
134
134
|
const alertData = {
|
|
135
|
-
category:
|
|
135
|
+
category: alert_types_1.AlertCategory.OPERATIONS,
|
|
136
136
|
propertyId: "prop123",
|
|
137
137
|
title: "Legacy Alert",
|
|
138
138
|
description: "This alert was created using the old CreateAlertData format",
|
|
@@ -15,7 +15,7 @@ export declare enum AlertSeverity {
|
|
|
15
15
|
}
|
|
16
16
|
export interface AlertDocument {
|
|
17
17
|
_id: string;
|
|
18
|
-
category: AlertCategory
|
|
18
|
+
category: AlertCategory;
|
|
19
19
|
propertyId: string;
|
|
20
20
|
title: string;
|
|
21
21
|
description: string;
|
|
@@ -32,7 +32,7 @@ export interface AlertDocument {
|
|
|
32
32
|
updatedAt: Date;
|
|
33
33
|
}
|
|
34
34
|
export interface CreateAlertData {
|
|
35
|
-
category: AlertCategory
|
|
35
|
+
category: AlertCategory;
|
|
36
36
|
propertyId: string;
|
|
37
37
|
title: string;
|
|
38
38
|
description: string;
|
|
@@ -43,7 +43,7 @@ export interface CreateAlertData {
|
|
|
43
43
|
snoozeUntil?: Date;
|
|
44
44
|
}
|
|
45
45
|
export interface UpdateAlertData {
|
|
46
|
-
category?: AlertCategory
|
|
46
|
+
category?: AlertCategory;
|
|
47
47
|
title?: string;
|
|
48
48
|
description?: string;
|
|
49
49
|
entityId?: string;
|
|
@@ -56,7 +56,7 @@ export interface UpdateAlertData {
|
|
|
56
56
|
}
|
|
57
57
|
export interface IAlertQuery {
|
|
58
58
|
propertyId?: string;
|
|
59
|
-
category?: AlertCategory
|
|
59
|
+
category?: AlertCategory;
|
|
60
60
|
severity?: AlertSeverity;
|
|
61
61
|
entityType?: EntityType;
|
|
62
62
|
entityId?: string;
|
|
@@ -65,11 +65,6 @@ let EventHandler = (() => {
|
|
|
65
65
|
actionPayload: body,
|
|
66
66
|
},
|
|
67
67
|
});
|
|
68
|
-
// const payload = {
|
|
69
|
-
// eventType: DT_EVENT_TYPES.DEVICE.CREATE.SUCCESS,
|
|
70
|
-
// properties: await this.auditUtils.buildAuditProperties(body),
|
|
71
|
-
// };
|
|
72
|
-
// await publishAudit(payload);
|
|
73
68
|
}
|
|
74
69
|
async onDeviceUpdate(deviceId, body, auditBody) {
|
|
75
70
|
await (0, audit_1.pushAudit)({
|
|
@@ -80,15 +75,6 @@ let EventHandler = (() => {
|
|
|
80
75
|
...auditBody,
|
|
81
76
|
},
|
|
82
77
|
});
|
|
83
|
-
// const payload = {
|
|
84
|
-
// eventType: DT_EVENT_TYPES.DEVICE.UPDATE.SUCCESS,
|
|
85
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
86
|
-
// ...auditBody,
|
|
87
|
-
// deviceId,
|
|
88
|
-
// ...body,
|
|
89
|
-
// }),
|
|
90
|
-
// };
|
|
91
|
-
// await publishAudit(payload);
|
|
92
78
|
}
|
|
93
79
|
async onDeviceDelete(deviceId, auditBody) {
|
|
94
80
|
await (0, audit_1.pushAudit)({
|
|
@@ -98,14 +84,6 @@ let EventHandler = (() => {
|
|
|
98
84
|
...auditBody,
|
|
99
85
|
},
|
|
100
86
|
});
|
|
101
|
-
// const payload = {
|
|
102
|
-
// eventType: DT_EVENT_TYPES.DEVICE.DELETE.SUCCESS,
|
|
103
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
104
|
-
// ...auditBody,
|
|
105
|
-
// deviceId,
|
|
106
|
-
// }),
|
|
107
|
-
// };
|
|
108
|
-
// await publishAudit(payload);
|
|
109
87
|
}
|
|
110
88
|
async onStateChange(deviceId, state, auditProperties, eventType) {
|
|
111
89
|
await (0, audit_1.pushAudit)({
|
|
@@ -116,15 +94,6 @@ let EventHandler = (() => {
|
|
|
116
94
|
...auditProperties,
|
|
117
95
|
},
|
|
118
96
|
});
|
|
119
|
-
// const payload = {
|
|
120
|
-
// eventType: eventType || DT_EVENT_TYPES.DEVICE.STATE.CHANGED,
|
|
121
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
122
|
-
// ...auditProperties,
|
|
123
|
-
// deviceId,
|
|
124
|
-
// ...state,
|
|
125
|
-
// }),
|
|
126
|
-
// };
|
|
127
|
-
// await publishAudit(payload);
|
|
128
97
|
}
|
|
129
98
|
async onStatusChange(deviceId, status, auditProperties, eventType) {
|
|
130
99
|
await (0, audit_1.pushAudit)({
|
|
@@ -135,15 +104,6 @@ let EventHandler = (() => {
|
|
|
135
104
|
...auditProperties,
|
|
136
105
|
},
|
|
137
106
|
});
|
|
138
|
-
// const payload = {
|
|
139
|
-
// eventType: eventType || DT_EVENT_TYPES.DEVICE.STATUS.CHANGED,
|
|
140
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
141
|
-
// ...auditProperties,
|
|
142
|
-
// deviceId,
|
|
143
|
-
// ...status,
|
|
144
|
-
// }),
|
|
145
|
-
// };
|
|
146
|
-
// await publishAudit(payload);
|
|
147
107
|
}
|
|
148
108
|
async onStatusChangeMany(query, status, auditProperties, eventType) {
|
|
149
109
|
await (0, audit_1.pushAudit)({
|
|
@@ -154,15 +114,6 @@ let EventHandler = (() => {
|
|
|
154
114
|
...auditProperties,
|
|
155
115
|
},
|
|
156
116
|
});
|
|
157
|
-
// const payload = {
|
|
158
|
-
// eventType: eventType || DT_EVENT_TYPES.DEVICE.STATUS.UPDATED,
|
|
159
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
160
|
-
// ...auditProperties,
|
|
161
|
-
// ...query,
|
|
162
|
-
// ...status,
|
|
163
|
-
// }),
|
|
164
|
-
// };
|
|
165
|
-
// await publishAudit(payload);
|
|
166
117
|
}
|
|
167
118
|
async onBatteryLevelChange(deviceId, batteryLevel, auditProperties) {
|
|
168
119
|
await (0, audit_1.pushAudit)({
|
|
@@ -173,15 +124,6 @@ let EventHandler = (() => {
|
|
|
173
124
|
...auditProperties,
|
|
174
125
|
},
|
|
175
126
|
});
|
|
176
|
-
// const payload = {
|
|
177
|
-
// eventType: DT_EVENT_TYPES.DEVICE.BATTERY_LEVEL.UPDATED,
|
|
178
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
179
|
-
// ...auditProperties,
|
|
180
|
-
// deviceId,
|
|
181
|
-
// batteryLevel,
|
|
182
|
-
// }),
|
|
183
|
-
// };
|
|
184
|
-
// await publishAudit(payload);
|
|
185
127
|
}
|
|
186
128
|
async onDeviceMetaChange(deviceId, metaData, auditProperties) {
|
|
187
129
|
await (0, audit_1.pushAudit)({
|
|
@@ -192,15 +134,6 @@ let EventHandler = (() => {
|
|
|
192
134
|
...auditProperties,
|
|
193
135
|
},
|
|
194
136
|
});
|
|
195
|
-
// const payload = {
|
|
196
|
-
// eventType: DT_EVENT_TYPES.DEVICE.METADATA.UPDATED,
|
|
197
|
-
// properties: await this.auditUtils.buildAuditProperties({
|
|
198
|
-
// ...auditProperties,
|
|
199
|
-
// deviceId,
|
|
200
|
-
// metaData,
|
|
201
|
-
// }),
|
|
202
|
-
// };
|
|
203
|
-
// await publishAudit(payload);
|
|
204
137
|
}
|
|
205
138
|
};
|
|
206
139
|
__setFunctionName(_classThis, "EventHandler");
|
|
@@ -123,6 +123,9 @@ const IssueSchema = new mongoose_1.Schema({
|
|
|
123
123
|
}, {
|
|
124
124
|
timestamps: true,
|
|
125
125
|
collection: "dt_issues",
|
|
126
|
+
toJSON: { virtuals: true },
|
|
127
|
+
toObject: { virtuals: true },
|
|
128
|
+
id: false, // Disable the virtual id field since we're handling it manually
|
|
126
129
|
});
|
|
127
130
|
exports.IssueSchema = IssueSchema;
|
|
128
131
|
IssueSchema.index({ propertyId: 1, status: 1 });
|
|
@@ -138,6 +141,35 @@ IssueSchema.pre(["updateOne", "findOneAndUpdate", "updateMany"], function (next)
|
|
|
138
141
|
this.set({ updatedAt: new Date() });
|
|
139
142
|
next();
|
|
140
143
|
});
|
|
144
|
+
// Post middleware to transform all find results to plain objects
|
|
145
|
+
IssueSchema.post(/^find/, function (result) {
|
|
146
|
+
if (!result)
|
|
147
|
+
return;
|
|
148
|
+
// Handle array results (find)
|
|
149
|
+
if (Array.isArray(result)) {
|
|
150
|
+
result.forEach((doc) => {
|
|
151
|
+
if (doc && typeof doc.toObject === "function") {
|
|
152
|
+
const plainDoc = doc.toObject();
|
|
153
|
+
// Transform _id to id and remove __v
|
|
154
|
+
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
|
|
155
|
+
delete plainDoc._id;
|
|
156
|
+
delete plainDoc.__v;
|
|
157
|
+
// Replace the document with plain object
|
|
158
|
+
Object.assign(doc, plainDoc);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// Handle single document results (findOne, findById, etc.)
|
|
163
|
+
else if (result && typeof result.toObject === "function") {
|
|
164
|
+
const plainDoc = result.toObject();
|
|
165
|
+
// Transform _id to id and remove __v
|
|
166
|
+
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
|
|
167
|
+
delete plainDoc._id;
|
|
168
|
+
delete plainDoc.__v;
|
|
169
|
+
// Replace the document with plain object
|
|
170
|
+
Object.assign(result, plainDoc);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
141
173
|
// Instance methods
|
|
142
174
|
IssueSchema.methods.addComment = function (commentData) {
|
|
143
175
|
const comment = {
|
|
@@ -225,8 +257,24 @@ IssueSchema.statics.findUpcoming = function (days = 7, includeDeleted = false) {
|
|
|
225
257
|
IssueSchema.virtual("isActive").get(function () {
|
|
226
258
|
return !this.isDeleted;
|
|
227
259
|
});
|
|
228
|
-
// Ensure virtuals are serialized
|
|
229
|
-
IssueSchema.set("toJSON", {
|
|
230
|
-
|
|
260
|
+
// Ensure virtuals are serialized and transform to plain objects
|
|
261
|
+
IssueSchema.set("toJSON", {
|
|
262
|
+
virtuals: true,
|
|
263
|
+
transform: function (doc, ret) {
|
|
264
|
+
ret.id = ret._id ? ret._id.toString() : ret._id;
|
|
265
|
+
delete ret._id;
|
|
266
|
+
delete ret.__v;
|
|
267
|
+
return ret;
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
IssueSchema.set("toObject", {
|
|
271
|
+
virtuals: true,
|
|
272
|
+
transform: function (doc, ret) {
|
|
273
|
+
ret.id = ret._id ? ret._id.toString() : ret._id;
|
|
274
|
+
delete ret._id;
|
|
275
|
+
delete ret.__v;
|
|
276
|
+
return ret;
|
|
277
|
+
},
|
|
278
|
+
});
|
|
231
279
|
// Create and export the model
|
|
232
280
|
exports.IssueModel = mongoose_1.default.model("Issue", IssueSchema);
|
|
@@ -100,7 +100,8 @@ let IssueRepository = (() => {
|
|
|
100
100
|
if (!includeDeleted) {
|
|
101
101
|
query.isDeleted = false;
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
const result = await Issue_model_1.IssueModel.findOne(query);
|
|
104
|
+
return result ? result.toObject() : null;
|
|
104
105
|
}
|
|
105
106
|
catch (error) {
|
|
106
107
|
throw new Error(`Failed to find issue by ID: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -123,7 +124,8 @@ let IssueRepository = (() => {
|
|
|
123
124
|
queryBuilder.skip(filters.skip);
|
|
124
125
|
if (filters.limit)
|
|
125
126
|
queryBuilder.limit(filters.limit);
|
|
126
|
-
|
|
127
|
+
const results = await queryBuilder.exec();
|
|
128
|
+
return results.map((result) => result.toObject());
|
|
127
129
|
}
|
|
128
130
|
catch (error) {
|
|
129
131
|
throw new Error(`Failed to find issues: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -134,7 +136,8 @@ let IssueRepository = (() => {
|
|
|
134
136
|
*/
|
|
135
137
|
async update(id, updateData) {
|
|
136
138
|
try {
|
|
137
|
-
|
|
139
|
+
const result = await Issue_model_1.IssueModel.findByIdAndUpdate(id, { ...updateData, updatedAt: new Date() }, { new: true, runValidators: true });
|
|
140
|
+
return result ? result.toObject() : null;
|
|
138
141
|
}
|
|
139
142
|
catch (error) {
|
|
140
143
|
throw new Error(`Failed to update issue: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -233,7 +236,8 @@ let IssueRepository = (() => {
|
|
|
233
236
|
queryBuilder.skip(filters.skip);
|
|
234
237
|
if (filters.limit)
|
|
235
238
|
queryBuilder.limit(filters.limit);
|
|
236
|
-
|
|
239
|
+
const results = await queryBuilder.exec();
|
|
240
|
+
return results.map((result) => result.toObject());
|
|
237
241
|
}
|
|
238
242
|
catch (error) {
|
|
239
243
|
throw new Error(`Failed to search issues: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -38,6 +38,7 @@ export declare class IssueService {
|
|
|
38
38
|
* Create issue for device going offline longer than baseline
|
|
39
39
|
*/
|
|
40
40
|
createDeviceOfflineIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument>;
|
|
41
|
+
createDoorLeftOpenIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument>;
|
|
41
42
|
/**
|
|
42
43
|
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
43
44
|
*/
|
|
@@ -77,6 +77,7 @@ const Issue_repository_1 = require("./Issue.repository");
|
|
|
77
77
|
const Issue_model_1 = require("./Issue.model");
|
|
78
78
|
const issue_types_1 = require("./issue.types");
|
|
79
79
|
const IssueBuilder_1 = require("./IssueBuilder");
|
|
80
|
+
const Admin_service_1 = require("../entities/admin/Admin.service");
|
|
80
81
|
let IssueService = (() => {
|
|
81
82
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
82
83
|
let _classDescriptor;
|
|
@@ -231,6 +232,19 @@ let IssueService = (() => {
|
|
|
231
232
|
priority: issue_types_1.IssuePriority.HIGH,
|
|
232
233
|
});
|
|
233
234
|
}
|
|
235
|
+
async createDoorLeftOpenIssue(device, source, reason) {
|
|
236
|
+
const zone = await typedi_1.default.get(Admin_service_1.AdminService).getZone(device.zoneId);
|
|
237
|
+
return await this.createDeviceIssue({
|
|
238
|
+
entityId: device.deviceId,
|
|
239
|
+
entityType: issue_types_1.EntityType.DEVICE,
|
|
240
|
+
propertyId: device.propertyId,
|
|
241
|
+
title: "Door Left Open - Requires Attention",
|
|
242
|
+
description: `Zone ${zone?.name} has a door left open, for more than 10 minutes. ${reason ? `Reason: ${reason}` : ""}. Please check the zone and close the door.`,
|
|
243
|
+
createdBy: source,
|
|
244
|
+
category: issue_types_1.IssuesCategory.SECURITY,
|
|
245
|
+
priority: issue_types_1.IssuePriority.HIGH,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
234
248
|
/**
|
|
235
249
|
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
236
250
|
*/
|
|
@@ -240,7 +254,7 @@ let IssueService = (() => {
|
|
|
240
254
|
entityType: issue_types_1.EntityType.DEVICE,
|
|
241
255
|
propertyId: device.propertyId,
|
|
242
256
|
title: "Device Battery Low - Requires Attention",
|
|
243
|
-
description: `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.
|
|
257
|
+
description: `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%. Please replace or charge the device battery.`,
|
|
244
258
|
createdBy: source,
|
|
245
259
|
category: issue_types_1.IssuesCategory.ENERGY,
|
|
246
260
|
priority: issue_types_1.IssuePriority.MEDIUM,
|