@7365admin1/module-hygiene 4.29.1-staging.12 → 4.30.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 +24 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +74 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +74 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/require-photo-on-completion.test.mjs +101 -120
package/dist/index.mjs
CHANGED
|
@@ -3324,7 +3324,11 @@ function useAreaChecklistRepo() {
|
|
|
3324
3324
|
const parentChecklistId = new ObjectId9(value.schedule);
|
|
3325
3325
|
const areaId = new ObjectId9(value.area);
|
|
3326
3326
|
const existingChecklist = await collection.findOne(
|
|
3327
|
-
{
|
|
3327
|
+
{
|
|
3328
|
+
schedule: parentChecklistId,
|
|
3329
|
+
area: areaId,
|
|
3330
|
+
serviceType: value.serviceType
|
|
3331
|
+
},
|
|
3328
3332
|
{ session }
|
|
3329
3333
|
);
|
|
3330
3334
|
if (existingChecklist) {
|
|
@@ -4080,6 +4084,32 @@ function useAreaChecklistRepo() {
|
|
|
4080
4084
|
throw error;
|
|
4081
4085
|
}
|
|
4082
4086
|
}
|
|
4087
|
+
async function readSetCompletionState(_id, set, unitId) {
|
|
4088
|
+
try {
|
|
4089
|
+
_id = new ObjectId9(_id);
|
|
4090
|
+
} catch (error) {
|
|
4091
|
+
throw new BadRequestError15("Invalid area checklist ID format.");
|
|
4092
|
+
}
|
|
4093
|
+
const doc = await collection.findOne(
|
|
4094
|
+
{ _id, "checklist.set": set },
|
|
4095
|
+
{ projection: { checklist: 1 } }
|
|
4096
|
+
);
|
|
4097
|
+
const group = (doc?.checklist ?? []).find(
|
|
4098
|
+
(entry) => entry.set === set
|
|
4099
|
+
);
|
|
4100
|
+
const units = group?.units ?? [];
|
|
4101
|
+
if (units.length === 0)
|
|
4102
|
+
return { completesSet: false, hasEvidence: false };
|
|
4103
|
+
const others = units.filter(
|
|
4104
|
+
(unit) => String(unit.unit) !== String(unitId)
|
|
4105
|
+
);
|
|
4106
|
+
return {
|
|
4107
|
+
completesSet: others.every((unit) => unit.status === "completed"),
|
|
4108
|
+
hasEvidence: others.some(
|
|
4109
|
+
(unit) => Array.isArray(unit.attachment) && unit.attachment.length > 0
|
|
4110
|
+
)
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
4083
4113
|
async function updateAreaChecklist(_id, value, session) {
|
|
4084
4114
|
try {
|
|
4085
4115
|
_id = new ObjectId9(_id);
|
|
@@ -4364,6 +4394,7 @@ function useAreaChecklistRepo() {
|
|
|
4364
4394
|
updateAreaChecklist,
|
|
4365
4395
|
updateAreaChecklistStatus,
|
|
4366
4396
|
updateAreaChecklistUnits,
|
|
4397
|
+
readSetCompletionState,
|
|
4367
4398
|
getMaxSetNumberForArea,
|
|
4368
4399
|
closeExpiredAreaChecklists,
|
|
4369
4400
|
pushScheduleTaskSets,
|
|
@@ -4619,6 +4650,24 @@ import {
|
|
|
4619
4650
|
} from "@7365admin1/node-server-utils";
|
|
4620
4651
|
import { AppServiceType as AppServiceType10 } from "@7365admin1/core";
|
|
4621
4652
|
|
|
4653
|
+
// src/utils/completion-photo.util.ts
|
|
4654
|
+
var COMPLETION_PHOTO_MESSAGE = "A photo is required to complete this task. Take or upload at least one photo before marking it complete.";
|
|
4655
|
+
function requiresCompletionPhoto({
|
|
4656
|
+
decision,
|
|
4657
|
+
attachment,
|
|
4658
|
+
completesSet,
|
|
4659
|
+
hasEvidence
|
|
4660
|
+
}) {
|
|
4661
|
+
if (decision !== "approve")
|
|
4662
|
+
return false;
|
|
4663
|
+
if (!completesSet)
|
|
4664
|
+
return false;
|
|
4665
|
+
if (hasEvidence)
|
|
4666
|
+
return false;
|
|
4667
|
+
const carriesEvidence = Array.isArray(attachment) && attachment.some((id) => typeof id === "string" && id.trim().length > 0);
|
|
4668
|
+
return !carriesEvidence;
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4622
4671
|
// src/services/hygiene-checklist-pdf.service.ts
|
|
4623
4672
|
import { launch } from "puppeteer";
|
|
4624
4673
|
import { InternalServerError as InternalServerError6, useAtlas as useAtlas8 } from "@7365admin1/node-server-utils";
|
|
@@ -4839,7 +4888,8 @@ function useAreaChecklistController() {
|
|
|
4839
4888
|
getAllAreaChecklist: _getAllAreaChecklist,
|
|
4840
4889
|
getAreaChecklistHistory: _getAreaChecklistHistory,
|
|
4841
4890
|
getAreaChecklistHistoryDetails: _getAreaChecklistHistoryDetails,
|
|
4842
|
-
getAreaChecklistUnits: _getAreaChecklistUnits
|
|
4891
|
+
getAreaChecklistUnits: _getAreaChecklistUnits,
|
|
4892
|
+
readSetCompletionState: _readSetCompletionState
|
|
4843
4893
|
} = useAreaChecklistRepo();
|
|
4844
4894
|
const {
|
|
4845
4895
|
createAreaChecklist: _createAreaChecklist,
|
|
@@ -5044,36 +5094,11 @@ function useAreaChecklistController() {
|
|
|
5044
5094
|
reject: Joi9.boolean().optional(),
|
|
5045
5095
|
remarks: Joi9.string().optional().allow("", null),
|
|
5046
5096
|
/*
|
|
5047
|
-
*
|
|
5048
|
-
*
|
|
5049
|
-
*
|
|
5050
|
-
* to take photo before completing the task ... all the services that has
|
|
5051
|
-
* this module must be the same process."*
|
|
5052
|
-
*
|
|
5053
|
-
* This endpoint is the one place every service and every client meets:
|
|
5054
|
-
* the five field apps (M&E, Cleaning, Landscape, Pest, Pool) all PATCH
|
|
5055
|
-
* `/api/hygiene-area-checklist/...` with a `serviceType`, and the web
|
|
5056
|
-
* checklist (`layer-common ManageChecklistMain`) posts here too. Requiring
|
|
5057
|
-
* it here is what makes "the same process" true rather than five client
|
|
5058
|
-
* guards that can drift apart — and a client guard alone is a suggestion.
|
|
5059
|
-
*
|
|
5060
|
-
* ONLY ON APPROVE. Completing a unit is the act the evidence is for.
|
|
5061
|
-
* A REJECT is the technician reporting a problem, and demanding a
|
|
5062
|
-
* photograph before somebody can report one would stop them reporting it.
|
|
5063
|
-
* `decision` carries which is which.
|
|
5064
|
-
*
|
|
5065
|
-
* At least one entry, and each must be a real id — an empty array or a
|
|
5066
|
-
* blank string would satisfy `.optional()` while carrying no evidence at
|
|
5067
|
-
* all, which is the shape a client sends when its uploader failed.
|
|
5097
|
+
* Shape only. WHETHER a photo is required depends on the set's current
|
|
5098
|
+
* state in the database, which Joi cannot see — see the check below.
|
|
5099
|
+
* Each entry must still be a real id: a blank string carries no evidence.
|
|
5068
5100
|
*/
|
|
5069
|
-
attachment: Joi9.array().items(Joi9.string().trim().min(1)).
|
|
5070
|
-
is: "approve",
|
|
5071
|
-
then: Joi9.array().min(1).required().messages({
|
|
5072
|
-
"array.min": "A photo is required to complete this task. Take or upload at least one photo before marking it complete.",
|
|
5073
|
-
"any.required": "A photo is required to complete this task. Take or upload at least one photo before marking it complete."
|
|
5074
|
-
}),
|
|
5075
|
-
otherwise: Joi9.array().optional()
|
|
5076
|
-
}),
|
|
5101
|
+
attachment: Joi9.array().items(Joi9.string().trim().min(1)).optional(),
|
|
5077
5102
|
completedBy: Joi9.string().hex().required()
|
|
5078
5103
|
});
|
|
5079
5104
|
const { error } = validation.validate(payload);
|
|
@@ -5084,7 +5109,24 @@ function useAreaChecklistController() {
|
|
|
5084
5109
|
}
|
|
5085
5110
|
try {
|
|
5086
5111
|
const { id, set, unit, decision: decision2, ...value } = payload;
|
|
5087
|
-
|
|
5112
|
+
const setNumber = parseInt(set);
|
|
5113
|
+
if (decision2 === "approve") {
|
|
5114
|
+
const { completesSet, hasEvidence } = await _readSetCompletionState(
|
|
5115
|
+
id,
|
|
5116
|
+
setNumber,
|
|
5117
|
+
unit
|
|
5118
|
+
);
|
|
5119
|
+
if (requiresCompletionPhoto({
|
|
5120
|
+
decision: decision2,
|
|
5121
|
+
attachment: value.attachment,
|
|
5122
|
+
completesSet,
|
|
5123
|
+
hasEvidence
|
|
5124
|
+
})) {
|
|
5125
|
+
next(new BadRequestError16(COMPLETION_PHOTO_MESSAGE));
|
|
5126
|
+
return;
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
await _updateAreaChecklistUnits(id, setNumber, unit, value);
|
|
5088
5130
|
res.json({ message: "Area checklist updated successfully." });
|
|
5089
5131
|
return;
|
|
5090
5132
|
} catch (error2) {
|