@iservice365/module-hygiene 0.1.0 → 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/dist/index.mjs CHANGED
@@ -1436,42 +1436,66 @@ function useToiletLocationController() {
1436
1436
  }
1437
1437
 
1438
1438
  // src/models/hygiene-parent-checklist.model.ts
1439
- import { BadRequestError as BadRequestError9 } from "@iservice365/node-server-utils";
1439
+ import { BadRequestError as BadRequestError9, logger as logger8 } from "@iservice365/node-server-utils";
1440
1440
  import Joi5 from "joi";
1441
+ import { ObjectId as ObjectId5 } from "mongodb";
1442
+ var allowedTypes = ["cleaner", "toilet"];
1443
+ var allowedStatus = [
1444
+ "To Do",
1445
+ "Pending",
1446
+ "In Progress",
1447
+ "Completed",
1448
+ "Expired"
1449
+ ];
1441
1450
  var parentChecklistSchema = Joi5.object({
1442
1451
  date: Joi5.date().required(),
1443
1452
  status: Joi5.array().items(
1444
1453
  Joi5.object({
1445
- site: Joi5.string().hex().required(),
1446
- status: Joi5.string().required(),
1447
- completedAt: Joi5.date().required(),
1448
- type: Joi5.string().required()
1454
+ type: Joi5.string().required().valid(...allowedTypes),
1455
+ site: Joi5.string().hex().required()
1449
1456
  })
1450
- ).optional(),
1451
- updatedAt: Joi5.date().optional().allow("", null)
1457
+ ).optional()
1452
1458
  });
1453
1459
  function MParentChecklist(value) {
1454
1460
  const { error } = parentChecklistSchema.validate(value);
1455
1461
  if (error) {
1462
+ logger8.info(`Hygiene Parent Checklist Model: ${error.message}`);
1456
1463
  throw new BadRequestError9(error.message);
1457
1464
  }
1465
+ if (value.status && Array.isArray(value.status)) {
1466
+ value.status = value.status.map((item) => {
1467
+ try {
1468
+ return {
1469
+ ...item,
1470
+ site: new ObjectId5(item.site),
1471
+ status: item.status || "To Do",
1472
+ completedAt: item.completedAt || ""
1473
+ };
1474
+ } catch (error2) {
1475
+ throw new BadRequestError9(
1476
+ `Invalid status site ID format: ${item.site}`
1477
+ );
1478
+ }
1479
+ });
1480
+ }
1458
1481
  return {
1459
- date: value.date,
1482
+ date: new Date(value.date),
1460
1483
  status: value.status,
1461
1484
  createdAt: /* @__PURE__ */ new Date(),
1462
- updatedAt: value.updatedAt ?? "",
1463
- deletedAt: value.deletedAt ?? ""
1485
+ updatedAt: value.updatedAt ?? ""
1464
1486
  };
1465
1487
  }
1466
1488
 
1467
1489
  // src/repositories/hygiene-parent-checklist.repository.ts
1490
+ import { ObjectId as ObjectId6 } from "mongodb";
1468
1491
  import {
1469
1492
  useAtlas as useAtlas5,
1470
1493
  InternalServerError as InternalServerError3,
1471
1494
  paginate as paginate3,
1472
1495
  useCache as useCache3,
1473
- logger as logger8,
1474
- makeCacheKey as makeCacheKey3
1496
+ logger as logger9,
1497
+ makeCacheKey as makeCacheKey3,
1498
+ BadRequestError as BadRequestError10
1475
1499
  } from "@iservice365/node-server-utils";
1476
1500
  function useParentChecklistRepo() {
1477
1501
  const db = useAtlas5.getDb();
@@ -1480,219 +1504,420 @@ function useParentChecklistRepo() {
1480
1504
  }
1481
1505
  const namespace_collection = "hygiene-parent-checklist";
1482
1506
  const collection = db.collection(namespace_collection);
1483
- const { delNamespace, setCache, getCache, delCache } = useCache3(namespace_collection);
1484
- async function createIndexes() {
1507
+ const { delNamespace, setCache, getCache } = useCache3(namespace_collection);
1508
+ async function createIndex() {
1485
1509
  try {
1486
1510
  await collection.createIndexes([
1487
- { key: { date: "text" } }
1511
+ { key: { date: 1 } },
1512
+ { key: { "status.type": 1, "status.site": 1 } }
1488
1513
  ]);
1489
1514
  } catch (error) {
1490
- throw new InternalServerError3("Failed to create index on site.");
1515
+ throw new InternalServerError3(
1516
+ "Failed to create index on hygiene parent checklist."
1517
+ );
1491
1518
  }
1492
1519
  }
1493
- async function create(value, session) {
1520
+ async function createParentChecklist(value, session) {
1494
1521
  try {
1495
- const currentDate = /* @__PURE__ */ new Date();
1522
+ const currentDate = value.date ? new Date(value.date) : /* @__PURE__ */ new Date();
1496
1523
  const startOfDay = new Date(currentDate);
1497
- startOfDay.setDate(currentDate.getDate());
1498
1524
  startOfDay.setUTCHours(0, 0, 0, 0);
1499
1525
  const endOfDay = new Date(currentDate);
1500
- endOfDay.setDate(currentDate.getDate());
1501
1526
  endOfDay.setUTCHours(23, 59, 59, 999);
1502
- const checklistRecord = await collection.findOne({
1527
+ const existingChecklist = await collection.findOne({
1503
1528
  date: {
1504
1529
  $gte: startOfDay,
1505
1530
  $lte: endOfDay
1506
1531
  }
1507
1532
  });
1533
+ if (existingChecklist) {
1534
+ const dateStr2 = currentDate.toISOString().split("T")[0];
1535
+ logger9.info(`Parent checklist already exists for today: ${dateStr2}`);
1536
+ return existingChecklist._id;
1537
+ }
1538
+ const processedValue = MParentChecklist(value);
1539
+ const result = await collection.insertOne(processedValue, { session });
1508
1540
  delNamespace().then(() => {
1509
- logger8.info(`Cache cleared for namespace: ${namespace_collection}`);
1541
+ logger9.info(`Cache cleared for namespace: ${namespace_collection}`);
1510
1542
  }).catch((err) => {
1511
- logger8.error(
1543
+ logger9.error(
1512
1544
  `Failed to clear cache for namespace: ${namespace_collection}`,
1513
1545
  err
1514
1546
  );
1515
1547
  });
1516
- if (!checklistRecord) {
1517
- value = MParentChecklist(value);
1518
- const res = await collection.insertOne(value, { session });
1519
- return res.insertedId;
1520
- }
1521
- return checklistRecord;
1548
+ const dateStr = currentDate.toISOString().split("T")[0];
1549
+ logger9.info(
1550
+ `Created new parent checklist ${result.insertedId} for today: ${dateStr}`
1551
+ );
1552
+ return result.insertedId;
1522
1553
  } catch (error) {
1554
+ logger9.error("Failed to create daily parent checklist", error);
1523
1555
  throw error;
1524
1556
  }
1525
1557
  }
1526
- async function get({
1558
+ async function getAllParentChecklist({
1527
1559
  page = 1,
1528
1560
  limit = 10,
1529
1561
  search = "",
1530
- sort = {},
1562
+ site,
1563
+ type,
1531
1564
  startDate = "",
1532
1565
  endDate = ""
1533
1566
  }) {
1534
1567
  page = page > 0 ? page - 1 : 0;
1535
- let dateFilter = {};
1536
- const query = {
1537
- createdAt: {
1538
- createdAt: {
1539
- $gte: new Date(startDate),
1540
- $lte: new Date(endDate)
1541
- }
1542
- }
1543
- };
1568
+ const query = {};
1544
1569
  const cacheOptions = {
1545
- createdAt: {
1546
- createdAt: {
1547
- $gte: new Date(startDate),
1548
- $lte: new Date(endDate)
1549
- }
1570
+ page,
1571
+ limit
1572
+ };
1573
+ try {
1574
+ site = new ObjectId6(site);
1575
+ cacheOptions.site = site.toString();
1576
+ } catch (error) {
1577
+ throw new BadRequestError10("Invalid site ID format.");
1578
+ }
1579
+ cacheOptions.type = type;
1580
+ query.status = {
1581
+ $elemMatch: {
1582
+ site: new ObjectId6(site),
1583
+ type
1550
1584
  }
1551
1585
  };
1552
- sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
1553
- cacheOptions.sort = JSON.stringify(sort);
1554
1586
  if (search) {
1555
1587
  query.$or = [{ name: { $regex: search, $options: "i" } }];
1556
1588
  cacheOptions.search = search;
1557
1589
  }
1558
- delNamespace().then(() => {
1559
- logger8.info(`Cache cleared for namespace: ${namespace_collection}`);
1560
- }).catch((err) => {
1561
- logger8.error(
1562
- `Failed to clear cache for namespace: ${namespace_collection}`,
1563
- err
1564
- );
1565
- });
1590
+ if (startDate && endDate) {
1591
+ query.createdAt = {
1592
+ $gte: new Date(startDate),
1593
+ $lte: new Date(endDate)
1594
+ };
1595
+ cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
1596
+ cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
1597
+ } else if (startDate) {
1598
+ query.createdAt = { $gte: new Date(startDate) };
1599
+ cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
1600
+ } else if (endDate) {
1601
+ query.createdAt = { $lte: new Date(endDate) };
1602
+ cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
1603
+ }
1566
1604
  const cacheKey = makeCacheKey3(namespace_collection, cacheOptions);
1567
1605
  const cachedData = await getCache(cacheKey);
1568
1606
  if (cachedData) {
1569
- logger8.info(`Cache hit for key: ${cacheKey}`);
1607
+ logger9.info(`Cache hit for key: ${cacheKey}`);
1570
1608
  return cachedData;
1571
1609
  }
1572
- if (startDate && endDate) {
1573
- dateFilter = {
1574
- createdAt: {
1575
- $gte: new Date(startDate),
1576
- $lte: new Date(endDate)
1610
+ try {
1611
+ const pipeline = [{ $match: query }];
1612
+ const filterConditions = [];
1613
+ filterConditions.push({ $eq: ["$$this.site", new ObjectId6(site)] });
1614
+ filterConditions.push({ $eq: ["$$this.type", type] });
1615
+ pipeline.push({
1616
+ $addFields: {
1617
+ filteredStatus: {
1618
+ $filter: {
1619
+ input: "$status",
1620
+ cond: { $and: filterConditions }
1621
+ }
1622
+ }
1577
1623
  }
1578
- };
1579
- } else if (startDate) {
1580
- dateFilter = { createdAt: { $gte: new Date(startDate) } };
1581
- } else if (endDate) {
1582
- dateFilter = { createdAt: { $lte: new Date(endDate) } };
1624
+ });
1625
+ pipeline.push({
1626
+ $match: {
1627
+ filteredStatus: { $ne: [] }
1628
+ }
1629
+ });
1630
+ pipeline.push({
1631
+ $addFields: {
1632
+ statusObj: { $arrayElemAt: ["$filteredStatus", 0] }
1633
+ }
1634
+ });
1635
+ pipeline.push({
1636
+ $project: {
1637
+ _id: 1,
1638
+ date: 1,
1639
+ status: "$statusObj.status",
1640
+ completedAt: "$statusObj.completedAt",
1641
+ createdAt: 1
1642
+ }
1643
+ });
1644
+ pipeline.push(
1645
+ { $sort: { _id: -1 } },
1646
+ { $skip: page * limit },
1647
+ { $limit: limit }
1648
+ );
1649
+ const items = await collection.aggregate(pipeline).toArray();
1650
+ const length = await collection.countDocuments(query);
1651
+ const data = paginate3(items, page, limit, length);
1652
+ setCache(cacheKey, data, 15 * 60).then(() => {
1653
+ logger9.info(`Cache set for key: ${cacheKey}`);
1654
+ }).catch((err) => {
1655
+ logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
1656
+ });
1657
+ return data;
1658
+ } catch (error) {
1659
+ throw error;
1583
1660
  }
1661
+ }
1662
+ async function updateParentChecklistStatuses(date) {
1584
1663
  try {
1585
- const items = await collection.aggregate([
1664
+ const currentDate = /* @__PURE__ */ new Date();
1665
+ const dateToUpdate = date || new Date(currentDate.getTime() - 24 * 60 * 60 * 1e3);
1666
+ const startOfDay = new Date(dateToUpdate);
1667
+ startOfDay.setUTCHours(0, 0, 0, 0);
1668
+ const endOfDay = new Date(dateToUpdate);
1669
+ endOfDay.setUTCHours(23, 59, 59, 999);
1670
+ logger9.info(
1671
+ `Updating parent checklist statuses for date: ${dateToUpdate.toISOString().split("T")[0]}`
1672
+ );
1673
+ const statusUpdates = await collection.aggregate([
1586
1674
  {
1587
1675
  $match: {
1588
- ...dateFilter
1676
+ createdAt: {
1677
+ $gte: startOfDay,
1678
+ $lte: endOfDay
1679
+ }
1680
+ }
1681
+ },
1682
+ {
1683
+ $lookup: {
1684
+ from: "hygiene-checklist.areas",
1685
+ localField: "_id",
1686
+ foreignField: "parentChecklist",
1687
+ pipeline: [
1688
+ {
1689
+ $group: {
1690
+ _id: {
1691
+ site: "$site",
1692
+ type: "$type"
1693
+ },
1694
+ completedCount: {
1695
+ $sum: {
1696
+ $cond: [{ $eq: ["$status", "Completed"] }, 1, 0]
1697
+ }
1698
+ },
1699
+ inProgressCount: {
1700
+ $sum: {
1701
+ $cond: [{ $eq: ["$status", "In Progress"] }, 1, 0]
1702
+ }
1703
+ },
1704
+ toDoCount: {
1705
+ $sum: {
1706
+ $cond: [
1707
+ {
1708
+ $or: [
1709
+ { $eq: ["$status", "To Do"] },
1710
+ { $eq: ["$status", "Pending"] }
1711
+ ]
1712
+ },
1713
+ 1,
1714
+ 0
1715
+ ]
1716
+ }
1717
+ },
1718
+ totalCount: { $sum: 1 }
1719
+ }
1720
+ },
1721
+ {
1722
+ $addFields: {
1723
+ finalStatus: {
1724
+ $cond: {
1725
+ if: {
1726
+ $and: [
1727
+ { $gt: ["$completedCount", 0] },
1728
+ { $eq: ["$inProgressCount", 0] },
1729
+ { $eq: ["$toDoCount", 0] }
1730
+ ]
1731
+ },
1732
+ then: "Completed",
1733
+ else: {
1734
+ $cond: {
1735
+ if: {
1736
+ $and: [
1737
+ { $eq: ["$completedCount", 0] },
1738
+ { $eq: ["$inProgressCount", 0] }
1739
+ ]
1740
+ },
1741
+ then: "Expired",
1742
+ else: "In Progress"
1743
+ }
1744
+ }
1745
+ }
1746
+ },
1747
+ completedAt: {
1748
+ $cond: {
1749
+ if: {
1750
+ $and: [
1751
+ { $gt: ["$completedCount", 0] },
1752
+ { $eq: ["$inProgressCount", 0] },
1753
+ { $eq: ["$toDoCount", 0] }
1754
+ ]
1755
+ },
1756
+ then: /* @__PURE__ */ new Date(),
1757
+ else: null
1758
+ }
1759
+ }
1760
+ }
1761
+ }
1762
+ ],
1763
+ as: "areaStats"
1764
+ }
1765
+ },
1766
+ {
1767
+ $addFields: {
1768
+ newStatus: {
1769
+ $map: {
1770
+ input: "$areaStats",
1771
+ as: "stat",
1772
+ in: {
1773
+ site: "$$stat._id.site",
1774
+ type: "$$stat._id.type",
1775
+ status: "$$stat.finalStatus",
1776
+ completedAt: "$$stat.completedAt"
1777
+ }
1778
+ }
1779
+ }
1589
1780
  }
1590
1781
  },
1782
+ { $match: { newStatus: { $ne: [] } } },
1591
1783
  {
1592
- $facet: {
1593
- totalCount: [{ $count: "count" }],
1594
- items: [
1595
- { $sort: { createdAt: -1 } },
1596
- { $skip: page * limit },
1597
- { $limit: limit }
1598
- ]
1784
+ $project: {
1785
+ _id: 1,
1786
+ newStatus: 1
1599
1787
  }
1600
1788
  }
1601
1789
  ]).toArray();
1602
- const length = await collection.countDocuments(dateFilter);
1603
- const data = paginate3(items, page, limit, length);
1604
- setCache(cacheKey, data, 15 * 60).then(() => {
1605
- logger8.info(`Cache set for key: ${cacheKey}`);
1606
- }).catch((err) => {
1607
- logger8.error(`Failed to set cache for key: ${cacheKey}`, err);
1790
+ logger9.info(
1791
+ `Found ${statusUpdates.length} parent checklists to potentially update`
1792
+ );
1793
+ if (statusUpdates.length === 0) {
1794
+ logger9.info(
1795
+ `No parent checklists found for date range: ${startOfDay.toISOString()} to ${endOfDay.toISOString()}`
1796
+ );
1797
+ return null;
1798
+ }
1799
+ const bulkOps = statusUpdates.map((update) => {
1800
+ const statusTypes = update.newStatus.map((s) => `${s.type}(${s.status})`).join(", ");
1801
+ logger9.info(
1802
+ `Updating parent checklist ${update._id} with ${update.newStatus.length} status entries: [${statusTypes}]`
1803
+ );
1804
+ return {
1805
+ updateOne: {
1806
+ filter: { _id: update._id },
1807
+ update: {
1808
+ $set: {
1809
+ status: update.newStatus,
1810
+ updatedAt: /* @__PURE__ */ new Date()
1811
+ }
1812
+ }
1813
+ }
1814
+ };
1608
1815
  });
1609
- return data;
1816
+ let result = null;
1817
+ if (bulkOps.length > 0) {
1818
+ result = await collection.bulkWrite(bulkOps);
1819
+ delNamespace().then(() => {
1820
+ logger9.info(`Cache cleared for namespace: ${namespace_collection}`);
1821
+ }).catch((err) => {
1822
+ logger9.error(
1823
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1824
+ err
1825
+ );
1826
+ });
1827
+ }
1828
+ logger9.info(`Updated statuses for ${bulkOps.length} parent checklists.`);
1829
+ return result;
1610
1830
  } catch (error) {
1831
+ logger9.error("Failed to update parent checklist statuses", error);
1611
1832
  throw error;
1612
1833
  }
1613
1834
  }
1614
1835
  return {
1615
- createIndexes,
1616
- create,
1617
- get
1836
+ createIndex,
1837
+ createParentChecklist,
1838
+ getAllParentChecklist,
1839
+ updateParentChecklistStatuses
1618
1840
  };
1619
1841
  }
1620
1842
 
1621
1843
  // src/controllers/hygiene-parent-checklist.controller.ts
1622
- import { BadRequestError as BadRequestError11, logger as logger9 } from "@iservice365/node-server-utils";
1844
+ import { BadRequestError as BadRequestError11, logger as logger10 } from "@iservice365/node-server-utils";
1623
1845
  import Joi6 from "joi";
1624
- function useParentCheckilstController() {
1846
+ function useParentChecklistController() {
1625
1847
  const {
1626
- get: _getAll,
1627
- create: _create
1848
+ createParentChecklist: _createParentChecklist,
1849
+ getAllParentChecklist: _getAllParentChecklist
1628
1850
  } = useParentChecklistRepo();
1629
- async function getAll(req, res, next) {
1630
- const query = req.query;
1631
- const validation = Joi6.object({
1632
- page: Joi6.number().min(1).optional().allow("", null),
1633
- limit: Joi6.number().min(1).optional().allow("", null)
1634
- });
1635
- const { error } = validation.validate(query);
1851
+ async function createParentChecklist(req, res, next) {
1852
+ const payload = req.body;
1853
+ const { error } = parentChecklistSchema.validate(payload);
1636
1854
  if (error) {
1855
+ logger10.log({ level: "error", message: error.message });
1637
1856
  next(new BadRequestError11(error.message));
1638
1857
  return;
1639
1858
  }
1640
- const page = parseInt(req.query.page) ?? 1;
1641
- let limit = parseInt(req.query.limit) ?? 20;
1642
- limit = isNaN(limit) ? 20 : limit;
1643
- const sort = req.query.sort ? String(req.query.sort).split(",") : "";
1644
- const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
1645
- const sortObj = {};
1646
- if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
1647
- sort.forEach((field, index) => {
1648
- sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
1649
- });
1650
- }
1651
- const site = req.query.site ?? "";
1652
- const search = req.query.search ?? "";
1653
1859
  try {
1654
- const buildings = await _getAll({
1655
- page,
1656
- limit,
1657
- sort: sortObj,
1658
- site,
1659
- search
1660
- });
1661
- res.json(buildings);
1860
+ const id = await _createParentChecklist(payload);
1861
+ res.status(201).json({ message: "Parent checklist created successfully.", id });
1662
1862
  return;
1663
1863
  } catch (error2) {
1864
+ logger10.log({ level: "error", message: error2.message });
1664
1865
  next(error2);
1866
+ return;
1665
1867
  }
1666
1868
  }
1667
- async function create(req, res, next) {
1668
- const value = req.body;
1669
- const schema = Joi6.object({
1670
- date: Joi6.string().required()
1869
+ async function getAllParentChecklist(req, res, next) {
1870
+ const query = { ...req.query, ...req.params };
1871
+ const validation = Joi6.object({
1872
+ page: Joi6.number().min(1).optional().allow("", null),
1873
+ limit: Joi6.number().min(1).optional().allow("", null),
1874
+ search: Joi6.string().optional().allow("", null),
1875
+ site: Joi6.string().hex().required(),
1876
+ type: Joi6.string().required().valid(...allowedTypes),
1877
+ startDate: Joi6.alternatives().try(Joi6.date(), Joi6.string()).optional().allow("", null),
1878
+ endDate: Joi6.alternatives().try(Joi6.date(), Joi6.string()).optional().allow("", null)
1671
1879
  });
1672
- const { error } = schema.validate(value);
1880
+ const { error } = validation.validate(query);
1673
1881
  if (error) {
1882
+ logger10.log({ level: "error", message: error.message });
1674
1883
  next(new BadRequestError11(error.message));
1675
- logger9.info(`Controller: ${error.message}`);
1676
1884
  return;
1677
1885
  }
1886
+ const page = parseInt(req.query.page) ?? 1;
1887
+ const limit = parseInt(req.query.limit) ?? 20;
1888
+ const search = req.query.search ?? "";
1889
+ const site = req.params.site ?? "";
1890
+ const type = req.params.type ?? "";
1891
+ const startDate = req.query.startDate ?? "";
1892
+ const endDate = req.query.endDate ?? "";
1678
1893
  try {
1679
- const result = await _create(value);
1680
- res.status(201).json(result);
1894
+ const data = await _getAllParentChecklist({
1895
+ page,
1896
+ limit,
1897
+ search,
1898
+ site,
1899
+ type,
1900
+ startDate,
1901
+ endDate
1902
+ });
1903
+ res.json(data);
1681
1904
  return;
1682
1905
  } catch (error2) {
1906
+ logger10.log({ level: "error", message: error2.message });
1683
1907
  next(error2);
1908
+ return;
1684
1909
  }
1685
1910
  }
1686
1911
  return {
1687
- getAll,
1688
- create
1912
+ createParentChecklist,
1913
+ getAllParentChecklist
1689
1914
  };
1690
1915
  }
1691
1916
 
1692
1917
  // src/models/hygiene-unit.model.ts
1693
- import { BadRequestError as BadRequestError12, logger as logger10 } from "@iservice365/node-server-utils";
1918
+ import { BadRequestError as BadRequestError12, logger as logger11 } from "@iservice365/node-server-utils";
1694
1919
  import Joi7 from "joi";
1695
- import { ObjectId as ObjectId5 } from "mongodb";
1920
+ import { ObjectId as ObjectId7 } from "mongodb";
1696
1921
  var unitSchema = Joi7.object({
1697
1922
  name: Joi7.string().required(),
1698
1923
  site: Joi7.string().hex().required(),
@@ -1701,19 +1926,19 @@ var unitSchema = Joi7.object({
1701
1926
  function MUnit(value) {
1702
1927
  const { error } = unitSchema.validate(value);
1703
1928
  if (error) {
1704
- logger10.info(`Hygiene Unit Model: ${error.message}`);
1929
+ logger11.info(`Hygiene Unit Model: ${error.message}`);
1705
1930
  throw new BadRequestError12(error.message);
1706
1931
  }
1707
1932
  if (value.site) {
1708
1933
  try {
1709
- value.site = new ObjectId5(value.site);
1934
+ value.site = new ObjectId7(value.site);
1710
1935
  } catch (error2) {
1711
1936
  throw new BadRequestError12("Invalid site ID format.");
1712
1937
  }
1713
1938
  }
1714
1939
  if (value.createdBy) {
1715
1940
  try {
1716
- value.createdBy = new ObjectId5(value.createdBy);
1941
+ value.createdBy = new ObjectId7(value.createdBy);
1717
1942
  } catch (error2) {
1718
1943
  throw new BadRequestError12("Invalid createdBy ID format.");
1719
1944
  }
@@ -1732,20 +1957,20 @@ function MUnit(value) {
1732
1957
  // src/services/hygiene-unit.service.ts
1733
1958
  import {
1734
1959
  BadRequestError as BadRequestError14,
1735
- logger as logger12,
1736
- NotFoundError as NotFoundError6,
1960
+ logger as logger13,
1961
+ NotFoundError as NotFoundError5,
1737
1962
  useAtlas as useAtlas7
1738
1963
  } from "@iservice365/node-server-utils";
1739
1964
 
1740
1965
  // src/repositories/hygiene-unit.repository.ts
1741
- import { ObjectId as ObjectId6 } from "mongodb";
1966
+ import { ObjectId as ObjectId8 } from "mongodb";
1742
1967
  import {
1743
1968
  useAtlas as useAtlas6,
1744
1969
  InternalServerError as InternalServerError4,
1745
1970
  paginate as paginate4,
1746
1971
  BadRequestError as BadRequestError13,
1747
1972
  useCache as useCache4,
1748
- logger as logger11,
1973
+ logger as logger12,
1749
1974
  makeCacheKey as makeCacheKey4
1750
1975
  } from "@iservice365/node-server-utils";
1751
1976
  function useUnitRepository() {
@@ -1793,9 +2018,9 @@ function useUnitRepository() {
1793
2018
  value = MUnit(value);
1794
2019
  const res = await collection.insertOne(value, { session });
1795
2020
  delNamespace().then(() => {
1796
- logger11.info(`Cache cleared for namespace: ${namespace_collection}`);
2021
+ logger12.info(`Cache cleared for namespace: ${namespace_collection}`);
1797
2022
  }).catch((err) => {
1798
- logger11.error(
2023
+ logger12.error(
1799
2024
  `Failed to clear cache for namespace: ${namespace_collection}`,
1800
2025
  err
1801
2026
  );
@@ -1819,7 +2044,7 @@ function useUnitRepository() {
1819
2044
  }) {
1820
2045
  page = page > 0 ? page - 1 : 0;
1821
2046
  try {
1822
- site = new ObjectId6(site);
2047
+ site = new ObjectId8(site);
1823
2048
  } catch (error) {
1824
2049
  throw new BadRequestError13("Invalid site ID format.");
1825
2050
  }
@@ -1853,7 +2078,7 @@ function useUnitRepository() {
1853
2078
  const cacheKey = makeCacheKey4(namespace_collection, cacheOptions);
1854
2079
  const cachedData = await getCache(cacheKey);
1855
2080
  if (cachedData) {
1856
- logger11.info(`Cache hit for key: ${cacheKey}`);
2081
+ logger12.info(`Cache hit for key: ${cacheKey}`);
1857
2082
  return cachedData;
1858
2083
  }
1859
2084
  try {
@@ -1907,9 +2132,9 @@ function useUnitRepository() {
1907
2132
  const length = await collection.countDocuments(query);
1908
2133
  const data = paginate4(items, page, limit, length);
1909
2134
  setCache(cacheKey, data, 15 * 60).then(() => {
1910
- logger11.info(`Cache set for key: ${cacheKey}`);
2135
+ logger12.info(`Cache set for key: ${cacheKey}`);
1911
2136
  }).catch((err) => {
1912
- logger11.error(`Failed to set cache for key: ${cacheKey}`, err);
2137
+ logger12.error(`Failed to set cache for key: ${cacheKey}`, err);
1913
2138
  });
1914
2139
  return data;
1915
2140
  } catch (error) {
@@ -1919,7 +2144,7 @@ function useUnitRepository() {
1919
2144
  async function getUnitByName(name, site) {
1920
2145
  try {
1921
2146
  if (site)
1922
- site = new ObjectId6(site);
2147
+ site = new ObjectId8(site);
1923
2148
  } catch (error) {
1924
2149
  throw new BadRequestError13("Invalid site ID format.");
1925
2150
  }
@@ -1934,13 +2159,13 @@ function useUnitRepository() {
1934
2159
  }
1935
2160
  async function getUnitById(id, site) {
1936
2161
  try {
1937
- id = typeof id === "string" ? new ObjectId6(id) : id;
2162
+ id = typeof id === "string" ? new ObjectId8(id) : id;
1938
2163
  } catch (error) {
1939
2164
  throw new BadRequestError13("Invalid unit ID format.");
1940
2165
  }
1941
2166
  try {
1942
2167
  if (site)
1943
- site = new ObjectId6(site);
2168
+ site = new ObjectId8(site);
1944
2169
  } catch (error) {
1945
2170
  throw new BadRequestError13(
1946
2171
  "Unable to fetch unit by ID, Invalid site ID format."
@@ -1954,7 +2179,7 @@ function useUnitRepository() {
1954
2179
  }
1955
2180
  async function updateUnit(_id, value) {
1956
2181
  try {
1957
- _id = new ObjectId6(_id);
2182
+ _id = new ObjectId8(_id);
1958
2183
  } catch (error) {
1959
2184
  throw new BadRequestError13("Invalid unit ID format.");
1960
2185
  }
@@ -1965,9 +2190,9 @@ function useUnitRepository() {
1965
2190
  throw new InternalServerError4("Unable to update cleaning unit.");
1966
2191
  }
1967
2192
  delNamespace().then(() => {
1968
- logger11.info(`Cache cleared for namespace: ${namespace_collection}`);
2193
+ logger12.info(`Cache cleared for namespace: ${namespace_collection}`);
1969
2194
  }).catch((err) => {
1970
- logger11.error(
2195
+ logger12.error(
1971
2196
  `Failed to clear cache for namespace: ${namespace_collection}`,
1972
2197
  err
1973
2198
  );
@@ -1983,7 +2208,7 @@ function useUnitRepository() {
1983
2208
  }
1984
2209
  async function deleteUnit(_id, session) {
1985
2210
  try {
1986
- _id = new ObjectId6(_id);
2211
+ _id = new ObjectId8(_id);
1987
2212
  } catch (error) {
1988
2213
  throw new BadRequestError13("Invalid unit ID format.");
1989
2214
  }
@@ -2002,9 +2227,9 @@ function useUnitRepository() {
2002
2227
  throw new InternalServerError4("Unable to delete unit.");
2003
2228
  }
2004
2229
  delNamespace().then(() => {
2005
- logger11.info(`Cache cleared for namespace: ${namespace_collection}`);
2230
+ logger12.info(`Cache cleared for namespace: ${namespace_collection}`);
2006
2231
  }).catch((err) => {
2007
- logger11.error(
2232
+ logger12.error(
2008
2233
  `Failed to clear cache for namespace: ${namespace_collection}`,
2009
2234
  err
2010
2235
  );
@@ -2042,7 +2267,7 @@ function useUnitService() {
2042
2267
  throw new BadRequestError14("Invalid JSON format for data in excel");
2043
2268
  }
2044
2269
  if (!dataArray || dataArray.length === 0) {
2045
- throw new NotFoundError6("No data found in the uploaded file");
2270
+ throw new NotFoundError5("No data found in the uploaded file");
2046
2271
  }
2047
2272
  const session = useAtlas7.getClient()?.startSession();
2048
2273
  const insertedUnitIds = [];
@@ -2050,7 +2275,7 @@ function useUnitService() {
2050
2275
  session?.startTransaction();
2051
2276
  for (const row of dataArray) {
2052
2277
  if (!row?.UNIT_NAME) {
2053
- logger12.warn("Skipping row with missing UNIT_NAME:", row);
2278
+ logger13.warn("Skipping row with missing UNIT_NAME:", row);
2054
2279
  continue;
2055
2280
  }
2056
2281
  try {
@@ -2064,7 +2289,7 @@ function useUnitService() {
2064
2289
  );
2065
2290
  insertedUnitIds.push(insertedId);
2066
2291
  } catch (error) {
2067
- logger12.error(
2292
+ logger13.error(
2068
2293
  `Error creating unit "${row.UNIT_NAME}":`,
2069
2294
  error.message
2070
2295
  );
@@ -2072,13 +2297,13 @@ function useUnitService() {
2072
2297
  }
2073
2298
  }
2074
2299
  await session?.commitTransaction();
2075
- logger12.info(`Successfully uploaded ${insertedUnitIds.length} units`);
2300
+ logger13.info(`Successfully uploaded ${insertedUnitIds.length} units`);
2076
2301
  return {
2077
2302
  message: `Successfully uploaded ${insertedUnitIds.length} units`
2078
2303
  };
2079
2304
  } catch (error) {
2080
2305
  await session?.abortTransaction();
2081
- logger12.error("Error while uploading unit information", error);
2306
+ logger13.error("Error while uploading unit information", error);
2082
2307
  throw error;
2083
2308
  } finally {
2084
2309
  session?.endSession();
@@ -2090,7 +2315,7 @@ function useUnitService() {
2090
2315
  }
2091
2316
 
2092
2317
  // src/controllers/hygiene-unit.controller.ts
2093
- import { BadRequestError as BadRequestError15, logger as logger13 } from "@iservice365/node-server-utils";
2318
+ import { BadRequestError as BadRequestError15, logger as logger14 } from "@iservice365/node-server-utils";
2094
2319
  import Joi8 from "joi";
2095
2320
  function useUnitController() {
2096
2321
  const {
@@ -2109,7 +2334,7 @@ function useUnitController() {
2109
2334
  const payload = { ...req.body, createdBy };
2110
2335
  const { error } = unitSchema.validate(payload);
2111
2336
  if (error) {
2112
- logger13.log({ level: "error", message: error.message });
2337
+ logger14.log({ level: "error", message: error.message });
2113
2338
  next(new BadRequestError15(error.message));
2114
2339
  return;
2115
2340
  }
@@ -2118,7 +2343,7 @@ function useUnitController() {
2118
2343
  res.status(201).json({ message: "Unit created successfully.", id });
2119
2344
  return;
2120
2345
  } catch (error2) {
2121
- logger13.log({ level: "error", message: error2.message });
2346
+ logger14.log({ level: "error", message: error2.message });
2122
2347
  next(error2);
2123
2348
  return;
2124
2349
  }
@@ -2135,7 +2360,7 @@ function useUnitController() {
2135
2360
  });
2136
2361
  const { error } = validation.validate(query);
2137
2362
  if (error) {
2138
- logger13.log({ level: "error", message: error.message });
2363
+ logger14.log({ level: "error", message: error.message });
2139
2364
  next(new BadRequestError15(error.message));
2140
2365
  return;
2141
2366
  }
@@ -2157,7 +2382,7 @@ function useUnitController() {
2157
2382
  res.json(data);
2158
2383
  return;
2159
2384
  } catch (error2) {
2160
- logger13.log({ level: "error", message: error2.message });
2385
+ logger14.log({ level: "error", message: error2.message });
2161
2386
  next(error2);
2162
2387
  return;
2163
2388
  }
@@ -2170,7 +2395,7 @@ function useUnitController() {
2170
2395
  });
2171
2396
  const { error } = schema.validate(payload);
2172
2397
  if (error) {
2173
- logger13.log({ level: "error", message: error.message });
2398
+ logger14.log({ level: "error", message: error.message });
2174
2399
  next(new BadRequestError15(error.message));
2175
2400
  return;
2176
2401
  }
@@ -2180,7 +2405,7 @@ function useUnitController() {
2180
2405
  res.json({ message: "Unit updated successfully." });
2181
2406
  return;
2182
2407
  } catch (error2) {
2183
- logger13.log({ level: "error", message: error2.message });
2408
+ logger14.log({ level: "error", message: error2.message });
2184
2409
  next(error2);
2185
2410
  return;
2186
2411
  }
@@ -2192,7 +2417,7 @@ function useUnitController() {
2192
2417
  });
2193
2418
  const { error } = validation.validate({ id });
2194
2419
  if (error) {
2195
- logger13.log({ level: "error", message: error.message });
2420
+ logger14.log({ level: "error", message: error.message });
2196
2421
  next(new BadRequestError15(error.message));
2197
2422
  return;
2198
2423
  }
@@ -2201,7 +2426,7 @@ function useUnitController() {
2201
2426
  res.json({ message: "Unit deleted successfully." });
2202
2427
  return;
2203
2428
  } catch (error2) {
2204
- logger13.log({ level: "error", message: error2.message });
2429
+ logger14.log({ level: "error", message: error2.message });
2205
2430
  next(error2);
2206
2431
  return;
2207
2432
  }
@@ -2223,7 +2448,7 @@ function useUnitController() {
2223
2448
  });
2224
2449
  const { error } = schema.validate({ site, createdBy });
2225
2450
  if (error) {
2226
- logger13.log({ level: "error", message: error.message });
2451
+ logger14.log({ level: "error", message: error.message });
2227
2452
  next(new BadRequestError15(error.message));
2228
2453
  return;
2229
2454
  }
@@ -2233,7 +2458,7 @@ function useUnitController() {
2233
2458
  const result = await _uploadByFile({ dataJson, createdBy, site });
2234
2459
  return res.status(201).json(result);
2235
2460
  } catch (error2) {
2236
- logger13.log({ level: "error", message: error2.message });
2461
+ logger14.log({ level: "error", message: error2.message });
2237
2462
  next(error2);
2238
2463
  return;
2239
2464
  }
@@ -2250,7 +2475,7 @@ function useUnitController() {
2250
2475
  // src/models/hygiene-schedule-task-area.model.ts
2251
2476
  import { BadRequestError as BadRequestError16 } from "@iservice365/node-server-utils";
2252
2477
  import Joi9 from "joi";
2253
- import { ObjectId as ObjectId7 } from "mongodb";
2478
+ import { ObjectId as ObjectId9 } from "mongodb";
2254
2479
  var scheduleTaskAreaSchema = Joi9.object({
2255
2480
  name: Joi9.string().required(),
2256
2481
  site: Joi9.string().hex().required(),
@@ -2271,14 +2496,14 @@ function MScheduleTaskArea(value) {
2271
2496
  }
2272
2497
  if (value.site) {
2273
2498
  try {
2274
- value.site = new ObjectId7(value.site);
2499
+ value.site = new ObjectId9(value.site);
2275
2500
  } catch (error2) {
2276
2501
  throw new BadRequestError16("Invalid site ID format.");
2277
2502
  }
2278
2503
  }
2279
2504
  if (value.createdBy) {
2280
2505
  try {
2281
- value.createdBy = new ObjectId7(value.createdBy);
2506
+ value.createdBy = new ObjectId9(value.createdBy);
2282
2507
  } catch (error2) {
2283
2508
  throw new BadRequestError16("Invalid createdBy ID format.");
2284
2509
  }
@@ -2288,7 +2513,7 @@ function MScheduleTaskArea(value) {
2288
2513
  try {
2289
2514
  return {
2290
2515
  ...item,
2291
- _id: new ObjectId7(item._id)
2516
+ _id: new ObjectId9(item._id)
2292
2517
  };
2293
2518
  } catch (error2) {
2294
2519
  throw new BadRequestError16(
@@ -2310,14 +2535,15 @@ function MScheduleTaskArea(value) {
2310
2535
  }
2311
2536
 
2312
2537
  // src/repositories/hygiene-schedule-task-area.repository.ts
2313
- import { ObjectId as ObjectId8 } from "mongodb";
2538
+ import { ObjectId as ObjectId10 } from "mongodb";
2314
2539
  import {
2315
2540
  useAtlas as useAtlas8,
2316
2541
  InternalServerError as InternalServerError5,
2317
2542
  paginate as paginate5,
2318
2543
  BadRequestError as BadRequestError17,
2544
+ NotFoundError as NotFoundError6,
2319
2545
  useCache as useCache5,
2320
- logger as logger14,
2546
+ logger as logger15,
2321
2547
  makeCacheKey as makeCacheKey5
2322
2548
  } from "@iservice365/node-server-utils";
2323
2549
  function useScheduleTaskAreaRepository() {
@@ -2338,51 +2564,71 @@ function useScheduleTaskAreaRepository() {
2338
2564
  throw new InternalServerError5("Failed to create index on site.");
2339
2565
  }
2340
2566
  }
2567
+ async function createUniqueIndex() {
2568
+ try {
2569
+ await collection.createIndex(
2570
+ { name: 1, site: 1, deletedAt: 1 },
2571
+ { unique: true }
2572
+ );
2573
+ } catch (error) {
2574
+ throw new InternalServerError5(
2575
+ "Failed to create unique index on hygiene area."
2576
+ );
2577
+ }
2578
+ }
2341
2579
  async function createScheduleTaskArea(value, session) {
2342
2580
  try {
2343
2581
  value = MScheduleTaskArea(value);
2344
2582
  const res = await collection.insertOne(value, { session });
2345
2583
  delNamespace().then(() => {
2346
- logger14.info(`Cache cleared for namespace: ${namespace_collection}`);
2584
+ logger15.info(`Cache cleared for namespace: ${namespace_collection}`);
2347
2585
  }).catch((err) => {
2348
- logger14.error(
2586
+ logger15.error(
2349
2587
  `Failed to clear cache for namespace: ${namespace_collection}`,
2350
2588
  err
2351
2589
  );
2352
2590
  });
2353
2591
  return res.insertedId;
2354
2592
  } catch (error) {
2593
+ const isDuplicated = error.message.includes("duplicate");
2594
+ if (isDuplicated) {
2595
+ throw new BadRequestError17("Area already exists.");
2596
+ }
2355
2597
  throw error;
2356
2598
  }
2357
2599
  }
2358
2600
  async function updateScheduleTaskArea(_id, params) {
2359
2601
  try {
2360
- _id = new ObjectId8(_id);
2602
+ _id = new ObjectId10(_id);
2361
2603
  } catch (error) {
2362
2604
  throw new BadRequestError17("Invalid area ID format.");
2363
2605
  }
2364
2606
  try {
2365
- const value = MScheduleTaskArea({ ...params, updatedAt: /* @__PURE__ */ new Date() });
2366
- const res = await collection.updateOne({ _id }, { $set: value });
2607
+ const updateValue = { ...params, updatedAt: /* @__PURE__ */ new Date() };
2608
+ const res = await collection.updateOne({ _id }, { $set: updateValue });
2367
2609
  if (res.modifiedCount === 0) {
2368
2610
  throw new InternalServerError5("Unable to update cleaning area.");
2369
2611
  }
2370
2612
  delNamespace().then(() => {
2371
- logger14.info(`Cache cleared for namespace: ${namespace_collection}`);
2613
+ logger15.info(`Cache cleared for namespace: ${namespace_collection}`);
2372
2614
  }).catch((err) => {
2373
- logger14.error(
2615
+ logger15.error(
2374
2616
  `Failed to clear cache for namespace: ${namespace_collection}`,
2375
2617
  err
2376
2618
  );
2377
2619
  });
2378
2620
  return res.modifiedCount;
2379
2621
  } catch (error) {
2622
+ const isDuplicated = error.message.includes("duplicate");
2623
+ if (isDuplicated) {
2624
+ throw new BadRequestError17("Area already exists.");
2625
+ }
2380
2626
  throw error;
2381
2627
  }
2382
2628
  }
2383
2629
  async function deleteScheduleTaskArea(_id, session) {
2384
2630
  try {
2385
- _id = new ObjectId8(_id);
2631
+ _id = new ObjectId10(_id);
2386
2632
  } catch (error) {
2387
2633
  throw new BadRequestError17("Invalid area ID format.");
2388
2634
  }
@@ -2397,13 +2643,16 @@ function useScheduleTaskAreaRepository() {
2397
2643
  { $set: updateValue },
2398
2644
  { session }
2399
2645
  );
2400
- if (res.modifiedCount === 0)
2646
+ if (res.modifiedCount === 0) {
2401
2647
  throw new InternalServerError5("Unable to delete area.");
2402
- const cacheKey = makeCacheKey5(namespace_collection, { _id });
2403
- delCache(cacheKey).then(() => {
2404
- logger14.info(`Cache deleted for key: ${cacheKey}`);
2648
+ }
2649
+ delNamespace().then(() => {
2650
+ logger15.info(`Cache cleared for namespace: ${namespace_collection}`);
2405
2651
  }).catch((err) => {
2406
- logger14.error(`Failed to delete cache for key: ${cacheKey}`, err);
2652
+ logger15.error(
2653
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2654
+ err
2655
+ );
2407
2656
  });
2408
2657
  return res.modifiedCount;
2409
2658
  } catch (error) {
@@ -2414,63 +2663,54 @@ function useScheduleTaskAreaRepository() {
2414
2663
  page = 1,
2415
2664
  limit = 10,
2416
2665
  search = "",
2417
- sort = {},
2418
2666
  startDate = "",
2419
2667
  endDate = "",
2420
2668
  site = ""
2421
2669
  }) {
2422
2670
  page = page > 0 ? page - 1 : 0;
2423
- let dateFilter = {};
2424
- try {
2425
- site = new ObjectId8(site);
2426
- } catch (error) {
2427
- throw new BadRequestError17("Invalid site ID format.");
2428
- }
2429
2671
  const query = {
2430
2672
  status: { $ne: "deleted" }
2431
2673
  };
2432
2674
  const cacheOptions = {
2433
- site: site.toString()
2675
+ page,
2676
+ limit
2434
2677
  };
2435
- sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
2436
- cacheOptions.sort = JSON.stringify(sort);
2678
+ if (site) {
2679
+ try {
2680
+ site = new ObjectId10(site);
2681
+ cacheOptions.site = site.toString();
2682
+ } catch (error) {
2683
+ throw new BadRequestError17("Invalid site ID format.");
2684
+ }
2685
+ }
2437
2686
  if (search) {
2438
2687
  query.$or = [{ name: { $regex: search, $options: "i" } }];
2439
2688
  cacheOptions.search = search;
2440
2689
  }
2441
- delNamespace().then(() => {
2442
- logger14.info(`Cache cleared for namespace: ${namespace_collection}`);
2443
- }).catch((err) => {
2444
- logger14.error(
2445
- `Failed to clear cache for namespace: ${namespace_collection}`,
2446
- err
2447
- );
2448
- });
2449
- const cacheKey = makeCacheKey5(namespace_collection, cacheOptions);
2450
- const cachedData = await getCache(cacheKey);
2451
- if (cachedData) {
2452
- logger14.info(`Cache hit for key: ${cacheKey}`);
2453
- return cachedData;
2454
- }
2455
2690
  if (startDate && endDate) {
2456
- dateFilter = {
2457
- createdAt: {
2458
- $gte: new Date(startDate),
2459
- $lte: new Date(endDate)
2460
- }
2461
- };
2462
- } else if (startDate) {
2463
- dateFilter = { createdAt: { $gte: new Date(startDate) } };
2691
+ query.createdAt = {
2692
+ $gte: new Date(startDate),
2693
+ $lte: new Date(endDate)
2694
+ };
2695
+ cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
2696
+ cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
2697
+ } else if (startDate) {
2698
+ query.createdAt = { $gte: new Date(startDate) };
2699
+ cacheOptions.startDate = new Date(startDate).toISOString().split("T")[0];
2464
2700
  } else if (endDate) {
2465
- dateFilter = { createdAt: { $lte: new Date(endDate) } };
2701
+ query.createdAt = { $lte: new Date(endDate) };
2702
+ cacheOptions.endDate = new Date(endDate).toISOString().split("T")[0];
2703
+ }
2704
+ const cacheKey = makeCacheKey5(namespace_collection, cacheOptions);
2705
+ const cachedData = await getCache(cacheKey);
2706
+ if (cachedData) {
2707
+ logger15.info(`Cache hit for key: ${cacheKey}`);
2708
+ return cachedData;
2466
2709
  }
2467
2710
  try {
2468
2711
  const items = await collection.aggregate([
2469
2712
  {
2470
- $match: {
2471
- ...dateFilter,
2472
- ...query
2473
- }
2713
+ $match: query
2474
2714
  },
2475
2715
  {
2476
2716
  $lookup: {
@@ -2503,22 +2743,26 @@ function useScheduleTaskAreaRepository() {
2503
2743
  }
2504
2744
  },
2505
2745
  {
2506
- $facet: {
2507
- totalCount: [{ $count: "count" }],
2508
- items: [
2509
- { $sort: { createdAt: -1 } },
2510
- { $skip: page * limit },
2511
- { $limit: limit }
2512
- ]
2746
+ $project: {
2747
+ name: 1,
2748
+ site: "$site._id",
2749
+ siteName: "$site.name",
2750
+ createdByName: "$createdBy.name",
2751
+ checklist: 1,
2752
+ status: 1,
2753
+ createdAt: 1
2513
2754
  }
2514
- }
2755
+ },
2756
+ { $sort: { _id: -1 } },
2757
+ { $skip: page * limit },
2758
+ { $limit: limit }
2515
2759
  ]).toArray();
2516
2760
  const length = await collection.countDocuments(query);
2517
2761
  const data = paginate5(items, page, limit, length);
2518
2762
  setCache(cacheKey, data, 15 * 60).then(() => {
2519
- logger14.info(`Cache set for key: ${cacheKey}`);
2763
+ logger15.info(`Cache set for key: ${cacheKey}`);
2520
2764
  }).catch((err) => {
2521
- logger14.error(`Failed to set cache for key: ${cacheKey}`, err);
2765
+ logger15.error(`Failed to set cache for key: ${cacheKey}`, err);
2522
2766
  });
2523
2767
  return data;
2524
2768
  } catch (error) {
@@ -2528,7 +2772,7 @@ function useScheduleTaskAreaRepository() {
2528
2772
  async function getScheduleTaskAreaByName(name, site) {
2529
2773
  try {
2530
2774
  if (site)
2531
- site = new ObjectId8(site);
2775
+ site = new ObjectId10(site);
2532
2776
  } catch (error) {
2533
2777
  throw new BadRequestError17("Invalid site ID format.");
2534
2778
  }
@@ -2543,13 +2787,13 @@ function useScheduleTaskAreaRepository() {
2543
2787
  }
2544
2788
  async function getScheduleTaskAreaById(id, site) {
2545
2789
  try {
2546
- id = typeof id === "string" ? new ObjectId8(id) : id;
2790
+ id = typeof id === "string" ? new ObjectId10(id) : id;
2547
2791
  } catch (error) {
2548
2792
  throw new BadRequestError17("Invalid unit ID format.");
2549
2793
  }
2550
2794
  try {
2551
2795
  if (site)
2552
- site = new ObjectId8(site);
2796
+ site = new ObjectId10(site);
2553
2797
  } catch (error) {
2554
2798
  throw new BadRequestError17(
2555
2799
  "Unable to fetch schedule task area by ID, Invalid site ID format."
@@ -2561,84 +2805,148 @@ function useScheduleTaskAreaRepository() {
2561
2805
  throw new BadRequestError17("Unable to fetch schedule task area by id.");
2562
2806
  }
2563
2807
  }
2808
+ async function getAreaById(_id) {
2809
+ try {
2810
+ _id = new ObjectId10(_id);
2811
+ } catch (error) {
2812
+ throw new BadRequestError17("Invalid area ID format.");
2813
+ }
2814
+ const query = {
2815
+ _id,
2816
+ status: { $ne: "deleted" }
2817
+ };
2818
+ const cacheKey = makeCacheKey5(namespace_collection, {
2819
+ _id: _id.toString()
2820
+ });
2821
+ const cachedData = await getCache(cacheKey);
2822
+ if (cachedData) {
2823
+ logger15.info(`Cache hit for key: ${cacheKey}`);
2824
+ return cachedData;
2825
+ }
2826
+ try {
2827
+ const data = await collection.aggregate([
2828
+ { $match: query },
2829
+ {
2830
+ $project: {
2831
+ name: 1,
2832
+ checklist: 1
2833
+ }
2834
+ }
2835
+ ]).toArray();
2836
+ if (!data || !data.length) {
2837
+ throw new NotFoundError6("Area not found.");
2838
+ }
2839
+ setCache(cacheKey, data[0], 15 * 60).then(() => {
2840
+ logger15.info(`Cache set for key: ${cacheKey}`);
2841
+ }).catch((err) => {
2842
+ logger15.error(`Failed to set cache for key: ${cacheKey}`, err);
2843
+ });
2844
+ return data[0];
2845
+ } catch (error) {
2846
+ throw error;
2847
+ }
2848
+ }
2564
2849
  return {
2850
+ createUniqueIndex,
2565
2851
  createScheduleTaskArea,
2566
2852
  updateScheduleTaskArea,
2567
2853
  deleteScheduleTaskArea,
2568
2854
  getScheduleTaskAreas,
2569
2855
  createIndexes,
2570
2856
  getScheduleTaskAreaByName,
2571
- getScheduleTaskAreaById
2857
+ getScheduleTaskAreaById,
2858
+ getAreaById
2572
2859
  };
2573
2860
  }
2574
2861
 
2575
2862
  // src/services/hygiene-schedule-task-area.service.ts
2576
2863
  import {
2577
- InternalServerError as InternalServerError6
2864
+ BadRequestError as BadRequestError18,
2865
+ logger as logger16,
2866
+ NotFoundError as NotFoundError7,
2867
+ useAtlas as useAtlas9
2578
2868
  } from "@iservice365/node-server-utils";
2579
2869
  function useScheduleTaskAreaService() {
2580
- const {
2581
- getScheduleTaskAreas: _getAll,
2582
- createScheduleTaskArea: _create,
2583
- updateScheduleTaskArea: _updateById,
2584
- deleteScheduleTaskArea: _deleteById,
2585
- getScheduleTaskAreaByName: _getScheduleTaskAreaByName,
2586
- getScheduleTaskAreaById: _getScheduleTaskAreaById
2587
- } = useScheduleTaskAreaRepository();
2588
- async function getAll(query) {
2589
- return await _getAll(query);
2590
- }
2591
- async function create(scheduleTaskArea) {
2592
- const result = await _getScheduleTaskAreaByName(
2593
- scheduleTaskArea.name,
2594
- scheduleTaskArea.site
2595
- );
2596
- if (result)
2597
- throw new InternalServerError6(
2598
- "Schedule Task Area name already exists in this site."
2599
- );
2600
- return await _create(scheduleTaskArea);
2601
- }
2602
- async function updateById(id, scheduleTaskArea) {
2603
- const result = await _getScheduleTaskAreaByName(
2604
- scheduleTaskArea.name,
2605
- scheduleTaskArea.site
2606
- );
2607
- const resultId = result?._id.toString() ?? "";
2608
- if (result && id != resultId) {
2609
- throw new InternalServerError6(
2610
- "Schedule Task Area name already exists in this site."
2611
- );
2870
+ const { createScheduleTaskArea: _create } = useScheduleTaskAreaRepository();
2871
+ async function uploadByFile({
2872
+ dataJson,
2873
+ createdBy,
2874
+ site
2875
+ }) {
2876
+ let dataArray;
2877
+ try {
2878
+ dataArray = JSON.parse(dataJson);
2879
+ } catch (error) {
2880
+ throw new BadRequestError18("Invalid JSON format for data in excel");
2881
+ }
2882
+ if (!dataArray || dataArray.length === 0) {
2883
+ throw new NotFoundError7("No data found in the uploaded file");
2884
+ }
2885
+ const session = useAtlas9.getClient()?.startSession();
2886
+ const insertedAreaIds = [];
2887
+ try {
2888
+ session?.startTransaction();
2889
+ for (const row of dataArray) {
2890
+ if (!row?.AREA_NAME) {
2891
+ logger16.warn("Skipping row with missing AREA_NAME:", row);
2892
+ continue;
2893
+ }
2894
+ try {
2895
+ const insertedId = await _create(
2896
+ {
2897
+ name: String(row.AREA_NAME).trim(),
2898
+ site,
2899
+ createdBy
2900
+ },
2901
+ session
2902
+ );
2903
+ insertedAreaIds.push(insertedId);
2904
+ } catch (error) {
2905
+ logger16.error(
2906
+ `Error creating area "${row.AREA_NAME}":`,
2907
+ error.message
2908
+ );
2909
+ continue;
2910
+ }
2911
+ }
2912
+ await session?.commitTransaction();
2913
+ logger16.info(`Successfully uploaded ${insertedAreaIds.length} areas`);
2914
+ return {
2915
+ message: `Successfully uploaded ${insertedAreaIds.length} areas`
2916
+ };
2917
+ } catch (error) {
2918
+ await session?.abortTransaction();
2919
+ logger16.error("Error while uploading area information", error);
2920
+ throw error;
2921
+ } finally {
2922
+ session?.endSession();
2612
2923
  }
2613
- return await _updateById(id, scheduleTaskArea);
2614
- }
2615
- async function deleteById(id) {
2616
- return await _deleteById(id);
2617
2924
  }
2618
2925
  return {
2619
- getAll,
2620
- create,
2621
- updateById,
2622
- deleteById
2926
+ uploadByFile
2623
2927
  };
2624
2928
  }
2625
2929
 
2626
2930
  // src/controllers/hygiene-schedule-task-area.controller.ts
2627
- import { BadRequestError as BadRequestError19, logger as logger16 } from "@iservice365/node-server-utils";
2931
+ import { BadRequestError as BadRequestError19, logger as logger17 } from "@iservice365/node-server-utils";
2628
2932
  import Joi10 from "joi";
2629
2933
  function useScheduleTaskAreaController() {
2934
+ const { uploadByFile: _uploadByFile } = useScheduleTaskAreaService();
2630
2935
  const {
2631
- getAll: _getAll,
2632
- create: _createScheduleTaskArea,
2633
- updateById: _updateScheduleTaskArea,
2634
- deleteById: _deleteById
2635
- } = useScheduleTaskAreaService();
2936
+ getScheduleTaskAreas: _getAll,
2937
+ createScheduleTaskArea: _createScheduleTaskArea,
2938
+ updateScheduleTaskArea: _updateScheduleTaskArea,
2939
+ deleteScheduleTaskArea: _deleteById,
2940
+ getAreaById: _getAreaById
2941
+ } = useScheduleTaskAreaRepository();
2636
2942
  async function getAll(req, res, next) {
2637
2943
  const query = req.query;
2638
2944
  const validation = Joi10.object({
2639
2945
  page: Joi10.number().min(1).optional().allow("", null),
2640
2946
  limit: Joi10.number().min(1).optional().allow("", null),
2641
2947
  search: Joi10.string().optional().allow("", null),
2948
+ startDate: Joi10.alternatives().try(Joi10.date(), Joi10.string()).optional().allow("", null),
2949
+ endDate: Joi10.alternatives().try(Joi10.date(), Joi10.string()).optional().allow("", null),
2642
2950
  site: Joi10.string().hex().optional().allow("", null)
2643
2951
  });
2644
2952
  const { error } = validation.validate(query);
@@ -2647,84 +2955,71 @@ function useScheduleTaskAreaController() {
2647
2955
  return;
2648
2956
  }
2649
2957
  const page = parseInt(req.query.page) ?? 1;
2650
- let limit = parseInt(req.query.limit) ?? 20;
2651
- limit = isNaN(limit) ? 20 : limit;
2652
- const sort = req.query.sort ? String(req.query.sort).split(",") : "";
2653
- const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
2654
- const sortObj = {};
2655
- if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
2656
- sort.forEach((field, index) => {
2657
- sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
2658
- });
2659
- }
2660
- const site = req.query.site ?? "";
2958
+ const limit = parseInt(req.query.limit) ?? 20;
2661
2959
  const search = req.query.search ?? "";
2960
+ const site = req.query.site ?? "";
2961
+ const startDate = req.query.startDate ?? "";
2962
+ const endDate = req.query.endDate ?? "";
2662
2963
  try {
2663
- const scheduleTaskAreas = await _getAll({
2964
+ const data = await _getAll({
2664
2965
  page,
2665
2966
  limit,
2666
- sort: sortObj,
2967
+ search,
2667
2968
  site,
2668
- search
2969
+ startDate,
2970
+ endDate
2669
2971
  });
2670
- res.json(scheduleTaskAreas);
2972
+ res.json(data);
2671
2973
  return;
2672
2974
  } catch (error2) {
2673
2975
  next(error2);
2976
+ return;
2674
2977
  }
2675
2978
  }
2676
2979
  async function createScheduleTaskArea(req, res, next) {
2677
- const value = req.body;
2678
- const schema = Joi10.object({
2679
- name: Joi10.string().required(),
2680
- site: Joi10.string().hex().optional().allow("", null),
2681
- createdBy: Joi10.string().hex().optional().allow("", null)
2682
- });
2683
- const { error } = schema.validate(value);
2980
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
2981
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
2982
+ {}
2983
+ ) : {};
2984
+ const createdBy = cookies["user"] || "";
2985
+ const payload = { ...req.body, createdBy };
2986
+ const { error } = scheduleTaskAreaSchema.validate(payload);
2684
2987
  if (error) {
2988
+ logger17.log({ level: "error", message: error.message });
2685
2989
  next(new BadRequestError19(error.message));
2686
- logger16.info(`Controller: ${error.message}`);
2687
2990
  return;
2688
2991
  }
2689
2992
  try {
2690
- const result = await _createScheduleTaskArea(value);
2691
- res.status(201).json(result);
2993
+ const id = await _createScheduleTaskArea(payload);
2994
+ res.status(201).json({ message: "Area created successfully.", id });
2692
2995
  return;
2693
2996
  } catch (error2) {
2997
+ logger17.log({ level: "error", message: error2.message });
2694
2998
  next(error2);
2999
+ return;
2695
3000
  }
2696
3001
  }
2697
3002
  async function updateScheduleTaskArea(req, res, next) {
2698
- const { name, site, createdBy } = req.body;
2699
- const id = req.params.id;
3003
+ const payload = { id: req.params.id, ...req.body };
2700
3004
  const schema = Joi10.object({
2701
3005
  id: Joi10.string().hex().required(),
2702
- name: Joi10.string().required(),
2703
- site: Joi10.string().required(),
2704
- checklist: Joi10.array().optional().items(
2705
- Joi10.object({
2706
- _id: Joi10.string().optional().required(),
2707
- name: Joi10.string().optional().required()
2708
- })
2709
- ),
2710
- createdBy: Joi10.string().hex().optional().allow("", null)
3006
+ name: Joi10.string().required()
2711
3007
  });
2712
- const { error } = schema.validate({ id, name, createdBy, site });
3008
+ const { error } = schema.validate(payload);
2713
3009
  if (error) {
2714
3010
  next(new BadRequestError19(error.message));
2715
- logger16.info(`Controller: ${error.message}`);
3011
+ logger17.info(`Controller: ${error.message}`);
2716
3012
  return;
2717
3013
  }
2718
3014
  try {
2719
- const result = await _updateScheduleTaskArea(id, {
2720
- name,
2721
- createdBy,
2722
- site
2723
- });
2724
- res.json(result);
3015
+ const { id, ...value } = payload;
3016
+ await _updateScheduleTaskArea(id, value);
3017
+ res.json({ message: "Area updated successfully." });
2725
3018
  return;
2726
3019
  } catch (error2) {
3020
+ logger17.log({ level: "error", message: error2.message });
2727
3021
  next(error2);
3022
+ return;
2728
3023
  }
2729
3024
  }
2730
3025
  async function deleteScheduleTaskArea(req, res, next) {
@@ -2734,39 +3029,1655 @@ function useScheduleTaskAreaController() {
2734
3029
  });
2735
3030
  const { error } = validation.validate({ id });
2736
3031
  if (error) {
3032
+ logger17.log({ level: "error", message: error.message });
2737
3033
  next(new BadRequestError19(error.message));
2738
3034
  return;
2739
3035
  }
2740
3036
  try {
2741
- const message = await _deleteById(id);
2742
- res.json(message);
3037
+ await _deleteById(id);
3038
+ res.json({ message: "Area deleted successfully." });
3039
+ return;
3040
+ } catch (error2) {
3041
+ logger17.log({ level: "error", message: error2.message });
3042
+ next(error2);
3043
+ return;
3044
+ }
3045
+ }
3046
+ async function uploadByFile(req, res, next) {
3047
+ if (!req.file) {
3048
+ next(new BadRequestError19("File is required!"));
3049
+ return;
3050
+ }
3051
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3052
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3053
+ {}
3054
+ ) : {};
3055
+ const createdBy = cookies["user"] || "";
3056
+ const { site } = req.body;
3057
+ const schema = Joi10.object({
3058
+ site: Joi10.string().hex().optional().allow("", null),
3059
+ createdBy: Joi10.string().hex().required()
3060
+ });
3061
+ const { error } = schema.validate({ site, createdBy });
3062
+ if (error) {
3063
+ logger17.log({ level: "error", message: error.message });
3064
+ next(new BadRequestError19(error.message));
3065
+ return;
3066
+ }
3067
+ try {
3068
+ const xlsData = await convertBufferFile(req.file.buffer);
3069
+ const dataJson = JSON.stringify(xlsData);
3070
+ const result = await _uploadByFile({ dataJson, createdBy, site });
3071
+ return res.status(201).json(result);
3072
+ } catch (error2) {
3073
+ logger17.log({ level: "error", message: error2.message });
3074
+ next(error2);
3075
+ return;
3076
+ }
3077
+ }
3078
+ async function getAreaById(req, res, next) {
3079
+ const validation = Joi10.string().hex().required();
3080
+ const _id = req.params.id;
3081
+ const { error } = validation.validate(_id);
3082
+ if (error) {
3083
+ logger17.log({ level: "error", message: error.message });
3084
+ next(new BadRequestError19(error.message));
3085
+ return;
3086
+ }
3087
+ try {
3088
+ const data = await _getAreaById(_id);
3089
+ res.json(data);
2743
3090
  return;
2744
3091
  } catch (error2) {
3092
+ logger17.log({ level: "error", message: error2.message });
2745
3093
  next(error2);
3094
+ return;
2746
3095
  }
2747
3096
  }
2748
3097
  return {
2749
3098
  getAll,
3099
+ getAreaById,
2750
3100
  createScheduleTaskArea,
2751
3101
  updateScheduleTaskArea,
2752
- deleteScheduleTaskArea
3102
+ deleteScheduleTaskArea,
3103
+ uploadByFile
3104
+ };
3105
+ }
3106
+
3107
+ // src/models/hygiene-area-checklist.model.ts
3108
+ import { BadRequestError as BadRequestError20, logger as logger18 } from "@iservice365/node-server-utils";
3109
+ import Joi11 from "joi";
3110
+ import { ObjectId as ObjectId11 } from "mongodb";
3111
+ var areaChecklistSchema = Joi11.object({
3112
+ type: Joi11.string().required().valid(...allowedTypes),
3113
+ site: Joi11.string().hex().required(),
3114
+ parentChecklist: Joi11.string().hex().required(),
3115
+ area: Joi11.string().hex().required(),
3116
+ name: Joi11.string().optional().allow("", null),
3117
+ createdBy: Joi11.string().hex().optional().allow("", null)
3118
+ });
3119
+ function MAreaChecklist(value) {
3120
+ const { error } = areaChecklistSchema.validate(value);
3121
+ if (error) {
3122
+ logger18.info(`Hygiene Checklist Area Model: ${error.message}`);
3123
+ throw new BadRequestError20(error.message);
3124
+ }
3125
+ if (value.site) {
3126
+ try {
3127
+ value.site = new ObjectId11(value.site);
3128
+ } catch (error2) {
3129
+ throw new BadRequestError20("Invalid site ID format.");
3130
+ }
3131
+ }
3132
+ if (value.parentChecklist) {
3133
+ try {
3134
+ value.parentChecklist = new ObjectId11(value.parentChecklist);
3135
+ } catch (error2) {
3136
+ throw new BadRequestError20("Invalid checklist ID format.");
3137
+ }
3138
+ }
3139
+ if (value.area) {
3140
+ try {
3141
+ value.area = new ObjectId11(value.area);
3142
+ } catch (error2) {
3143
+ throw new BadRequestError20("Invalid area ID format.");
3144
+ }
3145
+ }
3146
+ if (value.createdBy) {
3147
+ try {
3148
+ value.createdBy = new ObjectId11(value.createdBy);
3149
+ } catch (error2) {
3150
+ throw new BadRequestError20("Invalid createdBy ID format.");
3151
+ }
3152
+ }
3153
+ if (value.acceptedBy) {
3154
+ try {
3155
+ value.acceptedBy = new ObjectId11(value.acceptedBy);
3156
+ } catch (error2) {
3157
+ throw new BadRequestError20("Invalid acceptedBy ID format.");
3158
+ }
3159
+ }
3160
+ return {
3161
+ type: value.type,
3162
+ site: value.site,
3163
+ parentChecklist: value.parentChecklist,
3164
+ area: value.area,
3165
+ name: value.name ?? "",
3166
+ status: value.status ?? "To Do",
3167
+ createdBy: value.createdBy ?? "",
3168
+ createdAt: /* @__PURE__ */ new Date(),
3169
+ acceptedBy: value.acceptedBy ?? "",
3170
+ acceptedAt: value.acceptedAt ?? "",
3171
+ startedAt: value.startedAt ?? "",
3172
+ endedAt: value.endedAt ?? "",
3173
+ signature: value.signature ?? "",
3174
+ updatedAt: value.updatedAt ?? ""
3175
+ };
3176
+ }
3177
+
3178
+ // src/repositories/hygiene-area-checklist.repository.ts
3179
+ import {
3180
+ BadRequestError as BadRequestError21,
3181
+ InternalServerError as InternalServerError7,
3182
+ logger as logger19,
3183
+ makeCacheKey as makeCacheKey6,
3184
+ paginate as paginate6,
3185
+ useAtlas as useAtlas10,
3186
+ useCache as useCache6
3187
+ } from "@iservice365/node-server-utils";
3188
+ import { ObjectId as ObjectId12 } from "mongodb";
3189
+ function useAreaChecklistRepo() {
3190
+ const db = useAtlas10.getDb();
3191
+ if (!db) {
3192
+ throw new InternalServerError7("Unable to connect to server.");
3193
+ }
3194
+ const namespace_collection = "hygiene-checklist.areas";
3195
+ const unit_checklist_collection = "hygiene-checklist.units";
3196
+ const collection = db.collection(namespace_collection);
3197
+ const unitChecklistCollection = db.collection(unit_checklist_collection);
3198
+ const { delNamespace, setCache, getCache } = useCache6(namespace_collection);
3199
+ const { delNamespace: delUnitNamespace } = useCache6(
3200
+ unit_checklist_collection
3201
+ );
3202
+ async function createIndex() {
3203
+ try {
3204
+ await collection.createIndexes([
3205
+ { key: { type: 1 } },
3206
+ { key: { site: 1 } },
3207
+ { key: { parentChecklist: 1 } },
3208
+ { key: { area: 1 } },
3209
+ { key: { createdAt: 1 } },
3210
+ { key: { acceptedBy: 1 } }
3211
+ ]);
3212
+ } catch (error) {
3213
+ throw new InternalServerError7(
3214
+ "Failed to create index on hygiene checklist area."
3215
+ );
3216
+ }
3217
+ }
3218
+ async function createTextIndex() {
3219
+ try {
3220
+ await collection.createIndex({ name: "text" });
3221
+ } catch (error) {
3222
+ throw new InternalServerError7(
3223
+ "Failed to create text index on hygiene checklist area."
3224
+ );
3225
+ }
3226
+ }
3227
+ async function createAreaChecklist(value, session) {
3228
+ try {
3229
+ const siteId = new ObjectId12(value.site);
3230
+ const parentChecklistId = new ObjectId12(value.parentChecklist);
3231
+ const areaId = new ObjectId12(value.area);
3232
+ const currentDate = /* @__PURE__ */ new Date();
3233
+ const startOfDay = new Date(currentDate);
3234
+ startOfDay.setUTCHours(0, 0, 0, 0);
3235
+ const endOfDay = new Date(currentDate);
3236
+ endOfDay.setUTCHours(23, 59, 59, 999);
3237
+ const existingChecklist = await collection.findOne({
3238
+ type: value.type,
3239
+ site: siteId,
3240
+ parentChecklist: parentChecklistId,
3241
+ area: areaId,
3242
+ createdAt: {
3243
+ $gte: startOfDay,
3244
+ $lte: endOfDay
3245
+ }
3246
+ });
3247
+ if (existingChecklist) {
3248
+ logger19.info(
3249
+ `Area checklist already exists for area ${areaId} on ${currentDate.toISOString().split("T")[0]}`
3250
+ );
3251
+ return existingChecklist._id;
3252
+ }
3253
+ const processedValue = MAreaChecklist(value);
3254
+ const result = await collection.insertOne(processedValue, { session });
3255
+ delNamespace().then(() => {
3256
+ logger19.info(`Cache cleared for namespace: ${namespace_collection}`);
3257
+ }).catch((err) => {
3258
+ logger19.error(
3259
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3260
+ err
3261
+ );
3262
+ });
3263
+ return result.insertedId;
3264
+ } catch (error) {
3265
+ throw error;
3266
+ }
3267
+ }
3268
+ async function getAllAreaChecklist({
3269
+ page = 1,
3270
+ limit = 10,
3271
+ search = "",
3272
+ site,
3273
+ type,
3274
+ parentChecklist
3275
+ }) {
3276
+ page = page > 0 ? page - 1 : 0;
3277
+ const query = { type };
3278
+ const cacheOptions = {
3279
+ page,
3280
+ limit
3281
+ };
3282
+ try {
3283
+ query.site = new ObjectId12(site);
3284
+ cacheOptions.site = site.toString();
3285
+ } catch (error) {
3286
+ throw new BadRequestError21("Invalid site ID format.");
3287
+ }
3288
+ try {
3289
+ query.parentChecklist = new ObjectId12(parentChecklist);
3290
+ cacheOptions.parentChecklist = parentChecklist.toString();
3291
+ } catch (error) {
3292
+ throw new BadRequestError21("Invalid parent checklist ID format.");
3293
+ }
3294
+ if (search) {
3295
+ query.$text = { $search: search };
3296
+ cacheOptions.search = search;
3297
+ }
3298
+ const cacheKey = makeCacheKey6(namespace_collection, cacheOptions);
3299
+ const cachedData = await getCache(cacheKey);
3300
+ if (cachedData) {
3301
+ logger19.info(`Cache hit for key: ${cacheKey}`);
3302
+ return cachedData;
3303
+ }
3304
+ try {
3305
+ const pipeline = [
3306
+ { $match: query },
3307
+ {
3308
+ $lookup: {
3309
+ from: "users",
3310
+ localField: "acceptedBy",
3311
+ foreignField: "_id",
3312
+ pipeline: [{ $project: { name: 1 } }],
3313
+ as: "acceptedBy"
3314
+ }
3315
+ },
3316
+ {
3317
+ $unwind: {
3318
+ path: "$acceptedBy",
3319
+ preserveNullAndEmptyArrays: true
3320
+ }
3321
+ },
3322
+ {
3323
+ $project: {
3324
+ name: 1,
3325
+ acceptedByName: "$acceptedBy.name",
3326
+ status: 1,
3327
+ createdAt: 1
3328
+ }
3329
+ },
3330
+ { $sort: { _id: -1 } },
3331
+ { $skip: page * limit },
3332
+ { $limit: limit }
3333
+ ];
3334
+ const items = await collection.aggregate(pipeline).toArray();
3335
+ const length = await collection.countDocuments(query);
3336
+ const data = paginate6(items, page, limit, length);
3337
+ setCache(cacheKey, data, 15 * 60).then(() => {
3338
+ logger19.info(`Cache set for key: ${cacheKey}`);
3339
+ }).catch((err) => {
3340
+ logger19.error(`Failed to set cache for key: ${cacheKey}`, err);
3341
+ });
3342
+ return data;
3343
+ } catch (error) {
3344
+ throw error;
3345
+ }
3346
+ }
3347
+ async function getAreaChecklistHistory({
3348
+ page = 1,
3349
+ limit = 10,
3350
+ search = "",
3351
+ site,
3352
+ type,
3353
+ parentChecklist,
3354
+ status,
3355
+ createdAt,
3356
+ user
3357
+ }) {
3358
+ page = page > 0 ? page - 1 : 0;
3359
+ const query = { type };
3360
+ const cacheOptions = {
3361
+ page,
3362
+ limit
3363
+ };
3364
+ try {
3365
+ query.site = new ObjectId12(site);
3366
+ cacheOptions.site = site.toString();
3367
+ } catch (error) {
3368
+ throw new BadRequestError21("Invalid site ID format.");
3369
+ }
3370
+ try {
3371
+ query.parentChecklist = new ObjectId12(parentChecklist);
3372
+ cacheOptions.parentChecklist = parentChecklist.toString();
3373
+ } catch (error) {
3374
+ throw new BadRequestError21("Invalid parent checklist ID format.");
3375
+ }
3376
+ if (search) {
3377
+ query.$text = { $search: search };
3378
+ cacheOptions.search = search;
3379
+ }
3380
+ if (createdAt) {
3381
+ query.createdAt = {
3382
+ $gte: /* @__PURE__ */ new Date(`${createdAt}T00:00:00Z`),
3383
+ $lte: /* @__PURE__ */ new Date(`${createdAt}T23:59:59Z`)
3384
+ };
3385
+ cacheOptions.createdAt = new Date(createdAt).toISOString().split("T")[0];
3386
+ }
3387
+ if (status) {
3388
+ query.status = status;
3389
+ cacheOptions.status = status;
3390
+ } else {
3391
+ query.status = { $in: ["In Progress", "Completed"] };
3392
+ }
3393
+ if (user) {
3394
+ try {
3395
+ query.acceptedBy = new ObjectId12(user);
3396
+ cacheOptions.user = user.toString();
3397
+ } catch (error) {
3398
+ throw new BadRequestError21("Invalid user ID format.");
3399
+ }
3400
+ }
3401
+ const cacheKey = makeCacheKey6(namespace_collection, cacheOptions);
3402
+ const cachedData = await getCache(cacheKey);
3403
+ if (cachedData) {
3404
+ logger19.info(`Cache hit for key: ${cacheKey}`);
3405
+ return cachedData;
3406
+ }
3407
+ try {
3408
+ const pipeline = [
3409
+ { $match: query },
3410
+ {
3411
+ $lookup: {
3412
+ from: "users",
3413
+ localField: "acceptedBy",
3414
+ foreignField: "_id",
3415
+ pipeline: [
3416
+ ...search ? [{ $match: { name: { $regex: search, $options: "i" } } }] : [],
3417
+ { $project: { name: 1 } }
3418
+ ],
3419
+ as: "acceptedBy"
3420
+ }
3421
+ },
3422
+ {
3423
+ $unwind: {
3424
+ path: "$acceptedBy",
3425
+ preserveNullAndEmptyArrays: true
3426
+ }
3427
+ },
3428
+ {
3429
+ $project: {
3430
+ name: 1,
3431
+ createdAt: 1,
3432
+ acceptedByName: "$acceptedBy.name",
3433
+ status: 1,
3434
+ startedAt: 1,
3435
+ endedAt: 1
3436
+ }
3437
+ },
3438
+ { $sort: { status: 1 } },
3439
+ { $skip: page * limit },
3440
+ { $limit: limit }
3441
+ ];
3442
+ const items = await collection.aggregate(pipeline).toArray();
3443
+ const length = await collection.countDocuments(query);
3444
+ const data = paginate6(items, page, limit, length);
3445
+ setCache(cacheKey, data, 15 * 60).then(() => {
3446
+ logger19.info(`Cache set for key: ${cacheKey}`);
3447
+ }).catch((err) => {
3448
+ logger19.error(`Failed to set cache for key: ${cacheKey}`, err);
3449
+ });
3450
+ return data;
3451
+ } catch (error) {
3452
+ throw error;
3453
+ }
3454
+ }
3455
+ async function getAreaChecklistHistoryDetails(_id) {
3456
+ try {
3457
+ _id = new ObjectId12(_id);
3458
+ } catch (error) {
3459
+ throw new BadRequestError21("Invalid area checklist ID format.");
3460
+ }
3461
+ const cacheKey = makeCacheKey6(namespace_collection, {
3462
+ _id: _id.toString()
3463
+ });
3464
+ const cachedData = await getCache(cacheKey);
3465
+ if (cachedData) {
3466
+ logger19.info(`Cache hit for key: ${cacheKey}`);
3467
+ return cachedData;
3468
+ }
3469
+ try {
3470
+ const areaPipeline = [
3471
+ { $match: { _id } },
3472
+ {
3473
+ $lookup: {
3474
+ from: "users",
3475
+ localField: "createdBy",
3476
+ foreignField: "_id",
3477
+ pipeline: [{ $project: { name: 1 } }],
3478
+ as: "createdBy"
3479
+ }
3480
+ },
3481
+ {
3482
+ $unwind: {
3483
+ path: "$createdBy",
3484
+ preserveNullAndEmptyArrays: true
3485
+ }
3486
+ },
3487
+ {
3488
+ $lookup: {
3489
+ from: "users",
3490
+ localField: "acceptedBy",
3491
+ foreignField: "_id",
3492
+ pipeline: [{ $project: { name: 1 } }],
3493
+ as: "acceptedBy"
3494
+ }
3495
+ },
3496
+ {
3497
+ $unwind: {
3498
+ path: "$acceptedBy",
3499
+ preserveNullAndEmptyArrays: true
3500
+ }
3501
+ },
3502
+ {
3503
+ $project: {
3504
+ name: 1,
3505
+ createdAt: 1,
3506
+ createdByName: "$createdBy.name",
3507
+ startedAt: 1,
3508
+ endedAt: 1,
3509
+ status: 1,
3510
+ signature: 1,
3511
+ acceptedByName: "$acceptedBy.name"
3512
+ }
3513
+ }
3514
+ ];
3515
+ const unitPipeline = [
3516
+ { $match: { areaChecklist: _id } },
3517
+ {
3518
+ $project: {
3519
+ name: 1,
3520
+ remarks: "$metadata.remarks",
3521
+ attachments: "$metadata.attachments",
3522
+ approve: { $ifNull: ["$approve", null] },
3523
+ reject: { $ifNull: ["$reject", null] }
3524
+ }
3525
+ }
3526
+ ];
3527
+ const [area, units] = await Promise.all([
3528
+ collection.aggregate(areaPipeline).toArray(),
3529
+ unitChecklistCollection.aggregate(unitPipeline).toArray()
3530
+ ]);
3531
+ if (!area.length) {
3532
+ throw new BadRequestError21("Area checklist not found.");
3533
+ }
3534
+ const items = {
3535
+ area: area[0],
3536
+ units
3537
+ };
3538
+ setCache(cacheKey, items, 15 * 60).then(() => {
3539
+ logger19.info(`Cache set for key: ${cacheKey}`);
3540
+ }).catch((err) => {
3541
+ logger19.error(`Failed to set cache for key: ${cacheKey}`, err);
3542
+ });
3543
+ return items;
3544
+ } catch (error) {
3545
+ throw error;
3546
+ }
3547
+ }
3548
+ async function acceptAreaChecklist(_id, acceptedBy) {
3549
+ try {
3550
+ _id = new ObjectId12(_id);
3551
+ } catch (error) {
3552
+ throw new BadRequestError21("Invalid area ID format.");
3553
+ }
3554
+ try {
3555
+ acceptedBy = new ObjectId12(acceptedBy);
3556
+ } catch (error) {
3557
+ throw new BadRequestError21("Invalid acceptedBy ID format.");
3558
+ }
3559
+ try {
3560
+ const now = /* @__PURE__ */ new Date();
3561
+ const updateValue = {
3562
+ acceptedBy,
3563
+ acceptedAt: now,
3564
+ startedAt: now,
3565
+ updatedAt: now
3566
+ };
3567
+ const res = await collection.updateOne({ _id }, { $set: updateValue });
3568
+ if (res.modifiedCount === 0) {
3569
+ throw new InternalServerError7("Unable to update cleaning area.");
3570
+ }
3571
+ delNamespace().then(() => {
3572
+ logger19.info(`Cache cleared for namespace: ${namespace_collection}`);
3573
+ }).catch((err) => {
3574
+ logger19.error(
3575
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3576
+ err
3577
+ );
3578
+ });
3579
+ return res.modifiedCount;
3580
+ } catch (error) {
3581
+ throw error;
3582
+ }
3583
+ }
3584
+ async function attachImageAreaChecklist(_id, attachments, session) {
3585
+ try {
3586
+ _id = new ObjectId12(_id);
3587
+ } catch (error) {
3588
+ throw new BadRequestError21("Invalid area checklist ID format.");
3589
+ }
3590
+ try {
3591
+ const now = /* @__PURE__ */ new Date();
3592
+ const updateValue = {
3593
+ metadata: { attachments },
3594
+ updatedAt: now
3595
+ };
3596
+ const res = await collection.updateOne(
3597
+ { _id },
3598
+ { $set: updateValue },
3599
+ { session }
3600
+ );
3601
+ if (res.modifiedCount === 0) {
3602
+ throw new InternalServerError7(
3603
+ "Unable to update cleaning area checklist."
3604
+ );
3605
+ }
3606
+ delNamespace().then(() => {
3607
+ logger19.info(`Cache cleared for namespace: ${namespace_collection}`);
3608
+ }).catch((err) => {
3609
+ logger19.error(
3610
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3611
+ err
3612
+ );
3613
+ });
3614
+ delUnitNamespace().then(() => {
3615
+ logger19.info(
3616
+ `Cache cleared for namespace: ${unit_checklist_collection}`
3617
+ );
3618
+ }).catch((err) => {
3619
+ logger19.error(
3620
+ `Failed to clear cache for namespace: ${unit_checklist_collection}`,
3621
+ err
3622
+ );
3623
+ });
3624
+ return res.modifiedCount;
3625
+ } catch (error) {
3626
+ throw error;
3627
+ }
3628
+ }
3629
+ async function submitAreaChecklist(_id, signature) {
3630
+ try {
3631
+ _id = new ObjectId12(_id);
3632
+ } catch (error) {
3633
+ throw new BadRequestError21("Invalid area ID format.");
3634
+ }
3635
+ try {
3636
+ const now = /* @__PURE__ */ new Date();
3637
+ const updateValue = {
3638
+ signature,
3639
+ status: "In Progress",
3640
+ endedAt: now,
3641
+ updatedAt: now
3642
+ };
3643
+ const res = await collection.updateOne({ _id }, { $set: updateValue });
3644
+ if (res.modifiedCount === 0) {
3645
+ throw new InternalServerError7("Unable to update cleaning area.");
3646
+ }
3647
+ delNamespace().then(() => {
3648
+ logger19.info(`Cache cleared for namespace: ${namespace_collection}`);
3649
+ }).catch((err) => {
3650
+ logger19.error(
3651
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3652
+ err
3653
+ );
3654
+ });
3655
+ return res.modifiedCount;
3656
+ } catch (error) {
3657
+ throw error;
3658
+ }
3659
+ }
3660
+ async function completeAreaChecklist(_id, signature) {
3661
+ try {
3662
+ _id = new ObjectId12(_id);
3663
+ } catch (error) {
3664
+ throw new BadRequestError21("Invalid area ID format.");
3665
+ }
3666
+ try {
3667
+ const now = /* @__PURE__ */ new Date();
3668
+ const updateValue = {
3669
+ signature,
3670
+ status: "Completed",
3671
+ endedAt: now,
3672
+ updatedAt: now
3673
+ };
3674
+ const res = await collection.updateOne({ _id }, { $set: updateValue });
3675
+ if (res.modifiedCount === 0) {
3676
+ throw new InternalServerError7("Unable to update cleaning area.");
3677
+ }
3678
+ delNamespace().then(() => {
3679
+ logger19.info(`Cache cleared for namespace: ${namespace_collection}`);
3680
+ }).catch((err) => {
3681
+ logger19.error(
3682
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3683
+ err
3684
+ );
3685
+ });
3686
+ return res.modifiedCount;
3687
+ } catch (error) {
3688
+ throw error;
3689
+ }
3690
+ }
3691
+ return {
3692
+ createIndex,
3693
+ createTextIndex,
3694
+ createAreaChecklist,
3695
+ getAllAreaChecklist,
3696
+ getAreaChecklistHistory,
3697
+ getAreaChecklistHistoryDetails,
3698
+ acceptAreaChecklist,
3699
+ attachImageAreaChecklist,
3700
+ submitAreaChecklist,
3701
+ completeAreaChecklist
3702
+ };
3703
+ }
3704
+
3705
+ // src/controllers/hygiene-area-checklist.controller.ts
3706
+ import { BadRequestError as BadRequestError22, logger as logger21 } from "@iservice365/node-server-utils";
3707
+ import Joi12 from "joi";
3708
+
3709
+ // src/services/hygiene-area-checklist.service.ts
3710
+ import { logger as logger20 } from "@iservice365/node-server-utils";
3711
+ function useAreaChecklistService() {
3712
+ const { createAreaChecklist: _createAreaChecklist } = useAreaChecklistRepo();
3713
+ const { getAreas } = useAreaRepository();
3714
+ const { getToiletLocations } = useToiletLocationRepository();
3715
+ async function createAreaChecklist(value) {
3716
+ try {
3717
+ const results = [];
3718
+ if (value.type === "cleaner") {
3719
+ const cleanerAreasResult = await getAreas({
3720
+ site: value.site
3721
+ });
3722
+ const cleanerAreas = cleanerAreasResult.items || [];
3723
+ if (cleanerAreas.length === 0) {
3724
+ logger20.warn(`No cleaner areas found for site: ${value.site}`);
3725
+ return results;
3726
+ }
3727
+ for (const area of cleanerAreas) {
3728
+ const checklistData = {
3729
+ type: "cleaner",
3730
+ site: value.site,
3731
+ parentChecklist: value.parentChecklist,
3732
+ area: area._id.toString(),
3733
+ name: area.name,
3734
+ createdBy: value.createdBy
3735
+ };
3736
+ const insertedId = await _createAreaChecklist(checklistData);
3737
+ results.push(insertedId);
3738
+ }
3739
+ logger20.info(
3740
+ `Created ${results.length} cleaner area checklists for site: ${value.site}`
3741
+ );
3742
+ }
3743
+ if (value.type === "toilet") {
3744
+ const toiletAreasResult = await getToiletLocations({
3745
+ site: value.site
3746
+ });
3747
+ const toiletAreas = toiletAreasResult.items || [];
3748
+ if (toiletAreas.length === 0) {
3749
+ logger20.warn(`No toilet locations found for site: ${value.site}`);
3750
+ return results;
3751
+ }
3752
+ for (const toiletLocation of toiletAreas) {
3753
+ const checklistData = {
3754
+ type: "toilet",
3755
+ site: value.site,
3756
+ parentChecklist: value.parentChecklist,
3757
+ area: toiletLocation._id,
3758
+ name: toiletLocation.name,
3759
+ createdBy: value.createdBy
3760
+ };
3761
+ const insertedId = await _createAreaChecklist(checklistData);
3762
+ results.push(insertedId);
3763
+ }
3764
+ logger20.info(
3765
+ `Created ${results.length} toilet area checklists for site: ${value.site}`
3766
+ );
3767
+ }
3768
+ return results;
3769
+ } catch (error) {
3770
+ logger20.error(`Error generating area checklists:`, error);
3771
+ throw error;
3772
+ }
3773
+ }
3774
+ return { createAreaChecklist };
3775
+ }
3776
+
3777
+ // src/controllers/hygiene-area-checklist.controller.ts
3778
+ function useAreaChecklistController() {
3779
+ const {
3780
+ getAllAreaChecklist: _getAllAreaChecklist,
3781
+ getAreaChecklistHistory: _getAreaChecklistHistory,
3782
+ getAreaChecklistHistoryDetails: _getAreaChecklistHistoryDetails,
3783
+ acceptAreaChecklist: _acceptAreaChecklist,
3784
+ attachImageAreaChecklist: _attachImageAreaChecklist,
3785
+ submitAreaChecklist: _submitAreaChecklist,
3786
+ completeAreaChecklist: _completeAreaChecklist
3787
+ } = useAreaChecklistRepo();
3788
+ const { createAreaChecklist: _createAreaChecklist } = useAreaChecklistService();
3789
+ async function createAreaChecklist(req, res, next) {
3790
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3791
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3792
+ {}
3793
+ ) : {};
3794
+ const createdBy = cookies["user"] || "";
3795
+ const payload = { ...req.body, ...req.params, createdBy };
3796
+ const validation = Joi12.object({
3797
+ type: Joi12.string().required().valid(...allowedTypes),
3798
+ site: Joi12.string().hex().required(),
3799
+ parentChecklist: Joi12.string().hex().required(),
3800
+ createdBy: Joi12.string().hex().optional().allow("", null)
3801
+ });
3802
+ const { error } = validation.validate(payload);
3803
+ if (error) {
3804
+ logger21.log({ level: "error", message: error.message });
3805
+ next(new BadRequestError22(error.message));
3806
+ return;
3807
+ }
3808
+ try {
3809
+ await _createAreaChecklist(payload);
3810
+ res.status(201).json({ message: "Area checklists generated successfully." });
3811
+ return;
3812
+ } catch (error2) {
3813
+ logger21.log({ level: "error", message: error2.message });
3814
+ next(error2);
3815
+ return;
3816
+ }
3817
+ }
3818
+ async function getAllAreaChecklist(req, res, next) {
3819
+ const query = { ...req.query, ...req.params };
3820
+ const validation = Joi12.object({
3821
+ page: Joi12.number().min(1).optional().allow("", null),
3822
+ limit: Joi12.number().min(1).optional().allow("", null),
3823
+ search: Joi12.string().optional().allow("", null),
3824
+ site: Joi12.string().hex().required(),
3825
+ type: Joi12.string().valid(...allowedTypes).required(),
3826
+ parentChecklist: Joi12.string().hex().required()
3827
+ });
3828
+ const { error } = validation.validate(query);
3829
+ if (error) {
3830
+ logger21.log({ level: "error", message: error.message });
3831
+ next(new BadRequestError22(error.message));
3832
+ return;
3833
+ }
3834
+ const page = parseInt(req.query.page) ?? 1;
3835
+ const limit = parseInt(req.query.limit) ?? 20;
3836
+ const search = req.query.search ?? "";
3837
+ const site = req.params.site ?? "";
3838
+ const type = req.params.type ?? "";
3839
+ const parentChecklist = req.params.parentChecklist ?? "";
3840
+ try {
3841
+ const data = await _getAllAreaChecklist({
3842
+ page,
3843
+ limit,
3844
+ search,
3845
+ site,
3846
+ type,
3847
+ parentChecklist
3848
+ });
3849
+ res.json(data);
3850
+ return;
3851
+ } catch (error2) {
3852
+ logger21.log({ level: "error", message: error2.message });
3853
+ next(error2);
3854
+ return;
3855
+ }
3856
+ }
3857
+ async function getAreaChecklistHistory(req, res, next) {
3858
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3859
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3860
+ {}
3861
+ ) : {};
3862
+ const user = cookies["user"] || "";
3863
+ const query = { ...req.query, ...req.params, user };
3864
+ const validation = Joi12.object({
3865
+ page: Joi12.number().min(1).optional().allow("", null),
3866
+ limit: Joi12.number().min(1).optional().allow("", null),
3867
+ search: Joi12.string().optional().allow("", null),
3868
+ site: Joi12.string().hex().required(),
3869
+ type: Joi12.string().valid(...allowedTypes).required(),
3870
+ parentChecklist: Joi12.string().hex().required(),
3871
+ status: Joi12.string().allow("", null, ...allowedStatus),
3872
+ createdAt: Joi12.alternatives().try(Joi12.date(), Joi12.string()).optional().allow("", null),
3873
+ user: Joi12.string().hex().optional().allow("", null)
3874
+ });
3875
+ const { error } = validation.validate(query);
3876
+ if (error) {
3877
+ logger21.log({ level: "error", message: error.message });
3878
+ next(new BadRequestError22(error.message));
3879
+ return;
3880
+ }
3881
+ const page = parseInt(req.query.page) ?? 1;
3882
+ const limit = parseInt(req.query.limit) ?? 20;
3883
+ const search = req.query.search ?? "";
3884
+ const site = req.params.site ?? "";
3885
+ const type = req.params.type ?? "";
3886
+ const parentChecklist = req.params.parentChecklist ?? "";
3887
+ const status = req.query.status ?? "";
3888
+ const createdAt = req.query.createdAt ?? "";
3889
+ try {
3890
+ const data = await _getAreaChecklistHistory({
3891
+ page,
3892
+ limit,
3893
+ search,
3894
+ site,
3895
+ type,
3896
+ parentChecklist,
3897
+ status,
3898
+ createdAt,
3899
+ user
3900
+ });
3901
+ res.json(data);
3902
+ return;
3903
+ } catch (error2) {
3904
+ logger21.log({ level: "error", message: error2.message });
3905
+ next(error2);
3906
+ return;
3907
+ }
3908
+ }
3909
+ async function getAreaChecklistHistoryDetails(req, res, next) {
3910
+ const validation = Joi12.string().hex().required();
3911
+ const _id = req.params.id;
3912
+ const { error } = validation.validate(_id);
3913
+ if (error) {
3914
+ logger21.log({ level: "error", message: error.message });
3915
+ next(new BadRequestError22(error.message));
3916
+ return;
3917
+ }
3918
+ try {
3919
+ const data = await _getAreaChecklistHistoryDetails(_id);
3920
+ res.json(data);
3921
+ return;
3922
+ } catch (error2) {
3923
+ logger21.log({ level: "error", message: error2.message });
3924
+ next(error2);
3925
+ return;
3926
+ }
3927
+ }
3928
+ async function acceptAreaChecklist(req, res, next) {
3929
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3930
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3931
+ {}
3932
+ ) : {};
3933
+ const acceptedBy = cookies["user"] || "";
3934
+ const payload = { id: req.params.id, acceptedBy };
3935
+ const validation = Joi12.object({
3936
+ id: Joi12.string().hex().required(),
3937
+ acceptedBy: Joi12.string().hex().required()
3938
+ });
3939
+ const { error } = validation.validate(payload);
3940
+ if (error) {
3941
+ logger21.log({ level: "error", message: error.message });
3942
+ next(new BadRequestError22(error.message));
3943
+ return;
3944
+ }
3945
+ try {
3946
+ await _acceptAreaChecklist(payload.id, payload.acceptedBy);
3947
+ res.json({ message: "Area checklist updated successfully." });
3948
+ return;
3949
+ } catch (error2) {
3950
+ logger21.log({ level: "error", message: error2.message });
3951
+ next(error2);
3952
+ return;
3953
+ }
3954
+ }
3955
+ async function attachImageAreaChecklist(req, res, next) {
3956
+ const payload = { id: req.params.id, attachments: req.body.attachments };
3957
+ const validation = Joi12.object({
3958
+ id: Joi12.string().hex().required(),
3959
+ attachments: Joi12.array().items(Joi12.string()).optional()
3960
+ });
3961
+ const { error } = validation.validate(payload);
3962
+ if (error) {
3963
+ logger21.log({ level: "error", message: error.message });
3964
+ next(new BadRequestError22(error.message));
3965
+ return;
3966
+ }
3967
+ try {
3968
+ await _attachImageAreaChecklist(payload.id, payload.attachments);
3969
+ res.json({ message: "Area checklist attachments updated successfully." });
3970
+ return;
3971
+ } catch (error2) {
3972
+ logger21.log({ level: "error", message: error2.message });
3973
+ next(error2);
3974
+ return;
3975
+ }
3976
+ }
3977
+ async function submitAreaChecklist(req, res, next) {
3978
+ const payload = { id: req.params.id, signature: req.body.signature };
3979
+ const validation = Joi12.object({
3980
+ id: Joi12.string().hex().required(),
3981
+ signature: Joi12.string().required()
3982
+ });
3983
+ const { error } = validation.validate(payload);
3984
+ if (error) {
3985
+ logger21.log({ level: "error", message: error.message });
3986
+ next(new BadRequestError22(error.message));
3987
+ return;
3988
+ }
3989
+ try {
3990
+ await _submitAreaChecklist(payload.id, payload.signature);
3991
+ res.json({ message: "Area checklist submitted successfully." });
3992
+ return;
3993
+ } catch (error2) {
3994
+ logger21.log({ level: "error", message: error2.message });
3995
+ next(error2);
3996
+ return;
3997
+ }
3998
+ }
3999
+ async function completeAreaChecklist(req, res, next) {
4000
+ const payload = { id: req.params.id, signature: req.body.signature };
4001
+ const validation = Joi12.object({
4002
+ id: Joi12.string().hex().required(),
4003
+ signature: Joi12.string().required()
4004
+ });
4005
+ const { error } = validation.validate(payload);
4006
+ if (error) {
4007
+ logger21.log({ level: "error", message: error.message });
4008
+ next(new BadRequestError22(error.message));
4009
+ return;
4010
+ }
4011
+ try {
4012
+ await _completeAreaChecklist(payload.id, payload.signature);
4013
+ res.json({ message: "Area checklist completed successfully." });
4014
+ return;
4015
+ } catch (error2) {
4016
+ logger21.log({ level: "error", message: error2.message });
4017
+ next(error2);
4018
+ return;
4019
+ }
4020
+ }
4021
+ return {
4022
+ createAreaChecklist,
4023
+ getAllAreaChecklist,
4024
+ getAreaChecklistHistory,
4025
+ getAreaChecklistHistoryDetails,
4026
+ acceptAreaChecklist,
4027
+ attachImageAreaChecklist,
4028
+ submitAreaChecklist,
4029
+ completeAreaChecklist
4030
+ };
4031
+ }
4032
+
4033
+ // src/models/hygiene-unit-checklist.model.ts
4034
+ import { BadRequestError as BadRequestError23, logger as logger22 } from "@iservice365/node-server-utils";
4035
+ import Joi13 from "joi";
4036
+ import { ObjectId as ObjectId13 } from "mongodb";
4037
+ var unitChecklistSchema = Joi13.object({
4038
+ site: Joi13.string().hex().required(),
4039
+ type: Joi13.string().valid(...allowedTypes).required(),
4040
+ parentChecklist: Joi13.string().hex().required(),
4041
+ areaChecklist: Joi13.string().hex().required(),
4042
+ unit: Joi13.string().hex().required(),
4043
+ name: Joi13.string().optional().allow("", null),
4044
+ createdBy: Joi13.string().hex().optional().allow("", null)
4045
+ });
4046
+ function MUnitChecklist(value) {
4047
+ const { error } = unitChecklistSchema.validate(value);
4048
+ if (error) {
4049
+ logger22.info(`Hygiene Checklist Unit Model: ${error.message}`);
4050
+ throw new BadRequestError23(error.message);
4051
+ }
4052
+ if (value.site) {
4053
+ try {
4054
+ value.site = new ObjectId13(value.site);
4055
+ } catch (error2) {
4056
+ throw new BadRequestError23("Invalid site ID format.");
4057
+ }
4058
+ }
4059
+ if (value.parentChecklist) {
4060
+ try {
4061
+ value.parentChecklist = new ObjectId13(value.parentChecklist);
4062
+ } catch (error2) {
4063
+ throw new BadRequestError23("Invalid parent checklist ID format.");
4064
+ }
4065
+ }
4066
+ if (value.areaChecklist) {
4067
+ try {
4068
+ value.areaChecklist = new ObjectId13(value.areaChecklist);
4069
+ } catch (error2) {
4070
+ throw new BadRequestError23("Invalid area checklist ID format.");
4071
+ }
4072
+ }
4073
+ if (value.unit) {
4074
+ try {
4075
+ value.unit = new ObjectId13(value.unit);
4076
+ } catch (error2) {
4077
+ throw new BadRequestError23("Invalid unit ID format.");
4078
+ }
4079
+ }
4080
+ if (value.createdBy) {
4081
+ try {
4082
+ value.createdBy = new ObjectId13(value.createdBy);
4083
+ } catch (error2) {
4084
+ throw new BadRequestError23("Invalid createdBy ID format.");
4085
+ }
4086
+ }
4087
+ return {
4088
+ site: value.site,
4089
+ type: value.type,
4090
+ parentChecklist: value.parentChecklist,
4091
+ areaChecklist: value.areaChecklist,
4092
+ unit: value.unit,
4093
+ name: value.name ?? "",
4094
+ approve: false,
4095
+ reject: false,
4096
+ createdBy: value.createdBy ?? "",
4097
+ createdAt: /* @__PURE__ */ new Date(),
4098
+ updatedAt: value.updatedAt ?? ""
4099
+ };
4100
+ }
4101
+
4102
+ // src/repositories/hygiene-unit-checklist.repository.ts
4103
+ import {
4104
+ BadRequestError as BadRequestError24,
4105
+ InternalServerError as InternalServerError8,
4106
+ logger as logger23,
4107
+ makeCacheKey as makeCacheKey7,
4108
+ paginate as paginate7,
4109
+ useAtlas as useAtlas11,
4110
+ useCache as useCache7
4111
+ } from "@iservice365/node-server-utils";
4112
+ import { ObjectId as ObjectId14 } from "mongodb";
4113
+ function useUnitChecklistRepo() {
4114
+ const db = useAtlas11.getDb();
4115
+ if (!db) {
4116
+ throw new InternalServerError8("Unable to connect to server.");
4117
+ }
4118
+ const namespace_collection = "hygiene-checklist.units";
4119
+ const collection = db.collection(namespace_collection);
4120
+ const { delNamespace, setCache, getCache } = useCache7(namespace_collection);
4121
+ async function createIndex() {
4122
+ try {
4123
+ await collection.createIndexes([
4124
+ { key: { site: 1 } },
4125
+ { key: { type: 1 } },
4126
+ { key: { parentChecklist: 1 } },
4127
+ { key: { areaChecklist: 1 } },
4128
+ { key: { "metadata.workOrder.category": 1 } },
4129
+ { key: { "metadata.workOrder.createdBy": 1 } },
4130
+ { key: { "metadata.workOrder.serviceProvider": 1 } },
4131
+ { key: { "metadata.workOrder.organization": 1 } },
4132
+ { key: { "metadata.workOrder.site": 1 } }
4133
+ ]);
4134
+ } catch (error) {
4135
+ throw new InternalServerError8(
4136
+ "Failed to create index on hygiene unit checklist."
4137
+ );
4138
+ }
4139
+ }
4140
+ async function createTextIndex() {
4141
+ try {
4142
+ await collection.createIndex({ name: "text" });
4143
+ } catch (error) {
4144
+ throw new InternalServerError8(
4145
+ "Failed to create text index on hygiene unit checklist."
4146
+ );
4147
+ }
4148
+ }
4149
+ async function createUnitChecklist(value, session) {
4150
+ try {
4151
+ value = MUnitChecklist(value);
4152
+ const res = await collection.insertOne(value, { session });
4153
+ delNamespace().then(() => {
4154
+ logger23.info(`Cache cleared for namespace: ${namespace_collection}`);
4155
+ }).catch((err) => {
4156
+ logger23.error(
4157
+ `Failed to clear cache for namespace: ${namespace_collection}`,
4158
+ err
4159
+ );
4160
+ });
4161
+ return res.insertedId;
4162
+ } catch (error) {
4163
+ throw error;
4164
+ }
4165
+ }
4166
+ async function getAllUnitChecklist({
4167
+ page = 1,
4168
+ limit = 10,
4169
+ search = "",
4170
+ site,
4171
+ type,
4172
+ parentChecklist,
4173
+ areaChecklist
4174
+ }) {
4175
+ page = page > 0 ? page - 1 : 0;
4176
+ const query = { type };
4177
+ const cacheOptions = {
4178
+ page,
4179
+ limit
4180
+ };
4181
+ try {
4182
+ query.site = new ObjectId14(site);
4183
+ cacheOptions.site = site.toString();
4184
+ } catch (error) {
4185
+ throw new BadRequestError24("Invalid site ID format.");
4186
+ }
4187
+ try {
4188
+ query.parentChecklist = new ObjectId14(parentChecklist);
4189
+ cacheOptions.parentChecklist = parentChecklist.toString();
4190
+ } catch (error) {
4191
+ throw new BadRequestError24("Invalid parent checklist ID format.");
4192
+ }
4193
+ try {
4194
+ query.areaChecklist = new ObjectId14(areaChecklist);
4195
+ cacheOptions.areaChecklist = areaChecklist.toString();
4196
+ } catch (error) {
4197
+ throw new BadRequestError24("Invalid area checklist ID format.");
4198
+ }
4199
+ if (search) {
4200
+ query.$text = { $search: search };
4201
+ cacheOptions.search = search;
4202
+ }
4203
+ const cacheKey = makeCacheKey7(namespace_collection, cacheOptions);
4204
+ const cachedData = await getCache(cacheKey);
4205
+ if (cachedData) {
4206
+ logger23.info(`Cache hit for key: ${cacheKey}`);
4207
+ return cachedData;
4208
+ }
4209
+ try {
4210
+ const areaAttachmentsResult = await collection.aggregate([
4211
+ { $match: query },
4212
+ {
4213
+ $lookup: {
4214
+ from: "hygiene-checklist.areas",
4215
+ localField: "areaChecklist",
4216
+ foreignField: "_id",
4217
+ pipeline: [
4218
+ { $project: { attachments: "$metadata.attachments" } }
4219
+ ],
4220
+ as: "areaChecklistData"
4221
+ }
4222
+ },
4223
+ {
4224
+ $unwind: {
4225
+ path: "$areaChecklistData",
4226
+ preserveNullAndEmptyArrays: true
4227
+ }
4228
+ },
4229
+ {
4230
+ $group: {
4231
+ _id: null,
4232
+ attachments: { $first: "$areaChecklistData.attachments" }
4233
+ }
4234
+ }
4235
+ ]).toArray();
4236
+ const areaAttachments = areaAttachmentsResult.length > 0 ? areaAttachmentsResult[0].attachments || [] : [];
4237
+ const pipeline = [
4238
+ { $match: query },
4239
+ {
4240
+ $lookup: {
4241
+ from: "organizations",
4242
+ localField: "metadata.workOrder.category",
4243
+ foreignField: "_id",
4244
+ pipeline: [{ $project: { nature: 1 } }],
4245
+ as: "categoryData"
4246
+ }
4247
+ },
4248
+ {
4249
+ $lookup: {
4250
+ from: "users",
4251
+ localField: "metadata.workOrder.createdBy",
4252
+ foreignField: "_id",
4253
+ pipeline: [{ $project: { name: 1 } }],
4254
+ as: "createdByData"
4255
+ }
4256
+ },
4257
+ {
4258
+ $lookup: {
4259
+ from: "service-providers",
4260
+ localField: "metadata.workOrder.serviceProvider",
4261
+ foreignField: "_id",
4262
+ pipeline: [{ $project: { name: 1 } }],
4263
+ as: "serviceProviderData"
4264
+ }
4265
+ },
4266
+ {
4267
+ $lookup: {
4268
+ from: "organizations",
4269
+ localField: "metadata.workOrder.organization",
4270
+ foreignField: "_id",
4271
+ pipeline: [{ $project: { name: 1 } }],
4272
+ as: "organizationData"
4273
+ }
4274
+ },
4275
+ {
4276
+ $lookup: {
4277
+ from: "sites",
4278
+ localField: "metadata.workOrder.site",
4279
+ foreignField: "_id",
4280
+ pipeline: [{ $project: { name: 1 } }],
4281
+ as: "siteData"
4282
+ }
4283
+ },
4284
+ {
4285
+ $addFields: {
4286
+ "metadata.workOrder.categoryName": {
4287
+ $arrayElemAt: ["$categoryData.nature", 0]
4288
+ },
4289
+ "metadata.workOrder.createdByName": {
4290
+ $arrayElemAt: ["$createdByData.name", 0]
4291
+ },
4292
+ "metadata.workOrder.serviceProviderName": {
4293
+ $arrayElemAt: ["$serviceProviderData.name", 0]
4294
+ },
4295
+ "metadata.workOrder.organizationName": {
4296
+ $arrayElemAt: ["$organizationData.name", 0]
4297
+ },
4298
+ "metadata.workOrder.siteName": {
4299
+ $arrayElemAt: ["$siteData.name", 0]
4300
+ }
4301
+ }
4302
+ },
4303
+ {
4304
+ $project: {
4305
+ name: 1,
4306
+ remarks: "$metadata.remarks",
4307
+ attachments: "$metadata.attachments",
4308
+ workOrder: "$metadata.workOrder",
4309
+ approve: { $ifNull: ["$approve", null] },
4310
+ reject: { $ifNull: ["$reject", null] }
4311
+ }
4312
+ },
4313
+ { $sort: { _id: -1 } },
4314
+ { $skip: page * limit },
4315
+ { $limit: limit }
4316
+ ];
4317
+ const items = await collection.aggregate(pipeline).toArray();
4318
+ const length = await collection.countDocuments(query);
4319
+ const paginatedData = paginate7(items, page, limit, length);
4320
+ const data = {
4321
+ attachments: areaAttachments,
4322
+ ...paginatedData
4323
+ };
4324
+ setCache(cacheKey, data, 15 * 60).then(() => {
4325
+ logger23.info(`Cache set for key: ${cacheKey}`);
4326
+ }).catch((err) => {
4327
+ logger23.error(`Failed to set cache for key: ${cacheKey}`, err);
4328
+ });
4329
+ return data;
4330
+ } catch (error) {
4331
+ throw error;
4332
+ }
4333
+ }
4334
+ async function getUnitChecklistById(_id) {
4335
+ try {
4336
+ _id = new ObjectId14(_id);
4337
+ } catch (error) {
4338
+ throw new BadRequestError24("Invalid unit checklist ID format.");
4339
+ }
4340
+ try {
4341
+ return await collection.findOne({ _id });
4342
+ } catch (error) {
4343
+ throw error;
4344
+ }
4345
+ }
4346
+ async function updateUnitChecklist(_id, value, session) {
4347
+ try {
4348
+ _id = new ObjectId14(_id);
4349
+ } catch (error) {
4350
+ throw new BadRequestError24("Invalid unit checklist ID format.");
4351
+ }
4352
+ if (value.checkedBy && typeof value.checkedBy === "string") {
4353
+ try {
4354
+ value.checkedBy = new ObjectId14(value.checkedBy);
4355
+ } catch (error) {
4356
+ throw new BadRequestError24("Invalid checkedBy ID format.");
4357
+ }
4358
+ }
4359
+ if ("metadata" in value && value.metadata?.workOrder) {
4360
+ const workOrder = value.metadata.workOrder;
4361
+ if (workOrder.category && typeof workOrder.category === "string") {
4362
+ try {
4363
+ workOrder.category = new ObjectId14(workOrder.category);
4364
+ } catch (error) {
4365
+ throw new BadRequestError24("Invalid category ID format.");
4366
+ }
4367
+ }
4368
+ if (workOrder.createdBy && typeof workOrder.createdBy === "string") {
4369
+ try {
4370
+ workOrder.createdBy = new ObjectId14(workOrder.createdBy);
4371
+ } catch (error) {
4372
+ throw new BadRequestError24("Invalid createdBy ID format.");
4373
+ }
4374
+ }
4375
+ if (workOrder.serviceProvider && typeof workOrder.serviceProvider === "string") {
4376
+ try {
4377
+ workOrder.serviceProvider = new ObjectId14(workOrder.serviceProvider);
4378
+ } catch (error) {
4379
+ throw new BadRequestError24("Invalid serviceProvider ID format.");
4380
+ }
4381
+ }
4382
+ if (workOrder.organization && typeof workOrder.organization === "string") {
4383
+ try {
4384
+ workOrder.organization = new ObjectId14(workOrder.organization);
4385
+ } catch (error) {
4386
+ throw new BadRequestError24("Invalid organization ID format.");
4387
+ }
4388
+ }
4389
+ if (workOrder.site && typeof workOrder.site === "string") {
4390
+ try {
4391
+ workOrder.site = new ObjectId14(workOrder.site);
4392
+ } catch (error) {
4393
+ throw new BadRequestError24("Invalid site ID format.");
4394
+ }
4395
+ }
4396
+ }
4397
+ try {
4398
+ const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
4399
+ const res = await collection.updateOne(
4400
+ { _id },
4401
+ { $set: updateValue },
4402
+ { session }
4403
+ );
4404
+ if (res.modifiedCount === 0) {
4405
+ throw new InternalServerError8("Unable to update unit checklist.");
4406
+ }
4407
+ delNamespace().then(() => {
4408
+ logger23.info(`Cache cleared for namespace: ${namespace_collection}`);
4409
+ }).catch((err) => {
4410
+ logger23.error(
4411
+ `Failed to clear cache for namespace: ${namespace_collection}`,
4412
+ err
4413
+ );
4414
+ });
4415
+ return res.modifiedCount;
4416
+ } catch (error) {
4417
+ throw error;
4418
+ }
4419
+ }
4420
+ return {
4421
+ createIndex,
4422
+ createTextIndex,
4423
+ createUnitChecklist,
4424
+ getAllUnitChecklist,
4425
+ getUnitChecklistById,
4426
+ updateUnitChecklist
4427
+ };
4428
+ }
4429
+
4430
+ // src/controllers/hygiene-unit-checklist.controller.ts
4431
+ import { BadRequestError as BadRequestError25, logger as logger25 } from "@iservice365/node-server-utils";
4432
+ import Joi14 from "joi";
4433
+
4434
+ // src/services/hygiene-unit-checklist.service.ts
4435
+ import { logger as logger24, NotFoundError as NotFoundError8 } from "@iservice365/node-server-utils";
4436
+ import {
4437
+ useSiteRepo,
4438
+ useWorkOrderService
4439
+ } from "@iservice365/core";
4440
+ function useUnitChecklistService() {
4441
+ const {
4442
+ getUnitChecklistById: _getUnitChecklistById,
4443
+ updateUnitChecklist: _updateUnitChecklist
4444
+ } = useUnitChecklistRepo();
4445
+ const { getSiteById } = useSiteRepo();
4446
+ const { createWorkOrder } = useWorkOrderService();
4447
+ async function approveUnitChecklist(id, value) {
4448
+ try {
4449
+ value.approve = true;
4450
+ value.reject = false;
4451
+ const result = await _updateUnitChecklist(id, value);
4452
+ return result;
4453
+ } catch (error) {
4454
+ logger24.error(`Error updating unit checklist with id ${id}:`, error);
4455
+ throw error;
4456
+ }
4457
+ }
4458
+ async function rejectUnitChecklist(id, value, fullHost) {
4459
+ try {
4460
+ value.reject = true;
4461
+ value.approve = false;
4462
+ if (value.metadata?.workOrder) {
4463
+ const existingChecklist = await _getUnitChecklistById(id);
4464
+ if (!existingChecklist)
4465
+ throw new NotFoundError8("Unit checklist not found.");
4466
+ const site = await getSiteById(
4467
+ existingChecklist.site
4468
+ );
4469
+ if (!site)
4470
+ throw new NotFoundError8("Site not found.");
4471
+ const workOrderData = {
4472
+ ...value.metadata.workOrder,
4473
+ attachments: value.metadata.attachments,
4474
+ createdBy: value.checkedBy,
4475
+ organization: site.orgId,
4476
+ site: site._id
4477
+ };
4478
+ const workOrder = await createWorkOrder(
4479
+ workOrderData,
4480
+ fullHost
4481
+ );
4482
+ if (!workOrder)
4483
+ throw new NotFoundError8("Failed to create work order.");
4484
+ }
4485
+ const result = await _updateUnitChecklist(id, value);
4486
+ return result;
4487
+ } catch (error) {
4488
+ logger24.error(`Error updating unit checklist with id ${id}:`, error);
4489
+ throw error;
4490
+ }
4491
+ }
4492
+ return {
4493
+ approveUnitChecklist,
4494
+ rejectUnitChecklist
4495
+ };
4496
+ }
4497
+
4498
+ // src/controllers/hygiene-unit-checklist.controller.ts
4499
+ import { workOrderSchema } from "@iservice365/core";
4500
+ function useUnitChecklistController() {
4501
+ const {
4502
+ createUnitChecklist: _createUnitChecklist,
4503
+ getAllUnitChecklist: _getAllUnitChecklist
4504
+ } = useUnitChecklistRepo();
4505
+ const {
4506
+ approveUnitChecklist: _approveUnitChecklist,
4507
+ rejectUnitChecklist: _rejectUnitChecklist
4508
+ } = useUnitChecklistService();
4509
+ async function createUnitChecklist(req, res, next) {
4510
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
4511
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
4512
+ {}
4513
+ ) : {};
4514
+ const createdBy = cookies["user"] || "";
4515
+ const payload = { ...req.body, ...req.params, createdBy };
4516
+ const { error } = unitChecklistSchema.validate(payload);
4517
+ if (error) {
4518
+ logger25.log({ level: "error", message: error.message });
4519
+ next(new BadRequestError25(error.message));
4520
+ return;
4521
+ }
4522
+ try {
4523
+ const id = await _createUnitChecklist(payload);
4524
+ res.status(201).json({ message: "Unit checklist created successfully.", id });
4525
+ return;
4526
+ } catch (error2) {
4527
+ logger25.log({ level: "error", message: error2.message });
4528
+ next(error2);
4529
+ return;
4530
+ }
4531
+ }
4532
+ async function getAllUnitChecklist(req, res, next) {
4533
+ const query = { ...req.query, ...req.params };
4534
+ const validation = Joi14.object({
4535
+ page: Joi14.number().min(1).optional().allow("", null),
4536
+ limit: Joi14.number().min(1).optional().allow("", null),
4537
+ search: Joi14.string().optional().allow("", null),
4538
+ site: Joi14.string().hex().required(),
4539
+ type: Joi14.string().valid(...allowedTypes).required(),
4540
+ parentChecklist: Joi14.string().hex().required(),
4541
+ areaChecklist: Joi14.string().hex().required()
4542
+ });
4543
+ const { error } = validation.validate(query);
4544
+ if (error) {
4545
+ logger25.log({ level: "error", message: error.message });
4546
+ next(new BadRequestError25(error.message));
4547
+ return;
4548
+ }
4549
+ const page = parseInt(req.query.page) ?? 1;
4550
+ const limit = parseInt(req.query.limit) ?? 20;
4551
+ const search = req.query.search ?? "";
4552
+ const site = req.params.site ?? "";
4553
+ const type = req.params.type ?? "";
4554
+ const parentChecklist = req.params.parentChecklist ?? "";
4555
+ const areaChecklist = req.params.areaChecklist ?? "";
4556
+ try {
4557
+ const data = await _getAllUnitChecklist({
4558
+ page,
4559
+ limit,
4560
+ search,
4561
+ site,
4562
+ type,
4563
+ parentChecklist,
4564
+ areaChecklist
4565
+ });
4566
+ res.json(data);
4567
+ return;
4568
+ } catch (error2) {
4569
+ logger25.log({ level: "error", message: error2.message });
4570
+ next(error2);
4571
+ return;
4572
+ }
4573
+ }
4574
+ async function approveUnitChecklist(req, res, next) {
4575
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
4576
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
4577
+ {}
4578
+ ) : {};
4579
+ const checkedBy = cookies["user"] || "";
4580
+ const payload = { id: req.params.id, checkedBy };
4581
+ const validation = Joi14.object({
4582
+ id: Joi14.string().hex().required(),
4583
+ checkedBy: Joi14.string().hex().required()
4584
+ });
4585
+ const { error } = validation.validate(payload);
4586
+ if (error) {
4587
+ logger25.log({ level: "error", message: error.message });
4588
+ next(new BadRequestError25(error.message));
4589
+ return;
4590
+ }
4591
+ try {
4592
+ const { id, ...value } = payload;
4593
+ await _approveUnitChecklist(id, value);
4594
+ res.json({ message: "Unit checklist approved successfully." });
4595
+ return;
4596
+ } catch (error2) {
4597
+ logger25.log({ level: "error", message: error2.message });
4598
+ next(error2);
4599
+ return;
4600
+ }
4601
+ }
4602
+ async function rejectUnitChecklist(req, res, next) {
4603
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
4604
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
4605
+ {}
4606
+ ) : {};
4607
+ const checkedBy = cookies["user"] || "";
4608
+ if (req.body.workOrder) {
4609
+ req.body.workOrder.createdBy = checkedBy;
4610
+ }
4611
+ const payload = { id: req.params.id, checkedBy, ...req.body };
4612
+ const validation = Joi14.object({
4613
+ id: Joi14.string().hex().required(),
4614
+ attachments: Joi14.array().items(Joi14.string()).optional(),
4615
+ remarks: Joi14.string().required(),
4616
+ workOrder: workOrderSchema.optional(),
4617
+ checkedBy: Joi14.string().hex().required()
4618
+ });
4619
+ const { error } = validation.validate(payload);
4620
+ if (error) {
4621
+ logger25.log({ level: "error", message: error.message });
4622
+ next(new BadRequestError25(error.message));
4623
+ return;
4624
+ }
4625
+ try {
4626
+ const { id, attachments, remarks, workOrder, ...value } = payload;
4627
+ value.metadata = {
4628
+ attachments: attachments || [],
4629
+ remarks: remarks || "",
4630
+ workOrder
4631
+ };
4632
+ if (value.metadata.workOrder) {
4633
+ if (value.metadata.workOrder.category) {
4634
+ value.metadata.workOrder.category = value.metadata.workOrder.category;
4635
+ }
4636
+ if (value.metadata.workOrder.serviceProvider) {
4637
+ value.metadata.workOrder.serviceProvider = value.metadata.workOrder.serviceProvider;
4638
+ }
4639
+ value.metadata.workOrder.createdBy = checkedBy;
4640
+ }
4641
+ const fullHost = req.headers.origin;
4642
+ await _rejectUnitChecklist(id, value, fullHost);
4643
+ res.json({ message: "Unit checklist rejected successfully." });
4644
+ return;
4645
+ } catch (error2) {
4646
+ logger25.log({ level: "error", message: error2.message });
4647
+ next(error2);
4648
+ return;
4649
+ }
4650
+ }
4651
+ return {
4652
+ createUnitChecklist,
4653
+ getAllUnitChecklist,
4654
+ approveUnitChecklist,
4655
+ rejectUnitChecklist
2753
4656
  };
2754
4657
  }
2755
4658
  export {
2756
4659
  MArea,
4660
+ MAreaChecklist,
2757
4661
  MParentChecklist,
2758
4662
  MScheduleTaskArea,
2759
4663
  MToiletLocation,
2760
4664
  MUnit,
4665
+ MUnitChecklist,
4666
+ allowedStatus,
4667
+ allowedTypes,
4668
+ areaChecklistSchema,
2761
4669
  areaSchema,
2762
4670
  parentChecklistSchema,
2763
4671
  scheduleTaskAreaSchema,
2764
4672
  toiletLocationSchema,
4673
+ unitChecklistSchema,
2765
4674
  unitSchema,
4675
+ useAreaChecklistController,
4676
+ useAreaChecklistRepo,
2766
4677
  useAreaController,
2767
4678
  useAreaRepository,
2768
4679
  useAreaService,
2769
- useParentCheckilstController,
4680
+ useParentChecklistController,
2770
4681
  useParentChecklistRepo,
2771
4682
  useScheduleTaskAreaController,
2772
4683
  useScheduleTaskAreaRepository,
@@ -2774,6 +4685,8 @@ export {
2774
4685
  useToiletLocationController,
2775
4686
  useToiletLocationRepository,
2776
4687
  useToiletLocationService,
4688
+ useUnitChecklistController,
4689
+ useUnitChecklistRepo,
2777
4690
  useUnitController,
2778
4691
  useUnitRepository,
2779
4692
  useUnitService