@7365admin1/module-hygiene 4.31.0 → 4.32.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.32.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 98ff56f: Extra visits: editing a repeating visit no longer fails; one extra visit adds one round; an area or day already Done is reopened when an extra round is added; Next visit is right for a task saved after today's time.
8
+
9
+ ## 4.32.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 8b89acd: Extra-visit sets now store `scheduleTaskId`, `scheduleTaskTitle` and `scheduleTaskTime`, returned by the area-checklist unit/set responses (null on older sets). The history PDF marks not-done items "Missed".
14
+
3
15
  ## 4.31.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -242,6 +242,7 @@ declare function useParentChecklistRepo(): {
242
242
  _id: ObjectId;
243
243
  }>;
244
244
  updateParentChecklistStatuses: (_id: string | ObjectId, status: (typeof allowedStatus)[number], session?: ClientSession) => Promise<number>;
245
+ reopenParentChecklist: (_id: string | ObjectId) => Promise<number>;
245
246
  getHygieneSiteIds: () => Promise<any[]>;
246
247
  closeExpiredParentChecklists: () => Promise<number>;
247
248
  getTodayParentChecklists: () => Promise<{
@@ -281,6 +282,8 @@ type TAreaChecklist = {
281
282
  attachment?: string[];
282
283
  isScheduleTask?: boolean;
283
284
  scheduleTaskId?: string | ObjectId;
285
+ scheduleTaskTitle?: string;
286
+ scheduleTaskTime?: string;
284
287
  };
285
288
  type TAreaChecklistUnits = {
286
289
  unit: string | ObjectId;
package/dist/index.js CHANGED
@@ -3015,6 +3015,18 @@ function useParentChecklistRepo() {
3015
3015
  throw error;
3016
3016
  }
3017
3017
  }
3018
+ async function reopenParentChecklist(_id) {
3019
+ const res = await collection.updateOne(
3020
+ { _id: new import_mongodb7.ObjectId(_id), status: "completed" },
3021
+ { $set: { status: "ongoing", updatedAt: /* @__PURE__ */ new Date() }, $unset: { completedAt: "" } }
3022
+ );
3023
+ if (res.modifiedCount > 0) {
3024
+ delNamespace().catch((err) => {
3025
+ import_node_server_utils14.logger.error(`Failed to clear cache for namespace: ${namespace_collection}`, err);
3026
+ });
3027
+ }
3028
+ return res.modifiedCount;
3029
+ }
3018
3030
  async function getHygieneSiteIds() {
3019
3031
  const query = {
3020
3032
  status: { $ne: "deleted" }
@@ -3121,6 +3133,7 @@ function useParentChecklistRepo() {
3121
3133
  getAllParentChecklist,
3122
3134
  getParentChecklistById,
3123
3135
  updateParentChecklistStatuses,
3136
+ reopenParentChecklist,
3124
3137
  getHygieneSiteIds,
3125
3138
  closeExpiredParentChecklists,
3126
3139
  getTodayParentChecklists,
@@ -3233,7 +3246,9 @@ var areaChecklistSchema = import_joi9.default.object({
3233
3246
  }).required()
3234
3247
  ).min(1).required(),
3235
3248
  isScheduleTask: import_joi9.default.boolean().optional().default(false),
3236
- scheduleTaskId: import_joi9.default.string().hex().optional().allow(null)
3249
+ scheduleTaskId: import_joi9.default.string().hex().optional().allow(null),
3250
+ scheduleTaskTitle: import_joi9.default.string().optional().allow("", null),
3251
+ scheduleTaskTime: import_joi9.default.string().optional().allow("", null)
3237
3252
  }).required()
3238
3253
  ).optional().default([])
3239
3254
  });
@@ -3263,6 +3278,8 @@ function MAreaChecklist(value) {
3263
3278
  set: checklistItem.set,
3264
3279
  isScheduleTask: checklistItem.isScheduleTask ?? false,
3265
3280
  scheduleTaskId: checklistItem.scheduleTaskId ?? void 0,
3281
+ scheduleTaskTitle: checklistItem.scheduleTaskTitle ?? void 0,
3282
+ scheduleTaskTime: checklistItem.scheduleTaskTime ?? void 0,
3266
3283
  units: checklistItem.units.map((unit) => ({
3267
3284
  unit: new import_mongodb8.ObjectId(unit.unit),
3268
3285
  name: unit.name,
@@ -3745,6 +3762,9 @@ function useAreaChecklistRepo() {
3745
3762
  isScheduleTask: {
3746
3763
  $ifNull: ["$checklist.isScheduleTask", false]
3747
3764
  },
3765
+ scheduleTaskId: { $ifNull: ["$checklist.scheduleTaskId", null] },
3766
+ scheduleTaskTitle: { $ifNull: ["$checklist.scheduleTaskTitle", null] },
3767
+ scheduleTaskTime: { $ifNull: ["$checklist.scheduleTaskTime", null] },
3748
3768
  unit: "$checklist.units.unit",
3749
3769
  name: "$checklist.units.name",
3750
3770
  approve: "$checklist.units.approve",
@@ -3781,6 +3801,9 @@ function useAreaChecklistRepo() {
3781
3801
  $group: {
3782
3802
  _id: "$set",
3783
3803
  isScheduleTask: { $first: "$isScheduleTask" },
3804
+ scheduleTaskId: { $first: "$scheduleTaskId" },
3805
+ scheduleTaskTitle: { $first: "$scheduleTaskTitle" },
3806
+ scheduleTaskTime: { $first: "$scheduleTaskTime" },
3784
3807
  units: {
3785
3808
  $push: {
3786
3809
  unit: "$unit",
@@ -3801,6 +3824,9 @@ function useAreaChecklistRepo() {
3801
3824
  _id: 0,
3802
3825
  set: "$_id",
3803
3826
  isScheduleTask: 1,
3827
+ scheduleTaskId: 1,
3828
+ scheduleTaskTitle: 1,
3829
+ scheduleTaskTime: 1,
3804
3830
  units: 1
3805
3831
  }
3806
3832
  },
@@ -3932,6 +3958,8 @@ function useAreaChecklistRepo() {
3932
3958
  isScheduleTask: {
3933
3959
  $ifNull: ["$checklist.isScheduleTask", false]
3934
3960
  },
3961
+ scheduleTaskTitle: { $ifNull: ["$checklist.scheduleTaskTitle", null] },
3962
+ scheduleTaskTime: { $ifNull: ["$checklist.scheduleTaskTime", null] },
3935
3963
  scheduleTaskId: {
3936
3964
  $ifNull: ["$checklist.scheduleTaskId", null]
3937
3965
  },
@@ -3972,6 +4000,8 @@ function useAreaChecklistRepo() {
3972
4000
  $group: {
3973
4001
  _id: "$set",
3974
4002
  isScheduleTask: { $first: "$isScheduleTask" },
4003
+ scheduleTaskTitle: { $first: "$scheduleTaskTitle" },
4004
+ scheduleTaskTime: { $first: "$scheduleTaskTime" },
3975
4005
  scheduleTaskId: { $first: "$scheduleTaskId" },
3976
4006
  remarks: { $first: "$remarks" },
3977
4007
  attachment: { $first: "$attachment" },
@@ -3996,6 +4026,8 @@ function useAreaChecklistRepo() {
3996
4026
  _id: 0,
3997
4027
  set: "$_id",
3998
4028
  isScheduleTask: 1,
4029
+ scheduleTaskTitle: 1,
4030
+ scheduleTaskTime: 1,
3999
4031
  scheduleTaskId: 1,
4000
4032
  remarks: "$remarks",
4001
4033
  attachment: "$attachment",
@@ -4318,6 +4350,10 @@ function useAreaChecklistRepo() {
4318
4350
  }
4319
4351
  );
4320
4352
  if (result.modifiedCount > 0) {
4353
+ await collection.updateOne(
4354
+ { schedule, serviceType, area, status: "completed" },
4355
+ { $set: { status: "ongoing", updatedAt: /* @__PURE__ */ new Date() }, $unset: { completedAt: "" } }
4356
+ );
4321
4357
  delNamespace().catch((err) => {
4322
4358
  import_node_server_utils17.logger.error(
4323
4359
  `Failed to clear cache for namespace: ${namespace_collection}`,
@@ -4614,6 +4650,9 @@ function validateScheduleRules(task, now = /* @__PURE__ */ new Date()) {
4614
4650
  }
4615
4651
  if (task.endDate && task.endDate < today)
4616
4652
  return "The end date has already passed.";
4653
+ if (!repeating && !(task.dates ?? []).length) {
4654
+ return "Pick at least one date, or choose a repeat.";
4655
+ }
4617
4656
  if (!repeating) {
4618
4657
  const dates = (task.dates ?? []).filter((d) => !task.endDate || d <= task.endDate);
4619
4658
  if (dates.length && dates.every((d) => d < today)) {
@@ -4976,6 +5015,8 @@ var import_core11 = require("@7365admin1/core");
4976
5015
  var import_puppeteer = require("puppeteer");
4977
5016
  var import_node_server_utils19 = require("@7365admin1/node-server-utils");
4978
5017
  var import_mongodb11 = require("mongodb");
5018
+
5019
+ // src/utils/checklist-pdf-html.util.ts
4979
5020
  function escapeHtml(text) {
4980
5021
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
4981
5022
  }
@@ -4988,7 +5029,7 @@ function buildChecklistHtml(areaChecklists) {
4988
5029
  const unitRows = (setItem.units || []).map(
4989
5030
  (unit) => `
4990
5031
  <tr>
4991
- <td class="unit-name">${escapeHtml(unit.name || "")}</td>
5032
+ <td class="unit-name">${escapeHtml(unit.name || "")}${unit.approve || unit.reject ? "" : ' <span class="missed-label">Missed</span>'}</td>
4992
5033
  <td class="icon-cell">${unit.reject ? '<span class="reject-icon">&#10007;</span>' : ""}</td>
4993
5034
  <td class="icon-cell">${unit.approve ? '<span class="approve-icon">&#10003;</span>' : ""}</td>
4994
5035
  </tr>`
@@ -5125,6 +5166,12 @@ function buildChecklistHtml(areaChecklists) {
5125
5166
  font-size: 16px;
5126
5167
  font-weight: bold;
5127
5168
  }
5169
+ .missed-label {
5170
+ color: #b3261e;
5171
+ font-size: 11px;
5172
+ font-weight: bold;
5173
+ margin-left: 6px;
5174
+ }
5128
5175
  .reject-icon {
5129
5176
  color: #e74c3c;
5130
5177
  font-size: 16px;
@@ -5140,6 +5187,8 @@ function buildChecklistHtml(areaChecklists) {
5140
5187
  </body>
5141
5188
  </html>`;
5142
5189
  }
5190
+
5191
+ // src/services/hygiene-checklist-pdf.service.ts
5143
5192
  function useChecklistPdfService() {
5144
5193
  async function generateChecklistPdf(scheduleId) {
5145
5194
  const db = import_node_server_utils19.useAtlas.getDb();
@@ -7021,7 +7070,11 @@ var SCHEDULE_FIELDS = {
7021
7070
  startDate: 1,
7022
7071
  endDate: 1,
7023
7072
  paused: 1,
7024
- lastRunDate: 1
7073
+ lastRunDate: 1,
7074
+ // when it was saved: a task saved after its time today waits for its next
7075
+ // day, so Next visit must know it (else it says "today" for a visit that never comes)
7076
+ createdAt: 1,
7077
+ updatedAt: 1
7025
7078
  };
7026
7079
  function useScheduleTaskRepository() {
7027
7080
  const db = import_node_server_utils33.useAtlas.getDb();
@@ -7266,7 +7319,6 @@ function useScheduleTaskRepository() {
7266
7319
  description: 1,
7267
7320
  areas: 1,
7268
7321
  status: 1,
7269
- createdAt: 1,
7270
7322
  site: 1,
7271
7323
  serviceType: 1,
7272
7324
  ...SCHEDULE_FIELDS
@@ -7391,11 +7443,23 @@ function useScheduleTaskRepository() {
7391
7443
  };
7392
7444
  }
7393
7445
 
7446
+ // src/utils/schedule-task-set.util.ts
7447
+ function buildScheduleTaskSets(task, units, startSet, count = 1) {
7448
+ return Array.from({ length: count }, (_, i) => ({
7449
+ set: startSet + i,
7450
+ units,
7451
+ isScheduleTask: true,
7452
+ scheduleTaskId: task._id,
7453
+ scheduleTaskTitle: task.title,
7454
+ scheduleTaskTime: task.time
7455
+ }));
7456
+ }
7457
+
7394
7458
  // src/services/hygiene-schedule-task.service.ts
7395
7459
  var import_mongodb20 = require("mongodb");
7396
7460
  var import_node_server_utils34 = require("@7365admin1/node-server-utils");
7397
7461
  function useScheduleTaskService() {
7398
- const { createParentChecklist } = useParentChecklistRepo();
7462
+ const { createParentChecklist, reopenParentChecklist } = useParentChecklistRepo();
7399
7463
  const { getAllScheduleTask, markScheduleTaskRan } = useScheduleTaskRepository();
7400
7464
  const {
7401
7465
  createAreaChecklist,
@@ -7466,7 +7530,7 @@ function useScheduleTaskService() {
7466
7530
  const parentChecklistIds = await createParentChecklist({
7467
7531
  site: scheduleTask.site.toString(),
7468
7532
  serviceType,
7469
- createdAt: /* @__PURE__ */ new Date()
7533
+ createdAt: currentDate ?? /* @__PURE__ */ new Date()
7470
7534
  });
7471
7535
  const parentChecklistId = Array.isArray(parentChecklistIds) ? parentChecklistIds[0] : parentChecklistIds;
7472
7536
  import_node_server_utils34.logger.info(
@@ -7529,22 +7593,13 @@ function useScheduleTaskService() {
7529
7593
  );
7530
7594
  }
7531
7595
  if (existingAreaChecklist) {
7532
- const areaSetConfig = Number(areaDetails.set) || 1;
7533
7596
  const maxSetInChecklist = existingAreaChecklist.checklist?.length ? Math.max(
7534
7597
  ...existingAreaChecklist.checklist.map(
7535
7598
  (c) => c.set
7536
7599
  )
7537
7600
  ) : 0;
7538
7601
  const startSetNumber = maxSetInChecklist + 1;
7539
- const newSets = Array.from(
7540
- { length: areaSetConfig },
7541
- (_, index) => ({
7542
- set: startSetNumber + index,
7543
- units,
7544
- isScheduleTask: true,
7545
- scheduleTaskId: scheduleTask._id
7546
- })
7547
- );
7602
+ const newSets = buildScheduleTaskSets(scheduleTask, units, startSetNumber);
7548
7603
  const modified = await pushScheduleTaskSets(
7549
7604
  parentChecklistId.toString(),
7550
7605
  serviceType,
@@ -7555,7 +7610,7 @@ function useScheduleTaskService() {
7555
7610
  if (modified > 0) {
7556
7611
  addedAreas.push(area.name);
7557
7612
  import_node_server_utils34.logger.info(
7558
- `Appended ${areaSetConfig} set(s) starting from ${startSetNumber} to area checklist for area ${area.name}`
7613
+ `Appended extra-visit set ${startSetNumber} to area checklist for area ${area.name}`
7559
7614
  );
7560
7615
  } else {
7561
7616
  import_node_server_utils34.logger.info(
@@ -7563,17 +7618,7 @@ function useScheduleTaskService() {
7563
7618
  );
7564
7619
  }
7565
7620
  } else {
7566
- const areaSetConfig = Number(areaDetails.set) || 1;
7567
- const schedTaskId = scheduleTask._id;
7568
- const schedTaskSets = Array.from(
7569
- { length: areaSetConfig },
7570
- (_, index) => ({
7571
- set: index + 1,
7572
- units,
7573
- isScheduleTask: true,
7574
- scheduleTaskId: schedTaskId
7575
- })
7576
- );
7621
+ const schedTaskSets = buildScheduleTaskSets(scheduleTask, units, 1);
7577
7622
  const checklistData = {
7578
7623
  schedule: parentChecklistId.toString(),
7579
7624
  serviceType,
@@ -7595,6 +7640,13 @@ function useScheduleTaskService() {
7595
7640
  continue;
7596
7641
  }
7597
7642
  }
7643
+ if (addedAreas.length > 0) {
7644
+ try {
7645
+ await reopenParentChecklist(parentChecklistId);
7646
+ } catch (error) {
7647
+ import_node_server_utils34.logger.error(`Could not reopen day list ${parentChecklistId}`, error);
7648
+ }
7649
+ }
7598
7650
  const attemptKey = `${scheduleTask._id}:${today}`;
7599
7651
  const tried = (attempts.get(attemptKey) ?? 0) + 1;
7600
7652
  attempts.set(attemptKey, tried);
@@ -7744,8 +7796,8 @@ function useScheduleTaskController() {
7744
7796
  const optional = Object.fromEntries(
7745
7797
  Object.entries(scheduleTaskFields).map(([key, rule]) => [
7746
7798
  key,
7747
- key === "dates" ? import_joi19.default.array().min(1).items(scheduleDate).optional().messages({
7748
- "array.min": "Pick at least one date, or choose a repeat."
7799
+ key === "dates" ? import_joi19.default.array().items(scheduleDate).optional().messages({
7800
+ "array.base": "Dates must be a list of dates."
7749
7801
  }) : rule.optional()
7750
7802
  ])
7751
7803
  );