@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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @7365admin1/module-hygiene
2
2
 
3
+ ## 4.24.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Update module hygiene package
8
+
3
9
  ## 4.24.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -209,6 +209,7 @@ type TParentChecklist = {
209
209
  status?: (typeof allowedStatus)[number];
210
210
  createdAt?: Date | string;
211
211
  updatedAt?: Date | string;
212
+ dateStr?: string;
212
213
  };
213
214
  type TParentChecklistCreate = {
214
215
  site?: string | ObjectId;
@@ -228,13 +229,14 @@ declare function MParentChecklist(value: TParentChecklist): {
228
229
  site: string | ObjectId;
229
230
  serviceType: AppServiceType;
230
231
  status: string;
231
- createdAt: string | Date;
232
+ createdAt: Date;
232
233
  updatedAt: string | Date;
234
+ dateStr: string;
233
235
  };
234
236
 
235
237
  declare function useParentChecklistRepo(): {
236
238
  createIndex: () => Promise<void>;
237
- createParentChecklist: (value: TParentChecklistCreate, session?: ClientSession) => Promise<ObjectId | ObjectId[]>;
239
+ createParentChecklist: (value: TParentChecklistCreate, session?: ClientSession) => Promise<any>;
238
240
  getAllParentChecklist: ({ page, limit, search, site, startDate, endDate, status, serviceType, }: TParentChecklistGetQuery) => Promise<{}>;
239
241
  getParentChecklistById: (_id: string | ObjectId) => Promise<TParentChecklist & {
240
242
  _id: ObjectId;
package/dist/index.js CHANGED
@@ -2523,7 +2523,8 @@ var import_core6 = require("@7365admin1/core");
2523
2523
  var parentChecklistSchema = import_joi6.default.object({
2524
2524
  createdAt: import_joi6.default.alternatives().try(import_joi6.default.date(), import_joi6.default.string()).optional().allow("", null),
2525
2525
  site: import_joi6.default.string().hex().required(),
2526
- serviceType: import_joi6.default.string().valid(...Object.values(import_core6.AppServiceType)).required()
2526
+ serviceType: import_joi6.default.string().valid(...Object.values(import_core6.AppServiceType)).required(),
2527
+ dateStr: import_joi6.default.string().optional().allow("", null)
2527
2528
  });
2528
2529
  function MParentChecklist(value) {
2529
2530
  const { error } = parentChecklistSchema.validate(value);
@@ -2538,18 +2539,22 @@ function MParentChecklist(value) {
2538
2539
  throw new import_node_server_utils13.BadRequestError(`Invalid site ID format: ${value.site}`);
2539
2540
  }
2540
2541
  }
2542
+ const currentDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
2543
+ const sgOffset = 8 * 60 * 60 * 1e3;
2544
+ const sgTime = new Date(currentDate.getTime() + sgOffset);
2545
+ const dateStr = `${sgTime.getUTCFullYear()}-${String(sgTime.getUTCMonth() + 1).padStart(2, "0")}-${String(sgTime.getUTCDate()).padStart(2, "0")}`;
2541
2546
  return {
2542
2547
  site: value.site,
2543
2548
  serviceType: value.serviceType,
2544
2549
  status: "open",
2545
- createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
2546
- updatedAt: value.updatedAt ?? ""
2550
+ createdAt: currentDate,
2551
+ updatedAt: value.updatedAt ?? "",
2552
+ dateStr
2547
2553
  };
2548
2554
  }
2549
2555
 
2550
2556
  // src/repositories/hygiene-parent-checklist.repository.ts
2551
2557
  var import_mongodb7 = require("mongodb");
2552
- var import_moment_timezone2 = __toESM(require("moment-timezone"));
2553
2558
  var import_node_server_utils14 = require("@7365admin1/node-server-utils");
2554
2559
  var import_core7 = require("@7365admin1/core");
2555
2560
  function useParentChecklistRepo() {
@@ -2564,13 +2569,55 @@ function useParentChecklistRepo() {
2564
2569
  const { delNamespace, setCache, getCache } = (0, import_node_server_utils14.useCache)(namespace_collection);
2565
2570
  async function createIndex() {
2566
2571
  try {
2572
+ await collection.updateMany(
2573
+ { dateStr: { $exists: false } },
2574
+ [
2575
+ {
2576
+ $set: {
2577
+ dateStr: {
2578
+ $let: {
2579
+ vars: {
2580
+ sgTime: { $add: ["$createdAt", 8 * 60 * 60 * 1e3] }
2581
+ },
2582
+ in: {
2583
+ $dateToString: {
2584
+ format: "%Y-%m-%d",
2585
+ date: "$$sgTime",
2586
+ timezone: "UTC"
2587
+ }
2588
+ }
2589
+ }
2590
+ }
2591
+ }
2592
+ }
2593
+ ]
2594
+ );
2595
+ const duplicates = await collection.aggregate([
2596
+ {
2597
+ $group: {
2598
+ _id: { site: "$site", serviceType: "$serviceType", dateStr: "$dateStr" },
2599
+ docs: { $push: "$_id" },
2600
+ count: { $sum: 1 }
2601
+ }
2602
+ },
2603
+ { $match: { count: { $gt: 1 } } }
2604
+ ]).toArray();
2605
+ for (const group of duplicates) {
2606
+ const toDelete = group.docs.slice(1);
2607
+ await collection.deleteMany({ _id: { $in: toDelete } });
2608
+ import_node_server_utils14.logger.info(
2609
+ `Deleted ${toDelete.length} duplicate parent checklists for site ${group._id.site} / ${group._id.serviceType} on date ${group._id.dateStr}`
2610
+ );
2611
+ }
2567
2612
  await collection.createIndexes([
2568
2613
  { key: { serviceType: 1 } },
2569
2614
  { key: { createdAt: 1 } },
2570
2615
  { key: { site: 1 } },
2571
- { key: { status: 1 } }
2616
+ { key: { status: 1 } },
2617
+ { key: { site: 1, serviceType: 1, dateStr: 1 }, unique: true }
2572
2618
  ]);
2573
2619
  } catch (error) {
2620
+ import_node_server_utils14.logger.error("Failed to create index/backfill on hygiene parent checklist:", error);
2574
2621
  throw new import_node_server_utils14.InternalServerError(
2575
2622
  "Failed to create index on hygiene parent checklist."
2576
2623
  );
@@ -2579,10 +2626,13 @@ function useParentChecklistRepo() {
2579
2626
  async function createParentChecklist(value, session) {
2580
2627
  try {
2581
2628
  const currentDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
2582
- const startOfDay = (0, import_moment_timezone2.default)(currentDate).tz("Asia/Singapore").startOf("day").toDate();
2583
- const endOfDay = (0, import_moment_timezone2.default)(currentDate).tz("Asia/Singapore").endOf("day").toDate();
2629
+ const sgOffset = 8 * 60 * 60 * 1e3;
2630
+ const sgTime = new Date(currentDate.getTime() + sgOffset);
2631
+ const startOfDay = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
2632
+ const endOfDay = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2633
+ const targetDateStr = `${sgTime.getUTCFullYear()}-${String(sgTime.getUTCMonth() + 1).padStart(2, "0")}-${String(sgTime.getUTCDate()).padStart(2, "0")}`;
2634
+ const dateStr = targetDateStr;
2584
2635
  const allServiceTypes = Object.values(import_core7.AppServiceType);
2585
- const dateStr = currentDate.toISOString().split("T")[0];
2586
2636
  if (value.site) {
2587
2637
  let siteObjectId;
2588
2638
  try {
@@ -2592,9 +2642,12 @@ function useParentChecklistRepo() {
2592
2642
  }
2593
2643
  if (value.serviceType) {
2594
2644
  const existingChecklist = await collection.findOne({
2595
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2596
2645
  site: siteObjectId,
2597
- serviceType: value.serviceType
2646
+ serviceType: value.serviceType,
2647
+ $or: [
2648
+ { dateStr: targetDateStr },
2649
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2650
+ ]
2598
2651
  });
2599
2652
  if (existingChecklist) {
2600
2653
  import_node_server_utils14.logger.info(
@@ -2607,22 +2660,41 @@ function useParentChecklistRepo() {
2607
2660
  createdAt: currentDate,
2608
2661
  serviceType: value.serviceType
2609
2662
  });
2610
- const result3 = await collection.insertOne(doc, { session });
2611
- delNamespace().catch((err) => {
2612
- import_node_server_utils14.logger.error(
2613
- `Failed to clear cache for namespace: ${namespace_collection}`,
2614
- err
2663
+ let insertedId;
2664
+ try {
2665
+ const result = await collection.insertOne(doc, { session });
2666
+ insertedId = result.insertedId;
2667
+ delNamespace().catch((err) => {
2668
+ import_node_server_utils14.logger.error(
2669
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2670
+ err
2671
+ );
2672
+ });
2673
+ import_node_server_utils14.logger.info(
2674
+ `Created parent checklist for site ${value.site} / ${value.serviceType} for today: ${dateStr}`
2615
2675
  );
2616
- });
2617
- import_node_server_utils14.logger.info(
2618
- `Created parent checklist for site ${value.site} / ${value.serviceType} for today: ${dateStr}`
2619
- );
2620
- return result3.insertedId;
2676
+ } catch (error) {
2677
+ if (error.code === 11e3) {
2678
+ const existingChecklist2 = await collection.findOne({
2679
+ site: siteObjectId,
2680
+ serviceType: value.serviceType,
2681
+ dateStr: targetDateStr
2682
+ });
2683
+ if (existingChecklist2) {
2684
+ return existingChecklist2._id;
2685
+ }
2686
+ }
2687
+ throw error;
2688
+ }
2689
+ return insertedId;
2621
2690
  }
2622
2691
  const existingServiceTypes = await collection.distinct("serviceType", {
2623
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2624
2692
  site: siteObjectId,
2625
- serviceType: { $exists: true, $ne: null }
2693
+ serviceType: { $exists: true, $ne: null },
2694
+ $or: [
2695
+ { dateStr: targetDateStr },
2696
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2697
+ ]
2626
2698
  });
2627
2699
  const missingServiceTypes = allServiceTypes.filter(
2628
2700
  (st) => !existingServiceTypes.includes(st)
@@ -2632,8 +2704,11 @@ function useParentChecklistRepo() {
2632
2704
  `All serviceType checklists already exist for site ${value.site} on ${dateStr}`
2633
2705
  );
2634
2706
  const first = await collection.findOne({
2635
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2636
- site: siteObjectId
2707
+ site: siteObjectId,
2708
+ $or: [
2709
+ { dateStr: targetDateStr },
2710
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2711
+ ]
2637
2712
  });
2638
2713
  return first._id;
2639
2714
  }
@@ -2644,17 +2719,30 @@ function useParentChecklistRepo() {
2644
2719
  serviceType
2645
2720
  })
2646
2721
  );
2647
- const result2 = await collection.insertMany(checklistDocs2, { session });
2648
- delNamespace().catch((err) => {
2649
- import_node_server_utils14.logger.error(
2650
- `Failed to clear cache for namespace: ${namespace_collection}`,
2651
- err
2722
+ let insertedIds2 = [];
2723
+ try {
2724
+ const result = await collection.insertMany(checklistDocs2, { session, ordered: false });
2725
+ insertedIds2 = Object.values(result.insertedIds);
2726
+ delNamespace().catch((err) => {
2727
+ import_node_server_utils14.logger.error(
2728
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2729
+ err
2730
+ );
2731
+ });
2732
+ import_node_server_utils14.logger.info(
2733
+ `Created ${checklistDocs2.length} parent checklists for site ${value.site} for today: ${dateStr}`
2652
2734
  );
2653
- });
2654
- import_node_server_utils14.logger.info(
2655
- `Created ${checklistDocs2.length} parent checklists for site ${value.site} for today: ${dateStr}`
2656
- );
2657
- return Object.values(result2.insertedIds);
2735
+ } catch (error) {
2736
+ if (error.code === 11e3 || error.writeErrors) {
2737
+ const existing = await collection.find({
2738
+ site: siteObjectId,
2739
+ dateStr: targetDateStr
2740
+ }).toArray();
2741
+ return existing.map((e) => e._id);
2742
+ }
2743
+ throw error;
2744
+ }
2745
+ return insertedIds2;
2658
2746
  }
2659
2747
  const siteIds = await getHygieneSiteIds();
2660
2748
  if (!Array.isArray(siteIds)) {
@@ -2667,8 +2755,11 @@ function useParentChecklistRepo() {
2667
2755
  }
2668
2756
  const existingPairs = await collection.find(
2669
2757
  {
2670
- createdAt: { $gte: startOfDay, $lte: endOfDay },
2671
- serviceType: { $exists: true, $ne: null }
2758
+ serviceType: { $exists: true, $ne: null },
2759
+ $or: [
2760
+ { dateStr: targetDateStr },
2761
+ { createdAt: { $gte: startOfDay, $lte: endOfDay } }
2762
+ ]
2672
2763
  },
2673
2764
  { projection: { site: 1, serviceType: 1 } }
2674
2765
  ).toArray();
@@ -2700,19 +2791,31 @@ function useParentChecklistRepo() {
2700
2791
  import_node_server_utils14.logger.info(
2701
2792
  `createParentChecklist: Creating ${checklistDocs.length} missing site+serviceType checklist(s) for today: ${dateStr}`
2702
2793
  );
2703
- const result = await collection.insertMany(checklistDocs, { session });
2704
- delNamespace().then(() => {
2705
- import_node_server_utils14.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
2706
- }).catch((err) => {
2707
- import_node_server_utils14.logger.error(
2708
- `Failed to clear cache for namespace: ${namespace_collection}`,
2709
- err
2794
+ let insertedIds = [];
2795
+ try {
2796
+ const result = await collection.insertMany(checklistDocs, { session, ordered: false });
2797
+ insertedIds = Object.values(result.insertedIds);
2798
+ delNamespace().then(() => {
2799
+ import_node_server_utils14.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
2800
+ }).catch((err) => {
2801
+ import_node_server_utils14.logger.error(
2802
+ `Failed to clear cache for namespace: ${namespace_collection}`,
2803
+ err
2804
+ );
2805
+ });
2806
+ import_node_server_utils14.logger.info(
2807
+ `Created ${Object.keys(result.insertedIds).length} parent checklists for today: ${dateStr}`
2710
2808
  );
2711
- });
2712
- import_node_server_utils14.logger.info(
2713
- `Created ${Object.keys(result.insertedIds).length} parent checklists for today: ${dateStr}`
2714
- );
2715
- return Object.values(result.insertedIds);
2809
+ } catch (error) {
2810
+ if (error.code === 11e3 || error.writeErrors) {
2811
+ const existing = await collection.find({
2812
+ dateStr: targetDateStr
2813
+ }).toArray();
2814
+ return existing.map((e) => e._id);
2815
+ }
2816
+ throw error;
2817
+ }
2818
+ return insertedIds;
2716
2819
  } catch (error) {
2717
2820
  import_node_server_utils14.logger.error("Failed to create daily parent checklist", error);
2718
2821
  throw error;
@@ -2931,8 +3034,11 @@ function useParentChecklistRepo() {
2931
3034
  }
2932
3035
  }
2933
3036
  async function getTodayParentChecklists() {
2934
- const start = (0, import_moment_timezone2.default)().tz("Asia/Singapore").startOf("day").toDate();
2935
- const end = (0, import_moment_timezone2.default)().tz("Asia/Singapore").endOf("day").toDate();
3037
+ const sgOffset = 8 * 60 * 60 * 1e3;
3038
+ const now = /* @__PURE__ */ new Date();
3039
+ const sgTime = new Date(now.getTime() + sgOffset);
3040
+ const start = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
3041
+ const end = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2936
3042
  try {
2937
3043
  const items = await collection.find(
2938
3044
  { createdAt: { $gte: start, $lte: end } },
@@ -2945,8 +3051,11 @@ function useParentChecklistRepo() {
2945
3051
  }
2946
3052
  }
2947
3053
  async function getTodayParentChecklistsForAreaGen() {
2948
- const start = (0, import_moment_timezone2.default)().tz("Asia/Singapore").startOf("day").toDate();
2949
- const end = (0, import_moment_timezone2.default)().tz("Asia/Singapore").endOf("day").toDate();
3054
+ const sgOffset = 8 * 60 * 60 * 1e3;
3055
+ const now = /* @__PURE__ */ new Date();
3056
+ const sgTime = new Date(now.getTime() + sgOffset);
3057
+ const start = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 0, 0, 0, 0) - sgOffset);
3058
+ const end = new Date(Date.UTC(sgTime.getUTCFullYear(), sgTime.getUTCMonth(), sgTime.getUTCDate(), 23, 59, 59, 999) - sgOffset);
2950
3059
  try {
2951
3060
  const items = await collection.find(
2952
3061
  {