dt-common-device 7.5.0 → 7.6.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.
@@ -3,6 +3,7 @@ import { CreateAlertData, UpdateAlertData, AlertCategory, AlertSeverity, IAlertQ
3
3
  import { AlertBuilder } from "./AlertBuilder";
4
4
  import { IDevice } from "../entities/device/local/interfaces";
5
5
  import { Source } from "../constants";
6
+ import { IUser } from "../entities/admin";
6
7
  export declare class AlertService {
7
8
  private readonly alertRepository;
8
9
  constructor();
@@ -19,7 +20,7 @@ export declare class AlertService {
19
20
  * Create a hub-specific alert using AlertBuilder
20
21
  */
21
22
  raiseHubAlert(data: CreateAlertData): Promise<IAlertDocument | null>;
22
- raiseDoorLeftOpenAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
23
+ raiseDoorLeftOpenAlert(device: IDevice, zone: any, openThreshold: number, source: Source): Promise<IAlertDocument | null>;
23
24
  raiseNewDeviceAlert(device: {
24
25
  deviceId: string;
25
26
  deviceType: {
@@ -28,10 +29,16 @@ export declare class AlertService {
28
29
  propertyId: string;
29
30
  name: string;
30
31
  }, source: Source, description?: string): Promise<IAlertDocument | null>;
32
+ raiseDoorOpenFrequentAlert(device: IDevice, zone: any, accessTimes: number, openThreshold: number, source: Source): Promise<IAlertDocument | null>;
33
+ raiseDoorOpenOutsideBusinessHoursAlert(device: IDevice, zone: any, source: Source): Promise<IAlertDocument | null>;
31
34
  /**
32
35
  * Raise alert for device coming online (OPERATIONAL only)
33
36
  */
34
- raiseDeviceOnlineAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument | null>;
37
+ raiseDeviceOnlineAlert(device: IDevice, source: Source): Promise<IAlertDocument | null>;
38
+ raiseLockAccessEmergencyCodeAlert(device: IDevice, zone: any, source: Source): Promise<IAlertDocument | null>;
39
+ raiseLockAccessMasterCodeAlert(device: IDevice, zone: any, source: Source): Promise<IAlertDocument | null>;
40
+ raiseSpecificDoorAccessAlert(user: IUser, device: IDevice, zone: any, source: Source): Promise<IAlertDocument | null>;
41
+ raiseGuestLockFirstAccessAlert(user: IUser, device: IDevice, zone: any, source: Source): Promise<IAlertDocument | null>;
35
42
  /**
36
43
  * Create a new alert with business logic validation
37
44
  * Accepts either a CreateAlertData object or an AlertBuilder instance
@@ -78,7 +78,6 @@ const Alert_model_1 = require("./Alert.model");
78
78
  const alert_types_1 = require("./alert.types");
79
79
  const AlertBuilder_1 = require("./AlertBuilder");
80
80
  const constants_1 = require("../constants");
81
- const admin_1 = require("../entities/admin");
82
81
  const audit_1 = require("../audit");
83
82
  let AlertService = (() => {
84
83
  let _classDecorators = [(0, typedi_1.Service)()];
@@ -162,19 +161,18 @@ let AlertService = (() => {
162
161
  alertBuilder.setEntitySubType(data.entitySubType);
163
162
  return await this.createAlert(alertBuilder);
164
163
  }
165
- async raiseDoorLeftOpenAlert(device, source, reason) {
166
- const zone = await typedi_1.default.get(admin_1.AdminService).getZone(device.zoneId);
164
+ async raiseDoorLeftOpenAlert(device, zone, openThreshold, source) {
167
165
  return await this.createAlert({
168
166
  entityId: device.deviceId,
169
167
  entityType: alert_types_1.EntityType.DEVICE,
170
168
  entitySubType: device.deviceType.type,
171
169
  propertyId: device.propertyId,
172
170
  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}.` : ""}`,
171
+ title: "Door Left Open",
172
+ description: `${zone?.name} has a door left open, for more than ${openThreshold} minutes.`,
175
173
  createdBy: source,
176
174
  category: alert_types_1.AlertCategory.SECURITY,
177
- severity: alert_types_1.AlertSeverity.HIGH,
175
+ severity: alert_types_1.AlertSeverity.CRITICAL,
178
176
  type: alert_types_1.AlertType.DOOR_LEFT_OPEN,
179
177
  });
180
178
  }
@@ -192,10 +190,40 @@ let AlertService = (() => {
192
190
  type: alert_types_1.AlertType.ACCOUNT_NEW_DEVICE,
193
191
  });
194
192
  }
193
+ async raiseDoorOpenFrequentAlert(device, zone, accessTimes, openThreshold, source) {
194
+ return await this.createAlert({
195
+ entityId: device.deviceId,
196
+ entityType: alert_types_1.EntityType.DEVICE,
197
+ entitySubType: device.deviceType.type,
198
+ propertyId: device.propertyId,
199
+ zoneId: device.zoneId,
200
+ title: "Door Open Frequently",
201
+ description: `${zone?.name} has been opened ${accessTimes} times in the last ${openThreshold} minutes.`,
202
+ createdBy: source,
203
+ category: alert_types_1.AlertCategory.OPERATIONS,
204
+ severity: alert_types_1.AlertSeverity.HIGH,
205
+ type: alert_types_1.AlertType.DOOR_OPEN_FREQUENT,
206
+ });
207
+ }
208
+ async raiseDoorOpenOutsideBusinessHoursAlert(device, zone, source) {
209
+ return await this.createAlert({
210
+ entityId: device.deviceId,
211
+ entityType: alert_types_1.EntityType.DEVICE,
212
+ entitySubType: device.deviceType.type,
213
+ propertyId: device.propertyId,
214
+ zoneId: device.zoneId,
215
+ title: "Door Open Outside Business Hours",
216
+ description: `${zone?.name} has been opened outside business hours.`,
217
+ createdBy: source,
218
+ category: alert_types_1.AlertCategory.SECURITY,
219
+ severity: alert_types_1.AlertSeverity.HIGH,
220
+ type: alert_types_1.AlertType.DOOR_OPEN_OUTSIDE_BIZ_HOURS,
221
+ });
222
+ }
195
223
  /**
196
224
  * Raise alert for device coming online (OPERATIONAL only)
197
225
  */
198
- async raiseDeviceOnlineAlert(device, source, reason) {
226
+ async raiseDeviceOnlineAlert(device, source) {
199
227
  return await this.raiseDeviceAlert({
200
228
  entityId: device.deviceId,
201
229
  propertyId: device.propertyId,
@@ -210,6 +238,66 @@ let AlertService = (() => {
210
238
  type: alert_types_1.AlertType.DEVICE_ONLINE,
211
239
  });
212
240
  }
241
+ async raiseLockAccessEmergencyCodeAlert(device, zone, source) {
242
+ return await this.createAlert({
243
+ entityId: device.deviceId,
244
+ entityType: alert_types_1.EntityType.DEVICE,
245
+ entitySubType: device.deviceType.type,
246
+ propertyId: device.propertyId,
247
+ zoneId: device.zoneId,
248
+ title: "Emergency Code Used",
249
+ description: `${zone?.name} has been accessed using the emergency code.`,
250
+ createdBy: source,
251
+ category: alert_types_1.AlertCategory.SECURITY,
252
+ severity: alert_types_1.AlertSeverity.HIGH,
253
+ type: alert_types_1.AlertType.LOCK_ACCESS_EMERGENCY_CODE,
254
+ });
255
+ }
256
+ async raiseLockAccessMasterCodeAlert(device, zone, source) {
257
+ return await this.createAlert({
258
+ entityId: device.deviceId,
259
+ entityType: alert_types_1.EntityType.DEVICE,
260
+ entitySubType: device.deviceType.type,
261
+ propertyId: device.propertyId,
262
+ zoneId: device.zoneId,
263
+ title: "Master Code Used",
264
+ description: `${zone?.name} has been accessed using the master code.`,
265
+ createdBy: source,
266
+ category: alert_types_1.AlertCategory.SECURITY,
267
+ severity: alert_types_1.AlertSeverity.HIGH,
268
+ type: alert_types_1.AlertType.LOCK_ACCESS_MASTER_CODE,
269
+ });
270
+ }
271
+ async raiseSpecificDoorAccessAlert(user, device, zone, source) {
272
+ return await this.createAlert({
273
+ entityId: device.deviceId,
274
+ entityType: alert_types_1.EntityType.DEVICE,
275
+ entitySubType: device.deviceType.type,
276
+ propertyId: device.propertyId,
277
+ zoneId: device.zoneId,
278
+ title: "Specific Door Access",
279
+ description: `${user?.firstName} ${user?.lastName} has accessed ${zone?.name}.`,
280
+ createdBy: source,
281
+ category: alert_types_1.AlertCategory.OTHER,
282
+ severity: alert_types_1.AlertSeverity.INFO,
283
+ type: alert_types_1.AlertType.SPECIFIC_DOOR_ACCESS,
284
+ });
285
+ }
286
+ async raiseGuestLockFirstAccessAlert(user, device, zone, source) {
287
+ return await this.createAlert({
288
+ entityId: device.deviceId,
289
+ entityType: alert_types_1.EntityType.DEVICE,
290
+ entitySubType: device.deviceType.type,
291
+ propertyId: device.propertyId,
292
+ zoneId: device.zoneId,
293
+ title: "Guest Used Code for First Time",
294
+ description: `${user?.firstName} ${user?.lastName} has used the code for the first time to access ${zone?.name}.`,
295
+ createdBy: source,
296
+ category: alert_types_1.AlertCategory.OTHER,
297
+ severity: alert_types_1.AlertSeverity.INFO,
298
+ type: alert_types_1.AlertType.GUEST_LOCK_FIRST_ACCESS,
299
+ });
300
+ }
213
301
  /**
214
302
  * Create a new alert with business logic validation
215
303
  * Accepts either a CreateAlertData object or an AlertBuilder instance
@@ -13,5 +13,6 @@ export declare enum Source {
13
13
  CLOUD_WEBHOOK = "cloud-webhook",
14
14
  HEARTBEAT = "heartbeat",
15
15
  CODE_ACTION = "code-action",
16
- DEVICE_ACTION = "device-action"
16
+ DEVICE_ACTION = "device-action",
17
+ SYSTEM = "system"
17
18
  }
@@ -17,4 +17,5 @@ var Source;
17
17
  Source["HEARTBEAT"] = "heartbeat";
18
18
  Source["CODE_ACTION"] = "code-action";
19
19
  Source["DEVICE_ACTION"] = "device-action";
20
+ Source["SYSTEM"] = "system";
20
21
  })(Source || (exports.Source = Source = {}));
@@ -223,7 +223,13 @@ let AdminRepository = (() => {
223
223
  try {
224
224
  const zone = await this.postgres.query(`SELECT * FROM dt_zones WHERE "id" = $1`, [zoneId]);
225
225
  if (zone.rows.length > 0) {
226
- return zone.rows[0];
226
+ const zoneData = zone.rows[0];
227
+ const zoneType = await this.postgres.query(`SELECT * FROM dt_zoneTypes WHERE "id" = $1`, [zoneData.zoneTypeId]);
228
+ zoneData.zoneType = {
229
+ id: zoneType.rows[0].id,
230
+ name: zoneType.rows[0].name,
231
+ };
232
+ return zoneData;
227
233
  }
228
234
  return null;
229
235
  }
@@ -74,7 +74,7 @@ export interface IQueryDevice {
74
74
  deviceIds?: string[];
75
75
  propertyId?: string;
76
76
  hubId?: string;
77
- deviceType?: string;
77
+ deviceType?: string | string[];
78
78
  excludeDeviceType?: string | string[];
79
79
  connectionId?: string;
80
80
  }
@@ -11,7 +11,6 @@ export declare class DeviceRepository {
11
11
  deleteDevice(deviceId: string): Promise<void>;
12
12
  getDevices(deviceIds: string[], withHubDetails?: boolean): Promise<IDevice[]>;
13
13
  getPropertyDevices(propertyId: string, selectDeviceId?: boolean, type?: string, withHubDetails?: boolean): Promise<IDevice[]>;
14
- getPropertyDeviceIds(propertyId: string, selectDeviceId: boolean | undefined, manufacturer: string): Promise<any>;
15
14
  getState(deviceId: string): Promise<any>;
16
15
  setState(deviceId: string, state: any): Promise<any>;
17
16
  getStatus(deviceId: string): Promise<Record<string, any>>;
@@ -129,18 +129,6 @@ let DeviceRepository = (() => {
129
129
  throw new Error(`Failed to get property devices: ${error.message || "Unknown error"}`);
130
130
  }
131
131
  }
132
- async getPropertyDeviceIds(propertyId, selectDeviceId = false, manufacturer) {
133
- try {
134
- const response = await this.axiosInstance.get(`/devices`, {
135
- params: { propertyId, selectDeviceId, manufacturer },
136
- });
137
- return response.data;
138
- }
139
- catch (error) {
140
- (0, config_1.getConfig)().LOGGER.error(`Failed to get property device IDs for ${propertyId}:`, error);
141
- throw new Error(`Failed to get property device IDs: ${error.message || "Unknown error"}`);
142
- }
143
- }
144
132
  async getState(deviceId) {
145
133
  try {
146
134
  const response = await this.axiosInstance.get(`/devices/${deviceId}/state`);
@@ -12,7 +12,6 @@ export declare class LocalDeviceService {
12
12
  getDevice(deviceId: string, withHubDetails?: boolean): Promise<IDevice>;
13
13
  getDevices(deviceIds: string[], withHubDetails?: boolean): Promise<IDevice[]>;
14
14
  getPropertyDevices(propertyId: string, selectDeviceId?: boolean, type?: string, withHubDetails?: boolean): Promise<IDevice[]>;
15
- getPropertyDeviceIds(propertyId: string, selectDeviceId: boolean | undefined, type: string): Promise<any>;
16
15
  updateDevice(deviceId: string, body: Partial<IDevice>, auditBody: IAuditProperties): Promise<any>;
17
16
  updateDevices(query: any, updateData: any): Promise<any>;
18
17
  deleteDevice(deviceId: string, auditBody: IAuditProperties): Promise<any>;
@@ -121,12 +121,6 @@ let LocalDeviceService = (() => {
121
121
  }
122
122
  return await this.deviceRepository.getPropertyDevices(propertyId, selectDeviceId, type, withHubDetails);
123
123
  }
124
- async getPropertyDeviceIds(propertyId, selectDeviceId = false, type) {
125
- if (!propertyId) {
126
- throw new Error("Property ID is required");
127
- }
128
- return await this.deviceRepository.getPropertyDeviceIds(propertyId, selectDeviceId, type);
129
- }
130
124
  async updateDevice(deviceId, body, auditBody) {
131
125
  if (!deviceId) {
132
126
  throw new Error("Device ID is required");
@@ -139,6 +133,13 @@ let LocalDeviceService = (() => {
139
133
  const auditType = body?.status?.online
140
134
  ? constants_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE
141
135
  : constants_1.DT_EVENT_TYPES.DEVICE.STATUS.OFFLINE;
136
+ if (body?.status?.online) {
137
+ await this.handleOnlineStatus(device, device.status, body.status, auditBody?.source || Service_1.Source.SYSTEM, auditBody);
138
+ }
139
+ else {
140
+ await this.handleOfflineStatus(device, device.status, body.status, auditBody?.source || Service_1.Source.SYSTEM, auditBody);
141
+ }
142
+ await this.setBatteryLevel(deviceId, body.state?.batteryPercentage?.value, auditBody?.source || Service_1.Source.SYSTEM, auditBody);
142
143
  (0, audit_1.pushAudit)({
143
144
  auditType,
144
145
  auditData: {
@@ -165,7 +166,20 @@ let LocalDeviceService = (() => {
165
166
  ? constants_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE
166
167
  : constants_1.DT_EVENT_TYPES.DEVICE.STATUS.OFFLINE;
167
168
  const devices = await this.deviceRepository.queryDevices(query);
168
- devices.forEach((device) => {
169
+ for (const device of devices) {
170
+ const auditBody = {
171
+ source: Service_1.Source.DEVICE_ACTION,
172
+ resource: IAuditProperties_1.Resource.DEVICE,
173
+ propertyId: device.propertyId,
174
+ zoneId: device.zoneId,
175
+ deviceId: device.deviceId,
176
+ };
177
+ if (updateData?.status?.online) {
178
+ await this.handleOnlineStatus(device, device.status, updateData.status, Service_1.Source.DEVICE_ACTION, auditBody);
179
+ }
180
+ else {
181
+ await this.handleOfflineStatus(device, device.status, updateData.status, Service_1.Source.DEVICE_ACTION, auditBody);
182
+ }
169
183
  (0, audit_1.pushAudit)({
170
184
  auditType,
171
185
  auditData: {
@@ -181,7 +195,7 @@ let LocalDeviceService = (() => {
181
195
  newStatus: updateData.status,
182
196
  },
183
197
  });
184
- });
198
+ }
185
199
  }
186
200
  return await this.deviceRepository.updateDevices(query, updateData);
187
201
  }
@@ -224,8 +238,8 @@ let LocalDeviceService = (() => {
224
238
  const oldStatus = device.status;
225
239
  const currentTime = new Date().toISOString();
226
240
  // Determine if the new status is ONLINE or OFFLINE
227
- const isNewStatusOnline = newStatus.liveStatus === "ONLINE";
228
- const isNewStatusOffline = newStatus.liveStatus === "OFFLINE";
241
+ const isNewStatusOnline = newStatus?.liveStatus === "ONLINE";
242
+ const isNewStatusOffline = newStatus?.liveStatus === "OFFLINE";
229
243
  if (isNewStatusOffline) {
230
244
  // New Status = OFFLINE
231
245
  await this.handleOfflineStatus(device, oldStatus, newStatus, source, auditBody, reason, currentTime);
@@ -249,6 +263,15 @@ let LocalDeviceService = (() => {
249
263
  const eventType = newStatus.online
250
264
  ? constants_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE
251
265
  : constants_1.DT_EVENT_TYPES.DEVICE.STATUS.OFFLINE;
266
+ const devices = await this.deviceRepository.queryDevices(query);
267
+ for (const device of devices) {
268
+ if (newStatus.online) {
269
+ await this.handleOnlineStatus(device, device.status, newStatus, source, auditBody);
270
+ }
271
+ else {
272
+ await this.handleOfflineStatus(device, device.status, newStatus, source, auditBody);
273
+ }
274
+ }
252
275
  await this.deviceRepository.setStatusMany(query, newStatus);
253
276
  await this.eventHandler.onStatusChangeMany(query, newStatus, auditBody, eventType);
254
277
  }
@@ -286,8 +309,6 @@ let LocalDeviceService = (() => {
286
309
  };
287
310
  await this.deviceRepository.setStatus(device.deviceId, newStatus);
288
311
  await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody, constants_1.DT_EVENT_TYPES.DEVICE.STATUS.OFFLINE);
289
- // Raise alert (OPERATIONAL only)
290
- // await this.alertService.raiseDeviceOfflineAlert(device, source, reason);
291
312
  // Raise issue when the device goes offline if longer than the baseline (OPERATIONAL only)
292
313
  await this.issueService.createDeviceOfflineIssue(device, source, reason);
293
314
  }
@@ -310,9 +331,14 @@ let LocalDeviceService = (() => {
310
331
  newStatus.error = {}; // Clear the error
311
332
  await this.deviceRepository.setStatus(device.deviceId, newStatus);
312
333
  await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody, constants_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE);
313
- //TODO: ALERT NEEDED?
314
- // Raise alert
315
- // await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
334
+ // Resolve issue if exists
335
+ await this.issueService.performIssueAction({
336
+ entityId: device.deviceId,
337
+ entityType: issue_types_1.EntityType.DEVICE,
338
+ type: issue_types_1.IssueType.DEVICE_OFFLINE,
339
+ propertyId: device.propertyId,
340
+ zoneId: device.zoneId,
341
+ }, "resolve", source);
316
342
  }
317
343
  }
318
344
  else if (isExistingStatusOffline) {
@@ -323,9 +349,14 @@ let LocalDeviceService = (() => {
323
349
  newStatus.error = undefined; // Clear the error
324
350
  await this.deviceRepository.setStatus(device.deviceId, newStatus);
325
351
  await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody, constants_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE);
326
- //TODO: ALERT NEEDED?
327
- // Raise alert
328
- // await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
352
+ //Resolve issue if exists
353
+ await this.issueService.performIssueAction({
354
+ entityId: device.deviceId,
355
+ entityType: issue_types_1.EntityType.DEVICE,
356
+ type: issue_types_1.IssueType.DEVICE_OFFLINE,
357
+ propertyId: device.propertyId,
358
+ zoneId: device.zoneId,
359
+ }, "resolve", source);
329
360
  }
330
361
  }
331
362
  async getDeviceBaseline(deviceId) {
@@ -347,18 +378,18 @@ let LocalDeviceService = (() => {
347
378
  // Get device information
348
379
  const device = await this.getDevice(deviceId);
349
380
  // Fetch the old battery level state
350
- const oldBatteryLevel = device.state?.batteryPercentage;
381
+ const oldBatteryState = device.state?.batteryPercentage;
351
382
  // Check if battery level has changed
352
- const isDifferent = !(0, lodash_1.isEqual)(oldBatteryLevel?.value, batteryLevel);
383
+ const isDifferent = !(0, lodash_1.isEqual)(oldBatteryState?.value, batteryLevel);
353
384
  if (isDifferent) {
354
385
  // Check if current time is greater than or equal to last updated time (8-hour logic)
355
- const shouldUpdate = this.shouldUpdateBatteryLevel(oldBatteryLevel?.lastUpdated);
386
+ const shouldUpdate = this.shouldUpdateBatteryLevel(oldBatteryState?.lastUpdated);
356
387
  if (shouldUpdate) {
357
388
  // Save the battery level in the device
358
389
  await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
359
390
  await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel, auditBody);
360
- if (oldBatteryLevel?.value < batteryLevel &&
361
- batteryLevel - oldBatteryLevel?.value > 50) {
391
+ if (oldBatteryState?.value < batteryLevel &&
392
+ batteryLevel - oldBatteryState?.value > 50) {
362
393
  // Battery level has increased more than 50% (considering as battery has been replaced)
363
394
  const batteryState = {
364
395
  batteryState: {
@@ -368,6 +399,14 @@ let LocalDeviceService = (() => {
368
399
  };
369
400
  await this.updateBatteryState(deviceId, batteryState);
370
401
  await this.eventHandler.onBatteryReplaced(deviceId, batteryLevel, auditBody);
402
+ // Cancel any existing battery issue
403
+ await this.issueService.performIssueAction({
404
+ entityId: deviceId,
405
+ entityType: issue_types_1.EntityType.DEVICE,
406
+ type: issue_types_1.IssueType.BATTERY_LOW,
407
+ propertyId: device.propertyId,
408
+ zoneId: device.zoneId,
409
+ }, "resolve", source);
371
410
  }
372
411
  // Get property threshold
373
412
  const propertyThreshold = await this.getPropertyBatteryThreshold(device.propertyId);
@@ -6,4 +6,5 @@ export declare class PmsRepository {
6
6
  getScheduleIdByAccessGroupId(accessGroupId: string, status: string): Promise<string | null>;
7
7
  getGuest(guestId: string): Promise<IGuest | null>;
8
8
  getGuestId(scheduleId: string): Promise<string | null>;
9
+ getScheduleByGuestId(guestId: string): Promise<IPmsSchedule | null>;
9
10
  }
@@ -92,6 +92,17 @@ let PmsRepository = (() => {
92
92
  }
93
93
  return null;
94
94
  }
95
+ async getScheduleByGuestId(guestId) {
96
+ const scheduleMap = await this.pmsPostgres.query(`SELECT * FROM dt_schedule_guest_map WHERE "guestId" = $1`, [guestId]);
97
+ if (scheduleMap.rows.length > 0) {
98
+ const scheduleId = scheduleMap.rows[0].scheduleId;
99
+ const schedule = await this.getSchedule(scheduleId);
100
+ if (schedule) {
101
+ return schedule;
102
+ }
103
+ }
104
+ return null;
105
+ }
95
106
  };
96
107
  __setFunctionName(_classThis, "PmsRepository");
97
108
  (() => {
@@ -6,4 +6,5 @@ export declare class PmsService {
6
6
  getScheduleIdByAccessGroupId(accessGroupId: string, status: string): Promise<string | null>;
7
7
  getGuest(guestId: string): Promise<IGuest | null>;
8
8
  getGuestId(scheduleId: string): Promise<string | null>;
9
+ getScheduleByGuestId(guestId: string): Promise<IPmsSchedule | null>;
9
10
  }
@@ -119,6 +119,15 @@ let PmsService = (() => {
119
119
  return null;
120
120
  return guestId;
121
121
  }
122
+ async getScheduleByGuestId(guestId) {
123
+ if (!guestId) {
124
+ throw new Error("Guest ID is required");
125
+ }
126
+ const schedule = await this.pmsRepository.getScheduleByGuestId(guestId);
127
+ if (!schedule)
128
+ return null;
129
+ return schedule;
130
+ }
122
131
  };
123
132
  __setFunctionName(_classThis, "PmsService");
124
133
  (() => {
@@ -43,7 +43,6 @@ 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>;
47
46
  /**
48
47
  * Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
49
48
  */
@@ -66,6 +65,7 @@ export declare class IssueService {
66
65
  * Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
67
66
  */
68
67
  createDeviceMalfunctionIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument | null>;
68
+ createLockJammedIssue(device: IDevice, source: Source): Promise<IIssueDocument | null>;
69
69
  /**
70
70
  * Create a maintenance issue using IssueBuilder
71
71
  */
@@ -128,7 +128,7 @@ export declare class IssueService {
128
128
  */
129
129
  unassignIssue(id: string, unassignedBy: string): Promise<IIssueDocument | null>;
130
130
  /**
131
- * Cancel/Close/Resolve an issue based on query
131
+ * Cancel/Close/Resolve/Ignore/In_Progress/On_Hold an issue based on query
132
132
  * This method will find an issue matching the query and update its status
133
133
  */
134
134
  performIssueAction(query: IIssueQuery, action: "cancel" | "close" | "resolve" | "ignore" | "in_progress" | "on_hold", updatedBy: string): Promise<IIssueDocument | null>;
@@ -243,27 +243,16 @@ let IssueService = (() => {
243
243
  entitySubType: device.deviceType.type,
244
244
  propertyId: device.propertyId,
245
245
  zoneId: device.zoneId,
246
- title: "Device Offline - Requires Attention",
246
+ title: device.deviceType.type.toLowerCase() === "hub"
247
+ ? "Hub Offline"
248
+ : "Device Offline",
247
249
  description: `${device.name} has been offline for longer than the threshold time. ${reason ? `Reason: ${reason}.` : ""}`,
248
250
  createdBy: source,
249
251
  category: issue_types_1.IssuesCategory.OPERATIONS,
250
252
  priority: issue_types_1.IssuePriority.CRITICAL,
251
- type: issue_types_1.IssueType.DEVICE_OFFLINE,
252
- });
253
- }
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,
253
+ type: device.deviceType.type.toLowerCase() === "hub"
254
+ ? issue_types_1.IssueType.HUB_OFFLINE
255
+ : issue_types_1.IssueType.DEVICE_OFFLINE,
267
256
  });
268
257
  }
269
258
  /**
@@ -276,7 +265,7 @@ let IssueService = (() => {
276
265
  entitySubType: device.deviceType.type,
277
266
  propertyId: device.propertyId,
278
267
  zoneId: device.zoneId,
279
- title: "Device Battery Low - Requires Attention",
268
+ title: "Device Battery Low",
280
269
  description: `${device.name} battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`,
281
270
  createdBy: source,
282
271
  category: issue_types_1.IssuesCategory.ENERGY,
@@ -290,7 +279,7 @@ let IssueService = (() => {
290
279
  entityType: issue_types_1.EntityType.DEVICE,
291
280
  entitySubType: device.deviceType.type,
292
281
  propertyId: device.propertyId,
293
- title: "Device Missing - Requires Attention",
282
+ title: "Device Missing",
294
283
  description: `${device.name} is missing from the account. ${reason ? `Reason: ${reason}.` : ""}`,
295
284
  createdBy: source,
296
285
  category: issue_types_1.IssuesCategory.OPERATIONS,
@@ -322,7 +311,7 @@ let IssueService = (() => {
322
311
  entitySubType: device.deviceType.type,
323
312
  propertyId: device.propertyId,
324
313
  zoneId: device.zoneId,
325
- title: `Device Malfunction - Requires Attention`,
314
+ title: `Device Malfunction`,
326
315
  description: `${device.name} is malfunctioning. ${reason ? `Reason: ${reason}.` : ""}`,
327
316
  createdBy: source,
328
317
  category: issue_types_1.IssuesCategory.OPERATIONS,
@@ -330,6 +319,21 @@ let IssueService = (() => {
330
319
  type: issue_types_1.IssueType.DEVICE_MALFUNCTION,
331
320
  });
332
321
  }
322
+ async createLockJammedIssue(device, source) {
323
+ return await this.createDeviceIssue({
324
+ entityId: device.deviceId,
325
+ entityType: issue_types_1.EntityType.DEVICE,
326
+ entitySubType: device.deviceType.type,
327
+ propertyId: device.propertyId,
328
+ zoneId: device.zoneId,
329
+ title: "Lock Jammed",
330
+ description: `${device.name} is jammed. Requires Immediate Attention.`,
331
+ createdBy: source,
332
+ category: issue_types_1.IssuesCategory.OPERATIONS,
333
+ priority: issue_types_1.IssuePriority.HIGH,
334
+ type: issue_types_1.IssueType.LOCK_JAMMED,
335
+ });
336
+ }
333
337
  /**
334
338
  * Create a maintenance issue using IssueBuilder
335
339
  */
@@ -666,7 +670,7 @@ let IssueService = (() => {
666
670
  return await issueModel.save();
667
671
  }
668
672
  /**
669
- * Cancel/Close/Resolve an issue based on query
673
+ * Cancel/Close/Resolve/Ignore/In_Progress/On_Hold an issue based on query
670
674
  * This method will find an issue matching the query and update its status
671
675
  */
672
676
  async performIssueAction(query, action, updatedBy) {
@@ -932,10 +936,11 @@ let IssueService = (() => {
932
936
  applyBusinessRules(filters) {
933
937
  // Business logic: Apply additional filters based on business rules
934
938
  const enhancedFilters = { ...filters };
935
- // Example: Always exclude cancelled issues unless explicitly requested
936
- if (!enhancedFilters.status ||
937
- enhancedFilters.status !== issue_types_1.IssueStatus.CANCELLED) {
938
- enhancedFilters.status = { $ne: issue_types_1.IssueStatus.CANCELLED };
939
+ // Always exclude cancelled, resolved, and closed issues unless explicitly requested
940
+ if (!enhancedFilters.status) {
941
+ enhancedFilters.status = {
942
+ $nin: [issue_types_1.IssueStatus.CANCELLED, issue_types_1.IssueStatus.RESOLVED, issue_types_1.IssueStatus.CLOSED],
943
+ };
939
944
  }
940
945
  return enhancedFilters;
941
946
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "7.5.0",
3
+ "version": "7.6.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [