dt-common-device 1.3.0 → 2.0.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.
- package/TROUBLESHOOTING.md +184 -0
- package/dist/config/config.d.ts +9 -2
- package/dist/config/config.js +97 -14
- package/dist/constants/Event.d.ts +75 -0
- package/dist/constants/Event.js +78 -0
- package/dist/db/db.d.ts +1 -0
- package/dist/db/db.js +18 -2
- package/dist/device/local/entities/AlertBuilder.d.ts +87 -0
- package/dist/device/local/entities/AlertBuilder.example.d.ts +11 -0
- package/dist/device/local/entities/AlertBuilder.example.js +117 -0
- package/dist/device/local/entities/AlertBuilder.js +179 -0
- package/dist/device/local/entities/IssueBuilder.d.ts +109 -0
- package/dist/device/local/entities/IssueBuilder.example.d.ts +16 -0
- package/dist/device/local/entities/IssueBuilder.example.js +196 -0
- package/dist/device/local/entities/IssueBuilder.js +237 -0
- package/dist/device/local/entities/index.d.ts +2 -0
- package/dist/device/local/entities/index.js +7 -0
- package/dist/device/local/interfaces/IDevice.d.ts +10 -9
- package/dist/device/local/interfaces/IDevice.js +7 -0
- package/dist/device/local/models/Alert.model.d.ts +28 -0
- package/dist/device/local/models/Alert.model.js +222 -0
- package/dist/device/local/models/Issue.model.d.ts +28 -0
- package/dist/device/local/models/Issue.model.js +260 -0
- package/dist/device/local/repository/Alert.repository.d.ts +106 -0
- package/dist/device/local/repository/Alert.repository.js +374 -0
- package/dist/device/local/repository/Device.repository.d.ts +10 -2
- package/dist/device/local/repository/Device.repository.js +153 -30
- package/dist/device/local/repository/Hub.repository.d.ts +1 -1
- package/dist/device/local/repository/Hub.repository.js +60 -18
- package/dist/device/local/repository/Issue.repository.d.ts +113 -0
- package/dist/device/local/repository/Issue.repository.js +401 -0
- package/dist/device/local/repository/Schedule.repository.d.ts +1 -1
- package/dist/device/local/repository/Schedule.repository.js +14 -18
- package/dist/device/local/services/Alert.service.d.ts +135 -5
- package/dist/device/local/services/Alert.service.js +471 -7
- package/dist/device/local/services/AlertService.example.d.ts +55 -0
- package/dist/device/local/services/AlertService.example.js +148 -0
- package/dist/device/local/services/Device.service.d.ts +8 -5
- package/dist/device/local/services/Device.service.js +58 -40
- package/dist/device/local/services/Issue.service.d.ts +168 -0
- package/dist/device/local/services/Issue.service.js +642 -0
- package/dist/device/local/services/IssueService.example.d.ts +68 -0
- package/dist/device/local/services/IssueService.example.js +177 -0
- package/dist/device/local/services/index.d.ts +7 -5
- package/dist/device/local/services/index.js +21 -11
- package/dist/events/BaseEventHandler.d.ts +43 -0
- package/dist/events/BaseEventHandler.js +111 -0
- package/dist/events/BaseEventTransformer.d.ts +26 -0
- package/dist/events/BaseEventTransformer.js +72 -0
- package/dist/events/DeviceEventHandler.d.ts +15 -0
- package/dist/events/DeviceEventHandler.js +152 -0
- package/dist/events/DeviceEventTransformerFactory.d.ts +27 -0
- package/dist/events/DeviceEventTransformerFactory.js +116 -0
- package/dist/events/EventHandler.d.ts +11 -0
- package/dist/events/EventHandler.js +106 -0
- package/dist/events/EventHandlerOrchestrator.d.ts +35 -0
- package/dist/events/EventHandlerOrchestrator.js +141 -0
- package/dist/events/EventProcessingService.d.ts +43 -0
- package/dist/events/EventProcessingService.js +243 -0
- package/dist/events/InternalEventSubscription.d.ts +44 -0
- package/dist/events/InternalEventSubscription.js +152 -0
- package/dist/events/index.d.ts +9 -0
- package/dist/events/index.js +21 -0
- package/dist/events/interfaces/DeviceEvent.d.ts +48 -0
- package/dist/events/interfaces/DeviceEvent.js +2 -0
- package/dist/events/interfaces/IEventHandler.d.ts +23 -0
- package/dist/events/interfaces/IEventHandler.js +2 -0
- package/dist/events/interfaces/IEventTransformer.d.ts +7 -0
- package/dist/events/interfaces/IEventTransformer.js +2 -0
- package/dist/events/interfaces/IInternalEvent.d.ts +42 -0
- package/dist/events/interfaces/IInternalEvent.js +2 -0
- package/dist/events/interfaces/index.d.ts +4 -0
- package/dist/events/interfaces/index.js +20 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +9 -2
- package/dist/types/alert.types.d.ts +57 -0
- package/dist/types/alert.types.js +22 -0
- package/dist/types/config.types.d.ts +15 -4
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/issue.types.d.ts +90 -0
- package/dist/types/issue.types.js +40 -0
- package/dist/utils/http-utils.d.ts +13 -0
- package/dist/utils/http-utils.js +117 -0
- package/package.json +2 -1
- package/src/config/config.ts +117 -14
- package/src/{device/local/events/Events.ts → constants/Event.ts} +34 -13
- package/src/db/db.ts +14 -5
- package/src/device/local/entities/AlertBuilder.example.ts +126 -0
- package/src/device/local/entities/AlertBuilder.ts +202 -0
- package/src/device/local/entities/IssueBuilder.example.ts +210 -0
- package/src/device/local/entities/IssueBuilder.ts +263 -0
- package/src/device/local/entities/README.md +173 -0
- package/src/device/local/entities/index.ts +2 -0
- package/src/device/local/interfaces/IDevice.ts +11 -9
- package/src/device/local/models/Alert.model.md +319 -0
- package/src/device/local/models/Alert.model.ts +283 -0
- package/src/device/local/models/Issue.model.md +386 -0
- package/src/device/local/models/Issue.model.ts +350 -0
- package/src/device/local/models/README.md +312 -0
- package/src/device/local/repository/Alert.repository.ts +465 -0
- package/src/device/local/repository/Device.repository.ts +241 -32
- package/src/device/local/repository/Hub.repository.ts +74 -18
- package/src/device/local/repository/Issue.repository.ts +517 -0
- package/src/device/local/repository/Schedule.repository.ts +28 -22
- package/src/device/local/services/Alert.service.ts +617 -5
- package/src/device/local/services/AlertService.example.ts +229 -0
- package/src/device/local/services/Device.service.ts +70 -50
- package/src/device/local/services/Issue.service.ts +872 -0
- package/src/device/local/services/IssueService.example.ts +307 -0
- package/src/device/local/services/index.ts +7 -5
- package/src/events/BaseEventHandler.ts +145 -0
- package/src/events/BaseEventTransformer.ts +97 -0
- package/src/events/DeviceEventHandler.ts +211 -0
- package/src/events/DeviceEventTransformerFactory.ts +77 -0
- package/src/{device/local/events → events}/EventHandler.ts +19 -15
- package/src/events/EventHandlerOrchestrator.ts +119 -0
- package/src/events/EventProcessingService.ts +248 -0
- package/src/events/InternalEventSubscription.ts +219 -0
- package/src/events/index.ts +9 -0
- package/src/events/interfaces/DeviceEvent.ts +56 -0
- package/src/events/interfaces/IEventHandler.ts +28 -0
- package/src/events/interfaces/IEventTransformer.ts +8 -0
- package/src/events/interfaces/IInternalEvent.ts +47 -0
- package/src/events/interfaces/index.ts +4 -0
- package/src/index.ts +9 -2
- package/src/types/alert.types.ts +64 -0
- package/src/types/config.types.ts +17 -4
- package/src/types/index.ts +2 -0
- package/src/types/issue.types.ts +98 -0
- package/src/utils/http-utils.ts +143 -0
- package/src/device/local/events/index.ts +0 -2
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { Service } from "typedi";
|
|
2
|
+
import { IssueModel, IIssueDocument } from "../models/Issue.model";
|
|
3
|
+
import {
|
|
4
|
+
CreateIssueData,
|
|
5
|
+
UpdateIssueData,
|
|
6
|
+
IssueStatus,
|
|
7
|
+
IssuePriority,
|
|
8
|
+
IssuesCategory,
|
|
9
|
+
EntityType,
|
|
10
|
+
} from "../../../types/issue.types";
|
|
11
|
+
|
|
12
|
+
@Service()
|
|
13
|
+
export class IssueRepository {
|
|
14
|
+
/**
|
|
15
|
+
* Create a new issue
|
|
16
|
+
*/
|
|
17
|
+
async create(issueData: CreateIssueData): Promise<IIssueDocument> {
|
|
18
|
+
try {
|
|
19
|
+
const issue = new IssueModel({
|
|
20
|
+
...issueData,
|
|
21
|
+
status: IssueStatus.PENDING,
|
|
22
|
+
priority: issueData.priority || IssuePriority.MEDIUM,
|
|
23
|
+
isDeleted: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return await issue.save();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Failed to create issue: ${
|
|
30
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
31
|
+
}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Find issue by ID
|
|
38
|
+
*/
|
|
39
|
+
async findById(
|
|
40
|
+
id: string,
|
|
41
|
+
includeDeleted = false
|
|
42
|
+
): Promise<IIssueDocument | null> {
|
|
43
|
+
try {
|
|
44
|
+
const query: any = { _id: id };
|
|
45
|
+
if (!includeDeleted) {
|
|
46
|
+
query.isDeleted = false;
|
|
47
|
+
}
|
|
48
|
+
return await IssueModel.findOne(query);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Failed to find issue by ID: ${
|
|
52
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
53
|
+
}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Find all issues with filters
|
|
60
|
+
*/
|
|
61
|
+
async findAll(
|
|
62
|
+
filters: {
|
|
63
|
+
propertyId?: string;
|
|
64
|
+
assignedTo?: string;
|
|
65
|
+
status?: IssueStatus;
|
|
66
|
+
priority?: IssuePriority;
|
|
67
|
+
category?: IssuesCategory;
|
|
68
|
+
entityType?: EntityType;
|
|
69
|
+
entityId?: string;
|
|
70
|
+
includeDeleted?: boolean;
|
|
71
|
+
limit?: number;
|
|
72
|
+
skip?: number;
|
|
73
|
+
sort?: { [key: string]: 1 | -1 };
|
|
74
|
+
} = {}
|
|
75
|
+
): Promise<IIssueDocument[]> {
|
|
76
|
+
try {
|
|
77
|
+
const query: any = {};
|
|
78
|
+
|
|
79
|
+
if (filters.propertyId) query.propertyId = filters.propertyId;
|
|
80
|
+
if (filters.assignedTo) query.assignedTo = filters.assignedTo;
|
|
81
|
+
if (filters.status) query.status = filters.status;
|
|
82
|
+
if (filters.priority) query.priority = filters.priority;
|
|
83
|
+
if (filters.category) query.category = filters.category;
|
|
84
|
+
if (filters.entityType) query.entityType = filters.entityType;
|
|
85
|
+
if (filters.entityId) query.entityId = filters.entityId;
|
|
86
|
+
if (!filters.includeDeleted) query.isDeleted = false;
|
|
87
|
+
|
|
88
|
+
const queryBuilder = IssueModel.find(query);
|
|
89
|
+
|
|
90
|
+
if (filters.sort) {
|
|
91
|
+
queryBuilder.sort(filters.sort);
|
|
92
|
+
} else {
|
|
93
|
+
queryBuilder.sort({ createdAt: -1 });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (filters.skip) queryBuilder.skip(filters.skip);
|
|
97
|
+
if (filters.limit) queryBuilder.limit(filters.limit);
|
|
98
|
+
|
|
99
|
+
return await queryBuilder.exec();
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Failed to find issues: ${
|
|
103
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
104
|
+
}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Update an issue
|
|
111
|
+
*/
|
|
112
|
+
async update(
|
|
113
|
+
id: string,
|
|
114
|
+
updateData: UpdateIssueData
|
|
115
|
+
): Promise<IIssueDocument | null> {
|
|
116
|
+
try {
|
|
117
|
+
return await IssueModel.findByIdAndUpdate(
|
|
118
|
+
id,
|
|
119
|
+
{ ...updateData, updatedAt: new Date() },
|
|
120
|
+
{ new: true, runValidators: true }
|
|
121
|
+
);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Failed to update issue: ${
|
|
125
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
126
|
+
}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Soft delete an issue
|
|
133
|
+
*/
|
|
134
|
+
async softDelete(id: string, deletedBy: string): Promise<boolean> {
|
|
135
|
+
try {
|
|
136
|
+
const result = await IssueModel.findByIdAndUpdate(id, {
|
|
137
|
+
isDeleted: true,
|
|
138
|
+
updatedBy: deletedBy,
|
|
139
|
+
updatedAt: new Date(),
|
|
140
|
+
});
|
|
141
|
+
return !!result;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Failed to soft delete issue: ${
|
|
145
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
146
|
+
}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Permanently delete an issue
|
|
153
|
+
*/
|
|
154
|
+
async hardDelete(id: string): Promise<boolean> {
|
|
155
|
+
try {
|
|
156
|
+
const result = await IssueModel.findByIdAndDelete(id);
|
|
157
|
+
return !!result;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Failed to permanently delete issue: ${
|
|
161
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
162
|
+
}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Count issues with filters
|
|
169
|
+
*/
|
|
170
|
+
async count(
|
|
171
|
+
filters: {
|
|
172
|
+
propertyId?: string;
|
|
173
|
+
assignedTo?: string;
|
|
174
|
+
status?: IssueStatus;
|
|
175
|
+
priority?: IssuePriority;
|
|
176
|
+
category?: IssuesCategory;
|
|
177
|
+
entityType?: EntityType;
|
|
178
|
+
entityId?: string;
|
|
179
|
+
includeDeleted?: boolean;
|
|
180
|
+
} = {}
|
|
181
|
+
): Promise<number> {
|
|
182
|
+
try {
|
|
183
|
+
const query: any = {};
|
|
184
|
+
|
|
185
|
+
if (filters.propertyId) query.propertyId = filters.propertyId;
|
|
186
|
+
if (filters.assignedTo) query.assignedTo = filters.assignedTo;
|
|
187
|
+
if (filters.status) query.status = filters.status;
|
|
188
|
+
if (filters.priority) query.priority = filters.priority;
|
|
189
|
+
if (filters.category) query.category = filters.category;
|
|
190
|
+
if (filters.entityType) query.entityType = filters.entityType;
|
|
191
|
+
if (filters.entityId) query.entityId = filters.entityId;
|
|
192
|
+
if (!filters.includeDeleted) query.isDeleted = false;
|
|
193
|
+
|
|
194
|
+
return await IssueModel.countDocuments(query);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Failed to count issues: ${
|
|
198
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
199
|
+
}`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Find issues by property
|
|
206
|
+
*/
|
|
207
|
+
async findByProperty(
|
|
208
|
+
propertyId: string,
|
|
209
|
+
includeDeleted = false
|
|
210
|
+
): Promise<IIssueDocument[]> {
|
|
211
|
+
try {
|
|
212
|
+
return await IssueModel.findByProperty(propertyId, includeDeleted);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Failed to find issues by property: ${
|
|
216
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
217
|
+
}`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Find issues by assignee
|
|
224
|
+
*/
|
|
225
|
+
async findByAssignee(
|
|
226
|
+
assignedTo: string,
|
|
227
|
+
includeDeleted = false
|
|
228
|
+
): Promise<IIssueDocument[]> {
|
|
229
|
+
try {
|
|
230
|
+
return await IssueModel.findByAssignee(assignedTo, includeDeleted);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
`Failed to find issues by assignee: ${
|
|
234
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
235
|
+
}`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Find issues by entity
|
|
242
|
+
*/
|
|
243
|
+
async findByEntity(
|
|
244
|
+
entityId: string,
|
|
245
|
+
entityType: EntityType,
|
|
246
|
+
includeDeleted = false
|
|
247
|
+
): Promise<IIssueDocument[]> {
|
|
248
|
+
try {
|
|
249
|
+
return await IssueModel.findByEntity(
|
|
250
|
+
entityId,
|
|
251
|
+
entityType,
|
|
252
|
+
includeDeleted
|
|
253
|
+
);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`Failed to find issues by entity: ${
|
|
257
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
258
|
+
}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Find issues by status
|
|
265
|
+
*/
|
|
266
|
+
async findByStatus(
|
|
267
|
+
status: IssueStatus,
|
|
268
|
+
includeDeleted = false
|
|
269
|
+
): Promise<IIssueDocument[]> {
|
|
270
|
+
try {
|
|
271
|
+
return await IssueModel.findByStatus(status, includeDeleted);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`Failed to find issues by status: ${
|
|
275
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
276
|
+
}`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Find issues by priority
|
|
283
|
+
*/
|
|
284
|
+
async findByPriority(
|
|
285
|
+
priority: IssuePriority,
|
|
286
|
+
includeDeleted = false
|
|
287
|
+
): Promise<IIssueDocument[]> {
|
|
288
|
+
try {
|
|
289
|
+
return await IssueModel.findByPriority(priority, includeDeleted);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`Failed to find issues by priority: ${
|
|
293
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
294
|
+
}`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Find overdue issues
|
|
301
|
+
*/
|
|
302
|
+
async findOverdue(includeDeleted = false): Promise<IIssueDocument[]> {
|
|
303
|
+
try {
|
|
304
|
+
return await IssueModel.findOverdue(includeDeleted);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw new Error(
|
|
307
|
+
`Failed to find overdue issues: ${
|
|
308
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
309
|
+
}`
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Find upcoming issues
|
|
316
|
+
*/
|
|
317
|
+
async findUpcoming(
|
|
318
|
+
days: number = 7,
|
|
319
|
+
includeDeleted = false
|
|
320
|
+
): Promise<IIssueDocument[]> {
|
|
321
|
+
try {
|
|
322
|
+
return await IssueModel.findUpcoming(days, includeDeleted);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`Failed to find upcoming issues: ${
|
|
326
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
327
|
+
}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Search issues by text
|
|
334
|
+
*/
|
|
335
|
+
async search(
|
|
336
|
+
searchTerm: string,
|
|
337
|
+
filters: {
|
|
338
|
+
propertyId?: string;
|
|
339
|
+
includeDeleted?: boolean;
|
|
340
|
+
limit?: number;
|
|
341
|
+
skip?: number;
|
|
342
|
+
} = {}
|
|
343
|
+
): Promise<IIssueDocument[]> {
|
|
344
|
+
try {
|
|
345
|
+
const query: any = {
|
|
346
|
+
$or: [
|
|
347
|
+
{ title: { $regex: searchTerm, $options: "i" } },
|
|
348
|
+
{ description: { $regex: searchTerm, $options: "i" } },
|
|
349
|
+
],
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
if (filters.propertyId) query.propertyId = filters.propertyId;
|
|
353
|
+
if (!filters.includeDeleted) query.isDeleted = false;
|
|
354
|
+
|
|
355
|
+
const queryBuilder = IssueModel.find(query).sort({ createdAt: -1 });
|
|
356
|
+
|
|
357
|
+
if (filters.skip) queryBuilder.skip(filters.skip);
|
|
358
|
+
if (filters.limit) queryBuilder.limit(filters.limit);
|
|
359
|
+
|
|
360
|
+
return await queryBuilder.exec();
|
|
361
|
+
} catch (error) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Failed to search issues: ${
|
|
364
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
365
|
+
}`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get issue statistics
|
|
372
|
+
*/
|
|
373
|
+
async getStatistics(propertyId?: string): Promise<{
|
|
374
|
+
total: number;
|
|
375
|
+
pending: number;
|
|
376
|
+
inProgress: number;
|
|
377
|
+
resolved: number;
|
|
378
|
+
closed: number;
|
|
379
|
+
overdue: number;
|
|
380
|
+
byPriority: Record<IssuePriority, number>;
|
|
381
|
+
byCategory: Record<IssuesCategory, number>;
|
|
382
|
+
}> {
|
|
383
|
+
try {
|
|
384
|
+
const query: any = { isDeleted: false };
|
|
385
|
+
if (propertyId) query.propertyId = propertyId;
|
|
386
|
+
|
|
387
|
+
const [
|
|
388
|
+
total,
|
|
389
|
+
pending,
|
|
390
|
+
inProgress,
|
|
391
|
+
resolved,
|
|
392
|
+
closed,
|
|
393
|
+
overdue,
|
|
394
|
+
priorityStats,
|
|
395
|
+
categoryStats,
|
|
396
|
+
] = await Promise.all([
|
|
397
|
+
IssueModel.countDocuments(query),
|
|
398
|
+
IssueModel.countDocuments({ ...query, status: IssueStatus.PENDING }),
|
|
399
|
+
IssueModel.countDocuments({
|
|
400
|
+
...query,
|
|
401
|
+
status: IssueStatus.IN_PROGRESS,
|
|
402
|
+
}),
|
|
403
|
+
IssueModel.countDocuments({ ...query, status: IssueStatus.RESOLVED }),
|
|
404
|
+
IssueModel.countDocuments({ ...query, status: IssueStatus.CLOSED }),
|
|
405
|
+
IssueModel.countDocuments({
|
|
406
|
+
...query,
|
|
407
|
+
dueDate: { $lt: new Date() },
|
|
408
|
+
status: {
|
|
409
|
+
$nin: [
|
|
410
|
+
IssueStatus.RESOLVED,
|
|
411
|
+
IssueStatus.CLOSED,
|
|
412
|
+
IssueStatus.CANCELLED,
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
}),
|
|
416
|
+
IssueModel.aggregate([
|
|
417
|
+
{ $match: query },
|
|
418
|
+
{ $group: { _id: "$priority", count: { $sum: 1 } } },
|
|
419
|
+
]),
|
|
420
|
+
IssueModel.aggregate([
|
|
421
|
+
{ $match: query },
|
|
422
|
+
{ $group: { _id: "$category", count: { $sum: 1 } } },
|
|
423
|
+
]),
|
|
424
|
+
]);
|
|
425
|
+
|
|
426
|
+
const byPriority = Object.values(IssuePriority).reduce(
|
|
427
|
+
(acc, priority) => {
|
|
428
|
+
acc[priority] = 0;
|
|
429
|
+
return acc;
|
|
430
|
+
},
|
|
431
|
+
{} as Record<IssuePriority, number>
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const byCategory = Object.values(IssuesCategory).reduce(
|
|
435
|
+
(acc, category) => {
|
|
436
|
+
acc[category] = 0;
|
|
437
|
+
return acc;
|
|
438
|
+
},
|
|
439
|
+
{} as Record<IssuesCategory, number>
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
priorityStats.forEach((stat: { _id: string; count: number }) => {
|
|
443
|
+
if (stat._id in byPriority) {
|
|
444
|
+
byPriority[stat._id as IssuePriority] = stat.count;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
categoryStats.forEach((stat: { _id: string; count: number }) => {
|
|
449
|
+
if (stat._id in byCategory) {
|
|
450
|
+
byCategory[stat._id as IssuesCategory] = stat.count;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
return {
|
|
455
|
+
total,
|
|
456
|
+
pending,
|
|
457
|
+
inProgress,
|
|
458
|
+
resolved,
|
|
459
|
+
closed,
|
|
460
|
+
overdue,
|
|
461
|
+
byPriority,
|
|
462
|
+
byCategory,
|
|
463
|
+
};
|
|
464
|
+
} catch (error) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Failed to get issue statistics: ${
|
|
467
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
468
|
+
}`
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Bulk update issues
|
|
475
|
+
*/
|
|
476
|
+
async bulkUpdate(
|
|
477
|
+
ids: string[],
|
|
478
|
+
updateData: Partial<UpdateIssueData>
|
|
479
|
+
): Promise<number> {
|
|
480
|
+
try {
|
|
481
|
+
const result = await IssueModel.updateMany(
|
|
482
|
+
{ _id: { $in: ids } },
|
|
483
|
+
{ ...updateData, updatedAt: new Date() }
|
|
484
|
+
);
|
|
485
|
+
return result.modifiedCount;
|
|
486
|
+
} catch (error) {
|
|
487
|
+
throw new Error(
|
|
488
|
+
`Failed to bulk update issues: ${
|
|
489
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
490
|
+
}`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Bulk soft delete issues
|
|
497
|
+
*/
|
|
498
|
+
async bulkSoftDelete(ids: string[], deletedBy: string): Promise<number> {
|
|
499
|
+
try {
|
|
500
|
+
const result = await IssueModel.updateMany(
|
|
501
|
+
{ _id: { $in: ids } },
|
|
502
|
+
{
|
|
503
|
+
isDeleted: true,
|
|
504
|
+
updatedBy: deletedBy,
|
|
505
|
+
updatedAt: new Date(),
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
return result.modifiedCount;
|
|
509
|
+
} catch (error) {
|
|
510
|
+
throw new Error(
|
|
511
|
+
`Failed to bulk soft delete issues: ${
|
|
512
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
513
|
+
}`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
@@ -1,56 +1,62 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
2
|
import { getConfig } from "../../../config/config";
|
|
3
|
-
import axios from "axios";
|
|
4
3
|
import { ISchedule } from "../interfaces/ISchedule";
|
|
4
|
+
import { getDeviceServiceAxiosInstance } from "../../../utils/http-utils";
|
|
5
5
|
|
|
6
6
|
@Service()
|
|
7
7
|
export class ScheduleRepository {
|
|
8
|
-
private readonly
|
|
8
|
+
private readonly axiosInstance;
|
|
9
|
+
|
|
9
10
|
constructor() {
|
|
10
|
-
|
|
11
|
-
if (!DEVICE_SERVICE) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
"DEVICE_SERVICE is not configured. Call initialize() first with DEVICE_SERVICE."
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
this.baseUrl = DEVICE_SERVICE;
|
|
11
|
+
this.axiosInstance = getDeviceServiceAxiosInstance();
|
|
17
12
|
}
|
|
13
|
+
|
|
18
14
|
async getSchedule(scheduleId: string) {
|
|
19
15
|
try {
|
|
20
|
-
const response = await
|
|
21
|
-
|
|
16
|
+
const response = await this.axiosInstance.get(
|
|
17
|
+
`/devices/schedule?id=${scheduleId}`
|
|
22
18
|
);
|
|
23
19
|
return response.data;
|
|
24
20
|
} catch (error: any) {
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
getConfig().LOGGER.error(`Failed to get schedule ${scheduleId}:`, error);
|
|
22
|
+
const errorMessage =
|
|
23
|
+
error.response?.data?.message || error.message || "Unknown error";
|
|
24
|
+
throw new Error(`Failed to get schedule: ${errorMessage}`);
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
async getScheduleByZone(zoneId: string) {
|
|
31
29
|
try {
|
|
32
|
-
const response = await
|
|
33
|
-
|
|
30
|
+
const response = await this.axiosInstance.get(
|
|
31
|
+
`/devices/schedules?zoneId=${zoneId}`
|
|
34
32
|
);
|
|
35
33
|
return response.data;
|
|
36
34
|
} catch (error: any) {
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
getConfig().LOGGER.error(
|
|
36
|
+
`Failed to get schedule by zone ${zoneId}:`,
|
|
37
|
+
error
|
|
38
|
+
);
|
|
39
|
+
const errorMessage =
|
|
40
|
+
error.response?.data?.message || error.message || "Unknown error";
|
|
41
|
+
throw new Error(`Failed to get schedule: ${errorMessage}`);
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
async setSchedule(scheduleId: string, schedule: ISchedule) {
|
|
43
46
|
try {
|
|
44
|
-
const response = await
|
|
45
|
-
|
|
47
|
+
const response = await this.axiosInstance.put(
|
|
48
|
+
`/devices/schedules/${scheduleId}`,
|
|
46
49
|
schedule
|
|
47
50
|
);
|
|
48
51
|
return response.data;
|
|
49
52
|
} catch (error: any) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
getConfig().LOGGER.error(
|
|
54
|
+
`Failed to update schedule ${scheduleId}:`,
|
|
55
|
+
error
|
|
53
56
|
);
|
|
57
|
+
const errorMessage =
|
|
58
|
+
error.response?.data?.message || error.message || "Unknown error";
|
|
59
|
+
throw new Error(`Failed to update schedule: ${errorMessage}`);
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
}
|