@7365admin1/module-hygiene 4.10.0 → 4.12.0
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 +12 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +455 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +460 -133
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -2486,12 +2486,30 @@ function useParentChecklistRepo() {
|
|
|
2486
2486
|
throw error;
|
|
2487
2487
|
}
|
|
2488
2488
|
}
|
|
2489
|
+
async function getTodayParentChecklists() {
|
|
2490
|
+
const now = /* @__PURE__ */ new Date();
|
|
2491
|
+
const start = new Date(now);
|
|
2492
|
+
start.setUTCHours(0, 0, 0, 0);
|
|
2493
|
+
const end = new Date(now);
|
|
2494
|
+
end.setUTCHours(23, 59, 59, 999);
|
|
2495
|
+
try {
|
|
2496
|
+
const items = await collection.find(
|
|
2497
|
+
{ createdAt: { $gte: start, $lte: end } },
|
|
2498
|
+
{ projection: { _id: 1, site: 1 } }
|
|
2499
|
+
).toArray();
|
|
2500
|
+
return items;
|
|
2501
|
+
} catch (error) {
|
|
2502
|
+
logger14.error("Failed to get today's parent checklists", error);
|
|
2503
|
+
throw error;
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2489
2506
|
return {
|
|
2490
2507
|
createIndex,
|
|
2491
2508
|
createParentChecklist,
|
|
2492
2509
|
getAllParentChecklist,
|
|
2493
2510
|
updateParentChecklistStatuses,
|
|
2494
|
-
closeExpiredParentChecklists
|
|
2511
|
+
closeExpiredParentChecklists,
|
|
2512
|
+
getTodayParentChecklists
|
|
2495
2513
|
};
|
|
2496
2514
|
}
|
|
2497
2515
|
|
|
@@ -2587,7 +2605,9 @@ var areaChecklistSchema = Joi8.object({
|
|
|
2587
2605
|
unit: Joi8.string().hex().required(),
|
|
2588
2606
|
name: Joi8.string().required()
|
|
2589
2607
|
}).required()
|
|
2590
|
-
).min(1).required()
|
|
2608
|
+
).min(1).required(),
|
|
2609
|
+
isScheduleTask: Joi8.boolean().optional().default(false),
|
|
2610
|
+
scheduleTaskId: Joi8.string().hex().optional().allow(null)
|
|
2591
2611
|
}).required()
|
|
2592
2612
|
).optional().default([]),
|
|
2593
2613
|
createdBy: Joi8.string().hex().required()
|
|
@@ -2616,6 +2636,8 @@ function MAreaChecklist(value) {
|
|
|
2616
2636
|
value.checklist = value.checklist.map((checklistItem) => {
|
|
2617
2637
|
return {
|
|
2618
2638
|
set: checklistItem.set,
|
|
2639
|
+
isScheduleTask: checklistItem.isScheduleTask ?? false,
|
|
2640
|
+
scheduleTaskId: checklistItem.scheduleTaskId ?? void 0,
|
|
2619
2641
|
units: checklistItem.units.map((unit) => ({
|
|
2620
2642
|
unit: new ObjectId8(unit.unit),
|
|
2621
2643
|
name: unit.name,
|
|
@@ -2651,7 +2673,13 @@ function MAreaChecklist(value) {
|
|
|
2651
2673
|
}
|
|
2652
2674
|
|
|
2653
2675
|
// src/services/hygiene-area-checklist.service.ts
|
|
2654
|
-
import {
|
|
2676
|
+
import { ObjectId as ObjectId10 } from "mongodb";
|
|
2677
|
+
import {
|
|
2678
|
+
logger as logger18,
|
|
2679
|
+
UnauthorizedError,
|
|
2680
|
+
useAtlas as useAtlas7
|
|
2681
|
+
} from "@7365admin1/node-server-utils";
|
|
2682
|
+
import { useUserRepo } from "@7365admin1/core";
|
|
2655
2683
|
|
|
2656
2684
|
// src/repositories/hygiene-area-checklist.repository.ts
|
|
2657
2685
|
import { ObjectId as ObjectId9 } from "mongodb";
|
|
@@ -2701,26 +2729,26 @@ function useAreaChecklistRepo() {
|
|
|
2701
2729
|
);
|
|
2702
2730
|
}
|
|
2703
2731
|
}
|
|
2732
|
+
async function createUniqueIndex() {
|
|
2733
|
+
try {
|
|
2734
|
+
await collection.createIndex({ schedule: 1, area: 1 }, { unique: true });
|
|
2735
|
+
} catch (error) {
|
|
2736
|
+
throw new InternalServerError5(
|
|
2737
|
+
"Failed to create unique index on hygiene checklist area."
|
|
2738
|
+
);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2704
2741
|
async function createAreaChecklist(value, session) {
|
|
2705
2742
|
try {
|
|
2706
2743
|
const parentChecklistId = new ObjectId9(value.schedule);
|
|
2707
|
-
const
|
|
2708
|
-
const
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
const existingChecklist = await collection.findOne({
|
|
2713
|
-
type: value.type,
|
|
2714
|
-
schedule: parentChecklistId,
|
|
2715
|
-
name: value.name,
|
|
2716
|
-
createdAt: {
|
|
2717
|
-
$gte: startOfDay,
|
|
2718
|
-
$lte: endOfDay
|
|
2719
|
-
}
|
|
2720
|
-
});
|
|
2744
|
+
const areaId = new ObjectId9(value.area);
|
|
2745
|
+
const existingChecklist = await collection.findOne(
|
|
2746
|
+
{ schedule: parentChecklistId, area: areaId },
|
|
2747
|
+
{ session }
|
|
2748
|
+
);
|
|
2721
2749
|
if (existingChecklist) {
|
|
2722
2750
|
logger17.info(
|
|
2723
|
-
`Area checklist already exists for area ${value.name}
|
|
2751
|
+
`Area checklist already exists for area ${value.name} (schedule: ${parentChecklistId}, area: ${areaId})`
|
|
2724
2752
|
);
|
|
2725
2753
|
return existingChecklist._id;
|
|
2726
2754
|
}
|
|
@@ -2736,6 +2764,14 @@ function useAreaChecklistRepo() {
|
|
|
2736
2764
|
});
|
|
2737
2765
|
return result.insertedId;
|
|
2738
2766
|
} catch (error) {
|
|
2767
|
+
if (error?.code === 11e3) {
|
|
2768
|
+
logger17.info(`Duplicate area checklist skipped for area ${value.name}`);
|
|
2769
|
+
const existing = await collection.findOne({
|
|
2770
|
+
schedule: new ObjectId9(value.schedule),
|
|
2771
|
+
area: new ObjectId9(value.area)
|
|
2772
|
+
});
|
|
2773
|
+
return existing._id;
|
|
2774
|
+
}
|
|
2739
2775
|
throw error;
|
|
2740
2776
|
}
|
|
2741
2777
|
}
|
|
@@ -3073,6 +3109,9 @@ function useAreaChecklistRepo() {
|
|
|
3073
3109
|
$project: {
|
|
3074
3110
|
_id: 0,
|
|
3075
3111
|
set: "$checklist.set",
|
|
3112
|
+
isScheduleTask: {
|
|
3113
|
+
$ifNull: ["$checklist.isScheduleTask", false]
|
|
3114
|
+
},
|
|
3076
3115
|
unit: "$checklist.units.unit",
|
|
3077
3116
|
name: "$checklist.units.name",
|
|
3078
3117
|
remarks: "$checklist.units.remarks",
|
|
@@ -3103,6 +3142,7 @@ function useAreaChecklistRepo() {
|
|
|
3103
3142
|
{
|
|
3104
3143
|
$group: {
|
|
3105
3144
|
_id: "$set",
|
|
3145
|
+
isScheduleTask: { $first: "$isScheduleTask" },
|
|
3106
3146
|
units: {
|
|
3107
3147
|
$push: {
|
|
3108
3148
|
unit: "$unit",
|
|
@@ -3119,6 +3159,7 @@ function useAreaChecklistRepo() {
|
|
|
3119
3159
|
$project: {
|
|
3120
3160
|
_id: 0,
|
|
3121
3161
|
set: "$_id",
|
|
3162
|
+
isScheduleTask: 1,
|
|
3122
3163
|
units: 1
|
|
3123
3164
|
}
|
|
3124
3165
|
},
|
|
@@ -3192,7 +3233,19 @@ function useAreaChecklistRepo() {
|
|
|
3192
3233
|
},
|
|
3193
3234
|
{
|
|
3194
3235
|
$addFields: {
|
|
3195
|
-
isCompleted: { $ne: ["$checklist.units.completedBy", ""] }
|
|
3236
|
+
isCompleted: { $ne: ["$checklist.units.completedBy", ""] },
|
|
3237
|
+
isActioned: {
|
|
3238
|
+
$cond: {
|
|
3239
|
+
if: {
|
|
3240
|
+
$or: [
|
|
3241
|
+
{ $eq: ["$checklist.units.approve", true] },
|
|
3242
|
+
{ $eq: ["$checklist.units.reject", true] }
|
|
3243
|
+
]
|
|
3244
|
+
},
|
|
3245
|
+
then: 1,
|
|
3246
|
+
else: 0
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3196
3249
|
}
|
|
3197
3250
|
},
|
|
3198
3251
|
{
|
|
@@ -3221,11 +3274,24 @@ function useAreaChecklistRepo() {
|
|
|
3221
3274
|
preserveNullAndEmptyArrays: true
|
|
3222
3275
|
}
|
|
3223
3276
|
},
|
|
3224
|
-
{
|
|
3277
|
+
{
|
|
3278
|
+
$sort: {
|
|
3279
|
+
"checklist.set": 1,
|
|
3280
|
+
isActioned: 1,
|
|
3281
|
+
"checklist.units.timestamp": 1,
|
|
3282
|
+
isCompleted: -1
|
|
3283
|
+
}
|
|
3284
|
+
},
|
|
3225
3285
|
{
|
|
3226
3286
|
$project: {
|
|
3227
3287
|
_id: 0,
|
|
3228
3288
|
set: "$checklist.set",
|
|
3289
|
+
isScheduleTask: {
|
|
3290
|
+
$ifNull: ["$checklist.isScheduleTask", false]
|
|
3291
|
+
},
|
|
3292
|
+
scheduleTaskId: {
|
|
3293
|
+
$ifNull: ["$checklist.scheduleTaskId", null]
|
|
3294
|
+
},
|
|
3229
3295
|
remarks: "$checklist.remarks",
|
|
3230
3296
|
attachment: "$checklist.attachment",
|
|
3231
3297
|
unit: "$checklist.units.unit",
|
|
@@ -3258,6 +3324,8 @@ function useAreaChecklistRepo() {
|
|
|
3258
3324
|
{
|
|
3259
3325
|
$group: {
|
|
3260
3326
|
_id: "$set",
|
|
3327
|
+
isScheduleTask: { $first: "$isScheduleTask" },
|
|
3328
|
+
scheduleTaskId: { $first: "$scheduleTaskId" },
|
|
3261
3329
|
remarks: { $first: "$remarks" },
|
|
3262
3330
|
attachment: { $first: "$attachment" },
|
|
3263
3331
|
completedByName: { $first: "$completedByName" },
|
|
@@ -3279,13 +3347,33 @@ function useAreaChecklistRepo() {
|
|
|
3279
3347
|
$project: {
|
|
3280
3348
|
_id: 0,
|
|
3281
3349
|
set: "$_id",
|
|
3350
|
+
isScheduleTask: 1,
|
|
3351
|
+
scheduleTaskId: 1,
|
|
3282
3352
|
remarks: "$remarks",
|
|
3283
3353
|
attachment: "$attachment",
|
|
3284
3354
|
completedByName: 1,
|
|
3285
3355
|
units: 1
|
|
3286
3356
|
}
|
|
3287
3357
|
},
|
|
3288
|
-
{
|
|
3358
|
+
{
|
|
3359
|
+
$addFields: {
|
|
3360
|
+
isFullyActioned: {
|
|
3361
|
+
$allElementsTrue: {
|
|
3362
|
+
$map: {
|
|
3363
|
+
input: "$units",
|
|
3364
|
+
as: "u",
|
|
3365
|
+
in: {
|
|
3366
|
+
$or: [
|
|
3367
|
+
{ $eq: ["$$u.approve", true] },
|
|
3368
|
+
{ $eq: ["$$u.reject", true] }
|
|
3369
|
+
]
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
},
|
|
3376
|
+
{ $sort: { isFullyActioned: 1, set: 1 } },
|
|
3289
3377
|
{ $skip: page * limit },
|
|
3290
3378
|
{ $limit: limit }
|
|
3291
3379
|
];
|
|
@@ -3489,12 +3577,26 @@ function useAreaChecklistRepo() {
|
|
|
3489
3577
|
throw error;
|
|
3490
3578
|
}
|
|
3491
3579
|
}
|
|
3580
|
+
async function getAreaChecklistSetOwner(_id, set, session) {
|
|
3581
|
+
try {
|
|
3582
|
+
_id = new ObjectId9(_id);
|
|
3583
|
+
} catch (error) {
|
|
3584
|
+
throw new BadRequestError15("Invalid area checklist ID format.");
|
|
3585
|
+
}
|
|
3586
|
+
const existing = await collection.findOne(
|
|
3587
|
+
{ _id, "checklist.set": set },
|
|
3588
|
+
{ projection: { "checklist.$": 1 }, session }
|
|
3589
|
+
);
|
|
3590
|
+
if (!existing?.checklist?.length)
|
|
3591
|
+
return null;
|
|
3592
|
+
return existing.checklist[0].units.map((u) => u.completedBy).find((cb) => cb && cb.toString() !== "") ?? null;
|
|
3593
|
+
}
|
|
3492
3594
|
async function getMaxSetNumberForArea(areaId, session) {
|
|
3493
3595
|
try {
|
|
3494
3596
|
const _id = new ObjectId9(areaId);
|
|
3495
3597
|
const result = await collection.aggregate(
|
|
3496
3598
|
[
|
|
3497
|
-
{ $match: { area: _id
|
|
3599
|
+
{ $match: { area: _id } },
|
|
3498
3600
|
{ $unwind: "$checklist" },
|
|
3499
3601
|
{ $group: { _id: null, maxSet: { $max: "$checklist.set" } } }
|
|
3500
3602
|
],
|
|
@@ -3542,9 +3644,155 @@ function useAreaChecklistRepo() {
|
|
|
3542
3644
|
throw error;
|
|
3543
3645
|
}
|
|
3544
3646
|
}
|
|
3647
|
+
async function pushScheduleTaskSets(scheduleId, areaId, scheduleTaskId, newSets) {
|
|
3648
|
+
try {
|
|
3649
|
+
const schedule = new ObjectId9(scheduleId);
|
|
3650
|
+
const area = new ObjectId9(areaId);
|
|
3651
|
+
const taskId = new ObjectId9(scheduleTaskId);
|
|
3652
|
+
const result = await collection.updateOne(
|
|
3653
|
+
{
|
|
3654
|
+
schedule,
|
|
3655
|
+
area,
|
|
3656
|
+
checklist: { $not: { $elemMatch: { scheduleTaskId: taskId } } }
|
|
3657
|
+
},
|
|
3658
|
+
{
|
|
3659
|
+
$push: { checklist: { $each: newSets } },
|
|
3660
|
+
$set: { updatedAt: /* @__PURE__ */ new Date() }
|
|
3661
|
+
}
|
|
3662
|
+
);
|
|
3663
|
+
if (result.modifiedCount > 0) {
|
|
3664
|
+
delNamespace().catch((err) => {
|
|
3665
|
+
logger17.error(
|
|
3666
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3667
|
+
err
|
|
3668
|
+
);
|
|
3669
|
+
});
|
|
3670
|
+
}
|
|
3671
|
+
return result.modifiedCount;
|
|
3672
|
+
} catch (error) {
|
|
3673
|
+
logger17.error("Error in pushScheduleTaskSets:", error);
|
|
3674
|
+
throw error;
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
async function insertAutoGenSets(scheduleId, areaId, newSets) {
|
|
3678
|
+
try {
|
|
3679
|
+
const schedule = new ObjectId9(scheduleId);
|
|
3680
|
+
const area = new ObjectId9(areaId);
|
|
3681
|
+
const result = await collection.updateOne(
|
|
3682
|
+
{
|
|
3683
|
+
schedule,
|
|
3684
|
+
area,
|
|
3685
|
+
checklist: {
|
|
3686
|
+
$not: { $elemMatch: { isScheduleTask: { $ne: true } } }
|
|
3687
|
+
}
|
|
3688
|
+
},
|
|
3689
|
+
{
|
|
3690
|
+
$push: { checklist: { $each: newSets } },
|
|
3691
|
+
$set: { updatedAt: /* @__PURE__ */ new Date() }
|
|
3692
|
+
}
|
|
3693
|
+
);
|
|
3694
|
+
if (result.modifiedCount > 0) {
|
|
3695
|
+
delNamespace().catch((err) => {
|
|
3696
|
+
logger17.error(
|
|
3697
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
3698
|
+
err
|
|
3699
|
+
);
|
|
3700
|
+
});
|
|
3701
|
+
}
|
|
3702
|
+
return result.modifiedCount;
|
|
3703
|
+
} catch (error) {
|
|
3704
|
+
logger17.error("Error in insertAutoGenSets:", error);
|
|
3705
|
+
throw error;
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
async function trimOverflowSets() {
|
|
3709
|
+
try {
|
|
3710
|
+
const db2 = useAtlas6.getDb();
|
|
3711
|
+
if (!db2)
|
|
3712
|
+
return 0;
|
|
3713
|
+
const bloated = await collection.aggregate([
|
|
3714
|
+
{
|
|
3715
|
+
$lookup: {
|
|
3716
|
+
from: "site.cleaning.areas",
|
|
3717
|
+
localField: "area",
|
|
3718
|
+
foreignField: "_id",
|
|
3719
|
+
as: "areaDoc"
|
|
3720
|
+
}
|
|
3721
|
+
},
|
|
3722
|
+
{
|
|
3723
|
+
$unwind: { path: "$areaDoc", preserveNullAndEmptyArrays: false }
|
|
3724
|
+
},
|
|
3725
|
+
{
|
|
3726
|
+
$addFields: {
|
|
3727
|
+
configuredSet: { $max: [1, { $ifNull: ["$areaDoc.set", 1] }] },
|
|
3728
|
+
autoGenSets: {
|
|
3729
|
+
$filter: {
|
|
3730
|
+
input: { $ifNull: ["$checklist", []] },
|
|
3731
|
+
as: "item",
|
|
3732
|
+
cond: { $ne: ["$$item.isScheduleTask", true] }
|
|
3733
|
+
}
|
|
3734
|
+
},
|
|
3735
|
+
scheduledSets: {
|
|
3736
|
+
$filter: {
|
|
3737
|
+
input: { $ifNull: ["$checklist", []] },
|
|
3738
|
+
as: "item",
|
|
3739
|
+
cond: { $eq: ["$$item.isScheduleTask", true] }
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
},
|
|
3744
|
+
{
|
|
3745
|
+
$match: {
|
|
3746
|
+
$expr: {
|
|
3747
|
+
$gt: [{ $size: "$autoGenSets" }, "$configuredSet"]
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
},
|
|
3751
|
+
{
|
|
3752
|
+
$project: {
|
|
3753
|
+
_id: 1,
|
|
3754
|
+
checklist: 1,
|
|
3755
|
+
configuredSet: 1,
|
|
3756
|
+
autoGenSets: 1,
|
|
3757
|
+
scheduledSets: 1
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
]).toArray();
|
|
3761
|
+
if (bloated.length === 0) {
|
|
3762
|
+
logger17.info(
|
|
3763
|
+
"trimOverflowSets: no bloated area-checklist documents found"
|
|
3764
|
+
);
|
|
3765
|
+
return 0;
|
|
3766
|
+
}
|
|
3767
|
+
let trimmed = 0;
|
|
3768
|
+
for (const doc of bloated) {
|
|
3769
|
+
const limit = Number(doc.configuredSet) || 1;
|
|
3770
|
+
const trimmedAutoGen = [...doc.autoGenSets ?? []].sort((a, b) => (a.set ?? 0) - (b.set ?? 0)).slice(0, limit);
|
|
3771
|
+
const keep = [...trimmedAutoGen, ...doc.scheduledSets ?? []];
|
|
3772
|
+
const res = await collection.updateOne(
|
|
3773
|
+
{ _id: doc._id },
|
|
3774
|
+
{ $set: { checklist: keep, updatedAt: /* @__PURE__ */ new Date() } }
|
|
3775
|
+
);
|
|
3776
|
+
if (res.modifiedCount > 0) {
|
|
3777
|
+
trimmed++;
|
|
3778
|
+
logger17.info(
|
|
3779
|
+
`trimOverflowSets: trimmed doc ${doc._id} \u2014 kept ${keep.length} sets (${trimmedAutoGen.length} auto-gen, ${(doc.scheduledSets ?? []).length} scheduled), removed ${doc.checklist.length - keep.length} excess auto-gen`
|
|
3780
|
+
);
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
delNamespace().catch(() => {
|
|
3784
|
+
});
|
|
3785
|
+
logger17.info(`trimOverflowSets: trimmed ${trimmed} document(s)`);
|
|
3786
|
+
return trimmed;
|
|
3787
|
+
} catch (error) {
|
|
3788
|
+
logger17.error("Error in trimOverflowSets:", error);
|
|
3789
|
+
return 0;
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3545
3792
|
return {
|
|
3546
3793
|
createIndex,
|
|
3547
3794
|
createTextIndex,
|
|
3795
|
+
createUniqueIndex,
|
|
3548
3796
|
createAreaChecklist,
|
|
3549
3797
|
getAllAreaChecklist,
|
|
3550
3798
|
getAreaChecklistHistory,
|
|
@@ -3552,11 +3800,15 @@ function useAreaChecklistRepo() {
|
|
|
3552
3800
|
getAreaChecklistUnits,
|
|
3553
3801
|
getAreaChecklistById,
|
|
3554
3802
|
getAreaChecklistByAreaAndSchedule,
|
|
3803
|
+
getAreaChecklistSetOwner,
|
|
3555
3804
|
updateAreaChecklist,
|
|
3556
3805
|
updateAreaChecklistStatus,
|
|
3557
3806
|
updateAreaChecklistUnits,
|
|
3558
3807
|
getMaxSetNumberForArea,
|
|
3559
|
-
closeExpiredAreaChecklists
|
|
3808
|
+
closeExpiredAreaChecklists,
|
|
3809
|
+
pushScheduleTaskSets,
|
|
3810
|
+
insertAutoGenSets,
|
|
3811
|
+
trimOverflowSets
|
|
3560
3812
|
};
|
|
3561
3813
|
}
|
|
3562
3814
|
|
|
@@ -3568,17 +3820,18 @@ function useAreaChecklistService() {
|
|
|
3568
3820
|
getAllAreaChecklist,
|
|
3569
3821
|
getAreaChecklistUnits,
|
|
3570
3822
|
getAreaChecklistById,
|
|
3823
|
+
getAreaChecklistByAreaAndSchedule,
|
|
3824
|
+
getAreaChecklistSetOwner,
|
|
3571
3825
|
updateAreaChecklistUnits: _updateAreaChecklistUnits,
|
|
3572
3826
|
updateAreaChecklistStatus,
|
|
3573
|
-
|
|
3827
|
+
insertAutoGenSets
|
|
3574
3828
|
} = useAreaChecklistRepo();
|
|
3575
3829
|
const { updateParentChecklistStatuses } = useParentChecklistRepo();
|
|
3830
|
+
const { getUserById } = useUserRepo();
|
|
3576
3831
|
async function createAreaChecklist(value) {
|
|
3577
|
-
const
|
|
3832
|
+
const results = [];
|
|
3833
|
+
let totalChecklistsCreated = 0;
|
|
3578
3834
|
try {
|
|
3579
|
-
session?.startTransaction();
|
|
3580
|
-
const results = [];
|
|
3581
|
-
let totalChecklistsCreated = 0;
|
|
3582
3835
|
const BATCH_SIZE = 10;
|
|
3583
3836
|
const areasResult = await getAreasForChecklist(value.site);
|
|
3584
3837
|
const areas = areasResult || [];
|
|
@@ -3592,15 +3845,72 @@ function useAreaChecklistService() {
|
|
|
3592
3845
|
);
|
|
3593
3846
|
return null;
|
|
3594
3847
|
}
|
|
3595
|
-
|
|
3596
|
-
|
|
3848
|
+
let existing = null;
|
|
3849
|
+
try {
|
|
3850
|
+
existing = await getAreaChecklistByAreaAndSchedule(
|
|
3851
|
+
value.schedule.toString(),
|
|
3852
|
+
area._id.toString()
|
|
3853
|
+
);
|
|
3854
|
+
} catch (_) {
|
|
3855
|
+
}
|
|
3856
|
+
if (existing) {
|
|
3857
|
+
const hasAutoGenSets = existing.checklist?.some(
|
|
3858
|
+
(c) => c.isScheduleTask !== true
|
|
3859
|
+
);
|
|
3860
|
+
if (hasAutoGenSets) {
|
|
3861
|
+
logger18.info(
|
|
3862
|
+
`Area checklist already exists with auto-gen sets for area ${area.name}, skipping`
|
|
3863
|
+
);
|
|
3864
|
+
return existing._id;
|
|
3865
|
+
}
|
|
3866
|
+
logger18.info(
|
|
3867
|
+
`Area checklist for area ${area.name} exists but has no auto-gen sets. Inserting auto-gen sets.`
|
|
3868
|
+
);
|
|
3869
|
+
const setCount2 = Number(area.set) || 1;
|
|
3870
|
+
const totalExistingSets = existing.checklist?.length ?? 0;
|
|
3871
|
+
if (totalExistingSets >= setCount2) {
|
|
3872
|
+
logger18.info(
|
|
3873
|
+
`Area checklist for area ${area.name} already has ${totalExistingSets} set(s) (configured: ${setCount2}). Skipping auto-gen sets.`
|
|
3874
|
+
);
|
|
3875
|
+
return existing._id;
|
|
3876
|
+
}
|
|
3877
|
+
const maxExistingSet = existing.checklist?.reduce(
|
|
3878
|
+
(max, c) => Math.max(max, c.set ?? 0),
|
|
3879
|
+
0
|
|
3880
|
+
) ?? 0;
|
|
3881
|
+
const setsToAdd = setCount2 - totalExistingSets;
|
|
3882
|
+
const autoGenSets = Array.from(
|
|
3883
|
+
{ length: setsToAdd },
|
|
3884
|
+
(_, index) => ({
|
|
3885
|
+
set: maxExistingSet + index + 1,
|
|
3886
|
+
isScheduleTask: false,
|
|
3887
|
+
units: area.units.map((unit) => ({
|
|
3888
|
+
unit: new ObjectId10(unit.unit),
|
|
3889
|
+
name: unit.name,
|
|
3890
|
+
approve: false,
|
|
3891
|
+
reject: false,
|
|
3892
|
+
status: "open",
|
|
3893
|
+
remarks: "",
|
|
3894
|
+
completedBy: "",
|
|
3895
|
+
timestamp: ""
|
|
3896
|
+
}))
|
|
3897
|
+
})
|
|
3898
|
+
);
|
|
3899
|
+
await insertAutoGenSets(
|
|
3900
|
+
value.schedule.toString(),
|
|
3901
|
+
area._id.toString(),
|
|
3902
|
+
autoGenSets
|
|
3903
|
+
);
|
|
3904
|
+
return existing._id;
|
|
3905
|
+
}
|
|
3906
|
+
const setCount = Number(area.set) || 1;
|
|
3597
3907
|
const checklistData = {
|
|
3598
3908
|
schedule: value.schedule,
|
|
3599
3909
|
area: area._id.toString(),
|
|
3600
3910
|
name: area.name,
|
|
3601
3911
|
type: area.type,
|
|
3602
3912
|
checklist: Array.from({ length: setCount }, (_, index) => ({
|
|
3603
|
-
set:
|
|
3913
|
+
set: index + 1,
|
|
3604
3914
|
units: area.units.map((unit) => ({
|
|
3605
3915
|
unit: unit.unit.toString(),
|
|
3606
3916
|
name: unit.name
|
|
@@ -3608,10 +3918,7 @@ function useAreaChecklistService() {
|
|
|
3608
3918
|
})),
|
|
3609
3919
|
createdBy: value.createdBy
|
|
3610
3920
|
};
|
|
3611
|
-
const insertedId = await _createAreaChecklist(
|
|
3612
|
-
checklistData,
|
|
3613
|
-
session
|
|
3614
|
-
);
|
|
3921
|
+
const insertedId = await _createAreaChecklist(checklistData);
|
|
3615
3922
|
totalChecklistsCreated++;
|
|
3616
3923
|
return insertedId;
|
|
3617
3924
|
});
|
|
@@ -3624,25 +3931,26 @@ function useAreaChecklistService() {
|
|
|
3624
3931
|
} else {
|
|
3625
3932
|
logger18.warn(`No common areas found for site: ${value.site}`);
|
|
3626
3933
|
}
|
|
3627
|
-
await session?.commitTransaction();
|
|
3628
3934
|
logger18.info(
|
|
3629
3935
|
`Successfully created ${totalChecklistsCreated} area checklists for site: ${value.site}`
|
|
3630
3936
|
);
|
|
3631
3937
|
return results;
|
|
3632
3938
|
} catch (error) {
|
|
3633
3939
|
logger18.error(`Error generating area checklists:`, error);
|
|
3634
|
-
if (session?.inTransaction()) {
|
|
3635
|
-
await session?.abortTransaction();
|
|
3636
|
-
}
|
|
3637
3940
|
throw error;
|
|
3638
|
-
} finally {
|
|
3639
|
-
session?.endSession();
|
|
3640
3941
|
}
|
|
3641
3942
|
}
|
|
3642
3943
|
async function updateAreaChecklistUnits(_id, set, unitId, value) {
|
|
3643
3944
|
const session = useAtlas7.getClient()?.startSession();
|
|
3644
3945
|
try {
|
|
3645
3946
|
session?.startTransaction();
|
|
3947
|
+
const setOwner = await getAreaChecklistSetOwner(_id, set, session);
|
|
3948
|
+
if (setOwner && value.completedBy && setOwner.toString() !== value.completedBy.toString()) {
|
|
3949
|
+
const acceptedBy = await getUserById(setOwner.toString());
|
|
3950
|
+
throw new UnauthorizedError(
|
|
3951
|
+
`${acceptedBy.name} has already taken this set.`
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3646
3954
|
await _updateAreaChecklistUnits(_id, set, unitId, value, session);
|
|
3647
3955
|
const allUnitsResult = await getAreaChecklistUnits(
|
|
3648
3956
|
{
|
|
@@ -3733,7 +4041,7 @@ import { BadRequestError as BadRequestError16, InternalServerError as InternalSe
|
|
|
3733
4041
|
// src/services/hygiene-checklist-pdf.service.ts
|
|
3734
4042
|
import { launch } from "puppeteer";
|
|
3735
4043
|
import { InternalServerError as InternalServerError6, useAtlas as useAtlas8 } from "@7365admin1/node-server-utils";
|
|
3736
|
-
import { ObjectId as
|
|
4044
|
+
import { ObjectId as ObjectId11 } from "mongodb";
|
|
3737
4045
|
function escapeHtml(text) {
|
|
3738
4046
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3739
4047
|
}
|
|
@@ -3907,7 +4215,7 @@ function useChecklistPdfService() {
|
|
|
3907
4215
|
const collection = db.collection("site.cleaning.schedule.areas");
|
|
3908
4216
|
let scheduleObjectId;
|
|
3909
4217
|
try {
|
|
3910
|
-
scheduleObjectId = new
|
|
4218
|
+
scheduleObjectId = new ObjectId11(scheduleId);
|
|
3911
4219
|
} catch {
|
|
3912
4220
|
throw new InternalServerError6("Invalid schedule ID format.");
|
|
3913
4221
|
}
|
|
@@ -4216,7 +4524,7 @@ function useAreaChecklistController() {
|
|
|
4216
4524
|
|
|
4217
4525
|
// src/models/hygiene-supply.model.ts
|
|
4218
4526
|
import Joi10 from "joi";
|
|
4219
|
-
import { ObjectId as
|
|
4527
|
+
import { ObjectId as ObjectId12 } from "mongodb";
|
|
4220
4528
|
import { BadRequestError as BadRequestError17, logger as logger21 } from "@7365admin1/node-server-utils";
|
|
4221
4529
|
var supplySchema = Joi10.object({
|
|
4222
4530
|
site: Joi10.string().hex().required(),
|
|
@@ -4231,7 +4539,7 @@ function MSupply(value) {
|
|
|
4231
4539
|
}
|
|
4232
4540
|
if (value.site) {
|
|
4233
4541
|
try {
|
|
4234
|
-
value.site = new
|
|
4542
|
+
value.site = new ObjectId12(value.site);
|
|
4235
4543
|
} catch (error2) {
|
|
4236
4544
|
throw new BadRequestError17("Invalid site ID format.");
|
|
4237
4545
|
}
|
|
@@ -4249,7 +4557,7 @@ function MSupply(value) {
|
|
|
4249
4557
|
}
|
|
4250
4558
|
|
|
4251
4559
|
// src/repositories/hygiene-supply.repository.ts
|
|
4252
|
-
import { ObjectId as
|
|
4560
|
+
import { ObjectId as ObjectId13 } from "mongodb";
|
|
4253
4561
|
import {
|
|
4254
4562
|
useAtlas as useAtlas9,
|
|
4255
4563
|
InternalServerError as InternalServerError8,
|
|
@@ -4334,7 +4642,7 @@ function useSupplyRepository() {
|
|
|
4334
4642
|
limit
|
|
4335
4643
|
};
|
|
4336
4644
|
try {
|
|
4337
|
-
site = new
|
|
4645
|
+
site = new ObjectId13(site);
|
|
4338
4646
|
query.site = site;
|
|
4339
4647
|
cacheOptions.site = site.toString();
|
|
4340
4648
|
} catch (error) {
|
|
@@ -4378,7 +4686,7 @@ function useSupplyRepository() {
|
|
|
4378
4686
|
}
|
|
4379
4687
|
async function getSupplyById(_id, session) {
|
|
4380
4688
|
try {
|
|
4381
|
-
_id = new
|
|
4689
|
+
_id = new ObjectId13(_id);
|
|
4382
4690
|
} catch (error) {
|
|
4383
4691
|
throw new BadRequestError18("Invalid supply ID format.");
|
|
4384
4692
|
}
|
|
@@ -4424,7 +4732,7 @@ function useSupplyRepository() {
|
|
|
4424
4732
|
}
|
|
4425
4733
|
async function updateSupply(_id, value, session) {
|
|
4426
4734
|
try {
|
|
4427
|
-
_id = new
|
|
4735
|
+
_id = new ObjectId13(_id);
|
|
4428
4736
|
} catch (error) {
|
|
4429
4737
|
throw new BadRequestError18("Invalid supply ID format.");
|
|
4430
4738
|
}
|
|
@@ -4457,7 +4765,7 @@ function useSupplyRepository() {
|
|
|
4457
4765
|
}
|
|
4458
4766
|
async function deleteSupply(_id, session) {
|
|
4459
4767
|
try {
|
|
4460
|
-
_id = new
|
|
4768
|
+
_id = new ObjectId13(_id);
|
|
4461
4769
|
} catch (error) {
|
|
4462
4770
|
throw new BadRequestError18("Invalid supply ID format.");
|
|
4463
4771
|
}
|
|
@@ -4638,7 +4946,7 @@ function useSupplyController() {
|
|
|
4638
4946
|
|
|
4639
4947
|
// src/models/hygiene-stock.model.ts
|
|
4640
4948
|
import Joi12 from "joi";
|
|
4641
|
-
import { ObjectId as
|
|
4949
|
+
import { ObjectId as ObjectId14 } from "mongodb";
|
|
4642
4950
|
import { BadRequestError as BadRequestError20, logger as logger24 } from "@7365admin1/node-server-utils";
|
|
4643
4951
|
var stockSchema = Joi12.object({
|
|
4644
4952
|
site: Joi12.string().hex().required(),
|
|
@@ -4656,14 +4964,14 @@ function MStock(value) {
|
|
|
4656
4964
|
}
|
|
4657
4965
|
if (value.site) {
|
|
4658
4966
|
try {
|
|
4659
|
-
value.site = new
|
|
4967
|
+
value.site = new ObjectId14(value.site);
|
|
4660
4968
|
} catch (error2) {
|
|
4661
4969
|
throw new BadRequestError20("Invalid site ID format.");
|
|
4662
4970
|
}
|
|
4663
4971
|
}
|
|
4664
4972
|
if (value.supply) {
|
|
4665
4973
|
try {
|
|
4666
|
-
value.supply = new
|
|
4974
|
+
value.supply = new ObjectId14(value.supply);
|
|
4667
4975
|
} catch (error2) {
|
|
4668
4976
|
throw new BadRequestError20("Invalid supply ID format.");
|
|
4669
4977
|
}
|
|
@@ -4683,7 +4991,7 @@ function MStock(value) {
|
|
|
4683
4991
|
}
|
|
4684
4992
|
|
|
4685
4993
|
// src/repositories/hygiene-stock.repository.ts
|
|
4686
|
-
import { ObjectId as
|
|
4994
|
+
import { ObjectId as ObjectId15 } from "mongodb";
|
|
4687
4995
|
import {
|
|
4688
4996
|
useAtlas as useAtlas10,
|
|
4689
4997
|
InternalServerError as InternalServerError9,
|
|
@@ -4756,14 +5064,14 @@ function useStockRepository() {
|
|
|
4756
5064
|
limit
|
|
4757
5065
|
};
|
|
4758
5066
|
try {
|
|
4759
|
-
site = new
|
|
5067
|
+
site = new ObjectId15(site);
|
|
4760
5068
|
query.site = site;
|
|
4761
5069
|
cacheOptions.site = site.toString();
|
|
4762
5070
|
} catch (error) {
|
|
4763
5071
|
throw new BadRequestError21("Invalid site ID format.");
|
|
4764
5072
|
}
|
|
4765
5073
|
try {
|
|
4766
|
-
supply = new
|
|
5074
|
+
supply = new ObjectId15(supply);
|
|
4767
5075
|
query.supply = supply;
|
|
4768
5076
|
cacheOptions.supply = supply.toString();
|
|
4769
5077
|
} catch (error) {
|
|
@@ -4941,7 +5249,7 @@ function useStockController() {
|
|
|
4941
5249
|
|
|
4942
5250
|
// src/models/hygiene-checkout-item.model.ts
|
|
4943
5251
|
import Joi14 from "joi";
|
|
4944
|
-
import { ObjectId as
|
|
5252
|
+
import { ObjectId as ObjectId16 } from "mongodb";
|
|
4945
5253
|
import { BadRequestError as BadRequestError24, logger as logger27 } from "@7365admin1/node-server-utils";
|
|
4946
5254
|
var allowedCheckOutItemStatus = ["pending", "completed"];
|
|
4947
5255
|
var checkOutItemSchema = Joi14.object({
|
|
@@ -4961,14 +5269,14 @@ function MCheckOutItem(value) {
|
|
|
4961
5269
|
}
|
|
4962
5270
|
if (value.site) {
|
|
4963
5271
|
try {
|
|
4964
|
-
value.site = new
|
|
5272
|
+
value.site = new ObjectId16(value.site);
|
|
4965
5273
|
} catch (error2) {
|
|
4966
5274
|
throw new BadRequestError24("Invalid site ID format.");
|
|
4967
5275
|
}
|
|
4968
5276
|
}
|
|
4969
5277
|
if (value.supply) {
|
|
4970
5278
|
try {
|
|
4971
|
-
value.supply = new
|
|
5279
|
+
value.supply = new ObjectId16(value.supply);
|
|
4972
5280
|
} catch (error2) {
|
|
4973
5281
|
throw new BadRequestError24("Invalid supply ID format.");
|
|
4974
5282
|
}
|
|
@@ -4989,7 +5297,7 @@ function MCheckOutItem(value) {
|
|
|
4989
5297
|
}
|
|
4990
5298
|
|
|
4991
5299
|
// src/repositories/hygiene-checkout-item.repository.ts
|
|
4992
|
-
import { ObjectId as
|
|
5300
|
+
import { ObjectId as ObjectId17 } from "mongodb";
|
|
4993
5301
|
import {
|
|
4994
5302
|
useAtlas as useAtlas12,
|
|
4995
5303
|
InternalServerError as InternalServerError10,
|
|
@@ -5062,7 +5370,7 @@ function useCheckOutItemRepository() {
|
|
|
5062
5370
|
limit
|
|
5063
5371
|
};
|
|
5064
5372
|
try {
|
|
5065
|
-
site = new
|
|
5373
|
+
site = new ObjectId17(site);
|
|
5066
5374
|
query.site = site;
|
|
5067
5375
|
cacheOptions.site = site.toString();
|
|
5068
5376
|
} catch (error) {
|
|
@@ -5135,7 +5443,7 @@ function useCheckOutItemRepository() {
|
|
|
5135
5443
|
}
|
|
5136
5444
|
async function getCheckOutItemById(_id, session) {
|
|
5137
5445
|
try {
|
|
5138
|
-
_id = new
|
|
5446
|
+
_id = new ObjectId17(_id);
|
|
5139
5447
|
} catch (error) {
|
|
5140
5448
|
throw new BadRequestError25("Invalid check out item ID format.");
|
|
5141
5449
|
}
|
|
@@ -5199,7 +5507,7 @@ function useCheckOutItemRepository() {
|
|
|
5199
5507
|
}
|
|
5200
5508
|
async function completeCheckOutItem(_id, session) {
|
|
5201
5509
|
try {
|
|
5202
|
-
_id = new
|
|
5510
|
+
_id = new ObjectId17(_id);
|
|
5203
5511
|
} catch (error) {
|
|
5204
5512
|
throw new BadRequestError25("Invalid check out item ID format.");
|
|
5205
5513
|
}
|
|
@@ -5240,7 +5548,7 @@ function useCheckOutItemRepository() {
|
|
|
5240
5548
|
}
|
|
5241
5549
|
|
|
5242
5550
|
// src/services/hygiene-checkout-item.service.ts
|
|
5243
|
-
import { useUserRepo } from "@7365admin1/core";
|
|
5551
|
+
import { useUserRepo as useUserRepo2 } from "@7365admin1/core";
|
|
5244
5552
|
import { BadRequestError as BadRequestError26, useAtlas as useAtlas13 } from "@7365admin1/node-server-utils";
|
|
5245
5553
|
function useCheckOutItemService() {
|
|
5246
5554
|
const {
|
|
@@ -5249,7 +5557,7 @@ function useCheckOutItemService() {
|
|
|
5249
5557
|
completeCheckOutItem
|
|
5250
5558
|
} = useCheckOutItemRepository();
|
|
5251
5559
|
const { getSupplyById } = useSupplyRepository();
|
|
5252
|
-
const { getUserById } =
|
|
5560
|
+
const { getUserById } = useUserRepo2();
|
|
5253
5561
|
const { createStock } = useStockService();
|
|
5254
5562
|
async function createCheckOutItem(value) {
|
|
5255
5563
|
const session = useAtlas13.getClient()?.startSession();
|
|
@@ -5485,7 +5793,7 @@ function useCheckOutItemController() {
|
|
|
5485
5793
|
// src/models/hygiene-schedule-task.model.ts
|
|
5486
5794
|
import { BadRequestError as BadRequestError28, logger as logger30 } from "@7365admin1/node-server-utils";
|
|
5487
5795
|
import Joi16 from "joi";
|
|
5488
|
-
import { ObjectId as
|
|
5796
|
+
import { ObjectId as ObjectId18 } from "mongodb";
|
|
5489
5797
|
var scheduleTaskSchema = Joi16.object({
|
|
5490
5798
|
site: Joi16.string().hex().required(),
|
|
5491
5799
|
title: Joi16.string().required(),
|
|
@@ -5510,7 +5818,7 @@ function MScheduleTask(value) {
|
|
|
5510
5818
|
}
|
|
5511
5819
|
if (value.site) {
|
|
5512
5820
|
try {
|
|
5513
|
-
value.site = new
|
|
5821
|
+
value.site = new ObjectId18(value.site);
|
|
5514
5822
|
} catch (error2) {
|
|
5515
5823
|
throw new BadRequestError28("Invalid site ID format.");
|
|
5516
5824
|
}
|
|
@@ -5520,7 +5828,7 @@ function MScheduleTask(value) {
|
|
|
5520
5828
|
try {
|
|
5521
5829
|
return {
|
|
5522
5830
|
name: area.name,
|
|
5523
|
-
value: new
|
|
5831
|
+
value: new ObjectId18(area.value.toString())
|
|
5524
5832
|
};
|
|
5525
5833
|
} catch (error2) {
|
|
5526
5834
|
throw new BadRequestError28(`Invalid area value format: ${area.name}`);
|
|
@@ -5529,7 +5837,7 @@ function MScheduleTask(value) {
|
|
|
5529
5837
|
}
|
|
5530
5838
|
if (value.createdBy) {
|
|
5531
5839
|
try {
|
|
5532
|
-
value.createdBy = new
|
|
5840
|
+
value.createdBy = new ObjectId18(value.createdBy);
|
|
5533
5841
|
} catch (error2) {
|
|
5534
5842
|
throw new BadRequestError28("Invalid createdBy ID format.");
|
|
5535
5843
|
}
|
|
@@ -5550,7 +5858,7 @@ function MScheduleTask(value) {
|
|
|
5550
5858
|
}
|
|
5551
5859
|
|
|
5552
5860
|
// src/repositories/hygiene-schedule-task.repository.ts
|
|
5553
|
-
import { ObjectId as
|
|
5861
|
+
import { ObjectId as ObjectId19 } from "mongodb";
|
|
5554
5862
|
import {
|
|
5555
5863
|
useAtlas as useAtlas14,
|
|
5556
5864
|
InternalServerError as InternalServerError11,
|
|
@@ -5622,7 +5930,7 @@ function useScheduleTaskRepository() {
|
|
|
5622
5930
|
limit
|
|
5623
5931
|
};
|
|
5624
5932
|
try {
|
|
5625
|
-
site = new
|
|
5933
|
+
site = new ObjectId19(site);
|
|
5626
5934
|
query.site = site;
|
|
5627
5935
|
cacheOptions.site = site.toString();
|
|
5628
5936
|
} catch (error) {
|
|
@@ -5690,7 +5998,7 @@ function useScheduleTaskRepository() {
|
|
|
5690
5998
|
limit
|
|
5691
5999
|
};
|
|
5692
6000
|
try {
|
|
5693
|
-
site = new
|
|
6001
|
+
site = new ObjectId19(site);
|
|
5694
6002
|
query.site = site;
|
|
5695
6003
|
cacheOptions.site = site.toString();
|
|
5696
6004
|
} catch (error) {
|
|
@@ -5733,7 +6041,7 @@ function useScheduleTaskRepository() {
|
|
|
5733
6041
|
}
|
|
5734
6042
|
async function getScheduleTaskById(_id, session) {
|
|
5735
6043
|
try {
|
|
5736
|
-
_id = new
|
|
6044
|
+
_id = new ObjectId19(_id);
|
|
5737
6045
|
} catch (error) {
|
|
5738
6046
|
throw new BadRequestError29("Invalid schedule task ID format.");
|
|
5739
6047
|
}
|
|
@@ -5783,7 +6091,7 @@ function useScheduleTaskRepository() {
|
|
|
5783
6091
|
}
|
|
5784
6092
|
async function updateScheduleTask(_id, value, session) {
|
|
5785
6093
|
try {
|
|
5786
|
-
_id = new
|
|
6094
|
+
_id = new ObjectId19(_id);
|
|
5787
6095
|
} catch (error) {
|
|
5788
6096
|
throw new BadRequestError29("Invalid schedule task ID format.");
|
|
5789
6097
|
}
|
|
@@ -5792,7 +6100,7 @@ function useScheduleTaskRepository() {
|
|
|
5792
6100
|
try {
|
|
5793
6101
|
return {
|
|
5794
6102
|
name: area.name,
|
|
5795
|
-
value: new
|
|
6103
|
+
value: new ObjectId19(area.value.toString())
|
|
5796
6104
|
};
|
|
5797
6105
|
} catch (error) {
|
|
5798
6106
|
throw new BadRequestError29(`Invalid area value format: ${area.name}`);
|
|
@@ -5837,6 +6145,7 @@ function useScheduleTaskRepository() {
|
|
|
5837
6145
|
}
|
|
5838
6146
|
|
|
5839
6147
|
// src/services/hygiene-schedule-task.service.ts
|
|
6148
|
+
import { ObjectId as ObjectId20 } from "mongodb";
|
|
5840
6149
|
import { logger as logger32 } from "@7365admin1/node-server-utils";
|
|
5841
6150
|
function useScheduleTaskService() {
|
|
5842
6151
|
const { createParentChecklist } = useParentChecklistRepo();
|
|
@@ -5844,7 +6153,7 @@ function useScheduleTaskService() {
|
|
|
5844
6153
|
const {
|
|
5845
6154
|
createAreaChecklist,
|
|
5846
6155
|
getAreaChecklistByAreaAndSchedule,
|
|
5847
|
-
|
|
6156
|
+
pushScheduleTaskSets
|
|
5848
6157
|
} = useAreaChecklistRepo();
|
|
5849
6158
|
const { getAreaById } = useAreaRepo();
|
|
5850
6159
|
function checkScheduleConditions(schedule, currentDate = /* @__PURE__ */ new Date()) {
|
|
@@ -5883,6 +6192,35 @@ function useScheduleTaskService() {
|
|
|
5883
6192
|
);
|
|
5884
6193
|
return false;
|
|
5885
6194
|
}
|
|
6195
|
+
const relevantTimestamp = schedule.updatedAt || schedule.createdAt;
|
|
6196
|
+
if (relevantTimestamp) {
|
|
6197
|
+
const savedAt = new Date(relevantTimestamp);
|
|
6198
|
+
const savedHour = parseInt(
|
|
6199
|
+
savedAt.toLocaleTimeString("en-US", {
|
|
6200
|
+
hour: "2-digit",
|
|
6201
|
+
hour12: false,
|
|
6202
|
+
timeZone: "Asia/Singapore"
|
|
6203
|
+
}),
|
|
6204
|
+
10
|
|
6205
|
+
);
|
|
6206
|
+
const savedMinute = savedAt.toLocaleString("en-US", {
|
|
6207
|
+
minute: "2-digit",
|
|
6208
|
+
timeZone: "Asia/Singapore"
|
|
6209
|
+
});
|
|
6210
|
+
const savedDateFormatted = savedAt.toLocaleDateString("en-CA", {
|
|
6211
|
+
timeZone: "Asia/Singapore"
|
|
6212
|
+
});
|
|
6213
|
+
const savedMinNum = parseInt(savedMinute, 10);
|
|
6214
|
+
const wasSavedThisMinute = savedDateFormatted === currentDateFormatted && savedHour === currentHour && savedMinNum === currentMinute;
|
|
6215
|
+
if (wasSavedThisMinute) {
|
|
6216
|
+
logger32.info(
|
|
6217
|
+
`Schedule ${schedule._id}: Skipping \u2014 task was saved this minute (${savedHour}:${String(
|
|
6218
|
+
savedMinNum
|
|
6219
|
+
).padStart(2, "0")}). Will fire on next occurrence.`
|
|
6220
|
+
);
|
|
6221
|
+
return false;
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
5886
6224
|
logger32.info(
|
|
5887
6225
|
`Schedule ${schedule._id}: All conditions matched - Date is within range and time matches`
|
|
5888
6226
|
);
|
|
@@ -5950,8 +6288,14 @@ function useScheduleTaskService() {
|
|
|
5950
6288
|
let units = [];
|
|
5951
6289
|
if (areaDetails.units && areaDetails.units.length > 0) {
|
|
5952
6290
|
units = areaDetails.units.map((unit) => ({
|
|
5953
|
-
unit: unit.unit
|
|
5954
|
-
name: unit.name
|
|
6291
|
+
unit: new ObjectId20(unit.unit),
|
|
6292
|
+
name: unit.name,
|
|
6293
|
+
approve: false,
|
|
6294
|
+
reject: false,
|
|
6295
|
+
status: "open",
|
|
6296
|
+
remarks: "",
|
|
6297
|
+
completedBy: "",
|
|
6298
|
+
timestamp: ""
|
|
5955
6299
|
}));
|
|
5956
6300
|
logger32.info(
|
|
5957
6301
|
`Area ${area.name} (${areaId}): Using units from area details: ${JSON.stringify(
|
|
@@ -5988,79 +6332,62 @@ function useScheduleTaskService() {
|
|
|
5988
6332
|
);
|
|
5989
6333
|
}
|
|
5990
6334
|
if (existingAreaChecklist) {
|
|
5991
|
-
const
|
|
5992
|
-
const
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6335
|
+
const areaSetConfig = Number(areaDetails.set) || 1;
|
|
6336
|
+
const maxSetInChecklist = existingAreaChecklist.checklist?.length ? Math.max(
|
|
6337
|
+
...existingAreaChecklist.checklist.map(
|
|
6338
|
+
(c) => c.set
|
|
6339
|
+
)
|
|
6340
|
+
) : 0;
|
|
6341
|
+
const startSetNumber = maxSetInChecklist + 1;
|
|
6342
|
+
const newSets = Array.from(
|
|
6343
|
+
{ length: areaSetConfig },
|
|
6344
|
+
(_, index) => ({
|
|
6345
|
+
set: startSetNumber + index,
|
|
6346
|
+
units,
|
|
6347
|
+
isScheduleTask: true,
|
|
6348
|
+
scheduleTaskId: scheduleTask._id
|
|
6349
|
+
})
|
|
6004
6350
|
);
|
|
6005
|
-
await
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6351
|
+
const modified = await pushScheduleTaskSets(
|
|
6352
|
+
parentChecklistId.toString(),
|
|
6353
|
+
areaId,
|
|
6354
|
+
scheduleTask._id.toString(),
|
|
6355
|
+
newSets
|
|
6010
6356
|
);
|
|
6011
|
-
|
|
6012
|
-
const verifyChecklist = await getAreaChecklistByAreaAndSchedule(
|
|
6013
|
-
parentChecklistId.toString(),
|
|
6014
|
-
areaId
|
|
6015
|
-
);
|
|
6357
|
+
if (modified > 0) {
|
|
6016
6358
|
logger32.info(
|
|
6017
|
-
`
|
|
6018
|
-
verifyChecklist.checklist
|
|
6019
|
-
)}`
|
|
6359
|
+
`Appended ${areaSetConfig} set(s) starting from ${startSetNumber} to area checklist for area ${area.name}`
|
|
6020
6360
|
);
|
|
6021
|
-
}
|
|
6022
|
-
logger32.
|
|
6023
|
-
`Area ${area.name} (${areaId}):
|
|
6024
|
-
verifyError
|
|
6361
|
+
} else {
|
|
6362
|
+
logger32.info(
|
|
6363
|
+
`Area ${area.name} (${areaId}): Schedule task ${scheduleTask._id} already processed (atomic check), skipping.`
|
|
6025
6364
|
);
|
|
6026
6365
|
}
|
|
6027
6366
|
} else {
|
|
6367
|
+
const areaSetConfig = Number(areaDetails.set) || 1;
|
|
6368
|
+
const schedTaskId = scheduleTask._id;
|
|
6369
|
+
const schedTaskSets = Array.from(
|
|
6370
|
+
{ length: areaSetConfig },
|
|
6371
|
+
(_, index) => ({
|
|
6372
|
+
set: index + 1,
|
|
6373
|
+
units,
|
|
6374
|
+
isScheduleTask: true,
|
|
6375
|
+
scheduleTaskId: schedTaskId
|
|
6376
|
+
})
|
|
6377
|
+
);
|
|
6028
6378
|
const checklistData = {
|
|
6029
6379
|
schedule: parentChecklistId.toString(),
|
|
6030
6380
|
area: areaId,
|
|
6031
6381
|
name: area.name,
|
|
6032
6382
|
type: areaDetails.type || "common",
|
|
6033
|
-
checklist:
|
|
6034
|
-
{
|
|
6035
|
-
set: 1,
|
|
6036
|
-
units
|
|
6037
|
-
}
|
|
6038
|
-
],
|
|
6383
|
+
checklist: schedTaskSets,
|
|
6039
6384
|
createdBy: scheduleTask.createdBy
|
|
6040
6385
|
};
|
|
6041
6386
|
logger32.info(
|
|
6042
|
-
`Area ${area.name} (${areaId}): Creating new area checklist with
|
|
6043
|
-
checklistData
|
|
6044
|
-
)}`
|
|
6387
|
+
`Area ${area.name} (${areaId}): Creating new area checklist with schedule-task sets only`
|
|
6045
6388
|
);
|
|
6046
6389
|
await createAreaChecklist(checklistData);
|
|
6047
6390
|
logger32.info(`Created new area checklist for area ${area.name}`);
|
|
6048
|
-
try {
|
|
6049
|
-
const verifyChecklist = await getAreaChecklistByAreaAndSchedule(
|
|
6050
|
-
parentChecklistId.toString(),
|
|
6051
|
-
areaId
|
|
6052
|
-
);
|
|
6053
|
-
logger32.info(
|
|
6054
|
-
`Area ${area.name} (${areaId}): Checklist after creation: ${JSON.stringify(
|
|
6055
|
-
verifyChecklist.checklist
|
|
6056
|
-
)}`
|
|
6057
|
-
);
|
|
6058
|
-
} catch (verifyError) {
|
|
6059
|
-
logger32.warn(
|
|
6060
|
-
`Area ${area.name} (${areaId}): Error verifying checklist after creation:`,
|
|
6061
|
-
verifyError
|
|
6062
|
-
);
|
|
6063
|
-
}
|
|
6064
6391
|
}
|
|
6065
6392
|
} catch (error) {
|
|
6066
6393
|
logger32.error(`Error processing area ${area.name}:`, error);
|