@7365admin1/module-hygiene 4.29.0 → 4.29.1-staging.13

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
@@ -3253,6 +3253,39 @@ import {
3253
3253
  useAtlas as useAtlas6,
3254
3254
  useCache as useCache5
3255
3255
  } from "@7365admin1/node-server-utils";
3256
+
3257
+ // src/utils/completion-photo.util.ts
3258
+ var COMPLETION_PHOTO_MESSAGE = "A photo is required to complete this task. Take or upload at least one photo before marking it complete.";
3259
+ function readCompletion(units, unitId) {
3260
+ if (units.length === 0)
3261
+ return { completesSet: false, hasEvidence: false };
3262
+ const others = units.filter((unit) => String(unit.unit) !== String(unitId));
3263
+ return {
3264
+ completesSet: others.every(
3265
+ (unit) => unit.approve === true || unit.reject === true
3266
+ ),
3267
+ hasEvidence: others.some(
3268
+ (unit) => Array.isArray(unit.attachment) && unit.attachment.length > 0
3269
+ )
3270
+ };
3271
+ }
3272
+ function requiresCompletionPhoto({
3273
+ decision,
3274
+ attachment,
3275
+ completesSet,
3276
+ hasEvidence
3277
+ }) {
3278
+ if (decision !== "approve")
3279
+ return false;
3280
+ if (!completesSet)
3281
+ return false;
3282
+ if (hasEvidence)
3283
+ return false;
3284
+ const carriesEvidence = Array.isArray(attachment) && attachment.some((id) => typeof id === "string" && id.trim().length > 0);
3285
+ return !carriesEvidence;
3286
+ }
3287
+
3288
+ // src/repositories/hygiene-area-checklist.repository.ts
3256
3289
  function useAreaChecklistRepo() {
3257
3290
  const db = useAtlas6.getDb();
3258
3291
  if (!db) {
@@ -3324,7 +3357,11 @@ function useAreaChecklistRepo() {
3324
3357
  const parentChecklistId = new ObjectId9(value.schedule);
3325
3358
  const areaId = new ObjectId9(value.area);
3326
3359
  const existingChecklist = await collection.findOne(
3327
- { schedule: parentChecklistId, area: areaId, serviceType: value.serviceType },
3360
+ {
3361
+ schedule: parentChecklistId,
3362
+ area: areaId,
3363
+ serviceType: value.serviceType
3364
+ },
3328
3365
  { session }
3329
3366
  );
3330
3367
  if (existingChecklist) {
@@ -4080,6 +4117,21 @@ function useAreaChecklistRepo() {
4080
4117
  throw error;
4081
4118
  }
4082
4119
  }
4120
+ async function readSetCompletionState(_id, set, unitId) {
4121
+ try {
4122
+ _id = new ObjectId9(_id);
4123
+ } catch (error) {
4124
+ throw new BadRequestError15("Invalid area checklist ID format.");
4125
+ }
4126
+ const doc = await collection.findOne(
4127
+ { _id, "checklist.set": set },
4128
+ { projection: { checklist: 1 } }
4129
+ );
4130
+ const group = (doc?.checklist ?? []).find(
4131
+ (entry) => entry.set === set
4132
+ );
4133
+ return readCompletion(group?.units ?? [], unitId);
4134
+ }
4083
4135
  async function updateAreaChecklist(_id, value, session) {
4084
4136
  try {
4085
4137
  _id = new ObjectId9(_id);
@@ -4364,6 +4416,7 @@ function useAreaChecklistRepo() {
4364
4416
  updateAreaChecklist,
4365
4417
  updateAreaChecklistStatus,
4366
4418
  updateAreaChecklistUnits,
4419
+ readSetCompletionState,
4367
4420
  getMaxSetNumberForArea,
4368
4421
  closeExpiredAreaChecklists,
4369
4422
  pushScheduleTaskSets,
@@ -4839,7 +4892,8 @@ function useAreaChecklistController() {
4839
4892
  getAllAreaChecklist: _getAllAreaChecklist,
4840
4893
  getAreaChecklistHistory: _getAreaChecklistHistory,
4841
4894
  getAreaChecklistHistoryDetails: _getAreaChecklistHistoryDetails,
4842
- getAreaChecklistUnits: _getAreaChecklistUnits
4895
+ getAreaChecklistUnits: _getAreaChecklistUnits,
4896
+ readSetCompletionState: _readSetCompletionState
4843
4897
  } = useAreaChecklistRepo();
4844
4898
  const {
4845
4899
  createAreaChecklist: _createAreaChecklist,
@@ -5043,7 +5097,12 @@ function useAreaChecklistController() {
5043
5097
  approve: Joi9.boolean().optional(),
5044
5098
  reject: Joi9.boolean().optional(),
5045
5099
  remarks: Joi9.string().optional().allow("", null),
5046
- attachment: Joi9.array().items(Joi9.string()).optional(),
5100
+ /*
5101
+ * Shape only. WHETHER a photo is required depends on the set's current
5102
+ * state in the database, which Joi cannot see — see the check below.
5103
+ * Each entry must still be a real id: a blank string carries no evidence.
5104
+ */
5105
+ attachment: Joi9.array().items(Joi9.string().trim().min(1)).optional(),
5047
5106
  completedBy: Joi9.string().hex().required()
5048
5107
  });
5049
5108
  const { error } = validation.validate(payload);
@@ -5054,7 +5113,24 @@ function useAreaChecklistController() {
5054
5113
  }
5055
5114
  try {
5056
5115
  const { id, set, unit, decision: decision2, ...value } = payload;
5057
- await _updateAreaChecklistUnits(id, parseInt(set), unit, value);
5116
+ const setNumber = parseInt(set);
5117
+ if (decision2 === "approve") {
5118
+ const { completesSet, hasEvidence } = await _readSetCompletionState(
5119
+ id,
5120
+ setNumber,
5121
+ unit
5122
+ );
5123
+ if (requiresCompletionPhoto({
5124
+ decision: decision2,
5125
+ attachment: value.attachment,
5126
+ completesSet,
5127
+ hasEvidence
5128
+ })) {
5129
+ next(new BadRequestError16(COMPLETION_PHOTO_MESSAGE));
5130
+ return;
5131
+ }
5132
+ }
5133
+ await _updateAreaChecklistUnits(id, setNumber, unit, value);
5058
5134
  res.json({ message: "Area checklist updated successfully." });
5059
5135
  return;
5060
5136
  } catch (error2) {