@iservice365/module-hygiene 0.0.1 → 0.1.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/CHANGELOG.md +12 -0
- package/dist/index.d.ts +503 -1
- package/dist/index.js +4680 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4693 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -3
- package/dist/public/user-invite.hbs +0 -142
package/dist/index.js
CHANGED
|
@@ -1,2 +1,4682 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
MArea: () => MArea,
|
|
34
|
+
MAreaChecklist: () => MAreaChecklist,
|
|
35
|
+
MParentChecklist: () => MParentChecklist,
|
|
36
|
+
MScheduleTaskArea: () => MScheduleTaskArea,
|
|
37
|
+
MToiletLocation: () => MToiletLocation,
|
|
38
|
+
MUnit: () => MUnit,
|
|
39
|
+
MUnitChecklist: () => MUnitChecklist,
|
|
40
|
+
allowedStatus: () => allowedStatus,
|
|
41
|
+
allowedTypes: () => allowedTypes,
|
|
42
|
+
areaChecklistSchema: () => areaChecklistSchema,
|
|
43
|
+
areaSchema: () => areaSchema,
|
|
44
|
+
parentChecklistSchema: () => parentChecklistSchema,
|
|
45
|
+
scheduleTaskAreaSchema: () => scheduleTaskAreaSchema,
|
|
46
|
+
toiletLocationSchema: () => toiletLocationSchema,
|
|
47
|
+
unitChecklistSchema: () => unitChecklistSchema,
|
|
48
|
+
unitSchema: () => unitSchema,
|
|
49
|
+
useAreaChecklistController: () => useAreaChecklistController,
|
|
50
|
+
useAreaChecklistRepo: () => useAreaChecklistRepo,
|
|
51
|
+
useAreaController: () => useAreaController,
|
|
52
|
+
useAreaRepository: () => useAreaRepository,
|
|
53
|
+
useAreaService: () => useAreaService,
|
|
54
|
+
useParentChecklistController: () => useParentChecklistController,
|
|
55
|
+
useParentChecklistRepo: () => useParentChecklistRepo,
|
|
56
|
+
useScheduleTaskAreaController: () => useScheduleTaskAreaController,
|
|
57
|
+
useScheduleTaskAreaRepository: () => useScheduleTaskAreaRepository,
|
|
58
|
+
useScheduleTaskAreaService: () => useScheduleTaskAreaService,
|
|
59
|
+
useToiletLocationController: () => useToiletLocationController,
|
|
60
|
+
useToiletLocationRepository: () => useToiletLocationRepository,
|
|
61
|
+
useToiletLocationService: () => useToiletLocationService,
|
|
62
|
+
useUnitChecklistController: () => useUnitChecklistController,
|
|
63
|
+
useUnitChecklistRepo: () => useUnitChecklistRepo,
|
|
64
|
+
useUnitController: () => useUnitController,
|
|
65
|
+
useUnitRepository: () => useUnitRepository,
|
|
66
|
+
useUnitService: () => useUnitService
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(src_exports);
|
|
69
|
+
|
|
70
|
+
// src/models/hygiene-area.model.ts
|
|
71
|
+
var import_node_server_utils = require("@iservice365/node-server-utils");
|
|
72
|
+
var import_joi = __toESM(require("joi"));
|
|
73
|
+
var import_mongodb = require("mongodb");
|
|
74
|
+
var areaSchema = import_joi.default.object({
|
|
75
|
+
name: import_joi.default.string().required(),
|
|
76
|
+
site: import_joi.default.string().hex().required(),
|
|
77
|
+
createdBy: import_joi.default.string().hex().required(),
|
|
78
|
+
checklist: import_joi.default.array().items(
|
|
79
|
+
import_joi.default.object({
|
|
80
|
+
_id: import_joi.default.string().hex().required(),
|
|
81
|
+
name: import_joi.default.string().required()
|
|
82
|
+
})
|
|
83
|
+
).optional()
|
|
84
|
+
});
|
|
85
|
+
function MArea(value) {
|
|
86
|
+
const { error } = areaSchema.validate(value);
|
|
87
|
+
if (error) {
|
|
88
|
+
import_node_server_utils.logger.info(`Hygiene Area Model: ${error.message}`);
|
|
89
|
+
throw new import_node_server_utils.BadRequestError(error.message);
|
|
90
|
+
}
|
|
91
|
+
if (value.site) {
|
|
92
|
+
try {
|
|
93
|
+
value.site = new import_mongodb.ObjectId(value.site);
|
|
94
|
+
} catch (error2) {
|
|
95
|
+
throw new import_node_server_utils.BadRequestError("Invalid site ID format.");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (value.createdBy) {
|
|
99
|
+
try {
|
|
100
|
+
value.createdBy = new import_mongodb.ObjectId(value.createdBy);
|
|
101
|
+
} catch (error2) {
|
|
102
|
+
throw new import_node_server_utils.BadRequestError("Invalid createdBy ID format.");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
106
|
+
value.checklist = value.checklist.map((item) => {
|
|
107
|
+
try {
|
|
108
|
+
return {
|
|
109
|
+
...item,
|
|
110
|
+
_id: new import_mongodb.ObjectId(item._id)
|
|
111
|
+
};
|
|
112
|
+
} catch (error2) {
|
|
113
|
+
throw new import_node_server_utils.BadRequestError(
|
|
114
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
name: value.name,
|
|
121
|
+
site: value.site,
|
|
122
|
+
createdBy: value.createdBy,
|
|
123
|
+
checklist: value.checklist,
|
|
124
|
+
status: value.status ?? "active",
|
|
125
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
126
|
+
updatedAt: value.updatedAt ?? "",
|
|
127
|
+
deletedAt: value.deletedAt ?? ""
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/repositories/hygiene-area.repository.ts
|
|
132
|
+
var import_mongodb2 = require("mongodb");
|
|
133
|
+
var import_node_server_utils2 = require("@iservice365/node-server-utils");
|
|
134
|
+
function useAreaRepository() {
|
|
135
|
+
const db = import_node_server_utils2.useAtlas.getDb();
|
|
136
|
+
if (!db) {
|
|
137
|
+
throw new import_node_server_utils2.InternalServerError("Unable to connect to server.");
|
|
138
|
+
}
|
|
139
|
+
const namespace_collection = "hygiene-areas";
|
|
140
|
+
const collection = db.collection(namespace_collection);
|
|
141
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils2.useCache)(namespace_collection);
|
|
142
|
+
async function createIndex() {
|
|
143
|
+
try {
|
|
144
|
+
await collection.createIndexes([
|
|
145
|
+
{ key: { site: 1 } },
|
|
146
|
+
{ key: { createdBy: 1 } },
|
|
147
|
+
{ key: { status: 1 } }
|
|
148
|
+
]);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
throw new import_node_server_utils2.InternalServerError("Failed to create index on hygiene area.");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function createTextIndex() {
|
|
154
|
+
try {
|
|
155
|
+
await collection.createIndex({ name: "text" });
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw new import_node_server_utils2.InternalServerError(
|
|
158
|
+
"Failed to create text index on hygiene area."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function createUniqueIndex() {
|
|
163
|
+
try {
|
|
164
|
+
await collection.createIndex(
|
|
165
|
+
{ name: 1, site: 1, deletedAt: 1 },
|
|
166
|
+
{ unique: true }
|
|
167
|
+
);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new import_node_server_utils2.InternalServerError(
|
|
170
|
+
"Failed to create unique index on hygiene area."
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function createArea(value, session) {
|
|
175
|
+
try {
|
|
176
|
+
value = MArea(value);
|
|
177
|
+
const res = await collection.insertOne(value, { session });
|
|
178
|
+
delNamespace().then(() => {
|
|
179
|
+
import_node_server_utils2.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
180
|
+
}).catch((err) => {
|
|
181
|
+
import_node_server_utils2.logger.error(
|
|
182
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
183
|
+
err
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
return res.insertedId;
|
|
187
|
+
} catch (error) {
|
|
188
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
189
|
+
if (isDuplicated) {
|
|
190
|
+
throw new import_node_server_utils2.BadRequestError("Area already exists.");
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function getAreas({
|
|
196
|
+
page = 1,
|
|
197
|
+
limit = 10,
|
|
198
|
+
search = "",
|
|
199
|
+
startDate = "",
|
|
200
|
+
endDate = "",
|
|
201
|
+
site = ""
|
|
202
|
+
}) {
|
|
203
|
+
page = page > 0 ? page - 1 : 0;
|
|
204
|
+
const query = {
|
|
205
|
+
status: { $ne: "deleted" }
|
|
206
|
+
};
|
|
207
|
+
const cacheOptions = {
|
|
208
|
+
page,
|
|
209
|
+
limit
|
|
210
|
+
};
|
|
211
|
+
if (site) {
|
|
212
|
+
try {
|
|
213
|
+
site = new import_mongodb2.ObjectId(site);
|
|
214
|
+
cacheOptions.site = site.toString();
|
|
215
|
+
} catch (error) {
|
|
216
|
+
throw new import_node_server_utils2.BadRequestError("Invalid site ID format.");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (search) {
|
|
220
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
221
|
+
cacheOptions.search = search;
|
|
222
|
+
}
|
|
223
|
+
if (startDate && endDate) {
|
|
224
|
+
query.createdAt = {
|
|
225
|
+
$gte: new Date(startDate),
|
|
226
|
+
$lte: new Date(endDate)
|
|
227
|
+
};
|
|
228
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
229
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
230
|
+
} else if (startDate) {
|
|
231
|
+
query.createdAt = { $gte: new Date(startDate) };
|
|
232
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
233
|
+
} else if (endDate) {
|
|
234
|
+
query.createdAt = { $lte: new Date(endDate) };
|
|
235
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
236
|
+
}
|
|
237
|
+
const cacheKey = (0, import_node_server_utils2.makeCacheKey)(namespace_collection, cacheOptions);
|
|
238
|
+
const cachedData = await getCache(cacheKey);
|
|
239
|
+
if (cachedData) {
|
|
240
|
+
import_node_server_utils2.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
241
|
+
return cachedData;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const items = await collection.aggregate([
|
|
245
|
+
{ $match: query },
|
|
246
|
+
{
|
|
247
|
+
$lookup: {
|
|
248
|
+
from: "sites",
|
|
249
|
+
localField: "site",
|
|
250
|
+
foreignField: "_id",
|
|
251
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
252
|
+
as: "site"
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
$unwind: {
|
|
257
|
+
path: "$site",
|
|
258
|
+
preserveNullAndEmptyArrays: true
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
$lookup: {
|
|
263
|
+
from: "users",
|
|
264
|
+
localField: "createdBy",
|
|
265
|
+
foreignField: "_id",
|
|
266
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
267
|
+
as: "createdBy"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
$unwind: {
|
|
272
|
+
path: "$createdBy",
|
|
273
|
+
preserveNullAndEmptyArrays: true
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
$project: {
|
|
278
|
+
name: 1,
|
|
279
|
+
site: "$site._id",
|
|
280
|
+
siteName: "$site.name",
|
|
281
|
+
createdByName: "$createdBy.name",
|
|
282
|
+
checklist: 1,
|
|
283
|
+
status: 1,
|
|
284
|
+
createdAt: 1
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
{ $sort: { _id: -1 } },
|
|
288
|
+
{ $skip: page * limit },
|
|
289
|
+
{ $limit: limit }
|
|
290
|
+
]).toArray();
|
|
291
|
+
const length = await collection.countDocuments(query);
|
|
292
|
+
const data = (0, import_node_server_utils2.paginate)(items, page, limit, length);
|
|
293
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
294
|
+
import_node_server_utils2.logger.info(`Cache set for key: ${cacheKey}`);
|
|
295
|
+
}).catch((err) => {
|
|
296
|
+
import_node_server_utils2.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
297
|
+
});
|
|
298
|
+
return data;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async function getAreaById(_id) {
|
|
304
|
+
try {
|
|
305
|
+
_id = new import_mongodb2.ObjectId(_id);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw new import_node_server_utils2.BadRequestError("Invalid area ID format.");
|
|
308
|
+
}
|
|
309
|
+
const query = {
|
|
310
|
+
_id,
|
|
311
|
+
status: { $ne: "deleted" }
|
|
312
|
+
};
|
|
313
|
+
const cacheKey = (0, import_node_server_utils2.makeCacheKey)(namespace_collection, {
|
|
314
|
+
_id: _id.toString()
|
|
315
|
+
});
|
|
316
|
+
const cachedData = await getCache(cacheKey);
|
|
317
|
+
if (cachedData) {
|
|
318
|
+
import_node_server_utils2.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
319
|
+
return cachedData;
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
const data = await collection.aggregate([
|
|
323
|
+
{ $match: query },
|
|
324
|
+
{
|
|
325
|
+
$project: {
|
|
326
|
+
name: 1,
|
|
327
|
+
checklist: 1
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
]).toArray();
|
|
331
|
+
if (!data || !data.length) {
|
|
332
|
+
throw new import_node_server_utils2.NotFoundError("Area not found.");
|
|
333
|
+
}
|
|
334
|
+
setCache(cacheKey, data[0], 15 * 60).then(() => {
|
|
335
|
+
import_node_server_utils2.logger.info(`Cache set for key: ${cacheKey}`);
|
|
336
|
+
}).catch((err) => {
|
|
337
|
+
import_node_server_utils2.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
338
|
+
});
|
|
339
|
+
return data[0];
|
|
340
|
+
} catch (error) {
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async function getAreaByName(name, site) {
|
|
345
|
+
try {
|
|
346
|
+
if (site)
|
|
347
|
+
site = new import_mongodb2.ObjectId(site);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
throw new import_node_server_utils2.BadRequestError("Invalid site ID format.");
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
return await collection.findOne({
|
|
353
|
+
name: { $regex: new RegExp(`^${name}$`, "i") },
|
|
354
|
+
...site && { site }
|
|
355
|
+
});
|
|
356
|
+
} catch (error) {
|
|
357
|
+
throw new import_node_server_utils2.BadRequestError("Unable to fetch area by name.");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function updateArea(_id, value) {
|
|
361
|
+
try {
|
|
362
|
+
_id = new import_mongodb2.ObjectId(_id);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
throw new import_node_server_utils2.BadRequestError("Invalid area ID format.");
|
|
365
|
+
}
|
|
366
|
+
try {
|
|
367
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
368
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
369
|
+
if (res.modifiedCount === 0) {
|
|
370
|
+
throw new import_node_server_utils2.InternalServerError("Unable to update cleaning area.");
|
|
371
|
+
}
|
|
372
|
+
delNamespace().then(() => {
|
|
373
|
+
import_node_server_utils2.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
374
|
+
}).catch((err) => {
|
|
375
|
+
import_node_server_utils2.logger.error(
|
|
376
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
377
|
+
err
|
|
378
|
+
);
|
|
379
|
+
});
|
|
380
|
+
return res.modifiedCount;
|
|
381
|
+
} catch (error) {
|
|
382
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
383
|
+
if (isDuplicated) {
|
|
384
|
+
throw new import_node_server_utils2.BadRequestError("Area already exists.");
|
|
385
|
+
}
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async function updateAreaChecklist(_id, value) {
|
|
390
|
+
try {
|
|
391
|
+
_id = new import_mongodb2.ObjectId(_id);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
throw new import_node_server_utils2.BadRequestError("Invalid area ID format.");
|
|
394
|
+
}
|
|
395
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
396
|
+
value.checklist = value.checklist.map((item) => {
|
|
397
|
+
try {
|
|
398
|
+
return {
|
|
399
|
+
...item,
|
|
400
|
+
_id: new import_mongodb2.ObjectId(item._id)
|
|
401
|
+
};
|
|
402
|
+
} catch (error) {
|
|
403
|
+
throw new import_node_server_utils2.BadRequestError(
|
|
404
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
411
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
412
|
+
if (res.modifiedCount === 0) {
|
|
413
|
+
throw new import_node_server_utils2.InternalServerError("Unable to update cleaning area.");
|
|
414
|
+
}
|
|
415
|
+
delNamespace().then(() => {
|
|
416
|
+
import_node_server_utils2.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
417
|
+
}).catch((err) => {
|
|
418
|
+
import_node_server_utils2.logger.error(
|
|
419
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
420
|
+
err
|
|
421
|
+
);
|
|
422
|
+
});
|
|
423
|
+
return res.modifiedCount;
|
|
424
|
+
} catch (error) {
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async function deleteArea(_id, session) {
|
|
429
|
+
try {
|
|
430
|
+
_id = new import_mongodb2.ObjectId(_id);
|
|
431
|
+
} catch (error) {
|
|
432
|
+
throw new import_node_server_utils2.BadRequestError("Invalid area ID format.");
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const updateValue = {
|
|
436
|
+
status: "deleted",
|
|
437
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
438
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
439
|
+
};
|
|
440
|
+
const res = await collection.updateOne(
|
|
441
|
+
{ _id },
|
|
442
|
+
{ $set: updateValue },
|
|
443
|
+
{ session }
|
|
444
|
+
);
|
|
445
|
+
if (res.modifiedCount === 0) {
|
|
446
|
+
throw new import_node_server_utils2.InternalServerError("Unable to delete area.");
|
|
447
|
+
}
|
|
448
|
+
delNamespace().then(() => {
|
|
449
|
+
import_node_server_utils2.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
450
|
+
}).catch((err) => {
|
|
451
|
+
import_node_server_utils2.logger.error(
|
|
452
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
453
|
+
err
|
|
454
|
+
);
|
|
455
|
+
});
|
|
456
|
+
return res.modifiedCount;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
throw error;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
createIndex,
|
|
463
|
+
createTextIndex,
|
|
464
|
+
createUniqueIndex,
|
|
465
|
+
createArea,
|
|
466
|
+
getAreas,
|
|
467
|
+
getAreaById,
|
|
468
|
+
getAreaByName,
|
|
469
|
+
updateArea,
|
|
470
|
+
updateAreaChecklist,
|
|
471
|
+
deleteArea
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/services/hygiene-area.service.ts
|
|
476
|
+
var import_node_server_utils3 = require("@iservice365/node-server-utils");
|
|
477
|
+
function useAreaService() {
|
|
478
|
+
const { createArea: _createArea } = useAreaRepository();
|
|
479
|
+
async function uploadByFile({
|
|
480
|
+
dataJson,
|
|
481
|
+
createdBy,
|
|
482
|
+
site
|
|
483
|
+
}) {
|
|
484
|
+
let dataArray;
|
|
485
|
+
try {
|
|
486
|
+
dataArray = JSON.parse(dataJson);
|
|
487
|
+
} catch (error) {
|
|
488
|
+
throw new import_node_server_utils3.BadRequestError("Invalid JSON format for data in excel");
|
|
489
|
+
}
|
|
490
|
+
if (!dataArray || dataArray.length === 0) {
|
|
491
|
+
throw new import_node_server_utils3.NotFoundError("No data found in the uploaded file");
|
|
492
|
+
}
|
|
493
|
+
const session = import_node_server_utils3.useAtlas.getClient()?.startSession();
|
|
494
|
+
const insertedAreaIds = [];
|
|
495
|
+
try {
|
|
496
|
+
session?.startTransaction();
|
|
497
|
+
for (const row of dataArray) {
|
|
498
|
+
if (!row?.AREA_NAME) {
|
|
499
|
+
import_node_server_utils3.logger.warn("Skipping row with missing AREA_NAME:", row);
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
const insertedId = await _createArea(
|
|
504
|
+
{
|
|
505
|
+
name: String(row.AREA_NAME).trim(),
|
|
506
|
+
site,
|
|
507
|
+
createdBy
|
|
508
|
+
},
|
|
509
|
+
session
|
|
510
|
+
);
|
|
511
|
+
insertedAreaIds.push(insertedId);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
import_node_server_utils3.logger.error(
|
|
514
|
+
`Error creating area "${row.AREA_NAME}":`,
|
|
515
|
+
error.message
|
|
516
|
+
);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
await session?.commitTransaction();
|
|
521
|
+
import_node_server_utils3.logger.info(`Successfully uploaded ${insertedAreaIds.length} areas`);
|
|
522
|
+
return {
|
|
523
|
+
message: `Successfully uploaded ${insertedAreaIds.length} areas`
|
|
524
|
+
};
|
|
525
|
+
} catch (error) {
|
|
526
|
+
await session?.abortTransaction();
|
|
527
|
+
import_node_server_utils3.logger.error("Error while uploading area information", error);
|
|
528
|
+
throw error;
|
|
529
|
+
} finally {
|
|
530
|
+
session?.endSession();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
uploadByFile
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/controllers/hygiene-area.controller.ts
|
|
539
|
+
var import_node_server_utils4 = require("@iservice365/node-server-utils");
|
|
540
|
+
var import_joi2 = __toESM(require("joi"));
|
|
541
|
+
|
|
542
|
+
// src/utils/convert-excel.util.ts
|
|
543
|
+
var import_stream = require("stream");
|
|
544
|
+
var xlsx = __toESM(require("xlsx"));
|
|
545
|
+
function convertBufferFile(bufferFile) {
|
|
546
|
+
return new Promise((resolve, reject) => {
|
|
547
|
+
const fileStream = import_stream.Readable.from(bufferFile);
|
|
548
|
+
let fileBuffer = Buffer.alloc(0);
|
|
549
|
+
fileStream.on("data", (chunk) => {
|
|
550
|
+
fileBuffer = Buffer.concat([fileBuffer, chunk]);
|
|
551
|
+
});
|
|
552
|
+
fileStream.on("end", () => {
|
|
553
|
+
try {
|
|
554
|
+
const workbook = xlsx.read(fileBuffer, { type: "buffer" });
|
|
555
|
+
const sheetName = workbook.SheetNames[0];
|
|
556
|
+
const sheet = workbook.Sheets[sheetName];
|
|
557
|
+
const jsonData = xlsx.utils.sheet_to_json(sheet);
|
|
558
|
+
resolve(jsonData);
|
|
559
|
+
} catch (error) {
|
|
560
|
+
reject("Error parsing file");
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
fileStream.on("error", (err) => {
|
|
564
|
+
reject("Error Reading File: " + err.message);
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// src/controllers/hygiene-area.controller.ts
|
|
570
|
+
function useAreaController() {
|
|
571
|
+
const {
|
|
572
|
+
createArea: _createArea,
|
|
573
|
+
getAreas: _getAll,
|
|
574
|
+
getAreaById: _getAreaById,
|
|
575
|
+
updateArea: _updateArea,
|
|
576
|
+
updateAreaChecklist: _updateAreaChecklist,
|
|
577
|
+
deleteArea: _deleteById
|
|
578
|
+
} = useAreaRepository();
|
|
579
|
+
const { uploadByFile: _uploadByFile } = useAreaService();
|
|
580
|
+
async function createArea(req, res, next) {
|
|
581
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
582
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
583
|
+
{}
|
|
584
|
+
) : {};
|
|
585
|
+
const createdBy = cookies["user"] || "";
|
|
586
|
+
const payload = { ...req.body, createdBy };
|
|
587
|
+
const { error } = areaSchema.validate(payload);
|
|
588
|
+
if (error) {
|
|
589
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
590
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
try {
|
|
594
|
+
const id = await _createArea(payload);
|
|
595
|
+
res.status(201).json({ message: "Area created successfully.", id });
|
|
596
|
+
return;
|
|
597
|
+
} catch (error2) {
|
|
598
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
599
|
+
next(error2);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async function getAll(req, res, next) {
|
|
604
|
+
const query = req.query;
|
|
605
|
+
const validation = import_joi2.default.object({
|
|
606
|
+
page: import_joi2.default.number().min(1).optional().allow("", null),
|
|
607
|
+
limit: import_joi2.default.number().min(1).optional().allow("", null),
|
|
608
|
+
search: import_joi2.default.string().optional().allow("", null),
|
|
609
|
+
startDate: import_joi2.default.alternatives().try(import_joi2.default.date(), import_joi2.default.string()).optional().allow("", null),
|
|
610
|
+
endDate: import_joi2.default.alternatives().try(import_joi2.default.date(), import_joi2.default.string()).optional().allow("", null),
|
|
611
|
+
site: import_joi2.default.string().hex().optional().allow("", null)
|
|
612
|
+
});
|
|
613
|
+
const { error } = validation.validate(query);
|
|
614
|
+
if (error) {
|
|
615
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
619
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
620
|
+
const search = req.query.search ?? "";
|
|
621
|
+
const site = req.query.site ?? "";
|
|
622
|
+
const startDate = req.query.startDate ?? "";
|
|
623
|
+
const endDate = req.query.endDate ?? "";
|
|
624
|
+
try {
|
|
625
|
+
const data = await _getAll({
|
|
626
|
+
page,
|
|
627
|
+
limit,
|
|
628
|
+
search,
|
|
629
|
+
site,
|
|
630
|
+
startDate,
|
|
631
|
+
endDate
|
|
632
|
+
});
|
|
633
|
+
res.json(data);
|
|
634
|
+
return;
|
|
635
|
+
} catch (error2) {
|
|
636
|
+
next(error2);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
async function getAreaById(req, res, next) {
|
|
641
|
+
const validation = import_joi2.default.string().hex().required();
|
|
642
|
+
const _id = req.params.id;
|
|
643
|
+
const { error } = validation.validate(_id);
|
|
644
|
+
if (error) {
|
|
645
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
646
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
try {
|
|
650
|
+
const data = await _getAreaById(_id);
|
|
651
|
+
res.json(data);
|
|
652
|
+
return;
|
|
653
|
+
} catch (error2) {
|
|
654
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
655
|
+
next(error2);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async function updateArea(req, res, next) {
|
|
660
|
+
const payload = { id: req.params.id, ...req.body };
|
|
661
|
+
const schema = import_joi2.default.object({
|
|
662
|
+
id: import_joi2.default.string().hex().required(),
|
|
663
|
+
name: import_joi2.default.string().required()
|
|
664
|
+
});
|
|
665
|
+
const { error } = schema.validate(payload);
|
|
666
|
+
if (error) {
|
|
667
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
668
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
try {
|
|
672
|
+
const { id, ...value } = payload;
|
|
673
|
+
await _updateArea(id, value);
|
|
674
|
+
res.json({ message: "Area updated successfully." });
|
|
675
|
+
return;
|
|
676
|
+
} catch (error2) {
|
|
677
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
678
|
+
next(error2);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
async function updateAreaChecklist(req, res, next) {
|
|
683
|
+
const payload = { id: req.params.id, ...req.body };
|
|
684
|
+
const schema = import_joi2.default.object({
|
|
685
|
+
id: import_joi2.default.string().hex().required(),
|
|
686
|
+
checklist: import_joi2.default.array().items(
|
|
687
|
+
import_joi2.default.object({
|
|
688
|
+
_id: import_joi2.default.string().hex().required(),
|
|
689
|
+
name: import_joi2.default.string().required()
|
|
690
|
+
}).required()
|
|
691
|
+
).min(1).unique("_id", { ignoreUndefined: true }).messages({
|
|
692
|
+
"array.unique": "Duplicate checklist items are not allowed"
|
|
693
|
+
})
|
|
694
|
+
});
|
|
695
|
+
const { error } = schema.validate(payload);
|
|
696
|
+
if (error) {
|
|
697
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
698
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
const { id, ...value } = payload;
|
|
703
|
+
await _updateAreaChecklist(id, value);
|
|
704
|
+
res.json({ message: "Area updated successfully." });
|
|
705
|
+
return;
|
|
706
|
+
} catch (error2) {
|
|
707
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
708
|
+
next(error2);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
async function deleteArea(req, res, next) {
|
|
713
|
+
const id = req.params.id;
|
|
714
|
+
const validation = import_joi2.default.object({
|
|
715
|
+
id: import_joi2.default.string().hex().required()
|
|
716
|
+
});
|
|
717
|
+
const { error } = validation.validate({ id });
|
|
718
|
+
if (error) {
|
|
719
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
720
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
try {
|
|
724
|
+
await _deleteById(id);
|
|
725
|
+
res.json({ message: "Area deleted successfully." });
|
|
726
|
+
return;
|
|
727
|
+
} catch (error2) {
|
|
728
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
729
|
+
next(error2);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async function uploadByFile(req, res, next) {
|
|
734
|
+
if (!req.file) {
|
|
735
|
+
next(new import_node_server_utils4.BadRequestError("File is required!"));
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
739
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
740
|
+
{}
|
|
741
|
+
) : {};
|
|
742
|
+
const createdBy = cookies["user"] || "";
|
|
743
|
+
const { site } = req.body;
|
|
744
|
+
const schema = import_joi2.default.object({
|
|
745
|
+
site: import_joi2.default.string().hex().optional().allow("", null),
|
|
746
|
+
createdBy: import_joi2.default.string().hex().required()
|
|
747
|
+
});
|
|
748
|
+
const { error } = schema.validate({ site, createdBy });
|
|
749
|
+
if (error) {
|
|
750
|
+
import_node_server_utils4.logger.log({ level: "error", message: error.message });
|
|
751
|
+
next(new import_node_server_utils4.BadRequestError(error.message));
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
try {
|
|
755
|
+
const xlsData = await convertBufferFile(req.file.buffer);
|
|
756
|
+
const dataJson = JSON.stringify(xlsData);
|
|
757
|
+
const result = await _uploadByFile({ dataJson, createdBy, site });
|
|
758
|
+
return res.status(201).json(result);
|
|
759
|
+
} catch (error2) {
|
|
760
|
+
import_node_server_utils4.logger.log({ level: "error", message: error2.message });
|
|
761
|
+
next(error2);
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
createArea,
|
|
767
|
+
getAll,
|
|
768
|
+
getAreaById,
|
|
769
|
+
updateArea,
|
|
770
|
+
updateAreaChecklist,
|
|
771
|
+
deleteArea,
|
|
772
|
+
uploadByFile
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/models/hygiene-toilet-location.model.ts
|
|
777
|
+
var import_node_server_utils5 = require("@iservice365/node-server-utils");
|
|
778
|
+
var import_joi3 = __toESM(require("joi"));
|
|
779
|
+
var import_mongodb3 = require("mongodb");
|
|
780
|
+
var toiletLocationSchema = import_joi3.default.object({
|
|
781
|
+
name: import_joi3.default.string().required(),
|
|
782
|
+
site: import_joi3.default.string().hex().required(),
|
|
783
|
+
createdBy: import_joi3.default.string().hex().required(),
|
|
784
|
+
checklist: import_joi3.default.array().items(
|
|
785
|
+
import_joi3.default.object({
|
|
786
|
+
_id: import_joi3.default.string().hex().required(),
|
|
787
|
+
name: import_joi3.default.string().required()
|
|
788
|
+
})
|
|
789
|
+
).optional(),
|
|
790
|
+
updatedAt: import_joi3.default.date().optional().allow("", null),
|
|
791
|
+
status: import_joi3.default.string().allow("", null).optional()
|
|
792
|
+
});
|
|
793
|
+
function MToiletLocation(value) {
|
|
794
|
+
const { error } = toiletLocationSchema.validate(value);
|
|
795
|
+
if (error) {
|
|
796
|
+
throw new import_node_server_utils5.BadRequestError(error.message);
|
|
797
|
+
}
|
|
798
|
+
if (value.site) {
|
|
799
|
+
try {
|
|
800
|
+
value.site = new import_mongodb3.ObjectId(value.site);
|
|
801
|
+
} catch (error2) {
|
|
802
|
+
throw new import_node_server_utils5.BadRequestError("Invalid site ID format.");
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (value.createdBy) {
|
|
806
|
+
try {
|
|
807
|
+
value.createdBy = new import_mongodb3.ObjectId(value.createdBy);
|
|
808
|
+
} catch (error2) {
|
|
809
|
+
throw new import_node_server_utils5.BadRequestError("Invalid createdBy ID format.");
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
813
|
+
value.checklist = value.checklist.map((item) => {
|
|
814
|
+
try {
|
|
815
|
+
return {
|
|
816
|
+
...item,
|
|
817
|
+
_id: new import_mongodb3.ObjectId(item._id)
|
|
818
|
+
};
|
|
819
|
+
} catch (error2) {
|
|
820
|
+
throw new import_node_server_utils5.BadRequestError(
|
|
821
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
return {
|
|
827
|
+
name: value.name,
|
|
828
|
+
site: value.site,
|
|
829
|
+
createdBy: value.createdBy,
|
|
830
|
+
checklist: value.checklist,
|
|
831
|
+
status: value.status ?? "",
|
|
832
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
833
|
+
updatedAt: value.updatedAt ?? "",
|
|
834
|
+
deletedAt: value.deletedAt ?? ""
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/repositories/hygiene-toilet-location.repository.ts
|
|
839
|
+
var import_mongodb4 = require("mongodb");
|
|
840
|
+
var import_node_server_utils6 = require("@iservice365/node-server-utils");
|
|
841
|
+
function useToiletLocationRepository() {
|
|
842
|
+
const db = import_node_server_utils6.useAtlas.getDb();
|
|
843
|
+
if (!db) {
|
|
844
|
+
throw new import_node_server_utils6.InternalServerError("Unable to connect to server.");
|
|
845
|
+
}
|
|
846
|
+
const namespace_collection = "hygiene-toilet-locations";
|
|
847
|
+
const collection = db.collection(namespace_collection);
|
|
848
|
+
const { delNamespace, setCache, getCache, delCache } = (0, import_node_server_utils6.useCache)(namespace_collection);
|
|
849
|
+
async function createIndexes() {
|
|
850
|
+
try {
|
|
851
|
+
await collection.createIndexes([
|
|
852
|
+
{ key: { site: 1 } },
|
|
853
|
+
{ key: { name: "text" } }
|
|
854
|
+
]);
|
|
855
|
+
} catch (error) {
|
|
856
|
+
throw new import_node_server_utils6.InternalServerError("Failed to create index on site.");
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
async function createUniqueIndex() {
|
|
860
|
+
try {
|
|
861
|
+
await collection.createIndex(
|
|
862
|
+
{ name: 1, site: 1, deletedAt: 1 },
|
|
863
|
+
{ unique: true }
|
|
864
|
+
);
|
|
865
|
+
} catch (error) {
|
|
866
|
+
throw new import_node_server_utils6.InternalServerError(
|
|
867
|
+
"Failed to create unique index on hygiene area."
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
async function create(value, session) {
|
|
872
|
+
try {
|
|
873
|
+
value = MToiletLocation(value);
|
|
874
|
+
const res = await collection.insertOne(value, { session });
|
|
875
|
+
delNamespace().then(() => {
|
|
876
|
+
import_node_server_utils6.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
877
|
+
}).catch((err) => {
|
|
878
|
+
import_node_server_utils6.logger.error(
|
|
879
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
880
|
+
err
|
|
881
|
+
);
|
|
882
|
+
});
|
|
883
|
+
return res.insertedId;
|
|
884
|
+
} catch (error) {
|
|
885
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
886
|
+
if (isDuplicated) {
|
|
887
|
+
throw new import_node_server_utils6.BadRequestError("Toilet location already exists.");
|
|
888
|
+
}
|
|
889
|
+
throw error;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async function updateToiletLocation(_id, value) {
|
|
893
|
+
try {
|
|
894
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
895
|
+
} catch (error) {
|
|
896
|
+
throw new import_node_server_utils6.BadRequestError("Invalid area ID format.");
|
|
897
|
+
}
|
|
898
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
899
|
+
value.checklist = value.checklist.map((item) => {
|
|
900
|
+
try {
|
|
901
|
+
return {
|
|
902
|
+
...item,
|
|
903
|
+
_id: new import_mongodb4.ObjectId(item._id)
|
|
904
|
+
};
|
|
905
|
+
} catch (error) {
|
|
906
|
+
throw new import_node_server_utils6.BadRequestError(
|
|
907
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
try {
|
|
913
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
914
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
915
|
+
if (res.modifiedCount === 0) {
|
|
916
|
+
throw new import_node_server_utils6.InternalServerError("Unable to update toilet location.");
|
|
917
|
+
}
|
|
918
|
+
delNamespace().then(() => {
|
|
919
|
+
import_node_server_utils6.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
920
|
+
}).catch((err) => {
|
|
921
|
+
import_node_server_utils6.logger.error(
|
|
922
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
923
|
+
err
|
|
924
|
+
);
|
|
925
|
+
});
|
|
926
|
+
return res.modifiedCount;
|
|
927
|
+
} catch (error) {
|
|
928
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
929
|
+
if (isDuplicated) {
|
|
930
|
+
throw new import_node_server_utils6.BadRequestError("Toilet location already exists.");
|
|
931
|
+
}
|
|
932
|
+
throw error;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
async function deleteToiletLocation(_id, session) {
|
|
936
|
+
try {
|
|
937
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
938
|
+
} catch (error) {
|
|
939
|
+
throw new import_node_server_utils6.BadRequestError("Invalid area ID format.");
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
const updateValue = {
|
|
943
|
+
status: "deleted",
|
|
944
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
945
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
946
|
+
};
|
|
947
|
+
const res = await collection.updateOne(
|
|
948
|
+
{ _id },
|
|
949
|
+
{ $set: updateValue },
|
|
950
|
+
{ session }
|
|
951
|
+
);
|
|
952
|
+
if (res.modifiedCount === 0) {
|
|
953
|
+
throw new import_node_server_utils6.InternalServerError("Unable to delete toilet location.");
|
|
954
|
+
}
|
|
955
|
+
delNamespace().then(() => {
|
|
956
|
+
import_node_server_utils6.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
957
|
+
}).catch((err) => {
|
|
958
|
+
import_node_server_utils6.logger.error(
|
|
959
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
960
|
+
err
|
|
961
|
+
);
|
|
962
|
+
});
|
|
963
|
+
return res.modifiedCount;
|
|
964
|
+
} catch (error) {
|
|
965
|
+
throw error;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async function getToiletLocations({
|
|
969
|
+
page = 1,
|
|
970
|
+
limit = 10,
|
|
971
|
+
search = "",
|
|
972
|
+
sort = {},
|
|
973
|
+
startDate = "",
|
|
974
|
+
endDate = "",
|
|
975
|
+
site = ""
|
|
976
|
+
}) {
|
|
977
|
+
page = page > 0 ? page - 1 : 0;
|
|
978
|
+
let dateFilter = {};
|
|
979
|
+
try {
|
|
980
|
+
site = new import_mongodb4.ObjectId(site);
|
|
981
|
+
} catch (error) {
|
|
982
|
+
throw new import_node_server_utils6.BadRequestError("Invalid site ID format.");
|
|
983
|
+
}
|
|
984
|
+
const query = {
|
|
985
|
+
status: { $ne: "deleted" }
|
|
986
|
+
};
|
|
987
|
+
const cacheOptions = {
|
|
988
|
+
site: site.toString()
|
|
989
|
+
};
|
|
990
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
991
|
+
cacheOptions.sort = JSON.stringify(sort);
|
|
992
|
+
if (search) {
|
|
993
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
994
|
+
cacheOptions.search = search;
|
|
995
|
+
}
|
|
996
|
+
delNamespace().then(() => {
|
|
997
|
+
import_node_server_utils6.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
998
|
+
}).catch((err) => {
|
|
999
|
+
import_node_server_utils6.logger.error(
|
|
1000
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1001
|
+
err
|
|
1002
|
+
);
|
|
1003
|
+
});
|
|
1004
|
+
const cacheKey = (0, import_node_server_utils6.makeCacheKey)(namespace_collection, cacheOptions);
|
|
1005
|
+
const cachedData = await getCache(cacheKey);
|
|
1006
|
+
if (cachedData) {
|
|
1007
|
+
import_node_server_utils6.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
1008
|
+
return cachedData;
|
|
1009
|
+
}
|
|
1010
|
+
if (startDate && endDate) {
|
|
1011
|
+
dateFilter = {
|
|
1012
|
+
createdAt: {
|
|
1013
|
+
$gte: new Date(startDate),
|
|
1014
|
+
$lte: new Date(endDate)
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
} else if (startDate) {
|
|
1018
|
+
dateFilter = { createdAt: { $gte: new Date(startDate) } };
|
|
1019
|
+
} else if (endDate) {
|
|
1020
|
+
dateFilter = { createdAt: { $lte: new Date(endDate) } };
|
|
1021
|
+
}
|
|
1022
|
+
try {
|
|
1023
|
+
const items = await collection.aggregate([
|
|
1024
|
+
{
|
|
1025
|
+
$match: {
|
|
1026
|
+
...dateFilter,
|
|
1027
|
+
...query
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
$lookup: {
|
|
1032
|
+
from: "sites",
|
|
1033
|
+
localField: "site",
|
|
1034
|
+
foreignField: "_id",
|
|
1035
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
1036
|
+
as: "site"
|
|
1037
|
+
}
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
$unwind: {
|
|
1041
|
+
path: "$site",
|
|
1042
|
+
preserveNullAndEmptyArrays: true
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
$lookup: {
|
|
1047
|
+
from: "users",
|
|
1048
|
+
localField: "createdBy",
|
|
1049
|
+
foreignField: "_id",
|
|
1050
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
1051
|
+
as: "createdBy"
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
$unwind: {
|
|
1056
|
+
path: "$createdBy",
|
|
1057
|
+
preserveNullAndEmptyArrays: true
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
$project: {
|
|
1062
|
+
name: 1,
|
|
1063
|
+
site: "$site._id",
|
|
1064
|
+
siteName: "$site.name",
|
|
1065
|
+
createdByName: "$createdBy.name",
|
|
1066
|
+
checklist: 1,
|
|
1067
|
+
status: 1,
|
|
1068
|
+
createdAt: 1
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
{ $sort: { _id: -1 } },
|
|
1072
|
+
{ $skip: page * limit },
|
|
1073
|
+
{ $limit: limit }
|
|
1074
|
+
]).toArray();
|
|
1075
|
+
const length = await collection.countDocuments(query);
|
|
1076
|
+
const data = (0, import_node_server_utils6.paginate)(items, page, limit, length);
|
|
1077
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
1078
|
+
import_node_server_utils6.logger.info(`Cache set for key: ${cacheKey}`);
|
|
1079
|
+
}).catch((err) => {
|
|
1080
|
+
import_node_server_utils6.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
1081
|
+
});
|
|
1082
|
+
return data;
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
throw error;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
async function getToiletLocationByName(name, site) {
|
|
1088
|
+
try {
|
|
1089
|
+
if (site)
|
|
1090
|
+
site = new import_mongodb4.ObjectId(site);
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
throw new import_node_server_utils6.BadRequestError("Invalid site ID format.");
|
|
1093
|
+
}
|
|
1094
|
+
try {
|
|
1095
|
+
return await collection.findOne({
|
|
1096
|
+
name: { $regex: new RegExp(`^${name}$`, "i") },
|
|
1097
|
+
...site && { site }
|
|
1098
|
+
});
|
|
1099
|
+
} catch (error) {
|
|
1100
|
+
throw new import_node_server_utils6.BadRequestError("Unable to fetch toilet location by name.");
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
async function updateToiletLocationChecklist(_id, value) {
|
|
1104
|
+
try {
|
|
1105
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
throw new import_node_server_utils6.BadRequestError("Invalid area ID format.");
|
|
1108
|
+
}
|
|
1109
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
1110
|
+
value.checklist = value.checklist.map((item) => {
|
|
1111
|
+
try {
|
|
1112
|
+
return {
|
|
1113
|
+
...item,
|
|
1114
|
+
_id: new import_mongodb4.ObjectId(item._id)
|
|
1115
|
+
};
|
|
1116
|
+
} catch (error) {
|
|
1117
|
+
throw new import_node_server_utils6.BadRequestError(
|
|
1118
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
try {
|
|
1124
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
1125
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
1126
|
+
if (res.modifiedCount === 0) {
|
|
1127
|
+
throw new import_node_server_utils6.InternalServerError("Unable to update toilet location.");
|
|
1128
|
+
}
|
|
1129
|
+
delNamespace().then(() => {
|
|
1130
|
+
import_node_server_utils6.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
1131
|
+
}).catch((err) => {
|
|
1132
|
+
import_node_server_utils6.logger.error(
|
|
1133
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1134
|
+
err
|
|
1135
|
+
);
|
|
1136
|
+
});
|
|
1137
|
+
return res.modifiedCount;
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
throw error;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
async function getToiletLocationById(_id) {
|
|
1143
|
+
try {
|
|
1144
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
throw new import_node_server_utils6.BadRequestError("Invalid area ID format.");
|
|
1147
|
+
}
|
|
1148
|
+
const query = {
|
|
1149
|
+
_id,
|
|
1150
|
+
status: { $ne: "deleted" }
|
|
1151
|
+
};
|
|
1152
|
+
const cacheKey = (0, import_node_server_utils6.makeCacheKey)(namespace_collection, {
|
|
1153
|
+
_id: _id.toString()
|
|
1154
|
+
});
|
|
1155
|
+
const cachedData = await getCache(cacheKey);
|
|
1156
|
+
if (cachedData) {
|
|
1157
|
+
import_node_server_utils6.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
1158
|
+
return cachedData;
|
|
1159
|
+
}
|
|
1160
|
+
try {
|
|
1161
|
+
const data = await collection.aggregate([
|
|
1162
|
+
{ $match: query },
|
|
1163
|
+
{
|
|
1164
|
+
$project: {
|
|
1165
|
+
name: 1,
|
|
1166
|
+
checklist: 1
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
]).toArray();
|
|
1170
|
+
if (!data || !data.length) {
|
|
1171
|
+
throw new import_node_server_utils6.NotFoundError("Area not found.");
|
|
1172
|
+
}
|
|
1173
|
+
setCache(cacheKey, data[0], 15 * 60).then(() => {
|
|
1174
|
+
import_node_server_utils6.logger.info(`Cache set for key: ${cacheKey}`);
|
|
1175
|
+
}).catch((err) => {
|
|
1176
|
+
import_node_server_utils6.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
1177
|
+
});
|
|
1178
|
+
return data[0];
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
throw error;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return {
|
|
1184
|
+
createIndexes,
|
|
1185
|
+
createUniqueIndex,
|
|
1186
|
+
getToiletLocations,
|
|
1187
|
+
create,
|
|
1188
|
+
updateToiletLocation,
|
|
1189
|
+
deleteToiletLocation,
|
|
1190
|
+
getToiletLocationByName,
|
|
1191
|
+
getToiletLocationById,
|
|
1192
|
+
updateToiletLocationChecklist
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// src/services/hygiene-toilet-location.service.ts
|
|
1197
|
+
var import_node_server_utils7 = require("@iservice365/node-server-utils");
|
|
1198
|
+
function useToiletLocationService() {
|
|
1199
|
+
const { create: _createToilet } = useToiletLocationRepository();
|
|
1200
|
+
async function uploadByFile({
|
|
1201
|
+
dataJson,
|
|
1202
|
+
createdBy,
|
|
1203
|
+
site
|
|
1204
|
+
}) {
|
|
1205
|
+
let dataArray;
|
|
1206
|
+
try {
|
|
1207
|
+
dataArray = JSON.parse(dataJson);
|
|
1208
|
+
} catch (error) {
|
|
1209
|
+
throw new import_node_server_utils7.BadRequestError("Invalid JSON format for data in excel");
|
|
1210
|
+
}
|
|
1211
|
+
if (!dataArray || dataArray.length === 0) {
|
|
1212
|
+
throw new import_node_server_utils7.NotFoundError("No data found in the uploaded file");
|
|
1213
|
+
}
|
|
1214
|
+
const session = import_node_server_utils7.useAtlas.getClient()?.startSession();
|
|
1215
|
+
const insertedAreaIds = [];
|
|
1216
|
+
try {
|
|
1217
|
+
session?.startTransaction();
|
|
1218
|
+
for (const row of dataArray) {
|
|
1219
|
+
if (!row?.AREA_NAME) {
|
|
1220
|
+
import_node_server_utils7.logger.warn("Skipping row with missing TOILET NAME:", row);
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
try {
|
|
1224
|
+
const insertedId = await _createToilet(
|
|
1225
|
+
{
|
|
1226
|
+
name: String(row.TOILET_NAME).trim(),
|
|
1227
|
+
site,
|
|
1228
|
+
createdBy
|
|
1229
|
+
},
|
|
1230
|
+
session
|
|
1231
|
+
);
|
|
1232
|
+
insertedAreaIds.push(insertedId);
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
import_node_server_utils7.logger.error(
|
|
1235
|
+
`Error creating area "${row.AREA_NAME}":`,
|
|
1236
|
+
error.message
|
|
1237
|
+
);
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
await session?.commitTransaction();
|
|
1242
|
+
import_node_server_utils7.logger.info(`Successfully uploaded ${insertedAreaIds.length} areas`);
|
|
1243
|
+
return {
|
|
1244
|
+
message: `Successfully uploaded ${insertedAreaIds.length} areas`
|
|
1245
|
+
};
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
await session?.abortTransaction();
|
|
1248
|
+
import_node_server_utils7.logger.error("Error while uploading area information", error);
|
|
1249
|
+
throw error;
|
|
1250
|
+
} finally {
|
|
1251
|
+
session?.endSession();
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return {
|
|
1255
|
+
uploadByFile
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// src/controllers/hygiene-toilet-location.controller.ts
|
|
1260
|
+
var import_joi4 = __toESM(require("joi"));
|
|
1261
|
+
var import_node_server_utils8 = require("@iservice365/node-server-utils");
|
|
1262
|
+
function useToiletLocationController() {
|
|
1263
|
+
const { uploadByFile: _uploadByFile } = useToiletLocationService();
|
|
1264
|
+
const {
|
|
1265
|
+
create: _createToiletLocation,
|
|
1266
|
+
updateToiletLocation: _updateToiletLocation,
|
|
1267
|
+
updateToiletLocationChecklist: _updateToiletLocationChecklist,
|
|
1268
|
+
getToiletLocationById: _getToiletLocationById,
|
|
1269
|
+
getToiletLocations: _getAll,
|
|
1270
|
+
deleteToiletLocation: _deleteById
|
|
1271
|
+
} = useToiletLocationRepository();
|
|
1272
|
+
async function getAll(req, res, next) {
|
|
1273
|
+
const query = req.query;
|
|
1274
|
+
const validation = import_joi4.default.object({
|
|
1275
|
+
page: import_joi4.default.number().min(1).optional().allow("", null),
|
|
1276
|
+
limit: import_joi4.default.number().min(1).optional().allow("", null),
|
|
1277
|
+
search: import_joi4.default.string().optional().allow("", null),
|
|
1278
|
+
site: import_joi4.default.string().hex().optional().allow("", null)
|
|
1279
|
+
});
|
|
1280
|
+
const { error } = validation.validate(query);
|
|
1281
|
+
if (error) {
|
|
1282
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
1286
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
1287
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
1288
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
1289
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
1290
|
+
const sortObj = {};
|
|
1291
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
1292
|
+
sort.forEach((field, index) => {
|
|
1293
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
const site = req.query.site ?? "";
|
|
1297
|
+
const search = req.query.search ?? "";
|
|
1298
|
+
try {
|
|
1299
|
+
const buildings = await _getAll({
|
|
1300
|
+
page,
|
|
1301
|
+
limit,
|
|
1302
|
+
sort: sortObj,
|
|
1303
|
+
site,
|
|
1304
|
+
search
|
|
1305
|
+
});
|
|
1306
|
+
res.json(buildings);
|
|
1307
|
+
return;
|
|
1308
|
+
} catch (error2) {
|
|
1309
|
+
next(error2);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
async function createToiletLocation(req, res, next) {
|
|
1313
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
1314
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
1315
|
+
{}
|
|
1316
|
+
) : {};
|
|
1317
|
+
const createdBy = cookies["user"] || "";
|
|
1318
|
+
const payload = { ...req.body, createdBy };
|
|
1319
|
+
const schema = import_joi4.default.object({
|
|
1320
|
+
name: import_joi4.default.string().required(),
|
|
1321
|
+
site: import_joi4.default.string().hex().optional().allow("", null),
|
|
1322
|
+
status: import_joi4.default.string().optional().allow("", null),
|
|
1323
|
+
createdBy: import_joi4.default.string().hex().optional().allow("", null)
|
|
1324
|
+
});
|
|
1325
|
+
const { error } = schema.validate(payload);
|
|
1326
|
+
if (error) {
|
|
1327
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1328
|
+
import_node_server_utils8.logger.info(`Controller: ${error.message}`);
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
try {
|
|
1332
|
+
const result = await _createToiletLocation(payload);
|
|
1333
|
+
res.status(201).json(result);
|
|
1334
|
+
return;
|
|
1335
|
+
} catch (error2) {
|
|
1336
|
+
next(error2);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
async function updateToiletLocation(req, res, next) {
|
|
1340
|
+
const payload = { id: req.params.id, ...req.body };
|
|
1341
|
+
const schema = import_joi4.default.object({
|
|
1342
|
+
id: import_joi4.default.string().hex().required(),
|
|
1343
|
+
name: import_joi4.default.string().required(),
|
|
1344
|
+
checklist: import_joi4.default.array().items(
|
|
1345
|
+
import_joi4.default.object({
|
|
1346
|
+
_id: import_joi4.default.string().hex().required(),
|
|
1347
|
+
name: import_joi4.default.string().required()
|
|
1348
|
+
}).optional()
|
|
1349
|
+
),
|
|
1350
|
+
site: import_joi4.default.string().hex().optional().allow("", null),
|
|
1351
|
+
status: import_joi4.default.string().optional().allow("", null)
|
|
1352
|
+
});
|
|
1353
|
+
const { error } = schema.validate(payload);
|
|
1354
|
+
if (error) {
|
|
1355
|
+
import_node_server_utils8.logger.log({ level: "error", message: error.message });
|
|
1356
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
try {
|
|
1360
|
+
const { id, ...value } = payload;
|
|
1361
|
+
await _updateToiletLocation(id, value);
|
|
1362
|
+
res.status(201).json({ message: "Toilet location updated successfully." });
|
|
1363
|
+
return;
|
|
1364
|
+
} catch (error2) {
|
|
1365
|
+
import_node_server_utils8.logger.log({ level: "error", message: error2.message });
|
|
1366
|
+
next(error2);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
async function deleteToiletLocation(req, res, next) {
|
|
1370
|
+
const id = req.params.id;
|
|
1371
|
+
const validation = import_joi4.default.object({
|
|
1372
|
+
id: import_joi4.default.string().hex().required()
|
|
1373
|
+
});
|
|
1374
|
+
const { error } = validation.validate({ id });
|
|
1375
|
+
if (error) {
|
|
1376
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
try {
|
|
1380
|
+
const message = await _deleteById(id);
|
|
1381
|
+
res.json(message);
|
|
1382
|
+
return;
|
|
1383
|
+
} catch (error2) {
|
|
1384
|
+
next(error2);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
async function updateToiletLocationChecklist(req, res, next) {
|
|
1388
|
+
const payload = { id: req.params.id, ...req.body };
|
|
1389
|
+
const schema = import_joi4.default.object({
|
|
1390
|
+
id: import_joi4.default.string().hex().required(),
|
|
1391
|
+
checklist: import_joi4.default.array().items(
|
|
1392
|
+
import_joi4.default.object({
|
|
1393
|
+
_id: import_joi4.default.string().hex().required(),
|
|
1394
|
+
name: import_joi4.default.string().required()
|
|
1395
|
+
}).required()
|
|
1396
|
+
).min(1).unique("_id", { ignoreUndefined: true }).messages({
|
|
1397
|
+
"array.unique": "Duplicate checklist items are not allowed"
|
|
1398
|
+
})
|
|
1399
|
+
});
|
|
1400
|
+
const { error } = schema.validate(payload);
|
|
1401
|
+
if (error) {
|
|
1402
|
+
import_node_server_utils8.logger.log({ level: "error", message: error.message });
|
|
1403
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
try {
|
|
1407
|
+
const { id, ...value } = payload;
|
|
1408
|
+
await _updateToiletLocationChecklist(id, value);
|
|
1409
|
+
res.json({ message: "Toilet location updated successfully." });
|
|
1410
|
+
return;
|
|
1411
|
+
} catch (error2) {
|
|
1412
|
+
import_node_server_utils8.logger.log({ level: "error", message: error2.message });
|
|
1413
|
+
next(error2);
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
async function getToiletLocationById(req, res, next) {
|
|
1418
|
+
const validation = import_joi4.default.string().hex().required();
|
|
1419
|
+
const _id = req.params.id;
|
|
1420
|
+
const { error } = validation.validate(_id);
|
|
1421
|
+
if (error) {
|
|
1422
|
+
import_node_server_utils8.logger.log({ level: "error", message: error.message });
|
|
1423
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
try {
|
|
1427
|
+
const data = await _getToiletLocationById(_id);
|
|
1428
|
+
res.json(data);
|
|
1429
|
+
return;
|
|
1430
|
+
} catch (error2) {
|
|
1431
|
+
import_node_server_utils8.logger.log({ level: "error", message: error2.message });
|
|
1432
|
+
next(error2);
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
async function uploadByFile(req, res, next) {
|
|
1437
|
+
if (!req.file) {
|
|
1438
|
+
next(new import_node_server_utils8.BadRequestError("File is required!"));
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
1442
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
1443
|
+
{}
|
|
1444
|
+
) : {};
|
|
1445
|
+
const createdBy = cookies["user"] || "";
|
|
1446
|
+
const { site } = req.body;
|
|
1447
|
+
const schema = import_joi4.default.object({
|
|
1448
|
+
site: import_joi4.default.string().hex().optional().allow("", null),
|
|
1449
|
+
createdBy: import_joi4.default.string().hex().required()
|
|
1450
|
+
});
|
|
1451
|
+
const { error } = schema.validate({ site, createdBy });
|
|
1452
|
+
if (error) {
|
|
1453
|
+
import_node_server_utils8.logger.log({ level: "error", message: error.message });
|
|
1454
|
+
next(new import_node_server_utils8.BadRequestError(error.message));
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const xlsData = await convertBufferFile(req.file.buffer);
|
|
1459
|
+
const dataJson = JSON.stringify(xlsData);
|
|
1460
|
+
const result = await _uploadByFile({ dataJson, createdBy, site });
|
|
1461
|
+
return res.status(201).json(result);
|
|
1462
|
+
} catch (error2) {
|
|
1463
|
+
import_node_server_utils8.logger.log({ level: "error", message: error2.message });
|
|
1464
|
+
next(error2);
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
getAll,
|
|
1470
|
+
createToiletLocation,
|
|
1471
|
+
updateToiletLocation,
|
|
1472
|
+
deleteToiletLocation,
|
|
1473
|
+
updateToiletLocationChecklist,
|
|
1474
|
+
getToiletLocationById,
|
|
1475
|
+
uploadByFile
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
// src/models/hygiene-parent-checklist.model.ts
|
|
1480
|
+
var import_node_server_utils9 = require("@iservice365/node-server-utils");
|
|
1481
|
+
var import_joi5 = __toESM(require("joi"));
|
|
1482
|
+
var import_mongodb5 = require("mongodb");
|
|
1483
|
+
var allowedTypes = ["cleaner", "toilet"];
|
|
1484
|
+
var allowedStatus = [
|
|
1485
|
+
"To Do",
|
|
1486
|
+
"Pending",
|
|
1487
|
+
"In Progress",
|
|
1488
|
+
"Completed",
|
|
1489
|
+
"Expired"
|
|
1490
|
+
];
|
|
1491
|
+
var parentChecklistSchema = import_joi5.default.object({
|
|
1492
|
+
date: import_joi5.default.date().required(),
|
|
1493
|
+
status: import_joi5.default.array().items(
|
|
1494
|
+
import_joi5.default.object({
|
|
1495
|
+
type: import_joi5.default.string().required().valid(...allowedTypes),
|
|
1496
|
+
site: import_joi5.default.string().hex().required()
|
|
1497
|
+
})
|
|
1498
|
+
).optional()
|
|
1499
|
+
});
|
|
1500
|
+
function MParentChecklist(value) {
|
|
1501
|
+
const { error } = parentChecklistSchema.validate(value);
|
|
1502
|
+
if (error) {
|
|
1503
|
+
import_node_server_utils9.logger.info(`Hygiene Parent Checklist Model: ${error.message}`);
|
|
1504
|
+
throw new import_node_server_utils9.BadRequestError(error.message);
|
|
1505
|
+
}
|
|
1506
|
+
if (value.status && Array.isArray(value.status)) {
|
|
1507
|
+
value.status = value.status.map((item) => {
|
|
1508
|
+
try {
|
|
1509
|
+
return {
|
|
1510
|
+
...item,
|
|
1511
|
+
site: new import_mongodb5.ObjectId(item.site),
|
|
1512
|
+
status: item.status || "To Do",
|
|
1513
|
+
completedAt: item.completedAt || ""
|
|
1514
|
+
};
|
|
1515
|
+
} catch (error2) {
|
|
1516
|
+
throw new import_node_server_utils9.BadRequestError(
|
|
1517
|
+
`Invalid status site ID format: ${item.site}`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
return {
|
|
1523
|
+
date: new Date(value.date),
|
|
1524
|
+
status: value.status,
|
|
1525
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1526
|
+
updatedAt: value.updatedAt ?? ""
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
// src/repositories/hygiene-parent-checklist.repository.ts
|
|
1531
|
+
var import_mongodb6 = require("mongodb");
|
|
1532
|
+
var import_node_server_utils10 = require("@iservice365/node-server-utils");
|
|
1533
|
+
function useParentChecklistRepo() {
|
|
1534
|
+
const db = import_node_server_utils10.useAtlas.getDb();
|
|
1535
|
+
if (!db) {
|
|
1536
|
+
throw new import_node_server_utils10.InternalServerError("Unable to connect to server.");
|
|
1537
|
+
}
|
|
1538
|
+
const namespace_collection = "hygiene-parent-checklist";
|
|
1539
|
+
const collection = db.collection(namespace_collection);
|
|
1540
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils10.useCache)(namespace_collection);
|
|
1541
|
+
async function createIndex() {
|
|
1542
|
+
try {
|
|
1543
|
+
await collection.createIndexes([
|
|
1544
|
+
{ key: { date: 1 } },
|
|
1545
|
+
{ key: { "status.type": 1, "status.site": 1 } }
|
|
1546
|
+
]);
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
throw new import_node_server_utils10.InternalServerError(
|
|
1549
|
+
"Failed to create index on hygiene parent checklist."
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
async function createParentChecklist(value, session) {
|
|
1554
|
+
try {
|
|
1555
|
+
const currentDate = value.date ? new Date(value.date) : /* @__PURE__ */ new Date();
|
|
1556
|
+
const startOfDay = new Date(currentDate);
|
|
1557
|
+
startOfDay.setUTCHours(0, 0, 0, 0);
|
|
1558
|
+
const endOfDay = new Date(currentDate);
|
|
1559
|
+
endOfDay.setUTCHours(23, 59, 59, 999);
|
|
1560
|
+
const existingChecklist = await collection.findOne({
|
|
1561
|
+
date: {
|
|
1562
|
+
$gte: startOfDay,
|
|
1563
|
+
$lte: endOfDay
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
if (existingChecklist) {
|
|
1567
|
+
const dateStr2 = currentDate.toISOString().split("T")[0];
|
|
1568
|
+
import_node_server_utils10.logger.info(`Parent checklist already exists for today: ${dateStr2}`);
|
|
1569
|
+
return existingChecklist._id;
|
|
1570
|
+
}
|
|
1571
|
+
const processedValue = MParentChecklist(value);
|
|
1572
|
+
const result = await collection.insertOne(processedValue, { session });
|
|
1573
|
+
delNamespace().then(() => {
|
|
1574
|
+
import_node_server_utils10.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
1575
|
+
}).catch((err) => {
|
|
1576
|
+
import_node_server_utils10.logger.error(
|
|
1577
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1578
|
+
err
|
|
1579
|
+
);
|
|
1580
|
+
});
|
|
1581
|
+
const dateStr = currentDate.toISOString().split("T")[0];
|
|
1582
|
+
import_node_server_utils10.logger.info(
|
|
1583
|
+
`Created new parent checklist ${result.insertedId} for today: ${dateStr}`
|
|
1584
|
+
);
|
|
1585
|
+
return result.insertedId;
|
|
1586
|
+
} catch (error) {
|
|
1587
|
+
import_node_server_utils10.logger.error("Failed to create daily parent checklist", error);
|
|
1588
|
+
throw error;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
async function getAllParentChecklist({
|
|
1592
|
+
page = 1,
|
|
1593
|
+
limit = 10,
|
|
1594
|
+
search = "",
|
|
1595
|
+
site,
|
|
1596
|
+
type,
|
|
1597
|
+
startDate = "",
|
|
1598
|
+
endDate = ""
|
|
1599
|
+
}) {
|
|
1600
|
+
page = page > 0 ? page - 1 : 0;
|
|
1601
|
+
const query = {};
|
|
1602
|
+
const cacheOptions = {
|
|
1603
|
+
page,
|
|
1604
|
+
limit
|
|
1605
|
+
};
|
|
1606
|
+
try {
|
|
1607
|
+
site = new import_mongodb6.ObjectId(site);
|
|
1608
|
+
cacheOptions.site = site.toString();
|
|
1609
|
+
} catch (error) {
|
|
1610
|
+
throw new import_node_server_utils10.BadRequestError("Invalid site ID format.");
|
|
1611
|
+
}
|
|
1612
|
+
cacheOptions.type = type;
|
|
1613
|
+
query.status = {
|
|
1614
|
+
$elemMatch: {
|
|
1615
|
+
site: new import_mongodb6.ObjectId(site),
|
|
1616
|
+
type
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
if (search) {
|
|
1620
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
1621
|
+
cacheOptions.search = search;
|
|
1622
|
+
}
|
|
1623
|
+
if (startDate && endDate) {
|
|
1624
|
+
query.createdAt = {
|
|
1625
|
+
$gte: new Date(startDate),
|
|
1626
|
+
$lte: new Date(endDate)
|
|
1627
|
+
};
|
|
1628
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
1629
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
1630
|
+
} else if (startDate) {
|
|
1631
|
+
query.createdAt = { $gte: new Date(startDate) };
|
|
1632
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
1633
|
+
} else if (endDate) {
|
|
1634
|
+
query.createdAt = { $lte: new Date(endDate) };
|
|
1635
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
1636
|
+
}
|
|
1637
|
+
const cacheKey = (0, import_node_server_utils10.makeCacheKey)(namespace_collection, cacheOptions);
|
|
1638
|
+
const cachedData = await getCache(cacheKey);
|
|
1639
|
+
if (cachedData) {
|
|
1640
|
+
import_node_server_utils10.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
1641
|
+
return cachedData;
|
|
1642
|
+
}
|
|
1643
|
+
try {
|
|
1644
|
+
const pipeline = [{ $match: query }];
|
|
1645
|
+
const filterConditions = [];
|
|
1646
|
+
filterConditions.push({ $eq: ["$$this.site", new import_mongodb6.ObjectId(site)] });
|
|
1647
|
+
filterConditions.push({ $eq: ["$$this.type", type] });
|
|
1648
|
+
pipeline.push({
|
|
1649
|
+
$addFields: {
|
|
1650
|
+
filteredStatus: {
|
|
1651
|
+
$filter: {
|
|
1652
|
+
input: "$status",
|
|
1653
|
+
cond: { $and: filterConditions }
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
pipeline.push({
|
|
1659
|
+
$match: {
|
|
1660
|
+
filteredStatus: { $ne: [] }
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1663
|
+
pipeline.push({
|
|
1664
|
+
$addFields: {
|
|
1665
|
+
statusObj: { $arrayElemAt: ["$filteredStatus", 0] }
|
|
1666
|
+
}
|
|
1667
|
+
});
|
|
1668
|
+
pipeline.push({
|
|
1669
|
+
$project: {
|
|
1670
|
+
_id: 1,
|
|
1671
|
+
date: 1,
|
|
1672
|
+
status: "$statusObj.status",
|
|
1673
|
+
completedAt: "$statusObj.completedAt",
|
|
1674
|
+
createdAt: 1
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
pipeline.push(
|
|
1678
|
+
{ $sort: { _id: -1 } },
|
|
1679
|
+
{ $skip: page * limit },
|
|
1680
|
+
{ $limit: limit }
|
|
1681
|
+
);
|
|
1682
|
+
const items = await collection.aggregate(pipeline).toArray();
|
|
1683
|
+
const length = await collection.countDocuments(query);
|
|
1684
|
+
const data = (0, import_node_server_utils10.paginate)(items, page, limit, length);
|
|
1685
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
1686
|
+
import_node_server_utils10.logger.info(`Cache set for key: ${cacheKey}`);
|
|
1687
|
+
}).catch((err) => {
|
|
1688
|
+
import_node_server_utils10.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
1689
|
+
});
|
|
1690
|
+
return data;
|
|
1691
|
+
} catch (error) {
|
|
1692
|
+
throw error;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
async function updateParentChecklistStatuses(date) {
|
|
1696
|
+
try {
|
|
1697
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
1698
|
+
const dateToUpdate = date || new Date(currentDate.getTime() - 24 * 60 * 60 * 1e3);
|
|
1699
|
+
const startOfDay = new Date(dateToUpdate);
|
|
1700
|
+
startOfDay.setUTCHours(0, 0, 0, 0);
|
|
1701
|
+
const endOfDay = new Date(dateToUpdate);
|
|
1702
|
+
endOfDay.setUTCHours(23, 59, 59, 999);
|
|
1703
|
+
import_node_server_utils10.logger.info(
|
|
1704
|
+
`Updating parent checklist statuses for date: ${dateToUpdate.toISOString().split("T")[0]}`
|
|
1705
|
+
);
|
|
1706
|
+
const statusUpdates = await collection.aggregate([
|
|
1707
|
+
{
|
|
1708
|
+
$match: {
|
|
1709
|
+
createdAt: {
|
|
1710
|
+
$gte: startOfDay,
|
|
1711
|
+
$lte: endOfDay
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
$lookup: {
|
|
1717
|
+
from: "hygiene-checklist.areas",
|
|
1718
|
+
localField: "_id",
|
|
1719
|
+
foreignField: "parentChecklist",
|
|
1720
|
+
pipeline: [
|
|
1721
|
+
{
|
|
1722
|
+
$group: {
|
|
1723
|
+
_id: {
|
|
1724
|
+
site: "$site",
|
|
1725
|
+
type: "$type"
|
|
1726
|
+
},
|
|
1727
|
+
completedCount: {
|
|
1728
|
+
$sum: {
|
|
1729
|
+
$cond: [{ $eq: ["$status", "Completed"] }, 1, 0]
|
|
1730
|
+
}
|
|
1731
|
+
},
|
|
1732
|
+
inProgressCount: {
|
|
1733
|
+
$sum: {
|
|
1734
|
+
$cond: [{ $eq: ["$status", "In Progress"] }, 1, 0]
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
toDoCount: {
|
|
1738
|
+
$sum: {
|
|
1739
|
+
$cond: [
|
|
1740
|
+
{
|
|
1741
|
+
$or: [
|
|
1742
|
+
{ $eq: ["$status", "To Do"] },
|
|
1743
|
+
{ $eq: ["$status", "Pending"] }
|
|
1744
|
+
]
|
|
1745
|
+
},
|
|
1746
|
+
1,
|
|
1747
|
+
0
|
|
1748
|
+
]
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
totalCount: { $sum: 1 }
|
|
1752
|
+
}
|
|
1753
|
+
},
|
|
1754
|
+
{
|
|
1755
|
+
$addFields: {
|
|
1756
|
+
finalStatus: {
|
|
1757
|
+
$cond: {
|
|
1758
|
+
if: {
|
|
1759
|
+
$and: [
|
|
1760
|
+
{ $gt: ["$completedCount", 0] },
|
|
1761
|
+
{ $eq: ["$inProgressCount", 0] },
|
|
1762
|
+
{ $eq: ["$toDoCount", 0] }
|
|
1763
|
+
]
|
|
1764
|
+
},
|
|
1765
|
+
then: "Completed",
|
|
1766
|
+
else: {
|
|
1767
|
+
$cond: {
|
|
1768
|
+
if: {
|
|
1769
|
+
$and: [
|
|
1770
|
+
{ $eq: ["$completedCount", 0] },
|
|
1771
|
+
{ $eq: ["$inProgressCount", 0] }
|
|
1772
|
+
]
|
|
1773
|
+
},
|
|
1774
|
+
then: "Expired",
|
|
1775
|
+
else: "In Progress"
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
completedAt: {
|
|
1781
|
+
$cond: {
|
|
1782
|
+
if: {
|
|
1783
|
+
$and: [
|
|
1784
|
+
{ $gt: ["$completedCount", 0] },
|
|
1785
|
+
{ $eq: ["$inProgressCount", 0] },
|
|
1786
|
+
{ $eq: ["$toDoCount", 0] }
|
|
1787
|
+
]
|
|
1788
|
+
},
|
|
1789
|
+
then: /* @__PURE__ */ new Date(),
|
|
1790
|
+
else: null
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
],
|
|
1796
|
+
as: "areaStats"
|
|
1797
|
+
}
|
|
1798
|
+
},
|
|
1799
|
+
{
|
|
1800
|
+
$addFields: {
|
|
1801
|
+
newStatus: {
|
|
1802
|
+
$map: {
|
|
1803
|
+
input: "$areaStats",
|
|
1804
|
+
as: "stat",
|
|
1805
|
+
in: {
|
|
1806
|
+
site: "$$stat._id.site",
|
|
1807
|
+
type: "$$stat._id.type",
|
|
1808
|
+
status: "$$stat.finalStatus",
|
|
1809
|
+
completedAt: "$$stat.completedAt"
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
},
|
|
1815
|
+
{ $match: { newStatus: { $ne: [] } } },
|
|
1816
|
+
{
|
|
1817
|
+
$project: {
|
|
1818
|
+
_id: 1,
|
|
1819
|
+
newStatus: 1
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
]).toArray();
|
|
1823
|
+
import_node_server_utils10.logger.info(
|
|
1824
|
+
`Found ${statusUpdates.length} parent checklists to potentially update`
|
|
1825
|
+
);
|
|
1826
|
+
if (statusUpdates.length === 0) {
|
|
1827
|
+
import_node_server_utils10.logger.info(
|
|
1828
|
+
`No parent checklists found for date range: ${startOfDay.toISOString()} to ${endOfDay.toISOString()}`
|
|
1829
|
+
);
|
|
1830
|
+
return null;
|
|
1831
|
+
}
|
|
1832
|
+
const bulkOps = statusUpdates.map((update) => {
|
|
1833
|
+
const statusTypes = update.newStatus.map((s) => `${s.type}(${s.status})`).join(", ");
|
|
1834
|
+
import_node_server_utils10.logger.info(
|
|
1835
|
+
`Updating parent checklist ${update._id} with ${update.newStatus.length} status entries: [${statusTypes}]`
|
|
1836
|
+
);
|
|
1837
|
+
return {
|
|
1838
|
+
updateOne: {
|
|
1839
|
+
filter: { _id: update._id },
|
|
1840
|
+
update: {
|
|
1841
|
+
$set: {
|
|
1842
|
+
status: update.newStatus,
|
|
1843
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
});
|
|
1849
|
+
let result = null;
|
|
1850
|
+
if (bulkOps.length > 0) {
|
|
1851
|
+
result = await collection.bulkWrite(bulkOps);
|
|
1852
|
+
delNamespace().then(() => {
|
|
1853
|
+
import_node_server_utils10.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
1854
|
+
}).catch((err) => {
|
|
1855
|
+
import_node_server_utils10.logger.error(
|
|
1856
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1857
|
+
err
|
|
1858
|
+
);
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
import_node_server_utils10.logger.info(`Updated statuses for ${bulkOps.length} parent checklists.`);
|
|
1862
|
+
return result;
|
|
1863
|
+
} catch (error) {
|
|
1864
|
+
import_node_server_utils10.logger.error("Failed to update parent checklist statuses", error);
|
|
1865
|
+
throw error;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return {
|
|
1869
|
+
createIndex,
|
|
1870
|
+
createParentChecklist,
|
|
1871
|
+
getAllParentChecklist,
|
|
1872
|
+
updateParentChecklistStatuses
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
// src/controllers/hygiene-parent-checklist.controller.ts
|
|
1877
|
+
var import_node_server_utils11 = require("@iservice365/node-server-utils");
|
|
1878
|
+
var import_joi6 = __toESM(require("joi"));
|
|
1879
|
+
function useParentChecklistController() {
|
|
1880
|
+
const {
|
|
1881
|
+
createParentChecklist: _createParentChecklist,
|
|
1882
|
+
getAllParentChecklist: _getAllParentChecklist
|
|
1883
|
+
} = useParentChecklistRepo();
|
|
1884
|
+
async function createParentChecklist(req, res, next) {
|
|
1885
|
+
const payload = req.body;
|
|
1886
|
+
const { error } = parentChecklistSchema.validate(payload);
|
|
1887
|
+
if (error) {
|
|
1888
|
+
import_node_server_utils11.logger.log({ level: "error", message: error.message });
|
|
1889
|
+
next(new import_node_server_utils11.BadRequestError(error.message));
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
try {
|
|
1893
|
+
const id = await _createParentChecklist(payload);
|
|
1894
|
+
res.status(201).json({ message: "Parent checklist created successfully.", id });
|
|
1895
|
+
return;
|
|
1896
|
+
} catch (error2) {
|
|
1897
|
+
import_node_server_utils11.logger.log({ level: "error", message: error2.message });
|
|
1898
|
+
next(error2);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
async function getAllParentChecklist(req, res, next) {
|
|
1903
|
+
const query = { ...req.query, ...req.params };
|
|
1904
|
+
const validation = import_joi6.default.object({
|
|
1905
|
+
page: import_joi6.default.number().min(1).optional().allow("", null),
|
|
1906
|
+
limit: import_joi6.default.number().min(1).optional().allow("", null),
|
|
1907
|
+
search: import_joi6.default.string().optional().allow("", null),
|
|
1908
|
+
site: import_joi6.default.string().hex().required(),
|
|
1909
|
+
type: import_joi6.default.string().required().valid(...allowedTypes),
|
|
1910
|
+
startDate: import_joi6.default.alternatives().try(import_joi6.default.date(), import_joi6.default.string()).optional().allow("", null),
|
|
1911
|
+
endDate: import_joi6.default.alternatives().try(import_joi6.default.date(), import_joi6.default.string()).optional().allow("", null)
|
|
1912
|
+
});
|
|
1913
|
+
const { error } = validation.validate(query);
|
|
1914
|
+
if (error) {
|
|
1915
|
+
import_node_server_utils11.logger.log({ level: "error", message: error.message });
|
|
1916
|
+
next(new import_node_server_utils11.BadRequestError(error.message));
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
1920
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
1921
|
+
const search = req.query.search ?? "";
|
|
1922
|
+
const site = req.params.site ?? "";
|
|
1923
|
+
const type = req.params.type ?? "";
|
|
1924
|
+
const startDate = req.query.startDate ?? "";
|
|
1925
|
+
const endDate = req.query.endDate ?? "";
|
|
1926
|
+
try {
|
|
1927
|
+
const data = await _getAllParentChecklist({
|
|
1928
|
+
page,
|
|
1929
|
+
limit,
|
|
1930
|
+
search,
|
|
1931
|
+
site,
|
|
1932
|
+
type,
|
|
1933
|
+
startDate,
|
|
1934
|
+
endDate
|
|
1935
|
+
});
|
|
1936
|
+
res.json(data);
|
|
1937
|
+
return;
|
|
1938
|
+
} catch (error2) {
|
|
1939
|
+
import_node_server_utils11.logger.log({ level: "error", message: error2.message });
|
|
1940
|
+
next(error2);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return {
|
|
1945
|
+
createParentChecklist,
|
|
1946
|
+
getAllParentChecklist
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// src/models/hygiene-unit.model.ts
|
|
1951
|
+
var import_node_server_utils12 = require("@iservice365/node-server-utils");
|
|
1952
|
+
var import_joi7 = __toESM(require("joi"));
|
|
1953
|
+
var import_mongodb7 = require("mongodb");
|
|
1954
|
+
var unitSchema = import_joi7.default.object({
|
|
1955
|
+
name: import_joi7.default.string().required(),
|
|
1956
|
+
site: import_joi7.default.string().hex().required(),
|
|
1957
|
+
createdBy: import_joi7.default.string().hex().required()
|
|
1958
|
+
});
|
|
1959
|
+
function MUnit(value) {
|
|
1960
|
+
const { error } = unitSchema.validate(value);
|
|
1961
|
+
if (error) {
|
|
1962
|
+
import_node_server_utils12.logger.info(`Hygiene Unit Model: ${error.message}`);
|
|
1963
|
+
throw new import_node_server_utils12.BadRequestError(error.message);
|
|
1964
|
+
}
|
|
1965
|
+
if (value.site) {
|
|
1966
|
+
try {
|
|
1967
|
+
value.site = new import_mongodb7.ObjectId(value.site);
|
|
1968
|
+
} catch (error2) {
|
|
1969
|
+
throw new import_node_server_utils12.BadRequestError("Invalid site ID format.");
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
if (value.createdBy) {
|
|
1973
|
+
try {
|
|
1974
|
+
value.createdBy = new import_mongodb7.ObjectId(value.createdBy);
|
|
1975
|
+
} catch (error2) {
|
|
1976
|
+
throw new import_node_server_utils12.BadRequestError("Invalid createdBy ID format.");
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return {
|
|
1980
|
+
name: value.name,
|
|
1981
|
+
createdBy: value.createdBy,
|
|
1982
|
+
site: value.site,
|
|
1983
|
+
status: "active",
|
|
1984
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1985
|
+
updatedAt: value.updatedAt ?? "",
|
|
1986
|
+
deletedAt: value.deletedAt ?? ""
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
// src/services/hygiene-unit.service.ts
|
|
1991
|
+
var import_node_server_utils14 = require("@iservice365/node-server-utils");
|
|
1992
|
+
|
|
1993
|
+
// src/repositories/hygiene-unit.repository.ts
|
|
1994
|
+
var import_mongodb8 = require("mongodb");
|
|
1995
|
+
var import_node_server_utils13 = require("@iservice365/node-server-utils");
|
|
1996
|
+
function useUnitRepository() {
|
|
1997
|
+
const db = import_node_server_utils13.useAtlas.getDb();
|
|
1998
|
+
if (!db) {
|
|
1999
|
+
throw new import_node_server_utils13.InternalServerError("Unable to connect to server.");
|
|
2000
|
+
}
|
|
2001
|
+
const namespace_collection = "hygiene-units";
|
|
2002
|
+
const collection = db.collection(namespace_collection);
|
|
2003
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils13.useCache)(namespace_collection);
|
|
2004
|
+
async function createIndex() {
|
|
2005
|
+
try {
|
|
2006
|
+
await collection.createIndexes([
|
|
2007
|
+
{ key: { site: 1 } },
|
|
2008
|
+
{ key: { createdBy: 1 } },
|
|
2009
|
+
{ key: { status: 1 } }
|
|
2010
|
+
]);
|
|
2011
|
+
} catch (error) {
|
|
2012
|
+
throw new import_node_server_utils13.InternalServerError("Failed to create index on hygiene unit.");
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
async function createTextIndex() {
|
|
2016
|
+
try {
|
|
2017
|
+
await collection.createIndex({ name: "text" });
|
|
2018
|
+
} catch (error) {
|
|
2019
|
+
throw new import_node_server_utils13.InternalServerError(
|
|
2020
|
+
"Failed to create text index on hygiene unit."
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
async function createUniqueIndex() {
|
|
2025
|
+
try {
|
|
2026
|
+
await collection.createIndex(
|
|
2027
|
+
{ name: 1, site: 1, deletedAt: 1 },
|
|
2028
|
+
{ unique: true }
|
|
2029
|
+
);
|
|
2030
|
+
} catch (error) {
|
|
2031
|
+
throw new import_node_server_utils13.InternalServerError(
|
|
2032
|
+
"Failed to create unique index on hygiene unit."
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
async function createUnit(value, session) {
|
|
2037
|
+
try {
|
|
2038
|
+
value = MUnit(value);
|
|
2039
|
+
const res = await collection.insertOne(value, { session });
|
|
2040
|
+
delNamespace().then(() => {
|
|
2041
|
+
import_node_server_utils13.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2042
|
+
}).catch((err) => {
|
|
2043
|
+
import_node_server_utils13.logger.error(
|
|
2044
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2045
|
+
err
|
|
2046
|
+
);
|
|
2047
|
+
});
|
|
2048
|
+
return res.insertedId;
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2051
|
+
if (isDuplicated) {
|
|
2052
|
+
throw new import_node_server_utils13.BadRequestError("Unit already exists.");
|
|
2053
|
+
}
|
|
2054
|
+
throw error;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
async function getUnits({
|
|
2058
|
+
page = 1,
|
|
2059
|
+
limit = 10,
|
|
2060
|
+
search = "",
|
|
2061
|
+
startDate = "",
|
|
2062
|
+
endDate = "",
|
|
2063
|
+
site = ""
|
|
2064
|
+
}) {
|
|
2065
|
+
page = page > 0 ? page - 1 : 0;
|
|
2066
|
+
try {
|
|
2067
|
+
site = new import_mongodb8.ObjectId(site);
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
throw new import_node_server_utils13.BadRequestError("Invalid site ID format.");
|
|
2070
|
+
}
|
|
2071
|
+
const query = {
|
|
2072
|
+
status: { $ne: "deleted" },
|
|
2073
|
+
site
|
|
2074
|
+
};
|
|
2075
|
+
const cacheOptions = {
|
|
2076
|
+
page,
|
|
2077
|
+
limit,
|
|
2078
|
+
site: site.toString()
|
|
2079
|
+
};
|
|
2080
|
+
if (search) {
|
|
2081
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
2082
|
+
cacheOptions.search = search;
|
|
2083
|
+
}
|
|
2084
|
+
if (startDate && endDate) {
|
|
2085
|
+
query.createdAt = {
|
|
2086
|
+
$gte: new Date(startDate),
|
|
2087
|
+
$lte: new Date(endDate)
|
|
2088
|
+
};
|
|
2089
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
2090
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
2091
|
+
} else if (startDate) {
|
|
2092
|
+
query.createdAt = { $gte: new Date(startDate) };
|
|
2093
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
2094
|
+
} else if (endDate) {
|
|
2095
|
+
query.createdAt = { $lte: new Date(endDate) };
|
|
2096
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
2097
|
+
}
|
|
2098
|
+
const cacheKey = (0, import_node_server_utils13.makeCacheKey)(namespace_collection, cacheOptions);
|
|
2099
|
+
const cachedData = await getCache(cacheKey);
|
|
2100
|
+
if (cachedData) {
|
|
2101
|
+
import_node_server_utils13.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
2102
|
+
return cachedData;
|
|
2103
|
+
}
|
|
2104
|
+
try {
|
|
2105
|
+
const items = await collection.aggregate([
|
|
2106
|
+
{ $match: query },
|
|
2107
|
+
{
|
|
2108
|
+
$lookup: {
|
|
2109
|
+
from: "sites",
|
|
2110
|
+
localField: "site",
|
|
2111
|
+
foreignField: "_id",
|
|
2112
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
2113
|
+
as: "site"
|
|
2114
|
+
}
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
$unwind: {
|
|
2118
|
+
path: "$site",
|
|
2119
|
+
preserveNullAndEmptyArrays: true
|
|
2120
|
+
}
|
|
2121
|
+
},
|
|
2122
|
+
{
|
|
2123
|
+
$lookup: {
|
|
2124
|
+
from: "users",
|
|
2125
|
+
localField: "createdBy",
|
|
2126
|
+
foreignField: "_id",
|
|
2127
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
2128
|
+
as: "createdBy"
|
|
2129
|
+
}
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
$unwind: {
|
|
2133
|
+
path: "$createdBy",
|
|
2134
|
+
preserveNullAndEmptyArrays: true
|
|
2135
|
+
}
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
$project: {
|
|
2139
|
+
name: 1,
|
|
2140
|
+
site: "$site._id",
|
|
2141
|
+
siteName: "$site.name",
|
|
2142
|
+
createdByName: "$createdBy.name",
|
|
2143
|
+
checklist: 1,
|
|
2144
|
+
status: 1,
|
|
2145
|
+
createdAt: 1
|
|
2146
|
+
}
|
|
2147
|
+
},
|
|
2148
|
+
{ $sort: { _id: -1 } },
|
|
2149
|
+
{ $skip: page * limit },
|
|
2150
|
+
{ $limit: limit }
|
|
2151
|
+
]).toArray();
|
|
2152
|
+
const length = await collection.countDocuments(query);
|
|
2153
|
+
const data = (0, import_node_server_utils13.paginate)(items, page, limit, length);
|
|
2154
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
2155
|
+
import_node_server_utils13.logger.info(`Cache set for key: ${cacheKey}`);
|
|
2156
|
+
}).catch((err) => {
|
|
2157
|
+
import_node_server_utils13.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
2158
|
+
});
|
|
2159
|
+
return data;
|
|
2160
|
+
} catch (error) {
|
|
2161
|
+
throw error;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
async function getUnitByName(name, site) {
|
|
2165
|
+
try {
|
|
2166
|
+
if (site)
|
|
2167
|
+
site = new import_mongodb8.ObjectId(site);
|
|
2168
|
+
} catch (error) {
|
|
2169
|
+
throw new import_node_server_utils13.BadRequestError("Invalid site ID format.");
|
|
2170
|
+
}
|
|
2171
|
+
try {
|
|
2172
|
+
return await collection.findOne({
|
|
2173
|
+
name: { $regex: new RegExp(`^${name}$`, "i") },
|
|
2174
|
+
...site && { site }
|
|
2175
|
+
});
|
|
2176
|
+
} catch (error) {
|
|
2177
|
+
throw new import_node_server_utils13.BadRequestError("Unable to fetch unit by name.");
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
async function getUnitById(id, site) {
|
|
2181
|
+
try {
|
|
2182
|
+
id = typeof id === "string" ? new import_mongodb8.ObjectId(id) : id;
|
|
2183
|
+
} catch (error) {
|
|
2184
|
+
throw new import_node_server_utils13.BadRequestError("Invalid unit ID format.");
|
|
2185
|
+
}
|
|
2186
|
+
try {
|
|
2187
|
+
if (site)
|
|
2188
|
+
site = new import_mongodb8.ObjectId(site);
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
throw new import_node_server_utils13.BadRequestError(
|
|
2191
|
+
"Unable to fetch unit by ID, Invalid site ID format."
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
try {
|
|
2195
|
+
return await collection.findOne({ _id: id, ...site && { site } });
|
|
2196
|
+
} catch (error) {
|
|
2197
|
+
throw new import_node_server_utils13.BadRequestError("Unable to fetch unit by id.");
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
async function updateUnit(_id, value) {
|
|
2201
|
+
try {
|
|
2202
|
+
_id = new import_mongodb8.ObjectId(_id);
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
throw new import_node_server_utils13.BadRequestError("Invalid unit ID format.");
|
|
2205
|
+
}
|
|
2206
|
+
try {
|
|
2207
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
2208
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
2209
|
+
if (res.modifiedCount === 0) {
|
|
2210
|
+
throw new import_node_server_utils13.InternalServerError("Unable to update cleaning unit.");
|
|
2211
|
+
}
|
|
2212
|
+
delNamespace().then(() => {
|
|
2213
|
+
import_node_server_utils13.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2214
|
+
}).catch((err) => {
|
|
2215
|
+
import_node_server_utils13.logger.error(
|
|
2216
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2217
|
+
err
|
|
2218
|
+
);
|
|
2219
|
+
});
|
|
2220
|
+
return res.modifiedCount;
|
|
2221
|
+
} catch (error) {
|
|
2222
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2223
|
+
if (isDuplicated) {
|
|
2224
|
+
throw new import_node_server_utils13.BadRequestError("Area already exists.");
|
|
2225
|
+
}
|
|
2226
|
+
throw error;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
async function deleteUnit(_id, session) {
|
|
2230
|
+
try {
|
|
2231
|
+
_id = new import_mongodb8.ObjectId(_id);
|
|
2232
|
+
} catch (error) {
|
|
2233
|
+
throw new import_node_server_utils13.BadRequestError("Invalid unit ID format.");
|
|
2234
|
+
}
|
|
2235
|
+
try {
|
|
2236
|
+
const updateValue = {
|
|
2237
|
+
status: "deleted",
|
|
2238
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
2239
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
2240
|
+
};
|
|
2241
|
+
const res = await collection.updateOne(
|
|
2242
|
+
{ _id },
|
|
2243
|
+
{ $set: updateValue },
|
|
2244
|
+
{ session }
|
|
2245
|
+
);
|
|
2246
|
+
if (res.modifiedCount === 0) {
|
|
2247
|
+
throw new import_node_server_utils13.InternalServerError("Unable to delete unit.");
|
|
2248
|
+
}
|
|
2249
|
+
delNamespace().then(() => {
|
|
2250
|
+
import_node_server_utils13.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2251
|
+
}).catch((err) => {
|
|
2252
|
+
import_node_server_utils13.logger.error(
|
|
2253
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2254
|
+
err
|
|
2255
|
+
);
|
|
2256
|
+
});
|
|
2257
|
+
return res.modifiedCount;
|
|
2258
|
+
} catch (error) {
|
|
2259
|
+
throw error;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
return {
|
|
2263
|
+
createIndex,
|
|
2264
|
+
createTextIndex,
|
|
2265
|
+
createUniqueIndex,
|
|
2266
|
+
createUnit,
|
|
2267
|
+
getUnits,
|
|
2268
|
+
getUnitByName,
|
|
2269
|
+
getUnitById,
|
|
2270
|
+
updateUnit,
|
|
2271
|
+
deleteUnit
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
// src/services/hygiene-unit.service.ts
|
|
2276
|
+
function useUnitService() {
|
|
2277
|
+
const { createUnit: _createUnit } = useUnitRepository();
|
|
2278
|
+
async function uploadByFile({
|
|
2279
|
+
dataJson,
|
|
2280
|
+
createdBy,
|
|
2281
|
+
site
|
|
2282
|
+
}) {
|
|
2283
|
+
let dataArray;
|
|
2284
|
+
try {
|
|
2285
|
+
dataArray = JSON.parse(dataJson);
|
|
2286
|
+
} catch (error) {
|
|
2287
|
+
throw new import_node_server_utils14.BadRequestError("Invalid JSON format for data in excel");
|
|
2288
|
+
}
|
|
2289
|
+
if (!dataArray || dataArray.length === 0) {
|
|
2290
|
+
throw new import_node_server_utils14.NotFoundError("No data found in the uploaded file");
|
|
2291
|
+
}
|
|
2292
|
+
const session = import_node_server_utils14.useAtlas.getClient()?.startSession();
|
|
2293
|
+
const insertedUnitIds = [];
|
|
2294
|
+
try {
|
|
2295
|
+
session?.startTransaction();
|
|
2296
|
+
for (const row of dataArray) {
|
|
2297
|
+
if (!row?.UNIT_NAME) {
|
|
2298
|
+
import_node_server_utils14.logger.warn("Skipping row with missing UNIT_NAME:", row);
|
|
2299
|
+
continue;
|
|
2300
|
+
}
|
|
2301
|
+
try {
|
|
2302
|
+
const insertedId = await _createUnit(
|
|
2303
|
+
{
|
|
2304
|
+
name: String(row.UNIT_NAME).trim(),
|
|
2305
|
+
site,
|
|
2306
|
+
createdBy
|
|
2307
|
+
},
|
|
2308
|
+
session
|
|
2309
|
+
);
|
|
2310
|
+
insertedUnitIds.push(insertedId);
|
|
2311
|
+
} catch (error) {
|
|
2312
|
+
import_node_server_utils14.logger.error(
|
|
2313
|
+
`Error creating unit "${row.UNIT_NAME}":`,
|
|
2314
|
+
error.message
|
|
2315
|
+
);
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
await session?.commitTransaction();
|
|
2320
|
+
import_node_server_utils14.logger.info(`Successfully uploaded ${insertedUnitIds.length} units`);
|
|
2321
|
+
return {
|
|
2322
|
+
message: `Successfully uploaded ${insertedUnitIds.length} units`
|
|
2323
|
+
};
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
await session?.abortTransaction();
|
|
2326
|
+
import_node_server_utils14.logger.error("Error while uploading unit information", error);
|
|
2327
|
+
throw error;
|
|
2328
|
+
} finally {
|
|
2329
|
+
session?.endSession();
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
return {
|
|
2333
|
+
uploadByFile
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// src/controllers/hygiene-unit.controller.ts
|
|
2338
|
+
var import_node_server_utils15 = require("@iservice365/node-server-utils");
|
|
2339
|
+
var import_joi8 = __toESM(require("joi"));
|
|
2340
|
+
function useUnitController() {
|
|
2341
|
+
const {
|
|
2342
|
+
createUnit: _createUnit,
|
|
2343
|
+
getUnits: _getUnits,
|
|
2344
|
+
updateUnit: _updateUnit,
|
|
2345
|
+
deleteUnit: _deleteUnit
|
|
2346
|
+
} = useUnitRepository();
|
|
2347
|
+
const { uploadByFile: _uploadByFile } = useUnitService();
|
|
2348
|
+
async function createUnit(req, res, next) {
|
|
2349
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
2350
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2351
|
+
{}
|
|
2352
|
+
) : {};
|
|
2353
|
+
const createdBy = cookies["user"] || "";
|
|
2354
|
+
const payload = { ...req.body, createdBy };
|
|
2355
|
+
const { error } = unitSchema.validate(payload);
|
|
2356
|
+
if (error) {
|
|
2357
|
+
import_node_server_utils15.logger.log({ level: "error", message: error.message });
|
|
2358
|
+
next(new import_node_server_utils15.BadRequestError(error.message));
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2361
|
+
try {
|
|
2362
|
+
const id = await _createUnit(payload);
|
|
2363
|
+
res.status(201).json({ message: "Unit created successfully.", id });
|
|
2364
|
+
return;
|
|
2365
|
+
} catch (error2) {
|
|
2366
|
+
import_node_server_utils15.logger.log({ level: "error", message: error2.message });
|
|
2367
|
+
next(error2);
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
async function getAll(req, res, next) {
|
|
2372
|
+
const query = req.query;
|
|
2373
|
+
const validation = import_joi8.default.object({
|
|
2374
|
+
page: import_joi8.default.number().min(1).optional().allow("", null),
|
|
2375
|
+
limit: import_joi8.default.number().min(1).optional().allow("", null),
|
|
2376
|
+
search: import_joi8.default.string().optional().allow("", null),
|
|
2377
|
+
startDate: import_joi8.default.alternatives().try(import_joi8.default.date(), import_joi8.default.string()).optional().allow("", null),
|
|
2378
|
+
endDate: import_joi8.default.alternatives().try(import_joi8.default.date(), import_joi8.default.string()).optional().allow("", null),
|
|
2379
|
+
site: import_joi8.default.string().hex().optional().allow("", null)
|
|
2380
|
+
});
|
|
2381
|
+
const { error } = validation.validate(query);
|
|
2382
|
+
if (error) {
|
|
2383
|
+
import_node_server_utils15.logger.log({ level: "error", message: error.message });
|
|
2384
|
+
next(new import_node_server_utils15.BadRequestError(error.message));
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
2388
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
2389
|
+
const search = req.query.search ?? "";
|
|
2390
|
+
const site = req.query.site ?? "";
|
|
2391
|
+
const startDate = req.query.startDate ?? "";
|
|
2392
|
+
const endDate = req.query.endDate ?? "";
|
|
2393
|
+
try {
|
|
2394
|
+
const data = await _getUnits({
|
|
2395
|
+
page,
|
|
2396
|
+
limit,
|
|
2397
|
+
search,
|
|
2398
|
+
site,
|
|
2399
|
+
startDate,
|
|
2400
|
+
endDate
|
|
2401
|
+
});
|
|
2402
|
+
res.json(data);
|
|
2403
|
+
return;
|
|
2404
|
+
} catch (error2) {
|
|
2405
|
+
import_node_server_utils15.logger.log({ level: "error", message: error2.message });
|
|
2406
|
+
next(error2);
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
async function updateUnit(req, res, next) {
|
|
2411
|
+
const payload = { id: req.params.id, ...req.body };
|
|
2412
|
+
const schema = import_joi8.default.object({
|
|
2413
|
+
id: import_joi8.default.string().hex().required(),
|
|
2414
|
+
name: import_joi8.default.string().required()
|
|
2415
|
+
});
|
|
2416
|
+
const { error } = schema.validate(payload);
|
|
2417
|
+
if (error) {
|
|
2418
|
+
import_node_server_utils15.logger.log({ level: "error", message: error.message });
|
|
2419
|
+
next(new import_node_server_utils15.BadRequestError(error.message));
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
try {
|
|
2423
|
+
const { id, ...value } = payload;
|
|
2424
|
+
await _updateUnit(id, value);
|
|
2425
|
+
res.json({ message: "Unit updated successfully." });
|
|
2426
|
+
return;
|
|
2427
|
+
} catch (error2) {
|
|
2428
|
+
import_node_server_utils15.logger.log({ level: "error", message: error2.message });
|
|
2429
|
+
next(error2);
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
async function deleteUnit(req, res, next) {
|
|
2434
|
+
const id = req.params.id;
|
|
2435
|
+
const validation = import_joi8.default.object({
|
|
2436
|
+
id: import_joi8.default.string().hex().required()
|
|
2437
|
+
});
|
|
2438
|
+
const { error } = validation.validate({ id });
|
|
2439
|
+
if (error) {
|
|
2440
|
+
import_node_server_utils15.logger.log({ level: "error", message: error.message });
|
|
2441
|
+
next(new import_node_server_utils15.BadRequestError(error.message));
|
|
2442
|
+
return;
|
|
2443
|
+
}
|
|
2444
|
+
try {
|
|
2445
|
+
await _deleteUnit(id);
|
|
2446
|
+
res.json({ message: "Unit deleted successfully." });
|
|
2447
|
+
return;
|
|
2448
|
+
} catch (error2) {
|
|
2449
|
+
import_node_server_utils15.logger.log({ level: "error", message: error2.message });
|
|
2450
|
+
next(error2);
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
async function uploadByFile(req, res, next) {
|
|
2455
|
+
if (!req.file) {
|
|
2456
|
+
next(new import_node_server_utils15.BadRequestError("File is required!"));
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2459
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
2460
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2461
|
+
{}
|
|
2462
|
+
) : {};
|
|
2463
|
+
const createdBy = cookies["user"] || "";
|
|
2464
|
+
const { site } = req.body;
|
|
2465
|
+
const schema = import_joi8.default.object({
|
|
2466
|
+
site: import_joi8.default.string().hex().optional().allow("", null),
|
|
2467
|
+
createdBy: import_joi8.default.string().hex().required()
|
|
2468
|
+
});
|
|
2469
|
+
const { error } = schema.validate({ site, createdBy });
|
|
2470
|
+
if (error) {
|
|
2471
|
+
import_node_server_utils15.logger.log({ level: "error", message: error.message });
|
|
2472
|
+
next(new import_node_server_utils15.BadRequestError(error.message));
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
try {
|
|
2476
|
+
const xlsData = await convertBufferFile(req.file.buffer);
|
|
2477
|
+
const dataJson = JSON.stringify(xlsData);
|
|
2478
|
+
const result = await _uploadByFile({ dataJson, createdBy, site });
|
|
2479
|
+
return res.status(201).json(result);
|
|
2480
|
+
} catch (error2) {
|
|
2481
|
+
import_node_server_utils15.logger.log({ level: "error", message: error2.message });
|
|
2482
|
+
next(error2);
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
return {
|
|
2487
|
+
createUnit,
|
|
2488
|
+
getAll,
|
|
2489
|
+
updateUnit,
|
|
2490
|
+
deleteUnit,
|
|
2491
|
+
uploadByFile
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
// src/models/hygiene-schedule-task-area.model.ts
|
|
2496
|
+
var import_node_server_utils16 = require("@iservice365/node-server-utils");
|
|
2497
|
+
var import_joi9 = __toESM(require("joi"));
|
|
2498
|
+
var import_mongodb9 = require("mongodb");
|
|
2499
|
+
var scheduleTaskAreaSchema = import_joi9.default.object({
|
|
2500
|
+
name: import_joi9.default.string().required(),
|
|
2501
|
+
site: import_joi9.default.string().hex().required(),
|
|
2502
|
+
createdBy: import_joi9.default.string().hex().required(),
|
|
2503
|
+
checklist: import_joi9.default.array().items(
|
|
2504
|
+
import_joi9.default.object({
|
|
2505
|
+
_id: import_joi9.default.string().hex().required(),
|
|
2506
|
+
name: import_joi9.default.string().required()
|
|
2507
|
+
})
|
|
2508
|
+
).optional(),
|
|
2509
|
+
updatedAt: import_joi9.default.date().optional().allow("", null),
|
|
2510
|
+
status: import_joi9.default.string().allow("", null).optional()
|
|
2511
|
+
});
|
|
2512
|
+
function MScheduleTaskArea(value) {
|
|
2513
|
+
const { error } = scheduleTaskAreaSchema.validate(value);
|
|
2514
|
+
if (error) {
|
|
2515
|
+
throw new import_node_server_utils16.BadRequestError(error.message);
|
|
2516
|
+
}
|
|
2517
|
+
if (value.site) {
|
|
2518
|
+
try {
|
|
2519
|
+
value.site = new import_mongodb9.ObjectId(value.site);
|
|
2520
|
+
} catch (error2) {
|
|
2521
|
+
throw new import_node_server_utils16.BadRequestError("Invalid site ID format.");
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
if (value.createdBy) {
|
|
2525
|
+
try {
|
|
2526
|
+
value.createdBy = new import_mongodb9.ObjectId(value.createdBy);
|
|
2527
|
+
} catch (error2) {
|
|
2528
|
+
throw new import_node_server_utils16.BadRequestError("Invalid createdBy ID format.");
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (value.checklist && Array.isArray(value.checklist)) {
|
|
2532
|
+
value.checklist = value.checklist.map((item) => {
|
|
2533
|
+
try {
|
|
2534
|
+
return {
|
|
2535
|
+
...item,
|
|
2536
|
+
_id: new import_mongodb9.ObjectId(item._id)
|
|
2537
|
+
};
|
|
2538
|
+
} catch (error2) {
|
|
2539
|
+
throw new import_node_server_utils16.BadRequestError(
|
|
2540
|
+
`Invalid checklist item ID format: ${item._id}`
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
});
|
|
2544
|
+
}
|
|
2545
|
+
return {
|
|
2546
|
+
name: value.name,
|
|
2547
|
+
site: value.site,
|
|
2548
|
+
createdBy: value.createdBy,
|
|
2549
|
+
checklist: value.checklist,
|
|
2550
|
+
status: value.status ?? "",
|
|
2551
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2552
|
+
updatedAt: value.updatedAt ?? "",
|
|
2553
|
+
deletedAt: value.deletedAt ?? ""
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
// src/repositories/hygiene-schedule-task-area.repository.ts
|
|
2558
|
+
var import_mongodb10 = require("mongodb");
|
|
2559
|
+
var import_node_server_utils17 = require("@iservice365/node-server-utils");
|
|
2560
|
+
function useScheduleTaskAreaRepository() {
|
|
2561
|
+
const db = import_node_server_utils17.useAtlas.getDb();
|
|
2562
|
+
if (!db) {
|
|
2563
|
+
throw new import_node_server_utils17.InternalServerError("Unable to connect to server.");
|
|
2564
|
+
}
|
|
2565
|
+
const namespace_collection = "hygiene-schedule-task-areas";
|
|
2566
|
+
const collection = db.collection(namespace_collection);
|
|
2567
|
+
const { delNamespace, setCache, getCache, delCache } = (0, import_node_server_utils17.useCache)(namespace_collection);
|
|
2568
|
+
async function createIndexes() {
|
|
2569
|
+
try {
|
|
2570
|
+
await collection.createIndexes([
|
|
2571
|
+
{ key: { site: 1 } },
|
|
2572
|
+
{ key: { name: "text" } }
|
|
2573
|
+
]);
|
|
2574
|
+
} catch (error) {
|
|
2575
|
+
throw new import_node_server_utils17.InternalServerError("Failed to create index on site.");
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
async function createUniqueIndex() {
|
|
2579
|
+
try {
|
|
2580
|
+
await collection.createIndex(
|
|
2581
|
+
{ name: 1, site: 1, deletedAt: 1 },
|
|
2582
|
+
{ unique: true }
|
|
2583
|
+
);
|
|
2584
|
+
} catch (error) {
|
|
2585
|
+
throw new import_node_server_utils17.InternalServerError(
|
|
2586
|
+
"Failed to create unique index on hygiene area."
|
|
2587
|
+
);
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
async function createScheduleTaskArea(value, session) {
|
|
2591
|
+
try {
|
|
2592
|
+
value = MScheduleTaskArea(value);
|
|
2593
|
+
const res = await collection.insertOne(value, { session });
|
|
2594
|
+
delNamespace().then(() => {
|
|
2595
|
+
import_node_server_utils17.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2596
|
+
}).catch((err) => {
|
|
2597
|
+
import_node_server_utils17.logger.error(
|
|
2598
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2599
|
+
err
|
|
2600
|
+
);
|
|
2601
|
+
});
|
|
2602
|
+
return res.insertedId;
|
|
2603
|
+
} catch (error) {
|
|
2604
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2605
|
+
if (isDuplicated) {
|
|
2606
|
+
throw new import_node_server_utils17.BadRequestError("Area already exists.");
|
|
2607
|
+
}
|
|
2608
|
+
throw error;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
async function updateScheduleTaskArea(_id, params) {
|
|
2612
|
+
try {
|
|
2613
|
+
_id = new import_mongodb10.ObjectId(_id);
|
|
2614
|
+
} catch (error) {
|
|
2615
|
+
throw new import_node_server_utils17.BadRequestError("Invalid area ID format.");
|
|
2616
|
+
}
|
|
2617
|
+
try {
|
|
2618
|
+
const updateValue = { ...params, updatedAt: /* @__PURE__ */ new Date() };
|
|
2619
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
2620
|
+
if (res.modifiedCount === 0) {
|
|
2621
|
+
throw new import_node_server_utils17.InternalServerError("Unable to update cleaning area.");
|
|
2622
|
+
}
|
|
2623
|
+
delNamespace().then(() => {
|
|
2624
|
+
import_node_server_utils17.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2625
|
+
}).catch((err) => {
|
|
2626
|
+
import_node_server_utils17.logger.error(
|
|
2627
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2628
|
+
err
|
|
2629
|
+
);
|
|
2630
|
+
});
|
|
2631
|
+
return res.modifiedCount;
|
|
2632
|
+
} catch (error) {
|
|
2633
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2634
|
+
if (isDuplicated) {
|
|
2635
|
+
throw new import_node_server_utils17.BadRequestError("Area already exists.");
|
|
2636
|
+
}
|
|
2637
|
+
throw error;
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
async function deleteScheduleTaskArea(_id, session) {
|
|
2641
|
+
try {
|
|
2642
|
+
_id = new import_mongodb10.ObjectId(_id);
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
throw new import_node_server_utils17.BadRequestError("Invalid area ID format.");
|
|
2645
|
+
}
|
|
2646
|
+
try {
|
|
2647
|
+
const updateValue = {
|
|
2648
|
+
status: "deleted",
|
|
2649
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
2650
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
2651
|
+
};
|
|
2652
|
+
const res = await collection.updateOne(
|
|
2653
|
+
{ _id },
|
|
2654
|
+
{ $set: updateValue },
|
|
2655
|
+
{ session }
|
|
2656
|
+
);
|
|
2657
|
+
if (res.modifiedCount === 0) {
|
|
2658
|
+
throw new import_node_server_utils17.InternalServerError("Unable to delete area.");
|
|
2659
|
+
}
|
|
2660
|
+
delNamespace().then(() => {
|
|
2661
|
+
import_node_server_utils17.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2662
|
+
}).catch((err) => {
|
|
2663
|
+
import_node_server_utils17.logger.error(
|
|
2664
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2665
|
+
err
|
|
2666
|
+
);
|
|
2667
|
+
});
|
|
2668
|
+
return res.modifiedCount;
|
|
2669
|
+
} catch (error) {
|
|
2670
|
+
throw error;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
async function getScheduleTaskAreas({
|
|
2674
|
+
page = 1,
|
|
2675
|
+
limit = 10,
|
|
2676
|
+
search = "",
|
|
2677
|
+
startDate = "",
|
|
2678
|
+
endDate = "",
|
|
2679
|
+
site = ""
|
|
2680
|
+
}) {
|
|
2681
|
+
page = page > 0 ? page - 1 : 0;
|
|
2682
|
+
const query = {
|
|
2683
|
+
status: { $ne: "deleted" }
|
|
2684
|
+
};
|
|
2685
|
+
const cacheOptions = {
|
|
2686
|
+
page,
|
|
2687
|
+
limit
|
|
2688
|
+
};
|
|
2689
|
+
if (site) {
|
|
2690
|
+
try {
|
|
2691
|
+
site = new import_mongodb10.ObjectId(site);
|
|
2692
|
+
cacheOptions.site = site.toString();
|
|
2693
|
+
} catch (error) {
|
|
2694
|
+
throw new import_node_server_utils17.BadRequestError("Invalid site ID format.");
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
if (search) {
|
|
2698
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
2699
|
+
cacheOptions.search = search;
|
|
2700
|
+
}
|
|
2701
|
+
if (startDate && endDate) {
|
|
2702
|
+
query.createdAt = {
|
|
2703
|
+
$gte: new Date(startDate),
|
|
2704
|
+
$lte: new Date(endDate)
|
|
2705
|
+
};
|
|
2706
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
2707
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
2708
|
+
} else if (startDate) {
|
|
2709
|
+
query.createdAt = { $gte: new Date(startDate) };
|
|
2710
|
+
cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
|
|
2711
|
+
} else if (endDate) {
|
|
2712
|
+
query.createdAt = { $lte: new Date(endDate) };
|
|
2713
|
+
cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
|
|
2714
|
+
}
|
|
2715
|
+
const cacheKey = (0, import_node_server_utils17.makeCacheKey)(namespace_collection, cacheOptions);
|
|
2716
|
+
const cachedData = await getCache(cacheKey);
|
|
2717
|
+
if (cachedData) {
|
|
2718
|
+
import_node_server_utils17.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
2719
|
+
return cachedData;
|
|
2720
|
+
}
|
|
2721
|
+
try {
|
|
2722
|
+
const items = await collection.aggregate([
|
|
2723
|
+
{
|
|
2724
|
+
$match: query
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
$lookup: {
|
|
2728
|
+
from: "sites",
|
|
2729
|
+
localField: "site",
|
|
2730
|
+
foreignField: "_id",
|
|
2731
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
2732
|
+
as: "site"
|
|
2733
|
+
}
|
|
2734
|
+
},
|
|
2735
|
+
{
|
|
2736
|
+
$unwind: {
|
|
2737
|
+
path: "$site",
|
|
2738
|
+
preserveNullAndEmptyArrays: true
|
|
2739
|
+
}
|
|
2740
|
+
},
|
|
2741
|
+
{
|
|
2742
|
+
$lookup: {
|
|
2743
|
+
from: "users",
|
|
2744
|
+
localField: "createdBy",
|
|
2745
|
+
foreignField: "_id",
|
|
2746
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
2747
|
+
as: "createdBy"
|
|
2748
|
+
}
|
|
2749
|
+
},
|
|
2750
|
+
{
|
|
2751
|
+
$unwind: {
|
|
2752
|
+
path: "$createdBy",
|
|
2753
|
+
preserveNullAndEmptyArrays: true
|
|
2754
|
+
}
|
|
2755
|
+
},
|
|
2756
|
+
{
|
|
2757
|
+
$project: {
|
|
2758
|
+
name: 1,
|
|
2759
|
+
site: "$site._id",
|
|
2760
|
+
siteName: "$site.name",
|
|
2761
|
+
createdByName: "$createdBy.name",
|
|
2762
|
+
checklist: 1,
|
|
2763
|
+
status: 1,
|
|
2764
|
+
createdAt: 1
|
|
2765
|
+
}
|
|
2766
|
+
},
|
|
2767
|
+
{ $sort: { _id: -1 } },
|
|
2768
|
+
{ $skip: page * limit },
|
|
2769
|
+
{ $limit: limit }
|
|
2770
|
+
]).toArray();
|
|
2771
|
+
const length = await collection.countDocuments(query);
|
|
2772
|
+
const data = (0, import_node_server_utils17.paginate)(items, page, limit, length);
|
|
2773
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
2774
|
+
import_node_server_utils17.logger.info(`Cache set for key: ${cacheKey}`);
|
|
2775
|
+
}).catch((err) => {
|
|
2776
|
+
import_node_server_utils17.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
2777
|
+
});
|
|
2778
|
+
return data;
|
|
2779
|
+
} catch (error) {
|
|
2780
|
+
throw error;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
async function getScheduleTaskAreaByName(name, site) {
|
|
2784
|
+
try {
|
|
2785
|
+
if (site)
|
|
2786
|
+
site = new import_mongodb10.ObjectId(site);
|
|
2787
|
+
} catch (error) {
|
|
2788
|
+
throw new import_node_server_utils17.BadRequestError("Invalid site ID format.");
|
|
2789
|
+
}
|
|
2790
|
+
try {
|
|
2791
|
+
return await collection.findOne({
|
|
2792
|
+
name: { $regex: new RegExp(`^${name}$`, "i") },
|
|
2793
|
+
...site && { site }
|
|
2794
|
+
});
|
|
2795
|
+
} catch (error) {
|
|
2796
|
+
throw new import_node_server_utils17.BadRequestError("Unable to fetch schedule task area by name.");
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
async function getScheduleTaskAreaById(id, site) {
|
|
2800
|
+
try {
|
|
2801
|
+
id = typeof id === "string" ? new import_mongodb10.ObjectId(id) : id;
|
|
2802
|
+
} catch (error) {
|
|
2803
|
+
throw new import_node_server_utils17.BadRequestError("Invalid unit ID format.");
|
|
2804
|
+
}
|
|
2805
|
+
try {
|
|
2806
|
+
if (site)
|
|
2807
|
+
site = new import_mongodb10.ObjectId(site);
|
|
2808
|
+
} catch (error) {
|
|
2809
|
+
throw new import_node_server_utils17.BadRequestError(
|
|
2810
|
+
"Unable to fetch schedule task area by ID, Invalid site ID format."
|
|
2811
|
+
);
|
|
2812
|
+
}
|
|
2813
|
+
try {
|
|
2814
|
+
return await collection.findOne({ _id: id, ...site && { site } });
|
|
2815
|
+
} catch (error) {
|
|
2816
|
+
throw new import_node_server_utils17.BadRequestError("Unable to fetch schedule task area by id.");
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
async function getAreaById(_id) {
|
|
2820
|
+
try {
|
|
2821
|
+
_id = new import_mongodb10.ObjectId(_id);
|
|
2822
|
+
} catch (error) {
|
|
2823
|
+
throw new import_node_server_utils17.BadRequestError("Invalid area ID format.");
|
|
2824
|
+
}
|
|
2825
|
+
const query = {
|
|
2826
|
+
_id,
|
|
2827
|
+
status: { $ne: "deleted" }
|
|
2828
|
+
};
|
|
2829
|
+
const cacheKey = (0, import_node_server_utils17.makeCacheKey)(namespace_collection, {
|
|
2830
|
+
_id: _id.toString()
|
|
2831
|
+
});
|
|
2832
|
+
const cachedData = await getCache(cacheKey);
|
|
2833
|
+
if (cachedData) {
|
|
2834
|
+
import_node_server_utils17.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
2835
|
+
return cachedData;
|
|
2836
|
+
}
|
|
2837
|
+
try {
|
|
2838
|
+
const data = await collection.aggregate([
|
|
2839
|
+
{ $match: query },
|
|
2840
|
+
{
|
|
2841
|
+
$project: {
|
|
2842
|
+
name: 1,
|
|
2843
|
+
checklist: 1
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
]).toArray();
|
|
2847
|
+
if (!data || !data.length) {
|
|
2848
|
+
throw new import_node_server_utils17.NotFoundError("Area not found.");
|
|
2849
|
+
}
|
|
2850
|
+
setCache(cacheKey, data[0], 15 * 60).then(() => {
|
|
2851
|
+
import_node_server_utils17.logger.info(`Cache set for key: ${cacheKey}`);
|
|
2852
|
+
}).catch((err) => {
|
|
2853
|
+
import_node_server_utils17.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
2854
|
+
});
|
|
2855
|
+
return data[0];
|
|
2856
|
+
} catch (error) {
|
|
2857
|
+
throw error;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
return {
|
|
2861
|
+
createUniqueIndex,
|
|
2862
|
+
createScheduleTaskArea,
|
|
2863
|
+
updateScheduleTaskArea,
|
|
2864
|
+
deleteScheduleTaskArea,
|
|
2865
|
+
getScheduleTaskAreas,
|
|
2866
|
+
createIndexes,
|
|
2867
|
+
getScheduleTaskAreaByName,
|
|
2868
|
+
getScheduleTaskAreaById,
|
|
2869
|
+
getAreaById
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
// src/services/hygiene-schedule-task-area.service.ts
|
|
2874
|
+
var import_node_server_utils18 = require("@iservice365/node-server-utils");
|
|
2875
|
+
function useScheduleTaskAreaService() {
|
|
2876
|
+
const { createScheduleTaskArea: _create } = useScheduleTaskAreaRepository();
|
|
2877
|
+
async function uploadByFile({
|
|
2878
|
+
dataJson,
|
|
2879
|
+
createdBy,
|
|
2880
|
+
site
|
|
2881
|
+
}) {
|
|
2882
|
+
let dataArray;
|
|
2883
|
+
try {
|
|
2884
|
+
dataArray = JSON.parse(dataJson);
|
|
2885
|
+
} catch (error) {
|
|
2886
|
+
throw new import_node_server_utils18.BadRequestError("Invalid JSON format for data in excel");
|
|
2887
|
+
}
|
|
2888
|
+
if (!dataArray || dataArray.length === 0) {
|
|
2889
|
+
throw new import_node_server_utils18.NotFoundError("No data found in the uploaded file");
|
|
2890
|
+
}
|
|
2891
|
+
const session = import_node_server_utils18.useAtlas.getClient()?.startSession();
|
|
2892
|
+
const insertedAreaIds = [];
|
|
2893
|
+
try {
|
|
2894
|
+
session?.startTransaction();
|
|
2895
|
+
for (const row of dataArray) {
|
|
2896
|
+
if (!row?.AREA_NAME) {
|
|
2897
|
+
import_node_server_utils18.logger.warn("Skipping row with missing AREA_NAME:", row);
|
|
2898
|
+
continue;
|
|
2899
|
+
}
|
|
2900
|
+
try {
|
|
2901
|
+
const insertedId = await _create(
|
|
2902
|
+
{
|
|
2903
|
+
name: String(row.AREA_NAME).trim(),
|
|
2904
|
+
site,
|
|
2905
|
+
createdBy
|
|
2906
|
+
},
|
|
2907
|
+
session
|
|
2908
|
+
);
|
|
2909
|
+
insertedAreaIds.push(insertedId);
|
|
2910
|
+
} catch (error) {
|
|
2911
|
+
import_node_server_utils18.logger.error(
|
|
2912
|
+
`Error creating area "${row.AREA_NAME}":`,
|
|
2913
|
+
error.message
|
|
2914
|
+
);
|
|
2915
|
+
continue;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
await session?.commitTransaction();
|
|
2919
|
+
import_node_server_utils18.logger.info(`Successfully uploaded ${insertedAreaIds.length} areas`);
|
|
2920
|
+
return {
|
|
2921
|
+
message: `Successfully uploaded ${insertedAreaIds.length} areas`
|
|
2922
|
+
};
|
|
2923
|
+
} catch (error) {
|
|
2924
|
+
await session?.abortTransaction();
|
|
2925
|
+
import_node_server_utils18.logger.error("Error while uploading area information", error);
|
|
2926
|
+
throw error;
|
|
2927
|
+
} finally {
|
|
2928
|
+
session?.endSession();
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
return {
|
|
2932
|
+
uploadByFile
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
// src/controllers/hygiene-schedule-task-area.controller.ts
|
|
2937
|
+
var import_node_server_utils19 = require("@iservice365/node-server-utils");
|
|
2938
|
+
var import_joi10 = __toESM(require("joi"));
|
|
2939
|
+
function useScheduleTaskAreaController() {
|
|
2940
|
+
const { uploadByFile: _uploadByFile } = useScheduleTaskAreaService();
|
|
2941
|
+
const {
|
|
2942
|
+
getScheduleTaskAreas: _getAll,
|
|
2943
|
+
createScheduleTaskArea: _createScheduleTaskArea,
|
|
2944
|
+
updateScheduleTaskArea: _updateScheduleTaskArea,
|
|
2945
|
+
deleteScheduleTaskArea: _deleteById,
|
|
2946
|
+
getAreaById: _getAreaById
|
|
2947
|
+
} = useScheduleTaskAreaRepository();
|
|
2948
|
+
async function getAll(req, res, next) {
|
|
2949
|
+
const query = req.query;
|
|
2950
|
+
const validation = import_joi10.default.object({
|
|
2951
|
+
page: import_joi10.default.number().min(1).optional().allow("", null),
|
|
2952
|
+
limit: import_joi10.default.number().min(1).optional().allow("", null),
|
|
2953
|
+
search: import_joi10.default.string().optional().allow("", null),
|
|
2954
|
+
startDate: import_joi10.default.alternatives().try(import_joi10.default.date(), import_joi10.default.string()).optional().allow("", null),
|
|
2955
|
+
endDate: import_joi10.default.alternatives().try(import_joi10.default.date(), import_joi10.default.string()).optional().allow("", null),
|
|
2956
|
+
site: import_joi10.default.string().hex().optional().allow("", null)
|
|
2957
|
+
});
|
|
2958
|
+
const { error } = validation.validate(query);
|
|
2959
|
+
if (error) {
|
|
2960
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
2964
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
2965
|
+
const search = req.query.search ?? "";
|
|
2966
|
+
const site = req.query.site ?? "";
|
|
2967
|
+
const startDate = req.query.startDate ?? "";
|
|
2968
|
+
const endDate = req.query.endDate ?? "";
|
|
2969
|
+
try {
|
|
2970
|
+
const data = await _getAll({
|
|
2971
|
+
page,
|
|
2972
|
+
limit,
|
|
2973
|
+
search,
|
|
2974
|
+
site,
|
|
2975
|
+
startDate,
|
|
2976
|
+
endDate
|
|
2977
|
+
});
|
|
2978
|
+
res.json(data);
|
|
2979
|
+
return;
|
|
2980
|
+
} catch (error2) {
|
|
2981
|
+
next(error2);
|
|
2982
|
+
return;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
async function createScheduleTaskArea(req, res, next) {
|
|
2986
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
2987
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2988
|
+
{}
|
|
2989
|
+
) : {};
|
|
2990
|
+
const createdBy = cookies["user"] || "";
|
|
2991
|
+
const payload = { ...req.body, createdBy };
|
|
2992
|
+
const { error } = scheduleTaskAreaSchema.validate(payload);
|
|
2993
|
+
if (error) {
|
|
2994
|
+
import_node_server_utils19.logger.log({ level: "error", message: error.message });
|
|
2995
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
try {
|
|
2999
|
+
const id = await _createScheduleTaskArea(payload);
|
|
3000
|
+
res.status(201).json({ message: "Area created successfully.", id });
|
|
3001
|
+
return;
|
|
3002
|
+
} catch (error2) {
|
|
3003
|
+
import_node_server_utils19.logger.log({ level: "error", message: error2.message });
|
|
3004
|
+
next(error2);
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
async function updateScheduleTaskArea(req, res, next) {
|
|
3009
|
+
const payload = { id: req.params.id, ...req.body };
|
|
3010
|
+
const schema = import_joi10.default.object({
|
|
3011
|
+
id: import_joi10.default.string().hex().required(),
|
|
3012
|
+
name: import_joi10.default.string().required()
|
|
3013
|
+
});
|
|
3014
|
+
const { error } = schema.validate(payload);
|
|
3015
|
+
if (error) {
|
|
3016
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
3017
|
+
import_node_server_utils19.logger.info(`Controller: ${error.message}`);
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
3020
|
+
try {
|
|
3021
|
+
const { id, ...value } = payload;
|
|
3022
|
+
await _updateScheduleTaskArea(id, value);
|
|
3023
|
+
res.json({ message: "Area updated successfully." });
|
|
3024
|
+
return;
|
|
3025
|
+
} catch (error2) {
|
|
3026
|
+
import_node_server_utils19.logger.log({ level: "error", message: error2.message });
|
|
3027
|
+
next(error2);
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
async function deleteScheduleTaskArea(req, res, next) {
|
|
3032
|
+
const id = req.params.id;
|
|
3033
|
+
const validation = import_joi10.default.object({
|
|
3034
|
+
id: import_joi10.default.string().hex().required()
|
|
3035
|
+
});
|
|
3036
|
+
const { error } = validation.validate({ id });
|
|
3037
|
+
if (error) {
|
|
3038
|
+
import_node_server_utils19.logger.log({ level: "error", message: error.message });
|
|
3039
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
try {
|
|
3043
|
+
await _deleteById(id);
|
|
3044
|
+
res.json({ message: "Area deleted successfully." });
|
|
3045
|
+
return;
|
|
3046
|
+
} catch (error2) {
|
|
3047
|
+
import_node_server_utils19.logger.log({ level: "error", message: error2.message });
|
|
3048
|
+
next(error2);
|
|
3049
|
+
return;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
async function uploadByFile(req, res, next) {
|
|
3053
|
+
if (!req.file) {
|
|
3054
|
+
next(new import_node_server_utils19.BadRequestError("File is required!"));
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
3058
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3059
|
+
{}
|
|
3060
|
+
) : {};
|
|
3061
|
+
const createdBy = cookies["user"] || "";
|
|
3062
|
+
const { site } = req.body;
|
|
3063
|
+
const schema = import_joi10.default.object({
|
|
3064
|
+
site: import_joi10.default.string().hex().optional().allow("", null),
|
|
3065
|
+
createdBy: import_joi10.default.string().hex().required()
|
|
3066
|
+
});
|
|
3067
|
+
const { error } = schema.validate({ site, createdBy });
|
|
3068
|
+
if (error) {
|
|
3069
|
+
import_node_server_utils19.logger.log({ level: "error", message: error.message });
|
|
3070
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
3071
|
+
return;
|
|
3072
|
+
}
|
|
3073
|
+
try {
|
|
3074
|
+
const xlsData = await convertBufferFile(req.file.buffer);
|
|
3075
|
+
const dataJson = JSON.stringify(xlsData);
|
|
3076
|
+
const result = await _uploadByFile({ dataJson, createdBy, site });
|
|
3077
|
+
return res.status(201).json(result);
|
|
3078
|
+
} catch (error2) {
|
|
3079
|
+
import_node_server_utils19.logger.log({ level: "error", message: error2.message });
|
|
3080
|
+
next(error2);
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
async function getAreaById(req, res, next) {
|
|
3085
|
+
const validation = import_joi10.default.string().hex().required();
|
|
3086
|
+
const _id = req.params.id;
|
|
3087
|
+
const { error } = validation.validate(_id);
|
|
3088
|
+
if (error) {
|
|
3089
|
+
import_node_server_utils19.logger.log({ level: "error", message: error.message });
|
|
3090
|
+
next(new import_node_server_utils19.BadRequestError(error.message));
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
try {
|
|
3094
|
+
const data = await _getAreaById(_id);
|
|
3095
|
+
res.json(data);
|
|
3096
|
+
return;
|
|
3097
|
+
} catch (error2) {
|
|
3098
|
+
import_node_server_utils19.logger.log({ level: "error", message: error2.message });
|
|
3099
|
+
next(error2);
|
|
3100
|
+
return;
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
return {
|
|
3104
|
+
getAll,
|
|
3105
|
+
getAreaById,
|
|
3106
|
+
createScheduleTaskArea,
|
|
3107
|
+
updateScheduleTaskArea,
|
|
3108
|
+
deleteScheduleTaskArea,
|
|
3109
|
+
uploadByFile
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
// src/models/hygiene-area-checklist.model.ts
|
|
3114
|
+
var import_node_server_utils20 = require("@iservice365/node-server-utils");
|
|
3115
|
+
var import_joi11 = __toESM(require("joi"));
|
|
3116
|
+
var import_mongodb11 = require("mongodb");
|
|
3117
|
+
var areaChecklistSchema = import_joi11.default.object({
|
|
3118
|
+
type: import_joi11.default.string().required().valid(...allowedTypes),
|
|
3119
|
+
site: import_joi11.default.string().hex().required(),
|
|
3120
|
+
parentChecklist: import_joi11.default.string().hex().required(),
|
|
3121
|
+
area: import_joi11.default.string().hex().required(),
|
|
3122
|
+
name: import_joi11.default.string().optional().allow("", null),
|
|
3123
|
+
createdBy: import_joi11.default.string().hex().optional().allow("", null)
|
|
3124
|
+
});
|
|
3125
|
+
function MAreaChecklist(value) {
|
|
3126
|
+
const { error } = areaChecklistSchema.validate(value);
|
|
3127
|
+
if (error) {
|
|
3128
|
+
import_node_server_utils20.logger.info(`Hygiene Checklist Area Model: ${error.message}`);
|
|
3129
|
+
throw new import_node_server_utils20.BadRequestError(error.message);
|
|
3130
|
+
}
|
|
3131
|
+
if (value.site) {
|
|
3132
|
+
try {
|
|
3133
|
+
value.site = new import_mongodb11.ObjectId(value.site);
|
|
3134
|
+
} catch (error2) {
|
|
3135
|
+
throw new import_node_server_utils20.BadRequestError("Invalid site ID format.");
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
if (value.parentChecklist) {
|
|
3139
|
+
try {
|
|
3140
|
+
value.parentChecklist = new import_mongodb11.ObjectId(value.parentChecklist);
|
|
3141
|
+
} catch (error2) {
|
|
3142
|
+
throw new import_node_server_utils20.BadRequestError("Invalid checklist ID format.");
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
if (value.area) {
|
|
3146
|
+
try {
|
|
3147
|
+
value.area = new import_mongodb11.ObjectId(value.area);
|
|
3148
|
+
} catch (error2) {
|
|
3149
|
+
throw new import_node_server_utils20.BadRequestError("Invalid area ID format.");
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
if (value.createdBy) {
|
|
3153
|
+
try {
|
|
3154
|
+
value.createdBy = new import_mongodb11.ObjectId(value.createdBy);
|
|
3155
|
+
} catch (error2) {
|
|
3156
|
+
throw new import_node_server_utils20.BadRequestError("Invalid createdBy ID format.");
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
if (value.acceptedBy) {
|
|
3160
|
+
try {
|
|
3161
|
+
value.acceptedBy = new import_mongodb11.ObjectId(value.acceptedBy);
|
|
3162
|
+
} catch (error2) {
|
|
3163
|
+
throw new import_node_server_utils20.BadRequestError("Invalid acceptedBy ID format.");
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
return {
|
|
3167
|
+
type: value.type,
|
|
3168
|
+
site: value.site,
|
|
3169
|
+
parentChecklist: value.parentChecklist,
|
|
3170
|
+
area: value.area,
|
|
3171
|
+
name: value.name ?? "",
|
|
3172
|
+
status: value.status ?? "To Do",
|
|
3173
|
+
createdBy: value.createdBy ?? "",
|
|
3174
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
3175
|
+
acceptedBy: value.acceptedBy ?? "",
|
|
3176
|
+
acceptedAt: value.acceptedAt ?? "",
|
|
3177
|
+
startedAt: value.startedAt ?? "",
|
|
3178
|
+
endedAt: value.endedAt ?? "",
|
|
3179
|
+
signature: value.signature ?? "",
|
|
3180
|
+
updatedAt: value.updatedAt ?? ""
|
|
3181
|
+
};
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
// src/repositories/hygiene-area-checklist.repository.ts
|
|
3185
|
+
var import_node_server_utils21 = require("@iservice365/node-server-utils");
|
|
3186
|
+
var import_mongodb12 = require("mongodb");
|
|
3187
|
+
function useAreaChecklistRepo() {
|
|
3188
|
+
const db = import_node_server_utils21.useAtlas.getDb();
|
|
3189
|
+
if (!db) {
|
|
3190
|
+
throw new import_node_server_utils21.InternalServerError("Unable to connect to server.");
|
|
3191
|
+
}
|
|
3192
|
+
const namespace_collection = "hygiene-checklist.areas";
|
|
3193
|
+
const unit_checklist_collection = "hygiene-checklist.units";
|
|
3194
|
+
const collection = db.collection(namespace_collection);
|
|
3195
|
+
const unitChecklistCollection = db.collection(unit_checklist_collection);
|
|
3196
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils21.useCache)(namespace_collection);
|
|
3197
|
+
const { delNamespace: delUnitNamespace } = (0, import_node_server_utils21.useCache)(
|
|
3198
|
+
unit_checklist_collection
|
|
3199
|
+
);
|
|
3200
|
+
async function createIndex() {
|
|
3201
|
+
try {
|
|
3202
|
+
await collection.createIndexes([
|
|
3203
|
+
{ key: { type: 1 } },
|
|
3204
|
+
{ key: { site: 1 } },
|
|
3205
|
+
{ key: { parentChecklist: 1 } },
|
|
3206
|
+
{ key: { area: 1 } },
|
|
3207
|
+
{ key: { createdAt: 1 } },
|
|
3208
|
+
{ key: { acceptedBy: 1 } }
|
|
3209
|
+
]);
|
|
3210
|
+
} catch (error) {
|
|
3211
|
+
throw new import_node_server_utils21.InternalServerError(
|
|
3212
|
+
"Failed to create index on hygiene checklist area."
|
|
3213
|
+
);
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
async function createTextIndex() {
|
|
3217
|
+
try {
|
|
3218
|
+
await collection.createIndex({ name: "text" });
|
|
3219
|
+
} catch (error) {
|
|
3220
|
+
throw new import_node_server_utils21.InternalServerError(
|
|
3221
|
+
"Failed to create text index on hygiene checklist area."
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
async function createAreaChecklist(value, session) {
|
|
3226
|
+
try {
|
|
3227
|
+
const siteId = new import_mongodb12.ObjectId(value.site);
|
|
3228
|
+
const parentChecklistId = new import_mongodb12.ObjectId(value.parentChecklist);
|
|
3229
|
+
const areaId = new import_mongodb12.ObjectId(value.area);
|
|
3230
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
3231
|
+
const startOfDay = new Date(currentDate);
|
|
3232
|
+
startOfDay.setUTCHours(0, 0, 0, 0);
|
|
3233
|
+
const endOfDay = new Date(currentDate);
|
|
3234
|
+
endOfDay.setUTCHours(23, 59, 59, 999);
|
|
3235
|
+
const existingChecklist = await collection.findOne({
|
|
3236
|
+
type: value.type,
|
|
3237
|
+
site: siteId,
|
|
3238
|
+
parentChecklist: parentChecklistId,
|
|
3239
|
+
area: areaId,
|
|
3240
|
+
createdAt: {
|
|
3241
|
+
$gte: startOfDay,
|
|
3242
|
+
$lte: endOfDay
|
|
3243
|
+
}
|
|
3244
|
+
});
|
|
3245
|
+
if (existingChecklist) {
|
|
3246
|
+
import_node_server_utils21.logger.info(
|
|
3247
|
+
`Area checklist already exists for area ${areaId} on ${currentDate.toISOString().split("T")[0]}`
|
|
3248
|
+
);
|
|
3249
|
+
return existingChecklist._id;
|
|
3250
|
+
}
|
|
3251
|
+
const processedValue = MAreaChecklist(value);
|
|
3252
|
+
const result = await collection.insertOne(processedValue, { session });
|
|
3253
|
+
delNamespace().then(() => {
|
|
3254
|
+
import_node_server_utils21.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
3255
|
+
}).catch((err) => {
|
|
3256
|
+
import_node_server_utils21.logger.error(
|
|
3257
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3258
|
+
err
|
|
3259
|
+
);
|
|
3260
|
+
});
|
|
3261
|
+
return result.insertedId;
|
|
3262
|
+
} catch (error) {
|
|
3263
|
+
throw error;
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
async function getAllAreaChecklist({
|
|
3267
|
+
page = 1,
|
|
3268
|
+
limit = 10,
|
|
3269
|
+
search = "",
|
|
3270
|
+
site,
|
|
3271
|
+
type,
|
|
3272
|
+
parentChecklist
|
|
3273
|
+
}) {
|
|
3274
|
+
page = page > 0 ? page - 1 : 0;
|
|
3275
|
+
const query = { type };
|
|
3276
|
+
const cacheOptions = {
|
|
3277
|
+
page,
|
|
3278
|
+
limit
|
|
3279
|
+
};
|
|
3280
|
+
try {
|
|
3281
|
+
query.site = new import_mongodb12.ObjectId(site);
|
|
3282
|
+
cacheOptions.site = site.toString();
|
|
3283
|
+
} catch (error) {
|
|
3284
|
+
throw new import_node_server_utils21.BadRequestError("Invalid site ID format.");
|
|
3285
|
+
}
|
|
3286
|
+
try {
|
|
3287
|
+
query.parentChecklist = new import_mongodb12.ObjectId(parentChecklist);
|
|
3288
|
+
cacheOptions.parentChecklist = parentChecklist.toString();
|
|
3289
|
+
} catch (error) {
|
|
3290
|
+
throw new import_node_server_utils21.BadRequestError("Invalid parent checklist ID format.");
|
|
3291
|
+
}
|
|
3292
|
+
if (search) {
|
|
3293
|
+
query.$text = { $search: search };
|
|
3294
|
+
cacheOptions.search = search;
|
|
3295
|
+
}
|
|
3296
|
+
const cacheKey = (0, import_node_server_utils21.makeCacheKey)(namespace_collection, cacheOptions);
|
|
3297
|
+
const cachedData = await getCache(cacheKey);
|
|
3298
|
+
if (cachedData) {
|
|
3299
|
+
import_node_server_utils21.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
3300
|
+
return cachedData;
|
|
3301
|
+
}
|
|
3302
|
+
try {
|
|
3303
|
+
const pipeline = [
|
|
3304
|
+
{ $match: query },
|
|
3305
|
+
{
|
|
3306
|
+
$lookup: {
|
|
3307
|
+
from: "users",
|
|
3308
|
+
localField: "acceptedBy",
|
|
3309
|
+
foreignField: "_id",
|
|
3310
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
3311
|
+
as: "acceptedBy"
|
|
3312
|
+
}
|
|
3313
|
+
},
|
|
3314
|
+
{
|
|
3315
|
+
$unwind: {
|
|
3316
|
+
path: "$acceptedBy",
|
|
3317
|
+
preserveNullAndEmptyArrays: true
|
|
3318
|
+
}
|
|
3319
|
+
},
|
|
3320
|
+
{
|
|
3321
|
+
$project: {
|
|
3322
|
+
name: 1,
|
|
3323
|
+
acceptedByName: "$acceptedBy.name",
|
|
3324
|
+
status: 1,
|
|
3325
|
+
createdAt: 1
|
|
3326
|
+
}
|
|
3327
|
+
},
|
|
3328
|
+
{ $sort: { _id: -1 } },
|
|
3329
|
+
{ $skip: page * limit },
|
|
3330
|
+
{ $limit: limit }
|
|
3331
|
+
];
|
|
3332
|
+
const items = await collection.aggregate(pipeline).toArray();
|
|
3333
|
+
const length = await collection.countDocuments(query);
|
|
3334
|
+
const data = (0, import_node_server_utils21.paginate)(items, page, limit, length);
|
|
3335
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
3336
|
+
import_node_server_utils21.logger.info(`Cache set for key: ${cacheKey}`);
|
|
3337
|
+
}).catch((err) => {
|
|
3338
|
+
import_node_server_utils21.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
3339
|
+
});
|
|
3340
|
+
return data;
|
|
3341
|
+
} catch (error) {
|
|
3342
|
+
throw error;
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
async function getAreaChecklistHistory({
|
|
3346
|
+
page = 1,
|
|
3347
|
+
limit = 10,
|
|
3348
|
+
search = "",
|
|
3349
|
+
site,
|
|
3350
|
+
type,
|
|
3351
|
+
parentChecklist,
|
|
3352
|
+
status,
|
|
3353
|
+
createdAt,
|
|
3354
|
+
user
|
|
3355
|
+
}) {
|
|
3356
|
+
page = page > 0 ? page - 1 : 0;
|
|
3357
|
+
const query = { type };
|
|
3358
|
+
const cacheOptions = {
|
|
3359
|
+
page,
|
|
3360
|
+
limit
|
|
3361
|
+
};
|
|
3362
|
+
try {
|
|
3363
|
+
query.site = new import_mongodb12.ObjectId(site);
|
|
3364
|
+
cacheOptions.site = site.toString();
|
|
3365
|
+
} catch (error) {
|
|
3366
|
+
throw new import_node_server_utils21.BadRequestError("Invalid site ID format.");
|
|
3367
|
+
}
|
|
3368
|
+
try {
|
|
3369
|
+
query.parentChecklist = new import_mongodb12.ObjectId(parentChecklist);
|
|
3370
|
+
cacheOptions.parentChecklist = parentChecklist.toString();
|
|
3371
|
+
} catch (error) {
|
|
3372
|
+
throw new import_node_server_utils21.BadRequestError("Invalid parent checklist ID format.");
|
|
3373
|
+
}
|
|
3374
|
+
if (search) {
|
|
3375
|
+
query.$text = { $search: search };
|
|
3376
|
+
cacheOptions.search = search;
|
|
3377
|
+
}
|
|
3378
|
+
if (createdAt) {
|
|
3379
|
+
query.createdAt = {
|
|
3380
|
+
$gte: /* @__PURE__ */ new Date(`${createdAt}T00:00:00Z`),
|
|
3381
|
+
$lte: /* @__PURE__ */ new Date(`${createdAt}T23:59:59Z`)
|
|
3382
|
+
};
|
|
3383
|
+
cacheOptions.createdAt = new Date(createdAt).toISOString().split("T")[0];
|
|
3384
|
+
}
|
|
3385
|
+
if (status) {
|
|
3386
|
+
query.status = status;
|
|
3387
|
+
cacheOptions.status = status;
|
|
3388
|
+
} else {
|
|
3389
|
+
query.status = { $in: ["In Progress", "Completed"] };
|
|
3390
|
+
}
|
|
3391
|
+
if (user) {
|
|
3392
|
+
try {
|
|
3393
|
+
query.acceptedBy = new import_mongodb12.ObjectId(user);
|
|
3394
|
+
cacheOptions.user = user.toString();
|
|
3395
|
+
} catch (error) {
|
|
3396
|
+
throw new import_node_server_utils21.BadRequestError("Invalid user ID format.");
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
const cacheKey = (0, import_node_server_utils21.makeCacheKey)(namespace_collection, cacheOptions);
|
|
3400
|
+
const cachedData = await getCache(cacheKey);
|
|
3401
|
+
if (cachedData) {
|
|
3402
|
+
import_node_server_utils21.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
3403
|
+
return cachedData;
|
|
3404
|
+
}
|
|
3405
|
+
try {
|
|
3406
|
+
const pipeline = [
|
|
3407
|
+
{ $match: query },
|
|
3408
|
+
{
|
|
3409
|
+
$lookup: {
|
|
3410
|
+
from: "users",
|
|
3411
|
+
localField: "acceptedBy",
|
|
3412
|
+
foreignField: "_id",
|
|
3413
|
+
pipeline: [
|
|
3414
|
+
...search ? [{ $match: { name: { $regex: search, $options: "i" } } }] : [],
|
|
3415
|
+
{ $project: { name: 1 } }
|
|
3416
|
+
],
|
|
3417
|
+
as: "acceptedBy"
|
|
3418
|
+
}
|
|
3419
|
+
},
|
|
3420
|
+
{
|
|
3421
|
+
$unwind: {
|
|
3422
|
+
path: "$acceptedBy",
|
|
3423
|
+
preserveNullAndEmptyArrays: true
|
|
3424
|
+
}
|
|
3425
|
+
},
|
|
3426
|
+
{
|
|
3427
|
+
$project: {
|
|
3428
|
+
name: 1,
|
|
3429
|
+
createdAt: 1,
|
|
3430
|
+
acceptedByName: "$acceptedBy.name",
|
|
3431
|
+
status: 1,
|
|
3432
|
+
startedAt: 1,
|
|
3433
|
+
endedAt: 1
|
|
3434
|
+
}
|
|
3435
|
+
},
|
|
3436
|
+
{ $sort: { status: 1 } },
|
|
3437
|
+
{ $skip: page * limit },
|
|
3438
|
+
{ $limit: limit }
|
|
3439
|
+
];
|
|
3440
|
+
const items = await collection.aggregate(pipeline).toArray();
|
|
3441
|
+
const length = await collection.countDocuments(query);
|
|
3442
|
+
const data = (0, import_node_server_utils21.paginate)(items, page, limit, length);
|
|
3443
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
3444
|
+
import_node_server_utils21.logger.info(`Cache set for key: ${cacheKey}`);
|
|
3445
|
+
}).catch((err) => {
|
|
3446
|
+
import_node_server_utils21.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
3447
|
+
});
|
|
3448
|
+
return data;
|
|
3449
|
+
} catch (error) {
|
|
3450
|
+
throw error;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
async function getAreaChecklistHistoryDetails(_id) {
|
|
3454
|
+
try {
|
|
3455
|
+
_id = new import_mongodb12.ObjectId(_id);
|
|
3456
|
+
} catch (error) {
|
|
3457
|
+
throw new import_node_server_utils21.BadRequestError("Invalid area checklist ID format.");
|
|
3458
|
+
}
|
|
3459
|
+
const cacheKey = (0, import_node_server_utils21.makeCacheKey)(namespace_collection, {
|
|
3460
|
+
_id: _id.toString()
|
|
3461
|
+
});
|
|
3462
|
+
const cachedData = await getCache(cacheKey);
|
|
3463
|
+
if (cachedData) {
|
|
3464
|
+
import_node_server_utils21.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
3465
|
+
return cachedData;
|
|
3466
|
+
}
|
|
3467
|
+
try {
|
|
3468
|
+
const areaPipeline = [
|
|
3469
|
+
{ $match: { _id } },
|
|
3470
|
+
{
|
|
3471
|
+
$lookup: {
|
|
3472
|
+
from: "users",
|
|
3473
|
+
localField: "createdBy",
|
|
3474
|
+
foreignField: "_id",
|
|
3475
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
3476
|
+
as: "createdBy"
|
|
3477
|
+
}
|
|
3478
|
+
},
|
|
3479
|
+
{
|
|
3480
|
+
$unwind: {
|
|
3481
|
+
path: "$createdBy",
|
|
3482
|
+
preserveNullAndEmptyArrays: true
|
|
3483
|
+
}
|
|
3484
|
+
},
|
|
3485
|
+
{
|
|
3486
|
+
$lookup: {
|
|
3487
|
+
from: "users",
|
|
3488
|
+
localField: "acceptedBy",
|
|
3489
|
+
foreignField: "_id",
|
|
3490
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
3491
|
+
as: "acceptedBy"
|
|
3492
|
+
}
|
|
3493
|
+
},
|
|
3494
|
+
{
|
|
3495
|
+
$unwind: {
|
|
3496
|
+
path: "$acceptedBy",
|
|
3497
|
+
preserveNullAndEmptyArrays: true
|
|
3498
|
+
}
|
|
3499
|
+
},
|
|
3500
|
+
{
|
|
3501
|
+
$project: {
|
|
3502
|
+
name: 1,
|
|
3503
|
+
createdAt: 1,
|
|
3504
|
+
createdByName: "$createdBy.name",
|
|
3505
|
+
startedAt: 1,
|
|
3506
|
+
endedAt: 1,
|
|
3507
|
+
status: 1,
|
|
3508
|
+
signature: 1,
|
|
3509
|
+
acceptedByName: "$acceptedBy.name"
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
];
|
|
3513
|
+
const unitPipeline = [
|
|
3514
|
+
{ $match: { areaChecklist: _id } },
|
|
3515
|
+
{
|
|
3516
|
+
$project: {
|
|
3517
|
+
name: 1,
|
|
3518
|
+
remarks: "$metadata.remarks",
|
|
3519
|
+
attachments: "$metadata.attachments",
|
|
3520
|
+
approve: { $ifNull: ["$approve", null] },
|
|
3521
|
+
reject: { $ifNull: ["$reject", null] }
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
];
|
|
3525
|
+
const [area, units] = await Promise.all([
|
|
3526
|
+
collection.aggregate(areaPipeline).toArray(),
|
|
3527
|
+
unitChecklistCollection.aggregate(unitPipeline).toArray()
|
|
3528
|
+
]);
|
|
3529
|
+
if (!area.length) {
|
|
3530
|
+
throw new import_node_server_utils21.BadRequestError("Area checklist not found.");
|
|
3531
|
+
}
|
|
3532
|
+
const items = {
|
|
3533
|
+
area: area[0],
|
|
3534
|
+
units
|
|
3535
|
+
};
|
|
3536
|
+
setCache(cacheKey, items, 15 * 60).then(() => {
|
|
3537
|
+
import_node_server_utils21.logger.info(`Cache set for key: ${cacheKey}`);
|
|
3538
|
+
}).catch((err) => {
|
|
3539
|
+
import_node_server_utils21.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
3540
|
+
});
|
|
3541
|
+
return items;
|
|
3542
|
+
} catch (error) {
|
|
3543
|
+
throw error;
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
async function acceptAreaChecklist(_id, acceptedBy) {
|
|
3547
|
+
try {
|
|
3548
|
+
_id = new import_mongodb12.ObjectId(_id);
|
|
3549
|
+
} catch (error) {
|
|
3550
|
+
throw new import_node_server_utils21.BadRequestError("Invalid area ID format.");
|
|
3551
|
+
}
|
|
3552
|
+
try {
|
|
3553
|
+
acceptedBy = new import_mongodb12.ObjectId(acceptedBy);
|
|
3554
|
+
} catch (error) {
|
|
3555
|
+
throw new import_node_server_utils21.BadRequestError("Invalid acceptedBy ID format.");
|
|
3556
|
+
}
|
|
3557
|
+
try {
|
|
3558
|
+
const now = /* @__PURE__ */ new Date();
|
|
3559
|
+
const updateValue = {
|
|
3560
|
+
acceptedBy,
|
|
3561
|
+
acceptedAt: now,
|
|
3562
|
+
startedAt: now,
|
|
3563
|
+
updatedAt: now
|
|
3564
|
+
};
|
|
3565
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
3566
|
+
if (res.modifiedCount === 0) {
|
|
3567
|
+
throw new import_node_server_utils21.InternalServerError("Unable to update cleaning area.");
|
|
3568
|
+
}
|
|
3569
|
+
delNamespace().then(() => {
|
|
3570
|
+
import_node_server_utils21.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
3571
|
+
}).catch((err) => {
|
|
3572
|
+
import_node_server_utils21.logger.error(
|
|
3573
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3574
|
+
err
|
|
3575
|
+
);
|
|
3576
|
+
});
|
|
3577
|
+
return res.modifiedCount;
|
|
3578
|
+
} catch (error) {
|
|
3579
|
+
throw error;
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
async function attachImageAreaChecklist(_id, attachments, session) {
|
|
3583
|
+
try {
|
|
3584
|
+
_id = new import_mongodb12.ObjectId(_id);
|
|
3585
|
+
} catch (error) {
|
|
3586
|
+
throw new import_node_server_utils21.BadRequestError("Invalid area checklist ID format.");
|
|
3587
|
+
}
|
|
3588
|
+
try {
|
|
3589
|
+
const now = /* @__PURE__ */ new Date();
|
|
3590
|
+
const updateValue = {
|
|
3591
|
+
metadata: { attachments },
|
|
3592
|
+
updatedAt: now
|
|
3593
|
+
};
|
|
3594
|
+
const res = await collection.updateOne(
|
|
3595
|
+
{ _id },
|
|
3596
|
+
{ $set: updateValue },
|
|
3597
|
+
{ session }
|
|
3598
|
+
);
|
|
3599
|
+
if (res.modifiedCount === 0) {
|
|
3600
|
+
throw new import_node_server_utils21.InternalServerError(
|
|
3601
|
+
"Unable to update cleaning area checklist."
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3604
|
+
delNamespace().then(() => {
|
|
3605
|
+
import_node_server_utils21.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
3606
|
+
}).catch((err) => {
|
|
3607
|
+
import_node_server_utils21.logger.error(
|
|
3608
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3609
|
+
err
|
|
3610
|
+
);
|
|
3611
|
+
});
|
|
3612
|
+
delUnitNamespace().then(() => {
|
|
3613
|
+
import_node_server_utils21.logger.info(
|
|
3614
|
+
`Cache cleared for namespace: ${unit_checklist_collection}`
|
|
3615
|
+
);
|
|
3616
|
+
}).catch((err) => {
|
|
3617
|
+
import_node_server_utils21.logger.error(
|
|
3618
|
+
`Failed to clear cache for namespace: ${unit_checklist_collection}`,
|
|
3619
|
+
err
|
|
3620
|
+
);
|
|
3621
|
+
});
|
|
3622
|
+
return res.modifiedCount;
|
|
3623
|
+
} catch (error) {
|
|
3624
|
+
throw error;
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
async function submitAreaChecklist(_id, signature) {
|
|
3628
|
+
try {
|
|
3629
|
+
_id = new import_mongodb12.ObjectId(_id);
|
|
3630
|
+
} catch (error) {
|
|
3631
|
+
throw new import_node_server_utils21.BadRequestError("Invalid area ID format.");
|
|
3632
|
+
}
|
|
3633
|
+
try {
|
|
3634
|
+
const now = /* @__PURE__ */ new Date();
|
|
3635
|
+
const updateValue = {
|
|
3636
|
+
signature,
|
|
3637
|
+
status: "In Progress",
|
|
3638
|
+
endedAt: now,
|
|
3639
|
+
updatedAt: now
|
|
3640
|
+
};
|
|
3641
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
3642
|
+
if (res.modifiedCount === 0) {
|
|
3643
|
+
throw new import_node_server_utils21.InternalServerError("Unable to update cleaning area.");
|
|
3644
|
+
}
|
|
3645
|
+
delNamespace().then(() => {
|
|
3646
|
+
import_node_server_utils21.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
3647
|
+
}).catch((err) => {
|
|
3648
|
+
import_node_server_utils21.logger.error(
|
|
3649
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3650
|
+
err
|
|
3651
|
+
);
|
|
3652
|
+
});
|
|
3653
|
+
return res.modifiedCount;
|
|
3654
|
+
} catch (error) {
|
|
3655
|
+
throw error;
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
async function completeAreaChecklist(_id, signature) {
|
|
3659
|
+
try {
|
|
3660
|
+
_id = new import_mongodb12.ObjectId(_id);
|
|
3661
|
+
} catch (error) {
|
|
3662
|
+
throw new import_node_server_utils21.BadRequestError("Invalid area ID format.");
|
|
3663
|
+
}
|
|
3664
|
+
try {
|
|
3665
|
+
const now = /* @__PURE__ */ new Date();
|
|
3666
|
+
const updateValue = {
|
|
3667
|
+
signature,
|
|
3668
|
+
status: "Completed",
|
|
3669
|
+
endedAt: now,
|
|
3670
|
+
updatedAt: now
|
|
3671
|
+
};
|
|
3672
|
+
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
3673
|
+
if (res.modifiedCount === 0) {
|
|
3674
|
+
throw new import_node_server_utils21.InternalServerError("Unable to update cleaning area.");
|
|
3675
|
+
}
|
|
3676
|
+
delNamespace().then(() => {
|
|
3677
|
+
import_node_server_utils21.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
3678
|
+
}).catch((err) => {
|
|
3679
|
+
import_node_server_utils21.logger.error(
|
|
3680
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3681
|
+
err
|
|
3682
|
+
);
|
|
3683
|
+
});
|
|
3684
|
+
return res.modifiedCount;
|
|
3685
|
+
} catch (error) {
|
|
3686
|
+
throw error;
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
return {
|
|
3690
|
+
createIndex,
|
|
3691
|
+
createTextIndex,
|
|
3692
|
+
createAreaChecklist,
|
|
3693
|
+
getAllAreaChecklist,
|
|
3694
|
+
getAreaChecklistHistory,
|
|
3695
|
+
getAreaChecklistHistoryDetails,
|
|
3696
|
+
acceptAreaChecklist,
|
|
3697
|
+
attachImageAreaChecklist,
|
|
3698
|
+
submitAreaChecklist,
|
|
3699
|
+
completeAreaChecklist
|
|
3700
|
+
};
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
// src/controllers/hygiene-area-checklist.controller.ts
|
|
3704
|
+
var import_node_server_utils23 = require("@iservice365/node-server-utils");
|
|
3705
|
+
var import_joi12 = __toESM(require("joi"));
|
|
3706
|
+
|
|
3707
|
+
// src/services/hygiene-area-checklist.service.ts
|
|
3708
|
+
var import_node_server_utils22 = require("@iservice365/node-server-utils");
|
|
3709
|
+
function useAreaChecklistService() {
|
|
3710
|
+
const { createAreaChecklist: _createAreaChecklist } = useAreaChecklistRepo();
|
|
3711
|
+
const { getAreas } = useAreaRepository();
|
|
3712
|
+
const { getToiletLocations } = useToiletLocationRepository();
|
|
3713
|
+
async function createAreaChecklist(value) {
|
|
3714
|
+
try {
|
|
3715
|
+
const results = [];
|
|
3716
|
+
if (value.type === "cleaner") {
|
|
3717
|
+
const cleanerAreasResult = await getAreas({
|
|
3718
|
+
site: value.site
|
|
3719
|
+
});
|
|
3720
|
+
const cleanerAreas = cleanerAreasResult.items || [];
|
|
3721
|
+
if (cleanerAreas.length === 0) {
|
|
3722
|
+
import_node_server_utils22.logger.warn(`No cleaner areas found for site: ${value.site}`);
|
|
3723
|
+
return results;
|
|
3724
|
+
}
|
|
3725
|
+
for (const area of cleanerAreas) {
|
|
3726
|
+
const checklistData = {
|
|
3727
|
+
type: "cleaner",
|
|
3728
|
+
site: value.site,
|
|
3729
|
+
parentChecklist: value.parentChecklist,
|
|
3730
|
+
area: area._id.toString(),
|
|
3731
|
+
name: area.name,
|
|
3732
|
+
createdBy: value.createdBy
|
|
3733
|
+
};
|
|
3734
|
+
const insertedId = await _createAreaChecklist(checklistData);
|
|
3735
|
+
results.push(insertedId);
|
|
3736
|
+
}
|
|
3737
|
+
import_node_server_utils22.logger.info(
|
|
3738
|
+
`Created ${results.length} cleaner area checklists for site: ${value.site}`
|
|
3739
|
+
);
|
|
3740
|
+
}
|
|
3741
|
+
if (value.type === "toilet") {
|
|
3742
|
+
const toiletAreasResult = await getToiletLocations({
|
|
3743
|
+
site: value.site
|
|
3744
|
+
});
|
|
3745
|
+
const toiletAreas = toiletAreasResult.items || [];
|
|
3746
|
+
if (toiletAreas.length === 0) {
|
|
3747
|
+
import_node_server_utils22.logger.warn(`No toilet locations found for site: ${value.site}`);
|
|
3748
|
+
return results;
|
|
3749
|
+
}
|
|
3750
|
+
for (const toiletLocation of toiletAreas) {
|
|
3751
|
+
const checklistData = {
|
|
3752
|
+
type: "toilet",
|
|
3753
|
+
site: value.site,
|
|
3754
|
+
parentChecklist: value.parentChecklist,
|
|
3755
|
+
area: toiletLocation._id,
|
|
3756
|
+
name: toiletLocation.name,
|
|
3757
|
+
createdBy: value.createdBy
|
|
3758
|
+
};
|
|
3759
|
+
const insertedId = await _createAreaChecklist(checklistData);
|
|
3760
|
+
results.push(insertedId);
|
|
3761
|
+
}
|
|
3762
|
+
import_node_server_utils22.logger.info(
|
|
3763
|
+
`Created ${results.length} toilet area checklists for site: ${value.site}`
|
|
3764
|
+
);
|
|
3765
|
+
}
|
|
3766
|
+
return results;
|
|
3767
|
+
} catch (error) {
|
|
3768
|
+
import_node_server_utils22.logger.error(`Error generating area checklists:`, error);
|
|
3769
|
+
throw error;
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
return { createAreaChecklist };
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
// src/controllers/hygiene-area-checklist.controller.ts
|
|
3776
|
+
function useAreaChecklistController() {
|
|
3777
|
+
const {
|
|
3778
|
+
getAllAreaChecklist: _getAllAreaChecklist,
|
|
3779
|
+
getAreaChecklistHistory: _getAreaChecklistHistory,
|
|
3780
|
+
getAreaChecklistHistoryDetails: _getAreaChecklistHistoryDetails,
|
|
3781
|
+
acceptAreaChecklist: _acceptAreaChecklist,
|
|
3782
|
+
attachImageAreaChecklist: _attachImageAreaChecklist,
|
|
3783
|
+
submitAreaChecklist: _submitAreaChecklist,
|
|
3784
|
+
completeAreaChecklist: _completeAreaChecklist
|
|
3785
|
+
} = useAreaChecklistRepo();
|
|
3786
|
+
const { createAreaChecklist: _createAreaChecklist } = useAreaChecklistService();
|
|
3787
|
+
async function createAreaChecklist(req, res, next) {
|
|
3788
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
3789
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3790
|
+
{}
|
|
3791
|
+
) : {};
|
|
3792
|
+
const createdBy = cookies["user"] || "";
|
|
3793
|
+
const payload = { ...req.body, ...req.params, createdBy };
|
|
3794
|
+
const validation = import_joi12.default.object({
|
|
3795
|
+
type: import_joi12.default.string().required().valid(...allowedTypes),
|
|
3796
|
+
site: import_joi12.default.string().hex().required(),
|
|
3797
|
+
parentChecklist: import_joi12.default.string().hex().required(),
|
|
3798
|
+
createdBy: import_joi12.default.string().hex().optional().allow("", null)
|
|
3799
|
+
});
|
|
3800
|
+
const { error } = validation.validate(payload);
|
|
3801
|
+
if (error) {
|
|
3802
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3803
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
try {
|
|
3807
|
+
await _createAreaChecklist(payload);
|
|
3808
|
+
res.status(201).json({ message: "Area checklists generated successfully." });
|
|
3809
|
+
return;
|
|
3810
|
+
} catch (error2) {
|
|
3811
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3812
|
+
next(error2);
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
async function getAllAreaChecklist(req, res, next) {
|
|
3817
|
+
const query = { ...req.query, ...req.params };
|
|
3818
|
+
const validation = import_joi12.default.object({
|
|
3819
|
+
page: import_joi12.default.number().min(1).optional().allow("", null),
|
|
3820
|
+
limit: import_joi12.default.number().min(1).optional().allow("", null),
|
|
3821
|
+
search: import_joi12.default.string().optional().allow("", null),
|
|
3822
|
+
site: import_joi12.default.string().hex().required(),
|
|
3823
|
+
type: import_joi12.default.string().valid(...allowedTypes).required(),
|
|
3824
|
+
parentChecklist: import_joi12.default.string().hex().required()
|
|
3825
|
+
});
|
|
3826
|
+
const { error } = validation.validate(query);
|
|
3827
|
+
if (error) {
|
|
3828
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3829
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3830
|
+
return;
|
|
3831
|
+
}
|
|
3832
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
3833
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
3834
|
+
const search = req.query.search ?? "";
|
|
3835
|
+
const site = req.params.site ?? "";
|
|
3836
|
+
const type = req.params.type ?? "";
|
|
3837
|
+
const parentChecklist = req.params.parentChecklist ?? "";
|
|
3838
|
+
try {
|
|
3839
|
+
const data = await _getAllAreaChecklist({
|
|
3840
|
+
page,
|
|
3841
|
+
limit,
|
|
3842
|
+
search,
|
|
3843
|
+
site,
|
|
3844
|
+
type,
|
|
3845
|
+
parentChecklist
|
|
3846
|
+
});
|
|
3847
|
+
res.json(data);
|
|
3848
|
+
return;
|
|
3849
|
+
} catch (error2) {
|
|
3850
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3851
|
+
next(error2);
|
|
3852
|
+
return;
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
async function getAreaChecklistHistory(req, res, next) {
|
|
3856
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
3857
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3858
|
+
{}
|
|
3859
|
+
) : {};
|
|
3860
|
+
const user = cookies["user"] || "";
|
|
3861
|
+
const query = { ...req.query, ...req.params, user };
|
|
3862
|
+
const validation = import_joi12.default.object({
|
|
3863
|
+
page: import_joi12.default.number().min(1).optional().allow("", null),
|
|
3864
|
+
limit: import_joi12.default.number().min(1).optional().allow("", null),
|
|
3865
|
+
search: import_joi12.default.string().optional().allow("", null),
|
|
3866
|
+
site: import_joi12.default.string().hex().required(),
|
|
3867
|
+
type: import_joi12.default.string().valid(...allowedTypes).required(),
|
|
3868
|
+
parentChecklist: import_joi12.default.string().hex().required(),
|
|
3869
|
+
status: import_joi12.default.string().allow("", null, ...allowedStatus),
|
|
3870
|
+
createdAt: import_joi12.default.alternatives().try(import_joi12.default.date(), import_joi12.default.string()).optional().allow("", null),
|
|
3871
|
+
user: import_joi12.default.string().hex().optional().allow("", null)
|
|
3872
|
+
});
|
|
3873
|
+
const { error } = validation.validate(query);
|
|
3874
|
+
if (error) {
|
|
3875
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3876
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3877
|
+
return;
|
|
3878
|
+
}
|
|
3879
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
3880
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
3881
|
+
const search = req.query.search ?? "";
|
|
3882
|
+
const site = req.params.site ?? "";
|
|
3883
|
+
const type = req.params.type ?? "";
|
|
3884
|
+
const parentChecklist = req.params.parentChecklist ?? "";
|
|
3885
|
+
const status = req.query.status ?? "";
|
|
3886
|
+
const createdAt = req.query.createdAt ?? "";
|
|
3887
|
+
try {
|
|
3888
|
+
const data = await _getAreaChecklistHistory({
|
|
3889
|
+
page,
|
|
3890
|
+
limit,
|
|
3891
|
+
search,
|
|
3892
|
+
site,
|
|
3893
|
+
type,
|
|
3894
|
+
parentChecklist,
|
|
3895
|
+
status,
|
|
3896
|
+
createdAt,
|
|
3897
|
+
user
|
|
3898
|
+
});
|
|
3899
|
+
res.json(data);
|
|
3900
|
+
return;
|
|
3901
|
+
} catch (error2) {
|
|
3902
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3903
|
+
next(error2);
|
|
3904
|
+
return;
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
async function getAreaChecklistHistoryDetails(req, res, next) {
|
|
3908
|
+
const validation = import_joi12.default.string().hex().required();
|
|
3909
|
+
const _id = req.params.id;
|
|
3910
|
+
const { error } = validation.validate(_id);
|
|
3911
|
+
if (error) {
|
|
3912
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3913
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3914
|
+
return;
|
|
3915
|
+
}
|
|
3916
|
+
try {
|
|
3917
|
+
const data = await _getAreaChecklistHistoryDetails(_id);
|
|
3918
|
+
res.json(data);
|
|
3919
|
+
return;
|
|
3920
|
+
} catch (error2) {
|
|
3921
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3922
|
+
next(error2);
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
async function acceptAreaChecklist(req, res, next) {
|
|
3927
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
3928
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3929
|
+
{}
|
|
3930
|
+
) : {};
|
|
3931
|
+
const acceptedBy = cookies["user"] || "";
|
|
3932
|
+
const payload = { id: req.params.id, acceptedBy };
|
|
3933
|
+
const validation = import_joi12.default.object({
|
|
3934
|
+
id: import_joi12.default.string().hex().required(),
|
|
3935
|
+
acceptedBy: import_joi12.default.string().hex().required()
|
|
3936
|
+
});
|
|
3937
|
+
const { error } = validation.validate(payload);
|
|
3938
|
+
if (error) {
|
|
3939
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3940
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3943
|
+
try {
|
|
3944
|
+
await _acceptAreaChecklist(payload.id, payload.acceptedBy);
|
|
3945
|
+
res.json({ message: "Area checklist updated successfully." });
|
|
3946
|
+
return;
|
|
3947
|
+
} catch (error2) {
|
|
3948
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3949
|
+
next(error2);
|
|
3950
|
+
return;
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3953
|
+
async function attachImageAreaChecklist(req, res, next) {
|
|
3954
|
+
const payload = { id: req.params.id, attachments: req.body.attachments };
|
|
3955
|
+
const validation = import_joi12.default.object({
|
|
3956
|
+
id: import_joi12.default.string().hex().required(),
|
|
3957
|
+
attachments: import_joi12.default.array().items(import_joi12.default.string()).optional()
|
|
3958
|
+
});
|
|
3959
|
+
const { error } = validation.validate(payload);
|
|
3960
|
+
if (error) {
|
|
3961
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3962
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3963
|
+
return;
|
|
3964
|
+
}
|
|
3965
|
+
try {
|
|
3966
|
+
await _attachImageAreaChecklist(payload.id, payload.attachments);
|
|
3967
|
+
res.json({ message: "Area checklist attachments updated successfully." });
|
|
3968
|
+
return;
|
|
3969
|
+
} catch (error2) {
|
|
3970
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3971
|
+
next(error2);
|
|
3972
|
+
return;
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
async function submitAreaChecklist(req, res, next) {
|
|
3976
|
+
const payload = { id: req.params.id, signature: req.body.signature };
|
|
3977
|
+
const validation = import_joi12.default.object({
|
|
3978
|
+
id: import_joi12.default.string().hex().required(),
|
|
3979
|
+
signature: import_joi12.default.string().required()
|
|
3980
|
+
});
|
|
3981
|
+
const { error } = validation.validate(payload);
|
|
3982
|
+
if (error) {
|
|
3983
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
3984
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
try {
|
|
3988
|
+
await _submitAreaChecklist(payload.id, payload.signature);
|
|
3989
|
+
res.json({ message: "Area checklist submitted successfully." });
|
|
3990
|
+
return;
|
|
3991
|
+
} catch (error2) {
|
|
3992
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
3993
|
+
next(error2);
|
|
3994
|
+
return;
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
async function completeAreaChecklist(req, res, next) {
|
|
3998
|
+
const payload = { id: req.params.id, signature: req.body.signature };
|
|
3999
|
+
const validation = import_joi12.default.object({
|
|
4000
|
+
id: import_joi12.default.string().hex().required(),
|
|
4001
|
+
signature: import_joi12.default.string().required()
|
|
4002
|
+
});
|
|
4003
|
+
const { error } = validation.validate(payload);
|
|
4004
|
+
if (error) {
|
|
4005
|
+
import_node_server_utils23.logger.log({ level: "error", message: error.message });
|
|
4006
|
+
next(new import_node_server_utils23.BadRequestError(error.message));
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
try {
|
|
4010
|
+
await _completeAreaChecklist(payload.id, payload.signature);
|
|
4011
|
+
res.json({ message: "Area checklist completed successfully." });
|
|
4012
|
+
return;
|
|
4013
|
+
} catch (error2) {
|
|
4014
|
+
import_node_server_utils23.logger.log({ level: "error", message: error2.message });
|
|
4015
|
+
next(error2);
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
return {
|
|
4020
|
+
createAreaChecklist,
|
|
4021
|
+
getAllAreaChecklist,
|
|
4022
|
+
getAreaChecklistHistory,
|
|
4023
|
+
getAreaChecklistHistoryDetails,
|
|
4024
|
+
acceptAreaChecklist,
|
|
4025
|
+
attachImageAreaChecklist,
|
|
4026
|
+
submitAreaChecklist,
|
|
4027
|
+
completeAreaChecklist
|
|
4028
|
+
};
|
|
4029
|
+
}
|
|
4030
|
+
|
|
4031
|
+
// src/models/hygiene-unit-checklist.model.ts
|
|
4032
|
+
var import_node_server_utils24 = require("@iservice365/node-server-utils");
|
|
4033
|
+
var import_joi13 = __toESM(require("joi"));
|
|
4034
|
+
var import_mongodb13 = require("mongodb");
|
|
4035
|
+
var unitChecklistSchema = import_joi13.default.object({
|
|
4036
|
+
site: import_joi13.default.string().hex().required(),
|
|
4037
|
+
type: import_joi13.default.string().valid(...allowedTypes).required(),
|
|
4038
|
+
parentChecklist: import_joi13.default.string().hex().required(),
|
|
4039
|
+
areaChecklist: import_joi13.default.string().hex().required(),
|
|
4040
|
+
unit: import_joi13.default.string().hex().required(),
|
|
4041
|
+
name: import_joi13.default.string().optional().allow("", null),
|
|
4042
|
+
createdBy: import_joi13.default.string().hex().optional().allow("", null)
|
|
4043
|
+
});
|
|
4044
|
+
function MUnitChecklist(value) {
|
|
4045
|
+
const { error } = unitChecklistSchema.validate(value);
|
|
4046
|
+
if (error) {
|
|
4047
|
+
import_node_server_utils24.logger.info(`Hygiene Checklist Unit Model: ${error.message}`);
|
|
4048
|
+
throw new import_node_server_utils24.BadRequestError(error.message);
|
|
4049
|
+
}
|
|
4050
|
+
if (value.site) {
|
|
4051
|
+
try {
|
|
4052
|
+
value.site = new import_mongodb13.ObjectId(value.site);
|
|
4053
|
+
} catch (error2) {
|
|
4054
|
+
throw new import_node_server_utils24.BadRequestError("Invalid site ID format.");
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
if (value.parentChecklist) {
|
|
4058
|
+
try {
|
|
4059
|
+
value.parentChecklist = new import_mongodb13.ObjectId(value.parentChecklist);
|
|
4060
|
+
} catch (error2) {
|
|
4061
|
+
throw new import_node_server_utils24.BadRequestError("Invalid parent checklist ID format.");
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
if (value.areaChecklist) {
|
|
4065
|
+
try {
|
|
4066
|
+
value.areaChecklist = new import_mongodb13.ObjectId(value.areaChecklist);
|
|
4067
|
+
} catch (error2) {
|
|
4068
|
+
throw new import_node_server_utils24.BadRequestError("Invalid area checklist ID format.");
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
if (value.unit) {
|
|
4072
|
+
try {
|
|
4073
|
+
value.unit = new import_mongodb13.ObjectId(value.unit);
|
|
4074
|
+
} catch (error2) {
|
|
4075
|
+
throw new import_node_server_utils24.BadRequestError("Invalid unit ID format.");
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
if (value.createdBy) {
|
|
4079
|
+
try {
|
|
4080
|
+
value.createdBy = new import_mongodb13.ObjectId(value.createdBy);
|
|
4081
|
+
} catch (error2) {
|
|
4082
|
+
throw new import_node_server_utils24.BadRequestError("Invalid createdBy ID format.");
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
return {
|
|
4086
|
+
site: value.site,
|
|
4087
|
+
type: value.type,
|
|
4088
|
+
parentChecklist: value.parentChecklist,
|
|
4089
|
+
areaChecklist: value.areaChecklist,
|
|
4090
|
+
unit: value.unit,
|
|
4091
|
+
name: value.name ?? "",
|
|
4092
|
+
approve: false,
|
|
4093
|
+
reject: false,
|
|
4094
|
+
createdBy: value.createdBy ?? "",
|
|
4095
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
4096
|
+
updatedAt: value.updatedAt ?? ""
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
|
|
4100
|
+
// src/repositories/hygiene-unit-checklist.repository.ts
|
|
4101
|
+
var import_node_server_utils25 = require("@iservice365/node-server-utils");
|
|
4102
|
+
var import_mongodb14 = require("mongodb");
|
|
4103
|
+
function useUnitChecklistRepo() {
|
|
4104
|
+
const db = import_node_server_utils25.useAtlas.getDb();
|
|
4105
|
+
if (!db) {
|
|
4106
|
+
throw new import_node_server_utils25.InternalServerError("Unable to connect to server.");
|
|
4107
|
+
}
|
|
4108
|
+
const namespace_collection = "hygiene-checklist.units";
|
|
4109
|
+
const collection = db.collection(namespace_collection);
|
|
4110
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils25.useCache)(namespace_collection);
|
|
4111
|
+
async function createIndex() {
|
|
4112
|
+
try {
|
|
4113
|
+
await collection.createIndexes([
|
|
4114
|
+
{ key: { site: 1 } },
|
|
4115
|
+
{ key: { type: 1 } },
|
|
4116
|
+
{ key: { parentChecklist: 1 } },
|
|
4117
|
+
{ key: { areaChecklist: 1 } },
|
|
4118
|
+
{ key: { "metadata.workOrder.category": 1 } },
|
|
4119
|
+
{ key: { "metadata.workOrder.createdBy": 1 } },
|
|
4120
|
+
{ key: { "metadata.workOrder.serviceProvider": 1 } },
|
|
4121
|
+
{ key: { "metadata.workOrder.organization": 1 } },
|
|
4122
|
+
{ key: { "metadata.workOrder.site": 1 } }
|
|
4123
|
+
]);
|
|
4124
|
+
} catch (error) {
|
|
4125
|
+
throw new import_node_server_utils25.InternalServerError(
|
|
4126
|
+
"Failed to create index on hygiene unit checklist."
|
|
4127
|
+
);
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
async function createTextIndex() {
|
|
4131
|
+
try {
|
|
4132
|
+
await collection.createIndex({ name: "text" });
|
|
4133
|
+
} catch (error) {
|
|
4134
|
+
throw new import_node_server_utils25.InternalServerError(
|
|
4135
|
+
"Failed to create text index on hygiene unit checklist."
|
|
4136
|
+
);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
async function createUnitChecklist(value, session) {
|
|
4140
|
+
try {
|
|
4141
|
+
value = MUnitChecklist(value);
|
|
4142
|
+
const res = await collection.insertOne(value, { session });
|
|
4143
|
+
delNamespace().then(() => {
|
|
4144
|
+
import_node_server_utils25.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
4145
|
+
}).catch((err) => {
|
|
4146
|
+
import_node_server_utils25.logger.error(
|
|
4147
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
4148
|
+
err
|
|
4149
|
+
);
|
|
4150
|
+
});
|
|
4151
|
+
return res.insertedId;
|
|
4152
|
+
} catch (error) {
|
|
4153
|
+
throw error;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
async function getAllUnitChecklist({
|
|
4157
|
+
page = 1,
|
|
4158
|
+
limit = 10,
|
|
4159
|
+
search = "",
|
|
4160
|
+
site,
|
|
4161
|
+
type,
|
|
4162
|
+
parentChecklist,
|
|
4163
|
+
areaChecklist
|
|
4164
|
+
}) {
|
|
4165
|
+
page = page > 0 ? page - 1 : 0;
|
|
4166
|
+
const query = { type };
|
|
4167
|
+
const cacheOptions = {
|
|
4168
|
+
page,
|
|
4169
|
+
limit
|
|
4170
|
+
};
|
|
4171
|
+
try {
|
|
4172
|
+
query.site = new import_mongodb14.ObjectId(site);
|
|
4173
|
+
cacheOptions.site = site.toString();
|
|
4174
|
+
} catch (error) {
|
|
4175
|
+
throw new import_node_server_utils25.BadRequestError("Invalid site ID format.");
|
|
4176
|
+
}
|
|
4177
|
+
try {
|
|
4178
|
+
query.parentChecklist = new import_mongodb14.ObjectId(parentChecklist);
|
|
4179
|
+
cacheOptions.parentChecklist = parentChecklist.toString();
|
|
4180
|
+
} catch (error) {
|
|
4181
|
+
throw new import_node_server_utils25.BadRequestError("Invalid parent checklist ID format.");
|
|
4182
|
+
}
|
|
4183
|
+
try {
|
|
4184
|
+
query.areaChecklist = new import_mongodb14.ObjectId(areaChecklist);
|
|
4185
|
+
cacheOptions.areaChecklist = areaChecklist.toString();
|
|
4186
|
+
} catch (error) {
|
|
4187
|
+
throw new import_node_server_utils25.BadRequestError("Invalid area checklist ID format.");
|
|
4188
|
+
}
|
|
4189
|
+
if (search) {
|
|
4190
|
+
query.$text = { $search: search };
|
|
4191
|
+
cacheOptions.search = search;
|
|
4192
|
+
}
|
|
4193
|
+
const cacheKey = (0, import_node_server_utils25.makeCacheKey)(namespace_collection, cacheOptions);
|
|
4194
|
+
const cachedData = await getCache(cacheKey);
|
|
4195
|
+
if (cachedData) {
|
|
4196
|
+
import_node_server_utils25.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
4197
|
+
return cachedData;
|
|
4198
|
+
}
|
|
4199
|
+
try {
|
|
4200
|
+
const areaAttachmentsResult = await collection.aggregate([
|
|
4201
|
+
{ $match: query },
|
|
4202
|
+
{
|
|
4203
|
+
$lookup: {
|
|
4204
|
+
from: "hygiene-checklist.areas",
|
|
4205
|
+
localField: "areaChecklist",
|
|
4206
|
+
foreignField: "_id",
|
|
4207
|
+
pipeline: [
|
|
4208
|
+
{ $project: { attachments: "$metadata.attachments" } }
|
|
4209
|
+
],
|
|
4210
|
+
as: "areaChecklistData"
|
|
4211
|
+
}
|
|
4212
|
+
},
|
|
4213
|
+
{
|
|
4214
|
+
$unwind: {
|
|
4215
|
+
path: "$areaChecklistData",
|
|
4216
|
+
preserveNullAndEmptyArrays: true
|
|
4217
|
+
}
|
|
4218
|
+
},
|
|
4219
|
+
{
|
|
4220
|
+
$group: {
|
|
4221
|
+
_id: null,
|
|
4222
|
+
attachments: { $first: "$areaChecklistData.attachments" }
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
]).toArray();
|
|
4226
|
+
const areaAttachments = areaAttachmentsResult.length > 0 ? areaAttachmentsResult[0].attachments || [] : [];
|
|
4227
|
+
const pipeline = [
|
|
4228
|
+
{ $match: query },
|
|
4229
|
+
{
|
|
4230
|
+
$lookup: {
|
|
4231
|
+
from: "organizations",
|
|
4232
|
+
localField: "metadata.workOrder.category",
|
|
4233
|
+
foreignField: "_id",
|
|
4234
|
+
pipeline: [{ $project: { nature: 1 } }],
|
|
4235
|
+
as: "categoryData"
|
|
4236
|
+
}
|
|
4237
|
+
},
|
|
4238
|
+
{
|
|
4239
|
+
$lookup: {
|
|
4240
|
+
from: "users",
|
|
4241
|
+
localField: "metadata.workOrder.createdBy",
|
|
4242
|
+
foreignField: "_id",
|
|
4243
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
4244
|
+
as: "createdByData"
|
|
4245
|
+
}
|
|
4246
|
+
},
|
|
4247
|
+
{
|
|
4248
|
+
$lookup: {
|
|
4249
|
+
from: "service-providers",
|
|
4250
|
+
localField: "metadata.workOrder.serviceProvider",
|
|
4251
|
+
foreignField: "_id",
|
|
4252
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
4253
|
+
as: "serviceProviderData"
|
|
4254
|
+
}
|
|
4255
|
+
},
|
|
4256
|
+
{
|
|
4257
|
+
$lookup: {
|
|
4258
|
+
from: "organizations",
|
|
4259
|
+
localField: "metadata.workOrder.organization",
|
|
4260
|
+
foreignField: "_id",
|
|
4261
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
4262
|
+
as: "organizationData"
|
|
4263
|
+
}
|
|
4264
|
+
},
|
|
4265
|
+
{
|
|
4266
|
+
$lookup: {
|
|
4267
|
+
from: "sites",
|
|
4268
|
+
localField: "metadata.workOrder.site",
|
|
4269
|
+
foreignField: "_id",
|
|
4270
|
+
pipeline: [{ $project: { name: 1 } }],
|
|
4271
|
+
as: "siteData"
|
|
4272
|
+
}
|
|
4273
|
+
},
|
|
4274
|
+
{
|
|
4275
|
+
$addFields: {
|
|
4276
|
+
"metadata.workOrder.categoryName": {
|
|
4277
|
+
$arrayElemAt: ["$categoryData.nature", 0]
|
|
4278
|
+
},
|
|
4279
|
+
"metadata.workOrder.createdByName": {
|
|
4280
|
+
$arrayElemAt: ["$createdByData.name", 0]
|
|
4281
|
+
},
|
|
4282
|
+
"metadata.workOrder.serviceProviderName": {
|
|
4283
|
+
$arrayElemAt: ["$serviceProviderData.name", 0]
|
|
4284
|
+
},
|
|
4285
|
+
"metadata.workOrder.organizationName": {
|
|
4286
|
+
$arrayElemAt: ["$organizationData.name", 0]
|
|
4287
|
+
},
|
|
4288
|
+
"metadata.workOrder.siteName": {
|
|
4289
|
+
$arrayElemAt: ["$siteData.name", 0]
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
},
|
|
4293
|
+
{
|
|
4294
|
+
$project: {
|
|
4295
|
+
name: 1,
|
|
4296
|
+
remarks: "$metadata.remarks",
|
|
4297
|
+
attachments: "$metadata.attachments",
|
|
4298
|
+
workOrder: "$metadata.workOrder",
|
|
4299
|
+
approve: { $ifNull: ["$approve", null] },
|
|
4300
|
+
reject: { $ifNull: ["$reject", null] }
|
|
4301
|
+
}
|
|
4302
|
+
},
|
|
4303
|
+
{ $sort: { _id: -1 } },
|
|
4304
|
+
{ $skip: page * limit },
|
|
4305
|
+
{ $limit: limit }
|
|
4306
|
+
];
|
|
4307
|
+
const items = await collection.aggregate(pipeline).toArray();
|
|
4308
|
+
const length = await collection.countDocuments(query);
|
|
4309
|
+
const paginatedData = (0, import_node_server_utils25.paginate)(items, page, limit, length);
|
|
4310
|
+
const data = {
|
|
4311
|
+
attachments: areaAttachments,
|
|
4312
|
+
...paginatedData
|
|
4313
|
+
};
|
|
4314
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
4315
|
+
import_node_server_utils25.logger.info(`Cache set for key: ${cacheKey}`);
|
|
4316
|
+
}).catch((err) => {
|
|
4317
|
+
import_node_server_utils25.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
4318
|
+
});
|
|
4319
|
+
return data;
|
|
4320
|
+
} catch (error) {
|
|
4321
|
+
throw error;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
async function getUnitChecklistById(_id) {
|
|
4325
|
+
try {
|
|
4326
|
+
_id = new import_mongodb14.ObjectId(_id);
|
|
4327
|
+
} catch (error) {
|
|
4328
|
+
throw new import_node_server_utils25.BadRequestError("Invalid unit checklist ID format.");
|
|
4329
|
+
}
|
|
4330
|
+
try {
|
|
4331
|
+
return await collection.findOne({ _id });
|
|
4332
|
+
} catch (error) {
|
|
4333
|
+
throw error;
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
async function updateUnitChecklist(_id, value, session) {
|
|
4337
|
+
try {
|
|
4338
|
+
_id = new import_mongodb14.ObjectId(_id);
|
|
4339
|
+
} catch (error) {
|
|
4340
|
+
throw new import_node_server_utils25.BadRequestError("Invalid unit checklist ID format.");
|
|
4341
|
+
}
|
|
4342
|
+
if (value.checkedBy && typeof value.checkedBy === "string") {
|
|
4343
|
+
try {
|
|
4344
|
+
value.checkedBy = new import_mongodb14.ObjectId(value.checkedBy);
|
|
4345
|
+
} catch (error) {
|
|
4346
|
+
throw new import_node_server_utils25.BadRequestError("Invalid checkedBy ID format.");
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
if ("metadata" in value && value.metadata?.workOrder) {
|
|
4350
|
+
const workOrder = value.metadata.workOrder;
|
|
4351
|
+
if (workOrder.category && typeof workOrder.category === "string") {
|
|
4352
|
+
try {
|
|
4353
|
+
workOrder.category = new import_mongodb14.ObjectId(workOrder.category);
|
|
4354
|
+
} catch (error) {
|
|
4355
|
+
throw new import_node_server_utils25.BadRequestError("Invalid category ID format.");
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
if (workOrder.createdBy && typeof workOrder.createdBy === "string") {
|
|
4359
|
+
try {
|
|
4360
|
+
workOrder.createdBy = new import_mongodb14.ObjectId(workOrder.createdBy);
|
|
4361
|
+
} catch (error) {
|
|
4362
|
+
throw new import_node_server_utils25.BadRequestError("Invalid createdBy ID format.");
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
if (workOrder.serviceProvider && typeof workOrder.serviceProvider === "string") {
|
|
4366
|
+
try {
|
|
4367
|
+
workOrder.serviceProvider = new import_mongodb14.ObjectId(workOrder.serviceProvider);
|
|
4368
|
+
} catch (error) {
|
|
4369
|
+
throw new import_node_server_utils25.BadRequestError("Invalid serviceProvider ID format.");
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
if (workOrder.organization && typeof workOrder.organization === "string") {
|
|
4373
|
+
try {
|
|
4374
|
+
workOrder.organization = new import_mongodb14.ObjectId(workOrder.organization);
|
|
4375
|
+
} catch (error) {
|
|
4376
|
+
throw new import_node_server_utils25.BadRequestError("Invalid organization ID format.");
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
if (workOrder.site && typeof workOrder.site === "string") {
|
|
4380
|
+
try {
|
|
4381
|
+
workOrder.site = new import_mongodb14.ObjectId(workOrder.site);
|
|
4382
|
+
} catch (error) {
|
|
4383
|
+
throw new import_node_server_utils25.BadRequestError("Invalid site ID format.");
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
try {
|
|
4388
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
4389
|
+
const res = await collection.updateOne(
|
|
4390
|
+
{ _id },
|
|
4391
|
+
{ $set: updateValue },
|
|
4392
|
+
{ session }
|
|
4393
|
+
);
|
|
4394
|
+
if (res.modifiedCount === 0) {
|
|
4395
|
+
throw new import_node_server_utils25.InternalServerError("Unable to update unit checklist.");
|
|
4396
|
+
}
|
|
4397
|
+
delNamespace().then(() => {
|
|
4398
|
+
import_node_server_utils25.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
4399
|
+
}).catch((err) => {
|
|
4400
|
+
import_node_server_utils25.logger.error(
|
|
4401
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
4402
|
+
err
|
|
4403
|
+
);
|
|
4404
|
+
});
|
|
4405
|
+
return res.modifiedCount;
|
|
4406
|
+
} catch (error) {
|
|
4407
|
+
throw error;
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
return {
|
|
4411
|
+
createIndex,
|
|
4412
|
+
createTextIndex,
|
|
4413
|
+
createUnitChecklist,
|
|
4414
|
+
getAllUnitChecklist,
|
|
4415
|
+
getUnitChecklistById,
|
|
4416
|
+
updateUnitChecklist
|
|
4417
|
+
};
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4420
|
+
// src/controllers/hygiene-unit-checklist.controller.ts
|
|
4421
|
+
var import_node_server_utils27 = require("@iservice365/node-server-utils");
|
|
4422
|
+
var import_joi14 = __toESM(require("joi"));
|
|
4423
|
+
|
|
4424
|
+
// src/services/hygiene-unit-checklist.service.ts
|
|
4425
|
+
var import_node_server_utils26 = require("@iservice365/node-server-utils");
|
|
4426
|
+
var import_core = require("@iservice365/core");
|
|
4427
|
+
function useUnitChecklistService() {
|
|
4428
|
+
const {
|
|
4429
|
+
getUnitChecklistById: _getUnitChecklistById,
|
|
4430
|
+
updateUnitChecklist: _updateUnitChecklist
|
|
4431
|
+
} = useUnitChecklistRepo();
|
|
4432
|
+
const { getSiteById } = (0, import_core.useSiteRepo)();
|
|
4433
|
+
const { createWorkOrder } = (0, import_core.useWorkOrderService)();
|
|
4434
|
+
async function approveUnitChecklist(id, value) {
|
|
4435
|
+
try {
|
|
4436
|
+
value.approve = true;
|
|
4437
|
+
value.reject = false;
|
|
4438
|
+
const result = await _updateUnitChecklist(id, value);
|
|
4439
|
+
return result;
|
|
4440
|
+
} catch (error) {
|
|
4441
|
+
import_node_server_utils26.logger.error(`Error updating unit checklist with id ${id}:`, error);
|
|
4442
|
+
throw error;
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
async function rejectUnitChecklist(id, value, fullHost) {
|
|
4446
|
+
try {
|
|
4447
|
+
value.reject = true;
|
|
4448
|
+
value.approve = false;
|
|
4449
|
+
if (value.metadata?.workOrder) {
|
|
4450
|
+
const existingChecklist = await _getUnitChecklistById(id);
|
|
4451
|
+
if (!existingChecklist)
|
|
4452
|
+
throw new import_node_server_utils26.NotFoundError("Unit checklist not found.");
|
|
4453
|
+
const site = await getSiteById(
|
|
4454
|
+
existingChecklist.site
|
|
4455
|
+
);
|
|
4456
|
+
if (!site)
|
|
4457
|
+
throw new import_node_server_utils26.NotFoundError("Site not found.");
|
|
4458
|
+
const workOrderData = {
|
|
4459
|
+
...value.metadata.workOrder,
|
|
4460
|
+
attachments: value.metadata.attachments,
|
|
4461
|
+
createdBy: value.checkedBy,
|
|
4462
|
+
organization: site.orgId,
|
|
4463
|
+
site: site._id
|
|
4464
|
+
};
|
|
4465
|
+
const workOrder = await createWorkOrder(
|
|
4466
|
+
workOrderData,
|
|
4467
|
+
fullHost
|
|
4468
|
+
);
|
|
4469
|
+
if (!workOrder)
|
|
4470
|
+
throw new import_node_server_utils26.NotFoundError("Failed to create work order.");
|
|
4471
|
+
}
|
|
4472
|
+
const result = await _updateUnitChecklist(id, value);
|
|
4473
|
+
return result;
|
|
4474
|
+
} catch (error) {
|
|
4475
|
+
import_node_server_utils26.logger.error(`Error updating unit checklist with id ${id}:`, error);
|
|
4476
|
+
throw error;
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
return {
|
|
4480
|
+
approveUnitChecklist,
|
|
4481
|
+
rejectUnitChecklist
|
|
4482
|
+
};
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
// src/controllers/hygiene-unit-checklist.controller.ts
|
|
4486
|
+
var import_core2 = require("@iservice365/core");
|
|
4487
|
+
function useUnitChecklistController() {
|
|
4488
|
+
const {
|
|
4489
|
+
createUnitChecklist: _createUnitChecklist,
|
|
4490
|
+
getAllUnitChecklist: _getAllUnitChecklist
|
|
4491
|
+
} = useUnitChecklistRepo();
|
|
4492
|
+
const {
|
|
4493
|
+
approveUnitChecklist: _approveUnitChecklist,
|
|
4494
|
+
rejectUnitChecklist: _rejectUnitChecklist
|
|
4495
|
+
} = useUnitChecklistService();
|
|
4496
|
+
async function createUnitChecklist(req, res, next) {
|
|
4497
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
4498
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
4499
|
+
{}
|
|
4500
|
+
) : {};
|
|
4501
|
+
const createdBy = cookies["user"] || "";
|
|
4502
|
+
const payload = { ...req.body, ...req.params, createdBy };
|
|
4503
|
+
const { error } = unitChecklistSchema.validate(payload);
|
|
4504
|
+
if (error) {
|
|
4505
|
+
import_node_server_utils27.logger.log({ level: "error", message: error.message });
|
|
4506
|
+
next(new import_node_server_utils27.BadRequestError(error.message));
|
|
4507
|
+
return;
|
|
4508
|
+
}
|
|
4509
|
+
try {
|
|
4510
|
+
const id = await _createUnitChecklist(payload);
|
|
4511
|
+
res.status(201).json({ message: "Unit checklist created successfully.", id });
|
|
4512
|
+
return;
|
|
4513
|
+
} catch (error2) {
|
|
4514
|
+
import_node_server_utils27.logger.log({ level: "error", message: error2.message });
|
|
4515
|
+
next(error2);
|
|
4516
|
+
return;
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
async function getAllUnitChecklist(req, res, next) {
|
|
4520
|
+
const query = { ...req.query, ...req.params };
|
|
4521
|
+
const validation = import_joi14.default.object({
|
|
4522
|
+
page: import_joi14.default.number().min(1).optional().allow("", null),
|
|
4523
|
+
limit: import_joi14.default.number().min(1).optional().allow("", null),
|
|
4524
|
+
search: import_joi14.default.string().optional().allow("", null),
|
|
4525
|
+
site: import_joi14.default.string().hex().required(),
|
|
4526
|
+
type: import_joi14.default.string().valid(...allowedTypes).required(),
|
|
4527
|
+
parentChecklist: import_joi14.default.string().hex().required(),
|
|
4528
|
+
areaChecklist: import_joi14.default.string().hex().required()
|
|
4529
|
+
});
|
|
4530
|
+
const { error } = validation.validate(query);
|
|
4531
|
+
if (error) {
|
|
4532
|
+
import_node_server_utils27.logger.log({ level: "error", message: error.message });
|
|
4533
|
+
next(new import_node_server_utils27.BadRequestError(error.message));
|
|
4534
|
+
return;
|
|
4535
|
+
}
|
|
4536
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
4537
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
4538
|
+
const search = req.query.search ?? "";
|
|
4539
|
+
const site = req.params.site ?? "";
|
|
4540
|
+
const type = req.params.type ?? "";
|
|
4541
|
+
const parentChecklist = req.params.parentChecklist ?? "";
|
|
4542
|
+
const areaChecklist = req.params.areaChecklist ?? "";
|
|
4543
|
+
try {
|
|
4544
|
+
const data = await _getAllUnitChecklist({
|
|
4545
|
+
page,
|
|
4546
|
+
limit,
|
|
4547
|
+
search,
|
|
4548
|
+
site,
|
|
4549
|
+
type,
|
|
4550
|
+
parentChecklist,
|
|
4551
|
+
areaChecklist
|
|
4552
|
+
});
|
|
4553
|
+
res.json(data);
|
|
4554
|
+
return;
|
|
4555
|
+
} catch (error2) {
|
|
4556
|
+
import_node_server_utils27.logger.log({ level: "error", message: error2.message });
|
|
4557
|
+
next(error2);
|
|
4558
|
+
return;
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
async function approveUnitChecklist(req, res, next) {
|
|
4562
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
4563
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
4564
|
+
{}
|
|
4565
|
+
) : {};
|
|
4566
|
+
const checkedBy = cookies["user"] || "";
|
|
4567
|
+
const payload = { id: req.params.id, checkedBy };
|
|
4568
|
+
const validation = import_joi14.default.object({
|
|
4569
|
+
id: import_joi14.default.string().hex().required(),
|
|
4570
|
+
checkedBy: import_joi14.default.string().hex().required()
|
|
4571
|
+
});
|
|
4572
|
+
const { error } = validation.validate(payload);
|
|
4573
|
+
if (error) {
|
|
4574
|
+
import_node_server_utils27.logger.log({ level: "error", message: error.message });
|
|
4575
|
+
next(new import_node_server_utils27.BadRequestError(error.message));
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4578
|
+
try {
|
|
4579
|
+
const { id, ...value } = payload;
|
|
4580
|
+
await _approveUnitChecklist(id, value);
|
|
4581
|
+
res.json({ message: "Unit checklist approved successfully." });
|
|
4582
|
+
return;
|
|
4583
|
+
} catch (error2) {
|
|
4584
|
+
import_node_server_utils27.logger.log({ level: "error", message: error2.message });
|
|
4585
|
+
next(error2);
|
|
4586
|
+
return;
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
async function rejectUnitChecklist(req, res, next) {
|
|
4590
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
4591
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
4592
|
+
{}
|
|
4593
|
+
) : {};
|
|
4594
|
+
const checkedBy = cookies["user"] || "";
|
|
4595
|
+
if (req.body.workOrder) {
|
|
4596
|
+
req.body.workOrder.createdBy = checkedBy;
|
|
4597
|
+
}
|
|
4598
|
+
const payload = { id: req.params.id, checkedBy, ...req.body };
|
|
4599
|
+
const validation = import_joi14.default.object({
|
|
4600
|
+
id: import_joi14.default.string().hex().required(),
|
|
4601
|
+
attachments: import_joi14.default.array().items(import_joi14.default.string()).optional(),
|
|
4602
|
+
remarks: import_joi14.default.string().required(),
|
|
4603
|
+
workOrder: import_core2.workOrderSchema.optional(),
|
|
4604
|
+
checkedBy: import_joi14.default.string().hex().required()
|
|
4605
|
+
});
|
|
4606
|
+
const { error } = validation.validate(payload);
|
|
4607
|
+
if (error) {
|
|
4608
|
+
import_node_server_utils27.logger.log({ level: "error", message: error.message });
|
|
4609
|
+
next(new import_node_server_utils27.BadRequestError(error.message));
|
|
4610
|
+
return;
|
|
4611
|
+
}
|
|
4612
|
+
try {
|
|
4613
|
+
const { id, attachments, remarks, workOrder, ...value } = payload;
|
|
4614
|
+
value.metadata = {
|
|
4615
|
+
attachments: attachments || [],
|
|
4616
|
+
remarks: remarks || "",
|
|
4617
|
+
workOrder
|
|
4618
|
+
};
|
|
4619
|
+
if (value.metadata.workOrder) {
|
|
4620
|
+
if (value.metadata.workOrder.category) {
|
|
4621
|
+
value.metadata.workOrder.category = value.metadata.workOrder.category;
|
|
4622
|
+
}
|
|
4623
|
+
if (value.metadata.workOrder.serviceProvider) {
|
|
4624
|
+
value.metadata.workOrder.serviceProvider = value.metadata.workOrder.serviceProvider;
|
|
4625
|
+
}
|
|
4626
|
+
value.metadata.workOrder.createdBy = checkedBy;
|
|
4627
|
+
}
|
|
4628
|
+
const fullHost = req.headers.origin;
|
|
4629
|
+
await _rejectUnitChecklist(id, value, fullHost);
|
|
4630
|
+
res.json({ message: "Unit checklist rejected successfully." });
|
|
4631
|
+
return;
|
|
4632
|
+
} catch (error2) {
|
|
4633
|
+
import_node_server_utils27.logger.log({ level: "error", message: error2.message });
|
|
4634
|
+
next(error2);
|
|
4635
|
+
return;
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
return {
|
|
4639
|
+
createUnitChecklist,
|
|
4640
|
+
getAllUnitChecklist,
|
|
4641
|
+
approveUnitChecklist,
|
|
4642
|
+
rejectUnitChecklist
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4646
|
+
0 && (module.exports = {
|
|
4647
|
+
MArea,
|
|
4648
|
+
MAreaChecklist,
|
|
4649
|
+
MParentChecklist,
|
|
4650
|
+
MScheduleTaskArea,
|
|
4651
|
+
MToiletLocation,
|
|
4652
|
+
MUnit,
|
|
4653
|
+
MUnitChecklist,
|
|
4654
|
+
allowedStatus,
|
|
4655
|
+
allowedTypes,
|
|
4656
|
+
areaChecklistSchema,
|
|
4657
|
+
areaSchema,
|
|
4658
|
+
parentChecklistSchema,
|
|
4659
|
+
scheduleTaskAreaSchema,
|
|
4660
|
+
toiletLocationSchema,
|
|
4661
|
+
unitChecklistSchema,
|
|
4662
|
+
unitSchema,
|
|
4663
|
+
useAreaChecklistController,
|
|
4664
|
+
useAreaChecklistRepo,
|
|
4665
|
+
useAreaController,
|
|
4666
|
+
useAreaRepository,
|
|
4667
|
+
useAreaService,
|
|
4668
|
+
useParentChecklistController,
|
|
4669
|
+
useParentChecklistRepo,
|
|
4670
|
+
useScheduleTaskAreaController,
|
|
4671
|
+
useScheduleTaskAreaRepository,
|
|
4672
|
+
useScheduleTaskAreaService,
|
|
4673
|
+
useToiletLocationController,
|
|
4674
|
+
useToiletLocationRepository,
|
|
4675
|
+
useToiletLocationService,
|
|
4676
|
+
useUnitChecklistController,
|
|
4677
|
+
useUnitChecklistRepo,
|
|
4678
|
+
useUnitController,
|
|
4679
|
+
useUnitRepository,
|
|
4680
|
+
useUnitService
|
|
4681
|
+
});
|
|
2
4682
|
//# sourceMappingURL=index.js.map
|