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.
@@ -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: [String],
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: { $in: [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
- // Ensure virtuals are serialized
191
- AlertSchema.set("toJSON", { virtuals: true });
192
- AlertSchema.set("toObject", { virtuals: true });
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 | AlertCategory[], includeDeleted?: boolean): Promise<IAlertDocument[]>;
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
- if (Array.isArray(filters.category)) {
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
- return await alert.save();
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
- return await Alert_model_1.AlertModel.findOne(query);
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
- return await queryBuilder.exec();
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
- return await Alert_model_1.AlertModel.findByIdAndUpdate(id, { ...updateData, updatedAt: new Date() }, { new: true, runValidators: true });
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
- if (Array.isArray(category)) {
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 | AlertCategory[], severity?: AlertSeverity, source?: Source): Promise<IAlertDocument>;
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 | AlertCategory[], severity?: AlertSeverity, createdBy?: string): Promise<IAlertDocument>;
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 | AlertCategory[], includeDeleted?: boolean): Promise<IAlertDocument[]>;
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}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
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}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.INFO, source);
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}%.`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS, alert_types_1.AlertCategory.ENERGY], alert_types_1.AlertSeverity.MEDIUM, 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}%.`, 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}` : ""}`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
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) {
@@ -23,7 +23,7 @@ export declare class AlertBuilder {
23
23
  /**
24
24
  * Sets the alert category
25
25
  */
26
- setCategory(category: AlertCategory | AlertCategory[]): this;
26
+ setCategory(category: AlertCategory): this;
27
27
  /**
28
28
  * Sets the property ID
29
29
  */
@@ -29,7 +29,7 @@ class AlertBuilder {
29
29
  * Sets the alert category
30
30
  */
31
31
  setCategory(category) {
32
- this.data.category = Array.isArray(category) ? category : [category];
32
+ this.data.category = category;
33
33
  return this;
34
34
  }
35
35
  /**
@@ -132,7 +132,7 @@ class AlertServiceExample {
132
132
  */
133
133
  async createAlertWithLegacyData() {
134
134
  const alertData = {
135
- category: [alert_types_1.AlertCategory.OPERATIONS],
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 | 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", { virtuals: true });
230
- IssueSchema.set("toObject", { virtuals: true });
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
- return await Issue_model_1.IssueModel.findOne(query);
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
- return await queryBuilder.exec();
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
- return await Issue_model_1.IssueModel.findByIdAndUpdate(id, { ...updateData, updatedAt: new Date() }, { new: true, runValidators: true });
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
- return await queryBuilder.exec();
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}%. This requires immediate attention to replace or charge the device battery.`,
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [