dt-common-device 6.2.1 → 7.1.0

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.
@@ -48,6 +48,11 @@ const AlertSchema = new mongoose_1.Schema({
48
48
  required: true,
49
49
  index: true,
50
50
  },
51
+ zoneId: {
52
+ type: String,
53
+ required: true,
54
+ index: true,
55
+ },
51
56
  title: {
52
57
  type: String,
53
58
  required: true,
@@ -116,6 +121,7 @@ const AlertSchema = new mongoose_1.Schema({
116
121
  exports.AlertSchema = AlertSchema;
117
122
  // Compound indexes to match Prisma schema
118
123
  AlertSchema.index({ propertyId: 1, isActive: 1, isRead: 1 });
124
+ AlertSchema.index({ zoneId: 1, category: 1 });
119
125
  AlertSchema.index({ entityId: 1, entityType: 1 });
120
126
  AlertSchema.index({ createdAt: 1 });
121
127
  // Pre-save middleware to update the updatedAt field
@@ -45,7 +45,7 @@ export declare class AlertRepository {
45
45
  /**
46
46
  * Get alert statistics
47
47
  */
48
- getStatistics(propertyId?: string): Promise<{
48
+ getStatistics(propertyId?: string, zoneId?: string): Promise<{
49
49
  total: number;
50
50
  active: number;
51
51
  unread: number;
@@ -61,4 +61,38 @@ export declare class AlertRepository {
61
61
  * Bulk soft delete alerts
62
62
  */
63
63
  bulkSoftDelete(ids: string[], deletedBy: string): Promise<number>;
64
+ /**
65
+ * Find alerts by zone ID
66
+ */
67
+ findByZoneId(zoneId: string, includeDeleted?: boolean): Promise<IAlertDocument[]>;
68
+ /**
69
+ * Find alerts by zone ID and category
70
+ */
71
+ findByZoneIdAndCategory(zoneId: string, category: AlertCategory, includeDeleted?: boolean): Promise<IAlertDocument[]>;
72
+ /**
73
+ * Find alerts by zone ID and severity
74
+ */
75
+ findByZoneIdAndSeverity(zoneId: string, severity: AlertSeverity, includeDeleted?: boolean): Promise<IAlertDocument[]>;
76
+ /**
77
+ * Find alerts by zone ID and active status
78
+ */
79
+ findByZoneIdAndActiveStatus(zoneId: string, isActive: boolean, includeDeleted?: boolean): Promise<IAlertDocument[]>;
80
+ /**
81
+ * Find alerts by zone ID and read status
82
+ */
83
+ findByZoneIdAndReadStatus(zoneId: string, isRead: boolean, includeDeleted?: boolean): Promise<IAlertDocument[]>;
84
+ /**
85
+ * Find alerts by multiple zone IDs
86
+ */
87
+ findByZoneIds(zoneIds: string[], includeDeleted?: boolean): Promise<IAlertDocument[]>;
88
+ /**
89
+ * Get alert statistics by zone ID and severity
90
+ */
91
+ getStatisticsByZoneAndSeverity(zoneId: string, severity?: AlertSeverity): Promise<{
92
+ total: number;
93
+ active: number;
94
+ unread: number;
95
+ snoozed: number;
96
+ byCategory: Record<AlertCategory, number>;
97
+ }>;
64
98
  }
@@ -52,6 +52,8 @@ let AlertRepository = (() => {
52
52
  const query = {};
53
53
  if (filters.propertyId)
54
54
  query.propertyId = filters.propertyId;
55
+ if (filters.zoneId)
56
+ query.zoneId = filters.zoneId;
55
57
  if (filters.category)
56
58
  query.category = filters.category;
57
59
  if (filters.severity)
@@ -215,11 +217,13 @@ let AlertRepository = (() => {
215
217
  /**
216
218
  * Get alert statistics
217
219
  */
218
- async getStatistics(propertyId) {
220
+ async getStatistics(propertyId, zoneId) {
219
221
  try {
220
222
  const query = { isDeleted: false };
221
223
  if (propertyId)
222
224
  query.propertyId = propertyId;
225
+ if (zoneId)
226
+ query.zoneId = zoneId;
223
227
  const [total, active, unread, snoozed, severityStats, categoryStats] = await Promise.all([
224
228
  Alert_model_1.AlertModel.countDocuments(query),
225
229
  Alert_model_1.AlertModel.countDocuments({ ...query, isActive: true }),
@@ -297,6 +301,147 @@ let AlertRepository = (() => {
297
301
  throw new Error(`Failed to bulk soft delete alerts: ${error instanceof Error ? error.message : "Unknown error"}`);
298
302
  }
299
303
  }
304
+ /**
305
+ * Find alerts by zone ID
306
+ */
307
+ async findByZoneId(zoneId, includeDeleted = false) {
308
+ try {
309
+ const query = { zoneId };
310
+ if (!includeDeleted) {
311
+ query.isDeleted = false;
312
+ }
313
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
314
+ return results.map((result) => result.toObject());
315
+ }
316
+ catch (error) {
317
+ throw new Error(`Failed to find alerts by zone ID: ${error instanceof Error ? error.message : "Unknown error"}`);
318
+ }
319
+ }
320
+ /**
321
+ * Find alerts by zone ID and category
322
+ */
323
+ async findByZoneIdAndCategory(zoneId, category, includeDeleted = false) {
324
+ try {
325
+ const query = { zoneId, category };
326
+ if (!includeDeleted) {
327
+ query.isDeleted = false;
328
+ }
329
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
330
+ return results.map((result) => result.toObject());
331
+ }
332
+ catch (error) {
333
+ throw new Error(`Failed to find alerts by zone ID and category: ${error instanceof Error ? error.message : "Unknown error"}`);
334
+ }
335
+ }
336
+ /**
337
+ * Find alerts by zone ID and severity
338
+ */
339
+ async findByZoneIdAndSeverity(zoneId, severity, includeDeleted = false) {
340
+ try {
341
+ const query = { zoneId, severity };
342
+ if (!includeDeleted) {
343
+ query.isDeleted = false;
344
+ }
345
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
346
+ return results.map((result) => result.toObject());
347
+ }
348
+ catch (error) {
349
+ throw new Error(`Failed to find alerts by zone ID and severity: ${error instanceof Error ? error.message : "Unknown error"}`);
350
+ }
351
+ }
352
+ /**
353
+ * Find alerts by zone ID and active status
354
+ */
355
+ async findByZoneIdAndActiveStatus(zoneId, isActive, includeDeleted = false) {
356
+ try {
357
+ const query = { zoneId, isActive };
358
+ if (!includeDeleted) {
359
+ query.isDeleted = false;
360
+ }
361
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
362
+ return results.map((result) => result.toObject());
363
+ }
364
+ catch (error) {
365
+ throw new Error(`Failed to find alerts by zone ID and active status: ${error instanceof Error ? error.message : "Unknown error"}`);
366
+ }
367
+ }
368
+ /**
369
+ * Find alerts by zone ID and read status
370
+ */
371
+ async findByZoneIdAndReadStatus(zoneId, isRead, includeDeleted = false) {
372
+ try {
373
+ const query = { zoneId, isRead };
374
+ if (!includeDeleted) {
375
+ query.isDeleted = false;
376
+ }
377
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
378
+ return results.map((result) => result.toObject());
379
+ }
380
+ catch (error) {
381
+ throw new Error(`Failed to find alerts by zone ID and read status: ${error instanceof Error ? error.message : "Unknown error"}`);
382
+ }
383
+ }
384
+ /**
385
+ * Find alerts by multiple zone IDs
386
+ */
387
+ async findByZoneIds(zoneIds, includeDeleted = false) {
388
+ try {
389
+ if (!zoneIds || zoneIds.length === 0) {
390
+ throw new Error("Zone IDs array is required and cannot be empty");
391
+ }
392
+ const query = { zoneId: { $in: zoneIds } };
393
+ if (!includeDeleted) {
394
+ query.isDeleted = false;
395
+ }
396
+ const results = await Alert_model_1.AlertModel.find(query).sort({ createdAt: -1 });
397
+ return results.map((result) => result.toObject());
398
+ }
399
+ catch (error) {
400
+ throw new Error(`Failed to find alerts by zone IDs: ${error instanceof Error ? error.message : "Unknown error"}`);
401
+ }
402
+ }
403
+ /**
404
+ * Get alert statistics by zone ID and severity
405
+ */
406
+ async getStatisticsByZoneAndSeverity(zoneId, severity) {
407
+ try {
408
+ const query = { isDeleted: false, zoneId };
409
+ if (severity)
410
+ query.severity = severity;
411
+ const [total, active, unread, snoozed, categoryStats] = await Promise.all([
412
+ Alert_model_1.AlertModel.countDocuments(query),
413
+ Alert_model_1.AlertModel.countDocuments({ ...query, isActive: true }),
414
+ Alert_model_1.AlertModel.countDocuments({ ...query, isRead: false }),
415
+ Alert_model_1.AlertModel.countDocuments({
416
+ ...query,
417
+ snoozeUntil: { $exists: true, $ne: null },
418
+ }),
419
+ Alert_model_1.AlertModel.aggregate([
420
+ { $match: query },
421
+ { $group: { _id: "$category", count: { $sum: 1 } } },
422
+ ]),
423
+ ]);
424
+ const byCategory = Object.values(alert_types_1.AlertCategory).reduce((acc, category) => {
425
+ acc[category] = 0;
426
+ return acc;
427
+ }, {});
428
+ categoryStats.forEach((stat) => {
429
+ if (stat._id in byCategory) {
430
+ byCategory[stat._id] = stat.count;
431
+ }
432
+ });
433
+ return {
434
+ total,
435
+ active,
436
+ unread,
437
+ snoozed,
438
+ byCategory,
439
+ };
440
+ }
441
+ catch (error) {
442
+ throw new Error(`Failed to get alert statistics by zone and severity: ${error instanceof Error ? error.message : "Unknown error"}`);
443
+ }
444
+ }
300
445
  };
301
446
  __setFunctionName(_classThis, "AlertRepository");
302
447
  (() => {
@@ -9,27 +9,27 @@ export declare class AlertService {
9
9
  /**
10
10
  * Create a readiness alert using AlertBuilder
11
11
  */
12
- raiseReadinessAlert(propertyId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
12
+ raiseReadinessAlert(propertyId: string, zoneId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
13
13
  /**
14
14
  * Create an operations alert using AlertBuilder
15
15
  */
16
- raiseOperationsAlert(propertyId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
16
+ raiseOperationsAlert(propertyId: string, zoneId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
17
17
  /**
18
18
  * Create a security alert using AlertBuilder
19
19
  */
20
- raiseSecurityAlert(propertyId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
20
+ raiseSecurityAlert(propertyId: string, zoneId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
21
21
  /**
22
22
  * Create an energy alert using AlertBuilder
23
23
  */
24
- raiseEnergyAlert(propertyId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
24
+ raiseEnergyAlert(propertyId: string, zoneId: string, title: string, description: string, entityId?: string, entityType?: EntityType, createdBy?: string): Promise<IAlertDocument>;
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, severity?: AlertSeverity, source?: Source): Promise<IAlertDocument>;
28
+ raiseDeviceAlert(deviceId: string, propertyId: string, zoneId: 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, severity?: AlertSeverity, createdBy?: string): Promise<IAlertDocument>;
32
+ raiseHubAlert(hubId: string, propertyId: string, zoneId: 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
  */
@@ -106,7 +106,7 @@ export declare class AlertService {
106
106
  /**
107
107
  * Get alert statistics with business logic
108
108
  */
109
- getAlertStatistics(propertyId?: string): Promise<{
109
+ getAlertStatistics(propertyId?: string, zoneId?: string): Promise<{
110
110
  total: number;
111
111
  active: number;
112
112
  unread: number;
@@ -114,6 +114,40 @@ export declare class AlertService {
114
114
  bySeverity: Record<AlertSeverity, number>;
115
115
  byCategory: Record<AlertCategory, number>;
116
116
  }>;
117
+ /**
118
+ * Get alerts by zone ID
119
+ */
120
+ getAlertsByZoneId(zoneId: string, includeDeleted?: boolean): Promise<IAlertDocument[]>;
121
+ /**
122
+ * Get alerts by zone ID and category
123
+ */
124
+ getAlertsByZoneIdAndCategory(zoneId: string, category: AlertCategory, includeDeleted?: boolean): Promise<IAlertDocument[]>;
125
+ /**
126
+ * Get alerts by zone ID and severity
127
+ */
128
+ getAlertsByZoneIdAndSeverity(zoneId: string, severity: AlertSeverity, includeDeleted?: boolean): Promise<IAlertDocument[]>;
129
+ /**
130
+ * Get alerts by multiple zone IDs
131
+ */
132
+ getAlertsByZoneIds(zoneIds: string[], includeDeleted?: boolean): Promise<IAlertDocument[]>;
133
+ /**
134
+ * Get alert statistics by zone ID and severity
135
+ */
136
+ getAlertStatisticsByZoneAndSeverity(zoneId: string, severity?: AlertSeverity): Promise<{
137
+ total: number;
138
+ active: number;
139
+ unread: number;
140
+ snoozed: number;
141
+ byCategory: Record<AlertCategory, number>;
142
+ }>;
143
+ /**
144
+ * Get alerts by zone ID and active status
145
+ */
146
+ getAlertsByZoneIdAndActiveStatus(zoneId: string, isActive: boolean, includeDeleted?: boolean): Promise<IAlertDocument[]>;
147
+ /**
148
+ * Get alerts by zone ID and read status
149
+ */
150
+ getAlertsByZoneIdAndReadStatus(zoneId: string, isRead: boolean, includeDeleted?: boolean): Promise<IAlertDocument[]>;
117
151
  private validateAlertData;
118
152
  private validateFilters;
119
153
  private validateUpdateData;
@@ -89,9 +89,10 @@ let AlertService = (() => {
89
89
  /**
90
90
  * Create a readiness alert using AlertBuilder
91
91
  */
92
- async raiseReadinessAlert(propertyId, title, description, entityId, entityType, createdBy) {
92
+ async raiseReadinessAlert(propertyId, zoneId, title, description, entityId, entityType, createdBy) {
93
93
  const alertBuilder = AlertBuilder_1.AlertBuilder.createReadinessAlert()
94
94
  .setPropertyId(propertyId)
95
+ .setZoneId(zoneId)
95
96
  .setTitle(title)
96
97
  .setDescription(description);
97
98
  if (entityId)
@@ -105,9 +106,10 @@ let AlertService = (() => {
105
106
  /**
106
107
  * Create an operations alert using AlertBuilder
107
108
  */
108
- async raiseOperationsAlert(propertyId, title, description, entityId, entityType, createdBy) {
109
+ async raiseOperationsAlert(propertyId, zoneId, title, description, entityId, entityType, createdBy) {
109
110
  const alertBuilder = AlertBuilder_1.AlertBuilder.createOperationsAlert()
110
111
  .setPropertyId(propertyId)
112
+ .setZoneId(zoneId)
111
113
  .setTitle(title)
112
114
  .setDescription(description);
113
115
  if (entityId)
@@ -121,9 +123,10 @@ let AlertService = (() => {
121
123
  /**
122
124
  * Create a security alert using AlertBuilder
123
125
  */
124
- async raiseSecurityAlert(propertyId, title, description, entityId, entityType, createdBy) {
126
+ async raiseSecurityAlert(propertyId, zoneId, title, description, entityId, entityType, createdBy) {
125
127
  const alertBuilder = AlertBuilder_1.AlertBuilder.createSecurityAlert()
126
128
  .setPropertyId(propertyId)
129
+ .setZoneId(zoneId)
127
130
  .setTitle(title)
128
131
  .setDescription(description);
129
132
  if (entityId)
@@ -137,9 +140,10 @@ let AlertService = (() => {
137
140
  /**
138
141
  * Create an energy alert using AlertBuilder
139
142
  */
140
- async raiseEnergyAlert(propertyId, title, description, entityId, entityType, createdBy) {
143
+ async raiseEnergyAlert(propertyId, zoneId, title, description, entityId, entityType, createdBy) {
141
144
  const alertBuilder = AlertBuilder_1.AlertBuilder.createEnergyAlert()
142
145
  .setPropertyId(propertyId)
146
+ .setZoneId(zoneId)
143
147
  .setTitle(title)
144
148
  .setDescription(description);
145
149
  if (entityId)
@@ -153,8 +157,8 @@ let AlertService = (() => {
153
157
  /**
154
158
  * Create a device-specific alert using AlertBuilder
155
159
  */
156
- async raiseDeviceAlert(deviceId, propertyId, title, description, category, severity, source) {
157
- const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(deviceId, propertyId)
160
+ async raiseDeviceAlert(deviceId, propertyId, zoneId, title, description, category, severity, source) {
161
+ const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(deviceId, propertyId, zoneId)
158
162
  .setTitle(title)
159
163
  .setDescription(description);
160
164
  if (category)
@@ -168,8 +172,8 @@ let AlertService = (() => {
168
172
  /**
169
173
  * Create a hub-specific alert using AlertBuilder
170
174
  */
171
- async raiseHubAlert(hubId, propertyId, title, description, category, severity, createdBy) {
172
- const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(hubId, propertyId)
175
+ async raiseHubAlert(hubId, propertyId, zoneId, title, description, category, severity, createdBy) {
176
+ const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(hubId, propertyId, zoneId)
173
177
  .setTitle(title)
174
178
  .setDescription(description);
175
179
  if (category)
@@ -184,25 +188,25 @@ let AlertService = (() => {
184
188
  * Raise alert for device going offline (OPERATIONAL only)
185
189
  */
186
190
  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);
191
+ return await this.raiseDeviceAlert(device.deviceId, device.propertyId, device.zoneId, "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
192
  }
189
193
  /**
190
194
  * Raise alert for device coming online (OPERATIONAL only)
191
195
  */
192
196
  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);
197
+ return await this.raiseDeviceAlert(device.deviceId, device.propertyId, device.zoneId, "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
198
  }
195
199
  /**
196
200
  * Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
197
201
  */
198
202
  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.ENERGY, alert_types_1.AlertSeverity.MEDIUM, source);
203
+ return await this.raiseDeviceAlert(device.deviceId, device.propertyId, device.zoneId, "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
204
  }
201
205
  /**
202
206
  * Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
203
207
  */
204
208
  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.AlertSeverity.HIGH, source);
209
+ return await this.raiseDeviceAlert(device.deviceId, device.propertyId, device.zoneId, `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
210
  }
207
211
  /**
208
212
  * Create a new alert with business logic validation
@@ -401,8 +405,8 @@ let AlertService = (() => {
401
405
  /**
402
406
  * Get alert statistics with business logic
403
407
  */
404
- async getAlertStatistics(propertyId) {
405
- const stats = await this.alertRepository.getStatistics(propertyId);
408
+ async getAlertStatistics(propertyId, zoneId) {
409
+ const stats = await this.alertRepository.getStatistics(propertyId, zoneId);
406
410
  // Business logic: Add alerts for critical metrics
407
411
  if (stats.unread > 0) {
408
412
  console.warn(`Alert: ${stats.unread} unread alerts require attention`);
@@ -415,6 +419,83 @@ let AlertService = (() => {
415
419
  }
416
420
  return stats;
417
421
  }
422
+ /**
423
+ * Get alerts by zone ID
424
+ */
425
+ async getAlertsByZoneId(zoneId, includeDeleted = false) {
426
+ if (!zoneId) {
427
+ throw new Error("Zone ID is required");
428
+ }
429
+ return await this.alertRepository.findByZoneId(zoneId, includeDeleted);
430
+ }
431
+ /**
432
+ * Get alerts by zone ID and category
433
+ */
434
+ async getAlertsByZoneIdAndCategory(zoneId, category, includeDeleted = false) {
435
+ if (!zoneId) {
436
+ throw new Error("Zone ID is required");
437
+ }
438
+ if (!category) {
439
+ throw new Error("Alert category is required");
440
+ }
441
+ return await this.alertRepository.findByZoneIdAndCategory(zoneId, category, includeDeleted);
442
+ }
443
+ /**
444
+ * Get alerts by zone ID and severity
445
+ */
446
+ async getAlertsByZoneIdAndSeverity(zoneId, severity, includeDeleted = false) {
447
+ if (!zoneId) {
448
+ throw new Error("Zone ID is required");
449
+ }
450
+ if (!severity) {
451
+ throw new Error("Alert severity is required");
452
+ }
453
+ return await this.alertRepository.findByZoneIdAndSeverity(zoneId, severity, includeDeleted);
454
+ }
455
+ /**
456
+ * Get alerts by multiple zone IDs
457
+ */
458
+ async getAlertsByZoneIds(zoneIds, includeDeleted = false) {
459
+ if (!zoneIds || zoneIds.length === 0) {
460
+ throw new Error("Zone IDs array is required and cannot be empty");
461
+ }
462
+ return await this.alertRepository.findByZoneIds(zoneIds, includeDeleted);
463
+ }
464
+ /**
465
+ * Get alert statistics by zone ID and severity
466
+ */
467
+ async getAlertStatisticsByZoneAndSeverity(zoneId, severity) {
468
+ if (!zoneId) {
469
+ throw new Error("Zone ID is required");
470
+ }
471
+ const stats = await this.alertRepository.getStatisticsByZoneAndSeverity(zoneId, severity);
472
+ // Business logic: Add alerts for critical metrics
473
+ if (stats.unread > 0) {
474
+ console.warn(`Alert: ${stats.unread} unread alerts in zone ${zoneId} require attention`);
475
+ }
476
+ if (severity === alert_types_1.AlertSeverity.CRITICAL && stats.total > 0) {
477
+ console.error(`Alert: ${stats.total} critical alerts in zone ${zoneId} require immediate attention`);
478
+ }
479
+ return stats;
480
+ }
481
+ /**
482
+ * Get alerts by zone ID and active status
483
+ */
484
+ async getAlertsByZoneIdAndActiveStatus(zoneId, isActive, includeDeleted = false) {
485
+ if (!zoneId) {
486
+ throw new Error("Zone ID is required");
487
+ }
488
+ return await this.alertRepository.findByZoneIdAndActiveStatus(zoneId, isActive, includeDeleted);
489
+ }
490
+ /**
491
+ * Get alerts by zone ID and read status
492
+ */
493
+ async getAlertsByZoneIdAndReadStatus(zoneId, isRead, includeDeleted = false) {
494
+ if (!zoneId) {
495
+ throw new Error("Zone ID is required");
496
+ }
497
+ return await this.alertRepository.findByZoneIdAndReadStatus(zoneId, isRead, includeDeleted);
498
+ }
418
499
  // Private business logic methods
419
500
  validateAlertData(data) {
420
501
  if (!data.title || data.title.trim().length < 3) {
@@ -426,6 +507,9 @@ let AlertService = (() => {
426
507
  if (!data.propertyId) {
427
508
  throw new Error("Property ID is required");
428
509
  }
510
+ if (!data.zoneId) {
511
+ throw new Error("Zone ID is required");
512
+ }
429
513
  if (!data.entityType) {
430
514
  throw new Error("Entity type is required");
431
515
  }
@@ -28,6 +28,10 @@ export declare class AlertBuilder {
28
28
  * Sets the property ID
29
29
  */
30
30
  setPropertyId(propertyId: string): this;
31
+ /**
32
+ * Sets the zone ID
33
+ */
34
+ setZoneId(zoneId: string): this;
31
35
  /**
32
36
  * Sets the alert title
33
37
  */
@@ -79,9 +83,9 @@ export declare class AlertBuilder {
79
83
  /**
80
84
  * Creates a device-specific alert builder
81
85
  */
82
- static createDeviceAlert(deviceId: string, propertyId: string): AlertBuilder;
86
+ static createDeviceAlert(deviceId: string, propertyId: string, zoneId: string): AlertBuilder;
83
87
  /**
84
88
  * Creates a hub-specific alert builder
85
89
  */
86
- static createHubAlert(hubId: string, propertyId: string): AlertBuilder;
90
+ static createHubAlert(hubId: string, propertyId: string, zoneId: string): AlertBuilder;
87
91
  }
@@ -42,6 +42,16 @@ class AlertBuilder {
42
42
  this.data.propertyId = propertyId;
43
43
  return this;
44
44
  }
45
+ /**
46
+ * Sets the zone ID
47
+ */
48
+ setZoneId(zoneId) {
49
+ if (!zoneId || zoneId.trim() === "") {
50
+ throw new Error("Zone ID is required and cannot be empty");
51
+ }
52
+ this.data.zoneId = zoneId;
53
+ return this;
54
+ }
45
55
  /**
46
56
  * Sets the alert title
47
57
  */
@@ -112,6 +122,7 @@ class AlertBuilder {
112
122
  const requiredFields = [
113
123
  "category",
114
124
  "propertyId",
125
+ "zoneId",
115
126
  "title",
116
127
  "description",
117
128
  "entityType",
@@ -167,20 +178,22 @@ class AlertBuilder {
167
178
  /**
168
179
  * Creates a device-specific alert builder
169
180
  */
170
- static createDeviceAlert(deviceId, propertyId) {
181
+ static createDeviceAlert(deviceId, propertyId, zoneId) {
171
182
  return new AlertBuilder()
172
183
  .setEntityType(alert_types_1.EntityType.DEVICE)
173
184
  .setEntityId(deviceId)
174
- .setPropertyId(propertyId);
185
+ .setPropertyId(propertyId)
186
+ .setZoneId(zoneId);
175
187
  }
176
188
  /**
177
189
  * Creates a hub-specific alert builder
178
190
  */
179
- static createHubAlert(hubId, propertyId) {
191
+ static createHubAlert(hubId, propertyId, zoneId) {
180
192
  return new AlertBuilder()
181
193
  .setEntityType(alert_types_1.EntityType.HUB)
182
194
  .setEntityId(hubId)
183
- .setPropertyId(propertyId);
195
+ .setPropertyId(propertyId)
196
+ .setZoneId(zoneId);
184
197
  }
185
198
  }
186
199
  exports.AlertBuilder = AlertBuilder;
@@ -17,6 +17,7 @@ export interface AlertDocument {
17
17
  _id: string;
18
18
  category: AlertCategory;
19
19
  propertyId: string;
20
+ zoneId: string;
20
21
  title: string;
21
22
  description: string;
22
23
  entityId?: string;
@@ -34,6 +35,7 @@ export interface AlertDocument {
34
35
  export interface CreateAlertData {
35
36
  category: AlertCategory;
36
37
  propertyId: string;
38
+ zoneId: string;
37
39
  title: string;
38
40
  description: string;
39
41
  entityId?: string;
@@ -56,6 +58,7 @@ export interface UpdateAlertData {
56
58
  }
57
59
  export interface IAlertQuery {
58
60
  propertyId?: string;
61
+ zoneId?: string;
59
62
  category?: AlertCategory;
60
63
  severity?: AlertSeverity;
61
64
  entityType?: EntityType;
@@ -1,11 +1,11 @@
1
- import { IAccessGroup, IUser, IZone } from "./IAdmin";
1
+ import { IAccessGroup, IUser, IZone, IZoneAccessGroup } from "./IAdmin";
2
2
  export declare class AdminRepository {
3
- private readonly axiosInstance;
4
3
  private readonly deviceRepository;
5
4
  private readonly postgres;
6
5
  constructor();
7
6
  getZonesByAccessGroupIds(accessGroupIds: string[]): Promise<any[]>;
8
7
  getAccessGroup(accessGroupId: string): Promise<IAccessGroup | null>;
8
+ getZoneAccessGroupByZoneId(zoneId: string): Promise<IZoneAccessGroup | null>;
9
9
  getZone(zoneId: string): Promise<IZone | null>;
10
10
  getUser(userId: string): Promise<IUser | null>;
11
11
  }
@@ -84,7 +84,6 @@ let AdminRepository = (() => {
84
84
  let _classThis;
85
85
  var AdminRepository = _classThis = class {
86
86
  constructor() {
87
- this.axiosInstance = (0, utils_1.getAdminServiceAxiosInstance)();
88
87
  this.deviceRepository = typedi_1.default.get(Device_repository_1.DeviceRepository);
89
88
  this.postgres = (0, db_1.getPostgresClient)();
90
89
  }
@@ -112,7 +111,7 @@ let AdminRepository = (() => {
112
111
  const collectionZone = [];
113
112
  for (let zone of response) {
114
113
  let zoneIds = [];
115
- const zones = (await this.axiosInstance.get(`/zones/child?zoneId=${zone.zoneId}`))?.data?.data;
114
+ const zones = (await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zone.zoneId}`))?.data?.data;
116
115
  zoneIds.push(zone.zoneId);
117
116
  if (zones.childZones?.length > 0) {
118
117
  const nestedZoneIds = new Set(_zones(zones.childZones));
@@ -177,6 +176,17 @@ let AdminRepository = (() => {
177
176
  }
178
177
  return null;
179
178
  }
179
+ async getZoneAccessGroupByZoneId(zoneId) {
180
+ const query = `
181
+ SELECT * FROM dt_zones_collection_map
182
+ WHERE "zoneId" = $1
183
+ `;
184
+ const result = await this.postgres.query(query, [zoneId]);
185
+ if (result.rows.length > 0) {
186
+ return result.rows[0];
187
+ }
188
+ return null;
189
+ }
180
190
  async getZone(zoneId) {
181
191
  try {
182
192
  const zone = await this.postgres.query(`SELECT * FROM dt_zones WHERE "id" = $1`, [zoneId]);
@@ -4,6 +4,7 @@ export declare class AdminService {
4
4
  constructor();
5
5
  getZonesByAccessGroupIds(accessGroupIds: string[]): Promise<any[] | undefined>;
6
6
  getAccessGroup(accessGroupId: string): Promise<IAccessGroup | null>;
7
+ getAccessGroupByZoneId(zoneId: string): Promise<IAccessGroup | null>;
7
8
  getZone(zoneId: string): Promise<IZone | null>;
8
9
  getUser(userId: string): Promise<IUser | null>;
9
10
  }
@@ -100,6 +100,18 @@ let AdminService = (() => {
100
100
  return null;
101
101
  return accessGroup;
102
102
  }
103
+ async getAccessGroupByZoneId(zoneId) {
104
+ if (!zoneId) {
105
+ throw new Error("Zone ID is required");
106
+ }
107
+ const zoneAccessGroup = await this.adminRepository.getZoneAccessGroupByZoneId(zoneId);
108
+ if (!zoneAccessGroup)
109
+ return null;
110
+ const accessGroup = await this.adminRepository.getAccessGroup(zoneAccessGroup.collectionId);
111
+ if (!accessGroup)
112
+ return null;
113
+ return accessGroup;
114
+ }
103
115
  async getZone(zoneId) {
104
116
  if (!zoneId) {
105
117
  throw new Error("Zone ID is required");
@@ -12,6 +12,11 @@ export interface IAccessGroup {
12
12
  updatedAt: Date;
13
13
  accessibleBy: string[];
14
14
  }
15
+ export interface IZoneAccessGroup {
16
+ id: string;
17
+ zoneId: string;
18
+ collectionId: string;
19
+ }
15
20
  export interface IZone {
16
21
  id: string;
17
22
  name: string;
@@ -3,6 +3,7 @@ export declare class PmsRepository {
3
3
  private readonly pmsPostgres;
4
4
  constructor();
5
5
  getSchedule(scheduleId: string): Promise<IPmsSchedule | null>;
6
+ getScheduleIdByAccessGroupId(accessGroupId: string, status: string): Promise<string | null>;
6
7
  getGuest(guestId: string): Promise<IGuest | null>;
7
8
  getGuestId(scheduleId: string): Promise<string | null>;
8
9
  }
@@ -63,6 +63,14 @@ let PmsRepository = (() => {
63
63
  throw new Error("Failed to get schedule");
64
64
  }
65
65
  }
66
+ async getScheduleIdByAccessGroupId(accessGroupId, status) {
67
+ const scheduleId = await this.pmsPostgres.query(`SELECT "scheduleId" FROM dt_schedule_accessgroup_map WHERE "accessGroupId" = $1 AND "status" = $2`, [accessGroupId, status]);
68
+ //TODO: Need to Check if only one Schedule is there for the given Access Group in checked-in state!
69
+ if (scheduleId.rows.length > 0) {
70
+ return scheduleId.rows[0].scheduleId;
71
+ }
72
+ return null;
73
+ }
66
74
  async getGuest(guestId) {
67
75
  try {
68
76
  const guest = await this.pmsPostgres.query(`SELECT * FROM dt_guest WHERE "id" = $1`, [guestId]);
@@ -3,6 +3,7 @@ export declare class PmsService {
3
3
  private readonly pmsRepository;
4
4
  constructor();
5
5
  getSchedule(scheduleId: string): Promise<IPmsSchedule | null>;
6
+ getScheduleIdByAccessGroupId(accessGroupId: string, status: string): Promise<string | null>;
6
7
  getGuest(guestId: string): Promise<IGuest | null>;
7
8
  getGuestId(scheduleId: string): Promise<string | null>;
8
9
  }
@@ -92,6 +92,15 @@ let PmsService = (() => {
92
92
  return null;
93
93
  return schedule;
94
94
  }
95
+ async getScheduleIdByAccessGroupId(accessGroupId, status) {
96
+ if (!accessGroupId) {
97
+ throw new Error("Access Group ID is required");
98
+ }
99
+ const scheduleId = await this.pmsRepository.getScheduleIdByAccessGroupId(accessGroupId, status);
100
+ if (!scheduleId)
101
+ return null;
102
+ return scheduleId;
103
+ }
95
104
  async getGuest(guestId) {
96
105
  if (!guestId) {
97
106
  throw new Error("Guest ID is required");
@@ -56,6 +56,11 @@ const IssueSchema = new mongoose_1.Schema({
56
56
  required: true,
57
57
  index: true,
58
58
  },
59
+ zoneId: {
60
+ type: String,
61
+ required: true,
62
+ index: true,
63
+ },
59
64
  title: {
60
65
  type: String,
61
66
  required: true,
@@ -129,6 +134,7 @@ const IssueSchema = new mongoose_1.Schema({
129
134
  });
130
135
  exports.IssueSchema = IssueSchema;
131
136
  IssueSchema.index({ propertyId: 1, status: 1 });
137
+ IssueSchema.index({ zoneId: 1, status: 1 });
132
138
  IssueSchema.index({ assignedTo: 1, status: 1 });
133
139
  IssueSchema.index({ entityId: 1, entityType: 1 });
134
140
  // Pre-save middleware to update the updatedAt field
@@ -47,6 +47,7 @@ export declare class IssueRepository {
47
47
  */
48
48
  search(searchTerm: string, filters?: {
49
49
  propertyId?: string;
50
+ zoneId?: string;
50
51
  includeDeleted?: boolean;
51
52
  limit?: number;
52
53
  skip?: number;
@@ -54,7 +55,7 @@ export declare class IssueRepository {
54
55
  /**
55
56
  * Get issue statistics
56
57
  */
57
- getStatistics(propertyId?: string): Promise<{
58
+ getStatistics(propertyId?: string, zoneId?: string): Promise<{
58
59
  total: number;
59
60
  pending: number;
60
61
  inProgress: number;
@@ -72,4 +73,16 @@ export declare class IssueRepository {
72
73
  * Bulk soft delete issues
73
74
  */
74
75
  bulkSoftDelete(ids: string[], deletedBy: string): Promise<number>;
76
+ /**
77
+ * Find issues by zone ID
78
+ */
79
+ findByZoneId(zoneId: string, includeDeleted?: boolean): Promise<IIssueDocument[]>;
80
+ /**
81
+ * Find issues by zone ID and status
82
+ */
83
+ findByZoneIdAndStatus(zoneId: string, status: string, includeDeleted?: boolean): Promise<IIssueDocument[]>;
84
+ /**
85
+ * Find issues by multiple zone IDs
86
+ */
87
+ findByZoneIds(zoneIds: string[], includeDeleted?: boolean): Promise<IIssueDocument[]>;
75
88
  }
@@ -52,6 +52,8 @@ let IssueRepository = (() => {
52
52
  const query = {};
53
53
  if (filters.propertyId)
54
54
  query.propertyId = filters.propertyId;
55
+ if (filters.zoneId)
56
+ query.zoneId = filters.zoneId;
55
57
  if (filters.assignedTo)
56
58
  query.assignedTo = filters.assignedTo;
57
59
  if (filters.status)
@@ -229,6 +231,8 @@ let IssueRepository = (() => {
229
231
  };
230
232
  if (filters.propertyId)
231
233
  query.propertyId = filters.propertyId;
234
+ if (filters.zoneId)
235
+ query.zoneId = filters.zoneId;
232
236
  if (!filters.includeDeleted)
233
237
  query.isDeleted = false;
234
238
  const queryBuilder = Issue_model_1.IssueModel.find(query).sort({ createdAt: -1 });
@@ -246,11 +250,13 @@ let IssueRepository = (() => {
246
250
  /**
247
251
  * Get issue statistics
248
252
  */
249
- async getStatistics(propertyId) {
253
+ async getStatistics(propertyId, zoneId) {
250
254
  try {
251
255
  const query = { isDeleted: false };
252
256
  if (propertyId)
253
257
  query.propertyId = propertyId;
258
+ if (zoneId)
259
+ query.zoneId = zoneId;
254
260
  const [total, pending, inProgress, resolved, closed, overdue, priorityStats, categoryStats,] = await Promise.all([
255
261
  Issue_model_1.IssueModel.countDocuments(query),
256
262
  Issue_model_1.IssueModel.countDocuments({ ...query, status: issue_types_1.IssueStatus.PENDING }),
@@ -341,6 +347,57 @@ let IssueRepository = (() => {
341
347
  throw new Error(`Failed to bulk soft delete issues: ${error instanceof Error ? error.message : "Unknown error"}`);
342
348
  }
343
349
  }
350
+ /**
351
+ * Find issues by zone ID
352
+ */
353
+ async findByZoneId(zoneId, includeDeleted = false) {
354
+ try {
355
+ const query = { zoneId };
356
+ if (!includeDeleted) {
357
+ query.isDeleted = false;
358
+ }
359
+ const results = await Issue_model_1.IssueModel.find(query).sort({ createdAt: -1 });
360
+ return results.map((result) => result.toObject());
361
+ }
362
+ catch (error) {
363
+ throw new Error(`Failed to find issues by zone ID: ${error instanceof Error ? error.message : "Unknown error"}`);
364
+ }
365
+ }
366
+ /**
367
+ * Find issues by zone ID and status
368
+ */
369
+ async findByZoneIdAndStatus(zoneId, status, includeDeleted = false) {
370
+ try {
371
+ const query = { zoneId, status };
372
+ if (!includeDeleted) {
373
+ query.isDeleted = false;
374
+ }
375
+ const results = await Issue_model_1.IssueModel.find(query).sort({ createdAt: -1 });
376
+ return results.map((result) => result.toObject());
377
+ }
378
+ catch (error) {
379
+ throw new Error(`Failed to find issues by zone ID and status: ${error instanceof Error ? error.message : "Unknown error"}`);
380
+ }
381
+ }
382
+ /**
383
+ * Find issues by multiple zone IDs
384
+ */
385
+ async findByZoneIds(zoneIds, includeDeleted = false) {
386
+ try {
387
+ if (!zoneIds || zoneIds.length === 0) {
388
+ throw new Error("Zone IDs array is required and cannot be empty");
389
+ }
390
+ const query = { zoneId: { $in: zoneIds } };
391
+ if (!includeDeleted) {
392
+ query.isDeleted = false;
393
+ }
394
+ const results = await Issue_model_1.IssueModel.find(query).sort({ createdAt: -1 });
395
+ return results.map((result) => result.toObject());
396
+ }
397
+ catch (error) {
398
+ throw new Error(`Failed to find issues by zone IDs: ${error instanceof Error ? error.message : "Unknown error"}`);
399
+ }
400
+ }
344
401
  };
345
402
  __setFunctionName(_classThis, "IssueRepository");
346
403
  (() => {
@@ -123,7 +123,7 @@ export declare class IssueService {
123
123
  /**
124
124
  * Get issue statistics with business logic
125
125
  */
126
- getIssueStatistics(propertyId?: string): Promise<{
126
+ getIssueStatistics(propertyId?: string, zoneId?: string): Promise<{
127
127
  total: number;
128
128
  pending: number;
129
129
  inProgress: number;
@@ -138,10 +138,23 @@ export declare class IssueService {
138
138
  */
139
139
  searchIssues(searchTerm: string, filters?: {
140
140
  propertyId?: string;
141
+ zoneId?: string;
141
142
  includeDeleted?: boolean;
142
143
  limit?: number;
143
144
  skip?: number;
144
145
  }): Promise<IIssueDocument[]>;
146
+ /**
147
+ * Get issues by zone ID
148
+ */
149
+ getIssuesByZoneId(zoneId: string, includeDeleted?: boolean): Promise<IIssueDocument[]>;
150
+ /**
151
+ * Get issues by zone ID and status
152
+ */
153
+ getIssuesByZoneIdAndStatus(zoneId: string, status: string, includeDeleted?: boolean): Promise<IIssueDocument[]>;
154
+ /**
155
+ * Get issues by multiple zone IDs
156
+ */
157
+ getIssuesByZoneIds(zoneIds: string[], includeDeleted?: boolean): Promise<IIssueDocument[]>;
145
158
  private validateIssueData;
146
159
  private validateFilters;
147
160
  private validateUpdateData;
@@ -93,6 +93,7 @@ let IssueService = (() => {
93
93
  async createReadinessIssue(data) {
94
94
  const issueBuilder = IssueBuilder_1.IssueBuilder.createReadinessIssue()
95
95
  .setPropertyId(data.propertyId)
96
+ .setZoneId(data.zoneId)
96
97
  .setTitle(data.title)
97
98
  .setDescription(data.description)
98
99
  .setCreatedBy(data.createdBy);
@@ -112,6 +113,7 @@ let IssueService = (() => {
112
113
  async createOperationsIssue(data) {
113
114
  const issueBuilder = IssueBuilder_1.IssueBuilder.createOperationsIssue()
114
115
  .setPropertyId(data.propertyId)
116
+ .setZoneId(data.zoneId)
115
117
  .setTitle(data.title)
116
118
  .setDescription(data.description)
117
119
  .setCreatedBy(data.createdBy);
@@ -131,6 +133,7 @@ let IssueService = (() => {
131
133
  async createSecurityIssue(data) {
132
134
  const issueBuilder = IssueBuilder_1.IssueBuilder.createSecurityIssue()
133
135
  .setPropertyId(data.propertyId)
136
+ .setZoneId(data.zoneId)
134
137
  .setTitle(data.title)
135
138
  .setDescription(data.description)
136
139
  .setCreatedBy(data.createdBy);
@@ -150,6 +153,7 @@ let IssueService = (() => {
150
153
  async createEnergyIssue(data) {
151
154
  const issueBuilder = IssueBuilder_1.IssueBuilder.createEnergyIssue()
152
155
  .setPropertyId(data.propertyId)
156
+ .setZoneId(data.zoneId)
153
157
  .setTitle(data.title)
154
158
  .setDescription(data.description)
155
159
  .setCreatedBy(data.createdBy);
@@ -167,7 +171,7 @@ let IssueService = (() => {
167
171
  * Create a device-specific issue using IssueBuilder
168
172
  */
169
173
  async createDeviceIssue(data) {
170
- const issueBuilder = IssueBuilder_1.IssueBuilder.createDeviceIssue(data.entityId, data.propertyId)
174
+ const issueBuilder = IssueBuilder_1.IssueBuilder.createDeviceIssue(data.entityId, data.propertyId, data.zoneId)
171
175
  .setTitle(data.title)
172
176
  .setDescription(data.description)
173
177
  .setCreatedBy(data.createdBy);
@@ -185,7 +189,7 @@ let IssueService = (() => {
185
189
  * Create a hub-specific issue using IssueBuilder
186
190
  */
187
191
  async createHubIssue(data) {
188
- const issueBuilder = IssueBuilder_1.IssueBuilder.createHubIssue(data.entityId, data.propertyId)
192
+ const issueBuilder = IssueBuilder_1.IssueBuilder.createHubIssue(data.entityId, data.propertyId, data.zoneId)
189
193
  .setTitle(data.title)
190
194
  .setDescription(data.description)
191
195
  .setCreatedBy(data.createdBy);
@@ -203,7 +207,7 @@ let IssueService = (() => {
203
207
  * Create a user-specific issue using IssueBuilder
204
208
  */
205
209
  async createUserIssue(data) {
206
- const issueBuilder = IssueBuilder_1.IssueBuilder.createUserIssue(data.entityId, data.propertyId)
210
+ const issueBuilder = IssueBuilder_1.IssueBuilder.createUserIssue(data.entityId, data.propertyId, data.zoneId)
207
211
  .setTitle(data.title)
208
212
  .setDescription(data.description)
209
213
  .setCreatedBy(data.createdBy);
@@ -225,6 +229,7 @@ let IssueService = (() => {
225
229
  entityId: device.deviceId,
226
230
  entityType: issue_types_1.EntityType.DEVICE,
227
231
  propertyId: device.propertyId,
232
+ zoneId: device.zoneId,
228
233
  title: "Device Offline - Requires Attention",
229
234
  description: `Device ${device.name} (${device.deviceId}) has been offline for longer than the baseline time. ${reason ? `Reason: ${reason}` : ""} This requires immediate attention to restore device functionality.`,
230
235
  createdBy: source,
@@ -238,6 +243,7 @@ let IssueService = (() => {
238
243
  entityId: device.deviceId,
239
244
  entityType: issue_types_1.EntityType.DEVICE,
240
245
  propertyId: device.propertyId,
246
+ zoneId: device.zoneId,
241
247
  title: "Door Left Open - Requires Attention",
242
248
  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
249
  createdBy: source,
@@ -253,6 +259,7 @@ let IssueService = (() => {
253
259
  entityId: device.deviceId,
254
260
  entityType: issue_types_1.EntityType.DEVICE,
255
261
  propertyId: device.propertyId,
262
+ zoneId: device.zoneId,
256
263
  title: "Device Battery Low - Requires Attention",
257
264
  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.`,
258
265
  createdBy: source,
@@ -268,6 +275,7 @@ let IssueService = (() => {
268
275
  entityId: device.deviceId,
269
276
  entityType: issue_types_1.EntityType.DEVICE,
270
277
  propertyId: device.propertyId,
278
+ zoneId: device.zoneId,
271
279
  title: `Device Malfunction - ${issueType} - Requires Attention`,
272
280
  description: `Device ${device.name} (${device.deviceId}) has a malfunction: ${issueType}. ${reason ? `Reason: ${reason}` : ""} This requires immediate attention to resolve the device malfunction.`,
273
281
  createdBy: source,
@@ -279,7 +287,7 @@ let IssueService = (() => {
279
287
  * Create a maintenance issue using IssueBuilder
280
288
  */
281
289
  async createMaintenanceIssue(data) {
282
- const issueBuilder = IssueBuilder_1.IssueBuilder.createMaintenanceIssue(data.propertyId, data.entityId, data.entityType)
290
+ const issueBuilder = IssueBuilder_1.IssueBuilder.createMaintenanceIssue(data.propertyId, data.zoneId, data.entityId, data.entityType)
283
291
  .setTitle(data.title)
284
292
  .setDescription(data.description)
285
293
  .setCreatedBy(data.createdBy);
@@ -293,7 +301,7 @@ let IssueService = (() => {
293
301
  * Create an urgent issue using IssueBuilder
294
302
  */
295
303
  async createUrgentIssue(data) {
296
- const issueBuilder = IssueBuilder_1.IssueBuilder.createUrgentIssue(data.propertyId, data.entityId, data.entityType)
304
+ const issueBuilder = IssueBuilder_1.IssueBuilder.createUrgentIssue(data.propertyId, data.zoneId, data.entityId, data.entityType)
297
305
  .setTitle(data.title)
298
306
  .setDescription(data.description)
299
307
  .setCreatedBy(data.createdBy);
@@ -569,8 +577,8 @@ let IssueService = (() => {
569
577
  /**
570
578
  * Get issue statistics with business logic
571
579
  */
572
- async getIssueStatistics(propertyId) {
573
- const stats = await this.issueRepository.getStatistics(propertyId);
580
+ async getIssueStatistics(propertyId, zoneId) {
581
+ const stats = await this.issueRepository.getStatistics(propertyId, zoneId);
574
582
  // Business logic: Calculate additional metrics
575
583
  const responseTime = this.calculateAverageResponseTime(stats);
576
584
  const resolutionRate = this.calculateResolutionRate(stats);
@@ -595,6 +603,36 @@ let IssueService = (() => {
595
603
  }
596
604
  return await this.issueRepository.search(searchTerm, filters);
597
605
  }
606
+ /**
607
+ * Get issues by zone ID
608
+ */
609
+ async getIssuesByZoneId(zoneId, includeDeleted = false) {
610
+ if (!zoneId) {
611
+ throw new Error("Zone ID is required");
612
+ }
613
+ return await this.issueRepository.findByZoneId(zoneId, includeDeleted);
614
+ }
615
+ /**
616
+ * Get issues by zone ID and status
617
+ */
618
+ async getIssuesByZoneIdAndStatus(zoneId, status, includeDeleted = false) {
619
+ if (!zoneId) {
620
+ throw new Error("Zone ID is required");
621
+ }
622
+ if (!status) {
623
+ throw new Error("Status is required");
624
+ }
625
+ return await this.issueRepository.findByZoneIdAndStatus(zoneId, status, includeDeleted);
626
+ }
627
+ /**
628
+ * Get issues by multiple zone IDs
629
+ */
630
+ async getIssuesByZoneIds(zoneIds, includeDeleted = false) {
631
+ if (!zoneIds || zoneIds.length === 0) {
632
+ throw new Error("Zone IDs array is required and cannot be empty");
633
+ }
634
+ return await this.issueRepository.findByZoneIds(zoneIds, includeDeleted);
635
+ }
598
636
  // Private business logic methods
599
637
  validateIssueData(data) {
600
638
  if (!data.title || data.title.trim().length < 5) {
@@ -606,6 +644,9 @@ let IssueService = (() => {
606
644
  if (!data.propertyId) {
607
645
  throw new Error("Property ID is required");
608
646
  }
647
+ if (!data.zoneId) {
648
+ throw new Error("Zone ID is required");
649
+ }
609
650
  if (!data.createdBy) {
610
651
  throw new Error("Created by user ID is required");
611
652
  }
@@ -30,6 +30,10 @@ export declare class IssueBuilder {
30
30
  * Sets the property ID
31
31
  */
32
32
  setPropertyId(propertyId: string): this;
33
+ /**
34
+ * Sets the zone ID
35
+ */
36
+ setZoneId(zoneId: string): this;
33
37
  /**
34
38
  * Sets the issue title
35
39
  */
@@ -85,25 +89,25 @@ export declare class IssueBuilder {
85
89
  /**
86
90
  * Creates a device-specific issue builder
87
91
  */
88
- static createDeviceIssue(deviceId: string, propertyId: string): IssueBuilder;
92
+ static createDeviceIssue(deviceId: string, propertyId: string, zoneId: string): IssueBuilder;
89
93
  /**
90
94
  * Creates a hub-specific issue builder
91
95
  */
92
- static createHubIssue(hubId: string, propertyId: string): IssueBuilder;
96
+ static createHubIssue(hubId: string, propertyId: string, zoneId: string): IssueBuilder;
93
97
  /**
94
98
  * Creates a user-specific issue builder
95
99
  */
96
- static createUserIssue(userId: string, propertyId: string): IssueBuilder;
100
+ static createUserIssue(userId: string, propertyId: string, zoneId: string): IssueBuilder;
97
101
  /**
98
102
  * Creates a property-specific issue builder
99
103
  */
100
- static createPropertyIssue(propertyId: string): IssueBuilder;
104
+ static createPropertyIssue(propertyId: string, zoneId: string): IssueBuilder;
101
105
  /**
102
106
  * Creates a maintenance issue builder
103
107
  */
104
- static createMaintenanceIssue(propertyId: string, entityId?: string, entityType?: EntityType): IssueBuilder;
108
+ static createMaintenanceIssue(propertyId: string, zoneId: string, entityId?: string, entityType?: EntityType): IssueBuilder;
105
109
  /**
106
110
  * Creates an urgent issue builder
107
111
  */
108
- static createUrgentIssue(propertyId: string, entityId?: string, entityType?: EntityType): IssueBuilder;
112
+ static createUrgentIssue(propertyId: string, zoneId: string, entityId?: string, entityType?: EntityType): IssueBuilder;
109
113
  }
@@ -44,6 +44,16 @@ class IssueBuilder {
44
44
  this.data.propertyId = propertyId;
45
45
  return this;
46
46
  }
47
+ /**
48
+ * Sets the zone ID
49
+ */
50
+ setZoneId(zoneId) {
51
+ if (!zoneId || zoneId.trim() === "") {
52
+ throw new Error("Zone ID is required and cannot be empty");
53
+ }
54
+ this.data.zoneId = zoneId;
55
+ return this;
56
+ }
47
57
  /**
48
58
  * Sets the issue title
49
59
  */
@@ -124,6 +134,7 @@ class IssueBuilder {
124
134
  const requiredFields = [
125
135
  "category",
126
136
  "propertyId",
137
+ "zoneId",
127
138
  "title",
128
139
  "description",
129
140
  "entityId",
@@ -180,46 +191,51 @@ class IssueBuilder {
180
191
  /**
181
192
  * Creates a device-specific issue builder
182
193
  */
183
- static createDeviceIssue(deviceId, propertyId) {
194
+ static createDeviceIssue(deviceId, propertyId, zoneId) {
184
195
  return new IssueBuilder()
185
196
  .setEntityType(issue_types_1.EntityType.DEVICE)
186
197
  .setEntityId(deviceId)
187
- .setPropertyId(propertyId);
198
+ .setPropertyId(propertyId)
199
+ .setZoneId(zoneId);
188
200
  }
189
201
  /**
190
202
  * Creates a hub-specific issue builder
191
203
  */
192
- static createHubIssue(hubId, propertyId) {
204
+ static createHubIssue(hubId, propertyId, zoneId) {
193
205
  return new IssueBuilder()
194
206
  .setEntityType(issue_types_1.EntityType.HUB)
195
207
  .setEntityId(hubId)
196
- .setPropertyId(propertyId);
208
+ .setPropertyId(propertyId)
209
+ .setZoneId(zoneId);
197
210
  }
198
211
  /**
199
212
  * Creates a user-specific issue builder
200
213
  */
201
- static createUserIssue(userId, propertyId) {
214
+ static createUserIssue(userId, propertyId, zoneId) {
202
215
  return new IssueBuilder()
203
216
  .setEntityType(issue_types_1.EntityType.USER)
204
217
  .setEntityId(userId)
205
- .setPropertyId(propertyId);
218
+ .setPropertyId(propertyId)
219
+ .setZoneId(zoneId);
206
220
  }
207
221
  /**
208
222
  * Creates a property-specific issue builder
209
223
  */
210
- static createPropertyIssue(propertyId) {
224
+ static createPropertyIssue(propertyId, zoneId) {
211
225
  return new IssueBuilder()
212
226
  .setEntityType(issue_types_1.EntityType.PROPERTY)
213
227
  .setEntityId(propertyId)
214
- .setPropertyId(propertyId);
228
+ .setPropertyId(propertyId)
229
+ .setZoneId(zoneId);
215
230
  }
216
231
  /**
217
232
  * Creates a maintenance issue builder
218
233
  */
219
- static createMaintenanceIssue(propertyId, entityId, entityType) {
234
+ static createMaintenanceIssue(propertyId, zoneId, entityId, entityType) {
220
235
  const builder = new IssueBuilder()
221
236
  .setCategory(issue_types_1.IssuesCategory.READINESS)
222
237
  .setPropertyId(propertyId)
238
+ .setZoneId(zoneId)
223
239
  .setPriority(issue_types_1.IssuePriority.MEDIUM);
224
240
  if (entityId)
225
241
  builder.setEntityId(entityId);
@@ -230,10 +246,11 @@ class IssueBuilder {
230
246
  /**
231
247
  * Creates an urgent issue builder
232
248
  */
233
- static createUrgentIssue(propertyId, entityId, entityType) {
249
+ static createUrgentIssue(propertyId, zoneId, entityId, entityType) {
234
250
  const builder = new IssueBuilder()
235
251
  .setCategory(issue_types_1.IssuesCategory.OPERATIONS)
236
252
  .setPropertyId(propertyId)
253
+ .setZoneId(zoneId)
237
254
  .setPriority(issue_types_1.IssuePriority.URGENT);
238
255
  if (entityId)
239
256
  builder.setEntityId(entityId);
@@ -42,6 +42,7 @@ export interface IssueDocument {
42
42
  _id: string;
43
43
  category: IssuesCategory;
44
44
  propertyId: string;
45
+ zoneId: string;
45
46
  title: string;
46
47
  description: string;
47
48
  entityId?: string;
@@ -61,6 +62,7 @@ export interface IssueDocument {
61
62
  export interface CreateIssueData {
62
63
  category: IssuesCategory;
63
64
  propertyId: string;
65
+ zoneId: string;
64
66
  title: string;
65
67
  description: string;
66
68
  entityId: string;
@@ -90,6 +92,7 @@ export interface AddCommentData {
90
92
  }
91
93
  export interface IIssueQuery {
92
94
  propertyId?: string;
95
+ zoneId?: string;
93
96
  assignedTo?: string;
94
97
  status?: IssueStatus;
95
98
  priority?: IssuePriority;
@@ -34,7 +34,7 @@ function createAxiosInstance(baseURL) {
34
34
  validateStatus: (status) => status < 500, // Don't throw on 4xx errors
35
35
  headers: {
36
36
  "Content-Type": "application/json",
37
- "User-Agent": "dt-common-device/1.3.0",
37
+ "User-Agent": `dt-common-device/${require('../../package.json').version}`,
38
38
  "x-api-key": (0, config_1.getDTApiKey)(),
39
39
  },
40
40
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "6.2.1",
3
+ "version": "7.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [