@7365admin1/module-hygiene 4.24.0 → 4.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2473,7 +2473,8 @@ import { AppServiceType as AppServiceType6 } from "@7365admin1/core";
2473
2473
  var parentChecklistSchema = Joi6.object({
2474
2474
  createdAt: Joi6.alternatives().try(Joi6.date(), Joi6.string()).optional().allow("", null),
2475
2475
  site: Joi6.string().hex().required(),
2476
- serviceType: Joi6.string().valid(...Object.values(AppServiceType6)).required()
2476
+ serviceType: Joi6.string().valid(...Object.values(AppServiceType6)).required(),
2477
+ dateStr: Joi6.string().optional().allow("", null)
2477
2478
  });
2478
2479
  function MParentChecklist(value) {
2479
2480
  const { error } = parentChecklistSchema.validate(value);
@@ -2488,18 +2489,22 @@ function MParentChecklist(value) {
2488
2489
  throw new BadRequestError11(`Invalid site ID format: ${value.site}`);
2489
2490
  }
2490
2491
  }
2492
+ const currentDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
2493
+ const sgOffset = 8 * 60 * 60 * 1e3;
2494
+ const sgTime = new Date(currentDate.getTime() + sgOffset);
2495
+ const dateStr = `${sgTime.getUTCFullYear()}-${String(sgTime.getUTCMonth() + 1).padStart(2, "0")}-${String(sgTime.getUTCDate()).padStart(2, "0")}`;
2491
2496
  return {
2492
2497
  site: value.site,
2493
2498
  serviceType: value.serviceType,
2494
2499
  status: "open",
2495
- createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
2496
- updatedAt: value.updatedAt ?? ""
2500
+ createdAt: currentDate,
2501
+ updatedAt: value.updatedAt ?? "",
2502
+ dateStr
2497
2503
  };
2498
2504
  }
2499
2505
 
2500
2506
  // src/repositories/hygiene-parent-checklist.repository.ts
2501
2507
  import { ObjectId as ObjectId7 } from "mongodb";
2502
- import moment2 from "moment-timezone";
2503
2508
  import {
2504
2509
  useAtlas as useAtlas5,
2505
2510
  InternalServerError as InternalServerError4,
@@ -2522,13 +2527,55 @@ function useParentChecklistRepo() {
2522
2527
  const { delNamespace, setCache, getCache } = useCache4(namespace_collection);
2523
2528
  async function createIndex() {
2524
2529
  try {
2530
+ await collection.updateMany(
2531
+ { dateStr: { $exists: false } },
2532
+ [
2533
+ {
2534
+ $set: {
2535
+ dateStr: {
2536
+ $let: {
2537
+ vars: {
2538
+ sgTime: { $add: ["$createdAt", 8 * 60 * 60 * 1e3] }
2539
+ },
2540
+ in: {
2541
+ $dateToString: {
2542
+ format: "%Y-%m-%d",
2543
+ date: "$$sgTime",
2544
+ timezone: "UTC"
2545
+ }
2546
+ }
2547
+ }
2548
+ }
2549
+ }
2550
+ }
2551
+ ]
2552
+ );
2553
+ const duplicates = await collection.aggregate([
2554
+ {
2555
+ $group: {
2556
+ _id: { site: "$site", serviceType: "$serviceType", dateStr: "$dateStr" },
2557
+ docs: { $push: "$_id" },
2558
+ count: { $sum: 1 }
2559
+ }
2560
+ },
2561
+ { $match: { count: { $gt: 1 } } }
2562
+ ]).toArray();
2563
+ for (const group of duplicates) {
2564
+ const toDelete = group.docs.slice(1);
2565
+ await collection.deleteMany({ _id: { $in: toDelete } });
2566
+ logger14.info(
2567
+ `Deleted ${toDelete.length} duplicate parent checklists for site ${group._id.site} / ${group._id.serviceType} on date ${group._id.dateStr}`
2568
+ );
2569
+ }
2525
2570
  await collection.createIndexes([
2526
2571
  { key: { serviceType: 1 } },
2527
2572
  { key: { createdAt: 1 } },
2528
2573
  { key: { site: 1 } },
2529
- { key: { status: 1 } }
2574
+ { key: { status: 1 } },
2575
+ { key: { site: 1, serviceType: 1, dateStr: 1 }, unique: true }
2530
2576
  ]);
2531
2577
  } catch (error) {
2578
+ logger14.error("Failed to create index/backfill on hygiene parent checklist:", error);
2532
2579
  throw new InternalServerError4(
2533
2580
  "Failed to create index on hygiene parent checklist."
2534
2581
  );
@@ -2537,10 +2584,13 @@ function useParentChecklistRepo() {
2537
2584
  async function createParentChecklist(value, session) {
2538
2585
  try {
2539
2586
  const currentDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
2540
- const startOfDay = moment2(currentDate).tz("Asia/Singapore").startOf("day").toDate();
2541
- const endOfDay = moment2(currentDate).tz("Asia/Singapore").endOf("day").toDate();
2587
+ const sgOffset = 8 * 60 * 60 * 1e3;
2588
+ const sgTime = new Date(currentDate.getTime() + sgOffset);
2589
+ const startOfDay = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
2590
+ const endOfDay = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2591
+ const targetDateStr = `${sgTime.getUTCFullYear()}-${String(sgTime.getUTCMonth() + 1).padStart(2, "0")}-${String(sgTime.getUTCDate()).padStart(2, "0")}`;
2592
+ const dateStr = targetDateStr;
2542
2593
  const allServiceTypes = Object.values(AppServiceType7);
2543
- const dateStr = currentDate.toISOString().split("T")[0];
2544
2594
  if (value.site) {
2545
2595
  let siteObjectId;
2546
2596
  try {
@@ -2550,9 +2600,12 @@ function useParentChecklistRepo() {
2550
2600
  }
2551
2601
  if (value.serviceType) {
2552
2602
  const existingChecklist = await collection.findOne({
2553
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2554
2603
  site: siteObjectId,
2555
- serviceType: value.serviceType
2604
+ serviceType: value.serviceType,
2605
+ $or: [
2606
+ { dateStr: targetDateStr },
2607
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2608
+ ]
2556
2609
  });
2557
2610
  if (existingChecklist) {
2558
2611
  logger14.info(
@@ -2565,22 +2618,41 @@ function useParentChecklistRepo() {
2565
2618
  createdAt: currentDate,
2566
2619
  serviceType: value.serviceType
2567
2620
  });
2568
- const result3 = await collection.insertOne(doc, { session });
2569
- delNamespace().catch((err) => {
2570
- logger14.error(
2571
- `Failed to clear cache for namespace: ${namespace_collection}`,
2572
- err
2621
+ let insertedId;
2622
+ try {
2623
+ const result = await collection.insertOne(doc, { session });
2624
+ insertedId = result.insertedId;
2625
+ delNamespace().catch((err) => {
2626
+ logger14.error(
2627
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2628
+ err
2629
+ );
2630
+ });
2631
+ logger14.info(
2632
+ `Created parent checklist for site ${value.site} / ${value.serviceType} for today: ${dateStr}`
2573
2633
  );
2574
- });
2575
- logger14.info(
2576
- `Created parent checklist for site ${value.site} / ${value.serviceType} for today: ${dateStr}`
2577
- );
2578
- return result3.insertedId;
2634
+ } catch (error) {
2635
+ if (error.code === 11e3) {
2636
+ const existingChecklist2 = await collection.findOne({
2637
+ site: siteObjectId,
2638
+ serviceType: value.serviceType,
2639
+ dateStr: targetDateStr
2640
+ });
2641
+ if (existingChecklist2) {
2642
+ return existingChecklist2._id;
2643
+ }
2644
+ }
2645
+ throw error;
2646
+ }
2647
+ return insertedId;
2579
2648
  }
2580
2649
  const existingServiceTypes = await collection.distinct("serviceType", {
2581
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2582
2650
  site: siteObjectId,
2583
- serviceType: { $exists: true, $ne: null }
2651
+ serviceType: { $exists: true, $ne: null },
2652
+ $or: [
2653
+ { dateStr: targetDateStr },
2654
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2655
+ ]
2584
2656
  });
2585
2657
  const missingServiceTypes = allServiceTypes.filter(
2586
2658
  (st) => !existingServiceTypes.includes(st)
@@ -2590,8 +2662,11 @@ function useParentChecklistRepo() {
2590
2662
  `All serviceType checklists already exist for site ${value.site} on ${dateStr}`
2591
2663
  );
2592
2664
  const first = await collection.findOne({
2593
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2594
- site: siteObjectId
2665
+ site: siteObjectId,
2666
+ $or: [
2667
+ { dateStr: targetDateStr },
2668
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2669
+ ]
2595
2670
  });
2596
2671
  return first._id;
2597
2672
  }
@@ -2602,17 +2677,30 @@ function useParentChecklistRepo() {
2602
2677
  serviceType
2603
2678
  })
2604
2679
  );
2605
- const result2 = await collection.insertMany(checklistDocs2, { session });
2606
- delNamespace().catch((err) => {
2607
- logger14.error(
2608
- `Failed to clear cache for namespace: ${namespace_collection}`,
2609
- err
2680
+ let insertedIds2 = [];
2681
+ try {
2682
+ const result = await collection.insertMany(checklistDocs2, { session, ordered: false });
2683
+ insertedIds2 = Object.values(result.insertedIds);
2684
+ delNamespace().catch((err) => {
2685
+ logger14.error(
2686
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2687
+ err
2688
+ );
2689
+ });
2690
+ logger14.info(
2691
+ `Created ${checklistDocs2.length} parent checklists for site ${value.site} for today: ${dateStr}`
2610
2692
  );
2611
- });
2612
- logger14.info(
2613
- `Created ${checklistDocs2.length} parent checklists for site ${value.site} for today: ${dateStr}`
2614
- );
2615
- return Object.values(result2.insertedIds);
2693
+ } catch (error) {
2694
+ if (error.code === 11e3 || error.writeErrors) {
2695
+ const existing = await collection.find({
2696
+ site: siteObjectId,
2697
+ dateStr: targetDateStr
2698
+ }).toArray();
2699
+ return existing.map((e) => e._id);
2700
+ }
2701
+ throw error;
2702
+ }
2703
+ return insertedIds2;
2616
2704
  }
2617
2705
  const siteIds = await getHygieneSiteIds();
2618
2706
  if (!Array.isArray(siteIds)) {
@@ -2625,8 +2713,11 @@ function useParentChecklistRepo() {
2625
2713
  }
2626
2714
  const existingPairs = await collection.find(
2627
2715
  {
2628
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2629
- serviceType: { $exists: true, $ne: null }
2716
+ serviceType: { $exists: true, $ne: null },
2717
+ $or: [
2718
+ { dateStr: targetDateStr },
2719
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2720
+ ]
2630
2721
  },
2631
2722
  { projection: { site: 1, serviceType: 1 } }
2632
2723
  ).toArray();
@@ -2658,19 +2749,31 @@ function useParentChecklistRepo() {
2658
2749
  logger14.info(
2659
2750
  `createParentChecklist: Creating ${checklistDocs.length} missing site+serviceType checklist(s) for today: ${dateStr}`
2660
2751
  );
2661
- const result = await collection.insertMany(checklistDocs, { session });
2662
- delNamespace().then(() => {
2663
- logger14.info(`Cache cleared for namespace: ${namespace_collection}`);
2664
- }).catch((err) => {
2665
- logger14.error(
2666
- `Failed to clear cache for namespace: ${namespace_collection}`,
2667
- err
2752
+ let insertedIds = [];
2753
+ try {
2754
+ const result = await collection.insertMany(checklistDocs, { session, ordered: false });
2755
+ insertedIds = Object.values(result.insertedIds);
2756
+ delNamespace().then(() => {
2757
+ logger14.info(`Cache cleared for namespace: ${namespace_collection}`);
2758
+ }).catch((err) => {
2759
+ logger14.error(
2760
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2761
+ err
2762
+ );
2763
+ });
2764
+ logger14.info(
2765
+ `Created ${Object.keys(result.insertedIds).length} parent checklists for today: ${dateStr}`
2668
2766
  );
2669
- });
2670
- logger14.info(
2671
- `Created ${Object.keys(result.insertedIds).length} parent checklists for today: ${dateStr}`
2672
- );
2673
- return Object.values(result.insertedIds);
2767
+ } catch (error) {
2768
+ if (error.code === 11e3 || error.writeErrors) {
2769
+ const existing = await collection.find({
2770
+ dateStr: targetDateStr
2771
+ }).toArray();
2772
+ return existing.map((e) => e._id);
2773
+ }
2774
+ throw error;
2775
+ }
2776
+ return insertedIds;
2674
2777
  } catch (error) {
2675
2778
  logger14.error("Failed to create daily parent checklist", error);
2676
2779
  throw error;
@@ -2889,8 +2992,11 @@ function useParentChecklistRepo() {
2889
2992
  }
2890
2993
  }
2891
2994
  async function getTodayParentChecklists() {
2892
- const start = moment2().tz("Asia/Singapore").startOf("day").toDate();
2893
- const end = moment2().tz("Asia/Singapore").endOf("day").toDate();
2995
+ const sgOffset = 8 * 60 * 60 * 1e3;
2996
+ const now = /* @__PURE__ */ new Date();
2997
+ const sgTime = new Date(now.getTime() + sgOffset);
2998
+ const start = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
2999
+ const end = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2894
3000
  try {
2895
3001
  const items = await collection.find(
2896
3002
  { createdAt: { $gte: start, $lte: end } },
@@ -2903,8 +3009,11 @@ function useParentChecklistRepo() {
2903
3009
  }
2904
3010
  }
2905
3011
  async function getTodayParentChecklistsForAreaGen() {
2906
- const start = moment2().tz("Asia/Singapore").startOf("day").toDate();
2907
- const end = moment2().tz("Asia/Singapore").endOf("day").toDate();
3012
+ const sgOffset = 8 * 60 * 60 * 1e3;
3013
+ const now = /* @__PURE__ */ new Date();
3014
+ const sgTime = new Date(now.getTime() + sgOffset);
3015
+ const start = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
3016
+ const end = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2908
3017
  try {
2909
3018
  const items = await collection.find(
2910
3019
  {