@iservice365/module-hygiene 1.1.0 → 1.4.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/dist/index.js CHANGED
@@ -34,17 +34,24 @@ __export(src_exports, {
34
34
  MAreaChecklist: () => MAreaChecklist,
35
35
  MParentChecklist: () => MParentChecklist,
36
36
  MRequestItem: () => MRequestItem,
37
+ MScheduleTask: () => MScheduleTask,
37
38
  MStock: () => MStock,
38
39
  MSupply: () => MSupply,
39
40
  MUnit: () => MUnit,
40
41
  allowedChecklistStatus: () => allowedChecklistStatus,
42
+ allowedDays: () => allowedDays,
43
+ allowedFrequency: () => allowedFrequency,
44
+ allowedMonths: () => allowedMonths,
45
+ allowedQuarter: () => allowedQuarter,
41
46
  allowedRequestItemStatus: () => allowedRequestItemStatus,
42
47
  allowedStatus: () => allowedStatus,
43
48
  allowedTypes: () => allowedTypes,
49
+ allowedWeekOfMonth: () => allowedWeekOfMonth,
44
50
  areaChecklistSchema: () => areaChecklistSchema,
45
51
  areaSchema: () => areaSchema,
46
52
  parentChecklistSchema: () => parentChecklistSchema,
47
53
  requestItemSchema: () => requestItemSchema,
54
+ scheduleTaskSchema: () => scheduleTaskSchema,
48
55
  stockSchema: () => stockSchema,
49
56
  supplySchema: () => supplySchema,
50
57
  unitSchema: () => unitSchema,
@@ -59,6 +66,8 @@ __export(src_exports, {
59
66
  useRequestItemController: () => useRequestItemController,
60
67
  useRequestItemRepository: () => useRequestItemRepository,
61
68
  useRequestItemService: () => useRequestItemService,
69
+ useScheduleTaskController: () => useScheduleTaskController,
70
+ useScheduleTaskRepository: () => useScheduleTaskRepository,
62
71
  useStockController: () => useStockController,
63
72
  useStockRepository: () => useStockRepository,
64
73
  useStockService: () => useStockService,
@@ -849,8 +858,8 @@ function MUnit(value) {
849
858
  return {
850
859
  site: value.site,
851
860
  name: value.name,
852
- createdAt: /* @__PURE__ */ new Date(),
853
861
  status: "active",
862
+ createdAt: /* @__PURE__ */ new Date(),
854
863
  updatedAt: "",
855
864
  deletedAt: ""
856
865
  };
@@ -1541,6 +1550,9 @@ function useParentChecklistRepo() {
1541
1550
  status,
1542
1551
  updatedAt: /* @__PURE__ */ new Date()
1543
1552
  };
1553
+ if (status === "completed") {
1554
+ updateValue.completedAt = /* @__PURE__ */ new Date();
1555
+ }
1544
1556
  const res = await collection.updateOne(
1545
1557
  { _id },
1546
1558
  { $set: updateValue },
@@ -2953,7 +2965,8 @@ function useSupplyRepository() {
2953
2965
  {
2954
2966
  $project: {
2955
2967
  name: 1,
2956
- qty: 1
2968
+ qty: 1,
2969
+ status: 1
2957
2970
  }
2958
2971
  },
2959
2972
  { $sort: { _id: -1 } },
@@ -3046,7 +3059,7 @@ function useSupplyRepository() {
3046
3059
  } catch (error) {
3047
3060
  const isDuplicated = error.message.includes("duplicate");
3048
3061
  if (isDuplicated) {
3049
- throw new import_node_server_utils17.BadRequestError("Area already exists.");
3062
+ throw new import_node_server_utils17.BadRequestError("Supply already exists.");
3050
3063
  }
3051
3064
  throw error;
3052
3065
  }
@@ -3657,7 +3670,7 @@ function useRequestItemRepository() {
3657
3670
  status: 1
3658
3671
  }
3659
3672
  },
3660
- { $sort: { _id: 1 } },
3673
+ { $sort: { _id: -1 } },
3661
3674
  { $skip: page * limit },
3662
3675
  { $limit: limit }
3663
3676
  ]).toArray();
@@ -3673,11 +3686,140 @@ function useRequestItemRepository() {
3673
3686
  throw error;
3674
3687
  }
3675
3688
  }
3689
+ async function getRequestItemById(_id, session) {
3690
+ try {
3691
+ _id = new import_mongodb14.ObjectId(_id);
3692
+ } catch (error) {
3693
+ throw new import_node_server_utils24.BadRequestError("Invalid request item ID format.");
3694
+ }
3695
+ const query = { _id };
3696
+ const cacheKey = (0, import_node_server_utils24.makeCacheKey)(namespace_collection, {
3697
+ _id: _id.toString()
3698
+ });
3699
+ if (!session) {
3700
+ const cachedData = await getCache(cacheKey);
3701
+ if (cachedData) {
3702
+ import_node_server_utils24.logger.info(`Cache hit for key: ${cacheKey}`);
3703
+ return cachedData;
3704
+ }
3705
+ } else {
3706
+ import_node_server_utils24.logger.info(`Skipping cache during transaction for key: ${cacheKey}`);
3707
+ }
3708
+ try {
3709
+ const data = await collection.aggregate([
3710
+ { $match: query },
3711
+ {
3712
+ $lookup: {
3713
+ from: "site.supply.items",
3714
+ localField: "supply",
3715
+ foreignField: "_id",
3716
+ as: "supplyDetails"
3717
+ }
3718
+ },
3719
+ {
3720
+ $unwind: {
3721
+ path: "$supplyDetails",
3722
+ preserveNullAndEmptyArrays: true
3723
+ }
3724
+ },
3725
+ {
3726
+ $project: {
3727
+ site: 1,
3728
+ supply: 1,
3729
+ supplyName: 1,
3730
+ qty: 1,
3731
+ status: 1,
3732
+ unitOfMeasurement: "$supplyDetails.unitOfMeasurement"
3733
+ }
3734
+ }
3735
+ ]).toArray();
3736
+ if (!data || data.length === 0) {
3737
+ throw new import_node_server_utils24.NotFoundError("Request item not found.");
3738
+ }
3739
+ setCache(cacheKey, data[0], 15 * 60).then(() => {
3740
+ import_node_server_utils24.logger.info(`Cache set for key: ${cacheKey}`);
3741
+ }).catch((err) => {
3742
+ import_node_server_utils24.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
3743
+ });
3744
+ return data[0];
3745
+ } catch (error) {
3746
+ throw error;
3747
+ }
3748
+ }
3749
+ async function approveRequestItem(_id, remarks, session) {
3750
+ try {
3751
+ _id = new import_mongodb14.ObjectId(_id);
3752
+ } catch (error) {
3753
+ throw new import_node_server_utils24.BadRequestError("Invalid request item ID format.");
3754
+ }
3755
+ try {
3756
+ const updateValue = {
3757
+ status: "approved",
3758
+ remarks: remarks || "",
3759
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3760
+ };
3761
+ const res = await collection.updateOne(
3762
+ { _id },
3763
+ { $set: updateValue },
3764
+ { session }
3765
+ );
3766
+ if (res.modifiedCount === 0) {
3767
+ throw new import_node_server_utils24.InternalServerError("Unable to approve request item.");
3768
+ }
3769
+ delNamespace().then(() => {
3770
+ import_node_server_utils24.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
3771
+ }).catch((err) => {
3772
+ import_node_server_utils24.logger.error(
3773
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3774
+ err
3775
+ );
3776
+ });
3777
+ return res.modifiedCount;
3778
+ } catch (error) {
3779
+ throw error;
3780
+ }
3781
+ }
3782
+ async function disapproveRequestItem(_id, remarks, session) {
3783
+ try {
3784
+ _id = new import_mongodb14.ObjectId(_id);
3785
+ } catch (error) {
3786
+ throw new import_node_server_utils24.BadRequestError("Invalid request item ID format.");
3787
+ }
3788
+ try {
3789
+ const updateValue = {
3790
+ status: "disapproved",
3791
+ remarks: remarks || "",
3792
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3793
+ };
3794
+ const res = await collection.updateOne(
3795
+ { _id },
3796
+ { $set: updateValue },
3797
+ { session }
3798
+ );
3799
+ if (res.modifiedCount === 0) {
3800
+ throw new import_node_server_utils24.InternalServerError("Unable to disapprove request item.");
3801
+ }
3802
+ delNamespace().then(() => {
3803
+ import_node_server_utils24.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
3804
+ }).catch((err) => {
3805
+ import_node_server_utils24.logger.error(
3806
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3807
+ err
3808
+ );
3809
+ });
3810
+ return res.modifiedCount;
3811
+ } catch (error) {
3812
+ throw error;
3813
+ }
3814
+ }
3676
3815
  return {
3677
3816
  createIndex,
3678
3817
  createTextIndex,
3679
3818
  createRequestItem,
3680
- getRequestItems
3819
+ getRequestItems,
3820
+ getRequestItemById,
3821
+ approveRequestItem,
3822
+ disapproveRequestItem
3681
3823
  };
3682
3824
  }
3683
3825
 
@@ -3685,9 +3827,15 @@ function useRequestItemRepository() {
3685
3827
  var import_node_server_utils25 = require("@iservice365/node-server-utils");
3686
3828
  var import_core = require("@iservice365/core");
3687
3829
  function useRequestItemService() {
3688
- const { createRequestItem: _createRequestItem } = useRequestItemRepository();
3830
+ const {
3831
+ createRequestItem: _createRequestItem,
3832
+ getRequestItemById: _getRequestItemById,
3833
+ approveRequestItem: _approveRequestItem,
3834
+ disapproveRequestItem: _disapproveRequestItem
3835
+ } = useRequestItemRepository();
3689
3836
  const { getSupplyById } = useSupplyRepository();
3690
3837
  const { getUserById } = (0, import_core.useUserRepo)();
3838
+ const { createStock } = useStockService();
3691
3839
  async function createRequestItem(value) {
3692
3840
  try {
3693
3841
  const { supply, createdBy } = value;
@@ -3734,17 +3882,76 @@ function useRequestItemService() {
3734
3882
  await session?.endSession();
3735
3883
  }
3736
3884
  }
3737
- return { createRequestItem, createRequestItemByBatch };
3885
+ async function approveRequestItem(id, remarks) {
3886
+ const session = import_node_server_utils25.useAtlas.getClient()?.startSession();
3887
+ try {
3888
+ session?.startTransaction();
3889
+ await _approveRequestItem(id, remarks, session);
3890
+ const requestItem = await _getRequestItemById(id, session);
3891
+ if (requestItem.status !== "pending") {
3892
+ throw new import_node_server_utils25.BadRequestError(
3893
+ "Only 'pending' request items can be approved."
3894
+ );
3895
+ }
3896
+ const createdStocks = await createStock(
3897
+ {
3898
+ site: requestItem.site.toString(),
3899
+ supply: requestItem.supply.toString(),
3900
+ qty: requestItem.qty,
3901
+ remarks
3902
+ },
3903
+ true
3904
+ );
3905
+ await session?.commitTransaction();
3906
+ return createdStocks;
3907
+ } catch (error) {
3908
+ await session?.abortTransaction();
3909
+ throw error;
3910
+ } finally {
3911
+ await session?.endSession();
3912
+ }
3913
+ }
3914
+ async function disapproveRequestItem(id, remarks) {
3915
+ const session = import_node_server_utils25.useAtlas.getClient()?.startSession();
3916
+ try {
3917
+ session?.startTransaction();
3918
+ const result = await _disapproveRequestItem(id, remarks, session);
3919
+ const requestItem = await _getRequestItemById(id, session);
3920
+ if (requestItem.status !== "pending") {
3921
+ throw new import_node_server_utils25.BadRequestError(
3922
+ "Only 'pending' request items can be disapproved."
3923
+ );
3924
+ }
3925
+ await session?.commitTransaction();
3926
+ return result;
3927
+ } catch (error) {
3928
+ await session?.abortTransaction();
3929
+ throw error;
3930
+ } finally {
3931
+ await session?.endSession();
3932
+ }
3933
+ }
3934
+ return {
3935
+ createRequestItem,
3936
+ createRequestItemByBatch,
3937
+ approveRequestItem,
3938
+ disapproveRequestItem
3939
+ };
3738
3940
  }
3739
3941
 
3740
3942
  // src/controllers/hygiene-request-item.controller.ts
3741
3943
  var import_node_server_utils26 = require("@iservice365/node-server-utils");
3742
3944
  var import_joi14 = __toESM(require("joi"));
3743
3945
  function useRequestItemController() {
3744
- const { getRequestItems: _getRequestItems } = useRequestItemRepository();
3946
+ const {
3947
+ getRequestItems: _getRequestItems,
3948
+ getRequestItemById: _getRequestItemById
3949
+ } = useRequestItemRepository();
3745
3950
  const {
3746
3951
  createRequestItem: _createRequestItem,
3747
- createRequestItemByBatch: _createRequestItemByBatch
3952
+ createRequestItemByBatch: _createRequestItemByBatch,
3953
+ approveRequestItem: _approveRequestItem,
3954
+ disapproveRequestItem: _disapproveRequestItem
3748
3955
  } = useRequestItemService();
3749
3956
  async function createRequestItem(req, res, next) {
3750
3957
  const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
@@ -3849,10 +4056,521 @@ function useRequestItemController() {
3849
4056
  return;
3850
4057
  }
3851
4058
  }
4059
+ async function getRequestItemById(req, res, next) {
4060
+ const validation = import_joi14.default.string().hex().required();
4061
+ const _id = req.params.id;
4062
+ const { error } = validation.validate(_id);
4063
+ if (error) {
4064
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
4065
+ next(new import_node_server_utils26.BadRequestError(error.message));
4066
+ return;
4067
+ }
4068
+ try {
4069
+ const data = await _getRequestItemById(_id);
4070
+ res.json(data);
4071
+ return;
4072
+ } catch (error2) {
4073
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
4074
+ next(error2);
4075
+ return;
4076
+ }
4077
+ }
4078
+ async function approveRequestItem(req, res, next) {
4079
+ const payload = { ...req.params, ...req.body };
4080
+ const validation = import_joi14.default.object({
4081
+ id: import_joi14.default.string().hex().required(),
4082
+ remarks: import_joi14.default.string().optional().allow("", null)
4083
+ });
4084
+ const { error } = validation.validate(payload);
4085
+ if (error) {
4086
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
4087
+ next(new import_node_server_utils26.BadRequestError(error.message));
4088
+ return;
4089
+ }
4090
+ try {
4091
+ await _approveRequestItem(payload.id, payload.remarks);
4092
+ res.json({ message: "Request item approved successfully." });
4093
+ return;
4094
+ } catch (error2) {
4095
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
4096
+ next(error2);
4097
+ return;
4098
+ }
4099
+ }
4100
+ async function disapproveRequestItem(req, res, next) {
4101
+ const payload = { ...req.params, ...req.body };
4102
+ const validation = import_joi14.default.object({
4103
+ id: import_joi14.default.string().hex().required(),
4104
+ remarks: import_joi14.default.string().optional().allow("", null)
4105
+ });
4106
+ const { error } = validation.validate(payload);
4107
+ if (error) {
4108
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
4109
+ next(new import_node_server_utils26.BadRequestError(error.message));
4110
+ return;
4111
+ }
4112
+ try {
4113
+ await _disapproveRequestItem(payload.id, payload.remarks);
4114
+ res.json({ message: "Request item disapproved successfully." });
4115
+ return;
4116
+ } catch (error2) {
4117
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
4118
+ next(error2);
4119
+ return;
4120
+ }
4121
+ }
3852
4122
  return {
3853
4123
  createRequestItem,
3854
4124
  createRequestItemByBatch,
3855
- getRequestItems
4125
+ getRequestItems,
4126
+ getRequestItemById,
4127
+ approveRequestItem,
4128
+ disapproveRequestItem
4129
+ };
4130
+ }
4131
+
4132
+ // src/models/hygiene-schedule-task.model.ts
4133
+ var import_node_server_utils27 = require("@iservice365/node-server-utils");
4134
+ var import_joi15 = __toESM(require("joi"));
4135
+ var import_mongodb15 = require("mongodb");
4136
+ var allowedFrequency = ["week", "month", "quarter", "year"];
4137
+ var allowedDays = [
4138
+ "Mon",
4139
+ "Tue",
4140
+ "Wed",
4141
+ "Thu",
4142
+ "Fri",
4143
+ "Sat",
4144
+ "Sun"
4145
+ ];
4146
+ var allowedQuarter = ["1st", "2nd", "3rd", "4th"];
4147
+ var allowedWeekOfMonth = [
4148
+ "1st",
4149
+ "2nd",
4150
+ "3rd",
4151
+ "4th",
4152
+ "last"
4153
+ ];
4154
+ var allowedMonths = [
4155
+ "January",
4156
+ "February",
4157
+ "March",
4158
+ "April",
4159
+ "May",
4160
+ "June",
4161
+ "July",
4162
+ "August",
4163
+ "September",
4164
+ "October",
4165
+ "November",
4166
+ "December"
4167
+ ];
4168
+ var scheduleTaskSchema = import_joi15.default.object({
4169
+ site: import_joi15.default.string().hex().required(),
4170
+ title: import_joi15.default.string().required(),
4171
+ frequency: import_joi15.default.string().valid(...allowedFrequency).required(),
4172
+ time: import_joi15.default.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).required(),
4173
+ day: import_joi15.default.string().valid(...allowedDays).required(),
4174
+ weekOfMonth: import_joi15.default.string().valid(...allowedWeekOfMonth).when("frequency", {
4175
+ is: import_joi15.default.string().valid("month", "quarter", "year"),
4176
+ then: import_joi15.default.required(),
4177
+ otherwise: import_joi15.default.optional().allow("", null)
4178
+ }),
4179
+ quarter: import_joi15.default.string().valid(...allowedQuarter).when("frequency", {
4180
+ is: "quarter",
4181
+ then: import_joi15.default.required(),
4182
+ otherwise: import_joi15.default.optional().allow("", null)
4183
+ }),
4184
+ month: import_joi15.default.string().valid(...allowedMonths).when("frequency", {
4185
+ is: import_joi15.default.string().valid("quarter", "year"),
4186
+ then: import_joi15.default.required(),
4187
+ otherwise: import_joi15.default.optional().allow("", null)
4188
+ }),
4189
+ description: import_joi15.default.string().optional().allow("", null),
4190
+ areas: import_joi15.default.array().min(1).items(
4191
+ import_joi15.default.object({
4192
+ name: import_joi15.default.string().required(),
4193
+ value: import_joi15.default.any().required()
4194
+ })
4195
+ ).required()
4196
+ });
4197
+ function MScheduleTask(value) {
4198
+ const { error } = scheduleTaskSchema.validate(value);
4199
+ if (error) {
4200
+ import_node_server_utils27.logger.info(`Hygiene Schedule Task Model: ${error.message}`);
4201
+ throw new import_node_server_utils27.BadRequestError(error.message);
4202
+ }
4203
+ if (value.site) {
4204
+ try {
4205
+ value.site = new import_mongodb15.ObjectId(value.site);
4206
+ } catch (error2) {
4207
+ throw new import_node_server_utils27.BadRequestError("Invalid site ID format.");
4208
+ }
4209
+ }
4210
+ if (value.areas && Array.isArray(value.areas)) {
4211
+ value.areas = value.areas.map((area) => {
4212
+ try {
4213
+ return {
4214
+ name: area.name,
4215
+ value: new import_mongodb15.ObjectId(area.value.toString())
4216
+ };
4217
+ } catch (error2) {
4218
+ throw new import_node_server_utils27.BadRequestError(`Invalid area value format: ${area.name}`);
4219
+ }
4220
+ });
4221
+ }
4222
+ return {
4223
+ site: value.site,
4224
+ title: value.title,
4225
+ frequency: value.frequency,
4226
+ time: value.time,
4227
+ day: value.day,
4228
+ weekOfMonth: value.weekOfMonth,
4229
+ quarter: value.quarter,
4230
+ month: value.month,
4231
+ description: value.description,
4232
+ areas: value.areas,
4233
+ status: "active",
4234
+ createdAt: /* @__PURE__ */ new Date(),
4235
+ updatedAt: "",
4236
+ deletedAt: ""
4237
+ };
4238
+ }
4239
+
4240
+ // src/repositories/hygiene-schedule-task.repository.ts
4241
+ var import_mongodb16 = require("mongodb");
4242
+ var import_node_server_utils28 = require("@iservice365/node-server-utils");
4243
+ function useScheduleTaskRepository() {
4244
+ const db = import_node_server_utils28.useAtlas.getDb();
4245
+ if (!db) {
4246
+ throw new import_node_server_utils28.InternalServerError("Unable to connect to server.");
4247
+ }
4248
+ const namespace_collection = "site.schedule-tasks";
4249
+ const collection = db.collection(namespace_collection);
4250
+ const { delNamespace, setCache, getCache } = (0, import_node_server_utils28.useCache)(namespace_collection);
4251
+ async function createIndex() {
4252
+ try {
4253
+ await collection.createIndexes([
4254
+ { key: { site: 1 } },
4255
+ { key: { status: 1 } }
4256
+ ]);
4257
+ } catch (error) {
4258
+ throw new import_node_server_utils28.InternalServerError(
4259
+ "Failed to create index on hygiene schedule task."
4260
+ );
4261
+ }
4262
+ }
4263
+ async function createTextIndex() {
4264
+ try {
4265
+ await collection.createIndex({ title: "text", description: "text" });
4266
+ } catch (error) {
4267
+ throw new import_node_server_utils28.InternalServerError(
4268
+ "Failed to create text index on hygiene schedule task."
4269
+ );
4270
+ }
4271
+ }
4272
+ async function createScheduleTask(value, session) {
4273
+ try {
4274
+ value = MScheduleTask(value);
4275
+ const res = await collection.insertOne(value, { session });
4276
+ delNamespace().then(() => {
4277
+ import_node_server_utils28.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
4278
+ }).catch((err) => {
4279
+ import_node_server_utils28.logger.error(
4280
+ `Failed to clear cache for namespace: ${namespace_collection}`,
4281
+ err
4282
+ );
4283
+ });
4284
+ return res.insertedId;
4285
+ } catch (error) {
4286
+ throw error;
4287
+ }
4288
+ }
4289
+ async function getScheduleTasks({
4290
+ page = 1,
4291
+ limit = 10,
4292
+ search = "",
4293
+ site
4294
+ }) {
4295
+ page = page > 0 ? page - 1 : 0;
4296
+ const query = {
4297
+ status: { $ne: "deleted" }
4298
+ };
4299
+ const cacheOptions = {
4300
+ page,
4301
+ limit
4302
+ };
4303
+ try {
4304
+ site = new import_mongodb16.ObjectId(site);
4305
+ query.site = site;
4306
+ cacheOptions.site = site.toString();
4307
+ } catch (error) {
4308
+ throw new import_node_server_utils28.BadRequestError("Invalid site ID format.");
4309
+ }
4310
+ if (search) {
4311
+ query.$or = [{ name: { $regex: search, $options: "i" } }];
4312
+ cacheOptions.search = search;
4313
+ }
4314
+ const cacheKey = (0, import_node_server_utils28.makeCacheKey)(namespace_collection, cacheOptions);
4315
+ const cachedData = await getCache(cacheKey);
4316
+ if (cachedData) {
4317
+ import_node_server_utils28.logger.info(`Cache hit for key: ${cacheKey}`);
4318
+ return cachedData;
4319
+ }
4320
+ try {
4321
+ const items = await collection.aggregate([
4322
+ { $match: query },
4323
+ {
4324
+ $project: {
4325
+ title: 1,
4326
+ areas: 1,
4327
+ status: 1
4328
+ }
4329
+ },
4330
+ { $sort: { _id: -1 } },
4331
+ { $skip: page * limit },
4332
+ { $limit: limit }
4333
+ ]).toArray();
4334
+ const length = await collection.countDocuments(query);
4335
+ const data = (0, import_node_server_utils28.paginate)(items, page, limit, length);
4336
+ setCache(cacheKey, data, 15 * 60).then(() => {
4337
+ import_node_server_utils28.logger.info(`Cache set for key: ${cacheKey}`);
4338
+ }).catch((err) => {
4339
+ import_node_server_utils28.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
4340
+ });
4341
+ return data;
4342
+ } catch (error) {
4343
+ throw error;
4344
+ }
4345
+ }
4346
+ async function getScheduleTaskById(_id, session) {
4347
+ try {
4348
+ _id = new import_mongodb16.ObjectId(_id);
4349
+ } catch (error) {
4350
+ throw new import_node_server_utils28.BadRequestError("Invalid schedule task ID format.");
4351
+ }
4352
+ const query = {
4353
+ _id,
4354
+ status: { $ne: "deleted" }
4355
+ };
4356
+ const cacheKey = (0, import_node_server_utils28.makeCacheKey)(namespace_collection, {
4357
+ _id: _id.toString()
4358
+ });
4359
+ if (!session) {
4360
+ const cachedData = await getCache(cacheKey);
4361
+ if (cachedData) {
4362
+ import_node_server_utils28.logger.info(`Cache hit for key: ${cacheKey}`);
4363
+ return cachedData;
4364
+ }
4365
+ } else {
4366
+ import_node_server_utils28.logger.info(`Skipping cache during transaction for key: ${cacheKey}`);
4367
+ }
4368
+ try {
4369
+ const data = await collection.aggregate([
4370
+ { $match: query },
4371
+ {
4372
+ $project: {
4373
+ title: 1,
4374
+ frequency: 1,
4375
+ time: 1,
4376
+ day: 1,
4377
+ weekOfMonth: 1,
4378
+ quarter: 1,
4379
+ month: 1,
4380
+ description: 1,
4381
+ areas: 1,
4382
+ status: 1,
4383
+ createdAt: 1
4384
+ }
4385
+ }
4386
+ ]).toArray();
4387
+ if (!data || data.length === 0) {
4388
+ throw new import_node_server_utils28.NotFoundError("Schedule task not found.");
4389
+ }
4390
+ setCache(cacheKey, data[0], 15 * 60).then(() => {
4391
+ import_node_server_utils28.logger.info(`Cache set for key: ${cacheKey}`);
4392
+ }).catch((err) => {
4393
+ import_node_server_utils28.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
4394
+ });
4395
+ return data[0];
4396
+ } catch (error) {
4397
+ throw error;
4398
+ }
4399
+ }
4400
+ async function updateScheduleTask(_id, value, session) {
4401
+ try {
4402
+ _id = new import_mongodb16.ObjectId(_id);
4403
+ } catch (error) {
4404
+ throw new import_node_server_utils28.BadRequestError("Invalid schedule task ID format.");
4405
+ }
4406
+ if (value.areas && Array.isArray(value.areas)) {
4407
+ value.areas = value.areas.map((area) => {
4408
+ try {
4409
+ return {
4410
+ name: area.name,
4411
+ value: new import_mongodb16.ObjectId(area.value.toString())
4412
+ };
4413
+ } catch (error) {
4414
+ throw new import_node_server_utils28.BadRequestError(`Invalid area value format: ${area.name}`);
4415
+ }
4416
+ });
4417
+ }
4418
+ try {
4419
+ const updateValue = { ...value, updatedAt: /* @__PURE__ */ new Date() };
4420
+ const res = await collection.updateOne(
4421
+ { _id },
4422
+ { $set: updateValue },
4423
+ { session }
4424
+ );
4425
+ if (res.modifiedCount === 0) {
4426
+ throw new import_node_server_utils28.InternalServerError(
4427
+ "Unable to update hygiene schedule task."
4428
+ );
4429
+ }
4430
+ delNamespace().then(() => {
4431
+ import_node_server_utils28.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
4432
+ }).catch((err) => {
4433
+ import_node_server_utils28.logger.error(
4434
+ `Failed to clear cache for namespace: ${namespace_collection}`,
4435
+ err
4436
+ );
4437
+ });
4438
+ return res.modifiedCount;
4439
+ } catch (error) {
4440
+ throw error;
4441
+ }
4442
+ }
4443
+ return {
4444
+ createIndex,
4445
+ createTextIndex,
4446
+ createScheduleTask,
4447
+ getScheduleTasks,
4448
+ getScheduleTaskById,
4449
+ updateScheduleTask
4450
+ };
4451
+ }
4452
+
4453
+ // src/controllers/hygiene-schedule-task.controller.ts
4454
+ var import_node_server_utils29 = require("@iservice365/node-server-utils");
4455
+ var import_joi16 = __toESM(require("joi"));
4456
+ function useScheduleTaskController() {
4457
+ const {
4458
+ createScheduleTask: _createScheduleTask,
4459
+ getScheduleTasks: _getScheduleTasks,
4460
+ getScheduleTaskById: _getScheduleTaskById,
4461
+ updateScheduleTask: _updateScheduleTask
4462
+ } = useScheduleTaskRepository();
4463
+ async function createScheduleTask(req, res, next) {
4464
+ const payload = { ...req.body, ...req.params };
4465
+ const { error } = scheduleTaskSchema.validate(payload);
4466
+ if (error) {
4467
+ import_node_server_utils29.logger.log({ level: "error", message: error.message });
4468
+ next(new import_node_server_utils29.BadRequestError(error.message));
4469
+ return;
4470
+ }
4471
+ try {
4472
+ const id = await _createScheduleTask(payload);
4473
+ res.status(201).json({ message: "Schedule task created successfully.", id });
4474
+ return;
4475
+ } catch (error2) {
4476
+ import_node_server_utils29.logger.log({ level: "error", message: error2.message });
4477
+ next(error2);
4478
+ return;
4479
+ }
4480
+ }
4481
+ async function getScheduleTasks(req, res, next) {
4482
+ const query = { ...req.query, ...req.params };
4483
+ const validation = import_joi16.default.object({
4484
+ page: import_joi16.default.number().min(1).optional().allow("", null),
4485
+ limit: import_joi16.default.number().min(1).optional().allow("", null),
4486
+ search: import_joi16.default.string().optional().allow("", null),
4487
+ site: import_joi16.default.string().hex().required()
4488
+ });
4489
+ const { error } = validation.validate(query);
4490
+ if (error) {
4491
+ import_node_server_utils29.logger.log({ level: "error", message: error.message });
4492
+ next(new import_node_server_utils29.BadRequestError(error.message));
4493
+ return;
4494
+ }
4495
+ const page = parseInt(req.query.page) ?? 1;
4496
+ const limit = parseInt(req.query.limit) ?? 10;
4497
+ const search = req.query.search ?? "";
4498
+ const site = req.params.site ?? "";
4499
+ try {
4500
+ const data = await _getScheduleTasks({
4501
+ page,
4502
+ limit,
4503
+ search,
4504
+ site
4505
+ });
4506
+ res.json(data);
4507
+ return;
4508
+ } catch (error2) {
4509
+ import_node_server_utils29.logger.log({ level: "error", message: error2.message });
4510
+ next(error2);
4511
+ return;
4512
+ }
4513
+ }
4514
+ async function getScheduleTaskById(req, res, next) {
4515
+ const validation = import_joi16.default.string().hex().required();
4516
+ const _id = req.params.id;
4517
+ const { error } = validation.validate(_id);
4518
+ if (error) {
4519
+ import_node_server_utils29.logger.log({ level: "error", message: error.message });
4520
+ next(new import_node_server_utils29.BadRequestError(error.message));
4521
+ return;
4522
+ }
4523
+ try {
4524
+ const data = await _getScheduleTaskById(_id);
4525
+ res.json(data);
4526
+ return;
4527
+ } catch (error2) {
4528
+ import_node_server_utils29.logger.log({ level: "error", message: error2.message });
4529
+ next(error2);
4530
+ return;
4531
+ }
4532
+ }
4533
+ async function updateScheduleTask(req, res, next) {
4534
+ const payload = { id: req.params.id, ...req.body };
4535
+ const validation = import_joi16.default.object({
4536
+ id: import_joi16.default.string().hex().required(),
4537
+ title: import_joi16.default.string().optional().allow("", null),
4538
+ frequency: import_joi16.default.string().valid(...allowedFrequency).optional().allow("", null),
4539
+ time: import_joi16.default.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).optional().allow("", null),
4540
+ day: import_joi16.default.string().valid(...allowedDays).optional().allow("", null),
4541
+ weekOfMonth: import_joi16.default.string().valid(...allowedWeekOfMonth).optional().allow("", null),
4542
+ quarter: import_joi16.default.string().valid(...allowedQuarter).optional().allow("", null),
4543
+ month: import_joi16.default.string().valid(...allowedMonths).optional().allow("", null),
4544
+ description: import_joi16.default.string().optional().allow("", null),
4545
+ areas: import_joi16.default.array().min(1).items(
4546
+ import_joi16.default.object({
4547
+ name: import_joi16.default.string().required(),
4548
+ value: import_joi16.default.any().required()
4549
+ })
4550
+ ).optional()
4551
+ });
4552
+ const { error } = validation.validate(payload);
4553
+ if (error) {
4554
+ import_node_server_utils29.logger.log({ level: "error", message: error.message });
4555
+ next(new import_node_server_utils29.BadRequestError(error.message));
4556
+ return;
4557
+ }
4558
+ try {
4559
+ const { id, ...value } = payload;
4560
+ await _updateScheduleTask(id, value);
4561
+ res.json({ message: "Schedule task updated successfully." });
4562
+ return;
4563
+ } catch (error2) {
4564
+ import_node_server_utils29.logger.log({ level: "error", message: error2.message });
4565
+ next(error2);
4566
+ return;
4567
+ }
4568
+ }
4569
+ return {
4570
+ createScheduleTask,
4571
+ getScheduleTasks,
4572
+ getScheduleTaskById,
4573
+ updateScheduleTask
3856
4574
  };
3857
4575
  }
3858
4576
  // Annotate the CommonJS export names for ESM import in node:
@@ -3861,17 +4579,24 @@ function useRequestItemController() {
3861
4579
  MAreaChecklist,
3862
4580
  MParentChecklist,
3863
4581
  MRequestItem,
4582
+ MScheduleTask,
3864
4583
  MStock,
3865
4584
  MSupply,
3866
4585
  MUnit,
3867
4586
  allowedChecklistStatus,
4587
+ allowedDays,
4588
+ allowedFrequency,
4589
+ allowedMonths,
4590
+ allowedQuarter,
3868
4591
  allowedRequestItemStatus,
3869
4592
  allowedStatus,
3870
4593
  allowedTypes,
4594
+ allowedWeekOfMonth,
3871
4595
  areaChecklistSchema,
3872
4596
  areaSchema,
3873
4597
  parentChecklistSchema,
3874
4598
  requestItemSchema,
4599
+ scheduleTaskSchema,
3875
4600
  stockSchema,
3876
4601
  supplySchema,
3877
4602
  unitSchema,
@@ -3886,6 +4611,8 @@ function useRequestItemController() {
3886
4611
  useRequestItemController,
3887
4612
  useRequestItemRepository,
3888
4613
  useRequestItemService,
4614
+ useScheduleTaskController,
4615
+ useScheduleTaskRepository,
3889
4616
  useStockController,
3890
4617
  useStockRepository,
3891
4618
  useStockService,