@iservice365/module-hygiene 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +66 -84
- package/dist/index.js +759 -914
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +760 -920
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
// src/models/hygiene-area.model.ts
|
|
2
|
-
import { BadRequestError, logger } from "@iservice365/node-server-utils";
|
|
3
|
-
import Joi from "joi";
|
|
4
|
-
import { ObjectId } from "mongodb";
|
|
5
|
-
|
|
6
1
|
// src/models/hygiene-base.model.ts
|
|
7
2
|
var allowedTypes = ["common", "toilet"];
|
|
8
3
|
var allowedStatus = ["ready", "ongoing", "completed"];
|
|
9
4
|
|
|
10
5
|
// src/models/hygiene-area.model.ts
|
|
6
|
+
import { BadRequestError, logger } from "@iservice365/node-server-utils";
|
|
7
|
+
import Joi from "joi";
|
|
8
|
+
import { ObjectId } from "mongodb";
|
|
11
9
|
var areaSchema = Joi.object({
|
|
12
10
|
site: Joi.string().hex().required(),
|
|
13
11
|
name: Joi.string().required(),
|
|
@@ -266,6 +264,7 @@ function useAreaRepo() {
|
|
|
266
264
|
{ $match: query },
|
|
267
265
|
{
|
|
268
266
|
$project: {
|
|
267
|
+
type: 1,
|
|
269
268
|
name: 1,
|
|
270
269
|
set: 1,
|
|
271
270
|
units: 1
|
|
@@ -285,7 +284,38 @@ function useAreaRepo() {
|
|
|
285
284
|
throw error;
|
|
286
285
|
}
|
|
287
286
|
}
|
|
288
|
-
async function
|
|
287
|
+
async function verifyAreaByUnitId(unitId) {
|
|
288
|
+
try {
|
|
289
|
+
unitId = new ObjectId2(unitId);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
throw new BadRequestError2("Invalid unit ID format.");
|
|
292
|
+
}
|
|
293
|
+
const query = {
|
|
294
|
+
"units.unit": unitId,
|
|
295
|
+
status: { $ne: "deleted" }
|
|
296
|
+
};
|
|
297
|
+
const cacheKey = makeCacheKey(namespace_collection, {
|
|
298
|
+
verify_unitId: unitId.toString()
|
|
299
|
+
});
|
|
300
|
+
const cachedData = await getCache(cacheKey);
|
|
301
|
+
if (cachedData) {
|
|
302
|
+
logger2.info(`Cache hit for key: ${cacheKey}`);
|
|
303
|
+
return cachedData;
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const count = await collection.countDocuments(query);
|
|
307
|
+
const result = count > 0;
|
|
308
|
+
setCache(cacheKey, result, 15 * 60).then(() => {
|
|
309
|
+
logger2.info(`Cache set for key: ${cacheKey}`);
|
|
310
|
+
}).catch((err) => {
|
|
311
|
+
logger2.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
312
|
+
});
|
|
313
|
+
return result;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async function updateArea(_id, value, session) {
|
|
289
319
|
try {
|
|
290
320
|
_id = new ObjectId2(_id);
|
|
291
321
|
} catch (error) {
|
|
@@ -316,7 +346,11 @@ function useAreaRepo() {
|
|
|
316
346
|
}
|
|
317
347
|
});
|
|
318
348
|
}
|
|
319
|
-
const res = await collection.updateOne(
|
|
349
|
+
const res = await collection.updateOne(
|
|
350
|
+
{ _id },
|
|
351
|
+
{ $set: updateValue },
|
|
352
|
+
{ session }
|
|
353
|
+
);
|
|
320
354
|
if (res.modifiedCount === 0) {
|
|
321
355
|
throw new InternalServerError("Unable to update cleaning area.");
|
|
322
356
|
}
|
|
@@ -337,29 +371,25 @@ function useAreaRepo() {
|
|
|
337
371
|
throw error;
|
|
338
372
|
}
|
|
339
373
|
}
|
|
340
|
-
async function updateAreaChecklist(
|
|
374
|
+
async function updateAreaChecklist(unitId, name, session) {
|
|
341
375
|
try {
|
|
342
|
-
|
|
376
|
+
unitId = new ObjectId2(unitId);
|
|
343
377
|
} catch (error) {
|
|
344
|
-
throw new BadRequestError2("Invalid
|
|
345
|
-
}
|
|
346
|
-
if (value.units && Array.isArray(value.units)) {
|
|
347
|
-
value.units = value.units.map((item) => {
|
|
348
|
-
try {
|
|
349
|
-
return {
|
|
350
|
-
...item,
|
|
351
|
-
unit: new ObjectId2(item.unit)
|
|
352
|
-
};
|
|
353
|
-
} catch (error) {
|
|
354
|
-
throw new BadRequestError2(`Invalid unit ID format: ${item.unit}`);
|
|
355
|
-
}
|
|
356
|
-
});
|
|
378
|
+
throw new BadRequestError2("Invalid unit ID format.");
|
|
357
379
|
}
|
|
358
380
|
try {
|
|
359
|
-
const
|
|
360
|
-
|
|
381
|
+
const res = await collection.updateMany(
|
|
382
|
+
{ "units.unit": unitId },
|
|
383
|
+
{
|
|
384
|
+
$set: {
|
|
385
|
+
"units.$.name": name,
|
|
386
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
{ session }
|
|
390
|
+
);
|
|
361
391
|
if (res.modifiedCount === 0) {
|
|
362
|
-
throw new InternalServerError("Unable to update
|
|
392
|
+
throw new InternalServerError("Unable to update unit name in areas.");
|
|
363
393
|
}
|
|
364
394
|
delNamespace().then(() => {
|
|
365
395
|
logger2.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
@@ -415,6 +445,7 @@ function useAreaRepo() {
|
|
|
415
445
|
getAreas,
|
|
416
446
|
getAreasForChecklist,
|
|
417
447
|
getAreaById,
|
|
448
|
+
verifyAreaByUnitId,
|
|
418
449
|
updateArea,
|
|
419
450
|
updateAreaChecklist,
|
|
420
451
|
deleteArea
|
|
@@ -454,7 +485,7 @@ function useAreaService() {
|
|
|
454
485
|
skippedRows.push(i + 1);
|
|
455
486
|
continue;
|
|
456
487
|
}
|
|
457
|
-
const areaType = String(row.TYPE).trim();
|
|
488
|
+
const areaType = String(row.TYPE).trim().toLowerCase();
|
|
458
489
|
if (!areaType) {
|
|
459
490
|
logger3.warn(`Skipping row ${i + 1} with empty area type`);
|
|
460
491
|
skippedRows.push(i + 1);
|
|
@@ -502,18 +533,22 @@ function useAreaService() {
|
|
|
502
533
|
}
|
|
503
534
|
logger3.info(message);
|
|
504
535
|
if (insertedAreaIds.length === 0) {
|
|
505
|
-
if (duplicateAreas.length > 0 && failedAreas.length === 0) {
|
|
506
|
-
|
|
507
|
-
`No new areas were created. All ${duplicateAreas.length} areas already exist in the system: ${duplicateAreas.join(", ")}`
|
|
508
|
-
|
|
536
|
+
if (duplicateAreas.length > 0 && failedAreas.length === 0 && skippedRows.length === 0) {
|
|
537
|
+
return {
|
|
538
|
+
message: `No new areas were created. All ${duplicateAreas.length} areas already exist in the system: ${duplicateAreas.join(", ")}`
|
|
539
|
+
};
|
|
509
540
|
} else if (failedAreas.length > 0) {
|
|
510
541
|
throw new BadRequestError3(
|
|
511
|
-
`No areas were created. Please check your data format and ensure area names are valid.`
|
|
542
|
+
`No areas were created. ${failedAreas.length} areas failed due to errors. Please check your data format and ensure area names are valid.`
|
|
512
543
|
);
|
|
513
|
-
} else if (skippedRows.length > 0) {
|
|
544
|
+
} else if (skippedRows.length > 0 && duplicateAreas.length === 0) {
|
|
514
545
|
throw new BadRequestError3(
|
|
515
|
-
`No areas were created. All rows contained invalid or missing
|
|
546
|
+
`No areas were created. All ${skippedRows.length} rows contained invalid or missing data.`
|
|
516
547
|
);
|
|
548
|
+
} else {
|
|
549
|
+
return {
|
|
550
|
+
message: `No new areas were created. ${duplicateAreas.length} areas already exist, ${skippedRows.length} rows had invalid data.`
|
|
551
|
+
};
|
|
517
552
|
}
|
|
518
553
|
}
|
|
519
554
|
return { message };
|
|
@@ -521,10 +556,6 @@ function useAreaService() {
|
|
|
521
556
|
logger3.error("Error while uploading area information", error);
|
|
522
557
|
if (error instanceof BadRequestError3) {
|
|
523
558
|
throw error;
|
|
524
|
-
} else if (error.message.includes("duplicate")) {
|
|
525
|
-
throw new BadRequestError3(
|
|
526
|
-
`Upload failed due to duplicate area names. Please ensure all area names are unique.`
|
|
527
|
-
);
|
|
528
559
|
} else if (error.message.includes("validation")) {
|
|
529
560
|
throw new BadRequestError3(
|
|
530
561
|
"Upload failed due to invalid data format. Please check that all required fields are properly filled."
|
|
@@ -577,7 +608,6 @@ function useAreaController() {
|
|
|
577
608
|
getAreas: _getAreas,
|
|
578
609
|
getAreaById: _getAreaById,
|
|
579
610
|
updateArea: _updateArea,
|
|
580
|
-
updateAreaChecklist: _updateAreaChecklist,
|
|
581
611
|
deleteArea: _deleteById
|
|
582
612
|
} = useAreaRepo();
|
|
583
613
|
const { importArea: _importArea } = useAreaService();
|
|
@@ -683,36 +713,6 @@ function useAreaController() {
|
|
|
683
713
|
return;
|
|
684
714
|
}
|
|
685
715
|
}
|
|
686
|
-
async function updateAreaChecklist(req, res, next) {
|
|
687
|
-
const payload = { id: req.params.id, ...req.body };
|
|
688
|
-
const schema = Joi2.object({
|
|
689
|
-
id: Joi2.string().hex().required(),
|
|
690
|
-
units: Joi2.array().items(
|
|
691
|
-
Joi2.object({
|
|
692
|
-
unit: Joi2.string().hex().required(),
|
|
693
|
-
name: Joi2.string().required()
|
|
694
|
-
}).required()
|
|
695
|
-
).min(1).unique("unit", { ignoreUndefined: true }).messages({
|
|
696
|
-
"array.unique": "Duplicate area units are not allowed"
|
|
697
|
-
})
|
|
698
|
-
});
|
|
699
|
-
const { error } = schema.validate(payload);
|
|
700
|
-
if (error) {
|
|
701
|
-
logger4.log({ level: "error", message: error.message });
|
|
702
|
-
next(new BadRequestError4(error.message));
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
try {
|
|
706
|
-
const { id, ...value } = payload;
|
|
707
|
-
await _updateAreaChecklist(id, value);
|
|
708
|
-
res.json({ message: "Area updated successfully." });
|
|
709
|
-
return;
|
|
710
|
-
} catch (error2) {
|
|
711
|
-
logger4.log({ level: "error", message: error2.message });
|
|
712
|
-
next(error2);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
716
|
async function deleteArea(req, res, next) {
|
|
717
717
|
const id = req.params.id;
|
|
718
718
|
const validation = Joi2.string().hex().required();
|
|
@@ -761,7 +761,6 @@ function useAreaController() {
|
|
|
761
761
|
getAreas,
|
|
762
762
|
getAreaById,
|
|
763
763
|
updateArea,
|
|
764
|
-
updateAreaChecklist,
|
|
765
764
|
deleteArea,
|
|
766
765
|
importArea
|
|
767
766
|
};
|
|
@@ -802,7 +801,8 @@ function MUnit(value) {
|
|
|
802
801
|
import {
|
|
803
802
|
BadRequestError as BadRequestError7,
|
|
804
803
|
logger as logger7,
|
|
805
|
-
NotFoundError as NotFoundError3
|
|
804
|
+
NotFoundError as NotFoundError3,
|
|
805
|
+
useAtlas as useAtlas3
|
|
806
806
|
} from "@iservice365/node-server-utils";
|
|
807
807
|
|
|
808
808
|
// src/repositories/hygiene-unit.repository.ts
|
|
@@ -927,7 +927,7 @@ function useUnitRepository() {
|
|
|
927
927
|
throw error;
|
|
928
928
|
}
|
|
929
929
|
}
|
|
930
|
-
async function updateUnit(_id, value) {
|
|
930
|
+
async function updateUnit(_id, value, session) {
|
|
931
931
|
try {
|
|
932
932
|
_id = new ObjectId4(_id);
|
|
933
933
|
} catch (error) {
|
|
@@ -935,7 +935,11 @@ function useUnitRepository() {
|
|
|
935
935
|
}
|
|
936
936
|
try {
|
|
937
937
|
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
938
|
-
const res = await collection.updateOne(
|
|
938
|
+
const res = await collection.updateOne(
|
|
939
|
+
{ _id },
|
|
940
|
+
{ $set: updateValue },
|
|
941
|
+
{ session }
|
|
942
|
+
);
|
|
939
943
|
if (res.modifiedCount === 0) {
|
|
940
944
|
throw new InternalServerError2("Unable to update cleaning unit.");
|
|
941
945
|
}
|
|
@@ -1002,7 +1006,12 @@ function useUnitRepository() {
|
|
|
1002
1006
|
|
|
1003
1007
|
// src/services/hygiene-unit.service.ts
|
|
1004
1008
|
function useUnitService() {
|
|
1005
|
-
const {
|
|
1009
|
+
const {
|
|
1010
|
+
createUnit: _createUnit,
|
|
1011
|
+
updateUnit: _updateUnit,
|
|
1012
|
+
deleteUnit: _deleteUnit
|
|
1013
|
+
} = useUnitRepository();
|
|
1014
|
+
const { verifyAreaByUnitId, updateAreaChecklist } = useAreaRepo();
|
|
1006
1015
|
async function importUnit({
|
|
1007
1016
|
dataJson,
|
|
1008
1017
|
site
|
|
@@ -1096,20 +1105,61 @@ function useUnitService() {
|
|
|
1096
1105
|
}
|
|
1097
1106
|
}
|
|
1098
1107
|
}
|
|
1099
|
-
|
|
1108
|
+
async function updateUnit(_id, value) {
|
|
1109
|
+
const session = useAtlas3.getClient()?.startSession();
|
|
1110
|
+
try {
|
|
1111
|
+
session?.startTransaction();
|
|
1112
|
+
const result = await _updateUnit(_id, value, session);
|
|
1113
|
+
const isExistingArea = await verifyAreaByUnitId(_id);
|
|
1114
|
+
if (isExistingArea) {
|
|
1115
|
+
await updateAreaChecklist(_id, value.name, session);
|
|
1116
|
+
}
|
|
1117
|
+
await session?.commitTransaction();
|
|
1118
|
+
return result;
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
logger7.error(`Error updating unit and associated areas:`, error);
|
|
1121
|
+
if (session?.inTransaction()) {
|
|
1122
|
+
await session?.abortTransaction();
|
|
1123
|
+
}
|
|
1124
|
+
throw error;
|
|
1125
|
+
} finally {
|
|
1126
|
+
session?.endSession();
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
async function deleteUnit(_id) {
|
|
1130
|
+
const session = useAtlas3.getClient()?.startSession();
|
|
1131
|
+
try {
|
|
1132
|
+
session?.startTransaction();
|
|
1133
|
+
const isExistingArea = await verifyAreaByUnitId(_id);
|
|
1134
|
+
if (isExistingArea) {
|
|
1135
|
+
throw new BadRequestError7("Failed to delete unit, unit is in use.");
|
|
1136
|
+
}
|
|
1137
|
+
const result = await _deleteUnit(_id, session);
|
|
1138
|
+
await session?.commitTransaction();
|
|
1139
|
+
return result;
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
logger7.error(`Error deleting unit:`, error);
|
|
1142
|
+
if (session?.inTransaction()) {
|
|
1143
|
+
await session?.abortTransaction();
|
|
1144
|
+
}
|
|
1145
|
+
throw error;
|
|
1146
|
+
} finally {
|
|
1147
|
+
session?.endSession();
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return { importUnit, updateUnit, deleteUnit };
|
|
1100
1151
|
}
|
|
1101
1152
|
|
|
1102
1153
|
// src/controllers/hygiene-unit.controller.ts
|
|
1103
1154
|
import { BadRequestError as BadRequestError8, logger as logger8 } from "@iservice365/node-server-utils";
|
|
1104
1155
|
import Joi4 from "joi";
|
|
1105
1156
|
function useUnitController() {
|
|
1157
|
+
const { createUnit: _createUnit, getUnits: _getUnits } = useUnitRepository();
|
|
1106
1158
|
const {
|
|
1107
|
-
createUnit: _createUnit,
|
|
1108
|
-
getUnits: _getUnits,
|
|
1109
1159
|
updateUnit: _updateUnit,
|
|
1110
|
-
deleteUnit: _deleteUnit
|
|
1111
|
-
|
|
1112
|
-
|
|
1160
|
+
deleteUnit: _deleteUnit,
|
|
1161
|
+
importUnit: _importUnit
|
|
1162
|
+
} = useUnitService();
|
|
1113
1163
|
async function createUnit(req, res, next) {
|
|
1114
1164
|
const payload = { ...req.body, ...req.params };
|
|
1115
1165
|
const { error } = unitSchema.validate(payload);
|
|
@@ -1270,7 +1320,7 @@ function MParentChecklist(value) {
|
|
|
1270
1320
|
// src/repositories/hygiene-parent-checklist.repository.ts
|
|
1271
1321
|
import { ObjectId as ObjectId6 } from "mongodb";
|
|
1272
1322
|
import {
|
|
1273
|
-
useAtlas as
|
|
1323
|
+
useAtlas as useAtlas4,
|
|
1274
1324
|
InternalServerError as InternalServerError3,
|
|
1275
1325
|
paginate as paginate3,
|
|
1276
1326
|
useCache as useCache3,
|
|
@@ -1279,7 +1329,7 @@ import {
|
|
|
1279
1329
|
BadRequestError as BadRequestError10
|
|
1280
1330
|
} from "@iservice365/node-server-utils";
|
|
1281
1331
|
function useParentChecklistRepo() {
|
|
1282
|
-
const db =
|
|
1332
|
+
const db = useAtlas4.getDb();
|
|
1283
1333
|
if (!db) {
|
|
1284
1334
|
throw new InternalServerError3("Unable to connect to server.");
|
|
1285
1335
|
}
|
|
@@ -1442,164 +1492,37 @@ function useParentChecklistRepo() {
|
|
|
1442
1492
|
throw error;
|
|
1443
1493
|
}
|
|
1444
1494
|
}
|
|
1445
|
-
async function updateParentChecklistStatuses(
|
|
1495
|
+
async function updateParentChecklistStatuses(_id, status, session) {
|
|
1446
1496
|
try {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
const
|
|
1457
|
-
{
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
$gte: startOfDay,
|
|
1461
|
-
$lte: endOfDay
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
},
|
|
1465
|
-
{
|
|
1466
|
-
$lookup: {
|
|
1467
|
-
from: "site.cleaning.schedule.areas",
|
|
1468
|
-
let: { parentId: "$_id" },
|
|
1469
|
-
pipeline: [
|
|
1470
|
-
{
|
|
1471
|
-
$match: {
|
|
1472
|
-
$expr: { $eq: ["$parentChecklist", "$$parentId"] }
|
|
1473
|
-
}
|
|
1474
|
-
},
|
|
1475
|
-
{
|
|
1476
|
-
$group: {
|
|
1477
|
-
_id: {
|
|
1478
|
-
parentChecklist: "$parentChecklist"
|
|
1479
|
-
},
|
|
1480
|
-
completedCount: {
|
|
1481
|
-
$sum: {
|
|
1482
|
-
$cond: [{ $eq: ["$status", "completed"] }, 1, 0]
|
|
1483
|
-
}
|
|
1484
|
-
},
|
|
1485
|
-
ongoingCount: {
|
|
1486
|
-
$sum: {
|
|
1487
|
-
$cond: [{ $eq: ["$status", "ongoing"] }, 1, 0]
|
|
1488
|
-
}
|
|
1489
|
-
},
|
|
1490
|
-
readyCount: {
|
|
1491
|
-
$sum: {
|
|
1492
|
-
$cond: [{ $eq: ["$status", "ready"] }, 1, 0]
|
|
1493
|
-
}
|
|
1494
|
-
},
|
|
1495
|
-
totalCount: { $sum: 1 }
|
|
1496
|
-
}
|
|
1497
|
-
},
|
|
1498
|
-
{
|
|
1499
|
-
$addFields: {
|
|
1500
|
-
finalStatus: {
|
|
1501
|
-
$cond: {
|
|
1502
|
-
if: {
|
|
1503
|
-
$and: [
|
|
1504
|
-
{ $gt: ["$completedCount", 0] },
|
|
1505
|
-
{ $eq: ["$ongoingCount", 0] },
|
|
1506
|
-
{ $eq: ["$readyCount", 0] }
|
|
1507
|
-
]
|
|
1508
|
-
},
|
|
1509
|
-
then: "completed",
|
|
1510
|
-
else: {
|
|
1511
|
-
$cond: {
|
|
1512
|
-
if: {
|
|
1513
|
-
$and: [
|
|
1514
|
-
{ $eq: ["$completedCount", 0] },
|
|
1515
|
-
{ $eq: ["$ongoingCount", 0] }
|
|
1516
|
-
]
|
|
1517
|
-
},
|
|
1518
|
-
then: "expired",
|
|
1519
|
-
else: "ongoing"
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
},
|
|
1524
|
-
completedAt: {
|
|
1525
|
-
$cond: {
|
|
1526
|
-
if: {
|
|
1527
|
-
$and: [
|
|
1528
|
-
{ $gt: ["$completedCount", 0] },
|
|
1529
|
-
{ $eq: ["$ongoingCount", 0] },
|
|
1530
|
-
{ $eq: ["$readyCount", 0] }
|
|
1531
|
-
]
|
|
1532
|
-
},
|
|
1533
|
-
then: /* @__PURE__ */ new Date(),
|
|
1534
|
-
else: null
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
],
|
|
1540
|
-
as: "areaStats"
|
|
1541
|
-
}
|
|
1542
|
-
},
|
|
1543
|
-
{
|
|
1544
|
-
$match: {
|
|
1545
|
-
"areaStats.0": { $exists: true }
|
|
1546
|
-
}
|
|
1547
|
-
},
|
|
1548
|
-
{
|
|
1549
|
-
$addFields: {
|
|
1550
|
-
areaData: { $arrayElemAt: ["$areaStats", 0] }
|
|
1551
|
-
}
|
|
1552
|
-
},
|
|
1553
|
-
{
|
|
1554
|
-
$project: {
|
|
1555
|
-
_id: 1,
|
|
1556
|
-
newStatus: "$areaData.finalStatus",
|
|
1557
|
-
completedAt: "$areaData.completedAt"
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
]).toArray();
|
|
1561
|
-
logger10.info(
|
|
1562
|
-
`Found ${statusUpdates.length} parent checklists to potentially update`
|
|
1497
|
+
_id = new ObjectId6(_id);
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
throw new BadRequestError10("Invalid parent checklist ID format.");
|
|
1500
|
+
}
|
|
1501
|
+
try {
|
|
1502
|
+
const updateValue = {
|
|
1503
|
+
status,
|
|
1504
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1505
|
+
};
|
|
1506
|
+
const res = await collection.updateOne(
|
|
1507
|
+
{ _id },
|
|
1508
|
+
{ $set: updateValue },
|
|
1509
|
+
{ session }
|
|
1563
1510
|
);
|
|
1564
|
-
if (
|
|
1565
|
-
|
|
1566
|
-
|
|
1511
|
+
if (res.modifiedCount === 0) {
|
|
1512
|
+
throw new InternalServerError3(
|
|
1513
|
+
"Unable to update parent checklist status."
|
|
1567
1514
|
);
|
|
1568
|
-
return null;
|
|
1569
1515
|
}
|
|
1570
|
-
|
|
1571
|
-
logger10.info(
|
|
1572
|
-
|
|
1516
|
+
delNamespace().then(() => {
|
|
1517
|
+
logger10.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
1518
|
+
}).catch((err) => {
|
|
1519
|
+
logger10.error(
|
|
1520
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1521
|
+
err
|
|
1573
1522
|
);
|
|
1574
|
-
return {
|
|
1575
|
-
updateOne: {
|
|
1576
|
-
filter: { _id: update._id },
|
|
1577
|
-
update: {
|
|
1578
|
-
$set: {
|
|
1579
|
-
status: update.newStatus,
|
|
1580
|
-
completedAt: update.completedAt,
|
|
1581
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
};
|
|
1586
1523
|
});
|
|
1587
|
-
|
|
1588
|
-
if (bulkOps.length > 0) {
|
|
1589
|
-
result = await collection.bulkWrite(bulkOps);
|
|
1590
|
-
delNamespace().then(() => {
|
|
1591
|
-
logger10.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
1592
|
-
}).catch((err) => {
|
|
1593
|
-
logger10.error(
|
|
1594
|
-
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
1595
|
-
err
|
|
1596
|
-
);
|
|
1597
|
-
});
|
|
1598
|
-
}
|
|
1599
|
-
logger10.info(`Updated statuses for ${bulkOps.length} parent checklists.`);
|
|
1600
|
-
return result;
|
|
1524
|
+
return res.modifiedCount;
|
|
1601
1525
|
} catch (error) {
|
|
1602
|
-
logger10.error("Failed to update parent checklist statuses", error);
|
|
1603
1526
|
throw error;
|
|
1604
1527
|
}
|
|
1605
1528
|
}
|
|
@@ -1726,6 +1649,7 @@ var areaChecklistSchema = Joi7.object({
|
|
|
1726
1649
|
set: Joi7.number().min(0).required(),
|
|
1727
1650
|
units: Joi7.array().items(
|
|
1728
1651
|
Joi7.object({
|
|
1652
|
+
unit: Joi7.string().hex().required(),
|
|
1729
1653
|
name: Joi7.string().required()
|
|
1730
1654
|
}).required()
|
|
1731
1655
|
).min(1).required()
|
|
@@ -1750,9 +1674,11 @@ function MAreaChecklist(value) {
|
|
|
1750
1674
|
return {
|
|
1751
1675
|
set: checklistItem.set,
|
|
1752
1676
|
units: checklistItem.units.map((unit) => ({
|
|
1677
|
+
unit: new ObjectId7(unit.unit),
|
|
1753
1678
|
name: unit.name,
|
|
1754
1679
|
status: "ready",
|
|
1755
1680
|
remarks: "",
|
|
1681
|
+
completedBy: "",
|
|
1756
1682
|
timestamp: ""
|
|
1757
1683
|
}))
|
|
1758
1684
|
};
|
|
@@ -1765,10 +1691,14 @@ function MAreaChecklist(value) {
|
|
|
1765
1691
|
checklist: value.checklist || [],
|
|
1766
1692
|
status: "ready",
|
|
1767
1693
|
createdAt: /* @__PURE__ */ new Date(),
|
|
1694
|
+
completedAt: "",
|
|
1768
1695
|
updatedAt: ""
|
|
1769
1696
|
};
|
|
1770
1697
|
}
|
|
1771
1698
|
|
|
1699
|
+
// src/services/hygiene-area-checklist.service.ts
|
|
1700
|
+
import { logger as logger14, useAtlas as useAtlas6 } from "@iservice365/node-server-utils";
|
|
1701
|
+
|
|
1772
1702
|
// src/repositories/hygiene-area-checklist.repository.ts
|
|
1773
1703
|
import {
|
|
1774
1704
|
BadRequestError as BadRequestError13,
|
|
@@ -1776,23 +1706,18 @@ import {
|
|
|
1776
1706
|
logger as logger13,
|
|
1777
1707
|
makeCacheKey as makeCacheKey4,
|
|
1778
1708
|
paginate as paginate4,
|
|
1779
|
-
useAtlas as
|
|
1709
|
+
useAtlas as useAtlas5,
|
|
1780
1710
|
useCache as useCache4
|
|
1781
1711
|
} from "@iservice365/node-server-utils";
|
|
1782
1712
|
import { ObjectId as ObjectId8 } from "mongodb";
|
|
1783
1713
|
function useAreaChecklistRepo() {
|
|
1784
|
-
const db =
|
|
1714
|
+
const db = useAtlas5.getDb();
|
|
1785
1715
|
if (!db) {
|
|
1786
1716
|
throw new InternalServerError4("Unable to connect to server.");
|
|
1787
1717
|
}
|
|
1788
1718
|
const namespace_collection = "site.cleaning.schedule.areas";
|
|
1789
|
-
const unit_checklist_collection = "site.cleaning.schedule.units";
|
|
1790
1719
|
const collection = db.collection(namespace_collection);
|
|
1791
|
-
const unitChecklistCollection = db.collection(unit_checklist_collection);
|
|
1792
1720
|
const { delNamespace, setCache, getCache } = useCache4(namespace_collection);
|
|
1793
|
-
const { delNamespace: delUnitNamespace } = useCache4(
|
|
1794
|
-
unit_checklist_collection
|
|
1795
|
-
);
|
|
1796
1721
|
async function createIndex() {
|
|
1797
1722
|
try {
|
|
1798
1723
|
await collection.createIndexes([
|
|
@@ -1800,7 +1725,8 @@ function useAreaChecklistRepo() {
|
|
|
1800
1725
|
{ key: { type: 1 } },
|
|
1801
1726
|
{ key: { status: 1 } },
|
|
1802
1727
|
{ key: { createdAt: 1 } },
|
|
1803
|
-
{ key: {
|
|
1728
|
+
{ key: { "checklist.units.unit": 1 } },
|
|
1729
|
+
{ key: { "checklist.units.status": 1 } }
|
|
1804
1730
|
]);
|
|
1805
1731
|
} catch (error) {
|
|
1806
1732
|
throw new InternalServerError4(
|
|
@@ -1810,7 +1736,11 @@ function useAreaChecklistRepo() {
|
|
|
1810
1736
|
}
|
|
1811
1737
|
async function createTextIndex() {
|
|
1812
1738
|
try {
|
|
1813
|
-
await collection.createIndex({
|
|
1739
|
+
await collection.createIndex({
|
|
1740
|
+
name: "text",
|
|
1741
|
+
"checklist.units.name": "text",
|
|
1742
|
+
"checklist.units.remarks": "text"
|
|
1743
|
+
});
|
|
1814
1744
|
} catch (error) {
|
|
1815
1745
|
throw new InternalServerError4(
|
|
1816
1746
|
"Failed to create text index on hygiene checklist area."
|
|
@@ -1861,7 +1791,7 @@ function useAreaChecklistRepo() {
|
|
|
1861
1791
|
search = "",
|
|
1862
1792
|
type,
|
|
1863
1793
|
schedule
|
|
1864
|
-
}) {
|
|
1794
|
+
}, session) {
|
|
1865
1795
|
page = page > 0 ? page - 1 : 0;
|
|
1866
1796
|
const query = {};
|
|
1867
1797
|
const cacheOptions = {
|
|
@@ -1883,10 +1813,12 @@ function useAreaChecklistRepo() {
|
|
|
1883
1813
|
cacheOptions.search = search;
|
|
1884
1814
|
}
|
|
1885
1815
|
const cacheKey = makeCacheKey4(namespace_collection, cacheOptions);
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1816
|
+
if (!session) {
|
|
1817
|
+
const cachedData = await getCache(cacheKey);
|
|
1818
|
+
if (cachedData) {
|
|
1819
|
+
logger13.info(`Cache hit for key: ${cacheKey}`);
|
|
1820
|
+
return cachedData;
|
|
1821
|
+
}
|
|
1890
1822
|
}
|
|
1891
1823
|
try {
|
|
1892
1824
|
const pipeline = [
|
|
@@ -1911,7 +1843,15 @@ function useAreaChecklistRepo() {
|
|
|
1911
1843
|
set: {
|
|
1912
1844
|
$cond: {
|
|
1913
1845
|
if: { $gt: [{ $size: { $ifNull: ["$checklist", []] } }, 0] },
|
|
1914
|
-
then: {
|
|
1846
|
+
then: {
|
|
1847
|
+
$max: {
|
|
1848
|
+
$map: {
|
|
1849
|
+
input: "$checklist",
|
|
1850
|
+
as: "item",
|
|
1851
|
+
in: { $toInt: "$$item.set" }
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
},
|
|
1915
1855
|
else: 0
|
|
1916
1856
|
}
|
|
1917
1857
|
}
|
|
@@ -1921,8 +1861,8 @@ function useAreaChecklistRepo() {
|
|
|
1921
1861
|
{ $skip: page * limit },
|
|
1922
1862
|
{ $limit: limit }
|
|
1923
1863
|
];
|
|
1924
|
-
const items = await collection.aggregate(pipeline).toArray();
|
|
1925
|
-
const length = await collection.countDocuments(query);
|
|
1864
|
+
const items = await collection.aggregate(pipeline, { session }).toArray();
|
|
1865
|
+
const length = await collection.countDocuments(query, { session });
|
|
1926
1866
|
const data = paginate4(items, page, limit, length);
|
|
1927
1867
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
1928
1868
|
logger13.info(`Cache set for key: ${cacheKey}`);
|
|
@@ -1938,31 +1878,27 @@ function useAreaChecklistRepo() {
|
|
|
1938
1878
|
page = 1,
|
|
1939
1879
|
limit = 10,
|
|
1940
1880
|
search = "",
|
|
1941
|
-
site,
|
|
1942
1881
|
type,
|
|
1943
1882
|
schedule,
|
|
1944
1883
|
status,
|
|
1945
|
-
createdAt
|
|
1946
|
-
user
|
|
1884
|
+
createdAt
|
|
1947
1885
|
}) {
|
|
1948
1886
|
page = page > 0 ? page - 1 : 0;
|
|
1949
|
-
const query = {
|
|
1887
|
+
const query = {};
|
|
1950
1888
|
const cacheOptions = {
|
|
1951
1889
|
page,
|
|
1952
1890
|
limit
|
|
1953
1891
|
};
|
|
1954
|
-
try {
|
|
1955
|
-
query.site = new ObjectId8(site);
|
|
1956
|
-
cacheOptions.site = site.toString();
|
|
1957
|
-
} catch (error) {
|
|
1958
|
-
throw new BadRequestError13("Invalid site ID format.");
|
|
1959
|
-
}
|
|
1960
1892
|
try {
|
|
1961
1893
|
query.schedule = new ObjectId8(schedule);
|
|
1962
1894
|
cacheOptions.schedule = schedule.toString();
|
|
1963
1895
|
} catch (error) {
|
|
1964
1896
|
throw new BadRequestError13("Invalid parent checklist ID format.");
|
|
1965
1897
|
}
|
|
1898
|
+
if (type) {
|
|
1899
|
+
query.type = type;
|
|
1900
|
+
cacheOptions.type = type;
|
|
1901
|
+
}
|
|
1966
1902
|
if (search) {
|
|
1967
1903
|
query.$text = { $search: search };
|
|
1968
1904
|
cacheOptions.search = search;
|
|
@@ -1980,14 +1916,6 @@ function useAreaChecklistRepo() {
|
|
|
1980
1916
|
} else {
|
|
1981
1917
|
query.status = { $in: ["ongoing", "completed"] };
|
|
1982
1918
|
}
|
|
1983
|
-
if (user) {
|
|
1984
|
-
try {
|
|
1985
|
-
query.acceptedBy = new ObjectId8(user);
|
|
1986
|
-
cacheOptions.user = user.toString();
|
|
1987
|
-
} catch (error) {
|
|
1988
|
-
throw new BadRequestError13("Invalid user ID format.");
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
1919
|
const cacheKey = makeCacheKey4(namespace_collection, cacheOptions);
|
|
1992
1920
|
const cachedData = await getCache(cacheKey);
|
|
1993
1921
|
if (cachedData) {
|
|
@@ -1997,29 +1925,12 @@ function useAreaChecklistRepo() {
|
|
|
1997
1925
|
try {
|
|
1998
1926
|
const pipeline = [
|
|
1999
1927
|
{ $match: query },
|
|
2000
|
-
{
|
|
2001
|
-
$lookup: {
|
|
2002
|
-
from: "users",
|
|
2003
|
-
localField: "acceptedBy",
|
|
2004
|
-
foreignField: "_id",
|
|
2005
|
-
pipeline: [
|
|
2006
|
-
...search ? [{ $match: { name: { $regex: search, $options: "i" } } }] : [],
|
|
2007
|
-
{ $project: { name: 1 } }
|
|
2008
|
-
],
|
|
2009
|
-
as: "acceptedBy"
|
|
2010
|
-
}
|
|
2011
|
-
},
|
|
2012
|
-
{
|
|
2013
|
-
$unwind: {
|
|
2014
|
-
path: "$acceptedBy",
|
|
2015
|
-
preserveNullAndEmptyArrays: true
|
|
2016
|
-
}
|
|
2017
|
-
},
|
|
2018
1928
|
{
|
|
2019
1929
|
$project: {
|
|
2020
1930
|
name: 1,
|
|
1931
|
+
type: 1,
|
|
2021
1932
|
createdAt: 1,
|
|
2022
|
-
|
|
1933
|
+
completedAt: 1,
|
|
2023
1934
|
status: {
|
|
2024
1935
|
$switch: {
|
|
2025
1936
|
branches: [
|
|
@@ -2033,8 +1944,21 @@ function useAreaChecklistRepo() {
|
|
|
2033
1944
|
default: "$status"
|
|
2034
1945
|
}
|
|
2035
1946
|
},
|
|
2036
|
-
|
|
2037
|
-
|
|
1947
|
+
set: {
|
|
1948
|
+
$cond: {
|
|
1949
|
+
if: { $gt: [{ $size: { $ifNull: ["$checklist", []] } }, 0] },
|
|
1950
|
+
then: {
|
|
1951
|
+
$max: {
|
|
1952
|
+
$map: {
|
|
1953
|
+
input: "$checklist",
|
|
1954
|
+
as: "item",
|
|
1955
|
+
in: { $toInt: "$$item.set" }
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
},
|
|
1959
|
+
else: 0
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
2038
1962
|
}
|
|
2039
1963
|
},
|
|
2040
1964
|
{ $sort: { status: 1 } },
|
|
@@ -2072,75 +1996,120 @@ function useAreaChecklistRepo() {
|
|
|
2072
1996
|
const areaPipeline = [
|
|
2073
1997
|
{ $match: { _id } },
|
|
2074
1998
|
{
|
|
2075
|
-
$
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
1999
|
+
$project: {
|
|
2000
|
+
name: 1,
|
|
2001
|
+
createdAt: 1,
|
|
2002
|
+
completedAt: 1,
|
|
2003
|
+
status: {
|
|
2004
|
+
$switch: {
|
|
2005
|
+
branches: [
|
|
2006
|
+
{ case: { $eq: ["$status", "ready"] }, then: "Ready" },
|
|
2007
|
+
{ case: { $eq: ["$status", "ongoing"] }, then: "Ongoing" },
|
|
2008
|
+
{
|
|
2009
|
+
case: { $eq: ["$status", "completed"] },
|
|
2010
|
+
then: "Completed"
|
|
2011
|
+
}
|
|
2012
|
+
],
|
|
2013
|
+
default: "$status"
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
];
|
|
2019
|
+
const unitPipeline = [
|
|
2020
|
+
{ $match: { _id } },
|
|
2021
|
+
{
|
|
2022
|
+
$unwind: {
|
|
2023
|
+
path: "$checklist",
|
|
2024
|
+
preserveNullAndEmptyArrays: false
|
|
2081
2025
|
}
|
|
2082
2026
|
},
|
|
2083
2027
|
{
|
|
2084
2028
|
$unwind: {
|
|
2085
|
-
path: "$
|
|
2086
|
-
preserveNullAndEmptyArrays:
|
|
2029
|
+
path: "$checklist.units",
|
|
2030
|
+
preserveNullAndEmptyArrays: false
|
|
2087
2031
|
}
|
|
2088
2032
|
},
|
|
2089
2033
|
{
|
|
2090
2034
|
$lookup: {
|
|
2091
2035
|
from: "users",
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2036
|
+
let: { completedById: "$checklist.units.completedBy" },
|
|
2037
|
+
pipeline: [
|
|
2038
|
+
{
|
|
2039
|
+
$match: {
|
|
2040
|
+
$expr: {
|
|
2041
|
+
$and: [
|
|
2042
|
+
{ $ne: ["$$completedById", ""] },
|
|
2043
|
+
{ $eq: ["$_id", "$$completedById"] }
|
|
2044
|
+
]
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
},
|
|
2048
|
+
{ $project: { name: 1 } }
|
|
2049
|
+
],
|
|
2050
|
+
as: "completedBy"
|
|
2096
2051
|
}
|
|
2097
2052
|
},
|
|
2098
2053
|
{
|
|
2099
2054
|
$unwind: {
|
|
2100
|
-
path: "$
|
|
2055
|
+
path: "$completedBy",
|
|
2101
2056
|
preserveNullAndEmptyArrays: true
|
|
2102
2057
|
}
|
|
2103
2058
|
},
|
|
2104
2059
|
{
|
|
2105
2060
|
$project: {
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2061
|
+
_id: 0,
|
|
2062
|
+
set: "$checklist.set",
|
|
2063
|
+
unit: "$checklist.units.unit",
|
|
2064
|
+
name: "$checklist.units.name",
|
|
2065
|
+
remarks: "$checklist.units.remarks",
|
|
2111
2066
|
status: {
|
|
2112
2067
|
$switch: {
|
|
2113
2068
|
branches: [
|
|
2114
|
-
{ case: { $eq: ["$status", "ready"] }, then: "Ready" },
|
|
2115
|
-
{ case: { $eq: ["$status", "ongoing"] }, then: "Ongoing" },
|
|
2116
2069
|
{
|
|
2117
|
-
case: { $eq: ["$status", "
|
|
2070
|
+
case: { $eq: ["$checklist.units.status", "ready"] },
|
|
2071
|
+
then: "Ready"
|
|
2072
|
+
},
|
|
2073
|
+
{
|
|
2074
|
+
case: { $eq: ["$checklist.units.status", "completed"] },
|
|
2118
2075
|
then: "Completed"
|
|
2119
2076
|
}
|
|
2120
2077
|
],
|
|
2121
|
-
default: "$status"
|
|
2078
|
+
default: "$checklist.units.status"
|
|
2122
2079
|
}
|
|
2123
2080
|
},
|
|
2124
|
-
|
|
2125
|
-
|
|
2081
|
+
completedByName: "$completedBy.name",
|
|
2082
|
+
timestamp: "$checklist.units.timestamp"
|
|
2126
2083
|
}
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2084
|
+
},
|
|
2085
|
+
{ $sort: { set: 1, name: 1 } },
|
|
2086
|
+
{
|
|
2087
|
+
$group: {
|
|
2088
|
+
_id: "$set",
|
|
2089
|
+
units: {
|
|
2090
|
+
$push: {
|
|
2091
|
+
unit: "$unit",
|
|
2092
|
+
name: "$name",
|
|
2093
|
+
status: "$status",
|
|
2094
|
+
remarks: "$remarks",
|
|
2095
|
+
completedByName: "$completedByName",
|
|
2096
|
+
timestamp: "$timestamp"
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
},
|
|
2131
2101
|
{
|
|
2132
2102
|
$project: {
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
approve: { $ifNull: ["$approve", null] },
|
|
2137
|
-
reject: { $ifNull: ["$reject", null] }
|
|
2103
|
+
_id: 0,
|
|
2104
|
+
set: "$_id",
|
|
2105
|
+
units: 1
|
|
2138
2106
|
}
|
|
2139
|
-
}
|
|
2107
|
+
},
|
|
2108
|
+
{ $sort: { set: 1 } }
|
|
2140
2109
|
];
|
|
2141
2110
|
const [area, units] = await Promise.all([
|
|
2142
2111
|
collection.aggregate(areaPipeline).toArray(),
|
|
2143
|
-
|
|
2112
|
+
collection.aggregate(unitPipeline).toArray()
|
|
2144
2113
|
]);
|
|
2145
2114
|
if (!area.length) {
|
|
2146
2115
|
throw new BadRequestError13("Area checklist not found.");
|
|
@@ -2159,64 +2128,166 @@ function useAreaChecklistRepo() {
|
|
|
2159
2128
|
throw error;
|
|
2160
2129
|
}
|
|
2161
2130
|
}
|
|
2162
|
-
async function
|
|
2131
|
+
async function getAreaChecklistUnits({
|
|
2132
|
+
page = 1,
|
|
2133
|
+
limit = 10,
|
|
2134
|
+
search = "",
|
|
2135
|
+
_id
|
|
2136
|
+
}, session) {
|
|
2137
|
+
page = page > 0 ? page - 1 : 0;
|
|
2138
|
+
const query = {};
|
|
2139
|
+
const cacheOptions = {
|
|
2140
|
+
page,
|
|
2141
|
+
limit
|
|
2142
|
+
};
|
|
2163
2143
|
try {
|
|
2164
|
-
_id = new ObjectId8(_id);
|
|
2144
|
+
query._id = new ObjectId8(_id);
|
|
2145
|
+
cacheOptions._id = _id.toString();
|
|
2165
2146
|
} catch (error) {
|
|
2166
|
-
throw new BadRequestError13("Invalid area ID format.");
|
|
2147
|
+
throw new BadRequestError13("Invalid area checklist ID format.");
|
|
2167
2148
|
}
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2149
|
+
if (search) {
|
|
2150
|
+
query.$text = { $search: search };
|
|
2151
|
+
cacheOptions.search = search;
|
|
2152
|
+
}
|
|
2153
|
+
const cacheKey = makeCacheKey4(namespace_collection, cacheOptions);
|
|
2154
|
+
if (!session) {
|
|
2155
|
+
const cachedData = await getCache(cacheKey);
|
|
2156
|
+
if (cachedData) {
|
|
2157
|
+
logger13.info(`Cache hit for key: ${cacheKey}`);
|
|
2158
|
+
return cachedData;
|
|
2159
|
+
}
|
|
2172
2160
|
}
|
|
2173
2161
|
try {
|
|
2174
|
-
const
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2162
|
+
const pipeline = [
|
|
2163
|
+
{ $match: query },
|
|
2164
|
+
{
|
|
2165
|
+
$unwind: {
|
|
2166
|
+
path: "$checklist",
|
|
2167
|
+
preserveNullAndEmptyArrays: false
|
|
2168
|
+
}
|
|
2179
2169
|
},
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2170
|
+
{
|
|
2171
|
+
$unwind: {
|
|
2172
|
+
path: "$checklist.units",
|
|
2173
|
+
preserveNullAndEmptyArrays: false
|
|
2174
|
+
}
|
|
2175
|
+
},
|
|
2176
|
+
{
|
|
2177
|
+
$project: {
|
|
2178
|
+
_id: 0,
|
|
2179
|
+
set: "$checklist.set",
|
|
2180
|
+
unit: "$checklist.units.unit",
|
|
2181
|
+
name: "$checklist.units.name",
|
|
2182
|
+
status: {
|
|
2183
|
+
$switch: {
|
|
2184
|
+
branches: [
|
|
2185
|
+
{
|
|
2186
|
+
case: { $eq: ["$checklist.units.status", "ready"] },
|
|
2187
|
+
then: "Ready"
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
case: { $eq: ["$checklist.units.status", "completed"] },
|
|
2191
|
+
then: "Completed"
|
|
2192
|
+
}
|
|
2193
|
+
],
|
|
2194
|
+
default: "$checklist.units.status"
|
|
2195
|
+
}
|
|
2196
|
+
},
|
|
2197
|
+
remarks: "$checklist.units.remarks"
|
|
2198
|
+
}
|
|
2199
|
+
},
|
|
2200
|
+
{ $sort: { set: 1, name: 1 } },
|
|
2201
|
+
{
|
|
2202
|
+
$group: {
|
|
2203
|
+
_id: "$set",
|
|
2204
|
+
units: {
|
|
2205
|
+
$push: {
|
|
2206
|
+
unit: "$unit",
|
|
2207
|
+
name: "$name",
|
|
2208
|
+
status: "$status",
|
|
2209
|
+
remarks: "$remarks"
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
$project: {
|
|
2216
|
+
_id: 0,
|
|
2217
|
+
set: "$_id",
|
|
2218
|
+
units: 1
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
{ $sort: { set: 1 } },
|
|
2222
|
+
{ $skip: page * limit },
|
|
2223
|
+
{ $limit: limit }
|
|
2224
|
+
];
|
|
2225
|
+
const countPipeline = [
|
|
2226
|
+
{ $match: query },
|
|
2227
|
+
{
|
|
2228
|
+
$unwind: {
|
|
2229
|
+
path: "$checklist",
|
|
2230
|
+
preserveNullAndEmptyArrays: false
|
|
2231
|
+
}
|
|
2232
|
+
},
|
|
2233
|
+
{
|
|
2234
|
+
$group: {
|
|
2235
|
+
_id: "$checklist.set"
|
|
2236
|
+
}
|
|
2237
|
+
},
|
|
2238
|
+
{ $count: "total" }
|
|
2239
|
+
];
|
|
2240
|
+
const [items, countResult] = await Promise.all([
|
|
2241
|
+
collection.aggregate(pipeline, { session }).toArray(),
|
|
2242
|
+
collection.aggregate(countPipeline, { session }).toArray()
|
|
2243
|
+
]);
|
|
2244
|
+
const length = countResult.length > 0 ? countResult[0].total : 0;
|
|
2245
|
+
const data = paginate4(items, page, limit, length);
|
|
2246
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
2247
|
+
logger13.info(`Cache set for key: ${cacheKey}`);
|
|
2188
2248
|
}).catch((err) => {
|
|
2189
|
-
logger13.error(
|
|
2190
|
-
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2191
|
-
err
|
|
2192
|
-
);
|
|
2249
|
+
logger13.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
2193
2250
|
});
|
|
2194
|
-
return
|
|
2251
|
+
return data;
|
|
2195
2252
|
} catch (error) {
|
|
2196
2253
|
throw error;
|
|
2197
2254
|
}
|
|
2198
2255
|
}
|
|
2199
|
-
async function
|
|
2256
|
+
async function completeAreaChecklistUnits(_id, set, unitId, value, session) {
|
|
2200
2257
|
try {
|
|
2201
2258
|
_id = new ObjectId8(_id);
|
|
2202
2259
|
} catch (error) {
|
|
2203
2260
|
throw new BadRequestError13("Invalid area checklist ID format.");
|
|
2204
2261
|
}
|
|
2262
|
+
try {
|
|
2263
|
+
unitId = new ObjectId8(unitId);
|
|
2264
|
+
} catch (error) {
|
|
2265
|
+
throw new BadRequestError13("Invalid unit checklist ID format.");
|
|
2266
|
+
}
|
|
2205
2267
|
try {
|
|
2206
2268
|
const now = /* @__PURE__ */ new Date();
|
|
2207
2269
|
const updateValue = {
|
|
2208
|
-
|
|
2270
|
+
"checklist.$[checklist].units.$[unit].timestamp": now,
|
|
2271
|
+
"checklist.$[checklist].units.$[unit].status": "completed",
|
|
2209
2272
|
updatedAt: now
|
|
2210
2273
|
};
|
|
2274
|
+
if (value.remarks) {
|
|
2275
|
+
updateValue["checklist.$[checklist].units.$[unit].remarks"] = value.remarks;
|
|
2276
|
+
}
|
|
2277
|
+
if (value.completedBy) {
|
|
2278
|
+
updateValue["checklist.$[checklist].units.$[unit].completedBy"] = new ObjectId8(value.completedBy);
|
|
2279
|
+
}
|
|
2280
|
+
const arrayFilters = [
|
|
2281
|
+
{ "checklist.set": set, "checklist.units.unit": unitId },
|
|
2282
|
+
{ "unit.unit": unitId }
|
|
2283
|
+
];
|
|
2211
2284
|
const res = await collection.updateOne(
|
|
2212
|
-
{ _id },
|
|
2285
|
+
{ _id, "checklist.set": set, "checklist.units.unit": unitId },
|
|
2213
2286
|
{ $set: updateValue },
|
|
2214
|
-
{ session }
|
|
2287
|
+
{ arrayFilters, session }
|
|
2215
2288
|
);
|
|
2216
2289
|
if (res.modifiedCount === 0) {
|
|
2217
|
-
throw new InternalServerError4(
|
|
2218
|
-
"Unable to update cleaning area checklist."
|
|
2219
|
-
);
|
|
2290
|
+
throw new InternalServerError4("Unable to update area checklist unit.");
|
|
2220
2291
|
}
|
|
2221
2292
|
delNamespace().then(() => {
|
|
2222
2293
|
logger13.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
@@ -2226,40 +2297,35 @@ function useAreaChecklistRepo() {
|
|
|
2226
2297
|
err
|
|
2227
2298
|
);
|
|
2228
2299
|
});
|
|
2229
|
-
delUnitNamespace().then(() => {
|
|
2230
|
-
logger13.info(
|
|
2231
|
-
`Cache cleared for namespace: ${unit_checklist_collection}`
|
|
2232
|
-
);
|
|
2233
|
-
}).catch((err) => {
|
|
2234
|
-
logger13.error(
|
|
2235
|
-
`Failed to clear cache for namespace: ${unit_checklist_collection}`,
|
|
2236
|
-
err
|
|
2237
|
-
);
|
|
2238
|
-
});
|
|
2239
2300
|
return res.modifiedCount;
|
|
2240
2301
|
} catch (error) {
|
|
2302
|
+
logger13.error("Error updating area checklist unit:", error.message);
|
|
2241
2303
|
throw error;
|
|
2242
2304
|
}
|
|
2243
2305
|
}
|
|
2244
|
-
async function
|
|
2306
|
+
async function updateAreaChecklistStatus(_id, status, session) {
|
|
2245
2307
|
try {
|
|
2246
2308
|
_id = new ObjectId8(_id);
|
|
2247
2309
|
} catch (error) {
|
|
2248
|
-
throw new BadRequestError13("Invalid area ID format.");
|
|
2310
|
+
throw new BadRequestError13("Invalid area checklist ID format.");
|
|
2249
2311
|
}
|
|
2250
2312
|
try {
|
|
2251
|
-
const now = /* @__PURE__ */ new Date();
|
|
2252
2313
|
const updateValue = {
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
completedAt: now
|
|
2256
|
-
},
|
|
2257
|
-
status: "ongoing",
|
|
2258
|
-
updatedAt: now
|
|
2314
|
+
status,
|
|
2315
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2259
2316
|
};
|
|
2260
|
-
|
|
2317
|
+
if (status === "completed") {
|
|
2318
|
+
updateValue.completedAt = /* @__PURE__ */ new Date();
|
|
2319
|
+
}
|
|
2320
|
+
const res = await collection.updateOne(
|
|
2321
|
+
{ _id },
|
|
2322
|
+
{ $set: updateValue },
|
|
2323
|
+
{ session }
|
|
2324
|
+
);
|
|
2261
2325
|
if (res.modifiedCount === 0) {
|
|
2262
|
-
throw new InternalServerError4(
|
|
2326
|
+
throw new InternalServerError4(
|
|
2327
|
+
"Unable to update area checklist status."
|
|
2328
|
+
);
|
|
2263
2329
|
}
|
|
2264
2330
|
delNamespace().then(() => {
|
|
2265
2331
|
logger13.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
@@ -2274,35 +2340,21 @@ function useAreaChecklistRepo() {
|
|
|
2274
2340
|
throw error;
|
|
2275
2341
|
}
|
|
2276
2342
|
}
|
|
2277
|
-
async function
|
|
2343
|
+
async function getAreaChecklistById(_id, session) {
|
|
2278
2344
|
try {
|
|
2279
2345
|
_id = new ObjectId8(_id);
|
|
2280
2346
|
} catch (error) {
|
|
2281
|
-
throw new BadRequestError13("Invalid area ID format.");
|
|
2347
|
+
throw new BadRequestError13("Invalid area checklist ID format.");
|
|
2282
2348
|
}
|
|
2283
2349
|
try {
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
status: "completed",
|
|
2291
|
-
updatedAt: now
|
|
2292
|
-
};
|
|
2293
|
-
const res = await collection.updateOne({ _id }, { $set: updateValue });
|
|
2294
|
-
if (res.modifiedCount === 0) {
|
|
2295
|
-
throw new InternalServerError4("Unable to update cleaning area.");
|
|
2350
|
+
const area = await collection.findOne(
|
|
2351
|
+
{ _id },
|
|
2352
|
+
{ projection: { schedule: 1, name: 1, type: 1, status: 1 }, session }
|
|
2353
|
+
);
|
|
2354
|
+
if (!area) {
|
|
2355
|
+
throw new BadRequestError13("Area checklist not found.");
|
|
2296
2356
|
}
|
|
2297
|
-
|
|
2298
|
-
logger13.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2299
|
-
}).catch((err) => {
|
|
2300
|
-
logger13.error(
|
|
2301
|
-
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2302
|
-
err
|
|
2303
|
-
);
|
|
2304
|
-
});
|
|
2305
|
-
return res.modifiedCount;
|
|
2357
|
+
return area;
|
|
2306
2358
|
} catch (error) {
|
|
2307
2359
|
throw error;
|
|
2308
2360
|
}
|
|
@@ -2314,24 +2366,27 @@ function useAreaChecklistRepo() {
|
|
|
2314
2366
|
getAllAreaChecklist,
|
|
2315
2367
|
getAreaChecklistHistory,
|
|
2316
2368
|
getAreaChecklistHistoryDetails,
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2369
|
+
getAreaChecklistUnits,
|
|
2370
|
+
getAreaChecklistById,
|
|
2371
|
+
updateAreaChecklistStatus,
|
|
2372
|
+
completeAreaChecklistUnits
|
|
2321
2373
|
};
|
|
2322
2374
|
}
|
|
2323
2375
|
|
|
2324
|
-
// src/controllers/hygiene-area-checklist.controller.ts
|
|
2325
|
-
import { BadRequestError as BadRequestError14, logger as logger15 } from "@iservice365/node-server-utils";
|
|
2326
|
-
import Joi8 from "joi";
|
|
2327
|
-
|
|
2328
2376
|
// src/services/hygiene-area-checklist.service.ts
|
|
2329
|
-
import { logger as logger14, useAtlas as useAtlas5 } from "@iservice365/node-server-utils";
|
|
2330
2377
|
function useAreaChecklistService() {
|
|
2331
|
-
const {
|
|
2378
|
+
const {
|
|
2379
|
+
createAreaChecklist: _createAreaChecklist,
|
|
2380
|
+
getAllAreaChecklist,
|
|
2381
|
+
getAreaChecklistUnits,
|
|
2382
|
+
getAreaChecklistById,
|
|
2383
|
+
completeAreaChecklistUnits: _completeAreaChecklistUnits,
|
|
2384
|
+
updateAreaChecklistStatus
|
|
2385
|
+
} = useAreaChecklistRepo();
|
|
2332
2386
|
const { getAreasForChecklist } = useAreaRepo();
|
|
2387
|
+
const { updateParentChecklistStatuses } = useParentChecklistRepo();
|
|
2333
2388
|
async function createAreaChecklist(value) {
|
|
2334
|
-
const session =
|
|
2389
|
+
const session = useAtlas6.getClient()?.startSession();
|
|
2335
2390
|
try {
|
|
2336
2391
|
session?.startTransaction();
|
|
2337
2392
|
const results = [];
|
|
@@ -2350,14 +2405,13 @@ function useAreaChecklistService() {
|
|
|
2350
2405
|
schedule: value.schedule,
|
|
2351
2406
|
name: area.name,
|
|
2352
2407
|
type: "common",
|
|
2353
|
-
checklist: area.units && area.units.length > 0 ?
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
] : []
|
|
2408
|
+
checklist: area.units && area.units.length > 0 ? Array.from({ length: area.set || 1 }, (_, index) => ({
|
|
2409
|
+
set: index + 1,
|
|
2410
|
+
units: area.units.map((unit) => ({
|
|
2411
|
+
unit: unit.unit.toString(),
|
|
2412
|
+
name: unit.name
|
|
2413
|
+
}))
|
|
2414
|
+
})) : []
|
|
2361
2415
|
};
|
|
2362
2416
|
const insertedId = await _createAreaChecklist(
|
|
2363
2417
|
checklistData,
|
|
@@ -2388,14 +2442,16 @@ function useAreaChecklistService() {
|
|
|
2388
2442
|
schedule: value.schedule,
|
|
2389
2443
|
name: toiletLocation.name,
|
|
2390
2444
|
type: "toilet",
|
|
2391
|
-
checklist: toiletLocation.units && toiletLocation.units.length > 0 ?
|
|
2392
|
-
{
|
|
2393
|
-
|
|
2445
|
+
checklist: toiletLocation.units && toiletLocation.units.length > 0 ? Array.from(
|
|
2446
|
+
{ length: toiletLocation.set || 1 },
|
|
2447
|
+
(_, index) => ({
|
|
2448
|
+
set: index + 1,
|
|
2394
2449
|
units: toiletLocation.units.map((unit) => ({
|
|
2450
|
+
unit: unit.unit.toString(),
|
|
2395
2451
|
name: unit.name
|
|
2396
2452
|
}))
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2453
|
+
})
|
|
2454
|
+
) : []
|
|
2399
2455
|
};
|
|
2400
2456
|
const insertedId = await _createAreaChecklist(
|
|
2401
2457
|
checklistData,
|
|
@@ -2428,21 +2484,107 @@ function useAreaChecklistService() {
|
|
|
2428
2484
|
session?.endSession();
|
|
2429
2485
|
}
|
|
2430
2486
|
}
|
|
2431
|
-
|
|
2487
|
+
async function completeAreaChecklistUnits(_id, set, unitId, value) {
|
|
2488
|
+
const session = useAtlas6.getClient()?.startSession();
|
|
2489
|
+
try {
|
|
2490
|
+
session?.startTransaction();
|
|
2491
|
+
await _completeAreaChecklistUnits(_id, set, unitId, value, session);
|
|
2492
|
+
const allUnitsResult = await getAreaChecklistUnits(
|
|
2493
|
+
{
|
|
2494
|
+
page: 1,
|
|
2495
|
+
limit: 1e3,
|
|
2496
|
+
_id: _id.toString()
|
|
2497
|
+
},
|
|
2498
|
+
session
|
|
2499
|
+
);
|
|
2500
|
+
let areaStatus = "ready";
|
|
2501
|
+
if (allUnitsResult && allUnitsResult.items && allUnitsResult.items.length > 0) {
|
|
2502
|
+
const sets = allUnitsResult.items;
|
|
2503
|
+
const allUnits = sets.flatMap((set2) => set2.units || []);
|
|
2504
|
+
const readyCount = allUnits.filter(
|
|
2505
|
+
(unit) => unit.status === "Ready"
|
|
2506
|
+
).length;
|
|
2507
|
+
const completedCount = allUnits.filter(
|
|
2508
|
+
(unit) => unit.status === "Completed"
|
|
2509
|
+
).length;
|
|
2510
|
+
const totalCount = allUnits.length;
|
|
2511
|
+
if (completedCount === totalCount) {
|
|
2512
|
+
areaStatus = "completed";
|
|
2513
|
+
} else if (readyCount === totalCount) {
|
|
2514
|
+
areaStatus = "ready";
|
|
2515
|
+
} else {
|
|
2516
|
+
areaStatus = "ongoing";
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
await updateAreaChecklistStatus(_id, areaStatus, session);
|
|
2520
|
+
const currentArea = await getAreaChecklistById(_id, session);
|
|
2521
|
+
const scheduleId = currentArea.schedule;
|
|
2522
|
+
if (scheduleId) {
|
|
2523
|
+
const allAreasResult = await getAllAreaChecklist(
|
|
2524
|
+
{
|
|
2525
|
+
page: 1,
|
|
2526
|
+
limit: 1e3,
|
|
2527
|
+
schedule: scheduleId.toString()
|
|
2528
|
+
},
|
|
2529
|
+
session
|
|
2530
|
+
);
|
|
2531
|
+
if (allAreasResult && allAreasResult.items && allAreasResult.items.length > 0) {
|
|
2532
|
+
const areas = allAreasResult.items;
|
|
2533
|
+
const readyAreasCount = areas.filter(
|
|
2534
|
+
(area) => area.status === "Ready"
|
|
2535
|
+
).length;
|
|
2536
|
+
const completedAreasCount = areas.filter(
|
|
2537
|
+
(area) => area.status === "Completed"
|
|
2538
|
+
).length;
|
|
2539
|
+
const totalAreasCount = areas.length;
|
|
2540
|
+
let parentStatus = "ready";
|
|
2541
|
+
if (completedAreasCount === totalAreasCount) {
|
|
2542
|
+
parentStatus = "completed";
|
|
2543
|
+
} else if (readyAreasCount === totalAreasCount) {
|
|
2544
|
+
parentStatus = "ready";
|
|
2545
|
+
} else {
|
|
2546
|
+
parentStatus = "ongoing";
|
|
2547
|
+
}
|
|
2548
|
+
await updateParentChecklistStatuses(
|
|
2549
|
+
scheduleId,
|
|
2550
|
+
parentStatus,
|
|
2551
|
+
session
|
|
2552
|
+
);
|
|
2553
|
+
} else {
|
|
2554
|
+
logger14.info(
|
|
2555
|
+
"No area checklists found, keeping parent status as ready"
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
await session?.commitTransaction();
|
|
2560
|
+
return;
|
|
2561
|
+
} catch (error) {
|
|
2562
|
+
logger14.error(`Error updating area checklist unit and statuses:`, error);
|
|
2563
|
+
if (session?.inTransaction()) {
|
|
2564
|
+
await session?.abortTransaction();
|
|
2565
|
+
}
|
|
2566
|
+
throw error;
|
|
2567
|
+
} finally {
|
|
2568
|
+
session?.endSession();
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
return { createAreaChecklist, completeAreaChecklistUnits };
|
|
2432
2572
|
}
|
|
2433
2573
|
|
|
2434
2574
|
// src/controllers/hygiene-area-checklist.controller.ts
|
|
2575
|
+
import { BadRequestError as BadRequestError14, logger as logger15 } from "@iservice365/node-server-utils";
|
|
2576
|
+
import Joi8 from "joi";
|
|
2435
2577
|
function useAreaChecklistController() {
|
|
2436
2578
|
const {
|
|
2437
2579
|
getAllAreaChecklist: _getAllAreaChecklist,
|
|
2438
2580
|
getAreaChecklistHistory: _getAreaChecklistHistory,
|
|
2439
2581
|
getAreaChecklistHistoryDetails: _getAreaChecklistHistoryDetails,
|
|
2440
|
-
|
|
2441
|
-
attachImageAreaChecklist: _attachImageAreaChecklist,
|
|
2442
|
-
submitAreaChecklist: _submitAreaChecklist,
|
|
2443
|
-
completeAreaChecklist: _completeAreaChecklist
|
|
2582
|
+
getAreaChecklistUnits: _getAreaChecklistUnits
|
|
2444
2583
|
} = useAreaChecklistRepo();
|
|
2445
|
-
const {
|
|
2584
|
+
const {
|
|
2585
|
+
createAreaChecklist: _createAreaChecklist,
|
|
2586
|
+
completeAreaChecklistUnits: _completeAreaChecklistUnits
|
|
2587
|
+
} = useAreaChecklistService();
|
|
2446
2588
|
async function createAreaChecklist(req, res, next) {
|
|
2447
2589
|
const payload = {
|
|
2448
2590
|
site: req.params.site,
|
|
@@ -2505,22 +2647,15 @@ function useAreaChecklistController() {
|
|
|
2505
2647
|
}
|
|
2506
2648
|
}
|
|
2507
2649
|
async function getAreaChecklistHistory(req, res, next) {
|
|
2508
|
-
const
|
|
2509
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2510
|
-
{}
|
|
2511
|
-
) : {};
|
|
2512
|
-
const user = cookies["user"] || "";
|
|
2513
|
-
const query = { ...req.query, ...req.params, user };
|
|
2650
|
+
const query = { ...req.query, ...req.params };
|
|
2514
2651
|
const validation = Joi8.object({
|
|
2515
2652
|
page: Joi8.number().min(1).optional().allow("", null),
|
|
2516
2653
|
limit: Joi8.number().min(1).optional().allow("", null),
|
|
2517
2654
|
search: Joi8.string().optional().allow("", null),
|
|
2518
|
-
|
|
2519
|
-
type: Joi8.string().valid(...allowedTypes).required(),
|
|
2655
|
+
type: Joi8.string().optional().allow("", ...allowedTypes),
|
|
2520
2656
|
schedule: Joi8.string().hex().required(),
|
|
2521
2657
|
status: Joi8.string().allow("", null, ...allowedStatus),
|
|
2522
|
-
createdAt: Joi8.alternatives().try(Joi8.date(), Joi8.string()).optional().allow("", null)
|
|
2523
|
-
user: Joi8.string().hex().optional().allow("", null)
|
|
2658
|
+
createdAt: Joi8.alternatives().try(Joi8.date(), Joi8.string()).optional().allow("", null)
|
|
2524
2659
|
});
|
|
2525
2660
|
const { error } = validation.validate(query);
|
|
2526
2661
|
if (error) {
|
|
@@ -2531,7 +2666,6 @@ function useAreaChecklistController() {
|
|
|
2531
2666
|
const page = parseInt(req.query.page) ?? 1;
|
|
2532
2667
|
const limit = parseInt(req.query.limit) ?? 20;
|
|
2533
2668
|
const search = req.query.search ?? "";
|
|
2534
|
-
const site = req.params.site ?? "";
|
|
2535
2669
|
const type = req.query.type ?? "";
|
|
2536
2670
|
const schedule = req.params.schedule ?? "";
|
|
2537
2671
|
const status = req.query.status ?? "";
|
|
@@ -2541,12 +2675,10 @@ function useAreaChecklistController() {
|
|
|
2541
2675
|
page,
|
|
2542
2676
|
limit,
|
|
2543
2677
|
search,
|
|
2544
|
-
site,
|
|
2545
2678
|
type,
|
|
2546
2679
|
schedule,
|
|
2547
2680
|
status,
|
|
2548
|
-
createdAt
|
|
2549
|
-
user
|
|
2681
|
+
createdAt
|
|
2550
2682
|
});
|
|
2551
2683
|
res.json(data);
|
|
2552
2684
|
return;
|
|
@@ -2575,70 +2707,32 @@ function useAreaChecklistController() {
|
|
|
2575
2707
|
return;
|
|
2576
2708
|
}
|
|
2577
2709
|
}
|
|
2578
|
-
async function
|
|
2579
|
-
const
|
|
2580
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2581
|
-
{}
|
|
2582
|
-
) : {};
|
|
2583
|
-
const acceptedBy = cookies["user"] || "";
|
|
2584
|
-
const payload = { id: req.params.id, acceptedBy };
|
|
2585
|
-
const validation = Joi8.object({
|
|
2586
|
-
id: Joi8.string().hex().required(),
|
|
2587
|
-
acceptedBy: Joi8.string().hex().required()
|
|
2588
|
-
});
|
|
2589
|
-
const { error } = validation.validate(payload);
|
|
2590
|
-
if (error) {
|
|
2591
|
-
logger15.log({ level: "error", message: error.message });
|
|
2592
|
-
next(new BadRequestError14(error.message));
|
|
2593
|
-
return;
|
|
2594
|
-
}
|
|
2595
|
-
try {
|
|
2596
|
-
await _acceptAreaChecklist(payload.id, payload.acceptedBy);
|
|
2597
|
-
res.json({ message: "Area checklist updated successfully." });
|
|
2598
|
-
return;
|
|
2599
|
-
} catch (error2) {
|
|
2600
|
-
logger15.log({ level: "error", message: error2.message });
|
|
2601
|
-
next(error2);
|
|
2602
|
-
return;
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
async function attachImageAreaChecklist(req, res, next) {
|
|
2606
|
-
const payload = { id: req.params.id, attachments: req.body.attachments };
|
|
2607
|
-
const validation = Joi8.object({
|
|
2608
|
-
id: Joi8.string().hex().required(),
|
|
2609
|
-
attachments: Joi8.array().items(Joi8.string()).optional()
|
|
2610
|
-
});
|
|
2611
|
-
const { error } = validation.validate(payload);
|
|
2612
|
-
if (error) {
|
|
2613
|
-
logger15.log({ level: "error", message: error.message });
|
|
2614
|
-
next(new BadRequestError14(error.message));
|
|
2615
|
-
return;
|
|
2616
|
-
}
|
|
2617
|
-
try {
|
|
2618
|
-
await _attachImageAreaChecklist(payload.id, payload.attachments);
|
|
2619
|
-
res.json({ message: "Area checklist attachments updated successfully." });
|
|
2620
|
-
return;
|
|
2621
|
-
} catch (error2) {
|
|
2622
|
-
logger15.log({ level: "error", message: error2.message });
|
|
2623
|
-
next(error2);
|
|
2624
|
-
return;
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
async function submitAreaChecklist(req, res, next) {
|
|
2628
|
-
const payload = { id: req.params.id, signature: req.body.signature };
|
|
2710
|
+
async function getAreaChecklistUnits(req, res, next) {
|
|
2711
|
+
const query = { ...req.query, ...req.params };
|
|
2629
2712
|
const validation = Joi8.object({
|
|
2630
|
-
|
|
2631
|
-
|
|
2713
|
+
page: Joi8.number().min(1).optional().allow("", null),
|
|
2714
|
+
limit: Joi8.number().min(1).optional().allow("", null),
|
|
2715
|
+
search: Joi8.string().optional().allow("", null),
|
|
2716
|
+
id: Joi8.string().hex().required()
|
|
2632
2717
|
});
|
|
2633
|
-
const { error } = validation.validate(
|
|
2718
|
+
const { error } = validation.validate(query);
|
|
2634
2719
|
if (error) {
|
|
2635
2720
|
logger15.log({ level: "error", message: error.message });
|
|
2636
2721
|
next(new BadRequestError14(error.message));
|
|
2637
2722
|
return;
|
|
2638
2723
|
}
|
|
2724
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
2725
|
+
const limit = parseInt(req.query.limit) ?? 20;
|
|
2726
|
+
const search = req.query.search ?? "";
|
|
2727
|
+
const _id = req.params.id ?? "";
|
|
2639
2728
|
try {
|
|
2640
|
-
await
|
|
2641
|
-
|
|
2729
|
+
const data = await _getAreaChecklistUnits({
|
|
2730
|
+
page,
|
|
2731
|
+
limit,
|
|
2732
|
+
search,
|
|
2733
|
+
_id
|
|
2734
|
+
});
|
|
2735
|
+
res.json(data);
|
|
2642
2736
|
return;
|
|
2643
2737
|
} catch (error2) {
|
|
2644
2738
|
logger15.log({ level: "error", message: error2.message });
|
|
@@ -2646,11 +2740,23 @@ function useAreaChecklistController() {
|
|
|
2646
2740
|
return;
|
|
2647
2741
|
}
|
|
2648
2742
|
}
|
|
2649
|
-
async function
|
|
2650
|
-
const
|
|
2743
|
+
async function completeAreaChecklistUnits(req, res, next) {
|
|
2744
|
+
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
2745
|
+
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
2746
|
+
{}
|
|
2747
|
+
) : {};
|
|
2748
|
+
const completedBy = cookies["user"] || "";
|
|
2749
|
+
const payload = {
|
|
2750
|
+
...req.params,
|
|
2751
|
+
...req.body,
|
|
2752
|
+
completedBy
|
|
2753
|
+
};
|
|
2651
2754
|
const validation = Joi8.object({
|
|
2652
2755
|
id: Joi8.string().hex().required(),
|
|
2653
|
-
|
|
2756
|
+
set: Joi8.number().integer().min(1).required(),
|
|
2757
|
+
unit: Joi8.string().hex().required(),
|
|
2758
|
+
remarks: Joi8.string().optional().allow("", null),
|
|
2759
|
+
completedBy: Joi8.string().hex().required()
|
|
2654
2760
|
});
|
|
2655
2761
|
const { error } = validation.validate(payload);
|
|
2656
2762
|
if (error) {
|
|
@@ -2659,8 +2765,14 @@ function useAreaChecklistController() {
|
|
|
2659
2765
|
return;
|
|
2660
2766
|
}
|
|
2661
2767
|
try {
|
|
2662
|
-
|
|
2663
|
-
|
|
2768
|
+
const { id, set, unit, ...value } = payload;
|
|
2769
|
+
await _completeAreaChecklistUnits(
|
|
2770
|
+
id,
|
|
2771
|
+
parseInt(set),
|
|
2772
|
+
unit,
|
|
2773
|
+
value
|
|
2774
|
+
);
|
|
2775
|
+
res.json({ message: "Area checklist updated successfully." });
|
|
2664
2776
|
return;
|
|
2665
2777
|
} catch (error2) {
|
|
2666
2778
|
logger15.log({ level: "error", message: error2.message });
|
|
@@ -2673,30 +2785,25 @@ function useAreaChecklistController() {
|
|
|
2673
2785
|
getAllAreaChecklist,
|
|
2674
2786
|
getAreaChecklistHistory,
|
|
2675
2787
|
getAreaChecklistHistoryDetails,
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
submitAreaChecklist,
|
|
2679
|
-
completeAreaChecklist
|
|
2788
|
+
getAreaChecklistUnits,
|
|
2789
|
+
completeAreaChecklistUnits
|
|
2680
2790
|
};
|
|
2681
2791
|
}
|
|
2682
2792
|
|
|
2683
|
-
// src/models/hygiene-
|
|
2793
|
+
// src/models/hygiene-supply.model.ts
|
|
2684
2794
|
import { BadRequestError as BadRequestError15, logger as logger16 } from "@iservice365/node-server-utils";
|
|
2685
2795
|
import Joi9 from "joi";
|
|
2686
2796
|
import { ObjectId as ObjectId9 } from "mongodb";
|
|
2687
|
-
var
|
|
2797
|
+
var supplySchema = Joi9.object({
|
|
2688
2798
|
site: Joi9.string().hex().required(),
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
unit: Joi9.string().hex().required(),
|
|
2693
|
-
name: Joi9.string().optional().allow("", null),
|
|
2694
|
-
createdBy: Joi9.string().hex().optional().allow("", null)
|
|
2799
|
+
name: Joi9.string().required(),
|
|
2800
|
+
unitOfMeasurement: Joi9.string().required(),
|
|
2801
|
+
qty: Joi9.number().min(0).required()
|
|
2695
2802
|
});
|
|
2696
|
-
function
|
|
2697
|
-
const { error } =
|
|
2803
|
+
function MSupply(value) {
|
|
2804
|
+
const { error } = supplySchema.validate(value);
|
|
2698
2805
|
if (error) {
|
|
2699
|
-
logger16.info(`Hygiene
|
|
2806
|
+
logger16.info(`Hygiene Supply Model: ${error.message}`);
|
|
2700
2807
|
throw new BadRequestError15(error.message);
|
|
2701
2808
|
}
|
|
2702
2809
|
if (value.site) {
|
|
@@ -2706,84 +2813,43 @@ function MUnitChecklist(value) {
|
|
|
2706
2813
|
throw new BadRequestError15("Invalid site ID format.");
|
|
2707
2814
|
}
|
|
2708
2815
|
}
|
|
2709
|
-
if (value.parentChecklist) {
|
|
2710
|
-
try {
|
|
2711
|
-
value.parentChecklist = new ObjectId9(value.parentChecklist);
|
|
2712
|
-
} catch (error2) {
|
|
2713
|
-
throw new BadRequestError15("Invalid parent checklist ID format.");
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
if (value.areaChecklist) {
|
|
2717
|
-
try {
|
|
2718
|
-
value.areaChecklist = new ObjectId9(value.areaChecklist);
|
|
2719
|
-
} catch (error2) {
|
|
2720
|
-
throw new BadRequestError15("Invalid area checklist ID format.");
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
if (value.unit) {
|
|
2724
|
-
try {
|
|
2725
|
-
value.unit = new ObjectId9(value.unit);
|
|
2726
|
-
} catch (error2) {
|
|
2727
|
-
throw new BadRequestError15("Invalid unit ID format.");
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
if (value.createdBy) {
|
|
2731
|
-
try {
|
|
2732
|
-
value.createdBy = new ObjectId9(value.createdBy);
|
|
2733
|
-
} catch (error2) {
|
|
2734
|
-
throw new BadRequestError15("Invalid createdBy ID format.");
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
2816
|
return {
|
|
2738
2817
|
site: value.site,
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
unit: value.unit,
|
|
2743
|
-
name: value.name ?? "",
|
|
2744
|
-
approve: false,
|
|
2745
|
-
reject: false,
|
|
2746
|
-
createdBy: value.createdBy ?? "",
|
|
2818
|
+
name: value.name,
|
|
2819
|
+
unitOfMeasurement: value.unitOfMeasurement,
|
|
2820
|
+
qty: value.qty,
|
|
2747
2821
|
createdAt: /* @__PURE__ */ new Date(),
|
|
2748
|
-
|
|
2822
|
+
status: "active",
|
|
2823
|
+
updatedAt: "",
|
|
2824
|
+
deletedAt: ""
|
|
2749
2825
|
};
|
|
2750
2826
|
}
|
|
2751
2827
|
|
|
2752
|
-
// src/repositories/hygiene-
|
|
2828
|
+
// src/repositories/hygiene-supply.repository.ts
|
|
2829
|
+
import { ObjectId as ObjectId10 } from "mongodb";
|
|
2753
2830
|
import {
|
|
2754
|
-
|
|
2831
|
+
useAtlas as useAtlas7,
|
|
2755
2832
|
InternalServerError as InternalServerError5,
|
|
2756
|
-
logger as logger17,
|
|
2757
|
-
makeCacheKey as makeCacheKey5,
|
|
2758
2833
|
paginate as paginate5,
|
|
2759
|
-
|
|
2760
|
-
useCache as useCache5
|
|
2834
|
+
BadRequestError as BadRequestError16,
|
|
2835
|
+
useCache as useCache5,
|
|
2836
|
+
logger as logger17,
|
|
2837
|
+
makeCacheKey as makeCacheKey5
|
|
2761
2838
|
} from "@iservice365/node-server-utils";
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
const db = useAtlas6.getDb();
|
|
2839
|
+
function useSupplyRepository() {
|
|
2840
|
+
const db = useAtlas7.getDb();
|
|
2765
2841
|
if (!db) {
|
|
2766
2842
|
throw new InternalServerError5("Unable to connect to server.");
|
|
2767
2843
|
}
|
|
2768
|
-
const namespace_collection = "
|
|
2844
|
+
const namespace_collection = "site.supplies";
|
|
2769
2845
|
const collection = db.collection(namespace_collection);
|
|
2770
2846
|
const { delNamespace, setCache, getCache } = useCache5(namespace_collection);
|
|
2771
2847
|
async function createIndex() {
|
|
2772
2848
|
try {
|
|
2773
|
-
await collection.createIndexes([
|
|
2774
|
-
{ key: { site: 1 } },
|
|
2775
|
-
{ key: { type: 1 } },
|
|
2776
|
-
{ key: { parentChecklist: 1 } },
|
|
2777
|
-
{ key: { areaChecklist: 1 } },
|
|
2778
|
-
{ key: { "metadata.workOrder.category": 1 } },
|
|
2779
|
-
{ key: { "metadata.workOrder.createdBy": 1 } },
|
|
2780
|
-
{ key: { "metadata.workOrder.serviceProvider": 1 } },
|
|
2781
|
-
{ key: { "metadata.workOrder.organization": 1 } },
|
|
2782
|
-
{ key: { "metadata.workOrder.site": 1 } }
|
|
2783
|
-
]);
|
|
2849
|
+
await collection.createIndexes([{ key: { site: 1 } }]);
|
|
2784
2850
|
} catch (error) {
|
|
2785
2851
|
throw new InternalServerError5(
|
|
2786
|
-
"Failed to create index on hygiene
|
|
2852
|
+
"Failed to create index on hygiene supply."
|
|
2787
2853
|
);
|
|
2788
2854
|
}
|
|
2789
2855
|
}
|
|
@@ -2792,13 +2858,25 @@ function useUnitChecklistRepo() {
|
|
|
2792
2858
|
await collection.createIndex({ name: "text" });
|
|
2793
2859
|
} catch (error) {
|
|
2794
2860
|
throw new InternalServerError5(
|
|
2795
|
-
"Failed to create text index on hygiene
|
|
2861
|
+
"Failed to create text index on hygiene supply."
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
async function createUniqueIndex() {
|
|
2866
|
+
try {
|
|
2867
|
+
await collection.createIndex(
|
|
2868
|
+
{ site: 1, name: 1, deletedAt: 1 },
|
|
2869
|
+
{ unique: true }
|
|
2870
|
+
);
|
|
2871
|
+
} catch (error) {
|
|
2872
|
+
throw new InternalServerError5(
|
|
2873
|
+
"Failed to create unique index on hygiene supply."
|
|
2796
2874
|
);
|
|
2797
2875
|
}
|
|
2798
2876
|
}
|
|
2799
|
-
async function
|
|
2877
|
+
async function createSupply(value, session) {
|
|
2800
2878
|
try {
|
|
2801
|
-
value =
|
|
2879
|
+
value = MSupply(value);
|
|
2802
2880
|
const res = await collection.insertOne(value, { session });
|
|
2803
2881
|
delNamespace().then(() => {
|
|
2804
2882
|
logger17.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
@@ -2810,42 +2888,34 @@ function useUnitChecklistRepo() {
|
|
|
2810
2888
|
});
|
|
2811
2889
|
return res.insertedId;
|
|
2812
2890
|
} catch (error) {
|
|
2891
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2892
|
+
if (isDuplicated) {
|
|
2893
|
+
throw new BadRequestError16("Supply already exists.");
|
|
2894
|
+
}
|
|
2813
2895
|
throw error;
|
|
2814
2896
|
}
|
|
2815
2897
|
}
|
|
2816
|
-
async function
|
|
2898
|
+
async function getSupplies({
|
|
2817
2899
|
page = 1,
|
|
2818
2900
|
limit = 10,
|
|
2819
2901
|
search = "",
|
|
2820
|
-
site
|
|
2821
|
-
type,
|
|
2822
|
-
parentChecklist,
|
|
2823
|
-
areaChecklist
|
|
2902
|
+
site
|
|
2824
2903
|
}) {
|
|
2825
2904
|
page = page > 0 ? page - 1 : 0;
|
|
2826
|
-
const query = {
|
|
2905
|
+
const query = {
|
|
2906
|
+
status: { $ne: "deleted" }
|
|
2907
|
+
};
|
|
2827
2908
|
const cacheOptions = {
|
|
2828
2909
|
page,
|
|
2829
2910
|
limit
|
|
2830
2911
|
};
|
|
2831
2912
|
try {
|
|
2832
|
-
|
|
2913
|
+
site = new ObjectId10(site);
|
|
2914
|
+
query.site = site;
|
|
2833
2915
|
cacheOptions.site = site.toString();
|
|
2834
2916
|
} catch (error) {
|
|
2835
2917
|
throw new BadRequestError16("Invalid site ID format.");
|
|
2836
2918
|
}
|
|
2837
|
-
try {
|
|
2838
|
-
query.parentChecklist = new ObjectId10(parentChecklist);
|
|
2839
|
-
cacheOptions.parentChecklist = parentChecklist.toString();
|
|
2840
|
-
} catch (error) {
|
|
2841
|
-
throw new BadRequestError16("Invalid parent checklist ID format.");
|
|
2842
|
-
}
|
|
2843
|
-
try {
|
|
2844
|
-
query.areaChecklist = new ObjectId10(areaChecklist);
|
|
2845
|
-
cacheOptions.areaChecklist = areaChecklist.toString();
|
|
2846
|
-
} catch (error) {
|
|
2847
|
-
throw new BadRequestError16("Invalid area checklist ID format.");
|
|
2848
|
-
}
|
|
2849
2919
|
if (search) {
|
|
2850
2920
|
query.$text = { $search: search };
|
|
2851
2921
|
cacheOptions.search = search;
|
|
@@ -2857,120 +2927,20 @@ function useUnitChecklistRepo() {
|
|
|
2857
2927
|
return cachedData;
|
|
2858
2928
|
}
|
|
2859
2929
|
try {
|
|
2860
|
-
const
|
|
2861
|
-
{ $match: query },
|
|
2862
|
-
{
|
|
2863
|
-
$lookup: {
|
|
2864
|
-
from: "hygiene-checklist.areas",
|
|
2865
|
-
localField: "areaChecklist",
|
|
2866
|
-
foreignField: "_id",
|
|
2867
|
-
pipeline: [
|
|
2868
|
-
{ $project: { attachments: "$metadata.attachments" } }
|
|
2869
|
-
],
|
|
2870
|
-
as: "areaChecklistData"
|
|
2871
|
-
}
|
|
2872
|
-
},
|
|
2873
|
-
{
|
|
2874
|
-
$unwind: {
|
|
2875
|
-
path: "$areaChecklistData",
|
|
2876
|
-
preserveNullAndEmptyArrays: true
|
|
2877
|
-
}
|
|
2878
|
-
},
|
|
2879
|
-
{
|
|
2880
|
-
$group: {
|
|
2881
|
-
_id: null,
|
|
2882
|
-
attachments: { $first: "$areaChecklistData.attachments" }
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
]).toArray();
|
|
2886
|
-
const areaAttachments = areaAttachmentsResult.length > 0 ? areaAttachmentsResult[0].attachments || [] : [];
|
|
2887
|
-
const pipeline = [
|
|
2930
|
+
const items = await collection.aggregate([
|
|
2888
2931
|
{ $match: query },
|
|
2889
|
-
{
|
|
2890
|
-
$lookup: {
|
|
2891
|
-
from: "organizations",
|
|
2892
|
-
localField: "metadata.workOrder.category",
|
|
2893
|
-
foreignField: "_id",
|
|
2894
|
-
pipeline: [{ $project: { nature: 1 } }],
|
|
2895
|
-
as: "categoryData"
|
|
2896
|
-
}
|
|
2897
|
-
},
|
|
2898
|
-
{
|
|
2899
|
-
$lookup: {
|
|
2900
|
-
from: "users",
|
|
2901
|
-
localField: "metadata.workOrder.createdBy",
|
|
2902
|
-
foreignField: "_id",
|
|
2903
|
-
pipeline: [{ $project: { name: 1 } }],
|
|
2904
|
-
as: "createdByData"
|
|
2905
|
-
}
|
|
2906
|
-
},
|
|
2907
|
-
{
|
|
2908
|
-
$lookup: {
|
|
2909
|
-
from: "service-providers",
|
|
2910
|
-
localField: "metadata.workOrder.serviceProvider",
|
|
2911
|
-
foreignField: "_id",
|
|
2912
|
-
pipeline: [{ $project: { name: 1 } }],
|
|
2913
|
-
as: "serviceProviderData"
|
|
2914
|
-
}
|
|
2915
|
-
},
|
|
2916
|
-
{
|
|
2917
|
-
$lookup: {
|
|
2918
|
-
from: "organizations",
|
|
2919
|
-
localField: "metadata.workOrder.organization",
|
|
2920
|
-
foreignField: "_id",
|
|
2921
|
-
pipeline: [{ $project: { name: 1 } }],
|
|
2922
|
-
as: "organizationData"
|
|
2923
|
-
}
|
|
2924
|
-
},
|
|
2925
|
-
{
|
|
2926
|
-
$lookup: {
|
|
2927
|
-
from: "sites",
|
|
2928
|
-
localField: "metadata.workOrder.site",
|
|
2929
|
-
foreignField: "_id",
|
|
2930
|
-
pipeline: [{ $project: { name: 1 } }],
|
|
2931
|
-
as: "siteData"
|
|
2932
|
-
}
|
|
2933
|
-
},
|
|
2934
|
-
{
|
|
2935
|
-
$addFields: {
|
|
2936
|
-
"metadata.workOrder.categoryName": {
|
|
2937
|
-
$arrayElemAt: ["$categoryData.nature", 0]
|
|
2938
|
-
},
|
|
2939
|
-
"metadata.workOrder.createdByName": {
|
|
2940
|
-
$arrayElemAt: ["$createdByData.name", 0]
|
|
2941
|
-
},
|
|
2942
|
-
"metadata.workOrder.serviceProviderName": {
|
|
2943
|
-
$arrayElemAt: ["$serviceProviderData.name", 0]
|
|
2944
|
-
},
|
|
2945
|
-
"metadata.workOrder.organizationName": {
|
|
2946
|
-
$arrayElemAt: ["$organizationData.name", 0]
|
|
2947
|
-
},
|
|
2948
|
-
"metadata.workOrder.siteName": {
|
|
2949
|
-
$arrayElemAt: ["$siteData.name", 0]
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2952
|
-
},
|
|
2953
2932
|
{
|
|
2954
2933
|
$project: {
|
|
2955
2934
|
name: 1,
|
|
2956
|
-
|
|
2957
|
-
attachments: "$metadata.attachments",
|
|
2958
|
-
workOrder: "$metadata.workOrder",
|
|
2959
|
-
approve: { $ifNull: ["$approve", null] },
|
|
2960
|
-
reject: { $ifNull: ["$reject", null] }
|
|
2935
|
+
qty: 1
|
|
2961
2936
|
}
|
|
2962
2937
|
},
|
|
2963
2938
|
{ $sort: { _id: -1 } },
|
|
2964
2939
|
{ $skip: page * limit },
|
|
2965
2940
|
{ $limit: limit }
|
|
2966
|
-
];
|
|
2967
|
-
const items = await collection.aggregate(pipeline).toArray();
|
|
2941
|
+
]).toArray();
|
|
2968
2942
|
const length = await collection.countDocuments(query);
|
|
2969
|
-
const
|
|
2970
|
-
const data = {
|
|
2971
|
-
attachments: areaAttachments,
|
|
2972
|
-
...paginatedData
|
|
2973
|
-
};
|
|
2943
|
+
const data = paginate5(items, page, limit, length);
|
|
2974
2944
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
2975
2945
|
logger17.info(`Cache set for key: ${cacheKey}`);
|
|
2976
2946
|
}).catch((err) => {
|
|
@@ -2981,78 +2951,58 @@ function useUnitChecklistRepo() {
|
|
|
2981
2951
|
throw error;
|
|
2982
2952
|
}
|
|
2983
2953
|
}
|
|
2984
|
-
async function
|
|
2954
|
+
async function updateSupply(_id, value, session) {
|
|
2985
2955
|
try {
|
|
2986
2956
|
_id = new ObjectId10(_id);
|
|
2987
2957
|
} catch (error) {
|
|
2988
|
-
throw new BadRequestError16("Invalid
|
|
2958
|
+
throw new BadRequestError16("Invalid supply ID format.");
|
|
2989
2959
|
}
|
|
2990
2960
|
try {
|
|
2991
|
-
|
|
2961
|
+
const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
|
|
2962
|
+
const res = await collection.updateOne(
|
|
2963
|
+
{ _id },
|
|
2964
|
+
{ $set: updateValue },
|
|
2965
|
+
{ session }
|
|
2966
|
+
);
|
|
2967
|
+
if (res.modifiedCount === 0) {
|
|
2968
|
+
throw new InternalServerError5("Unable to update cleaning supply.");
|
|
2969
|
+
}
|
|
2970
|
+
delNamespace().then(() => {
|
|
2971
|
+
logger17.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
2972
|
+
}).catch((err) => {
|
|
2973
|
+
logger17.error(
|
|
2974
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
2975
|
+
err
|
|
2976
|
+
);
|
|
2977
|
+
});
|
|
2978
|
+
return res.modifiedCount;
|
|
2992
2979
|
} catch (error) {
|
|
2980
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
2981
|
+
if (isDuplicated) {
|
|
2982
|
+
throw new BadRequestError16("Area already exists.");
|
|
2983
|
+
}
|
|
2993
2984
|
throw error;
|
|
2994
2985
|
}
|
|
2995
2986
|
}
|
|
2996
|
-
async function
|
|
2987
|
+
async function deleteSupply(_id, session) {
|
|
2997
2988
|
try {
|
|
2998
2989
|
_id = new ObjectId10(_id);
|
|
2999
2990
|
} catch (error) {
|
|
3000
|
-
throw new BadRequestError16("Invalid
|
|
3001
|
-
}
|
|
3002
|
-
if (value.checkedBy && typeof value.checkedBy === "string") {
|
|
3003
|
-
try {
|
|
3004
|
-
value.checkedBy = new ObjectId10(value.checkedBy);
|
|
3005
|
-
} catch (error) {
|
|
3006
|
-
throw new BadRequestError16("Invalid checkedBy ID format.");
|
|
3007
|
-
}
|
|
3008
|
-
}
|
|
3009
|
-
if ("metadata" in value && value.metadata?.workOrder) {
|
|
3010
|
-
const workOrder = value.metadata.workOrder;
|
|
3011
|
-
if (workOrder.category && typeof workOrder.category === "string") {
|
|
3012
|
-
try {
|
|
3013
|
-
workOrder.category = new ObjectId10(workOrder.category);
|
|
3014
|
-
} catch (error) {
|
|
3015
|
-
throw new BadRequestError16("Invalid category ID format.");
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
if (workOrder.createdBy && typeof workOrder.createdBy === "string") {
|
|
3019
|
-
try {
|
|
3020
|
-
workOrder.createdBy = new ObjectId10(workOrder.createdBy);
|
|
3021
|
-
} catch (error) {
|
|
3022
|
-
throw new BadRequestError16("Invalid createdBy ID format.");
|
|
3023
|
-
}
|
|
3024
|
-
}
|
|
3025
|
-
if (workOrder.serviceProvider && typeof workOrder.serviceProvider === "string") {
|
|
3026
|
-
try {
|
|
3027
|
-
workOrder.serviceProvider = new ObjectId10(workOrder.serviceProvider);
|
|
3028
|
-
} catch (error) {
|
|
3029
|
-
throw new BadRequestError16("Invalid serviceProvider ID format.");
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
if (workOrder.organization && typeof workOrder.organization === "string") {
|
|
3033
|
-
try {
|
|
3034
|
-
workOrder.organization = new ObjectId10(workOrder.organization);
|
|
3035
|
-
} catch (error) {
|
|
3036
|
-
throw new BadRequestError16("Invalid organization ID format.");
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
if (workOrder.site && typeof workOrder.site === "string") {
|
|
3040
|
-
try {
|
|
3041
|
-
workOrder.site = new ObjectId10(workOrder.site);
|
|
3042
|
-
} catch (error) {
|
|
3043
|
-
throw new BadRequestError16("Invalid site ID format.");
|
|
3044
|
-
}
|
|
3045
|
-
}
|
|
2991
|
+
throw new BadRequestError16("Invalid supply ID format.");
|
|
3046
2992
|
}
|
|
3047
2993
|
try {
|
|
3048
|
-
const updateValue = {
|
|
2994
|
+
const updateValue = {
|
|
2995
|
+
status: "deleted",
|
|
2996
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
2997
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
2998
|
+
};
|
|
3049
2999
|
const res = await collection.updateOne(
|
|
3050
3000
|
{ _id },
|
|
3051
3001
|
{ $set: updateValue },
|
|
3052
3002
|
{ session }
|
|
3053
3003
|
);
|
|
3054
3004
|
if (res.modifiedCount === 0) {
|
|
3055
|
-
throw new InternalServerError5("Unable to
|
|
3005
|
+
throw new InternalServerError5("Unable to delete supply.");
|
|
3056
3006
|
}
|
|
3057
3007
|
delNamespace().then(() => {
|
|
3058
3008
|
logger17.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
@@ -3070,129 +3020,53 @@ function useUnitChecklistRepo() {
|
|
|
3070
3020
|
return {
|
|
3071
3021
|
createIndex,
|
|
3072
3022
|
createTextIndex,
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3023
|
+
createUniqueIndex,
|
|
3024
|
+
createSupply,
|
|
3025
|
+
getSupplies,
|
|
3026
|
+
updateSupply,
|
|
3027
|
+
deleteSupply
|
|
3077
3028
|
};
|
|
3078
3029
|
}
|
|
3079
3030
|
|
|
3080
|
-
// src/controllers/hygiene-
|
|
3081
|
-
import { BadRequestError as BadRequestError17, logger as
|
|
3031
|
+
// src/controllers/hygiene-supply.controller.ts
|
|
3032
|
+
import { BadRequestError as BadRequestError17, logger as logger18 } from "@iservice365/node-server-utils";
|
|
3082
3033
|
import Joi10 from "joi";
|
|
3083
|
-
|
|
3084
|
-
// src/services/hygiene-unit-checklist.service.ts
|
|
3085
|
-
import { logger as logger18, NotFoundError as NotFoundError4 } from "@iservice365/node-server-utils";
|
|
3086
|
-
import {
|
|
3087
|
-
useSiteRepo,
|
|
3088
|
-
useWorkOrderService
|
|
3089
|
-
} from "@iservice365/core";
|
|
3090
|
-
function useUnitChecklistService() {
|
|
3091
|
-
const {
|
|
3092
|
-
getUnitChecklistById: _getUnitChecklistById,
|
|
3093
|
-
updateUnitChecklist: _updateUnitChecklist
|
|
3094
|
-
} = useUnitChecklistRepo();
|
|
3095
|
-
const { getSiteById } = useSiteRepo();
|
|
3096
|
-
const { createWorkOrder } = useWorkOrderService();
|
|
3097
|
-
async function approveUnitChecklist(id, value) {
|
|
3098
|
-
try {
|
|
3099
|
-
value.approve = true;
|
|
3100
|
-
value.reject = false;
|
|
3101
|
-
const result = await _updateUnitChecklist(id, value);
|
|
3102
|
-
return result;
|
|
3103
|
-
} catch (error) {
|
|
3104
|
-
logger18.error(`Error updating unit checklist with id ${id}:`, error);
|
|
3105
|
-
throw error;
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
async function rejectUnitChecklist(id, value, fullHost) {
|
|
3109
|
-
try {
|
|
3110
|
-
value.reject = true;
|
|
3111
|
-
value.approve = false;
|
|
3112
|
-
if (value.metadata?.workOrder) {
|
|
3113
|
-
const existingChecklist = await _getUnitChecklistById(id);
|
|
3114
|
-
if (!existingChecklist)
|
|
3115
|
-
throw new NotFoundError4("Unit checklist not found.");
|
|
3116
|
-
const site = await getSiteById(
|
|
3117
|
-
existingChecklist.site
|
|
3118
|
-
);
|
|
3119
|
-
if (!site)
|
|
3120
|
-
throw new NotFoundError4("Site not found.");
|
|
3121
|
-
const workOrderData = {
|
|
3122
|
-
...value.metadata.workOrder,
|
|
3123
|
-
attachments: value.metadata.attachments,
|
|
3124
|
-
createdBy: value.checkedBy,
|
|
3125
|
-
organization: site.orgId,
|
|
3126
|
-
site: site._id
|
|
3127
|
-
};
|
|
3128
|
-
const workOrder = await createWorkOrder(
|
|
3129
|
-
workOrderData,
|
|
3130
|
-
fullHost
|
|
3131
|
-
);
|
|
3132
|
-
if (!workOrder)
|
|
3133
|
-
throw new NotFoundError4("Failed to create work order.");
|
|
3134
|
-
}
|
|
3135
|
-
const result = await _updateUnitChecklist(id, value);
|
|
3136
|
-
return result;
|
|
3137
|
-
} catch (error) {
|
|
3138
|
-
logger18.error(`Error updating unit checklist with id ${id}:`, error);
|
|
3139
|
-
throw error;
|
|
3140
|
-
}
|
|
3141
|
-
}
|
|
3142
|
-
return {
|
|
3143
|
-
approveUnitChecklist,
|
|
3144
|
-
rejectUnitChecklist
|
|
3145
|
-
};
|
|
3146
|
-
}
|
|
3147
|
-
|
|
3148
|
-
// src/controllers/hygiene-unit-checklist.controller.ts
|
|
3149
|
-
import { workOrderSchema } from "@iservice365/core";
|
|
3150
|
-
function useUnitChecklistController() {
|
|
3034
|
+
function useSupplyController() {
|
|
3151
3035
|
const {
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
|
|
3161
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3162
|
-
{}
|
|
3163
|
-
) : {};
|
|
3164
|
-
const createdBy = cookies["user"] || "";
|
|
3165
|
-
const payload = { ...req.body, ...req.params, createdBy };
|
|
3166
|
-
const { error } = unitChecklistSchema.validate(payload);
|
|
3036
|
+
createSupply: _createSupply,
|
|
3037
|
+
getSupplies: _getSupplies,
|
|
3038
|
+
updateSupply: _updateSupply,
|
|
3039
|
+
deleteSupply: _deleteSupply
|
|
3040
|
+
} = useSupplyRepository();
|
|
3041
|
+
async function createSupply(req, res, next) {
|
|
3042
|
+
const payload = { ...req.body, ...req.params };
|
|
3043
|
+
const { error } = supplySchema.validate(payload);
|
|
3167
3044
|
if (error) {
|
|
3168
|
-
|
|
3045
|
+
logger18.log({ level: "error", message: error.message });
|
|
3169
3046
|
next(new BadRequestError17(error.message));
|
|
3170
3047
|
return;
|
|
3171
3048
|
}
|
|
3172
3049
|
try {
|
|
3173
|
-
const id = await
|
|
3174
|
-
res.status(201).json({ message: "
|
|
3050
|
+
const id = await _createSupply(payload);
|
|
3051
|
+
res.status(201).json({ message: "Supply created successfully.", id });
|
|
3175
3052
|
return;
|
|
3176
3053
|
} catch (error2) {
|
|
3177
|
-
|
|
3054
|
+
logger18.log({ level: "error", message: error2.message });
|
|
3178
3055
|
next(error2);
|
|
3179
3056
|
return;
|
|
3180
3057
|
}
|
|
3181
3058
|
}
|
|
3182
|
-
async function
|
|
3059
|
+
async function getSupplies(req, res, next) {
|
|
3183
3060
|
const query = { ...req.query, ...req.params };
|
|
3184
3061
|
const validation = Joi10.object({
|
|
3185
3062
|
page: Joi10.number().min(1).optional().allow("", null),
|
|
3186
3063
|
limit: Joi10.number().min(1).optional().allow("", null),
|
|
3187
3064
|
search: Joi10.string().optional().allow("", null),
|
|
3188
|
-
site: Joi10.string().hex().required()
|
|
3189
|
-
type: Joi10.string().valid(...allowedTypes).required(),
|
|
3190
|
-
parentChecklist: Joi10.string().hex().required(),
|
|
3191
|
-
areaChecklist: Joi10.string().hex().required()
|
|
3065
|
+
site: Joi10.string().hex().required()
|
|
3192
3066
|
});
|
|
3193
3067
|
const { error } = validation.validate(query);
|
|
3194
3068
|
if (error) {
|
|
3195
|
-
|
|
3069
|
+
logger18.log({ level: "error", message: error.message });
|
|
3196
3070
|
next(new BadRequestError17(error.message));
|
|
3197
3071
|
return;
|
|
3198
3072
|
}
|
|
@@ -3200,132 +3074,98 @@ function useUnitChecklistController() {
|
|
|
3200
3074
|
const limit = parseInt(req.query.limit) ?? 20;
|
|
3201
3075
|
const search = req.query.search ?? "";
|
|
3202
3076
|
const site = req.params.site ?? "";
|
|
3203
|
-
const type = req.params.type ?? "";
|
|
3204
|
-
const parentChecklist = req.params.parentChecklist ?? "";
|
|
3205
|
-
const areaChecklist = req.params.areaChecklist ?? "";
|
|
3206
3077
|
try {
|
|
3207
|
-
const data = await
|
|
3078
|
+
const data = await _getSupplies({
|
|
3208
3079
|
page,
|
|
3209
3080
|
limit,
|
|
3210
3081
|
search,
|
|
3211
|
-
site
|
|
3212
|
-
type,
|
|
3213
|
-
parentChecklist,
|
|
3214
|
-
areaChecklist
|
|
3082
|
+
site
|
|
3215
3083
|
});
|
|
3216
3084
|
res.json(data);
|
|
3217
3085
|
return;
|
|
3218
3086
|
} catch (error2) {
|
|
3219
|
-
|
|
3087
|
+
logger18.log({ level: "error", message: error2.message });
|
|
3220
3088
|
next(error2);
|
|
3221
3089
|
return;
|
|
3222
3090
|
}
|
|
3223
3091
|
}
|
|
3224
|
-
async function
|
|
3225
|
-
const
|
|
3226
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3227
|
-
{}
|
|
3228
|
-
) : {};
|
|
3229
|
-
const checkedBy = cookies["user"] || "";
|
|
3230
|
-
const payload = { id: req.params.id, checkedBy };
|
|
3092
|
+
async function updateSupply(req, res, next) {
|
|
3093
|
+
const payload = { id: req.params.id, ...req.body };
|
|
3231
3094
|
const validation = Joi10.object({
|
|
3232
3095
|
id: Joi10.string().hex().required(),
|
|
3233
|
-
|
|
3096
|
+
name: Joi10.string().optional().allow("", null),
|
|
3097
|
+
unitOfMeasurement: Joi10.string().optional().allow("", null),
|
|
3098
|
+
qty: Joi10.number().min(0).optional().allow("", null)
|
|
3234
3099
|
});
|
|
3235
3100
|
const { error } = validation.validate(payload);
|
|
3236
3101
|
if (error) {
|
|
3237
|
-
|
|
3102
|
+
logger18.log({ level: "error", message: error.message });
|
|
3238
3103
|
next(new BadRequestError17(error.message));
|
|
3239
3104
|
return;
|
|
3240
3105
|
}
|
|
3241
3106
|
try {
|
|
3242
3107
|
const { id, ...value } = payload;
|
|
3243
|
-
await
|
|
3244
|
-
res.json({ message: "
|
|
3108
|
+
await _updateSupply(id, value);
|
|
3109
|
+
res.json({ message: "Supply updated successfully." });
|
|
3245
3110
|
return;
|
|
3246
3111
|
} catch (error2) {
|
|
3247
|
-
|
|
3112
|
+
logger18.log({ level: "error", message: error2.message });
|
|
3248
3113
|
next(error2);
|
|
3249
3114
|
return;
|
|
3250
3115
|
}
|
|
3251
3116
|
}
|
|
3252
|
-
async function
|
|
3253
|
-
const
|
|
3254
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
3255
|
-
{}
|
|
3256
|
-
) : {};
|
|
3257
|
-
const checkedBy = cookies["user"] || "";
|
|
3258
|
-
if (req.body.workOrder) {
|
|
3259
|
-
req.body.workOrder.createdBy = checkedBy;
|
|
3260
|
-
}
|
|
3261
|
-
const payload = { id: req.params.id, checkedBy, ...req.body };
|
|
3117
|
+
async function deleteSupply(req, res, next) {
|
|
3118
|
+
const id = req.params.id;
|
|
3262
3119
|
const validation = Joi10.object({
|
|
3263
|
-
id: Joi10.string().hex().required()
|
|
3264
|
-
attachments: Joi10.array().items(Joi10.string()).optional(),
|
|
3265
|
-
remarks: Joi10.string().required(),
|
|
3266
|
-
workOrder: workOrderSchema.optional(),
|
|
3267
|
-
checkedBy: Joi10.string().hex().required()
|
|
3120
|
+
id: Joi10.string().hex().required()
|
|
3268
3121
|
});
|
|
3269
|
-
const { error } = validation.validate(
|
|
3122
|
+
const { error } = validation.validate({ id });
|
|
3270
3123
|
if (error) {
|
|
3271
|
-
|
|
3124
|
+
logger18.log({ level: "error", message: error.message });
|
|
3272
3125
|
next(new BadRequestError17(error.message));
|
|
3273
3126
|
return;
|
|
3274
3127
|
}
|
|
3275
3128
|
try {
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
attachments: attachments || [],
|
|
3279
|
-
remarks: remarks || "",
|
|
3280
|
-
workOrder
|
|
3281
|
-
};
|
|
3282
|
-
if (value.metadata.workOrder) {
|
|
3283
|
-
if (value.metadata.workOrder.category) {
|
|
3284
|
-
value.metadata.workOrder.category = value.metadata.workOrder.category;
|
|
3285
|
-
}
|
|
3286
|
-
if (value.metadata.workOrder.serviceProvider) {
|
|
3287
|
-
value.metadata.workOrder.serviceProvider = value.metadata.workOrder.serviceProvider;
|
|
3288
|
-
}
|
|
3289
|
-
value.metadata.workOrder.createdBy = checkedBy;
|
|
3290
|
-
}
|
|
3291
|
-
const fullHost = req.headers.origin;
|
|
3292
|
-
await _rejectUnitChecklist(id, value, fullHost);
|
|
3293
|
-
res.json({ message: "Unit checklist rejected successfully." });
|
|
3129
|
+
await _deleteSupply(id);
|
|
3130
|
+
res.json({ message: "Supply deleted successfully." });
|
|
3294
3131
|
return;
|
|
3295
3132
|
} catch (error2) {
|
|
3296
|
-
|
|
3133
|
+
logger18.log({ level: "error", message: error2.message });
|
|
3297
3134
|
next(error2);
|
|
3298
3135
|
return;
|
|
3299
3136
|
}
|
|
3300
3137
|
}
|
|
3301
3138
|
return {
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3139
|
+
createSupply,
|
|
3140
|
+
getSupplies,
|
|
3141
|
+
updateSupply,
|
|
3142
|
+
deleteSupply
|
|
3306
3143
|
};
|
|
3307
3144
|
}
|
|
3308
3145
|
export {
|
|
3309
3146
|
MArea,
|
|
3310
3147
|
MAreaChecklist,
|
|
3311
3148
|
MParentChecklist,
|
|
3149
|
+
MSupply,
|
|
3312
3150
|
MUnit,
|
|
3313
|
-
MUnitChecklist,
|
|
3314
3151
|
allowedChecklistStatus,
|
|
3152
|
+
allowedStatus,
|
|
3153
|
+
allowedTypes,
|
|
3315
3154
|
areaChecklistSchema,
|
|
3316
3155
|
areaSchema,
|
|
3317
3156
|
parentChecklistSchema,
|
|
3318
|
-
|
|
3157
|
+
supplySchema,
|
|
3319
3158
|
unitSchema,
|
|
3320
3159
|
useAreaChecklistController,
|
|
3321
3160
|
useAreaChecklistRepo,
|
|
3161
|
+
useAreaChecklistService,
|
|
3322
3162
|
useAreaController,
|
|
3323
3163
|
useAreaRepo,
|
|
3324
3164
|
useAreaService,
|
|
3325
3165
|
useParentChecklistController,
|
|
3326
3166
|
useParentChecklistRepo,
|
|
3327
|
-
|
|
3328
|
-
|
|
3167
|
+
useSupplyController,
|
|
3168
|
+
useSupplyRepository,
|
|
3329
3169
|
useUnitController,
|
|
3330
3170
|
useUnitRepository,
|
|
3331
3171
|
useUnitService
|