@iservice365/module-hygiene 1.4.0 → 1.5.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 +6 -0
- package/dist/index.d.ts +29 -12
- package/dist/index.js +377 -107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +372 -102
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -200,12 +200,9 @@ function useAreaRepo() {
|
|
|
200
200
|
throw error;
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
async function getAreasForChecklist({
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}) {
|
|
207
|
-
const query = { type, status: { $ne: "deleted" } };
|
|
208
|
-
const cacheOptions = { type };
|
|
203
|
+
async function getAreasForChecklist(site) {
|
|
204
|
+
const query = { status: { $ne: "deleted" } };
|
|
205
|
+
const cacheOptions = {};
|
|
209
206
|
try {
|
|
210
207
|
site = new ObjectId2(site);
|
|
211
208
|
query.site = site;
|
|
@@ -225,6 +222,7 @@ function useAreaRepo() {
|
|
|
225
222
|
{
|
|
226
223
|
$project: {
|
|
227
224
|
name: 1,
|
|
225
|
+
type: 1,
|
|
228
226
|
set: 1,
|
|
229
227
|
units: 1
|
|
230
228
|
}
|
|
@@ -284,6 +282,28 @@ function useAreaRepo() {
|
|
|
284
282
|
throw error;
|
|
285
283
|
}
|
|
286
284
|
}
|
|
285
|
+
async function getAreaByMultipleId(_id) {
|
|
286
|
+
for (let i = 0; i < _id.length; i++) {
|
|
287
|
+
try {
|
|
288
|
+
_id[i] = new ObjectId2(_id[i]);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw new BadRequestError2("Invalid area ID format.");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const query = {
|
|
294
|
+
_id: { $in: _id },
|
|
295
|
+
status: { $ne: "deleted" }
|
|
296
|
+
};
|
|
297
|
+
try {
|
|
298
|
+
const data = await collection.aggregate([{ $match: query }]).toArray();
|
|
299
|
+
if (!data || data.length === 0) {
|
|
300
|
+
throw new NotFoundError("Area not found.");
|
|
301
|
+
}
|
|
302
|
+
return data;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
287
307
|
async function verifyAreaByUnitId(unitId) {
|
|
288
308
|
try {
|
|
289
309
|
unitId = new ObjectId2(unitId);
|
|
@@ -445,6 +465,7 @@ function useAreaRepo() {
|
|
|
445
465
|
getAreas,
|
|
446
466
|
getAreasForChecklist,
|
|
447
467
|
getAreaById,
|
|
468
|
+
getAreaByMultipleId,
|
|
448
469
|
verifyAreaByUnitId,
|
|
449
470
|
updateArea,
|
|
450
471
|
updateAreaChecklist,
|
|
@@ -1645,6 +1666,7 @@ import { ObjectId as ObjectId7 } from "mongodb";
|
|
|
1645
1666
|
var allowedChecklistStatus = ["ready", "completed"];
|
|
1646
1667
|
var areaChecklistSchema = Joi7.object({
|
|
1647
1668
|
schedule: Joi7.string().hex().required(),
|
|
1669
|
+
area: Joi7.string().hex().required(),
|
|
1648
1670
|
name: Joi7.string().required(),
|
|
1649
1671
|
type: Joi7.string().valid(...allowedTypes).required(),
|
|
1650
1672
|
checklist: Joi7.array().items(
|
|
@@ -1672,6 +1694,13 @@ function MAreaChecklist(value) {
|
|
|
1672
1694
|
throw new BadRequestError12("Invalid schedule ID format.");
|
|
1673
1695
|
}
|
|
1674
1696
|
}
|
|
1697
|
+
if (value.area) {
|
|
1698
|
+
try {
|
|
1699
|
+
value.area = new ObjectId7(value.area);
|
|
1700
|
+
} catch (error2) {
|
|
1701
|
+
throw new BadRequestError12("Invalid area ID format.");
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1675
1704
|
if (value.checklist && Array.isArray(value.checklist)) {
|
|
1676
1705
|
value.checklist = value.checklist.map((checklistItem) => {
|
|
1677
1706
|
return {
|
|
@@ -1689,6 +1718,7 @@ function MAreaChecklist(value) {
|
|
|
1689
1718
|
}
|
|
1690
1719
|
return {
|
|
1691
1720
|
schedule: value.schedule,
|
|
1721
|
+
area: value.area,
|
|
1692
1722
|
name: value.name,
|
|
1693
1723
|
type: value.type,
|
|
1694
1724
|
checklist: value.checklist || [],
|
|
@@ -2395,19 +2425,17 @@ function useAreaChecklistService() {
|
|
|
2395
2425
|
const results = [];
|
|
2396
2426
|
let totalChecklistsCreated = 0;
|
|
2397
2427
|
const BATCH_SIZE = 10;
|
|
2398
|
-
const
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
if (commonAreas.length > 0) {
|
|
2404
|
-
for (let i = 0; i < commonAreas.length; i += BATCH_SIZE) {
|
|
2405
|
-
const batch = commonAreas.slice(i, i + BATCH_SIZE);
|
|
2428
|
+
const areasResult = await getAreasForChecklist(value.site);
|
|
2429
|
+
const areas = areasResult || [];
|
|
2430
|
+
if (areas.length > 0) {
|
|
2431
|
+
for (let i = 0; i < areas.length; i += BATCH_SIZE) {
|
|
2432
|
+
const batch = areas.slice(i, i + BATCH_SIZE);
|
|
2406
2433
|
const batchPromises = batch.map(async (area) => {
|
|
2407
2434
|
const checklistData = {
|
|
2408
2435
|
schedule: value.schedule,
|
|
2436
|
+
area: area._id.toString(),
|
|
2409
2437
|
name: area.name,
|
|
2410
|
-
type:
|
|
2438
|
+
type: area.type,
|
|
2411
2439
|
checklist: area.units && area.units.length > 0 ? Array.from({ length: area.set || 1 }, (_, index) => ({
|
|
2412
2440
|
set: index + 1,
|
|
2413
2441
|
units: area.units.map((unit) => ({
|
|
@@ -2427,51 +2455,11 @@ function useAreaChecklistService() {
|
|
|
2427
2455
|
results.push(...batchResults);
|
|
2428
2456
|
}
|
|
2429
2457
|
logger14.info(
|
|
2430
|
-
`Created ${
|
|
2458
|
+
`Created ${areas.length} common area checklists for site: ${value.site}`
|
|
2431
2459
|
);
|
|
2432
2460
|
} else {
|
|
2433
2461
|
logger14.warn(`No common areas found for site: ${value.site}`);
|
|
2434
2462
|
}
|
|
2435
|
-
const toiletAreasResult = await getAreasForChecklist({
|
|
2436
|
-
site: value.site,
|
|
2437
|
-
type: "toilet"
|
|
2438
|
-
});
|
|
2439
|
-
const toiletAreas = toiletAreasResult || [];
|
|
2440
|
-
if (toiletAreas.length > 0) {
|
|
2441
|
-
for (let i = 0; i < toiletAreas.length; i += BATCH_SIZE) {
|
|
2442
|
-
const batch = toiletAreas.slice(i, i + BATCH_SIZE);
|
|
2443
|
-
const batchPromises = batch.map(async (toiletLocation) => {
|
|
2444
|
-
const checklistData = {
|
|
2445
|
-
schedule: value.schedule,
|
|
2446
|
-
name: toiletLocation.name,
|
|
2447
|
-
type: "toilet",
|
|
2448
|
-
checklist: toiletLocation.units && toiletLocation.units.length > 0 ? Array.from(
|
|
2449
|
-
{ length: toiletLocation.set || 1 },
|
|
2450
|
-
(_, index) => ({
|
|
2451
|
-
set: index + 1,
|
|
2452
|
-
units: toiletLocation.units.map((unit) => ({
|
|
2453
|
-
unit: unit.unit.toString(),
|
|
2454
|
-
name: unit.name
|
|
2455
|
-
}))
|
|
2456
|
-
})
|
|
2457
|
-
) : []
|
|
2458
|
-
};
|
|
2459
|
-
const insertedId = await _createAreaChecklist(
|
|
2460
|
-
checklistData,
|
|
2461
|
-
session
|
|
2462
|
-
);
|
|
2463
|
-
totalChecklistsCreated++;
|
|
2464
|
-
return insertedId;
|
|
2465
|
-
});
|
|
2466
|
-
const batchResults = await Promise.all(batchPromises);
|
|
2467
|
-
results.push(...batchResults);
|
|
2468
|
-
}
|
|
2469
|
-
logger14.info(
|
|
2470
|
-
`Created ${toiletAreas.length} toilet area checklists for site: ${value.site}`
|
|
2471
|
-
);
|
|
2472
|
-
} else {
|
|
2473
|
-
logger14.warn(`No toilet locations found for site: ${value.site}`);
|
|
2474
|
-
}
|
|
2475
2463
|
await session?.commitTransaction();
|
|
2476
2464
|
logger14.info(
|
|
2477
2465
|
`Successfully created ${totalChecklistsCreated} area checklists for site: ${value.site}`
|
|
@@ -4124,24 +4112,22 @@ function useRequestItemController() {
|
|
|
4124
4112
|
import { BadRequestError as BadRequestError26, logger as logger25 } from "@iservice365/node-server-utils";
|
|
4125
4113
|
import Joi15 from "joi";
|
|
4126
4114
|
import { ObjectId as ObjectId15 } from "mongodb";
|
|
4127
|
-
var allowedFrequency = [
|
|
4128
|
-
|
|
4129
|
-
"
|
|
4130
|
-
"
|
|
4131
|
-
"
|
|
4132
|
-
"Thu",
|
|
4133
|
-
"Fri",
|
|
4134
|
-
"Sat",
|
|
4135
|
-
"Sun"
|
|
4115
|
+
var allowedFrequency = [
|
|
4116
|
+
"daily",
|
|
4117
|
+
"weekly",
|
|
4118
|
+
"monthly",
|
|
4119
|
+
"annually"
|
|
4136
4120
|
];
|
|
4137
|
-
var
|
|
4138
|
-
|
|
4139
|
-
"
|
|
4140
|
-
"
|
|
4141
|
-
"
|
|
4142
|
-
"
|
|
4143
|
-
"
|
|
4121
|
+
var allowedDays = [
|
|
4122
|
+
"Monday",
|
|
4123
|
+
"Tuesday",
|
|
4124
|
+
"Wednesday",
|
|
4125
|
+
"Thursday",
|
|
4126
|
+
"Friday",
|
|
4127
|
+
"Saturday",
|
|
4128
|
+
"Sunday"
|
|
4144
4129
|
];
|
|
4130
|
+
var allowedWeekOfMonth = ["start", "end"];
|
|
4145
4131
|
var allowedMonths = [
|
|
4146
4132
|
"January",
|
|
4147
4133
|
"February",
|
|
@@ -4161,22 +4147,10 @@ var scheduleTaskSchema = Joi15.object({
|
|
|
4161
4147
|
title: Joi15.string().required(),
|
|
4162
4148
|
frequency: Joi15.string().valid(...allowedFrequency).required(),
|
|
4163
4149
|
time: Joi15.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).required(),
|
|
4164
|
-
day: Joi15.string().valid(...allowedDays).
|
|
4165
|
-
weekOfMonth: Joi15.string().valid(...allowedWeekOfMonth).
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
otherwise: Joi15.optional().allow("", null)
|
|
4169
|
-
}),
|
|
4170
|
-
quarter: Joi15.string().valid(...allowedQuarter).when("frequency", {
|
|
4171
|
-
is: "quarter",
|
|
4172
|
-
then: Joi15.required(),
|
|
4173
|
-
otherwise: Joi15.optional().allow("", null)
|
|
4174
|
-
}),
|
|
4175
|
-
month: Joi15.string().valid(...allowedMonths).when("frequency", {
|
|
4176
|
-
is: Joi15.string().valid("quarter", "year"),
|
|
4177
|
-
then: Joi15.required(),
|
|
4178
|
-
otherwise: Joi15.optional().allow("", null)
|
|
4179
|
-
}),
|
|
4150
|
+
day: Joi15.array().items(Joi15.string().valid(...allowedDays)).optional().allow(null),
|
|
4151
|
+
weekOfMonth: Joi15.string().valid(...allowedWeekOfMonth).optional().allow("", null),
|
|
4152
|
+
month: Joi15.string().valid(...allowedMonths).optional().allow("", null),
|
|
4153
|
+
date: Joi15.number().min(1).max(31).optional().allow(null),
|
|
4180
4154
|
description: Joi15.string().optional().allow("", null),
|
|
4181
4155
|
areas: Joi15.array().min(1).items(
|
|
4182
4156
|
Joi15.object({
|
|
@@ -4217,8 +4191,8 @@ function MScheduleTask(value) {
|
|
|
4217
4191
|
time: value.time,
|
|
4218
4192
|
day: value.day,
|
|
4219
4193
|
weekOfMonth: value.weekOfMonth,
|
|
4220
|
-
quarter: value.quarter,
|
|
4221
4194
|
month: value.month,
|
|
4195
|
+
date: value.date,
|
|
4222
4196
|
description: value.description,
|
|
4223
4197
|
areas: value.areas,
|
|
4224
4198
|
status: "active",
|
|
@@ -4343,6 +4317,73 @@ function useScheduleTaskRepository() {
|
|
|
4343
4317
|
throw error;
|
|
4344
4318
|
}
|
|
4345
4319
|
}
|
|
4320
|
+
async function getAllScheduleTask() {
|
|
4321
|
+
const query = {
|
|
4322
|
+
status: { $ne: "deleted" }
|
|
4323
|
+
};
|
|
4324
|
+
try {
|
|
4325
|
+
const items = await collection.aggregate([{ $match: query }, { $sort: { _id: -1 } }]).toArray();
|
|
4326
|
+
return items;
|
|
4327
|
+
} catch (error) {
|
|
4328
|
+
throw error;
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
async function getTasksForScheduleTask({
|
|
4332
|
+
page = 1,
|
|
4333
|
+
limit = 10,
|
|
4334
|
+
search = "",
|
|
4335
|
+
site
|
|
4336
|
+
}) {
|
|
4337
|
+
page = page > 0 ? page - 1 : 0;
|
|
4338
|
+
const query = {
|
|
4339
|
+
status: { $ne: "deleted" }
|
|
4340
|
+
};
|
|
4341
|
+
const cacheOptions = {
|
|
4342
|
+
page,
|
|
4343
|
+
limit
|
|
4344
|
+
};
|
|
4345
|
+
try {
|
|
4346
|
+
site = new ObjectId16(site);
|
|
4347
|
+
query.site = site;
|
|
4348
|
+
cacheOptions.site = site.toString();
|
|
4349
|
+
} catch (error) {
|
|
4350
|
+
throw new BadRequestError27("Invalid site ID format.");
|
|
4351
|
+
}
|
|
4352
|
+
if (search) {
|
|
4353
|
+
query.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
4354
|
+
cacheOptions.search = search;
|
|
4355
|
+
}
|
|
4356
|
+
const cacheKey = makeCacheKey8(namespace_collection, cacheOptions);
|
|
4357
|
+
const cachedData = await getCache(cacheKey);
|
|
4358
|
+
if (cachedData) {
|
|
4359
|
+
logger26.info(`Cache hit for key: ${cacheKey}`);
|
|
4360
|
+
return cachedData;
|
|
4361
|
+
}
|
|
4362
|
+
try {
|
|
4363
|
+
const items = await collection.aggregate([
|
|
4364
|
+
{ $match: query },
|
|
4365
|
+
{
|
|
4366
|
+
$project: {
|
|
4367
|
+
createdAt: 1,
|
|
4368
|
+
title: 1
|
|
4369
|
+
}
|
|
4370
|
+
},
|
|
4371
|
+
{ $sort: { _id: -1 } },
|
|
4372
|
+
{ $skip: page * limit },
|
|
4373
|
+
{ $limit: limit }
|
|
4374
|
+
]).toArray();
|
|
4375
|
+
const length = await collection.countDocuments(query);
|
|
4376
|
+
const data = paginate8(items, page, limit, length);
|
|
4377
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
4378
|
+
logger26.info(`Cache set for key: ${cacheKey}`);
|
|
4379
|
+
}).catch((err) => {
|
|
4380
|
+
logger26.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
4381
|
+
});
|
|
4382
|
+
return data;
|
|
4383
|
+
} catch (error) {
|
|
4384
|
+
throw error;
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4346
4387
|
async function getScheduleTaskById(_id, session) {
|
|
4347
4388
|
try {
|
|
4348
4389
|
_id = new ObjectId16(_id);
|
|
@@ -4375,8 +4416,8 @@ function useScheduleTaskRepository() {
|
|
|
4375
4416
|
time: 1,
|
|
4376
4417
|
day: 1,
|
|
4377
4418
|
weekOfMonth: 1,
|
|
4378
|
-
quarter: 1,
|
|
4379
4419
|
month: 1,
|
|
4420
|
+
date: 1,
|
|
4380
4421
|
description: 1,
|
|
4381
4422
|
areas: 1,
|
|
4382
4423
|
status: 1,
|
|
@@ -4445,18 +4486,213 @@ function useScheduleTaskRepository() {
|
|
|
4445
4486
|
createTextIndex,
|
|
4446
4487
|
createScheduleTask,
|
|
4447
4488
|
getScheduleTasks,
|
|
4489
|
+
getAllScheduleTask,
|
|
4490
|
+
getTasksForScheduleTask,
|
|
4448
4491
|
getScheduleTaskById,
|
|
4449
4492
|
updateScheduleTask
|
|
4450
4493
|
};
|
|
4451
4494
|
}
|
|
4452
4495
|
|
|
4496
|
+
// src/services/hygiene-schedule-task.service.ts
|
|
4497
|
+
import { logger as logger27 } from "@iservice365/node-server-utils";
|
|
4498
|
+
function useScheduleTaskService() {
|
|
4499
|
+
const { getAllScheduleTask } = useScheduleTaskRepository();
|
|
4500
|
+
const { createAreaChecklist } = useAreaChecklistService();
|
|
4501
|
+
const { createParentChecklist } = useParentChecklistRepo();
|
|
4502
|
+
function checkScheduleConditions(schedule, currentDate = /* @__PURE__ */ new Date()) {
|
|
4503
|
+
try {
|
|
4504
|
+
const now = currentDate;
|
|
4505
|
+
const currentDay = now.toLocaleDateString("en-US", {
|
|
4506
|
+
weekday: "long",
|
|
4507
|
+
timeZone: "Asia/Singapore"
|
|
4508
|
+
});
|
|
4509
|
+
const currentMonth = now.toLocaleDateString("en-US", {
|
|
4510
|
+
month: "long",
|
|
4511
|
+
timeZone: "Asia/Singapore"
|
|
4512
|
+
});
|
|
4513
|
+
const currentDate_num = Number(
|
|
4514
|
+
now.toLocaleDateString("en-US", {
|
|
4515
|
+
day: "numeric",
|
|
4516
|
+
timeZone: "Asia/Singapore"
|
|
4517
|
+
})
|
|
4518
|
+
);
|
|
4519
|
+
const timeString = now.toLocaleTimeString("en-US", {
|
|
4520
|
+
hour: "2-digit",
|
|
4521
|
+
minute: "2-digit",
|
|
4522
|
+
hour12: false,
|
|
4523
|
+
timeZone: "Asia/Singapore"
|
|
4524
|
+
});
|
|
4525
|
+
const [currentHour, currentMinute] = timeString.split(":").map(Number);
|
|
4526
|
+
logger27.info(
|
|
4527
|
+
`Checking schedule ${schedule._id}: Current time ${currentHour}:${currentMinute}, Schedule time ${schedule.time}, Frequency ${schedule.frequency}`
|
|
4528
|
+
);
|
|
4529
|
+
const [scheduleHour, scheduleMinute] = schedule.time.split(":").map(Number);
|
|
4530
|
+
const timeMatches = currentHour === scheduleHour && currentMinute === scheduleMinute;
|
|
4531
|
+
if (!timeMatches) {
|
|
4532
|
+
logger27.info(
|
|
4533
|
+
`Schedule ${schedule._id}: Time does not match. Current: ${currentHour}:${currentMinute}, Expected: ${scheduleHour}:${scheduleMinute}`
|
|
4534
|
+
);
|
|
4535
|
+
return false;
|
|
4536
|
+
}
|
|
4537
|
+
logger27.info(
|
|
4538
|
+
`Schedule ${schedule._id}: Time matches, checking frequency...`
|
|
4539
|
+
);
|
|
4540
|
+
switch (schedule.frequency) {
|
|
4541
|
+
case "daily":
|
|
4542
|
+
logger27.info(`Schedule ${schedule._id}: Daily frequency matched`);
|
|
4543
|
+
return true;
|
|
4544
|
+
case "weekly":
|
|
4545
|
+
if (!schedule.day || schedule.day.length === 0) {
|
|
4546
|
+
logger27.warn(
|
|
4547
|
+
`Schedule ${schedule._id} is weekly but has no days specified`
|
|
4548
|
+
);
|
|
4549
|
+
return false;
|
|
4550
|
+
}
|
|
4551
|
+
const dayMatches = schedule.day.includes(currentDay);
|
|
4552
|
+
logger27.info(
|
|
4553
|
+
`Schedule ${schedule._id}: Weekly - Current day: ${currentDay}, Schedule days: ${schedule.day.join(
|
|
4554
|
+
", "
|
|
4555
|
+
)}, Match: ${dayMatches}`
|
|
4556
|
+
);
|
|
4557
|
+
return dayMatches;
|
|
4558
|
+
case "monthly":
|
|
4559
|
+
if (!schedule.weekOfMonth) {
|
|
4560
|
+
logger27.warn(
|
|
4561
|
+
`Schedule ${schedule._id} is monthly but has no weekOfMonth specified`
|
|
4562
|
+
);
|
|
4563
|
+
return false;
|
|
4564
|
+
}
|
|
4565
|
+
if (schedule.weekOfMonth === "start") {
|
|
4566
|
+
const matches2 = currentDate_num >= 1 && currentDate_num <= 7;
|
|
4567
|
+
logger27.info(
|
|
4568
|
+
`Schedule ${schedule._id}: Monthly start - Current date: ${currentDate_num}, Match: ${matches2}`
|
|
4569
|
+
);
|
|
4570
|
+
return matches2;
|
|
4571
|
+
} else if (schedule.weekOfMonth === "end") {
|
|
4572
|
+
const lastDayOfMonth = new Date(
|
|
4573
|
+
now.getFullYear(),
|
|
4574
|
+
now.getMonth() + 1,
|
|
4575
|
+
0
|
|
4576
|
+
).getDate();
|
|
4577
|
+
const matches2 = currentDate_num > lastDayOfMonth - 7;
|
|
4578
|
+
logger27.info(
|
|
4579
|
+
`Schedule ${schedule._id}: Monthly end - Current date: ${currentDate_num}, Last day: ${lastDayOfMonth}, Match: ${matches2}`
|
|
4580
|
+
);
|
|
4581
|
+
return matches2;
|
|
4582
|
+
}
|
|
4583
|
+
return false;
|
|
4584
|
+
case "annually":
|
|
4585
|
+
if (!schedule.month || !schedule.date) {
|
|
4586
|
+
logger27.warn(
|
|
4587
|
+
`Schedule ${schedule._id} is annually but has no month or date specified`
|
|
4588
|
+
);
|
|
4589
|
+
return false;
|
|
4590
|
+
}
|
|
4591
|
+
const matches = currentMonth === schedule.month && currentDate_num === schedule.date;
|
|
4592
|
+
logger27.info(
|
|
4593
|
+
`Schedule ${schedule._id}: Annually - Current: ${currentMonth} ${currentDate_num}, Expected: ${schedule.month} ${schedule.date}, Match: ${matches}`
|
|
4594
|
+
);
|
|
4595
|
+
return matches;
|
|
4596
|
+
default:
|
|
4597
|
+
logger27.warn(`Unknown frequency type: ${schedule.frequency}`);
|
|
4598
|
+
return false;
|
|
4599
|
+
}
|
|
4600
|
+
} catch (error) {
|
|
4601
|
+
logger27.error(
|
|
4602
|
+
`Error checking schedule conditions for ${schedule._id}:`,
|
|
4603
|
+
error
|
|
4604
|
+
);
|
|
4605
|
+
return false;
|
|
4606
|
+
}
|
|
4607
|
+
}
|
|
4608
|
+
async function processScheduledTasks(currentDate) {
|
|
4609
|
+
try {
|
|
4610
|
+
logger27.info("Starting scheduled task processing...");
|
|
4611
|
+
const scheduleTasks = await getAllScheduleTask();
|
|
4612
|
+
if (!scheduleTasks || scheduleTasks.length === 0) {
|
|
4613
|
+
logger27.info("No schedule tasks found to process");
|
|
4614
|
+
return { processed: 0, validated: 0 };
|
|
4615
|
+
}
|
|
4616
|
+
logger27.info(`Found ${scheduleTasks.length} schedule tasks to check`);
|
|
4617
|
+
let processedCount = 0;
|
|
4618
|
+
let validatedCount = 0;
|
|
4619
|
+
const validatedTasks = [];
|
|
4620
|
+
for (const scheduleTask of scheduleTasks) {
|
|
4621
|
+
try {
|
|
4622
|
+
logger27.info(
|
|
4623
|
+
`Checking schedule ${scheduleTask._id} - ${scheduleTask.title}: time=${scheduleTask.time}, frequency=${scheduleTask.frequency}`
|
|
4624
|
+
);
|
|
4625
|
+
const shouldRun = checkScheduleConditions(scheduleTask, currentDate);
|
|
4626
|
+
if (!shouldRun) {
|
|
4627
|
+
logger27.info(
|
|
4628
|
+
`Schedule ${scheduleTask._id} conditions not met, skipping`
|
|
4629
|
+
);
|
|
4630
|
+
continue;
|
|
4631
|
+
}
|
|
4632
|
+
logger27.info(
|
|
4633
|
+
`Schedule ${scheduleTask._id} conditions validated, creating area checklists`
|
|
4634
|
+
);
|
|
4635
|
+
if (!scheduleTask._id) {
|
|
4636
|
+
logger27.warn(`Schedule ${scheduleTask.title} has no _id, skipping`);
|
|
4637
|
+
continue;
|
|
4638
|
+
}
|
|
4639
|
+
if (!scheduleTask.site) {
|
|
4640
|
+
logger27.warn(`Schedule ${scheduleTask._id} has no site, skipping`);
|
|
4641
|
+
continue;
|
|
4642
|
+
}
|
|
4643
|
+
logger27.info(
|
|
4644
|
+
`Getting or creating parent checklist for schedule ${scheduleTask._id} in site ${scheduleTask.site}`
|
|
4645
|
+
);
|
|
4646
|
+
const parentChecklistIds = await createParentChecklist({
|
|
4647
|
+
site: scheduleTask.site.toString(),
|
|
4648
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4649
|
+
});
|
|
4650
|
+
const parentChecklistId = Array.isArray(parentChecklistIds) ? parentChecklistIds[0] : parentChecklistIds;
|
|
4651
|
+
logger27.info(
|
|
4652
|
+
`Using parent checklist ${parentChecklistId}, now creating area checklists`
|
|
4653
|
+
);
|
|
4654
|
+
const createdChecklistIds = await createAreaChecklist({
|
|
4655
|
+
schedule: parentChecklistId.toString(),
|
|
4656
|
+
site: scheduleTask.site.toString()
|
|
4657
|
+
});
|
|
4658
|
+
processedCount++;
|
|
4659
|
+
validatedCount++;
|
|
4660
|
+
validatedTasks.push(scheduleTask);
|
|
4661
|
+
logger27.info(
|
|
4662
|
+
`Successfully processed schedule ${scheduleTask._id}, created parent checklist ${parentChecklistId} and ${createdChecklistIds.length} area checklists`
|
|
4663
|
+
);
|
|
4664
|
+
} catch (error) {
|
|
4665
|
+
logger27.error(
|
|
4666
|
+
`Error processing schedule task ${scheduleTask._id}:`,
|
|
4667
|
+
error
|
|
4668
|
+
);
|
|
4669
|
+
continue;
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
logger27.info(
|
|
4673
|
+
`Scheduled task processing completed. Processed: ${processedCount}, Validated: ${validatedCount} tasks`
|
|
4674
|
+
);
|
|
4675
|
+
return {
|
|
4676
|
+
processed: processedCount,
|
|
4677
|
+
validated: validatedCount,
|
|
4678
|
+
tasks: validatedTasks
|
|
4679
|
+
};
|
|
4680
|
+
} catch (error) {
|
|
4681
|
+
logger27.error("Error processing scheduled tasks:", error);
|
|
4682
|
+
throw error;
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
return { checkScheduleConditions, processScheduledTasks };
|
|
4686
|
+
}
|
|
4687
|
+
|
|
4453
4688
|
// src/controllers/hygiene-schedule-task.controller.ts
|
|
4454
|
-
import { BadRequestError as BadRequestError28, logger as
|
|
4689
|
+
import { BadRequestError as BadRequestError28, logger as logger28 } from "@iservice365/node-server-utils";
|
|
4455
4690
|
import Joi16 from "joi";
|
|
4456
4691
|
function useScheduleTaskController() {
|
|
4457
4692
|
const {
|
|
4458
4693
|
createScheduleTask: _createScheduleTask,
|
|
4459
4694
|
getScheduleTasks: _getScheduleTasks,
|
|
4695
|
+
getTasksForScheduleTask: _getTasksForScheduleTask,
|
|
4460
4696
|
getScheduleTaskById: _getScheduleTaskById,
|
|
4461
4697
|
updateScheduleTask: _updateScheduleTask
|
|
4462
4698
|
} = useScheduleTaskRepository();
|
|
@@ -4464,7 +4700,7 @@ function useScheduleTaskController() {
|
|
|
4464
4700
|
const payload = { ...req.body, ...req.params };
|
|
4465
4701
|
const { error } = scheduleTaskSchema.validate(payload);
|
|
4466
4702
|
if (error) {
|
|
4467
|
-
|
|
4703
|
+
logger28.log({ level: "error", message: error.message });
|
|
4468
4704
|
next(new BadRequestError28(error.message));
|
|
4469
4705
|
return;
|
|
4470
4706
|
}
|
|
@@ -4473,7 +4709,7 @@ function useScheduleTaskController() {
|
|
|
4473
4709
|
res.status(201).json({ message: "Schedule task created successfully.", id });
|
|
4474
4710
|
return;
|
|
4475
4711
|
} catch (error2) {
|
|
4476
|
-
|
|
4712
|
+
logger28.log({ level: "error", message: error2.message });
|
|
4477
4713
|
next(error2);
|
|
4478
4714
|
return;
|
|
4479
4715
|
}
|
|
@@ -4488,7 +4724,7 @@ function useScheduleTaskController() {
|
|
|
4488
4724
|
});
|
|
4489
4725
|
const { error } = validation.validate(query);
|
|
4490
4726
|
if (error) {
|
|
4491
|
-
|
|
4727
|
+
logger28.log({ level: "error", message: error.message });
|
|
4492
4728
|
next(new BadRequestError28(error.message));
|
|
4493
4729
|
return;
|
|
4494
4730
|
}
|
|
@@ -4506,7 +4742,40 @@ function useScheduleTaskController() {
|
|
|
4506
4742
|
res.json(data);
|
|
4507
4743
|
return;
|
|
4508
4744
|
} catch (error2) {
|
|
4509
|
-
|
|
4745
|
+
logger28.log({ level: "error", message: error2.message });
|
|
4746
|
+
next(error2);
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
async function getTasksForScheduleTask(req, res, next) {
|
|
4751
|
+
const query = { ...req.query, ...req.params };
|
|
4752
|
+
const validation = Joi16.object({
|
|
4753
|
+
page: Joi16.number().min(1).optional().allow("", null),
|
|
4754
|
+
limit: Joi16.number().min(1).optional().allow("", null),
|
|
4755
|
+
search: Joi16.string().optional().allow("", null),
|
|
4756
|
+
site: Joi16.string().hex().required()
|
|
4757
|
+
});
|
|
4758
|
+
const { error } = validation.validate(query);
|
|
4759
|
+
if (error) {
|
|
4760
|
+
logger28.log({ level: "error", message: error.message });
|
|
4761
|
+
next(new BadRequestError28(error.message));
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4764
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
4765
|
+
const limit = parseInt(req.query.limit) ?? 10;
|
|
4766
|
+
const search = req.query.search ?? "";
|
|
4767
|
+
const site = req.params.site ?? "";
|
|
4768
|
+
try {
|
|
4769
|
+
const data = await _getTasksForScheduleTask({
|
|
4770
|
+
page,
|
|
4771
|
+
limit,
|
|
4772
|
+
search,
|
|
4773
|
+
site
|
|
4774
|
+
});
|
|
4775
|
+
res.json(data);
|
|
4776
|
+
return;
|
|
4777
|
+
} catch (error2) {
|
|
4778
|
+
logger28.log({ level: "error", message: error2.message });
|
|
4510
4779
|
next(error2);
|
|
4511
4780
|
return;
|
|
4512
4781
|
}
|
|
@@ -4516,7 +4785,7 @@ function useScheduleTaskController() {
|
|
|
4516
4785
|
const _id = req.params.id;
|
|
4517
4786
|
const { error } = validation.validate(_id);
|
|
4518
4787
|
if (error) {
|
|
4519
|
-
|
|
4788
|
+
logger28.log({ level: "error", message: error.message });
|
|
4520
4789
|
next(new BadRequestError28(error.message));
|
|
4521
4790
|
return;
|
|
4522
4791
|
}
|
|
@@ -4525,7 +4794,7 @@ function useScheduleTaskController() {
|
|
|
4525
4794
|
res.json(data);
|
|
4526
4795
|
return;
|
|
4527
4796
|
} catch (error2) {
|
|
4528
|
-
|
|
4797
|
+
logger28.log({ level: "error", message: error2.message });
|
|
4529
4798
|
next(error2);
|
|
4530
4799
|
return;
|
|
4531
4800
|
}
|
|
@@ -4537,10 +4806,10 @@ function useScheduleTaskController() {
|
|
|
4537
4806
|
title: Joi16.string().optional().allow("", null),
|
|
4538
4807
|
frequency: Joi16.string().valid(...allowedFrequency).optional().allow("", null),
|
|
4539
4808
|
time: Joi16.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).optional().allow("", null),
|
|
4540
|
-
day: Joi16.string().valid(...allowedDays).optional().allow(
|
|
4809
|
+
day: Joi16.array().items(Joi16.string().valid(...allowedDays)).optional().allow(null),
|
|
4541
4810
|
weekOfMonth: Joi16.string().valid(...allowedWeekOfMonth).optional().allow("", null),
|
|
4542
|
-
quarter: Joi16.string().valid(...allowedQuarter).optional().allow("", null),
|
|
4543
4811
|
month: Joi16.string().valid(...allowedMonths).optional().allow("", null),
|
|
4812
|
+
date: Joi16.number().min(1).max(31).optional().allow(null),
|
|
4544
4813
|
description: Joi16.string().optional().allow("", null),
|
|
4545
4814
|
areas: Joi16.array().min(1).items(
|
|
4546
4815
|
Joi16.object({
|
|
@@ -4551,7 +4820,7 @@ function useScheduleTaskController() {
|
|
|
4551
4820
|
});
|
|
4552
4821
|
const { error } = validation.validate(payload);
|
|
4553
4822
|
if (error) {
|
|
4554
|
-
|
|
4823
|
+
logger28.log({ level: "error", message: error.message });
|
|
4555
4824
|
next(new BadRequestError28(error.message));
|
|
4556
4825
|
return;
|
|
4557
4826
|
}
|
|
@@ -4561,7 +4830,7 @@ function useScheduleTaskController() {
|
|
|
4561
4830
|
res.json({ message: "Schedule task updated successfully." });
|
|
4562
4831
|
return;
|
|
4563
4832
|
} catch (error2) {
|
|
4564
|
-
|
|
4833
|
+
logger28.log({ level: "error", message: error2.message });
|
|
4565
4834
|
next(error2);
|
|
4566
4835
|
return;
|
|
4567
4836
|
}
|
|
@@ -4569,6 +4838,7 @@ function useScheduleTaskController() {
|
|
|
4569
4838
|
return {
|
|
4570
4839
|
createScheduleTask,
|
|
4571
4840
|
getScheduleTasks,
|
|
4841
|
+
getTasksForScheduleTask,
|
|
4572
4842
|
getScheduleTaskById,
|
|
4573
4843
|
updateScheduleTask
|
|
4574
4844
|
};
|
|
@@ -4586,7 +4856,6 @@ export {
|
|
|
4586
4856
|
allowedDays,
|
|
4587
4857
|
allowedFrequency,
|
|
4588
4858
|
allowedMonths,
|
|
4589
|
-
allowedQuarter,
|
|
4590
4859
|
allowedRequestItemStatus,
|
|
4591
4860
|
allowedStatus,
|
|
4592
4861
|
allowedTypes,
|
|
@@ -4612,6 +4881,7 @@ export {
|
|
|
4612
4881
|
useRequestItemService,
|
|
4613
4882
|
useScheduleTaskController,
|
|
4614
4883
|
useScheduleTaskRepository,
|
|
4884
|
+
useScheduleTaskService,
|
|
4615
4885
|
useStockController,
|
|
4616
4886
|
useStockRepository,
|
|
4617
4887
|
useStockService,
|