@7365admin1/module-hygiene 4.7.0 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,11 @@
1
1
  // src/models/hygiene-base.model.ts
2
2
  var allowedTypes = ["common", "toilet"];
3
- var allowedStatus = ["ready", "ongoing", "completed"];
3
+ var allowedStatus = [
4
+ "open",
5
+ "ongoing",
6
+ "completed",
7
+ "closed"
8
+ ];
4
9
  var allowedPeriods = ["today", "thisWeek", "thisMonth"];
5
10
 
6
11
  // src/repositories/hygiene-dashboard.repository.ts
@@ -1310,10 +1315,14 @@ function useAreaService() {
1310
1315
  try {
1311
1316
  dataArray = JSON.parse(dataJson);
1312
1317
  } catch (error) {
1313
- throw new BadRequestError7("Invalid JSON format for data in excel");
1318
+ throw new BadRequestError7(
1319
+ "We couldn't read the uploaded file. Please make sure you're uploading the correct file and try again."
1320
+ );
1314
1321
  }
1315
1322
  if (!dataArray || dataArray.length === 0) {
1316
- throw new NotFoundError2("No data found in the uploaded file");
1323
+ throw new NotFoundError2(
1324
+ "The uploaded file is empty. Please make sure your file contains data and try again."
1325
+ );
1317
1326
  }
1318
1327
  let availableUnits = [];
1319
1328
  try {
@@ -1414,33 +1423,35 @@ function useAreaService() {
1414
1423
  }
1415
1424
  }
1416
1425
  }
1417
- let message = `Upload completed: ${insertedAreaIds.length} areas successfully created`;
1426
+ let message = `Upload complete! ${insertedAreaIds.length} ${insertedAreaIds.length === 1 ? "area was" : "areas were"} successfully added`;
1418
1427
  if (duplicateAreas.length > 0) {
1419
- message += `, ${duplicateAreas.length} areas skipped (already exist)`;
1428
+ message += `, ${duplicateAreas.length} ${duplicateAreas.length === 1 ? "area was" : "areas were"} skipped because they already exist`;
1420
1429
  }
1421
1430
  if (failedAreas.length > 0) {
1422
- message += `, ${failedAreas.length} areas failed`;
1431
+ message += `, ${failedAreas.length} ${failedAreas.length === 1 ? "area" : "areas"} could not be saved`;
1423
1432
  }
1424
1433
  if (skippedRows.length > 0) {
1425
- message += `, ${skippedRows.length} rows skipped (invalid data)`;
1434
+ message += `, ${skippedRows.length} ${skippedRows.length === 1 ? "row was" : "rows were"} skipped due to missing information`;
1426
1435
  }
1427
1436
  logger8.info(message);
1428
1437
  if (insertedAreaIds.length === 0) {
1429
1438
  if (duplicateAreas.length > 0 && failedAreas.length === 0 && skippedRows.length === 0) {
1430
1439
  return {
1431
- message: `No new areas were created. All ${duplicateAreas.length} areas already exist in the system: ${duplicateAreas.join(", ")}`
1440
+ message: `No new areas were added. All ${duplicateAreas.length} ${duplicateAreas.length === 1 ? "area" : "areas"} in your file already exist in the system: ${duplicateAreas.join(
1441
+ ", "
1442
+ )}.`
1432
1443
  };
1433
1444
  } else if (failedAreas.length > 0) {
1434
1445
  throw new BadRequestError7(
1435
- `No areas were created. ${failedAreas.length} areas failed due to errors. Please check your data format and ensure area names are valid.`
1446
+ `No areas were added. ${failedAreas.length} ${failedAreas.length === 1 ? "area" : "areas"} could not be saved. Please review the area names and information in your file, then try again.`
1436
1447
  );
1437
1448
  } else if (skippedRows.length > 0 && duplicateAreas.length === 0) {
1438
1449
  throw new BadRequestError7(
1439
- `No areas were created. All ${skippedRows.length} rows contained invalid or missing data.`
1450
+ `No areas were added. ${skippedRows.length} ${skippedRows.length === 1 ? "row" : "rows"} in your file had missing or incomplete information. Please fill in all required fields and try again.`
1440
1451
  );
1441
1452
  } else {
1442
1453
  return {
1443
- message: `No new areas were created. ${duplicateAreas.length} areas already exist, ${skippedRows.length} rows had invalid data.`
1454
+ message: `No new areas were added. ${duplicateAreas.length} ${duplicateAreas.length === 1 ? "area" : "areas"} already exist${skippedRows.length > 0 ? `, and ${skippedRows.length} ${skippedRows.length === 1 ? "row" : "rows"} had missing or incomplete information` : ""}.`
1444
1455
  };
1445
1456
  }
1446
1457
  }
@@ -1451,11 +1462,11 @@ function useAreaService() {
1451
1462
  throw error;
1452
1463
  } else if (error.message.includes("validation")) {
1453
1464
  throw new BadRequestError7(
1454
- "Upload failed due to invalid data format. Please check that all required fields are properly filled."
1465
+ "Upload failed because some required information is missing or incorrect. Please review your file and make sure all fields are filled in properly."
1455
1466
  );
1456
1467
  } else {
1457
1468
  throw new BadRequestError7(
1458
- `Upload failed: ${error.message || "Please check your data format and try again."}`
1469
+ "Something went wrong while uploading. Please check your file and try again."
1459
1470
  );
1460
1471
  }
1461
1472
  }
@@ -1464,11 +1475,15 @@ function useAreaService() {
1464
1475
  try {
1465
1476
  const areas = await getAreasForChecklist(site);
1466
1477
  if (!areas || !Array.isArray(areas) || areas.length === 0) {
1467
- throw new BadRequestError7("No data found to export");
1478
+ throw new BadRequestError7(
1479
+ "There are no areas to export yet. Please add some areas first, then try again."
1480
+ );
1468
1481
  }
1469
1482
  const excelBuffer = await generateAreaExcel(areas);
1470
1483
  if (!excelBuffer || excelBuffer.length === 0) {
1471
- throw new Error("Generated Excel file is empty or invalid.");
1484
+ throw new Error(
1485
+ "Something went wrong while preparing your export file. Please try again."
1486
+ );
1472
1487
  }
1473
1488
  return excelBuffer;
1474
1489
  } catch (error) {
@@ -1773,10 +1788,14 @@ function useUnitService() {
1773
1788
  try {
1774
1789
  dataArray = JSON.parse(dataJson);
1775
1790
  } catch (error) {
1776
- throw new BadRequestError9("Invalid JSON format for data in excel");
1791
+ throw new BadRequestError9(
1792
+ "We couldn't read the uploaded file. Please make sure you're uploading the correct file and try again."
1793
+ );
1777
1794
  }
1778
1795
  if (!dataArray || dataArray.length === 0) {
1779
- throw new NotFoundError3("No data found in the uploaded file");
1796
+ throw new NotFoundError3(
1797
+ "The uploaded file is empty. Please make sure your file contains data and try again."
1798
+ );
1780
1799
  }
1781
1800
  const insertedUnitIds = [];
1782
1801
  const duplicateUnits = [];
@@ -1817,29 +1836,31 @@ function useUnitService() {
1817
1836
  }
1818
1837
  }
1819
1838
  }
1820
- let message = `Upload completed: ${insertedUnitIds.length} units successfully created`;
1839
+ let message = `Upload complete! ${insertedUnitIds.length} ${insertedUnitIds.length === 1 ? "unit was" : "units were"} successfully added`;
1821
1840
  if (duplicateUnits.length > 0) {
1822
- message += `, ${duplicateUnits.length} units skipped (already exist)`;
1841
+ message += `, ${duplicateUnits.length} ${duplicateUnits.length === 1 ? "unit was" : "units were"} skipped because they already exist`;
1823
1842
  }
1824
1843
  if (failedUnits.length > 0) {
1825
- message += `, ${failedUnits.length} units failed`;
1844
+ message += `, ${failedUnits.length} ${failedUnits.length === 1 ? "unit" : "units"} could not be saved`;
1826
1845
  }
1827
1846
  if (skippedRows.length > 0) {
1828
- message += `, ${skippedRows.length} rows skipped (invalid data)`;
1847
+ message += `, ${skippedRows.length} ${skippedRows.length === 1 ? "row was" : "rows were"} skipped due to missing information`;
1829
1848
  }
1830
1849
  logger11.info(message);
1831
1850
  if (insertedUnitIds.length === 0) {
1832
1851
  if (duplicateUnits.length > 0 && failedUnits.length === 0) {
1833
1852
  throw new BadRequestError9(
1834
- `No new units were created. All ${duplicateUnits.length} units already exist in the system: ${duplicateUnits.join(", ")}`
1853
+ `No new units were added. All ${duplicateUnits.length} ${duplicateUnits.length === 1 ? "unit" : "units"} in your file already exist in the system: ${duplicateUnits.join(
1854
+ ", "
1855
+ )}.`
1835
1856
  );
1836
1857
  } else if (failedUnits.length > 0) {
1837
1858
  throw new BadRequestError9(
1838
- `No units were created. Please check your data format and ensure unit names are valid.`
1859
+ `No units were added. ${failedUnits.length} ${failedUnits.length === 1 ? "unit" : "units"} could not be saved. Please review the unit names in your file and try again.`
1839
1860
  );
1840
1861
  } else if (skippedRows.length > 0) {
1841
1862
  throw new BadRequestError9(
1842
- `No units were created. All rows contained invalid or missing unit names.`
1863
+ `No units were added. ${skippedRows.length} ${skippedRows.length === 1 ? "row" : "rows"} in your file had missing or incomplete information. Please fill in all required fields and try again.`
1843
1864
  );
1844
1865
  }
1845
1866
  }
@@ -1850,15 +1871,15 @@ function useUnitService() {
1850
1871
  throw error;
1851
1872
  } else if (error.message.includes("duplicate")) {
1852
1873
  throw new BadRequestError9(
1853
- "Upload failed due to duplicate unit names. Please ensure all unit names are unique."
1874
+ "Upload failed because some unit names are already taken. Please make sure each unit has a unique name and try again."
1854
1875
  );
1855
1876
  } else if (error.message.includes("validation")) {
1856
1877
  throw new BadRequestError9(
1857
- "Upload failed due to invalid data format. Please check that all required fields are properly filled."
1878
+ "Upload failed because some required information is missing or incorrect. Please review your file and make sure all fields are filled in properly."
1858
1879
  );
1859
1880
  } else {
1860
1881
  throw new BadRequestError9(
1861
- `Upload failed: ${error.message || "Please check your data format and try again."}`
1882
+ "Something went wrong while uploading. Please check your file and try again."
1862
1883
  );
1863
1884
  }
1864
1885
  }
@@ -1890,7 +1911,9 @@ function useUnitService() {
1890
1911
  session?.startTransaction();
1891
1912
  const isExistingArea = await verifyAreaByUnitId(_id);
1892
1913
  if (isExistingArea) {
1893
- throw new BadRequestError9("Failed to delete unit, unit is in use.");
1914
+ throw new BadRequestError9(
1915
+ "This unit can't be deleted because it's currently being used in one or more areas. Please remove it from those areas first, then try again."
1916
+ );
1894
1917
  }
1895
1918
  const result = await _deleteUnit(_id, session);
1896
1919
  await session?.commitTransaction();
@@ -1916,11 +1939,15 @@ function useUnitService() {
1916
1939
  site
1917
1940
  });
1918
1941
  if (!data || !data.items || data.items.length === 0) {
1919
- throw new BadRequestError9("No data found to export");
1942
+ throw new BadRequestError9(
1943
+ "There are no units to export yet. Please add some units first, then try again."
1944
+ );
1920
1945
  }
1921
1946
  const excelBuffer = await _generateUnitExcel(data.items);
1922
1947
  if (!excelBuffer || excelBuffer.length === 0) {
1923
- throw new Error("Generated Excel file is empty or invalid.");
1948
+ throw new Error(
1949
+ "Something went wrong while preparing your export file. Please try again."
1950
+ );
1924
1951
  }
1925
1952
  return excelBuffer;
1926
1953
  } catch (error) {
@@ -2127,7 +2154,7 @@ function MParentChecklist(value) {
2127
2154
  }
2128
2155
  return {
2129
2156
  site: value.site,
2130
- status: "ready",
2157
+ status: "open",
2131
2158
  createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
2132
2159
  updatedAt: value.updatedAt ?? ""
2133
2160
  };
@@ -2325,18 +2352,23 @@ function useParentChecklistRepo() {
2325
2352
  status: {
2326
2353
  $switch: {
2327
2354
  branches: [
2328
- { case: { $eq: ["$status", "ready"] }, then: "Ready" },
2355
+ { case: { $eq: ["$status", "open"] }, then: "Open" },
2329
2356
  {
2330
2357
  case: { $eq: ["$status", "ongoing"] },
2331
2358
  then: "Ongoing"
2332
2359
  },
2333
- { case: { $eq: ["$status", "completed"] }, then: "Completed" }
2360
+ { case: { $eq: ["$status", "completed"] }, then: "Completed" },
2361
+ {
2362
+ case: { $eq: ["$status", "closed"] },
2363
+ then: "Closed"
2364
+ }
2334
2365
  ],
2335
2366
  default: "$status"
2336
2367
  }
2337
2368
  },
2338
2369
  completedAt: 1,
2339
- createdAt: 1
2370
+ createdAt: 1,
2371
+ closeIn: { $add: ["$createdAt", 24 * 60 * 60 * 1e3] }
2340
2372
  }
2341
2373
  });
2342
2374
  pipeline.push(
@@ -2424,11 +2456,42 @@ function useParentChecklistRepo() {
2424
2456
  throw error;
2425
2457
  }
2426
2458
  }
2459
+ async function closeExpiredParentChecklists() {
2460
+ try {
2461
+ const expiryDate = new Date(Date.now() - 24 * 60 * 60 * 1e3);
2462
+ const result = await collection.updateMany(
2463
+ {
2464
+ status: { $in: ["open", "ongoing", "completed"] },
2465
+ createdAt: { $lte: expiryDate }
2466
+ },
2467
+ {
2468
+ $set: {
2469
+ status: "closed",
2470
+ updatedAt: /* @__PURE__ */ new Date()
2471
+ }
2472
+ }
2473
+ );
2474
+ if (result.modifiedCount > 0) {
2475
+ delNamespace().catch((err) => {
2476
+ logger14.error(
2477
+ "Failed to invalidate cache after closing expired parent checklists",
2478
+ err
2479
+ );
2480
+ });
2481
+ logger14.info(`Closed ${result.modifiedCount} expired parent checklists`);
2482
+ }
2483
+ return result.modifiedCount;
2484
+ } catch (error) {
2485
+ logger14.error("Failed to close expired parent checklists", error);
2486
+ throw error;
2487
+ }
2488
+ }
2427
2489
  return {
2428
2490
  createIndex,
2429
2491
  createParentChecklist,
2430
2492
  getAllParentChecklist,
2431
- updateParentChecklistStatuses
2493
+ updateParentChecklistStatuses,
2494
+ closeExpiredParentChecklists
2432
2495
  };
2433
2496
  }
2434
2497
 
@@ -2510,7 +2573,7 @@ function useParentChecklistController() {
2510
2573
  import Joi8 from "joi";
2511
2574
  import { ObjectId as ObjectId8 } from "mongodb";
2512
2575
  import { BadRequestError as BadRequestError14, logger as logger16 } from "@7365admin1/node-server-utils";
2513
- var allowedChecklistStatus = ["ready", "completed"];
2576
+ var allowedChecklistStatus = ["open", "completed", "closed"];
2514
2577
  var areaChecklistSchema = Joi8.object({
2515
2578
  schedule: Joi8.string().hex().required(),
2516
2579
  area: Joi8.string().hex().required(),
@@ -2558,7 +2621,7 @@ function MAreaChecklist(value) {
2558
2621
  name: unit.name,
2559
2622
  approve: false,
2560
2623
  reject: false,
2561
- status: "ready",
2624
+ status: "open",
2562
2625
  remarks: "",
2563
2626
  completedBy: "",
2564
2627
  timestamp: ""
@@ -2579,7 +2642,7 @@ function MAreaChecklist(value) {
2579
2642
  name: value.name,
2580
2643
  type: value.type,
2581
2644
  checklist: value.checklist || [],
2582
- status: "ready",
2645
+ status: "open",
2583
2646
  createdBy: value.createdBy,
2584
2647
  createdAt: /* @__PURE__ */ new Date(),
2585
2648
  completedAt: "",
@@ -2751,11 +2814,15 @@ function useAreaChecklistRepo() {
2751
2814
  status: {
2752
2815
  $switch: {
2753
2816
  branches: [
2754
- { case: { $eq: ["$status", "ready"] }, then: "Ready" },
2817
+ { case: { $eq: ["$status", "open"] }, then: "Open" },
2755
2818
  { case: { $eq: ["$status", "ongoing"] }, then: "Ongoing" },
2756
2819
  {
2757
2820
  case: { $eq: ["$status", "completed"] },
2758
2821
  then: "Completed"
2822
+ },
2823
+ {
2824
+ case: { $eq: ["$status", "closed"] },
2825
+ then: "Closed"
2759
2826
  }
2760
2827
  ],
2761
2828
  default: "$status"
@@ -2857,11 +2924,15 @@ function useAreaChecklistRepo() {
2857
2924
  status: {
2858
2925
  $switch: {
2859
2926
  branches: [
2860
- { case: { $eq: ["$status", "ready"] }, then: "Ready" },
2927
+ { case: { $eq: ["$status", "open"] }, then: "Open" },
2861
2928
  { case: { $eq: ["$status", "ongoing"] }, then: "Ongoing" },
2862
2929
  {
2863
2930
  case: { $eq: ["$status", "completed"] },
2864
2931
  then: "Completed"
2932
+ },
2933
+ {
2934
+ case: { $eq: ["$status", "closed"] },
2935
+ then: "Closed"
2865
2936
  }
2866
2937
  ],
2867
2938
  default: "$status"
@@ -2926,11 +2997,15 @@ function useAreaChecklistRepo() {
2926
2997
  status: {
2927
2998
  $switch: {
2928
2999
  branches: [
2929
- { case: { $eq: ["$status", "ready"] }, then: "Ready" },
3000
+ { case: { $eq: ["$status", "open"] }, then: "Open" },
2930
3001
  { case: { $eq: ["$status", "ongoing"] }, then: "Ongoing" },
2931
3002
  {
2932
3003
  case: { $eq: ["$status", "completed"] },
2933
3004
  then: "Completed"
3005
+ },
3006
+ {
3007
+ case: { $eq: ["$status", "closed"] },
3008
+ then: "Closed"
2934
3009
  }
2935
3010
  ],
2936
3011
  default: "$status"
@@ -2990,12 +3065,16 @@ function useAreaChecklistRepo() {
2990
3065
  $switch: {
2991
3066
  branches: [
2992
3067
  {
2993
- case: { $eq: ["$checklist.units.status", "ready"] },
2994
- then: "Ready"
3068
+ case: { $eq: ["$checklist.units.status", "open"] },
3069
+ then: "Open"
2995
3070
  },
2996
3071
  {
2997
3072
  case: { $eq: ["$checklist.units.status", "completed"] },
2998
3073
  then: "Completed"
3074
+ },
3075
+ {
3076
+ case: { $eq: ["$checklist.units.status", "closed"] },
3077
+ then: "Closed"
2999
3078
  }
3000
3079
  ],
3001
3080
  default: "$checklist.units.status"
@@ -3096,6 +3175,38 @@ function useAreaChecklistRepo() {
3096
3175
  preserveNullAndEmptyArrays: false
3097
3176
  }
3098
3177
  },
3178
+ {
3179
+ $addFields: {
3180
+ isCompleted: { $ne: ["$checklist.units.completedBy", ""] }
3181
+ }
3182
+ },
3183
+ {
3184
+ $lookup: {
3185
+ from: "users",
3186
+ let: { completedById: "$checklist.units.completedBy" },
3187
+ pipeline: [
3188
+ {
3189
+ $match: {
3190
+ $expr: {
3191
+ $and: [
3192
+ { $ne: ["$$completedById", ""] },
3193
+ { $eq: ["$_id", "$$completedById"] }
3194
+ ]
3195
+ }
3196
+ }
3197
+ },
3198
+ { $project: { name: 1 } }
3199
+ ],
3200
+ as: "completedBy"
3201
+ }
3202
+ },
3203
+ {
3204
+ $unwind: {
3205
+ path: "$completedBy",
3206
+ preserveNullAndEmptyArrays: true
3207
+ }
3208
+ },
3209
+ { $sort: { set: 1, isCompleted: -1, "checklist.units.timestamp": 1 } },
3099
3210
  {
3100
3211
  $project: {
3101
3212
  _id: 0,
@@ -3110,25 +3221,30 @@ function useAreaChecklistRepo() {
3110
3221
  $switch: {
3111
3222
  branches: [
3112
3223
  {
3113
- case: { $eq: ["$checklist.units.status", "ready"] },
3114
- then: "Ready"
3224
+ case: { $eq: ["$checklist.units.status", "open"] },
3225
+ then: "Open"
3115
3226
  },
3116
3227
  {
3117
3228
  case: { $eq: ["$checklist.units.status", "completed"] },
3118
3229
  then: "Completed"
3230
+ },
3231
+ {
3232
+ case: { $eq: ["$checklist.units.status", "closed"] },
3233
+ then: "Closed"
3119
3234
  }
3120
3235
  ],
3121
3236
  default: "$checklist.units.status"
3122
3237
  }
3123
- }
3238
+ },
3239
+ completedByName: "$completedBy.name"
3124
3240
  }
3125
3241
  },
3126
- { $sort: { set: 1, name: 1 } },
3127
3242
  {
3128
3243
  $group: {
3129
3244
  _id: "$set",
3130
3245
  remarks: { $first: "$remarks" },
3131
3246
  attachment: { $first: "$attachment" },
3247
+ completedByName: { $first: "$completedByName" },
3132
3248
  units: {
3133
3249
  $push: {
3134
3250
  unit: "$unit",
@@ -3136,7 +3252,8 @@ function useAreaChecklistRepo() {
3136
3252
  approve: "$approve",
3137
3253
  reject: "$reject",
3138
3254
  status: "$status",
3139
- remarks: "$remarks"
3255
+ remarks: "$remarks",
3256
+ completedByName: "$completedByName"
3140
3257
  }
3141
3258
  }
3142
3259
  }
@@ -3147,6 +3264,7 @@ function useAreaChecklistRepo() {
3147
3264
  set: "$_id",
3148
3265
  remarks: "$remarks",
3149
3266
  attachment: "$attachment",
3267
+ completedByName: 1,
3150
3268
  units: 1
3151
3269
  }
3152
3270
  },
@@ -3245,7 +3363,7 @@ function useAreaChecklistRepo() {
3245
3363
  } else if (value.reject === true) {
3246
3364
  updateValue["checklist.$[checklist].units.$[unit].approve"] = false;
3247
3365
  updateValue["checklist.$[checklist].units.$[unit].reject"] = true;
3248
- updateValue["checklist.$[checklist].units.$[unit].status"] = "ready";
3366
+ updateValue["checklist.$[checklist].units.$[unit].status"] = "open";
3249
3367
  }
3250
3368
  if (value.remarks) {
3251
3369
  updateValue["checklist.$[checklist].units.$[unit].remarks"] = value.remarks;
@@ -3371,6 +3489,42 @@ function useAreaChecklistRepo() {
3371
3489
  return 0;
3372
3490
  }
3373
3491
  }
3492
+ async function closeExpiredAreaChecklists() {
3493
+ try {
3494
+ const expiryDate = new Date(Date.now() - 24 * 60 * 60 * 1e3);
3495
+ const result = await collection.updateMany(
3496
+ {
3497
+ status: { $in: ["open", "ongoing", "completed"] },
3498
+ createdAt: { $lte: expiryDate }
3499
+ },
3500
+ {
3501
+ $set: {
3502
+ status: "closed",
3503
+ updatedAt: /* @__PURE__ */ new Date(),
3504
+ "checklist.$[].units.$[unit].status": "closed"
3505
+ }
3506
+ },
3507
+ {
3508
+ arrayFilters: [{ "unit.status": { $in: ["open", "completed"] } }]
3509
+ }
3510
+ );
3511
+ if (result.modifiedCount > 0) {
3512
+ delNamespace().catch((err) => {
3513
+ logger17.error(
3514
+ "Failed to invalidate cache after closing expired area checklists",
3515
+ err
3516
+ );
3517
+ });
3518
+ logger17.info(
3519
+ `Closed ${result.modifiedCount} expired area checklists and their units`
3520
+ );
3521
+ }
3522
+ return result.modifiedCount;
3523
+ } catch (error) {
3524
+ logger17.error("Failed to close expired area checklists", error);
3525
+ throw error;
3526
+ }
3527
+ }
3374
3528
  return {
3375
3529
  createIndex,
3376
3530
  createTextIndex,
@@ -3384,7 +3538,8 @@ function useAreaChecklistRepo() {
3384
3538
  updateAreaChecklist,
3385
3539
  updateAreaChecklistStatus,
3386
3540
  updateAreaChecklistUnits,
3387
- getMaxSetNumberForArea
3541
+ getMaxSetNumberForArea,
3542
+ closeExpiredAreaChecklists
3388
3543
  };
3389
3544
  }
3390
3545
 
@@ -3480,12 +3635,12 @@ function useAreaChecklistService() {
3480
3635
  },
3481
3636
  session
3482
3637
  );
3483
- let areaStatus = "ready";
3638
+ let areaStatus = "open";
3484
3639
  if (allUnitsResult && allUnitsResult.items && allUnitsResult.items.length > 0) {
3485
3640
  const sets = allUnitsResult.items;
3486
3641
  const allUnits = sets.flatMap((set2) => set2.units || []);
3487
- const readyCount = allUnits.filter(
3488
- (unit) => unit.status === "Ready"
3642
+ const openCount = allUnits.filter(
3643
+ (unit) => unit.status === "Open"
3489
3644
  ).length;
3490
3645
  const completedCount = allUnits.filter(
3491
3646
  (unit) => unit.status === "Completed"
@@ -3493,8 +3648,8 @@ function useAreaChecklistService() {
3493
3648
  const totalCount = allUnits.length;
3494
3649
  if (completedCount === totalCount) {
3495
3650
  areaStatus = "completed";
3496
- } else if (readyCount === totalCount) {
3497
- areaStatus = "ready";
3651
+ } else if (openCount === totalCount) {
3652
+ areaStatus = "open";
3498
3653
  } else {
3499
3654
  areaStatus = "ongoing";
3500
3655
  }
@@ -3513,18 +3668,18 @@ function useAreaChecklistService() {
3513
3668
  );
3514
3669
  if (allAreasResult && allAreasResult.items && allAreasResult.items.length > 0) {
3515
3670
  const areas = allAreasResult.items;
3516
- const readyAreasCount = areas.filter(
3517
- (area) => area.status === "Ready"
3671
+ const openAreasCount = areas.filter(
3672
+ (area) => area.status === "Open"
3518
3673
  ).length;
3519
3674
  const completedAreasCount = areas.filter(
3520
3675
  (area) => area.status === "Completed"
3521
3676
  ).length;
3522
3677
  const totalAreasCount = areas.length;
3523
- let parentStatus = "ready";
3678
+ let parentStatus = "open";
3524
3679
  if (completedAreasCount === totalAreasCount) {
3525
3680
  parentStatus = "completed";
3526
- } else if (readyAreasCount === totalAreasCount) {
3527
- parentStatus = "ready";
3681
+ } else if (openAreasCount === totalAreasCount) {
3682
+ parentStatus = "open";
3528
3683
  } else {
3529
3684
  parentStatus = "ongoing";
3530
3685
  }
@@ -3535,7 +3690,7 @@ function useAreaChecklistService() {
3535
3690
  );
3536
3691
  } else {
3537
3692
  logger18.info(
3538
- "No area checklists found, keeping parent status as ready"
3693
+ "No area checklists found, keeping parent status as open"
3539
3694
  );
3540
3695
  }
3541
3696
  }
@@ -3556,7 +3711,223 @@ function useAreaChecklistService() {
3556
3711
 
3557
3712
  // src/controllers/hygiene-area-checklist.controller.ts
3558
3713
  import Joi9 from "joi";
3559
- import { BadRequestError as BadRequestError16, logger as logger19 } from "@7365admin1/node-server-utils";
3714
+ import { BadRequestError as BadRequestError16, InternalServerError as InternalServerError7, logger as logger20 } from "@7365admin1/node-server-utils";
3715
+
3716
+ // src/services/hygiene-checklist-pdf.service.ts
3717
+ import { launch } from "puppeteer";
3718
+ import { InternalServerError as InternalServerError6, useAtlas as useAtlas8 } from "@7365admin1/node-server-utils";
3719
+ import { ObjectId as ObjectId10 } from "mongodb";
3720
+ function escapeHtml(text) {
3721
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
3722
+ }
3723
+ function buildChecklistHtml(areaChecklists) {
3724
+ const areaSections = areaChecklists.map((area) => {
3725
+ const sortedChecklist = [...area.checklist || []].sort(
3726
+ (a, b) => a.set - b.set
3727
+ );
3728
+ const setRows = sortedChecklist.map((setItem) => {
3729
+ const unitRows = (setItem.units || []).map(
3730
+ (unit) => `
3731
+ <tr>
3732
+ <td class="unit-name">${escapeHtml(unit.name || "")}</td>
3733
+ <td class="icon-cell">${unit.reject ? '<span class="reject-icon">&#10007;</span>' : ""}</td>
3734
+ <td class="icon-cell">${unit.approve ? '<span class="approve-icon">&#10003;</span>' : ""}</td>
3735
+ </tr>`
3736
+ ).join("");
3737
+ return `
3738
+ <tr class="set-header-row">
3739
+ <td colspan="3">Set ${setItem.set}</td>
3740
+ </tr>
3741
+ ${unitRows}`;
3742
+ }).join("");
3743
+ return `
3744
+ <div class="area-section">
3745
+ <div class="area-header">
3746
+ <span class="area-name">${escapeHtml(area.name || "")}</span>
3747
+ <span class="area-type">${escapeHtml(area.type || "")}</span>
3748
+ </div>
3749
+ <table class="checklist-table">
3750
+ <thead>
3751
+ <tr>
3752
+ <th class="col-unit">Unit</th>
3753
+ <th class="col-icon">&#10007;</th>
3754
+ <th class="col-icon">&#10003;</th>
3755
+ </tr>
3756
+ </thead>
3757
+ <tbody>
3758
+ ${setRows}
3759
+ </tbody>
3760
+ </table>
3761
+ </div>`;
3762
+ }).join("");
3763
+ return `<!DOCTYPE html>
3764
+ <html lang="en">
3765
+ <head>
3766
+ <meta charset="UTF-8">
3767
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
3768
+ <title>Checklist</title>
3769
+ <style>
3770
+ * {
3771
+ margin: 0;
3772
+ padding: 0;
3773
+ box-sizing: border-box;
3774
+ }
3775
+ body {
3776
+ font-family: Arial, Helvetica, sans-serif;
3777
+ background: #ffffff;
3778
+ padding: 30px 35px;
3779
+ color: #1a1a1a;
3780
+ font-size: 13px;
3781
+ }
3782
+ .page-header {
3783
+ display: flex;
3784
+ align-items: center;
3785
+ justify-content: flex-start;
3786
+ background: #1a3a6b;
3787
+ margin-bottom: 24px;
3788
+ padding: 12px 16px;
3789
+ border-radius: 4px;
3790
+ }
3791
+ .page-logo {
3792
+ height: 40px;
3793
+ width: auto;
3794
+ object-fit: contain;
3795
+ }
3796
+ .area-section {
3797
+ margin-bottom: 22px;
3798
+ border: 1px solid #dce1e7;
3799
+ border-radius: 4px;
3800
+ overflow: hidden;
3801
+ page-break-inside: avoid;
3802
+ }
3803
+ .area-header {
3804
+ display: flex;
3805
+ align-items: center;
3806
+ justify-content: space-between;
3807
+ background: #2c3e50;
3808
+ color: #ffffff;
3809
+ padding: 9px 12px;
3810
+ }
3811
+ .area-name {
3812
+ font-size: 14px;
3813
+ font-weight: 600;
3814
+ }
3815
+ .area-type {
3816
+ font-size: 11px;
3817
+ text-transform: capitalize;
3818
+ background: rgba(255,255,255,0.2);
3819
+ padding: 2px 8px;
3820
+ border-radius: 10px;
3821
+ }
3822
+ .checklist-table {
3823
+ width: 100%;
3824
+ border-collapse: collapse;
3825
+ }
3826
+ .checklist-table thead tr th {
3827
+ background: #34495e;
3828
+ color: #ffffff;
3829
+ padding: 7px 10px;
3830
+ text-align: left;
3831
+ font-size: 12px;
3832
+ font-weight: 600;
3833
+ letter-spacing: 0.3px;
3834
+ }
3835
+ .checklist-table thead tr th.col-icon {
3836
+ text-align: center;
3837
+ width: 52px;
3838
+ }
3839
+ .checklist-table thead tr th.col-unit {
3840
+ width: auto;
3841
+ }
3842
+ .set-header-row td {
3843
+ background: #ecf0f1;
3844
+ color: #555;
3845
+ font-weight: 700;
3846
+ font-size: 12px;
3847
+ padding: 5px 10px;
3848
+ border-bottom: 1px solid #dce1e7;
3849
+ text-transform: uppercase;
3850
+ letter-spacing: 0.4px;
3851
+ }
3852
+ .checklist-table tbody tr td {
3853
+ padding: 7px 10px;
3854
+ border-bottom: 1px solid #f0f2f4;
3855
+ font-size: 13px;
3856
+ }
3857
+ .checklist-table tbody tr:last-child td {
3858
+ border-bottom: none;
3859
+ }
3860
+ .icon-cell {
3861
+ text-align: center;
3862
+ width: 52px;
3863
+ }
3864
+ .approve-icon {
3865
+ color: #27ae60;
3866
+ font-size: 16px;
3867
+ font-weight: bold;
3868
+ }
3869
+ .reject-icon {
3870
+ color: #e74c3c;
3871
+ font-size: 16px;
3872
+ font-weight: bold;
3873
+ }
3874
+ </style>
3875
+ </head>
3876
+ <body>
3877
+ <div class="page-header">
3878
+ <img class="page-logo" src="https://seven365-storage.sgp1.cdn.digitaloceanspaces.com/seven365-public/images/seven365-logo.png" alt="Seven365 Logo" />
3879
+ </div>
3880
+ ${areaSections}
3881
+ </body>
3882
+ </html>`;
3883
+ }
3884
+ function useChecklistPdfService() {
3885
+ async function generateChecklistPdf(scheduleId) {
3886
+ const db = useAtlas8.getDb();
3887
+ if (!db) {
3888
+ throw new InternalServerError6("Unable to connect to server.");
3889
+ }
3890
+ const collection = db.collection("site.cleaning.schedule.areas");
3891
+ let scheduleObjectId;
3892
+ try {
3893
+ scheduleObjectId = new ObjectId10(scheduleId);
3894
+ } catch {
3895
+ throw new InternalServerError6("Invalid schedule ID format.");
3896
+ }
3897
+ const areaChecklists = await collection.find({ schedule: scheduleObjectId }).sort({ createdAt: 1, name: 1 }).toArray();
3898
+ const html = buildChecklistHtml(areaChecklists);
3899
+ const browser = await launch({
3900
+ headless: true,
3901
+ executablePath: process.env.CHROME_BINARY,
3902
+ args: ["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage"]
3903
+ });
3904
+ try {
3905
+ const page = await browser.newPage();
3906
+ await page.setViewport({ width: 794, height: 1123 });
3907
+ await page.setContent(html, {
3908
+ waitUntil: ["load", "networkidle0"]
3909
+ });
3910
+ const pdfBuffer = await page.pdf({
3911
+ format: "A4",
3912
+ printBackground: true,
3913
+ margin: {
3914
+ top: "15mm",
3915
+ right: "15mm",
3916
+ bottom: "15mm",
3917
+ left: "15mm"
3918
+ }
3919
+ });
3920
+ return pdfBuffer;
3921
+ } finally {
3922
+ await browser.close();
3923
+ }
3924
+ }
3925
+ return {
3926
+ generateChecklistPdf
3927
+ };
3928
+ }
3929
+
3930
+ // src/controllers/hygiene-area-checklist.controller.ts
3560
3931
  function useAreaChecklistController() {
3561
3932
  const {
3562
3933
  getAllAreaChecklist: _getAllAreaChecklist,
@@ -3568,6 +3939,7 @@ function useAreaChecklistController() {
3568
3939
  createAreaChecklist: _createAreaChecklist,
3569
3940
  updateAreaChecklistUnits: _updateAreaChecklistUnits
3570
3941
  } = useAreaChecklistService();
3942
+ const { generateChecklistPdf: _generateChecklistPdf } = useChecklistPdfService();
3571
3943
  async function createAreaChecklist(req, res, next) {
3572
3944
  const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3573
3945
  (acc, [key, value2]) => ({ ...acc, [key]: value2 }),
@@ -3586,7 +3958,7 @@ function useAreaChecklistController() {
3586
3958
  });
3587
3959
  const { error, value } = validation.validate(payload);
3588
3960
  if (error) {
3589
- logger19.log({ level: "error", message: error.message });
3961
+ logger20.log({ level: "error", message: error.message });
3590
3962
  next(new BadRequestError16(error.message));
3591
3963
  return;
3592
3964
  }
@@ -3595,7 +3967,7 @@ function useAreaChecklistController() {
3595
3967
  res.status(201).json({ message: "Area checklist generated successfully." });
3596
3968
  return;
3597
3969
  } catch (error2) {
3598
- logger19.log({ level: "error", message: error2.message });
3970
+ logger20.log({ level: "error", message: error2.message });
3599
3971
  next(error2);
3600
3972
  return;
3601
3973
  }
@@ -3612,7 +3984,7 @@ function useAreaChecklistController() {
3612
3984
  });
3613
3985
  const { error } = validation.validate(query);
3614
3986
  if (error) {
3615
- logger19.log({ level: "error", message: error.message });
3987
+ logger20.log({ level: "error", message: error.message });
3616
3988
  next(new BadRequestError16(error.message));
3617
3989
  return;
3618
3990
  }
@@ -3634,7 +4006,7 @@ function useAreaChecklistController() {
3634
4006
  res.json(data);
3635
4007
  return;
3636
4008
  } catch (error2) {
3637
- logger19.log({ level: "error", message: error2.message });
4009
+ logger20.log({ level: "error", message: error2.message });
3638
4010
  next(error2);
3639
4011
  return;
3640
4012
  }
@@ -3652,7 +4024,7 @@ function useAreaChecklistController() {
3652
4024
  });
3653
4025
  const { error } = validation.validate(query);
3654
4026
  if (error) {
3655
- logger19.log({ level: "error", message: error.message });
4027
+ logger20.log({ level: "error", message: error.message });
3656
4028
  next(new BadRequestError16(error.message));
3657
4029
  return;
3658
4030
  }
@@ -3676,7 +4048,7 @@ function useAreaChecklistController() {
3676
4048
  res.json(data);
3677
4049
  return;
3678
4050
  } catch (error2) {
3679
- logger19.log({ level: "error", message: error2.message });
4051
+ logger20.log({ level: "error", message: error2.message });
3680
4052
  next(error2);
3681
4053
  return;
3682
4054
  }
@@ -3686,7 +4058,7 @@ function useAreaChecklistController() {
3686
4058
  const _id = req.params.id;
3687
4059
  const { error, value } = validation.validate(_id);
3688
4060
  if (error) {
3689
- logger19.log({ level: "error", message: error.message });
4061
+ logger20.log({ level: "error", message: error.message });
3690
4062
  next(new BadRequestError16(error.message));
3691
4063
  return;
3692
4064
  }
@@ -3695,7 +4067,7 @@ function useAreaChecklistController() {
3695
4067
  res.json(data);
3696
4068
  return;
3697
4069
  } catch (error2) {
3698
- logger19.log({ level: "error", message: error2.message });
4070
+ logger20.log({ level: "error", message: error2.message });
3699
4071
  next(error2);
3700
4072
  return;
3701
4073
  }
@@ -3710,7 +4082,7 @@ function useAreaChecklistController() {
3710
4082
  });
3711
4083
  const { error } = validation.validate(query);
3712
4084
  if (error) {
3713
- logger19.log({ level: "error", message: error.message });
4085
+ logger20.log({ level: "error", message: error.message });
3714
4086
  next(new BadRequestError16(error.message));
3715
4087
  return;
3716
4088
  }
@@ -3728,7 +4100,7 @@ function useAreaChecklistController() {
3728
4100
  res.json(data);
3729
4101
  return;
3730
4102
  } catch (error2) {
3731
- logger19.log({ level: "error", message: error2.message });
4103
+ logger20.log({ level: "error", message: error2.message });
3732
4104
  next(error2);
3733
4105
  return;
3734
4106
  }
@@ -3767,7 +4139,7 @@ function useAreaChecklistController() {
3767
4139
  });
3768
4140
  const { error } = validation.validate(payload);
3769
4141
  if (error) {
3770
- logger19.log({ level: "error", message: error.message });
4142
+ logger20.log({ level: "error", message: error.message });
3771
4143
  next(new BadRequestError16(error.message));
3772
4144
  return;
3773
4145
  }
@@ -3777,7 +4149,39 @@ function useAreaChecklistController() {
3777
4149
  res.json({ message: "Area checklist updated successfully." });
3778
4150
  return;
3779
4151
  } catch (error2) {
3780
- logger19.log({ level: "error", message: error2.message });
4152
+ logger20.log({ level: "error", message: error2.message });
4153
+ next(error2);
4154
+ return;
4155
+ }
4156
+ }
4157
+ async function downloadChecklistPdf(req, res, next) {
4158
+ const validation = Joi9.string().hex().required();
4159
+ const schedule = req.params.schedule;
4160
+ const { error, value } = validation.validate(schedule);
4161
+ if (error) {
4162
+ logger20.log({ level: "error", message: error.message });
4163
+ next(new BadRequestError16(error.message));
4164
+ return;
4165
+ }
4166
+ try {
4167
+ const pdfBuffer = await _generateChecklistPdf(value);
4168
+ if (!pdfBuffer || pdfBuffer.length === 0) {
4169
+ throw new InternalServerError7("Generated checklist PDF is empty or invalid.");
4170
+ }
4171
+ const date = /* @__PURE__ */ new Date();
4172
+ const formattedDate = `${String(date.getDate()).padStart(2, "0")}_${String(
4173
+ date.getMonth() + 1
4174
+ ).padStart(2, "0")}_${date.getFullYear()}`;
4175
+ res.setHeader("Content-Type", "application/pdf");
4176
+ res.setHeader(
4177
+ "Content-Disposition",
4178
+ `attachment; filename="CHECKLIST_${formattedDate}.pdf"`
4179
+ );
4180
+ res.setHeader("Content-Length", pdfBuffer.length);
4181
+ res.end(pdfBuffer);
4182
+ return;
4183
+ } catch (error2) {
4184
+ logger20.log({ level: "error", message: error2.message });
3781
4185
  next(error2);
3782
4186
  return;
3783
4187
  }
@@ -3788,14 +4192,15 @@ function useAreaChecklistController() {
3788
4192
  getAreaChecklistHistory,
3789
4193
  getAreaChecklistHistoryDetails,
3790
4194
  getAreaChecklistUnits,
3791
- updateAreaChecklistUnits
4195
+ updateAreaChecklistUnits,
4196
+ downloadChecklistPdf
3792
4197
  };
3793
4198
  }
3794
4199
 
3795
4200
  // src/models/hygiene-supply.model.ts
3796
4201
  import Joi10 from "joi";
3797
- import { ObjectId as ObjectId10 } from "mongodb";
3798
- import { BadRequestError as BadRequestError17, logger as logger20 } from "@7365admin1/node-server-utils";
4202
+ import { ObjectId as ObjectId11 } from "mongodb";
4203
+ import { BadRequestError as BadRequestError17, logger as logger21 } from "@7365admin1/node-server-utils";
3799
4204
  var supplySchema = Joi10.object({
3800
4205
  site: Joi10.string().hex().required(),
3801
4206
  name: Joi10.string().required(),
@@ -3804,12 +4209,12 @@ var supplySchema = Joi10.object({
3804
4209
  function MSupply(value) {
3805
4210
  const { error } = supplySchema.validate(value);
3806
4211
  if (error) {
3807
- logger20.info(`Hygiene Supply Model: ${error.message}`);
4212
+ logger21.info(`Hygiene Supply Model: ${error.message}`);
3808
4213
  throw new BadRequestError17(error.message);
3809
4214
  }
3810
4215
  if (value.site) {
3811
4216
  try {
3812
- value.site = new ObjectId10(value.site);
4217
+ value.site = new ObjectId11(value.site);
3813
4218
  } catch (error2) {
3814
4219
  throw new BadRequestError17("Invalid site ID format.");
3815
4220
  }
@@ -3827,21 +4232,21 @@ function MSupply(value) {
3827
4232
  }
3828
4233
 
3829
4234
  // src/repositories/hygiene-supply.repository.ts
3830
- import { ObjectId as ObjectId11 } from "mongodb";
4235
+ import { ObjectId as ObjectId12 } from "mongodb";
3831
4236
  import {
3832
- useAtlas as useAtlas8,
3833
- InternalServerError as InternalServerError6,
4237
+ useAtlas as useAtlas9,
4238
+ InternalServerError as InternalServerError8,
3834
4239
  paginate as paginate5,
3835
4240
  BadRequestError as BadRequestError18,
3836
4241
  useCache as useCache6,
3837
- logger as logger21,
4242
+ logger as logger22,
3838
4243
  makeCacheKey as makeCacheKey6,
3839
4244
  NotFoundError as NotFoundError4
3840
4245
  } from "@7365admin1/node-server-utils";
3841
4246
  function useSupplyRepository() {
3842
- const db = useAtlas8.getDb();
4247
+ const db = useAtlas9.getDb();
3843
4248
  if (!db) {
3844
- throw new InternalServerError6("Unable to connect to server.");
4249
+ throw new InternalServerError8("Unable to connect to server.");
3845
4250
  }
3846
4251
  const namespace_collection = "site.supplies";
3847
4252
  const collection = db.collection(namespace_collection);
@@ -3850,7 +4255,7 @@ function useSupplyRepository() {
3850
4255
  try {
3851
4256
  await collection.createIndexes([{ key: { site: 1 } }]);
3852
4257
  } catch (error) {
3853
- throw new InternalServerError6(
4258
+ throw new InternalServerError8(
3854
4259
  "Failed to create index on hygiene supply."
3855
4260
  );
3856
4261
  }
@@ -3859,7 +4264,7 @@ function useSupplyRepository() {
3859
4264
  try {
3860
4265
  await collection.createIndex({ name: "text" });
3861
4266
  } catch (error) {
3862
- throw new InternalServerError6(
4267
+ throw new InternalServerError8(
3863
4268
  "Failed to create text index on hygiene supply."
3864
4269
  );
3865
4270
  }
@@ -3871,7 +4276,7 @@ function useSupplyRepository() {
3871
4276
  { unique: true }
3872
4277
  );
3873
4278
  } catch (error) {
3874
- throw new InternalServerError6(
4279
+ throw new InternalServerError8(
3875
4280
  "Failed to create unique index on hygiene supply."
3876
4281
  );
3877
4282
  }
@@ -3881,9 +4286,9 @@ function useSupplyRepository() {
3881
4286
  value = MSupply(value);
3882
4287
  const res = await collection.insertOne(value, { session });
3883
4288
  delNamespace().then(() => {
3884
- logger21.info(`Cache cleared for namespace: ${namespace_collection}`);
4289
+ logger22.info(`Cache cleared for namespace: ${namespace_collection}`);
3885
4290
  }).catch((err) => {
3886
- logger21.error(
4291
+ logger22.error(
3887
4292
  `Failed to clear cache for namespace: ${namespace_collection}`,
3888
4293
  err
3889
4294
  );
@@ -3912,7 +4317,7 @@ function useSupplyRepository() {
3912
4317
  limit
3913
4318
  };
3914
4319
  try {
3915
- site = new ObjectId11(site);
4320
+ site = new ObjectId12(site);
3916
4321
  query.site = site;
3917
4322
  cacheOptions.site = site.toString();
3918
4323
  } catch (error) {
@@ -3925,7 +4330,7 @@ function useSupplyRepository() {
3925
4330
  const cacheKey = makeCacheKey6(namespace_collection, cacheOptions);
3926
4331
  const cachedData = await getCache(cacheKey);
3927
4332
  if (cachedData) {
3928
- logger21.info(`Cache hit for key: ${cacheKey}`);
4333
+ logger22.info(`Cache hit for key: ${cacheKey}`);
3929
4334
  return cachedData;
3930
4335
  }
3931
4336
  try {
@@ -3945,9 +4350,9 @@ function useSupplyRepository() {
3945
4350
  const length = await collection.countDocuments(query);
3946
4351
  const data = paginate5(items, page, limit, length);
3947
4352
  setCache(cacheKey, data, 15 * 60).then(() => {
3948
- logger21.info(`Cache set for key: ${cacheKey}`);
4353
+ logger22.info(`Cache set for key: ${cacheKey}`);
3949
4354
  }).catch((err) => {
3950
- logger21.error(`Failed to set cache for key: ${cacheKey}`, err);
4355
+ logger22.error(`Failed to set cache for key: ${cacheKey}`, err);
3951
4356
  });
3952
4357
  return data;
3953
4358
  } catch (error) {
@@ -3956,7 +4361,7 @@ function useSupplyRepository() {
3956
4361
  }
3957
4362
  async function getSupplyById(_id, session) {
3958
4363
  try {
3959
- _id = new ObjectId11(_id);
4364
+ _id = new ObjectId12(_id);
3960
4365
  } catch (error) {
3961
4366
  throw new BadRequestError18("Invalid supply ID format.");
3962
4367
  }
@@ -3970,11 +4375,11 @@ function useSupplyRepository() {
3970
4375
  if (!session) {
3971
4376
  const cachedData = await getCache(cacheKey);
3972
4377
  if (cachedData) {
3973
- logger21.info(`Cache hit for key: ${cacheKey}`);
4378
+ logger22.info(`Cache hit for key: ${cacheKey}`);
3974
4379
  return cachedData;
3975
4380
  }
3976
4381
  } else {
3977
- logger21.info(`Skipping cache during transaction for key: ${cacheKey}`);
4382
+ logger22.info(`Skipping cache during transaction for key: ${cacheKey}`);
3978
4383
  }
3979
4384
  try {
3980
4385
  const data = await collection.aggregate([
@@ -3991,9 +4396,9 @@ function useSupplyRepository() {
3991
4396
  throw new NotFoundError4("Supply not found.");
3992
4397
  }
3993
4398
  setCache(cacheKey, data[0], 15 * 60).then(() => {
3994
- logger21.info(`Cache set for key: ${cacheKey}`);
4399
+ logger22.info(`Cache set for key: ${cacheKey}`);
3995
4400
  }).catch((err) => {
3996
- logger21.error(`Failed to set cache for key: ${cacheKey}`, err);
4401
+ logger22.error(`Failed to set cache for key: ${cacheKey}`, err);
3997
4402
  });
3998
4403
  return data[0];
3999
4404
  } catch (error) {
@@ -4002,7 +4407,7 @@ function useSupplyRepository() {
4002
4407
  }
4003
4408
  async function updateSupply(_id, value, session) {
4004
4409
  try {
4005
- _id = new ObjectId11(_id);
4410
+ _id = new ObjectId12(_id);
4006
4411
  } catch (error) {
4007
4412
  throw new BadRequestError18("Invalid supply ID format.");
4008
4413
  }
@@ -4014,12 +4419,12 @@ function useSupplyRepository() {
4014
4419
  { session }
4015
4420
  );
4016
4421
  if (res.modifiedCount === 0) {
4017
- throw new InternalServerError6("Unable to update cleaning supply.");
4422
+ throw new InternalServerError8("Unable to update cleaning supply.");
4018
4423
  }
4019
4424
  delNamespace().then(() => {
4020
- logger21.info(`Cache cleared for namespace: ${namespace_collection}`);
4425
+ logger22.info(`Cache cleared for namespace: ${namespace_collection}`);
4021
4426
  }).catch((err) => {
4022
- logger21.error(
4427
+ logger22.error(
4023
4428
  `Failed to clear cache for namespace: ${namespace_collection}`,
4024
4429
  err
4025
4430
  );
@@ -4035,7 +4440,7 @@ function useSupplyRepository() {
4035
4440
  }
4036
4441
  async function deleteSupply(_id, session) {
4037
4442
  try {
4038
- _id = new ObjectId11(_id);
4443
+ _id = new ObjectId12(_id);
4039
4444
  } catch (error) {
4040
4445
  throw new BadRequestError18("Invalid supply ID format.");
4041
4446
  }
@@ -4051,12 +4456,12 @@ function useSupplyRepository() {
4051
4456
  { session }
4052
4457
  );
4053
4458
  if (res.modifiedCount === 0) {
4054
- throw new InternalServerError6("Unable to delete supply.");
4459
+ throw new InternalServerError8("Unable to delete supply.");
4055
4460
  }
4056
4461
  delNamespace().then(() => {
4057
- logger21.info(`Cache cleared for namespace: ${namespace_collection}`);
4462
+ logger22.info(`Cache cleared for namespace: ${namespace_collection}`);
4058
4463
  }).catch((err) => {
4059
- logger21.error(
4464
+ logger22.error(
4060
4465
  `Failed to clear cache for namespace: ${namespace_collection}`,
4061
4466
  err
4062
4467
  );
@@ -4080,7 +4485,7 @@ function useSupplyRepository() {
4080
4485
 
4081
4486
  // src/controllers/hygiene-supply.controller.ts
4082
4487
  import Joi11 from "joi";
4083
- import { BadRequestError as BadRequestError19, logger as logger22 } from "@7365admin1/node-server-utils";
4488
+ import { BadRequestError as BadRequestError19, logger as logger23 } from "@7365admin1/node-server-utils";
4084
4489
  function useSupplyController() {
4085
4490
  const {
4086
4491
  createSupply: _createSupply,
@@ -4093,7 +4498,7 @@ function useSupplyController() {
4093
4498
  const payload = { ...req.body, ...req.params };
4094
4499
  const { error } = supplySchema.validate(payload);
4095
4500
  if (error) {
4096
- logger22.log({ level: "error", message: error.message });
4501
+ logger23.log({ level: "error", message: error.message });
4097
4502
  next(new BadRequestError19(error.message));
4098
4503
  return;
4099
4504
  }
@@ -4102,7 +4507,7 @@ function useSupplyController() {
4102
4507
  res.status(201).json({ message: "Supply created successfully.", id });
4103
4508
  return;
4104
4509
  } catch (error2) {
4105
- logger22.log({ level: "error", message: error2.message });
4510
+ logger23.log({ level: "error", message: error2.message });
4106
4511
  next(error2);
4107
4512
  return;
4108
4513
  }
@@ -4117,7 +4522,7 @@ function useSupplyController() {
4117
4522
  });
4118
4523
  const { error } = validation.validate(query);
4119
4524
  if (error) {
4120
- logger22.log({ level: "error", message: error.message });
4525
+ logger23.log({ level: "error", message: error.message });
4121
4526
  next(new BadRequestError19(error.message));
4122
4527
  return;
4123
4528
  }
@@ -4135,7 +4540,7 @@ function useSupplyController() {
4135
4540
  res.json(data);
4136
4541
  return;
4137
4542
  } catch (error2) {
4138
- logger22.log({ level: "error", message: error2.message });
4543
+ logger23.log({ level: "error", message: error2.message });
4139
4544
  next(error2);
4140
4545
  return;
4141
4546
  }
@@ -4145,7 +4550,7 @@ function useSupplyController() {
4145
4550
  const _id = req.params.id;
4146
4551
  const { error, value } = validation.validate(_id);
4147
4552
  if (error) {
4148
- logger22.log({ level: "error", message: error.message });
4553
+ logger23.log({ level: "error", message: error.message });
4149
4554
  next(new BadRequestError19(error.message));
4150
4555
  return;
4151
4556
  }
@@ -4154,7 +4559,7 @@ function useSupplyController() {
4154
4559
  res.json(data);
4155
4560
  return;
4156
4561
  } catch (error2) {
4157
- logger22.log({ level: "error", message: error2.message });
4562
+ logger23.log({ level: "error", message: error2.message });
4158
4563
  next(error2);
4159
4564
  return;
4160
4565
  }
@@ -4169,7 +4574,7 @@ function useSupplyController() {
4169
4574
  });
4170
4575
  const { error } = validation.validate(payload);
4171
4576
  if (error) {
4172
- logger22.log({ level: "error", message: error.message });
4577
+ logger23.log({ level: "error", message: error.message });
4173
4578
  next(new BadRequestError19(error.message));
4174
4579
  return;
4175
4580
  }
@@ -4179,7 +4584,7 @@ function useSupplyController() {
4179
4584
  res.json({ message: "Supply updated successfully." });
4180
4585
  return;
4181
4586
  } catch (error2) {
4182
- logger22.log({ level: "error", message: error2.message });
4587
+ logger23.log({ level: "error", message: error2.message });
4183
4588
  next(error2);
4184
4589
  return;
4185
4590
  }
@@ -4191,7 +4596,7 @@ function useSupplyController() {
4191
4596
  });
4192
4597
  const { error, value } = validation.validate({ id });
4193
4598
  if (error) {
4194
- logger22.log({ level: "error", message: error.message });
4599
+ logger23.log({ level: "error", message: error.message });
4195
4600
  next(new BadRequestError19(error.message));
4196
4601
  return;
4197
4602
  }
@@ -4200,7 +4605,7 @@ function useSupplyController() {
4200
4605
  res.json({ message: "Supply deleted successfully." });
4201
4606
  return;
4202
4607
  } catch (error2) {
4203
- logger22.log({ level: "error", message: error2.message });
4608
+ logger23.log({ level: "error", message: error2.message });
4204
4609
  next(error2);
4205
4610
  return;
4206
4611
  }
@@ -4216,8 +4621,8 @@ function useSupplyController() {
4216
4621
 
4217
4622
  // src/models/hygiene-stock.model.ts
4218
4623
  import Joi12 from "joi";
4219
- import { ObjectId as ObjectId12 } from "mongodb";
4220
- import { BadRequestError as BadRequestError20, logger as logger23 } from "@7365admin1/node-server-utils";
4624
+ import { ObjectId as ObjectId13 } from "mongodb";
4625
+ import { BadRequestError as BadRequestError20, logger as logger24 } from "@7365admin1/node-server-utils";
4221
4626
  var stockSchema = Joi12.object({
4222
4627
  site: Joi12.string().hex().required(),
4223
4628
  supply: Joi12.string().hex().required(),
@@ -4229,19 +4634,19 @@ var stockSchema = Joi12.object({
4229
4634
  function MStock(value) {
4230
4635
  const { error } = stockSchema.validate(value);
4231
4636
  if (error) {
4232
- logger23.info(`Hygiene Stock Model: ${error.message}`);
4637
+ logger24.info(`Hygiene Stock Model: ${error.message}`);
4233
4638
  throw new BadRequestError20(error.message);
4234
4639
  }
4235
4640
  if (value.site) {
4236
4641
  try {
4237
- value.site = new ObjectId12(value.site);
4642
+ value.site = new ObjectId13(value.site);
4238
4643
  } catch (error2) {
4239
4644
  throw new BadRequestError20("Invalid site ID format.");
4240
4645
  }
4241
4646
  }
4242
4647
  if (value.supply) {
4243
4648
  try {
4244
- value.supply = new ObjectId12(value.supply);
4649
+ value.supply = new ObjectId13(value.supply);
4245
4650
  } catch (error2) {
4246
4651
  throw new BadRequestError20("Invalid supply ID format.");
4247
4652
  }
@@ -4261,20 +4666,20 @@ function MStock(value) {
4261
4666
  }
4262
4667
 
4263
4668
  // src/repositories/hygiene-stock.repository.ts
4264
- import { ObjectId as ObjectId13 } from "mongodb";
4669
+ import { ObjectId as ObjectId14 } from "mongodb";
4265
4670
  import {
4266
- useAtlas as useAtlas9,
4267
- InternalServerError as InternalServerError7,
4671
+ useAtlas as useAtlas10,
4672
+ InternalServerError as InternalServerError9,
4268
4673
  BadRequestError as BadRequestError21,
4269
4674
  useCache as useCache7,
4270
- logger as logger24,
4675
+ logger as logger25,
4271
4676
  makeCacheKey as makeCacheKey7,
4272
4677
  paginate as paginate6
4273
4678
  } from "@7365admin1/node-server-utils";
4274
4679
  function useStockRepository() {
4275
- const db = useAtlas9.getDb();
4680
+ const db = useAtlas10.getDb();
4276
4681
  if (!db) {
4277
- throw new InternalServerError7("Unable to connect to server.");
4682
+ throw new InternalServerError9("Unable to connect to server.");
4278
4683
  }
4279
4684
  const namespace_collection = "site.supply.stocks";
4280
4685
  const supply_collection = "site.supplies";
@@ -4290,7 +4695,7 @@ function useStockRepository() {
4290
4695
  { key: { status: 1 } }
4291
4696
  ]);
4292
4697
  } catch (error) {
4293
- throw new InternalServerError7("Failed to create index on hygiene stock.");
4698
+ throw new InternalServerError9("Failed to create index on hygiene stock.");
4294
4699
  }
4295
4700
  }
4296
4701
  async function createStock(value, session) {
@@ -4298,17 +4703,17 @@ function useStockRepository() {
4298
4703
  value = MStock(value);
4299
4704
  const res = await collection.insertOne(value, { session });
4300
4705
  delNamespace().then(() => {
4301
- logger24.info(`Cache cleared for namespace: ${namespace_collection}`);
4706
+ logger25.info(`Cache cleared for namespace: ${namespace_collection}`);
4302
4707
  }).catch((err) => {
4303
- logger24.error(
4708
+ logger25.error(
4304
4709
  `Failed to clear cache for namespace: ${namespace_collection}`,
4305
4710
  err
4306
4711
  );
4307
4712
  });
4308
4713
  delSupplyNamespace().then(() => {
4309
- logger24.info(`Cache cleared for namespace: ${supply_collection}`);
4714
+ logger25.info(`Cache cleared for namespace: ${supply_collection}`);
4310
4715
  }).catch((err) => {
4311
- logger24.error(
4716
+ logger25.error(
4312
4717
  `Failed to clear cache for namespace: ${supply_collection}`,
4313
4718
  err
4314
4719
  );
@@ -4334,14 +4739,14 @@ function useStockRepository() {
4334
4739
  limit
4335
4740
  };
4336
4741
  try {
4337
- site = new ObjectId13(site);
4742
+ site = new ObjectId14(site);
4338
4743
  query.site = site;
4339
4744
  cacheOptions.site = site.toString();
4340
4745
  } catch (error) {
4341
4746
  throw new BadRequestError21("Invalid site ID format.");
4342
4747
  }
4343
4748
  try {
4344
- supply = new ObjectId13(supply);
4749
+ supply = new ObjectId14(supply);
4345
4750
  query.supply = supply;
4346
4751
  cacheOptions.supply = supply.toString();
4347
4752
  } catch (error) {
@@ -4354,7 +4759,7 @@ function useStockRepository() {
4354
4759
  const cacheKey = makeCacheKey7(namespace_collection, cacheOptions);
4355
4760
  const cachedData = await getCache(cacheKey);
4356
4761
  if (cachedData) {
4357
- logger24.info(`Cache hit for key: ${cacheKey}`);
4762
+ logger25.info(`Cache hit for key: ${cacheKey}`);
4358
4763
  return cachedData;
4359
4764
  }
4360
4765
  try {
@@ -4375,9 +4780,9 @@ function useStockRepository() {
4375
4780
  const length = await collection.countDocuments(query);
4376
4781
  const data = paginate6(items, page, limit, length);
4377
4782
  setCache(cacheKey, data, 15 * 60).then(() => {
4378
- logger24.info(`Cache set for key: ${cacheKey}`);
4783
+ logger25.info(`Cache set for key: ${cacheKey}`);
4379
4784
  }).catch((err) => {
4380
- logger24.error(`Failed to set cache for key: ${cacheKey}`, err);
4785
+ logger25.error(`Failed to set cache for key: ${cacheKey}`, err);
4381
4786
  });
4382
4787
  return data;
4383
4788
  } catch (error) {
@@ -4394,7 +4799,7 @@ function useStockRepository() {
4394
4799
  // src/services/hygiene-stock.service.ts
4395
4800
  import {
4396
4801
  NotFoundError as NotFoundError5,
4397
- useAtlas as useAtlas10,
4802
+ useAtlas as useAtlas11,
4398
4803
  BadRequestError as BadRequestError22
4399
4804
  } from "@7365admin1/node-server-utils";
4400
4805
  function useStockService() {
@@ -4403,7 +4808,7 @@ function useStockService() {
4403
4808
  async function createStock(value, out = false, session) {
4404
4809
  let ownSession = false;
4405
4810
  if (!session) {
4406
- session = useAtlas10.getClient()?.startSession();
4811
+ session = useAtlas11.getClient()?.startSession();
4407
4812
  ownSession = true;
4408
4813
  }
4409
4814
  try {
@@ -4447,7 +4852,7 @@ function useStockService() {
4447
4852
 
4448
4853
  // src/controllers/hygiene-stock.controller.ts
4449
4854
  import Joi13 from "joi";
4450
- import { BadRequestError as BadRequestError23, logger as logger25 } from "@7365admin1/node-server-utils";
4855
+ import { BadRequestError as BadRequestError23, logger as logger26 } from "@7365admin1/node-server-utils";
4451
4856
  function useStockController() {
4452
4857
  const { getStocksBySupplyId: _getStocksBySupplyId } = useStockRepository();
4453
4858
  const { createStock: _createStock } = useStockService();
@@ -4461,7 +4866,7 @@ function useStockController() {
4461
4866
  });
4462
4867
  const { error } = validation.validate(payload);
4463
4868
  if (error) {
4464
- logger25.log({ level: "error", message: error.message });
4869
+ logger26.log({ level: "error", message: error.message });
4465
4870
  next(new BadRequestError23(error.message));
4466
4871
  return;
4467
4872
  }
@@ -4470,7 +4875,7 @@ function useStockController() {
4470
4875
  res.status(201).json({ message: "Stock created successfully.", id });
4471
4876
  return;
4472
4877
  } catch (error2) {
4473
- logger25.log({ level: "error", message: error2.message });
4878
+ logger26.log({ level: "error", message: error2.message });
4474
4879
  next(error2);
4475
4880
  return;
4476
4881
  }
@@ -4486,7 +4891,7 @@ function useStockController() {
4486
4891
  });
4487
4892
  const { error } = validation.validate(query);
4488
4893
  if (error) {
4489
- logger25.log({ level: "error", message: error.message });
4894
+ logger26.log({ level: "error", message: error.message });
4490
4895
  next(new BadRequestError23(error.message));
4491
4896
  return;
4492
4897
  }
@@ -4506,7 +4911,7 @@ function useStockController() {
4506
4911
  res.json(data);
4507
4912
  return;
4508
4913
  } catch (error2) {
4509
- logger25.log({ level: "error", message: error2.message });
4914
+ logger26.log({ level: "error", message: error2.message });
4510
4915
  next(error2);
4511
4916
  return;
4512
4917
  }
@@ -4519,8 +4924,8 @@ function useStockController() {
4519
4924
 
4520
4925
  // src/models/hygiene-checkout-item.model.ts
4521
4926
  import Joi14 from "joi";
4522
- import { ObjectId as ObjectId14 } from "mongodb";
4523
- import { BadRequestError as BadRequestError24, logger as logger26 } from "@7365admin1/node-server-utils";
4927
+ import { ObjectId as ObjectId15 } from "mongodb";
4928
+ import { BadRequestError as BadRequestError24, logger as logger27 } from "@7365admin1/node-server-utils";
4524
4929
  var allowedCheckOutItemStatus = ["pending", "completed"];
4525
4930
  var checkOutItemSchema = Joi14.object({
4526
4931
  site: Joi14.string().hex().required(),
@@ -4534,19 +4939,19 @@ var checkOutItemSchema = Joi14.object({
4534
4939
  function MCheckOutItem(value) {
4535
4940
  const { error } = checkOutItemSchema.validate(value);
4536
4941
  if (error) {
4537
- logger26.info(`Hygiene Check Out Item Model: ${error.message}`);
4942
+ logger27.info(`Hygiene Check Out Item Model: ${error.message}`);
4538
4943
  throw new BadRequestError24(error.message);
4539
4944
  }
4540
4945
  if (value.site) {
4541
4946
  try {
4542
- value.site = new ObjectId14(value.site);
4947
+ value.site = new ObjectId15(value.site);
4543
4948
  } catch (error2) {
4544
4949
  throw new BadRequestError24("Invalid site ID format.");
4545
4950
  }
4546
4951
  }
4547
4952
  if (value.supply) {
4548
4953
  try {
4549
- value.supply = new ObjectId14(value.supply);
4954
+ value.supply = new ObjectId15(value.supply);
4550
4955
  } catch (error2) {
4551
4956
  throw new BadRequestError24("Invalid supply ID format.");
4552
4957
  }
@@ -4567,21 +4972,21 @@ function MCheckOutItem(value) {
4567
4972
  }
4568
4973
 
4569
4974
  // src/repositories/hygiene-checkout-item.repository.ts
4570
- import { ObjectId as ObjectId15 } from "mongodb";
4975
+ import { ObjectId as ObjectId16 } from "mongodb";
4571
4976
  import {
4572
- useAtlas as useAtlas11,
4573
- InternalServerError as InternalServerError8,
4977
+ useAtlas as useAtlas12,
4978
+ InternalServerError as InternalServerError10,
4574
4979
  useCache as useCache8,
4575
- logger as logger27,
4980
+ logger as logger28,
4576
4981
  makeCacheKey as makeCacheKey8,
4577
4982
  paginate as paginate7,
4578
4983
  BadRequestError as BadRequestError25,
4579
4984
  NotFoundError as NotFoundError6
4580
4985
  } from "@7365admin1/node-server-utils";
4581
4986
  function useCheckOutItemRepository() {
4582
- const db = useAtlas11.getDb();
4987
+ const db = useAtlas12.getDb();
4583
4988
  if (!db) {
4584
- throw new InternalServerError8("Unable to connect to server.");
4989
+ throw new InternalServerError10("Unable to connect to server.");
4585
4990
  }
4586
4991
  const namespace_collection = "site.supply.checkouts";
4587
4992
  const collection = db.collection(namespace_collection);
@@ -4594,7 +4999,7 @@ function useCheckOutItemRepository() {
4594
4999
  { key: { status: 1 } }
4595
5000
  ]);
4596
5001
  } catch (error) {
4597
- throw new InternalServerError8(
5002
+ throw new InternalServerError10(
4598
5003
  "Failed to create index on hygiene check out item."
4599
5004
  );
4600
5005
  }
@@ -4603,7 +5008,7 @@ function useCheckOutItemRepository() {
4603
5008
  try {
4604
5009
  await collection.createIndex({ supplyName: "text" });
4605
5010
  } catch (error) {
4606
- throw new InternalServerError8(
5011
+ throw new InternalServerError10(
4607
5012
  "Failed to create text index on hygiene supply."
4608
5013
  );
4609
5014
  }
@@ -4613,9 +5018,9 @@ function useCheckOutItemRepository() {
4613
5018
  value = MCheckOutItem(value);
4614
5019
  const res = await collection.insertOne(value, { session });
4615
5020
  delNamespace().then(() => {
4616
- logger27.info(`Cache cleared for namespace: ${namespace_collection}`);
5021
+ logger28.info(`Cache cleared for namespace: ${namespace_collection}`);
4617
5022
  }).catch((err) => {
4618
- logger27.error(
5023
+ logger28.error(
4619
5024
  `Failed to clear cache for namespace: ${namespace_collection}`,
4620
5025
  err
4621
5026
  );
@@ -4640,7 +5045,7 @@ function useCheckOutItemRepository() {
4640
5045
  limit
4641
5046
  };
4642
5047
  try {
4643
- site = new ObjectId15(site);
5048
+ site = new ObjectId16(site);
4644
5049
  query.site = site;
4645
5050
  cacheOptions.site = site.toString();
4646
5051
  } catch (error) {
@@ -4653,7 +5058,7 @@ function useCheckOutItemRepository() {
4653
5058
  const cacheKey = makeCacheKey8(namespace_collection, cacheOptions);
4654
5059
  const cachedData = await getCache(cacheKey);
4655
5060
  if (cachedData) {
4656
- logger27.info(`Cache hit for key: ${cacheKey}`);
5061
+ logger28.info(`Cache hit for key: ${cacheKey}`);
4657
5062
  return cachedData;
4658
5063
  }
4659
5064
  try {
@@ -4702,9 +5107,9 @@ function useCheckOutItemRepository() {
4702
5107
  const length = await collection.countDocuments(query);
4703
5108
  const data = paginate7(items, page, limit, length);
4704
5109
  setCache(cacheKey, data, 15 * 60).then(() => {
4705
- logger27.info(`Cache set for key: ${cacheKey}`);
5110
+ logger28.info(`Cache set for key: ${cacheKey}`);
4706
5111
  }).catch((err) => {
4707
- logger27.error(`Failed to set cache for key: ${cacheKey}`, err);
5112
+ logger28.error(`Failed to set cache for key: ${cacheKey}`, err);
4708
5113
  });
4709
5114
  return data;
4710
5115
  } catch (error) {
@@ -4713,7 +5118,7 @@ function useCheckOutItemRepository() {
4713
5118
  }
4714
5119
  async function getCheckOutItemById(_id, session) {
4715
5120
  try {
4716
- _id = new ObjectId15(_id);
5121
+ _id = new ObjectId16(_id);
4717
5122
  } catch (error) {
4718
5123
  throw new BadRequestError25("Invalid check out item ID format.");
4719
5124
  }
@@ -4724,11 +5129,11 @@ function useCheckOutItemRepository() {
4724
5129
  if (!session) {
4725
5130
  const cachedData = await getCache(cacheKey);
4726
5131
  if (cachedData) {
4727
- logger27.info(`Cache hit for key: ${cacheKey}`);
5132
+ logger28.info(`Cache hit for key: ${cacheKey}`);
4728
5133
  return cachedData;
4729
5134
  }
4730
5135
  } else {
4731
- logger27.info(`Skipping cache during transaction for key: ${cacheKey}`);
5136
+ logger28.info(`Skipping cache during transaction for key: ${cacheKey}`);
4732
5137
  }
4733
5138
  try {
4734
5139
  const data = await collection.aggregate(
@@ -4766,9 +5171,9 @@ function useCheckOutItemRepository() {
4766
5171
  throw new NotFoundError6("Check out item not found.");
4767
5172
  }
4768
5173
  setCache(cacheKey, data[0], 15 * 60).then(() => {
4769
- logger27.info(`Cache set for key: ${cacheKey}`);
5174
+ logger28.info(`Cache set for key: ${cacheKey}`);
4770
5175
  }).catch((err) => {
4771
- logger27.error(`Failed to set cache for key: ${cacheKey}`, err);
5176
+ logger28.error(`Failed to set cache for key: ${cacheKey}`, err);
4772
5177
  });
4773
5178
  return data[0];
4774
5179
  } catch (error) {
@@ -4777,7 +5182,7 @@ function useCheckOutItemRepository() {
4777
5182
  }
4778
5183
  async function completeCheckOutItem(_id, session) {
4779
5184
  try {
4780
- _id = new ObjectId15(_id);
5185
+ _id = new ObjectId16(_id);
4781
5186
  } catch (error) {
4782
5187
  throw new BadRequestError25("Invalid check out item ID format.");
4783
5188
  }
@@ -4792,12 +5197,12 @@ function useCheckOutItemRepository() {
4792
5197
  { session }
4793
5198
  );
4794
5199
  if (res.modifiedCount === 0) {
4795
- throw new InternalServerError8("Unable to complete check out item.");
5200
+ throw new InternalServerError10("Unable to complete check out item.");
4796
5201
  }
4797
5202
  delNamespace().then(() => {
4798
- logger27.info(`Cache cleared for namespace: ${namespace_collection}`);
5203
+ logger28.info(`Cache cleared for namespace: ${namespace_collection}`);
4799
5204
  }).catch((err) => {
4800
- logger27.error(
5205
+ logger28.error(
4801
5206
  `Failed to clear cache for namespace: ${namespace_collection}`,
4802
5207
  err
4803
5208
  );
@@ -4819,7 +5224,7 @@ function useCheckOutItemRepository() {
4819
5224
 
4820
5225
  // src/services/hygiene-checkout-item.service.ts
4821
5226
  import { useUserRepo } from "@7365admin1/core";
4822
- import { BadRequestError as BadRequestError26, useAtlas as useAtlas12 } from "@7365admin1/node-server-utils";
5227
+ import { BadRequestError as BadRequestError26, useAtlas as useAtlas13 } from "@7365admin1/node-server-utils";
4823
5228
  function useCheckOutItemService() {
4824
5229
  const {
4825
5230
  createCheckOutItem: _createCheckOutItem,
@@ -4830,7 +5235,7 @@ function useCheckOutItemService() {
4830
5235
  const { getUserById } = useUserRepo();
4831
5236
  const { createStock } = useStockService();
4832
5237
  async function createCheckOutItem(value) {
4833
- const session = useAtlas12.getClient()?.startSession();
5238
+ const session = useAtlas13.getClient()?.startSession();
4834
5239
  try {
4835
5240
  session?.startTransaction();
4836
5241
  const supplyData = await getSupplyById(value.supply);
@@ -4870,10 +5275,10 @@ function useCheckOutItemService() {
4870
5275
  }
4871
5276
  }
4872
5277
  async function createCheckOutItemByBatch(value) {
4873
- const session = useAtlas12.getClient()?.startSession();
5278
+ const session = useAtlas13.getClient()?.startSession();
4874
5279
  try {
4875
5280
  session?.startTransaction();
4876
- const { site, attachment, createdBy, items } = value;
5281
+ const { site, createdBy, items } = value;
4877
5282
  const createdByData = await getUserById(createdBy);
4878
5283
  const createdCheckOutItemIds = [];
4879
5284
  for (const item of items) {
@@ -4884,7 +5289,7 @@ function useCheckOutItemService() {
4884
5289
  supply: item.supply,
4885
5290
  supplyName: supplyData?.name || "",
4886
5291
  qty: item.qty,
4887
- attachment,
5292
+ attachment: item.attachment,
4888
5293
  createdBy,
4889
5294
  createdByName: createdByData?.name || ""
4890
5295
  },
@@ -4918,7 +5323,7 @@ function useCheckOutItemService() {
4918
5323
 
4919
5324
  // src/controllers/hygiene-checkout-item.controller.ts
4920
5325
  import Joi15 from "joi";
4921
- import { BadRequestError as BadRequestError27, logger as logger28 } from "@7365admin1/node-server-utils";
5326
+ import { BadRequestError as BadRequestError27, logger as logger29 } from "@7365admin1/node-server-utils";
4922
5327
  function useCheckOutItemController() {
4923
5328
  const {
4924
5329
  getCheckOutItems: _getCheckOutItems,
@@ -4948,7 +5353,7 @@ function useCheckOutItemController() {
4948
5353
  });
4949
5354
  const { error } = validation.validate(payload);
4950
5355
  if (error) {
4951
- logger28.log({ level: "error", message: error.message });
5356
+ logger29.log({ level: "error", message: error.message });
4952
5357
  next(new BadRequestError27(error.message));
4953
5358
  return;
4954
5359
  }
@@ -4957,7 +5362,7 @@ function useCheckOutItemController() {
4957
5362
  res.status(201).json({ message: "Check out item created successfully.", id });
4958
5363
  return;
4959
5364
  } catch (error2) {
4960
- logger28.log({ level: "error", message: error2.message });
5365
+ logger29.log({ level: "error", message: error2.message });
4961
5366
  next(error2);
4962
5367
  return;
4963
5368
  }
@@ -4975,18 +5380,18 @@ function useCheckOutItemController() {
4975
5380
  };
4976
5381
  const validation = Joi15.object({
4977
5382
  site: Joi15.string().hex().required(),
4978
- attachment: Joi15.array().items(Joi15.string()).optional().allow(null),
4979
5383
  createdBy: Joi15.string().hex().required(),
4980
5384
  items: Joi15.array().items(
4981
5385
  Joi15.object({
4982
5386
  supply: Joi15.string().hex().required(),
4983
- qty: Joi15.number().min(0).required()
5387
+ qty: Joi15.number().min(0).required(),
5388
+ attachment: Joi15.array().items(Joi15.string()).optional().allow(null)
4984
5389
  })
4985
5390
  ).min(1).required()
4986
5391
  });
4987
5392
  const { error } = validation.validate(payload);
4988
5393
  if (error) {
4989
- logger28.log({ level: "error", message: error.message });
5394
+ logger29.log({ level: "error", message: error.message });
4990
5395
  next(new BadRequestError27(error.message));
4991
5396
  return;
4992
5397
  }
@@ -4995,7 +5400,7 @@ function useCheckOutItemController() {
4995
5400
  res.status(201).json({ message: "Check out items created successfully." });
4996
5401
  return;
4997
5402
  } catch (error2) {
4998
- logger28.log({ level: "error", message: error2.message });
5403
+ logger29.log({ level: "error", message: error2.message });
4999
5404
  next(error2);
5000
5405
  return;
5001
5406
  }
@@ -5010,7 +5415,7 @@ function useCheckOutItemController() {
5010
5415
  });
5011
5416
  const { error } = validation.validate(query);
5012
5417
  if (error) {
5013
- logger28.log({ level: "error", message: error.message });
5418
+ logger29.log({ level: "error", message: error.message });
5014
5419
  next(new BadRequestError27(error.message));
5015
5420
  return;
5016
5421
  }
@@ -5028,7 +5433,7 @@ function useCheckOutItemController() {
5028
5433
  res.json(data);
5029
5434
  return;
5030
5435
  } catch (error2) {
5031
- logger28.log({ level: "error", message: error2.message });
5436
+ logger29.log({ level: "error", message: error2.message });
5032
5437
  next(error2);
5033
5438
  return;
5034
5439
  }
@@ -5038,7 +5443,7 @@ function useCheckOutItemController() {
5038
5443
  const _id = req.params.id;
5039
5444
  const { error, value } = validation.validate(_id);
5040
5445
  if (error) {
5041
- logger28.log({ level: "error", message: error.message });
5446
+ logger29.log({ level: "error", message: error.message });
5042
5447
  next(new BadRequestError27(error.message));
5043
5448
  return;
5044
5449
  }
@@ -5047,7 +5452,7 @@ function useCheckOutItemController() {
5047
5452
  res.json(data);
5048
5453
  return;
5049
5454
  } catch (error2) {
5050
- logger28.log({ level: "error", message: error2.message });
5455
+ logger29.log({ level: "error", message: error2.message });
5051
5456
  next(error2);
5052
5457
  return;
5053
5458
  }
@@ -5061,15 +5466,16 @@ function useCheckOutItemController() {
5061
5466
  }
5062
5467
 
5063
5468
  // src/models/hygiene-schedule-task.model.ts
5064
- import { BadRequestError as BadRequestError28, logger as logger29 } from "@7365admin1/node-server-utils";
5469
+ import { BadRequestError as BadRequestError28, logger as logger30 } from "@7365admin1/node-server-utils";
5065
5470
  import Joi16 from "joi";
5066
- import { ObjectId as ObjectId16 } from "mongodb";
5471
+ import { ObjectId as ObjectId17 } from "mongodb";
5067
5472
  var scheduleTaskSchema = Joi16.object({
5068
5473
  site: Joi16.string().hex().required(),
5069
5474
  title: Joi16.string().required(),
5070
5475
  time: Joi16.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).required(),
5071
- startDate: Joi16.string().pattern(/^\d{4}-\d{2}-\d{2}$/).required(),
5072
- endDate: Joi16.string().pattern(/^\d{4}-\d{2}-\d{2}$/).optional().allow("", null),
5476
+ dates: Joi16.array().min(1).items(
5477
+ Joi16.string().pattern(/^\d{4}-\d{2}-\d{2}$/).required()
5478
+ ).required(),
5073
5479
  description: Joi16.string().optional().allow("", null),
5074
5480
  areas: Joi16.array().min(1).items(
5075
5481
  Joi16.object({
@@ -5082,12 +5488,12 @@ var scheduleTaskSchema = Joi16.object({
5082
5488
  function MScheduleTask(value) {
5083
5489
  const { error } = scheduleTaskSchema.validate(value);
5084
5490
  if (error) {
5085
- logger29.info(`Hygiene Schedule Task Model: ${error.message}`);
5491
+ logger30.info(`Hygiene Schedule Task Model: ${error.message}`);
5086
5492
  throw new BadRequestError28(error.message);
5087
5493
  }
5088
5494
  if (value.site) {
5089
5495
  try {
5090
- value.site = new ObjectId16(value.site);
5496
+ value.site = new ObjectId17(value.site);
5091
5497
  } catch (error2) {
5092
5498
  throw new BadRequestError28("Invalid site ID format.");
5093
5499
  }
@@ -5097,7 +5503,7 @@ function MScheduleTask(value) {
5097
5503
  try {
5098
5504
  return {
5099
5505
  name: area.name,
5100
- value: new ObjectId16(area.value.toString())
5506
+ value: new ObjectId17(area.value.toString())
5101
5507
  };
5102
5508
  } catch (error2) {
5103
5509
  throw new BadRequestError28(`Invalid area value format: ${area.name}`);
@@ -5106,7 +5512,7 @@ function MScheduleTask(value) {
5106
5512
  }
5107
5513
  if (value.createdBy) {
5108
5514
  try {
5109
- value.createdBy = new ObjectId16(value.createdBy);
5515
+ value.createdBy = new ObjectId17(value.createdBy);
5110
5516
  } catch (error2) {
5111
5517
  throw new BadRequestError28("Invalid createdBy ID format.");
5112
5518
  }
@@ -5115,8 +5521,7 @@ function MScheduleTask(value) {
5115
5521
  site: value.site,
5116
5522
  title: value.title,
5117
5523
  time: value.time,
5118
- startDate: value.startDate,
5119
- endDate: value.endDate,
5524
+ dates: value.dates,
5120
5525
  description: value.description,
5121
5526
  areas: value.areas,
5122
5527
  status: "active",
@@ -5128,21 +5533,21 @@ function MScheduleTask(value) {
5128
5533
  }
5129
5534
 
5130
5535
  // src/repositories/hygiene-schedule-task.repository.ts
5131
- import { ObjectId as ObjectId17 } from "mongodb";
5536
+ import { ObjectId as ObjectId18 } from "mongodb";
5132
5537
  import {
5133
- useAtlas as useAtlas13,
5134
- InternalServerError as InternalServerError9,
5538
+ useAtlas as useAtlas14,
5539
+ InternalServerError as InternalServerError11,
5135
5540
  paginate as paginate8,
5136
5541
  BadRequestError as BadRequestError29,
5137
5542
  useCache as useCache9,
5138
- logger as logger30,
5543
+ logger as logger31,
5139
5544
  makeCacheKey as makeCacheKey9,
5140
5545
  NotFoundError as NotFoundError7
5141
5546
  } from "@7365admin1/node-server-utils";
5142
5547
  function useScheduleTaskRepository() {
5143
- const db = useAtlas13.getDb();
5548
+ const db = useAtlas14.getDb();
5144
5549
  if (!db) {
5145
- throw new InternalServerError9("Unable to connect to server.");
5550
+ throw new InternalServerError11("Unable to connect to server.");
5146
5551
  }
5147
5552
  const namespace_collection = "site.schedule-tasks";
5148
5553
  const collection = db.collection(namespace_collection);
@@ -5154,7 +5559,7 @@ function useScheduleTaskRepository() {
5154
5559
  { key: { status: 1 } }
5155
5560
  ]);
5156
5561
  } catch (error) {
5157
- throw new InternalServerError9(
5562
+ throw new InternalServerError11(
5158
5563
  "Failed to create index on hygiene schedule task."
5159
5564
  );
5160
5565
  }
@@ -5163,7 +5568,7 @@ function useScheduleTaskRepository() {
5163
5568
  try {
5164
5569
  await collection.createIndex({ title: "text", description: "text" });
5165
5570
  } catch (error) {
5166
- throw new InternalServerError9(
5571
+ throw new InternalServerError11(
5167
5572
  "Failed to create text index on hygiene schedule task."
5168
5573
  );
5169
5574
  }
@@ -5173,9 +5578,9 @@ function useScheduleTaskRepository() {
5173
5578
  value = MScheduleTask(value);
5174
5579
  const res = await collection.insertOne(value, { session });
5175
5580
  delNamespace().then(() => {
5176
- logger30.info(`Cache cleared for namespace: ${namespace_collection}`);
5581
+ logger31.info(`Cache cleared for namespace: ${namespace_collection}`);
5177
5582
  }).catch((err) => {
5178
- logger30.error(
5583
+ logger31.error(
5179
5584
  `Failed to clear cache for namespace: ${namespace_collection}`,
5180
5585
  err
5181
5586
  );
@@ -5200,7 +5605,7 @@ function useScheduleTaskRepository() {
5200
5605
  limit
5201
5606
  };
5202
5607
  try {
5203
- site = new ObjectId17(site);
5608
+ site = new ObjectId18(site);
5204
5609
  query.site = site;
5205
5610
  cacheOptions.site = site.toString();
5206
5611
  } catch (error) {
@@ -5213,7 +5618,7 @@ function useScheduleTaskRepository() {
5213
5618
  const cacheKey = makeCacheKey9(namespace_collection, cacheOptions);
5214
5619
  const cachedData = await getCache(cacheKey);
5215
5620
  if (cachedData) {
5216
- logger30.info(`Cache hit for key: ${cacheKey}`);
5621
+ logger31.info(`Cache hit for key: ${cacheKey}`);
5217
5622
  return cachedData;
5218
5623
  }
5219
5624
  try {
@@ -5233,9 +5638,9 @@ function useScheduleTaskRepository() {
5233
5638
  const length = await collection.countDocuments(query);
5234
5639
  const data = paginate8(items, page, limit, length);
5235
5640
  setCache(cacheKey, data, 15 * 60).then(() => {
5236
- logger30.info(`Cache set for key: ${cacheKey}`);
5641
+ logger31.info(`Cache set for key: ${cacheKey}`);
5237
5642
  }).catch((err) => {
5238
- logger30.error(`Failed to set cache for key: ${cacheKey}`, err);
5643
+ logger31.error(`Failed to set cache for key: ${cacheKey}`, err);
5239
5644
  });
5240
5645
  return data;
5241
5646
  } catch (error) {
@@ -5268,7 +5673,7 @@ function useScheduleTaskRepository() {
5268
5673
  limit
5269
5674
  };
5270
5675
  try {
5271
- site = new ObjectId17(site);
5676
+ site = new ObjectId18(site);
5272
5677
  query.site = site;
5273
5678
  cacheOptions.site = site.toString();
5274
5679
  } catch (error) {
@@ -5281,7 +5686,7 @@ function useScheduleTaskRepository() {
5281
5686
  const cacheKey = makeCacheKey9(namespace_collection, cacheOptions);
5282
5687
  const cachedData = await getCache(cacheKey);
5283
5688
  if (cachedData) {
5284
- logger30.info(`Cache hit for key: ${cacheKey}`);
5689
+ logger31.info(`Cache hit for key: ${cacheKey}`);
5285
5690
  return cachedData;
5286
5691
  }
5287
5692
  try {
@@ -5300,9 +5705,9 @@ function useScheduleTaskRepository() {
5300
5705
  const length = await collection.countDocuments(query);
5301
5706
  const data = paginate8(items, page, limit, length);
5302
5707
  setCache(cacheKey, data, 15 * 60).then(() => {
5303
- logger30.info(`Cache set for key: ${cacheKey}`);
5708
+ logger31.info(`Cache set for key: ${cacheKey}`);
5304
5709
  }).catch((err) => {
5305
- logger30.error(`Failed to set cache for key: ${cacheKey}`, err);
5710
+ logger31.error(`Failed to set cache for key: ${cacheKey}`, err);
5306
5711
  });
5307
5712
  return data;
5308
5713
  } catch (error) {
@@ -5311,7 +5716,7 @@ function useScheduleTaskRepository() {
5311
5716
  }
5312
5717
  async function getScheduleTaskById(_id, session) {
5313
5718
  try {
5314
- _id = new ObjectId17(_id);
5719
+ _id = new ObjectId18(_id);
5315
5720
  } catch (error) {
5316
5721
  throw new BadRequestError29("Invalid schedule task ID format.");
5317
5722
  }
@@ -5325,11 +5730,11 @@ function useScheduleTaskRepository() {
5325
5730
  if (!session) {
5326
5731
  const cachedData = await getCache(cacheKey);
5327
5732
  if (cachedData) {
5328
- logger30.info(`Cache hit for key: ${cacheKey}`);
5733
+ logger31.info(`Cache hit for key: ${cacheKey}`);
5329
5734
  return cachedData;
5330
5735
  }
5331
5736
  } else {
5332
- logger30.info(`Skipping cache during transaction for key: ${cacheKey}`);
5737
+ logger31.info(`Skipping cache during transaction for key: ${cacheKey}`);
5333
5738
  }
5334
5739
  try {
5335
5740
  const data = await collection.aggregate([
@@ -5338,8 +5743,7 @@ function useScheduleTaskRepository() {
5338
5743
  $project: {
5339
5744
  title: 1,
5340
5745
  time: 1,
5341
- startDate: 1,
5342
- endDate: 1,
5746
+ dates: 1,
5343
5747
  description: 1,
5344
5748
  areas: 1,
5345
5749
  status: 1,
@@ -5351,9 +5755,9 @@ function useScheduleTaskRepository() {
5351
5755
  throw new NotFoundError7("Schedule task not found.");
5352
5756
  }
5353
5757
  setCache(cacheKey, data[0], 15 * 60).then(() => {
5354
- logger30.info(`Cache set for key: ${cacheKey}`);
5758
+ logger31.info(`Cache set for key: ${cacheKey}`);
5355
5759
  }).catch((err) => {
5356
- logger30.error(`Failed to set cache for key: ${cacheKey}`, err);
5760
+ logger31.error(`Failed to set cache for key: ${cacheKey}`, err);
5357
5761
  });
5358
5762
  return data[0];
5359
5763
  } catch (error) {
@@ -5362,7 +5766,7 @@ function useScheduleTaskRepository() {
5362
5766
  }
5363
5767
  async function updateScheduleTask(_id, value, session) {
5364
5768
  try {
5365
- _id = new ObjectId17(_id);
5769
+ _id = new ObjectId18(_id);
5366
5770
  } catch (error) {
5367
5771
  throw new BadRequestError29("Invalid schedule task ID format.");
5368
5772
  }
@@ -5371,7 +5775,7 @@ function useScheduleTaskRepository() {
5371
5775
  try {
5372
5776
  return {
5373
5777
  name: area.name,
5374
- value: new ObjectId17(area.value.toString())
5778
+ value: new ObjectId18(area.value.toString())
5375
5779
  };
5376
5780
  } catch (error) {
5377
5781
  throw new BadRequestError29(`Invalid area value format: ${area.name}`);
@@ -5386,14 +5790,14 @@ function useScheduleTaskRepository() {
5386
5790
  { session }
5387
5791
  );
5388
5792
  if (res.modifiedCount === 0) {
5389
- throw new InternalServerError9(
5793
+ throw new InternalServerError11(
5390
5794
  "Unable to update hygiene schedule task."
5391
5795
  );
5392
5796
  }
5393
5797
  delNamespace().then(() => {
5394
- logger30.info(`Cache cleared for namespace: ${namespace_collection}`);
5798
+ logger31.info(`Cache cleared for namespace: ${namespace_collection}`);
5395
5799
  }).catch((err) => {
5396
- logger30.error(
5800
+ logger31.error(
5397
5801
  `Failed to clear cache for namespace: ${namespace_collection}`,
5398
5802
  err
5399
5803
  );
@@ -5416,7 +5820,7 @@ function useScheduleTaskRepository() {
5416
5820
  }
5417
5821
 
5418
5822
  // src/services/hygiene-schedule-task.service.ts
5419
- import { logger as logger31 } from "@7365admin1/node-server-utils";
5823
+ import { logger as logger32 } from "@7365admin1/node-server-utils";
5420
5824
  function useScheduleTaskService() {
5421
5825
  const { createParentChecklist } = useParentChecklistRepo();
5422
5826
  const { getAllScheduleTask } = useScheduleTaskRepository();
@@ -5436,43 +5840,38 @@ function useScheduleTaskService() {
5436
5840
  timeZone: "Asia/Singapore"
5437
5841
  });
5438
5842
  const [currentHour, currentMinute] = timeString.split(":").map(Number);
5439
- const currentDateString = now.toLocaleDateString("en-US", {
5843
+ logger32.info(
5844
+ `Checking schedule ${schedule._id}: Current time ${currentHour}:${currentMinute}, Schedule time ${schedule.time}, Dates ${JSON.stringify(schedule.dates)}`
5845
+ );
5846
+ const currentDateFormatted = now.toLocaleDateString("en-CA", {
5440
5847
  timeZone: "Asia/Singapore"
5441
5848
  });
5442
- logger31.info(
5443
- `Checking schedule ${schedule._id}: Current time ${currentHour}:${currentMinute}, Current date ${currentDateString}, Schedule time ${schedule.time}, Start date ${schedule.startDate}, End date ${schedule.endDate}`
5444
- );
5445
- const startDate = /* @__PURE__ */ new Date(schedule.startDate + "T00:00:00");
5446
- const currentDateOnly = /* @__PURE__ */ new Date(currentDateString + "T00:00:00");
5447
- if (currentDateOnly < startDate) {
5448
- logger31.info(
5449
- `Schedule ${schedule._id}: Current date ${currentDateString} is before start date ${schedule.startDate}`
5450
- );
5849
+ if (!schedule.dates || !Array.isArray(schedule.dates) || schedule.dates.length === 0) {
5850
+ logger32.info(`Schedule ${schedule._id}: No dates configured, skipping`);
5451
5851
  return false;
5452
5852
  }
5453
- if (schedule.endDate) {
5454
- const endDate = /* @__PURE__ */ new Date(schedule.endDate + "T00:00:00");
5455
- if (currentDateOnly > endDate) {
5456
- logger31.info(
5457
- `Schedule ${schedule._id}: Current date ${currentDateString} is after end date ${schedule.endDate}`
5458
- );
5459
- return false;
5460
- }
5853
+ if (!schedule.dates.includes(currentDateFormatted)) {
5854
+ logger32.info(
5855
+ `Schedule ${schedule._id}: Current date ${currentDateFormatted} is not in scheduled dates [${schedule.dates.join(
5856
+ ", "
5857
+ )}]`
5858
+ );
5859
+ return false;
5461
5860
  }
5462
5861
  const [scheduleHour, scheduleMinute] = schedule.time.split(":").map(Number);
5463
5862
  const timeMatches = currentHour === scheduleHour && currentMinute === scheduleMinute;
5464
5863
  if (!timeMatches) {
5465
- logger31.info(
5864
+ logger32.info(
5466
5865
  `Schedule ${schedule._id}: Time does not match. Current: ${currentHour}:${currentMinute}, Expected: ${scheduleHour}:${scheduleMinute}`
5467
5866
  );
5468
5867
  return false;
5469
5868
  }
5470
- logger31.info(
5869
+ logger32.info(
5471
5870
  `Schedule ${schedule._id}: All conditions matched - Date is within range and time matches`
5472
5871
  );
5473
5872
  return true;
5474
5873
  } catch (error) {
5475
- logger31.error(
5874
+ logger32.error(
5476
5875
  `Error checking schedule conditions for ${schedule._id}:`,
5477
5876
  error
5478
5877
  );
@@ -5481,40 +5880,42 @@ function useScheduleTaskService() {
5481
5880
  }
5482
5881
  async function processScheduledTasks(currentDate) {
5483
5882
  try {
5484
- logger31.info("Starting scheduled task processing...");
5883
+ logger32.info("Starting scheduled task processing...");
5485
5884
  const scheduleTasks = await getAllScheduleTask();
5486
5885
  if (!scheduleTasks || scheduleTasks.length === 0) {
5487
- logger31.info("No schedule tasks found to process");
5886
+ logger32.info("No schedule tasks found to process");
5488
5887
  return { processed: 0, validated: 0 };
5489
5888
  }
5490
- logger31.info(`Found ${scheduleTasks.length} schedule tasks to check`);
5889
+ logger32.info(`Found ${scheduleTasks.length} schedule tasks to check`);
5491
5890
  let processedCount = 0;
5492
5891
  let validatedCount = 0;
5493
5892
  const validatedTasks = [];
5494
5893
  for (const scheduleTask of scheduleTasks) {
5495
5894
  try {
5496
- logger31.info(
5497
- `Checking schedule ${scheduleTask._id} - ${scheduleTask.title}: time=${scheduleTask.time}, startDate=${scheduleTask.startDate}, endDate=${scheduleTask.endDate}`
5895
+ logger32.info(
5896
+ `Checking schedule ${scheduleTask._id} - ${scheduleTask.title}: time=${scheduleTask.time}, dates=${JSON.stringify(
5897
+ scheduleTask.dates
5898
+ )}`
5498
5899
  );
5499
5900
  const shouldRun = checkScheduleConditions(scheduleTask, currentDate);
5500
5901
  if (!shouldRun) {
5501
- logger31.info(
5902
+ logger32.info(
5502
5903
  `Schedule ${scheduleTask._id} conditions not met, skipping`
5503
5904
  );
5504
5905
  continue;
5505
5906
  }
5506
- logger31.info(
5907
+ logger32.info(
5507
5908
  `Schedule ${scheduleTask._id} conditions validated, creating area checklists`
5508
5909
  );
5509
5910
  if (!scheduleTask._id) {
5510
- logger31.warn(`Schedule ${scheduleTask.title} has no _id, skipping`);
5911
+ logger32.warn(`Schedule ${scheduleTask.title} has no _id, skipping`);
5511
5912
  continue;
5512
5913
  }
5513
5914
  if (!scheduleTask.site) {
5514
- logger31.warn(`Schedule ${scheduleTask._id} has no site, skipping`);
5915
+ logger32.warn(`Schedule ${scheduleTask._id} has no site, skipping`);
5515
5916
  continue;
5516
5917
  }
5517
- logger31.info(
5918
+ logger32.info(
5518
5919
  `Getting or creating parent checklist for schedule ${scheduleTask._id} in site ${scheduleTask.site}`
5519
5920
  );
5520
5921
  const parentChecklistIds = await createParentChecklist({
@@ -5522,7 +5923,7 @@ function useScheduleTaskService() {
5522
5923
  createdAt: /* @__PURE__ */ new Date()
5523
5924
  });
5524
5925
  const parentChecklistId = Array.isArray(parentChecklistIds) ? parentChecklistIds[0] : parentChecklistIds;
5525
- logger31.info(
5926
+ logger32.info(
5526
5927
  `Using parent checklist ${parentChecklistId}, now creating/updating area checklists`
5527
5928
  );
5528
5929
  for (const area of scheduleTask.areas) {
@@ -5535,14 +5936,14 @@ function useScheduleTaskService() {
5535
5936
  unit: unit.unit.toString(),
5536
5937
  name: unit.name
5537
5938
  }));
5538
- logger31.info(
5939
+ logger32.info(
5539
5940
  `Area ${area.name} (${areaId}): Using units from area details: ${JSON.stringify(
5540
5941
  units
5541
5942
  )}`
5542
5943
  );
5543
5944
  }
5544
5945
  if (units.length === 0) {
5545
- logger31.warn(
5946
+ logger32.warn(
5546
5947
  `Area ${area.name} (${areaId}): No units found, skipping area.`
5547
5948
  );
5548
5949
  continue;
@@ -5553,11 +5954,11 @@ function useScheduleTaskService() {
5553
5954
  parentChecklistId.toString(),
5554
5955
  areaId
5555
5956
  );
5556
- logger31.info(
5957
+ logger32.info(
5557
5958
  `Area ${area.name} (${areaId}): Existing area checklist found: ${existingAreaChecklist ? "Yes" : "No"}`
5558
5959
  );
5559
5960
  if (existingAreaChecklist) {
5560
- logger31.info(
5961
+ logger32.info(
5561
5962
  `Area ${area.name} (${areaId}): Existing checklist content: ${JSON.stringify(
5562
5963
  existingAreaChecklist.checklist
5563
5964
  )}`
@@ -5565,7 +5966,7 @@ function useScheduleTaskService() {
5565
5966
  }
5566
5967
  } catch (error) {
5567
5968
  existingAreaChecklist = null;
5568
- logger31.info(
5969
+ logger32.info(
5569
5970
  `Area ${area.name} (${areaId}): No existing area checklist found (exception).`
5570
5971
  );
5571
5972
  }
@@ -5579,7 +5980,7 @@ function useScheduleTaskService() {
5579
5980
  ...existingAreaChecklist.checklist || [],
5580
5981
  newSet
5581
5982
  ];
5582
- logger31.info(
5983
+ logger32.info(
5583
5984
  `Area ${area.name} (${areaId}): Appending new set ${newSet.set} to checklist. Updated checklist: ${JSON.stringify(
5584
5985
  updatedChecklist
5585
5986
  )}`
@@ -5587,7 +5988,7 @@ function useScheduleTaskService() {
5587
5988
  await updateAreaChecklist(existingAreaChecklist._id, {
5588
5989
  checklist: updatedChecklist
5589
5990
  });
5590
- logger31.info(
5991
+ logger32.info(
5591
5992
  `Appended set ${newSet.set} to area checklist for area ${area.name}`
5592
5993
  );
5593
5994
  try {
@@ -5595,13 +5996,13 @@ function useScheduleTaskService() {
5595
5996
  parentChecklistId.toString(),
5596
5997
  areaId
5597
5998
  );
5598
- logger31.info(
5999
+ logger32.info(
5599
6000
  `Area ${area.name} (${areaId}): Checklist after update: ${JSON.stringify(
5600
6001
  verifyChecklist.checklist
5601
6002
  )}`
5602
6003
  );
5603
6004
  } catch (verifyError) {
5604
- logger31.warn(
6005
+ logger32.warn(
5605
6006
  `Area ${area.name} (${areaId}): Error verifying checklist after update:`,
5606
6007
  verifyError
5607
6008
  );
@@ -5620,50 +6021,50 @@ function useScheduleTaskService() {
5620
6021
  ],
5621
6022
  createdBy: scheduleTask.createdBy
5622
6023
  };
5623
- logger31.info(
6024
+ logger32.info(
5624
6025
  `Area ${area.name} (${areaId}): Creating new area checklist with data: ${JSON.stringify(
5625
6026
  checklistData
5626
6027
  )}`
5627
6028
  );
5628
6029
  await createAreaChecklist(checklistData);
5629
- logger31.info(`Created new area checklist for area ${area.name}`);
6030
+ logger32.info(`Created new area checklist for area ${area.name}`);
5630
6031
  try {
5631
6032
  const verifyChecklist = await getAreaChecklistByAreaAndSchedule(
5632
6033
  parentChecklistId.toString(),
5633
6034
  areaId
5634
6035
  );
5635
- logger31.info(
6036
+ logger32.info(
5636
6037
  `Area ${area.name} (${areaId}): Checklist after creation: ${JSON.stringify(
5637
6038
  verifyChecklist.checklist
5638
6039
  )}`
5639
6040
  );
5640
6041
  } catch (verifyError) {
5641
- logger31.warn(
6042
+ logger32.warn(
5642
6043
  `Area ${area.name} (${areaId}): Error verifying checklist after creation:`,
5643
6044
  verifyError
5644
6045
  );
5645
6046
  }
5646
6047
  }
5647
6048
  } catch (error) {
5648
- logger31.error(`Error processing area ${area.name}:`, error);
6049
+ logger32.error(`Error processing area ${area.name}:`, error);
5649
6050
  continue;
5650
6051
  }
5651
6052
  }
5652
6053
  processedCount++;
5653
6054
  validatedCount++;
5654
6055
  validatedTasks.push(scheduleTask);
5655
- logger31.info(
6056
+ logger32.info(
5656
6057
  `Successfully processed schedule ${scheduleTask._id}, created/updated area checklists for all areas.`
5657
6058
  );
5658
6059
  } catch (error) {
5659
- logger31.error(
6060
+ logger32.error(
5660
6061
  `Error processing schedule task ${scheduleTask._id}:`,
5661
6062
  error
5662
6063
  );
5663
6064
  continue;
5664
6065
  }
5665
6066
  }
5666
- logger31.info(
6067
+ logger32.info(
5667
6068
  `Scheduled task processing completed. Processed: ${processedCount}, Validated: ${validatedCount} tasks`
5668
6069
  );
5669
6070
  return {
@@ -5672,7 +6073,7 @@ function useScheduleTaskService() {
5672
6073
  tasks: validatedTasks
5673
6074
  };
5674
6075
  } catch (error) {
5675
- logger31.error("Error processing scheduled tasks:", error);
6076
+ logger32.error("Error processing scheduled tasks:", error);
5676
6077
  throw error;
5677
6078
  }
5678
6079
  }
@@ -5681,7 +6082,7 @@ function useScheduleTaskService() {
5681
6082
 
5682
6083
  // src/controllers/hygiene-schedule-task.controller.ts
5683
6084
  import Joi17 from "joi";
5684
- import { BadRequestError as BadRequestError30, logger as logger32 } from "@7365admin1/node-server-utils";
6085
+ import { BadRequestError as BadRequestError30, logger as logger33 } from "@7365admin1/node-server-utils";
5685
6086
  function useScheduleTaskController() {
5686
6087
  const {
5687
6088
  createScheduleTask: _createScheduleTask,
@@ -5699,7 +6100,7 @@ function useScheduleTaskController() {
5699
6100
  const payload = { ...req.body, ...req.params, createdBy };
5700
6101
  const { error } = scheduleTaskSchema.validate(payload);
5701
6102
  if (error) {
5702
- logger32.log({ level: "error", message: error.message });
6103
+ logger33.log({ level: "error", message: error.message });
5703
6104
  next(new BadRequestError30(error.message));
5704
6105
  return;
5705
6106
  }
@@ -5708,7 +6109,7 @@ function useScheduleTaskController() {
5708
6109
  res.status(201).json({ message: "Schedule task created successfully.", id });
5709
6110
  return;
5710
6111
  } catch (error2) {
5711
- logger32.log({ level: "error", message: error2.message });
6112
+ logger33.log({ level: "error", message: error2.message });
5712
6113
  next(error2);
5713
6114
  return;
5714
6115
  }
@@ -5723,7 +6124,7 @@ function useScheduleTaskController() {
5723
6124
  });
5724
6125
  const { error } = validation.validate(query);
5725
6126
  if (error) {
5726
- logger32.log({ level: "error", message: error.message });
6127
+ logger33.log({ level: "error", message: error.message });
5727
6128
  next(new BadRequestError30(error.message));
5728
6129
  return;
5729
6130
  }
@@ -5741,7 +6142,7 @@ function useScheduleTaskController() {
5741
6142
  res.json(data);
5742
6143
  return;
5743
6144
  } catch (error2) {
5744
- logger32.log({ level: "error", message: error2.message });
6145
+ logger33.log({ level: "error", message: error2.message });
5745
6146
  next(error2);
5746
6147
  return;
5747
6148
  }
@@ -5756,7 +6157,7 @@ function useScheduleTaskController() {
5756
6157
  });
5757
6158
  const { error } = validation.validate(query);
5758
6159
  if (error) {
5759
- logger32.log({ level: "error", message: error.message });
6160
+ logger33.log({ level: "error", message: error.message });
5760
6161
  next(new BadRequestError30(error.message));
5761
6162
  return;
5762
6163
  }
@@ -5774,7 +6175,7 @@ function useScheduleTaskController() {
5774
6175
  res.json(data);
5775
6176
  return;
5776
6177
  } catch (error2) {
5777
- logger32.log({ level: "error", message: error2.message });
6178
+ logger33.log({ level: "error", message: error2.message });
5778
6179
  next(error2);
5779
6180
  return;
5780
6181
  }
@@ -5784,7 +6185,7 @@ function useScheduleTaskController() {
5784
6185
  const _id = req.params.id;
5785
6186
  const { error, value } = validation.validate(_id);
5786
6187
  if (error) {
5787
- logger32.log({ level: "error", message: error.message });
6188
+ logger33.log({ level: "error", message: error.message });
5788
6189
  next(new BadRequestError30(error.message));
5789
6190
  return;
5790
6191
  }
@@ -5793,7 +6194,7 @@ function useScheduleTaskController() {
5793
6194
  res.json(data);
5794
6195
  return;
5795
6196
  } catch (error2) {
5796
- logger32.log({ level: "error", message: error2.message });
6197
+ logger33.log({ level: "error", message: error2.message });
5797
6198
  next(error2);
5798
6199
  return;
5799
6200
  }
@@ -5804,8 +6205,9 @@ function useScheduleTaskController() {
5804
6205
  id: Joi17.string().hex().required(),
5805
6206
  title: Joi17.string().optional().allow("", null),
5806
6207
  time: Joi17.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).optional().allow("", null),
5807
- startDate: Joi17.string().pattern(/^\d{4}-\d{2}-\d{2}$/).optional().allow("", null),
5808
- endDate: Joi17.string().pattern(/^\d{4}-\d{2}-\d{2}$/).optional().allow("", null),
6208
+ dates: Joi17.array().min(1).items(
6209
+ Joi17.string().pattern(/^\d{4}-\d{2}-\d{2}$/).required()
6210
+ ).optional(),
5809
6211
  description: Joi17.string().optional().allow("", null),
5810
6212
  areas: Joi17.array().min(1).items(
5811
6213
  Joi17.object({
@@ -5816,7 +6218,7 @@ function useScheduleTaskController() {
5816
6218
  });
5817
6219
  const { error } = validation.validate(payload);
5818
6220
  if (error) {
5819
- logger32.log({ level: "error", message: error.message });
6221
+ logger33.log({ level: "error", message: error.message });
5820
6222
  next(new BadRequestError30(error.message));
5821
6223
  return;
5822
6224
  }
@@ -5826,7 +6228,7 @@ function useScheduleTaskController() {
5826
6228
  res.json({ message: "Schedule task updated successfully." });
5827
6229
  return;
5828
6230
  } catch (error2) {
5829
- logger32.log({ level: "error", message: error2.message });
6231
+ logger33.log({ level: "error", message: error2.message });
5830
6232
  next(error2);
5831
6233
  return;
5832
6234
  }
@@ -5841,8 +6243,8 @@ function useScheduleTaskController() {
5841
6243
  }
5842
6244
 
5843
6245
  // src/services/hygiene-qr.service.ts
5844
- import { logger as logger33 } from "@7365admin1/node-server-utils";
5845
- import { launch } from "puppeteer";
6246
+ import { logger as logger34 } from "@7365admin1/node-server-utils";
6247
+ import { launch as launch2 } from "puppeteer";
5846
6248
  import QRCode from "qrcode";
5847
6249
  function useQRService() {
5848
6250
  async function generateQRDataUrl(qrUrl) {
@@ -5859,7 +6261,7 @@ function useQRService() {
5859
6261
  async function generateQRImage(qrUrl) {
5860
6262
  try {
5861
6263
  const qrDataUrl = await generateQRDataUrl(qrUrl);
5862
- const browser = await launch({
6264
+ const browser = await launch2({
5863
6265
  headless: true,
5864
6266
  executablePath: process.env.CHROME_BINARY,
5865
6267
  args: [`--no-sandbox`, `--disable-gpu`, `--disable-dev-shm-usage`]
@@ -5912,17 +6314,17 @@ function useQRService() {
5912
6314
  await browser.close();
5913
6315
  return imageBuffer;
5914
6316
  } catch (error) {
5915
- logger33.log({
6317
+ logger34.log({
5916
6318
  level: "error",
5917
6319
  message: `Failed to generate QR image: ${error.message}`
5918
6320
  });
5919
6321
  throw error;
5920
6322
  }
5921
6323
  }
5922
- async function generateQRPDF(qrUrl, title) {
6324
+ async function generateQRPDF(qrUrl, title, subtitle) {
5923
6325
  try {
5924
6326
  const qrDataUrl = await generateQRDataUrl(qrUrl);
5925
- const browser = await launch({
6327
+ const browser = await launch2({
5926
6328
  headless: true,
5927
6329
  executablePath: process.env.CHROME_BINARY,
5928
6330
  args: [`--no-sandbox`, `--disable-gpu`, `--disable-dev-shm-usage`]
@@ -5933,6 +6335,7 @@ function useQRService() {
5933
6335
  height: 1100
5934
6336
  });
5935
6337
  const escapedTitle = (title || "Cleaning Schedule QR Code").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6338
+ const escapedSubtitle = subtitle ? subtitle.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;") : "";
5936
6339
  const html = `
5937
6340
  <!DOCTYPE html>
5938
6341
  <html>
@@ -5960,10 +6363,16 @@ function useQRService() {
5960
6363
  padding: 0;
5961
6364
  }
5962
6365
  h1 {
5963
- font-size: 28px;
6366
+ font-size: 38px;
5964
6367
  color: #333;
5965
- margin-bottom: 20px;
5966
- font-weight: 600;
6368
+ margin-bottom: 8px;
6369
+ font-weight: 700;
6370
+ }
6371
+ .subtitle {
6372
+ font-size: 26px;
6373
+ color: #555;
6374
+ margin-bottom: 12px;
6375
+ font-weight: 500;
5967
6376
  }
5968
6377
  .qr-wrapper {
5969
6378
  display: inline-block;
@@ -5998,6 +6407,7 @@ function useQRService() {
5998
6407
  <body>
5999
6408
  <div class="qr-container">
6000
6409
  <h1>${escapedTitle}</h1>
6410
+ ${escapedSubtitle ? `<p class="subtitle">${escapedSubtitle}</p>` : ""}
6001
6411
  <div class="qr-wrapper">
6002
6412
  <img id="qr-image" src="${qrDataUrl}" alt="QR Code" />
6003
6413
  </div>
@@ -6035,7 +6445,7 @@ function useQRService() {
6035
6445
  await browser.close();
6036
6446
  return pdfBuffer;
6037
6447
  } catch (error) {
6038
- logger33.log({
6448
+ logger34.log({
6039
6449
  level: "error",
6040
6450
  message: `Failed to generate QR PDF: ${error.message}`
6041
6451
  });
@@ -6050,7 +6460,7 @@ function useQRService() {
6050
6460
 
6051
6461
  // src/controllers/hygiene-qr.controller.ts
6052
6462
  import Joi18 from "joi";
6053
- import { BadRequestError as BadRequestError31, logger as logger34 } from "@7365admin1/node-server-utils";
6463
+ import { BadRequestError as BadRequestError31, logger as logger35 } from "@7365admin1/node-server-utils";
6054
6464
  function useQRController() {
6055
6465
  const { generateQRImage: _generateQRImage, generateQRPDF: _generateQRPDF } = useQRService();
6056
6466
  async function generateQR(req, res, next) {
@@ -6058,19 +6468,20 @@ function useQRController() {
6058
6468
  url: Joi18.string().uri().required(),
6059
6469
  filename: Joi18.string().optional().allow("", null),
6060
6470
  title: Joi18.string().optional().allow("", null),
6471
+ subtitle: Joi18.string().optional().allow("", null),
6061
6472
  download: Joi18.boolean().optional().default(false)
6062
6473
  });
6063
6474
  const query = { ...req.query };
6064
6475
  const { error, value } = validation.validate(query);
6065
6476
  if (error) {
6066
- logger34.log({ level: "error", message: error.message });
6477
+ logger35.log({ level: "error", message: error.message });
6067
6478
  next(new BadRequestError31(error.message));
6068
6479
  return;
6069
6480
  }
6070
6481
  try {
6071
- const { url, filename, title, download } = value;
6482
+ const { url, filename, title, subtitle, download } = value;
6072
6483
  if (download) {
6073
- const pdfBuffer = await _generateQRPDF(url, title);
6484
+ const pdfBuffer = await _generateQRPDF(url, title, subtitle);
6074
6485
  if (!pdfBuffer || pdfBuffer.length === 0) {
6075
6486
  throw new Error("Generated QR PDF is empty or invalid.");
6076
6487
  }
@@ -6099,7 +6510,7 @@ function useQRController() {
6099
6510
  }
6100
6511
  return;
6101
6512
  } catch (error2) {
6102
- logger34.log({ level: "error", message: error2.message });
6513
+ logger35.log({ level: "error", message: error2.message });
6103
6514
  next(error2);
6104
6515
  return;
6105
6516
  }