dt-common-device 7.3.0 → 7.5.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.
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AlertSchema = exports.AlertModel = void 0;
37
37
  const mongoose_1 = __importStar(require("mongoose"));
38
38
  const alert_types_1 = require("./alert.types");
39
+ const issues_1 = require("../issues");
39
40
  // Main Alert schema
40
41
  const AlertSchema = new mongoose_1.Schema({
41
42
  category: {
@@ -50,7 +51,7 @@ const AlertSchema = new mongoose_1.Schema({
50
51
  },
51
52
  zoneId: {
52
53
  type: String,
53
- required: true,
54
+ required: false,
54
55
  index: true,
55
56
  },
56
57
  title: {
@@ -74,6 +75,12 @@ const AlertSchema = new mongoose_1.Schema({
74
75
  required: true,
75
76
  index: true,
76
77
  },
78
+ entitySubType: {
79
+ type: String,
80
+ enum: Object.values(issues_1.EntitySubType),
81
+ required: true,
82
+ index: true,
83
+ },
77
84
  severity: {
78
85
  type: String,
79
86
  enum: Object.values(alert_types_1.AlertSeverity),
@@ -1,45 +1,42 @@
1
1
  import { IAlertDocument } from "./Alert.model";
2
2
  import { CreateAlertData, UpdateAlertData, AlertCategory, AlertSeverity, IAlertQuery } from "./alert.types";
3
3
  import { AlertBuilder } from "./AlertBuilder";
4
+ import { IDevice } from "../entities/device/local/interfaces";
5
+ import { Source } from "../constants";
4
6
  export declare class AlertService {
5
7
  private readonly alertRepository;
6
8
  constructor();
7
9
  /**
8
10
  * Create an operations alert using AlertBuilder
9
11
  */
10
- raiseOperationsAlert(data: CreateAlertData): Promise<IAlertDocument>;
12
+ raiseOperationsAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
11
13
  /**
12
14
  * Create a security alert using AlertBuilder
13
15
  */
14
- raiseSecurityAlert(data: CreateAlertData): Promise<IAlertDocument>;
15
- /**
16
- * Create an energy alert using AlertBuilder
17
- */
18
- raiseEnergyAlert(data: CreateAlertData): Promise<IAlertDocument>;
19
- /**
20
- * Create a device-specific alert using AlertBuilder
21
- */
16
+ raiseSecurityAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
17
+ raiseDeviceAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
22
18
  /**
23
19
  * Create a hub-specific alert using AlertBuilder
24
20
  */
25
- raiseHubAlert(data: CreateAlertData): Promise<IAlertDocument>;
26
- /**
27
- * Raise alert for device going offline (OPERATIONAL only)
28
- */
21
+ raiseHubAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
22
+ raiseDoorLeftOpenAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
23
+ raiseNewDeviceAlert(device: {
24
+ deviceId: string;
25
+ deviceType: {
26
+ type: any;
27
+ };
28
+ propertyId: string;
29
+ name: string;
30
+ }, source: Source, description?: string): Promise<IAlertDocument | null>;
29
31
  /**
30
32
  * Raise alert for device coming online (OPERATIONAL only)
31
33
  */
32
- /**
33
- * Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
34
- */
35
- /**
36
- * Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
37
- */
34
+ raiseDeviceOnlineAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
38
35
  /**
39
36
  * Create a new alert with business logic validation
40
37
  * Accepts either a CreateAlertData object or an AlertBuilder instance
41
38
  */
42
- createAlert(alertData: CreateAlertData | AlertBuilder): Promise<IAlertDocument>;
39
+ createAlert(alertData: CreateAlertData | AlertBuilder): Promise<IAlertDocument | null>;
43
40
  /**
44
41
  * Get alert by ID with business logic
45
42
  */
@@ -77,6 +77,9 @@ const Alert_repository_1 = require("./Alert.repository");
77
77
  const Alert_model_1 = require("./Alert.model");
78
78
  const alert_types_1 = require("./alert.types");
79
79
  const AlertBuilder_1 = require("./AlertBuilder");
80
+ const constants_1 = require("../constants");
81
+ const admin_1 = require("../entities/admin");
82
+ const audit_1 = require("../audit");
80
83
  let AlertService = (() => {
81
84
  let _classDecorators = [(0, typedi_1.Service)()];
82
85
  let _classDescriptor;
@@ -92,13 +95,15 @@ let AlertService = (() => {
92
95
  async raiseOperationsAlert(data) {
93
96
  const alertBuilder = AlertBuilder_1.AlertBuilder.createOperationsAlert()
94
97
  .setPropertyId(data.propertyId)
95
- .setZoneId(data.zoneId)
98
+ .setZoneId(data.zoneId || "")
96
99
  .setTitle(data.title)
97
100
  .setDescription(data.description);
98
101
  if (data.entityId)
99
102
  alertBuilder.setEntityId(data.entityId);
100
103
  if (data.entityType)
101
104
  alertBuilder.setEntityType(data.entityType);
105
+ if (data.entitySubType)
106
+ alertBuilder.setEntitySubType(data.entitySubType);
102
107
  if (data.createdBy)
103
108
  alertBuilder.setCreatedBy(data.createdBy);
104
109
  return await this.createAlert(alertBuilder);
@@ -109,56 +114,40 @@ let AlertService = (() => {
109
114
  async raiseSecurityAlert(data) {
110
115
  const alertBuilder = AlertBuilder_1.AlertBuilder.createSecurityAlert()
111
116
  .setPropertyId(data.propertyId)
112
- .setZoneId(data.zoneId)
117
+ .setZoneId(data.zoneId || "")
113
118
  .setTitle(data.title)
114
119
  .setDescription(data.description);
115
120
  if (data.entityId)
116
121
  alertBuilder.setEntityId(data.entityId);
117
122
  if (data.entityType)
118
123
  alertBuilder.setEntityType(data.entityType);
124
+ if (data.entitySubType)
125
+ alertBuilder.setEntitySubType(data.entitySubType);
119
126
  if (data.createdBy)
120
127
  alertBuilder.setCreatedBy(data.createdBy);
121
128
  return await this.createAlert(alertBuilder);
122
129
  }
123
- /**
124
- * Create an energy alert using AlertBuilder
125
- */
126
- async raiseEnergyAlert(data) {
127
- const alertBuilder = AlertBuilder_1.AlertBuilder.createEnergyAlert()
128
- .setPropertyId(data.propertyId)
129
- .setZoneId(data.zoneId)
130
+ async raiseDeviceAlert(data) {
131
+ const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(data.entityId || "", data.propertyId, data.zoneId || "")
130
132
  .setTitle(data.title)
131
133
  .setDescription(data.description);
132
- if (data.entityId)
133
- alertBuilder.setEntityId(data.entityId);
134
- if (data.entityType)
135
- alertBuilder.setEntityType(data.entityType);
134
+ if (data.category)
135
+ alertBuilder.setCategory(data.category);
136
+ if (data.severity)
137
+ alertBuilder.setSeverity(data.severity);
138
+ if (data.type)
139
+ alertBuilder.setType(data.type);
136
140
  if (data.createdBy)
137
141
  alertBuilder.setCreatedBy(data.createdBy);
142
+ if (data.entitySubType)
143
+ alertBuilder.setEntitySubType(data.entitySubType);
138
144
  return await this.createAlert(alertBuilder);
139
145
  }
140
- /**
141
- * Create a device-specific alert using AlertBuilder
142
- */
143
- // async raiseDeviceAlert(data: CreateAlertData): Promise<IAlertDocument> {
144
- // const alertBuilder = AlertBuilder.createDeviceAlert(
145
- // data.entityId || "",
146
- // data.propertyId,
147
- // data.zoneId
148
- // )
149
- // .setTitle(data.title)
150
- // .setDescription(data.description);
151
- // if (data.category) alertBuilder.setCategory(data.category);
152
- // if (data.severity) alertBuilder.setSeverity(data.severity);
153
- // if (data.type) alertBuilder.setType(data.type);
154
- // if (data.createdBy) alertBuilder.setCreatedBy(data.createdBy);
155
- // return await this.createAlert(alertBuilder);
156
- // }
157
146
  /**
158
147
  * Create a hub-specific alert using AlertBuilder
159
148
  */
160
149
  async raiseHubAlert(data) {
161
- const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(data.entityId || "", data.propertyId, data.zoneId)
150
+ const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(data.entityId || "", data.propertyId, data.zoneId || "")
162
151
  .setTitle(data.title)
163
152
  .setDescription(data.description);
164
153
  if (data.category)
@@ -169,125 +158,138 @@ let AlertService = (() => {
169
158
  alertBuilder.setType(data.type);
170
159
  if (data.createdBy)
171
160
  alertBuilder.setCreatedBy(data.createdBy);
161
+ if (data.entitySubType)
162
+ alertBuilder.setEntitySubType(data.entitySubType);
172
163
  return await this.createAlert(alertBuilder);
173
164
  }
174
- /**
175
- * Raise alert for device going offline (OPERATIONAL only)
176
- */
177
- // async raiseDeviceOfflineAlert(
178
- // device: IDevice,
179
- // source: Source,
180
- // reason?: string
181
- // ): Promise<IAlertDocument> {
182
- // return await this.raiseDeviceAlert({
183
- // entityId: device.deviceId,
184
- // propertyId: device.propertyId,
185
- // zoneId: device.zoneId,
186
- // title: "Device Offline",
187
- // description: `Device ${device.name} has gone offline. ${
188
- // reason ? `Reason: ${reason}` : ""
189
- // }`,
190
- // category: AlertCategory.OPERATIONS,
191
- // severity: AlertSeverity.HIGH,
192
- // createdBy: source,
193
- // entityType: EntityType.DEVICE,
194
- // type: AlertType.DEVICE_OFFLINE, // Using a relevant type for device offline
195
- // });
196
- // }
165
+ async raiseDoorLeftOpenAlert(device, source, reason) {
166
+ const zone = await typedi_1.default.get(admin_1.AdminService).getZone(device.zoneId);
167
+ return await this.createAlert({
168
+ entityId: device.deviceId,
169
+ entityType: alert_types_1.EntityType.DEVICE,
170
+ entitySubType: device.deviceType.type,
171
+ propertyId: device.propertyId,
172
+ zoneId: device.zoneId,
173
+ title: "Door Left Open - Requires Attention",
174
+ description: `${zone?.name} has a door left open, for more than 10 minutes. ${reason ? `Reason: ${reason}.` : ""}`,
175
+ createdBy: source,
176
+ category: alert_types_1.AlertCategory.SECURITY,
177
+ severity: alert_types_1.AlertSeverity.HIGH,
178
+ type: alert_types_1.AlertType.DOOR_LEFT_OPEN,
179
+ });
180
+ }
181
+ async raiseNewDeviceAlert(device, source, description) {
182
+ return await this.createAlert({
183
+ entityId: device.deviceId,
184
+ entityType: alert_types_1.EntityType.DEVICE,
185
+ entitySubType: device?.deviceType?.type,
186
+ propertyId: device?.propertyId,
187
+ title: "New Device Detected",
188
+ description: description || `New device ${device?.name} has been detected.`,
189
+ createdBy: source,
190
+ category: alert_types_1.AlertCategory.OPERATIONS,
191
+ severity: alert_types_1.AlertSeverity.INFO,
192
+ type: alert_types_1.AlertType.ACCOUNT_NEW_DEVICE,
193
+ });
194
+ }
197
195
  /**
198
196
  * Raise alert for device coming online (OPERATIONAL only)
199
197
  */
200
- // async raiseDeviceOnlineAlert(
201
- // device: IDevice,
202
- // source: Source,
203
- // reason?: string
204
- // ): Promise<IAlertDocument> {
205
- // return await this.raiseDeviceAlert({
206
- // entityId: device.deviceId,
207
- // propertyId: device.propertyId,
208
- // zoneId: device.zoneId,
209
- // title: "Device Online",
210
- // description: `Device ${device.name} is now online. ${
211
- // reason ? `Reason: ${reason}` : ""
212
- // }`,
213
- // category: AlertCategory.OPERATIONS,
214
- // severity: AlertSeverity.INFO,
215
- // createdBy: source,
216
- // entityType: EntityType.DEVICE,
217
- // type: AlertType.DEVICE_ONLINE,
218
- // });
219
- // }
220
- /**
221
- * Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
222
- */
223
- // async raiseDeviceBatteryAlert(
224
- // device: IDevice,
225
- // batteryLevel: number,
226
- // threshold: number,
227
- // source: Source
228
- // ): Promise<IAlertDocument> {
229
- // return await this.raiseDeviceAlert({
230
- // entityId: device.deviceId,
231
- // propertyId: device.propertyId,
232
- // zoneId: device.zoneId,
233
- // title: "Device Battery Low",
234
- // description: `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`,
235
- // category: AlertCategory.ENERGY,
236
- // severity: AlertSeverity.HIGH,
237
- // createdBy: source,
238
- // entityType: EntityType.DEVICE,
239
- // type: AlertType.DEVICE_BATTERY_LOW,
240
- // });
241
- // }
242
- /**
243
- * Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
244
- */
245
- // async raiseDeviceIssueAlert(
246
- // device: IDevice,
247
- // issueType: string,
248
- // source: Source,
249
- // reason?: string
250
- // ): Promise<IAlertDocument> {
251
- // return await this.raiseDeviceAlert({
252
- // entityId: device.deviceId,
253
- // propertyId: device.propertyId,
254
- // zoneId: device.zoneId,
255
- // title: `Device Issue - ${issueType}`,
256
- // description: `Device ${device.name} has an issue: ${issueType}. ${
257
- // reason ? `Reason: ${reason}` : ""
258
- // }`,
259
- // category: AlertCategory.OPERATIONS,
260
- // severity: AlertSeverity.HIGH,
261
- // createdBy: source,
262
- // entityType: EntityType.DEVICE,
263
- // type: AlertType.DEVICE_ISSUE,
264
- // });
265
- // }
198
+ async raiseDeviceOnlineAlert(device, source, reason) {
199
+ return await this.raiseDeviceAlert({
200
+ entityId: device.deviceId,
201
+ propertyId: device.propertyId,
202
+ zoneId: device.zoneId,
203
+ title: "Device Online",
204
+ description: `Device ${device.name} is now online.`,
205
+ category: alert_types_1.AlertCategory.OPERATIONS,
206
+ severity: alert_types_1.AlertSeverity.INFO,
207
+ createdBy: source,
208
+ entityType: alert_types_1.EntityType.DEVICE,
209
+ entitySubType: device.deviceType.type,
210
+ type: alert_types_1.AlertType.DEVICE_ONLINE,
211
+ });
212
+ }
266
213
  /**
267
214
  * Create a new alert with business logic validation
268
215
  * Accepts either a CreateAlertData object or an AlertBuilder instance
269
216
  */
270
217
  async createAlert(alertData) {
271
- let processedAlertData;
272
- // Handle AlertBuilder instance
273
- if (alertData instanceof AlertBuilder_1.AlertBuilder) {
274
- processedAlertData = alertData.build();
275
- }
276
- else {
277
- processedAlertData = alertData;
278
- }
279
- // Business logic: Validate alert data
280
- this.validateAlertData(processedAlertData);
281
- // Business logic: Set default severity if not provided
282
- if (!processedAlertData.severity) {
283
- processedAlertData.severity = this.determineDefaultSeverity(processedAlertData.category, processedAlertData.type);
284
- }
285
- // Business logic: Validate snooze date is in the future
286
- if (processedAlertData.snoozeUntil &&
287
- processedAlertData.snoozeUntil <= new Date()) {
288
- throw new Error("Snooze date must be in the future");
218
+ try {
219
+ let processedAlertData;
220
+ // Handle AlertBuilder instance
221
+ if (alertData instanceof AlertBuilder_1.AlertBuilder) {
222
+ processedAlertData = alertData.build();
223
+ }
224
+ else {
225
+ processedAlertData = alertData;
226
+ }
227
+ // Business logic: Validate alert data
228
+ this.validateAlertData(processedAlertData);
229
+ // Business logic: Set default severity if not provided
230
+ if (!processedAlertData.severity) {
231
+ processedAlertData.severity = this.determineDefaultSeverity(processedAlertData.category, processedAlertData.type);
232
+ }
233
+ // Business logic: Validate snooze date is in the future
234
+ if (processedAlertData.snoozeUntil &&
235
+ processedAlertData.snoozeUntil <= new Date()) {
236
+ throw new Error("Snooze date must be in the future");
237
+ }
238
+ const existingAlert = await this.queryAlerts({
239
+ propertyId: processedAlertData.propertyId,
240
+ zoneId: processedAlertData.zoneId,
241
+ entityId: processedAlertData.entityId,
242
+ entityType: processedAlertData.entityType,
243
+ entitySubType: processedAlertData.entitySubType,
244
+ });
245
+ if (existingAlert.length > 0) {
246
+ await (0, audit_1.pushAudit)({
247
+ auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SKIPPED,
248
+ auditData: {
249
+ reason: "Alert already exists",
250
+ resource: audit_1.Resource.ALERT,
251
+ source: processedAlertData.createdBy,
252
+ propertyId: processedAlertData.propertyId,
253
+ entityId: processedAlertData.entityId,
254
+ entityType: processedAlertData.entityType,
255
+ entitySubType: processedAlertData.entitySubType,
256
+ },
257
+ });
258
+ return null;
259
+ }
260
+ const alert = await this.alertRepository.create(processedAlertData);
261
+ await (0, audit_1.pushAudit)({
262
+ auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.SUCCESS,
263
+ auditData: {
264
+ resource: audit_1.Resource.ALERT,
265
+ source: constants_1.Source.USER,
266
+ propertyId: processedAlertData.propertyId,
267
+ zoneId: processedAlertData.zoneId,
268
+ entityId: processedAlertData.entityId,
269
+ entityType: processedAlertData.entityType,
270
+ entitySubType: processedAlertData.entitySubType,
271
+ type: processedAlertData.type,
272
+ createdBy: processedAlertData.createdBy,
273
+ createdAt: new Date(),
274
+ },
275
+ });
276
+ return alert;
277
+ }
278
+ catch (error) {
279
+ await (0, audit_1.pushAudit)({
280
+ auditType: constants_1.DT_EVENT_TYPES.ALERT.CREATE.FAILED,
281
+ auditData: {
282
+ resource: audit_1.Resource.ALERT,
283
+ source: constants_1.Source.USER,
284
+ propertyId: alertData?.propertyId || "",
285
+ zoneId: alertData?.zoneId || "",
286
+ errorMessage: error.message,
287
+ error: error,
288
+ createdBy: alertData?.createdBy || "",
289
+ },
290
+ });
291
+ throw error;
289
292
  }
290
- return await this.alertRepository.create(processedAlertData);
291
293
  }
292
294
  /**
293
295
  * Get alert by ID with business logic
@@ -1,3 +1,4 @@
1
+ import { EntitySubType } from "../issues";
1
2
  import { CreateAlertData, AlertCategory, AlertSeverity, EntityType, AlertType } from "./alert.types";
2
3
  /**
3
4
  * AlertBuilder - A builder pattern implementation for constructing CreateAlertData objects
@@ -48,6 +49,10 @@ export declare class AlertBuilder {
48
49
  * Sets the entity type
49
50
  */
50
51
  setEntityType(entityType: EntityType): this;
52
+ /**
53
+ * Sets the entity sub type
54
+ */
55
+ setEntitySubType(entitySubType: EntitySubType): this;
51
56
  /**
52
57
  * Sets the alert severity (optional, defaults to LOW)
53
58
  */
@@ -88,6 +88,13 @@ class AlertBuilder {
88
88
  this.data.entityType = entityType;
89
89
  return this;
90
90
  }
91
+ /**
92
+ * Sets the entity sub type
93
+ */
94
+ setEntitySubType(entitySubType) {
95
+ this.data.entitySubType = entitySubType;
96
+ return this;
97
+ }
91
98
  /**
92
99
  * Sets the alert severity (optional, defaults to LOW)
93
100
  */
@@ -1,4 +1,4 @@
1
- import { EntityType } from "../issues/issue.types";
1
+ import { EntitySubType, EntityType } from "../issues/issue.types";
2
2
  export declare enum AlertCategory {
3
3
  OPERATIONS = "OPERATIONS",
4
4
  SECURITY = "SECURITY",
@@ -20,18 +20,20 @@ export declare enum AlertType {
20
20
  LOCK_ACCESS_EMERGENCY_CODE = "LOCK_ACCESS_EMERGENCY_CODE",
21
21
  LOCK_ACCESS_MASTER_CODE = "LOCK_ACCESS_MASTER_CODE",
22
22
  SPECIFIC_DOOR_ACCESS = "SPECIFIC_DOOR_ACCESS",
23
- GUEST_LOCK_FIRST_ACCESS = "GUEST_LOCK_FIRST_ACCESS"
23
+ GUEST_LOCK_FIRST_ACCESS = "GUEST_LOCK_FIRST_ACCESS",
24
+ DEVICE_ONLINE = "DEVICE_ONLINE"
24
25
  }
25
26
  export interface AlertDocument {
26
27
  _id: string;
27
28
  category: AlertCategory;
28
29
  propertyId: string;
29
- zoneId: string;
30
+ zoneId?: string;
30
31
  type: AlertType;
31
32
  title: string;
32
33
  description: string;
33
34
  entityId?: string;
34
35
  entityType: EntityType;
36
+ entitySubType: EntitySubType;
35
37
  severity: AlertSeverity;
36
38
  isRead: boolean;
37
39
  isActive: boolean;
@@ -45,11 +47,12 @@ export interface AlertDocument {
45
47
  export interface CreateAlertData {
46
48
  category: AlertCategory;
47
49
  propertyId: string;
48
- zoneId: string;
50
+ zoneId?: string;
49
51
  title: string;
50
52
  description: string;
51
53
  entityId?: string;
52
54
  entityType: EntityType;
55
+ entitySubType: EntitySubType;
53
56
  severity?: AlertSeverity;
54
57
  type?: AlertType;
55
58
  createdBy?: string;
@@ -59,8 +62,10 @@ export interface UpdateAlertData {
59
62
  category?: AlertCategory;
60
63
  title?: string;
61
64
  description?: string;
65
+ zoneId?: string;
62
66
  entityId?: string;
63
67
  entityType?: EntityType;
68
+ entitySubType?: EntitySubType;
64
69
  severity?: AlertSeverity;
65
70
  type?: AlertType;
66
71
  isRead?: boolean;
@@ -74,6 +79,7 @@ export interface IAlertQuery {
74
79
  category?: AlertCategory;
75
80
  severity?: AlertSeverity;
76
81
  entityType?: EntityType;
82
+ entitySubType?: EntitySubType;
77
83
  entityId?: string;
78
84
  type?: AlertType | AlertType[];
79
85
  isActive?: boolean;
@@ -26,6 +26,7 @@ var AlertType;
26
26
  AlertType["LOCK_ACCESS_MASTER_CODE"] = "LOCK_ACCESS_MASTER_CODE";
27
27
  AlertType["SPECIFIC_DOOR_ACCESS"] = "SPECIFIC_DOOR_ACCESS";
28
28
  AlertType["GUEST_LOCK_FIRST_ACCESS"] = "GUEST_LOCK_FIRST_ACCESS";
29
+ AlertType["DEVICE_ONLINE"] = "DEVICE_ONLINE";
29
30
  })(AlertType || (exports.AlertType = AlertType = {}));
30
31
  // Re-export EntityType from issue.types.ts to avoid duplication
31
32
  var issue_types_1 = require("../issues/issue.types");
@@ -5,6 +5,7 @@ export declare function getConfig(): IConfig;
5
5
  export declare function getDeviceServiceUrl(): string;
6
6
  export declare function getAdminServiceUrl(): string;
7
7
  export declare function getSqsQueueUrl(): string;
8
+ export declare function getReservationSqsQueueUrl(): string;
8
9
  export declare function getEventSubscription(): InternalEventSubscription | null;
9
10
  export declare function checkRequiredEnv(requiredEnvs: string[]): void;
10
11
  export declare function ensureAuditInitialized(): void;
@@ -8,6 +8,7 @@ exports.getConfig = getConfig;
8
8
  exports.getDeviceServiceUrl = getDeviceServiceUrl;
9
9
  exports.getAdminServiceUrl = getAdminServiceUrl;
10
10
  exports.getSqsQueueUrl = getSqsQueueUrl;
11
+ exports.getReservationSqsQueueUrl = getReservationSqsQueueUrl;
11
12
  exports.getEventSubscription = getEventSubscription;
12
13
  exports.checkRequiredEnv = checkRequiredEnv;
13
14
  exports.ensureAuditInitialized = ensureAuditInitialized;
@@ -149,6 +150,17 @@ function getSqsQueueUrl() {
149
150
  }
150
151
  throw new Error("dt-common-device: AWS_SQS_URL is not configured for this service");
151
152
  }
153
+ function getReservationSqsQueueUrl() {
154
+ if (constants_1.CONFIG_KEYS[sourceKey].env.includes("RESERVATION_SQS_URL")) {
155
+ const reservationSqsQueueUrl = process.env.RESERVATION_SQS_URL;
156
+ if (!reservationSqsQueueUrl) {
157
+ getConfig().LOGGER.error("RESERVATION_SQS_URL must be set in environment variables");
158
+ throw new Error("dt-common-device: RESERVATION_SQS_URL must be set in environment variables");
159
+ }
160
+ return reservationSqsQueueUrl;
161
+ }
162
+ return "";
163
+ }
152
164
  function getEventSubscription() {
153
165
  return eventSubscription;
154
166
  }
@@ -17,7 +17,13 @@ exports.REQUIRED = {
17
17
  };
18
18
  exports.CONFIG_KEYS = {
19
19
  ACCESS: {
20
- env: ["ADMIN_DB_URI", "PMS_DB_URI", "AWS_SQS_URL", "ADMIN_SERVICE"],
20
+ env: [
21
+ "ADMIN_DB_URI",
22
+ "PMS_DB_URI",
23
+ "AWS_SQS_URL",
24
+ "RESERVATION_SQS_URL",
25
+ "ADMIN_SERVICE",
26
+ ],
21
27
  INTERNAL_EVENT_HANDLER: true,
22
28
  db_keys: {
23
29
  access: "DATABASE_URL",
@@ -29,7 +29,6 @@ export declare class LocalDeviceService {
29
29
  private shouldUpdateBatteryLevel;
30
30
  updateBatteryState(deviceId: string, batteryState: any): Promise<void>;
31
31
  private getPropertyBatteryThreshold;
32
- private checkForDeviceMalfunctions;
33
32
  getMetaData(deviceId: string): Promise<any>;
34
33
  setMetaData(deviceId: string, metaData: Record<string, any>, auditBody: IAuditProperties): Promise<any>;
35
34
  getDevicesByZone(zoneId: string): Promise<import("../interfaces").IDtDevice[]>;
@@ -358,32 +358,21 @@ let LocalDeviceService = (() => {
358
358
  await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
359
359
  await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel, auditBody);
360
360
  if (oldBatteryLevel?.value < batteryLevel &&
361
- batteryLevel - oldBatteryLevel?.value > 10) {
362
- // Battery level has increased (considering as battery has been replaced)
363
- await this.eventHandler.onBatteryReplaced(deviceId, batteryLevel, auditBody);
364
- }
365
- // Additional condition: if battery level is less than 50, update battery state to "replace"
366
- if (batteryLevel < 50) {
361
+ batteryLevel - oldBatteryLevel?.value > 50) {
362
+ // Battery level has increased more than 50% (considering as battery has been replaced)
367
363
  const batteryState = {
368
364
  batteryState: {
369
- value: "replace",
365
+ value: "replaced",
370
366
  lastUpdated: new Date().toISOString(),
371
367
  },
372
368
  };
373
369
  await this.updateBatteryState(deviceId, batteryState);
374
- await this.eventHandler.onBatteryStateChange(deviceId, batteryState, auditBody);
370
+ await this.eventHandler.onBatteryReplaced(deviceId, batteryLevel, auditBody);
375
371
  }
376
372
  // Get property threshold
377
373
  const propertyThreshold = await this.getPropertyBatteryThreshold(device.propertyId);
378
374
  // Check if battery level is below threshold
379
375
  if (batteryLevel < propertyThreshold) {
380
- // Raise alert
381
- // await this.alertService.raiseDeviceBatteryAlert(
382
- // device,
383
- // batteryLevel,
384
- // propertyThreshold,
385
- // source
386
- // );
387
376
  // Raise issue when the level is below threshold
388
377
  await this.issueService.createDeviceBatteryIssue(device, batteryLevel, propertyThreshold, issue_types_1.IssuePriority.CRITICAL, source);
389
378
  }
@@ -415,37 +404,6 @@ let LocalDeviceService = (() => {
415
404
  }
416
405
  return preferences?.settings?.batteryPreference?.value ?? 20;
417
406
  }
418
- async checkForDeviceMalfunctions(device, source, reason) {
419
- // TODO: Implement device malfunction detection logic
420
- // This should check for:
421
- // - Lock jammed
422
- // - Device not accepting codes
423
- // - Other malfunction indicators
424
- // For now, we'll check if the reason indicates a malfunction
425
- const malfunctionIndicators = [
426
- "jammed",
427
- "not accepting codes",
428
- "malfunction",
429
- "error",
430
- "failure",
431
- ];
432
- const hasMalfunction = malfunctionIndicators.some((indicator) => reason?.toLowerCase().includes(indicator));
433
- // if (hasMalfunction) {
434
- // // Raise alert for device malfunction (READINESS + OPERATIONAL)
435
- // await this.alertService.raiseDeviceIssueAlert(
436
- // device,
437
- // "Device Malfunction Detected",
438
- // source,
439
- // reason
440
- // );
441
- // // Raise issue for device malfunction (READINESS + OPERATIONAL)
442
- // await this.issueService.createDeviceMalfunctionIssue(
443
- // device,
444
- // source,
445
- // reason
446
- // );
447
- // }
448
- }
449
407
  async getMetaData(deviceId) {
450
408
  if (!deviceId) {
451
409
  throw new Error("Device ID is required");
@@ -9,7 +9,6 @@ export declare class EventHandler {
9
9
  onStatusChange(deviceId: string, status: any, auditProperties: IAuditProperties, eventType: any): Promise<void>;
10
10
  onStatusChangeMany(query: IStatusQuery, status: IStatus, auditProperties: IAuditProperties, eventType: any): Promise<void>;
11
11
  onBatteryLevelChange(deviceId: string, batteryLevel: number, auditProperties: IAuditProperties): Promise<void>;
12
- onBatteryStateChange(deviceId: string, batteryState: any, auditProperties: IAuditProperties): Promise<void>;
13
12
  onBatteryReplaced(deviceId: string, batteryLevel: number, auditProperties: IAuditProperties): Promise<void>;
14
13
  onDeviceMetaChange(deviceId: string, metaData: Record<string, any>, auditProperties: IAuditProperties): Promise<void>;
15
14
  }
@@ -125,16 +125,6 @@ let EventHandler = (() => {
125
125
  },
126
126
  });
127
127
  }
128
- async onBatteryStateChange(deviceId, batteryState, auditProperties) {
129
- await (0, audit_1.pushAudit)({
130
- auditType: Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.STATE.REPLACE,
131
- auditData: {
132
- deviceId,
133
- batteryState,
134
- ...auditProperties,
135
- },
136
- });
137
- }
138
128
  async onBatteryReplaced(deviceId, batteryLevel, auditProperties) {
139
129
  await (0, audit_1.pushAudit)({
140
130
  auditType: Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.REPLACED,
@@ -9,6 +9,7 @@ export declare enum InternalEventType {
9
9
  export declare class InternalEventSubscription {
10
10
  private readonly internalEventHandler;
11
11
  private readonly sqsQueueUrl;
12
+ private readonly reservationSqsQueueUrl;
12
13
  private readonly logger;
13
14
  private readonly isInitialized;
14
15
  private isSubscribed;
@@ -18,6 +18,7 @@ class InternalEventSubscription {
18
18
  this.isInitialized = false;
19
19
  this.isSubscribed = false;
20
20
  this.sqsQueueUrl = (0, config_1.getSqsQueueUrl)() || "";
21
+ this.reservationSqsQueueUrl = (0, config_1.getReservationSqsQueueUrl)() || "";
21
22
  this.logger = (0, config_1.getConfig)().LOGGER;
22
23
  this.isInitialized = true;
23
24
  }
@@ -85,6 +86,9 @@ class InternalEventSubscription {
85
86
  return;
86
87
  }
87
88
  try {
89
+ if (this.reservationSqsQueueUrl) {
90
+ await dt_pub_sub_1.eventDispatcher.subscribeToQueue(this.reservationSqsQueueUrl, this.handleMessage.bind(this));
91
+ }
88
92
  await dt_pub_sub_1.eventDispatcher.subscribeToQueue(this.sqsQueueUrl, this.handleMessage.bind(this));
89
93
  this.isSubscribed = true;
90
94
  this.logger.info("Successfully subscribed to internal events", {
@@ -1,5 +1,5 @@
1
1
  import { IIssueDocument } from "./Issue.model";
2
- import { CreateIssueData, UpdateIssueData, AddCommentData, IssuePriority, IssuesCategory, EntityType, IIssueQuery, IssueType } from "./issue.types";
2
+ import { CreateIssueData, UpdateIssueData, AddCommentData, IssuePriority, IssuesCategory, EntityType, EntitySubType, IIssueQuery, IssueType } from "./issue.types";
3
3
  import { IssueBuilder } from "./IssueBuilder";
4
4
  import { Source } from "../constants/Service";
5
5
  import { IDevice } from "../entities/device/local/interfaces";
@@ -43,10 +43,25 @@ export declare class IssueService {
43
43
  * Create issue for device going offline longer than baseline
44
44
  */
45
45
  createDeviceOfflineIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument | null>;
46
+ createHubOfflineIssue(hub: IDevice, source: Source, reason?: string): Promise<IIssueDocument | null>;
46
47
  /**
47
48
  * Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
48
49
  */
49
50
  createDeviceBatteryIssue(device: IDevice, batteryLevel: number, threshold: number, priority: IssuePriority, source: Source): Promise<IIssueDocument | null>;
51
+ createAccountMissingDeviceIssue(device: {
52
+ deviceId: string;
53
+ deviceType: {
54
+ type: any;
55
+ };
56
+ propertyId: string;
57
+ name: string;
58
+ }, source: Source, reason?: string): Promise<IIssueDocument | null>;
59
+ createAccountUnauthorizedIssue(account: {
60
+ accountId: string;
61
+ accountType: EntitySubType;
62
+ propertyId: string;
63
+ name: string;
64
+ }, source: Source, reason?: string): Promise<IIssueDocument | null>;
50
65
  /**
51
66
  * Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
52
67
  */
@@ -251,30 +251,21 @@ let IssueService = (() => {
251
251
  type: issue_types_1.IssueType.DEVICE_OFFLINE,
252
252
  });
253
253
  }
254
- // async createDoorLeftOpenIssue(
255
- // device: IDevice,
256
- // source: Source,
257
- // reason?: string
258
- // ): Promise<IIssueDocument | null> {
259
- // const zone = await Container.get(AdminService).getZone(device.zoneId);
260
- // return await this.createDeviceIssue({
261
- // entityId: device.deviceId,
262
- // entityType: EntityType.DEVICE,
263
- // entitySubType: device.deviceType.type as EntitySubType,
264
- // propertyId: device.propertyId,
265
- // zoneId: device.zoneId,
266
- // title: "Door Left Open - Requires Attention",
267
- // description: `${
268
- // zone?.name
269
- // } has a door left open, for more than 10 minutes. ${
270
- // reason ? `Reason: ${reason}.` : ""
271
- // }`,
272
- // createdBy: source,
273
- // category: IssuesCategory.SECURITY,
274
- // priority: IssuePriority.HIGH,
275
- // type: IssueType.DOOR_LEFT_OPEN,
276
- // });
277
- // }
254
+ async createHubOfflineIssue(hub, source, reason) {
255
+ return await this.createHubIssue({
256
+ entityId: hub.deviceId,
257
+ entityType: issue_types_1.EntityType.DEVICE,
258
+ entitySubType: hub.deviceType.type,
259
+ propertyId: hub.propertyId,
260
+ zoneId: hub.zoneId,
261
+ title: "Hub Offline - Requires Attention",
262
+ description: `${hub.name} has gone offline. ${reason ? `Reason: ${reason}.` : ""}`,
263
+ createdBy: source,
264
+ category: issue_types_1.IssuesCategory.OPERATIONS,
265
+ priority: issue_types_1.IssuePriority.CRITICAL,
266
+ type: issue_types_1.IssueType.HUB_OFFLINE,
267
+ });
268
+ }
278
269
  /**
279
270
  * Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
280
271
  */
@@ -293,6 +284,34 @@ let IssueService = (() => {
293
284
  type: issue_types_1.IssueType.BATTERY_LOW,
294
285
  });
295
286
  }
287
+ async createAccountMissingDeviceIssue(device, source, reason) {
288
+ return await this.createIssue({
289
+ entityId: device.deviceId,
290
+ entityType: issue_types_1.EntityType.DEVICE,
291
+ entitySubType: device.deviceType.type,
292
+ propertyId: device.propertyId,
293
+ title: "Device Missing - Requires Attention",
294
+ description: `${device.name} is missing from the account. ${reason ? `Reason: ${reason}.` : ""}`,
295
+ createdBy: source,
296
+ category: issue_types_1.IssuesCategory.OPERATIONS,
297
+ priority: issue_types_1.IssuePriority.CRITICAL,
298
+ type: issue_types_1.IssueType.ACCOUNT_MISSING_DEVICE,
299
+ });
300
+ }
301
+ async createAccountUnauthorizedIssue(account, source, reason) {
302
+ return await this.createIssue({
303
+ entityId: account.accountId,
304
+ entityType: issue_types_1.EntityType.CLOUD_DEVICE_ACCOUNT,
305
+ entitySubType: account.accountType,
306
+ propertyId: account.propertyId,
307
+ title: "Account re-authorization required",
308
+ description: `${account.name}'s authorization has expired. Please re-authorize the account. ${reason ? `Reason: ${reason}.` : ""}`,
309
+ createdBy: source,
310
+ category: issue_types_1.IssuesCategory.OPERATIONS,
311
+ priority: issue_types_1.IssuePriority.CRITICAL,
312
+ type: issue_types_1.IssueType.ACCOUNT_UNAUTHORIZED,
313
+ });
314
+ }
296
315
  /**
297
316
  * Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
298
317
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "7.3.0",
3
+ "version": "7.5.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [