@7365admin1/module-hygiene 4.23.1 → 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,17 @@
1
1
  # @7365admin1/module-hygiene
2
2
 
3
+ ## 4.24.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Update module hygiene package
8
+
9
+ ## 4.24.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Update hygiene package
14
+
3
15
  ## 4.23.1
4
16
 
5
17
  ### Patch 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;
@@ -287,6 +289,7 @@ type TAreaChecklistUnits = {
287
289
  reject?: boolean;
288
290
  status?: (typeof allowedChecklistStatus)[number];
289
291
  remarks?: string;
292
+ attachment?: string[];
290
293
  completedBy?: string | ObjectId;
291
294
  timestamp?: Date | string;
292
295
  };
@@ -302,7 +305,7 @@ type TCleaningScheduleAreaGetQuery = {
302
305
  status?: (typeof allowedStatus)[number] | "all";
303
306
  } & Pick<TCleaningScheduleArea, "schedule" | "serviceType">;
304
307
  type TAreaChecklistUpdate = Pick<TCleaningScheduleArea, "checklist">;
305
- type TAreaChecklistUnitsUpdate = Pick<TAreaChecklistUnits, "approve" | "reject" | "remarks" | "completedBy"> & Pick<TAreaChecklist, "attachment">;
308
+ type TAreaChecklistUnitsUpdate = Pick<TAreaChecklistUnits, "approve" | "reject" | "remarks" | "attachment" | "completedBy">;
306
309
  declare const areaChecklistSchema: Joi.ObjectSchema<any>;
307
310
  declare function MAreaChecklist(value: TAreaChecklistCreate): {
308
311
  schedule: string | 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
  {
@@ -3119,6 +3228,7 @@ function MAreaChecklist(value) {
3119
3228
  reject: false,
3120
3229
  status: "open",
3121
3230
  remarks: "",
3231
+ attachment: [],
3122
3232
  completedBy: "",
3123
3233
  timestamp: ""
3124
3234
  }))
@@ -3544,7 +3654,12 @@ function useAreaChecklistRepo() {
3544
3654
  },
3545
3655
  unit: "$checklist.units.unit",
3546
3656
  name: "$checklist.units.name",
3657
+ approve: "$checklist.units.approve",
3658
+ reject: "$checklist.units.reject",
3547
3659
  remarks: "$checklist.units.remarks",
3660
+ attachment: {
3661
+ $ifNull: ["$checklist.units.attachment", []]
3662
+ },
3548
3663
  status: {
3549
3664
  $switch: {
3550
3665
  branches: [
@@ -3577,8 +3692,11 @@ function useAreaChecklistRepo() {
3577
3692
  $push: {
3578
3693
  unit: "$unit",
3579
3694
  name: "$name",
3695
+ approve: "$approve",
3696
+ reject: "$reject",
3580
3697
  status: "$status",
3581
3698
  remarks: "$remarks",
3699
+ attachment: "$attachment",
3582
3700
  completedByName: "$completedByName",
3583
3701
  timestamp: "$timestamp"
3584
3702
  }
@@ -3730,6 +3848,10 @@ function useAreaChecklistRepo() {
3730
3848
  name: "$checklist.units.name",
3731
3849
  approve: "$checklist.units.approve",
3732
3850
  reject: "$checklist.units.reject",
3851
+ unitRemarks: "$checklist.units.remarks",
3852
+ unitAttachment: {
3853
+ $ifNull: ["$checklist.units.attachment", []]
3854
+ },
3733
3855
  timestamp: "$checklist.units.timestamp",
3734
3856
  status: {
3735
3857
  $switch: {
@@ -3769,7 +3891,8 @@ function useAreaChecklistRepo() {
3769
3891
  reject: "$reject",
3770
3892
  timestamp: "$timestamp",
3771
3893
  status: "$status",
3772
- remarks: "$remarks",
3894
+ remarks: "$unitRemarks",
3895
+ attachment: "$unitAttachment",
3773
3896
  completedByName: "$completedByName"
3774
3897
  }
3775
3898
  }
@@ -3917,16 +4040,13 @@ function useAreaChecklistRepo() {
3917
4040
  } else if (value.reject === true) {
3918
4041
  updateValue["checklist.$[checklist].units.$[unit].approve"] = false;
3919
4042
  updateValue["checklist.$[checklist].units.$[unit].reject"] = true;
3920
- updateValue["checklist.$[checklist].units.$[unit].status"] = "open";
4043
+ updateValue["checklist.$[checklist].units.$[unit].status"] = "completed";
3921
4044
  }
3922
- if (value.remarks) {
3923
- updateValue["checklist.$[checklist].units.$[unit].remarks"] = value.remarks;
4045
+ if (value.remarks !== void 0) {
4046
+ updateValue["checklist.$[checklist].units.$[unit].remarks"] = value.remarks ?? "";
3924
4047
  }
3925
- if (value.attachment) {
3926
- updateValue["checklist.$[checklist].attachment"] = value.attachment;
3927
- if (value.remarks) {
3928
- updateValue["checklist.$[checklist].remarks"] = value.remarks;
3929
- }
4048
+ if (value.attachment !== void 0) {
4049
+ updateValue["checklist.$[checklist].units.$[unit].attachment"] = value.attachment ?? [];
3930
4050
  }
3931
4051
  if (value.completedBy) {
3932
4052
  updateValue["checklist.$[checklist].units.$[unit].completedBy"] = new import_mongodb9.ObjectId(value.completedBy);
@@ -4354,6 +4474,7 @@ function useAreaChecklistService() {
4354
4474
  reject: false,
4355
4475
  status: "open",
4356
4476
  remarks: "",
4477
+ attachment: [],
4357
4478
  completedBy: "",
4358
4479
  timestamp: ""
4359
4480
  }))
@@ -6784,6 +6905,7 @@ function useScheduleTaskService() {
6784
6905
  reject: false,
6785
6906
  status: "open",
6786
6907
  remarks: "",
6908
+ attachment: [],
6787
6909
  completedBy: "",
6788
6910
  timestamp: ""
6789
6911
  }));