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.
- package/dist/alerts/Alert.service.d.ts +9 -2
- package/dist/alerts/Alert.service.js +95 -7
- package/dist/constants/Service.d.ts +2 -1
- package/dist/constants/Service.js +1 -0
- package/dist/entities/admin/Admin.repository.js +7 -1
- package/dist/entities/device/local/interfaces/IDevice.d.ts +1 -1
- package/dist/entities/device/local/repository/Device.repository.d.ts +0 -1
- package/dist/entities/device/local/repository/Device.repository.js +0 -12
- package/dist/entities/device/local/services/Device.service.d.ts +0 -1
- package/dist/entities/device/local/services/Device.service.js +62 -23
- package/dist/entities/pms/pms.repository.d.ts +1 -0
- package/dist/entities/pms/pms.repository.js +11 -0
- package/dist/entities/pms/pms.service.d.ts +1 -0
- package/dist/entities/pms/pms.service.js +9 -0
- package/dist/issues/Issue.service.d.ts +2 -2
- package/dist/issues/Issue.service.js +30 -25
- package/package.json +1 -1
|
@@ -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,
|
|
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
|
|
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,
|
|
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
|
|
174
|
-
description: `${zone?.name} has a door left open, for more than
|
|
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.
|
|
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
|
|
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
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
|
228
|
-
const isNewStatusOffline = newStatus
|
|
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
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
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
|
|
381
|
+
const oldBatteryState = device.state?.batteryPercentage;
|
|
351
382
|
// Check if battery level has changed
|
|
352
|
-
const isDifferent = !(0, lodash_1.isEqual)(
|
|
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(
|
|
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 (
|
|
361
|
-
batteryLevel -
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
936
|
-
if (!enhancedFilters.status
|
|
937
|
-
enhancedFilters.status
|
|
938
|
-
|
|
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
|
}
|