@iservice365/module-hygiene 1.0.3 → 1.1.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
@@ -33,15 +33,18 @@ __export(src_exports, {
33
33
  MArea: () => MArea,
34
34
  MAreaChecklist: () => MAreaChecklist,
35
35
  MParentChecklist: () => MParentChecklist,
36
+ MRequestItem: () => MRequestItem,
36
37
  MStock: () => MStock,
37
38
  MSupply: () => MSupply,
38
39
  MUnit: () => MUnit,
39
40
  allowedChecklistStatus: () => allowedChecklistStatus,
41
+ allowedRequestItemStatus: () => allowedRequestItemStatus,
40
42
  allowedStatus: () => allowedStatus,
41
43
  allowedTypes: () => allowedTypes,
42
44
  areaChecklistSchema: () => areaChecklistSchema,
43
45
  areaSchema: () => areaSchema,
44
46
  parentChecklistSchema: () => parentChecklistSchema,
47
+ requestItemSchema: () => requestItemSchema,
45
48
  stockSchema: () => stockSchema,
46
49
  supplySchema: () => supplySchema,
47
50
  unitSchema: () => unitSchema,
@@ -53,12 +56,14 @@ __export(src_exports, {
53
56
  useAreaService: () => useAreaService,
54
57
  useParentChecklistController: () => useParentChecklistController,
55
58
  useParentChecklistRepo: () => useParentChecklistRepo,
59
+ useRequestItemController: () => useRequestItemController,
60
+ useRequestItemRepository: () => useRequestItemRepository,
61
+ useRequestItemService: () => useRequestItemService,
56
62
  useStockController: () => useStockController,
57
63
  useStockRepository: () => useStockRepository,
58
64
  useStockService: () => useStockService,
59
65
  useSupplyController: () => useSupplyController,
60
66
  useSupplyRepository: () => useSupplyRepository,
61
- useSupplyService: () => useSupplyService,
62
67
  useUnitController: () => useUnitController,
63
68
  useUnitRepository: () => useUnitRepository,
64
69
  useUnitService: () => useUnitService
@@ -698,7 +703,7 @@ function useAreaController() {
698
703
  return;
699
704
  }
700
705
  const page = parseInt(req.query.page) ?? 1;
701
- const limit = parseInt(req.query.limit) ?? 20;
706
+ const limit = parseInt(req.query.limit) ?? 10;
702
707
  const search = req.query.search ?? "";
703
708
  const site = req.params.site ?? "";
704
709
  try {
@@ -1234,7 +1239,7 @@ function useUnitController() {
1234
1239
  return;
1235
1240
  }
1236
1241
  const page = parseInt(req.query.page) ?? 1;
1237
- const limit = parseInt(req.query.limit) ?? 20;
1242
+ const limit = parseInt(req.query.limit) ?? 10;
1238
1243
  const search = req.query.search ?? "";
1239
1244
  const site = req.params.site ?? "";
1240
1245
  try {
@@ -1640,7 +1645,7 @@ function useParentChecklistController() {
1640
1645
  return;
1641
1646
  }
1642
1647
  const page = parseInt(req.query.page) ?? 1;
1643
- const limit = parseInt(req.query.limit) ?? 20;
1648
+ const limit = parseInt(req.query.limit) ?? 10;
1644
1649
  const search = req.query.search ?? "";
1645
1650
  const site = req.params.site ?? "";
1646
1651
  const startDate = req.query.startDate ?? "";
@@ -2651,7 +2656,7 @@ function useAreaChecklistController() {
2651
2656
  return;
2652
2657
  }
2653
2658
  const page = parseInt(req.query.page) ?? 1;
2654
- const limit = parseInt(req.query.limit) ?? 20;
2659
+ const limit = parseInt(req.query.limit) ?? 10;
2655
2660
  const search = req.query.search ?? "";
2656
2661
  const type = req.query.type ?? "";
2657
2662
  const schedule = req.params.schedule ?? "";
@@ -2689,7 +2694,7 @@ function useAreaChecklistController() {
2689
2694
  return;
2690
2695
  }
2691
2696
  const page = parseInt(req.query.page) ?? 1;
2692
- const limit = parseInt(req.query.limit) ?? 20;
2697
+ const limit = parseInt(req.query.limit) ?? 10;
2693
2698
  const search = req.query.search ?? "";
2694
2699
  const type = req.query.type ?? "";
2695
2700
  const schedule = req.params.schedule ?? "";
@@ -2747,7 +2752,7 @@ function useAreaChecklistController() {
2747
2752
  return;
2748
2753
  }
2749
2754
  const page = parseInt(req.query.page) ?? 1;
2750
- const limit = parseInt(req.query.limit) ?? 20;
2755
+ const limit = parseInt(req.query.limit) ?? 10;
2751
2756
  const search = req.query.search ?? "";
2752
2757
  const _id = req.params.id ?? "";
2753
2758
  try {
@@ -2822,8 +2827,7 @@ var import_mongodb9 = require("mongodb");
2822
2827
  var supplySchema = import_joi9.default.object({
2823
2828
  site: import_joi9.default.string().hex().required(),
2824
2829
  name: import_joi9.default.string().required(),
2825
- unitOfMeasurement: import_joi9.default.string().required(),
2826
- qty: import_joi9.default.number().min(0).required()
2830
+ unitOfMeasurement: import_joi9.default.string().required()
2827
2831
  });
2828
2832
  function MSupply(value) {
2829
2833
  const { error } = supplySchema.validate(value);
@@ -2842,7 +2846,7 @@ function MSupply(value) {
2842
2846
  site: value.site,
2843
2847
  name: value.name,
2844
2848
  unitOfMeasurement: value.unitOfMeasurement,
2845
- qty: value.qty,
2849
+ qty: 0,
2846
2850
  status: "active",
2847
2851
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2848
2852
  updatedAt: "",
@@ -2968,7 +2972,7 @@ function useSupplyRepository() {
2968
2972
  throw error;
2969
2973
  }
2970
2974
  }
2971
- async function getSupplyById(_id) {
2975
+ async function getSupplyById(_id, session) {
2972
2976
  try {
2973
2977
  _id = new import_mongodb10.ObjectId(_id);
2974
2978
  } catch (error) {
@@ -2981,10 +2985,14 @@ function useSupplyRepository() {
2981
2985
  const cacheKey = (0, import_node_server_utils17.makeCacheKey)(namespace_collection, {
2982
2986
  _id: _id.toString()
2983
2987
  });
2984
- const cachedData = await getCache(cacheKey);
2985
- if (cachedData) {
2986
- import_node_server_utils17.logger.info(`Cache hit for key: ${cacheKey}`);
2987
- return cachedData;
2988
+ if (!session) {
2989
+ const cachedData = await getCache(cacheKey);
2990
+ if (cachedData) {
2991
+ import_node_server_utils17.logger.info(`Cache hit for key: ${cacheKey}`);
2992
+ return cachedData;
2993
+ }
2994
+ } else {
2995
+ import_node_server_utils17.logger.info(`Skipping cache during transaction for key: ${cacheKey}`);
2988
2996
  }
2989
2997
  try {
2990
2998
  const data = await collection.aggregate([
@@ -3088,39 +3096,172 @@ function useSupplyRepository() {
3088
3096
  };
3089
3097
  }
3090
3098
 
3091
- // src/services/hygiene-supply.service.ts
3092
- var import_node_server_utils20 = require("@iservice365/node-server-utils");
3093
-
3094
- // src/models/hygiene-stock.model.ts
3099
+ // src/controllers/hygiene-supply.controller.ts
3095
3100
  var import_node_server_utils18 = require("@iservice365/node-server-utils");
3096
3101
  var import_joi10 = __toESM(require("joi"));
3102
+ function useSupplyController() {
3103
+ const {
3104
+ createSupply: _createSupply,
3105
+ getSupplies: _getSupplies,
3106
+ getSupplyById: _getSupplyById,
3107
+ updateSupply: _updateSupply,
3108
+ deleteSupply: _deleteSupply
3109
+ } = useSupplyRepository();
3110
+ async function createSupply(req, res, next) {
3111
+ const payload = { ...req.body, ...req.params };
3112
+ const { error } = supplySchema.validate(payload);
3113
+ if (error) {
3114
+ import_node_server_utils18.logger.log({ level: "error", message: error.message });
3115
+ next(new import_node_server_utils18.BadRequestError(error.message));
3116
+ return;
3117
+ }
3118
+ try {
3119
+ const id = await _createSupply(payload);
3120
+ res.status(201).json({ message: "Supply created successfully.", id });
3121
+ return;
3122
+ } catch (error2) {
3123
+ import_node_server_utils18.logger.log({ level: "error", message: error2.message });
3124
+ next(error2);
3125
+ return;
3126
+ }
3127
+ }
3128
+ async function getSupplies(req, res, next) {
3129
+ const query = { ...req.query, ...req.params };
3130
+ const validation = import_joi10.default.object({
3131
+ page: import_joi10.default.number().min(1).optional().allow("", null),
3132
+ limit: import_joi10.default.number().min(1).optional().allow("", null),
3133
+ search: import_joi10.default.string().optional().allow("", null),
3134
+ site: import_joi10.default.string().hex().required()
3135
+ });
3136
+ const { error } = validation.validate(query);
3137
+ if (error) {
3138
+ import_node_server_utils18.logger.log({ level: "error", message: error.message });
3139
+ next(new import_node_server_utils18.BadRequestError(error.message));
3140
+ return;
3141
+ }
3142
+ const page = parseInt(req.query.page) ?? 1;
3143
+ const limit = parseInt(req.query.limit) ?? 10;
3144
+ const search = req.query.search ?? "";
3145
+ const site = req.params.site ?? "";
3146
+ try {
3147
+ const data = await _getSupplies({
3148
+ page,
3149
+ limit,
3150
+ search,
3151
+ site
3152
+ });
3153
+ res.json(data);
3154
+ return;
3155
+ } catch (error2) {
3156
+ import_node_server_utils18.logger.log({ level: "error", message: error2.message });
3157
+ next(error2);
3158
+ return;
3159
+ }
3160
+ }
3161
+ async function getSupplyById(req, res, next) {
3162
+ const validation = import_joi10.default.string().hex().required();
3163
+ const _id = req.params.id;
3164
+ const { error } = validation.validate(_id);
3165
+ if (error) {
3166
+ import_node_server_utils18.logger.log({ level: "error", message: error.message });
3167
+ next(new import_node_server_utils18.BadRequestError(error.message));
3168
+ return;
3169
+ }
3170
+ try {
3171
+ const data = await _getSupplyById(_id);
3172
+ res.json(data);
3173
+ return;
3174
+ } catch (error2) {
3175
+ import_node_server_utils18.logger.log({ level: "error", message: error2.message });
3176
+ next(error2);
3177
+ return;
3178
+ }
3179
+ }
3180
+ async function updateSupply(req, res, next) {
3181
+ const payload = { id: req.params.id, ...req.body };
3182
+ const validation = import_joi10.default.object({
3183
+ id: import_joi10.default.string().hex().required(),
3184
+ name: import_joi10.default.string().optional().allow("", null),
3185
+ unitOfMeasurement: import_joi10.default.string().optional().allow("", null),
3186
+ qty: import_joi10.default.number().min(0).optional().allow("", null)
3187
+ });
3188
+ const { error } = validation.validate(payload);
3189
+ if (error) {
3190
+ import_node_server_utils18.logger.log({ level: "error", message: error.message });
3191
+ next(new import_node_server_utils18.BadRequestError(error.message));
3192
+ return;
3193
+ }
3194
+ try {
3195
+ const { id, ...value } = payload;
3196
+ await _updateSupply(id, value);
3197
+ res.json({ message: "Supply updated successfully." });
3198
+ return;
3199
+ } catch (error2) {
3200
+ import_node_server_utils18.logger.log({ level: "error", message: error2.message });
3201
+ next(error2);
3202
+ return;
3203
+ }
3204
+ }
3205
+ async function deleteSupply(req, res, next) {
3206
+ const id = req.params.id;
3207
+ const validation = import_joi10.default.object({
3208
+ id: import_joi10.default.string().hex().required()
3209
+ });
3210
+ const { error } = validation.validate({ id });
3211
+ if (error) {
3212
+ import_node_server_utils18.logger.log({ level: "error", message: error.message });
3213
+ next(new import_node_server_utils18.BadRequestError(error.message));
3214
+ return;
3215
+ }
3216
+ try {
3217
+ await _deleteSupply(id);
3218
+ res.json({ message: "Supply deleted successfully." });
3219
+ return;
3220
+ } catch (error2) {
3221
+ import_node_server_utils18.logger.log({ level: "error", message: error2.message });
3222
+ next(error2);
3223
+ return;
3224
+ }
3225
+ }
3226
+ return {
3227
+ createSupply,
3228
+ getSupplies,
3229
+ getSupplyById,
3230
+ updateSupply,
3231
+ deleteSupply
3232
+ };
3233
+ }
3234
+
3235
+ // src/models/hygiene-stock.model.ts
3236
+ var import_node_server_utils19 = require("@iservice365/node-server-utils");
3237
+ var import_joi11 = __toESM(require("joi"));
3097
3238
  var import_mongodb11 = require("mongodb");
3098
- var stockSchema = import_joi10.default.object({
3099
- site: import_joi10.default.string().hex().required(),
3100
- supply: import_joi10.default.string().hex().required(),
3101
- in: import_joi10.default.number().min(0).optional(),
3102
- out: import_joi10.default.number().min(0).optional(),
3103
- balance: import_joi10.default.number().min(0).required(),
3104
- remarks: import_joi10.default.string().optional().allow("", null)
3239
+ var stockSchema = import_joi11.default.object({
3240
+ site: import_joi11.default.string().hex().required(),
3241
+ supply: import_joi11.default.string().hex().required(),
3242
+ in: import_joi11.default.number().min(0).optional(),
3243
+ out: import_joi11.default.number().min(0).optional(),
3244
+ balance: import_joi11.default.number().min(0).required(),
3245
+ remarks: import_joi11.default.string().optional().allow("", null)
3105
3246
  });
3106
3247
  function MStock(value) {
3107
3248
  const { error } = stockSchema.validate(value);
3108
3249
  if (error) {
3109
- import_node_server_utils18.logger.info(`Hygiene Stock Model: ${error.message}`);
3110
- throw new import_node_server_utils18.BadRequestError(error.message);
3250
+ import_node_server_utils19.logger.info(`Hygiene Stock Model: ${error.message}`);
3251
+ throw new import_node_server_utils19.BadRequestError(error.message);
3111
3252
  }
3112
3253
  if (value.site) {
3113
3254
  try {
3114
3255
  value.site = new import_mongodb11.ObjectId(value.site);
3115
3256
  } catch (error2) {
3116
- throw new import_node_server_utils18.BadRequestError("Invalid site ID format.");
3257
+ throw new import_node_server_utils19.BadRequestError("Invalid site ID format.");
3117
3258
  }
3118
3259
  }
3119
3260
  if (value.supply) {
3120
3261
  try {
3121
3262
  value.supply = new import_mongodb11.ObjectId(value.supply);
3122
3263
  } catch (error2) {
3123
- throw new import_node_server_utils18.BadRequestError("Invalid supply ID format.");
3264
+ throw new import_node_server_utils19.BadRequestError("Invalid supply ID format.");
3124
3265
  }
3125
3266
  }
3126
3267
  return {
@@ -3138,15 +3279,18 @@ function MStock(value) {
3138
3279
  }
3139
3280
 
3140
3281
  // src/repositories/hygiene-stock.repository.ts
3141
- var import_node_server_utils19 = require("@iservice365/node-server-utils");
3282
+ var import_mongodb12 = require("mongodb");
3283
+ var import_node_server_utils20 = require("@iservice365/node-server-utils");
3142
3284
  function useStockRepository() {
3143
- const db = import_node_server_utils19.useAtlas.getDb();
3285
+ const db = import_node_server_utils20.useAtlas.getDb();
3144
3286
  if (!db) {
3145
- throw new import_node_server_utils19.InternalServerError("Unable to connect to server.");
3287
+ throw new import_node_server_utils20.InternalServerError("Unable to connect to server.");
3146
3288
  }
3147
3289
  const namespace_collection = "site.supply.stocks";
3290
+ const supply_collection = "site.supplies";
3148
3291
  const collection = db.collection(namespace_collection);
3149
- const { delNamespace } = (0, import_node_server_utils19.useCache)(namespace_collection);
3292
+ const { delNamespace, setCache, getCache } = (0, import_node_server_utils20.useCache)(namespace_collection);
3293
+ const { delNamespace: delSupplyNamespace } = (0, import_node_server_utils20.useCache)(supply_collection);
3150
3294
  async function createIndex() {
3151
3295
  try {
3152
3296
  await collection.createIndexes([
@@ -3156,7 +3300,7 @@ function useStockRepository() {
3156
3300
  { key: { status: 1 } }
3157
3301
  ]);
3158
3302
  } catch (error) {
3159
- throw new import_node_server_utils19.InternalServerError("Failed to create index on hygiene stock.");
3303
+ throw new import_node_server_utils20.InternalServerError("Failed to create index on hygiene stock.");
3160
3304
  }
3161
3305
  }
3162
3306
  async function createStock(value, session) {
@@ -3164,49 +3308,131 @@ function useStockRepository() {
3164
3308
  value = MStock(value);
3165
3309
  const res = await collection.insertOne(value, { session });
3166
3310
  delNamespace().then(() => {
3167
- import_node_server_utils19.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
3311
+ import_node_server_utils20.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
3168
3312
  }).catch((err) => {
3169
- import_node_server_utils19.logger.error(
3313
+ import_node_server_utils20.logger.error(
3170
3314
  `Failed to clear cache for namespace: ${namespace_collection}`,
3171
3315
  err
3172
3316
  );
3173
3317
  });
3318
+ delSupplyNamespace().then(() => {
3319
+ import_node_server_utils20.logger.info(`Cache cleared for namespace: ${supply_collection}`);
3320
+ }).catch((err) => {
3321
+ import_node_server_utils20.logger.error(
3322
+ `Failed to clear cache for namespace: ${supply_collection}`,
3323
+ err
3324
+ );
3325
+ });
3174
3326
  return res.insertedId;
3175
3327
  } catch (error) {
3176
- const isDuplicated = error.message.includes("duplicate");
3177
- if (isDuplicated) {
3178
- throw new import_node_server_utils19.BadRequestError("Stock already exists.");
3179
- }
3328
+ throw error;
3329
+ }
3330
+ }
3331
+ async function getStocksBySupplyId({
3332
+ page = 1,
3333
+ limit = 10,
3334
+ search = "",
3335
+ site,
3336
+ supply
3337
+ }) {
3338
+ page = page > 0 ? page - 1 : 0;
3339
+ const query = {
3340
+ status: { $ne: "deleted" }
3341
+ };
3342
+ const cacheOptions = {
3343
+ page,
3344
+ limit
3345
+ };
3346
+ try {
3347
+ site = new import_mongodb12.ObjectId(site);
3348
+ query.site = site;
3349
+ cacheOptions.site = site.toString();
3350
+ } catch (error) {
3351
+ throw new import_node_server_utils20.BadRequestError("Invalid site ID format.");
3352
+ }
3353
+ try {
3354
+ supply = new import_mongodb12.ObjectId(supply);
3355
+ query.supply = supply;
3356
+ cacheOptions.supply = supply.toString();
3357
+ } catch (error) {
3358
+ throw new import_node_server_utils20.BadRequestError("Invalid supply ID format.");
3359
+ }
3360
+ if (search) {
3361
+ query.$text = { $search: search };
3362
+ cacheOptions.search = search;
3363
+ }
3364
+ const cacheKey = (0, import_node_server_utils20.makeCacheKey)(namespace_collection, cacheOptions);
3365
+ const cachedData = await getCache(cacheKey);
3366
+ if (cachedData) {
3367
+ import_node_server_utils20.logger.info(`Cache hit for key: ${cacheKey}`);
3368
+ return cachedData;
3369
+ }
3370
+ try {
3371
+ const items = await collection.aggregate([
3372
+ { $match: query },
3373
+ {
3374
+ $project: {
3375
+ createdAt: 1,
3376
+ in: 1,
3377
+ out: 1,
3378
+ balance: 1
3379
+ }
3380
+ },
3381
+ { $sort: { _id: 1 } },
3382
+ { $skip: page * limit },
3383
+ { $limit: limit }
3384
+ ]).toArray();
3385
+ const length = await collection.countDocuments(query);
3386
+ const data = (0, import_node_server_utils20.paginate)(items, page, limit, length);
3387
+ setCache(cacheKey, data, 15 * 60).then(() => {
3388
+ import_node_server_utils20.logger.info(`Cache set for key: ${cacheKey}`);
3389
+ }).catch((err) => {
3390
+ import_node_server_utils20.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
3391
+ });
3392
+ return data;
3393
+ } catch (error) {
3180
3394
  throw error;
3181
3395
  }
3182
3396
  }
3183
3397
  return {
3184
3398
  createIndex,
3185
- createStock
3399
+ createStock,
3400
+ getStocksBySupplyId
3186
3401
  };
3187
3402
  }
3188
3403
 
3189
- // src/services/hygiene-supply.service.ts
3190
- function useSupplyService() {
3191
- const { createSupply: _createSupply } = useSupplyRepository();
3192
- const { createStock } = useStockRepository();
3193
- async function createSupply(value) {
3194
- const session = import_node_server_utils20.useAtlas.getClient()?.startSession();
3404
+ // src/services/hygiene-stock.service.ts
3405
+ var import_node_server_utils21 = require("@iservice365/node-server-utils");
3406
+ function useStockService() {
3407
+ const { createStock: _createStock } = useStockRepository();
3408
+ const { getSupplyById, updateSupply } = useSupplyRepository();
3409
+ async function createStock(value, out = false) {
3410
+ const session = import_node_server_utils21.useAtlas.getClient()?.startSession();
3195
3411
  try {
3196
3412
  session?.startTransaction();
3197
- const { qty, site } = value;
3198
- const supply = await _createSupply(value, session);
3199
- const createdSupply = await createStock(
3413
+ const { qty, ...stockData } = value;
3414
+ const supply = await getSupplyById(value.supply, session);
3415
+ if (!supply || supply.qty === void 0) {
3416
+ throw new import_node_server_utils21.NotFoundError("Supply not found.");
3417
+ }
3418
+ const newSupplyQty = out ? supply.qty - qty : supply.qty + qty;
3419
+ if (out && newSupplyQty < 0) {
3420
+ throw new import_node_server_utils21.BadRequestError(
3421
+ `Insufficient stock. Available: ${supply.qty}, Requested: ${qty}`
3422
+ );
3423
+ }
3424
+ await updateSupply(value.supply, { qty: newSupplyQty }, session);
3425
+ const createdStock = await _createStock(
3200
3426
  {
3201
- site,
3202
- supply: supply.toString(),
3203
- in: qty,
3204
- balance: qty
3427
+ ...stockData,
3428
+ in: out ? 0 : qty,
3429
+ out: out ? qty : 0,
3430
+ balance: newSupplyQty
3205
3431
  },
3206
3432
  session
3207
3433
  );
3208
3434
  await session?.commitTransaction();
3209
- return createdSupply;
3435
+ return createdStock;
3210
3436
  } catch (error) {
3211
3437
  await session?.abortTransaction();
3212
3438
  throw error;
@@ -3214,167 +3440,293 @@ function useSupplyService() {
3214
3440
  await session?.endSession();
3215
3441
  }
3216
3442
  }
3217
- return { createSupply };
3443
+ return { createStock };
3218
3444
  }
3219
3445
 
3220
- // src/controllers/hygiene-supply.controller.ts
3221
- var import_node_server_utils21 = require("@iservice365/node-server-utils");
3222
- var import_joi11 = __toESM(require("joi"));
3223
- function useSupplyController() {
3224
- const {
3225
- getSupplies: _getSupplies,
3226
- getSupplyById: _getSupplyById,
3227
- updateSupply: _updateSupply,
3228
- deleteSupply: _deleteSupply
3229
- } = useSupplyRepository();
3230
- const { createSupply: _createSupply } = useSupplyService();
3231
- async function createSupply(req, res, next) {
3446
+ // src/controllers/hygiene-stock.controller.ts
3447
+ var import_node_server_utils22 = require("@iservice365/node-server-utils");
3448
+ var import_joi12 = __toESM(require("joi"));
3449
+ function useStockController() {
3450
+ const { getStocksBySupplyId: _getStocksBySupplyId } = useStockRepository();
3451
+ const { createStock: _createStock } = useStockService();
3452
+ async function createStock(req, res, next) {
3232
3453
  const payload = { ...req.body, ...req.params };
3233
- const { error } = supplySchema.validate(payload);
3454
+ const validation = import_joi12.default.object({
3455
+ site: import_joi12.default.string().hex().required(),
3456
+ supply: import_joi12.default.string().hex().required(),
3457
+ qty: import_joi12.default.number().min(0).required(),
3458
+ remarks: import_joi12.default.string().optional().allow("", null)
3459
+ });
3460
+ const { error } = validation.validate(payload);
3234
3461
  if (error) {
3235
- import_node_server_utils21.logger.log({ level: "error", message: error.message });
3236
- next(new import_node_server_utils21.BadRequestError(error.message));
3462
+ import_node_server_utils22.logger.log({ level: "error", message: error.message });
3463
+ next(new import_node_server_utils22.BadRequestError(error.message));
3237
3464
  return;
3238
3465
  }
3239
3466
  try {
3240
- const id = await _createSupply(payload);
3241
- res.status(201).json({ message: "Supply created successfully.", id });
3467
+ const id = await _createStock(payload);
3468
+ res.status(201).json({ message: "Stock created successfully.", id });
3242
3469
  return;
3243
3470
  } catch (error2) {
3244
- import_node_server_utils21.logger.log({ level: "error", message: error2.message });
3471
+ import_node_server_utils22.logger.log({ level: "error", message: error2.message });
3245
3472
  next(error2);
3246
3473
  return;
3247
3474
  }
3248
3475
  }
3249
- async function getSupplies(req, res, next) {
3476
+ async function getStocksBySupplyId(req, res, next) {
3250
3477
  const query = { ...req.query, ...req.params };
3251
- const validation = import_joi11.default.object({
3252
- page: import_joi11.default.number().min(1).optional().allow("", null),
3253
- limit: import_joi11.default.number().min(1).optional().allow("", null),
3254
- search: import_joi11.default.string().optional().allow("", null),
3255
- site: import_joi11.default.string().hex().required()
3478
+ const validation = import_joi12.default.object({
3479
+ page: import_joi12.default.number().min(1).optional().allow("", null),
3480
+ limit: import_joi12.default.number().min(1).optional().allow("", null),
3481
+ search: import_joi12.default.string().optional().allow("", null),
3482
+ site: import_joi12.default.string().hex().required(),
3483
+ supply: import_joi12.default.string().hex().required()
3256
3484
  });
3257
3485
  const { error } = validation.validate(query);
3258
3486
  if (error) {
3259
- import_node_server_utils21.logger.log({ level: "error", message: error.message });
3260
- next(new import_node_server_utils21.BadRequestError(error.message));
3487
+ import_node_server_utils22.logger.log({ level: "error", message: error.message });
3488
+ next(new import_node_server_utils22.BadRequestError(error.message));
3261
3489
  return;
3262
3490
  }
3263
3491
  const page = parseInt(req.query.page) ?? 1;
3264
- const limit = parseInt(req.query.limit) ?? 20;
3492
+ const limit = parseInt(req.query.limit) ?? 10;
3265
3493
  const search = req.query.search ?? "";
3266
3494
  const site = req.params.site ?? "";
3495
+ const supply = req.params.supply ?? "";
3267
3496
  try {
3268
- const data = await _getSupplies({
3497
+ const data = await _getStocksBySupplyId({
3269
3498
  page,
3270
3499
  limit,
3271
3500
  search,
3272
- site
3501
+ site,
3502
+ supply
3273
3503
  });
3274
3504
  res.json(data);
3275
3505
  return;
3276
3506
  } catch (error2) {
3277
- import_node_server_utils21.logger.log({ level: "error", message: error2.message });
3507
+ import_node_server_utils22.logger.log({ level: "error", message: error2.message });
3278
3508
  next(error2);
3279
3509
  return;
3280
3510
  }
3281
3511
  }
3282
- async function getSupplyById(req, res, next) {
3283
- const validation = import_joi11.default.string().hex().required();
3284
- const _id = req.params.id;
3285
- const { error } = validation.validate(_id);
3286
- if (error) {
3287
- import_node_server_utils21.logger.log({ level: "error", message: error.message });
3288
- next(new import_node_server_utils21.BadRequestError(error.message));
3289
- return;
3512
+ return {
3513
+ createStock,
3514
+ getStocksBySupplyId
3515
+ };
3516
+ }
3517
+
3518
+ // src/models/hygiene-request-item.model.ts
3519
+ var import_node_server_utils23 = require("@iservice365/node-server-utils");
3520
+ var import_joi13 = __toESM(require("joi"));
3521
+ var import_mongodb13 = require("mongodb");
3522
+ var allowedRequestItemStatus = [
3523
+ "pending",
3524
+ "approved",
3525
+ "disapproved"
3526
+ ];
3527
+ var requestItemSchema = import_joi13.default.object({
3528
+ site: import_joi13.default.string().hex().required(),
3529
+ supply: import_joi13.default.string().hex().required(),
3530
+ supplyName: import_joi13.default.string().required(),
3531
+ qty: import_joi13.default.number().min(0).required(),
3532
+ createdBy: import_joi13.default.string().hex().required(),
3533
+ createdByName: import_joi13.default.string().required()
3534
+ });
3535
+ function MRequestItem(value) {
3536
+ const { error } = requestItemSchema.validate(value);
3537
+ if (error) {
3538
+ import_node_server_utils23.logger.info(`Hygiene Request Item Model: ${error.message}`);
3539
+ throw new import_node_server_utils23.BadRequestError(error.message);
3540
+ }
3541
+ if (value.site) {
3542
+ try {
3543
+ value.site = new import_mongodb13.ObjectId(value.site);
3544
+ } catch (error2) {
3545
+ throw new import_node_server_utils23.BadRequestError("Invalid site ID format.");
3290
3546
  }
3547
+ }
3548
+ if (value.supply) {
3291
3549
  try {
3292
- const data = await _getSupplyById(_id);
3293
- res.json(data);
3294
- return;
3550
+ value.supply = new import_mongodb13.ObjectId(value.supply);
3295
3551
  } catch (error2) {
3296
- import_node_server_utils21.logger.log({ level: "error", message: error2.message });
3297
- next(error2);
3298
- return;
3552
+ throw new import_node_server_utils23.BadRequestError("Invalid supply ID format.");
3299
3553
  }
3300
3554
  }
3301
- async function updateSupply(req, res, next) {
3302
- const payload = { id: req.params.id, ...req.body };
3303
- const validation = import_joi11.default.object({
3304
- id: import_joi11.default.string().hex().required(),
3305
- name: import_joi11.default.string().optional().allow("", null),
3306
- unitOfMeasurement: import_joi11.default.string().optional().allow("", null),
3307
- qty: import_joi11.default.number().min(0).optional().allow("", null)
3308
- });
3309
- const { error } = validation.validate(payload);
3310
- if (error) {
3311
- import_node_server_utils21.logger.log({ level: "error", message: error.message });
3312
- next(new import_node_server_utils21.BadRequestError(error.message));
3313
- return;
3555
+ return {
3556
+ site: value.site,
3557
+ supply: value.supply,
3558
+ supplyName: value.supplyName,
3559
+ qty: value.qty,
3560
+ remarks: "",
3561
+ createdBy: value.createdBy,
3562
+ createdByName: value.createdByName,
3563
+ status: "pending",
3564
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3565
+ updatedAt: "",
3566
+ deletedAt: ""
3567
+ };
3568
+ }
3569
+
3570
+ // src/repositories/hygiene-request-item.repository.ts
3571
+ var import_mongodb14 = require("mongodb");
3572
+ var import_node_server_utils24 = require("@iservice365/node-server-utils");
3573
+ function useRequestItemRepository() {
3574
+ const db = import_node_server_utils24.useAtlas.getDb();
3575
+ if (!db) {
3576
+ throw new import_node_server_utils24.InternalServerError("Unable to connect to server.");
3577
+ }
3578
+ const namespace_collection = "site.supply.requests";
3579
+ const collection = db.collection(namespace_collection);
3580
+ const { delNamespace, setCache, getCache } = (0, import_node_server_utils24.useCache)(namespace_collection);
3581
+ async function createIndex() {
3582
+ try {
3583
+ await collection.createIndexes([
3584
+ { key: { site: 1 } },
3585
+ { key: { supply: 1 } },
3586
+ { key: { status: 1 } }
3587
+ ]);
3588
+ } catch (error) {
3589
+ throw new import_node_server_utils24.InternalServerError(
3590
+ "Failed to create index on hygiene request item."
3591
+ );
3314
3592
  }
3593
+ }
3594
+ async function createTextIndex() {
3315
3595
  try {
3316
- const { id, ...value } = payload;
3317
- await _updateSupply(id, value);
3318
- res.json({ message: "Supply updated successfully." });
3319
- return;
3320
- } catch (error2) {
3321
- import_node_server_utils21.logger.log({ level: "error", message: error2.message });
3322
- next(error2);
3323
- return;
3596
+ await collection.createIndex({ supplyName: "text" });
3597
+ } catch (error) {
3598
+ throw new import_node_server_utils24.InternalServerError(
3599
+ "Failed to create text index on hygiene supply."
3600
+ );
3324
3601
  }
3325
3602
  }
3326
- async function deleteSupply(req, res, next) {
3327
- const id = req.params.id;
3328
- const validation = import_joi11.default.object({
3329
- id: import_joi11.default.string().hex().required()
3330
- });
3331
- const { error } = validation.validate({ id });
3332
- if (error) {
3333
- import_node_server_utils21.logger.log({ level: "error", message: error.message });
3334
- next(new import_node_server_utils21.BadRequestError(error.message));
3335
- return;
3603
+ async function createRequestItem(value, session) {
3604
+ try {
3605
+ value = MRequestItem(value);
3606
+ const res = await collection.insertOne(value, { session });
3607
+ delNamespace().then(() => {
3608
+ import_node_server_utils24.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
3609
+ }).catch((err) => {
3610
+ import_node_server_utils24.logger.error(
3611
+ `Failed to clear cache for namespace: ${namespace_collection}`,
3612
+ err
3613
+ );
3614
+ });
3615
+ return res.insertedId;
3616
+ } catch (error) {
3617
+ throw error;
3336
3618
  }
3619
+ }
3620
+ async function getRequestItems({
3621
+ page = 1,
3622
+ limit = 10,
3623
+ search = "",
3624
+ site
3625
+ }) {
3626
+ page = page > 0 ? page - 1 : 0;
3627
+ const query = {
3628
+ status: { $ne: "deleted" }
3629
+ };
3630
+ const cacheOptions = {
3631
+ page,
3632
+ limit
3633
+ };
3337
3634
  try {
3338
- await _deleteSupply(id);
3339
- res.json({ message: "Supply deleted successfully." });
3340
- return;
3341
- } catch (error2) {
3342
- import_node_server_utils21.logger.log({ level: "error", message: error2.message });
3343
- next(error2);
3344
- return;
3635
+ site = new import_mongodb14.ObjectId(site);
3636
+ query.site = site;
3637
+ cacheOptions.site = site.toString();
3638
+ } catch (error) {
3639
+ throw new import_node_server_utils24.BadRequestError("Invalid site ID format.");
3640
+ }
3641
+ if (search) {
3642
+ query.$text = { $search: search };
3643
+ cacheOptions.search = search;
3644
+ }
3645
+ const cacheKey = (0, import_node_server_utils24.makeCacheKey)(namespace_collection, cacheOptions);
3646
+ const cachedData = await getCache(cacheKey);
3647
+ if (cachedData) {
3648
+ import_node_server_utils24.logger.info(`Cache hit for key: ${cacheKey}`);
3649
+ return cachedData;
3650
+ }
3651
+ try {
3652
+ const items = await collection.aggregate([
3653
+ { $match: query },
3654
+ {
3655
+ $project: {
3656
+ createdAt: 1,
3657
+ status: 1
3658
+ }
3659
+ },
3660
+ { $sort: { _id: 1 } },
3661
+ { $skip: page * limit },
3662
+ { $limit: limit }
3663
+ ]).toArray();
3664
+ const length = await collection.countDocuments(query);
3665
+ const data = (0, import_node_server_utils24.paginate)(items, page, limit, length);
3666
+ setCache(cacheKey, data, 15 * 60).then(() => {
3667
+ import_node_server_utils24.logger.info(`Cache set for key: ${cacheKey}`);
3668
+ }).catch((err) => {
3669
+ import_node_server_utils24.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
3670
+ });
3671
+ return data;
3672
+ } catch (error) {
3673
+ throw error;
3345
3674
  }
3346
3675
  }
3347
3676
  return {
3348
- createSupply,
3349
- getSupplies,
3350
- getSupplyById,
3351
- updateSupply,
3352
- deleteSupply
3677
+ createIndex,
3678
+ createTextIndex,
3679
+ createRequestItem,
3680
+ getRequestItems
3353
3681
  };
3354
3682
  }
3355
3683
 
3356
- // src/services/hygiene-stock.service.ts
3357
- var import_node_server_utils22 = require("@iservice365/node-server-utils");
3358
- function useStockService() {
3359
- const { createStock: _createStock } = useStockRepository();
3360
- const { getSupplyById, updateSupply } = useSupplyRepository();
3361
- async function createStock(value) {
3362
- const session = import_node_server_utils22.useAtlas.getClient()?.startSession();
3684
+ // src/services/hygiene-request-item.service.ts
3685
+ var import_node_server_utils25 = require("@iservice365/node-server-utils");
3686
+ var import_core = require("@iservice365/core");
3687
+ function useRequestItemService() {
3688
+ const { createRequestItem: _createRequestItem } = useRequestItemRepository();
3689
+ const { getSupplyById } = useSupplyRepository();
3690
+ const { getUserById } = (0, import_core.useUserRepo)();
3691
+ async function createRequestItem(value) {
3692
+ try {
3693
+ const { supply, createdBy } = value;
3694
+ const supplyData = await getSupplyById(supply);
3695
+ const createdByData = await getUserById(createdBy);
3696
+ const createdRequestItem = await _createRequestItem({
3697
+ ...value,
3698
+ supplyName: supplyData?.name || "",
3699
+ createdByName: createdByData?.name || ""
3700
+ });
3701
+ return createdRequestItem;
3702
+ } catch (error) {
3703
+ throw error;
3704
+ }
3705
+ }
3706
+ async function createRequestItemByBatch(value) {
3707
+ const session = import_node_server_utils25.useAtlas.getClient()?.startSession();
3363
3708
  try {
3364
3709
  session?.startTransaction();
3365
- const { qty, ...stockData } = value;
3366
- const supply = await getSupplyById(value.supply);
3367
- if (!supply || supply.qty === void 0) {
3368
- throw new import_node_server_utils22.NotFoundError("Supply not found.");
3710
+ const { site, createdBy, items } = value;
3711
+ const createdByData = await getUserById(createdBy);
3712
+ const createdRequestItemIds = [];
3713
+ for (const item of items) {
3714
+ const supplyData = await getSupplyById(item.supply, session);
3715
+ const createdId = await _createRequestItem(
3716
+ {
3717
+ site,
3718
+ supply: item.supply,
3719
+ qty: item.qty,
3720
+ supplyName: supplyData?.name || "",
3721
+ createdBy,
3722
+ createdByName: createdByData?.name || ""
3723
+ },
3724
+ session
3725
+ );
3726
+ createdRequestItemIds.push(createdId);
3369
3727
  }
3370
- const newSupplyQty = supply.qty + qty;
3371
- await updateSupply(value.supply, { qty: newSupplyQty }, session);
3372
- const createdStock = await _createStock(
3373
- { ...stockData, in: qty, balance: newSupplyQty },
3374
- session
3375
- );
3376
3728
  await session?.commitTransaction();
3377
- return createdStock;
3729
+ return createdRequestItemIds;
3378
3730
  } catch (error) {
3379
3731
  await session?.abortTransaction();
3380
3732
  throw error;
@@ -3382,40 +3734,125 @@ function useStockService() {
3382
3734
  await session?.endSession();
3383
3735
  }
3384
3736
  }
3385
- return { createStock };
3737
+ return { createRequestItem, createRequestItemByBatch };
3386
3738
  }
3387
3739
 
3388
- // src/controllers/hygiene-stock.controller.ts
3389
- var import_node_server_utils23 = require("@iservice365/node-server-utils");
3390
- var import_joi12 = __toESM(require("joi"));
3391
- function useStockController() {
3392
- const { createStock: _createStock } = useStockService();
3393
- async function createStock(req, res, next) {
3394
- const payload = { ...req.body, ...req.params };
3395
- const validation = import_joi12.default.object({
3396
- site: import_joi12.default.string().hex().required(),
3397
- supply: import_joi12.default.string().hex().required(),
3398
- qty: import_joi12.default.number().min(0).optional(),
3399
- remarks: import_joi12.default.string().optional().allow("", null)
3740
+ // src/controllers/hygiene-request-item.controller.ts
3741
+ var import_node_server_utils26 = require("@iservice365/node-server-utils");
3742
+ var import_joi14 = __toESM(require("joi"));
3743
+ function useRequestItemController() {
3744
+ const { getRequestItems: _getRequestItems } = useRequestItemRepository();
3745
+ const {
3746
+ createRequestItem: _createRequestItem,
3747
+ createRequestItemByBatch: _createRequestItemByBatch
3748
+ } = useRequestItemService();
3749
+ async function createRequestItem(req, res, next) {
3750
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3751
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3752
+ {}
3753
+ ) : {};
3754
+ const createdBy = cookies["user"] || "";
3755
+ const payload = {
3756
+ ...req.body,
3757
+ ...req.params,
3758
+ createdBy
3759
+ };
3760
+ const validation = import_joi14.default.object({
3761
+ site: import_joi14.default.string().hex().required(),
3762
+ supply: import_joi14.default.string().hex().required(),
3763
+ qty: import_joi14.default.number().min(0).required(),
3764
+ createdBy: import_joi14.default.string().hex().required()
3400
3765
  });
3401
3766
  const { error } = validation.validate(payload);
3402
3767
  if (error) {
3403
- import_node_server_utils23.logger.log({ level: "error", message: error.message });
3404
- next(new import_node_server_utils23.BadRequestError(error.message));
3768
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
3769
+ next(new import_node_server_utils26.BadRequestError(error.message));
3405
3770
  return;
3406
3771
  }
3407
3772
  try {
3408
- const id = await _createStock(payload);
3409
- res.status(201).json({ message: "Stock created successfully.", id });
3773
+ const id = await _createRequestItem(payload);
3774
+ res.status(201).json({ message: "Request item created successfully.", id });
3775
+ return;
3776
+ } catch (error2) {
3777
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
3778
+ next(error2);
3779
+ return;
3780
+ }
3781
+ }
3782
+ async function createRequestItemByBatch(req, res, next) {
3783
+ const cookies = req.headers.cookie ? req.headers.cookie.split(";").map((cookie) => cookie.trim().split("=")).reduce(
3784
+ (acc, [key, value]) => ({ ...acc, [key]: value }),
3785
+ {}
3786
+ ) : {};
3787
+ const createdBy = cookies["user"] || "";
3788
+ const payload = {
3789
+ ...req.body,
3790
+ ...req.params,
3791
+ createdBy
3792
+ };
3793
+ const validation = import_joi14.default.object({
3794
+ site: import_joi14.default.string().hex().required(),
3795
+ createdBy: import_joi14.default.string().hex().required(),
3796
+ items: import_joi14.default.array().items(
3797
+ import_joi14.default.object({
3798
+ supply: import_joi14.default.string().hex().required(),
3799
+ qty: import_joi14.default.number().min(0).required()
3800
+ })
3801
+ ).min(1).required()
3802
+ });
3803
+ const { error } = validation.validate(payload);
3804
+ if (error) {
3805
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
3806
+ next(new import_node_server_utils26.BadRequestError(error.message));
3807
+ return;
3808
+ }
3809
+ try {
3810
+ await _createRequestItemByBatch(payload);
3811
+ res.status(201).json({ message: "Request items created successfully." });
3812
+ return;
3813
+ } catch (error2) {
3814
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
3815
+ next(error2);
3816
+ return;
3817
+ }
3818
+ }
3819
+ async function getRequestItems(req, res, next) {
3820
+ const query = { ...req.query, ...req.params };
3821
+ const validation = import_joi14.default.object({
3822
+ page: import_joi14.default.number().min(1).optional().allow("", null),
3823
+ limit: import_joi14.default.number().min(1).optional().allow("", null),
3824
+ search: import_joi14.default.string().optional().allow("", null),
3825
+ site: import_joi14.default.string().hex().required()
3826
+ });
3827
+ const { error } = validation.validate(query);
3828
+ if (error) {
3829
+ import_node_server_utils26.logger.log({ level: "error", message: error.message });
3830
+ next(new import_node_server_utils26.BadRequestError(error.message));
3831
+ return;
3832
+ }
3833
+ const page = parseInt(req.query.page) ?? 1;
3834
+ const limit = parseInt(req.query.limit) ?? 10;
3835
+ const search = req.query.search ?? "";
3836
+ const site = req.params.site ?? "";
3837
+ try {
3838
+ const data = await _getRequestItems({
3839
+ page,
3840
+ limit,
3841
+ search,
3842
+ site
3843
+ });
3844
+ res.json(data);
3410
3845
  return;
3411
3846
  } catch (error2) {
3412
- import_node_server_utils23.logger.log({ level: "error", message: error2.message });
3847
+ import_node_server_utils26.logger.log({ level: "error", message: error2.message });
3413
3848
  next(error2);
3414
3849
  return;
3415
3850
  }
3416
3851
  }
3417
3852
  return {
3418
- createStock
3853
+ createRequestItem,
3854
+ createRequestItemByBatch,
3855
+ getRequestItems
3419
3856
  };
3420
3857
  }
3421
3858
  // Annotate the CommonJS export names for ESM import in node:
@@ -3423,15 +3860,18 @@ function useStockController() {
3423
3860
  MArea,
3424
3861
  MAreaChecklist,
3425
3862
  MParentChecklist,
3863
+ MRequestItem,
3426
3864
  MStock,
3427
3865
  MSupply,
3428
3866
  MUnit,
3429
3867
  allowedChecklistStatus,
3868
+ allowedRequestItemStatus,
3430
3869
  allowedStatus,
3431
3870
  allowedTypes,
3432
3871
  areaChecklistSchema,
3433
3872
  areaSchema,
3434
3873
  parentChecklistSchema,
3874
+ requestItemSchema,
3435
3875
  stockSchema,
3436
3876
  supplySchema,
3437
3877
  unitSchema,
@@ -3443,12 +3883,14 @@ function useStockController() {
3443
3883
  useAreaService,
3444
3884
  useParentChecklistController,
3445
3885
  useParentChecklistRepo,
3886
+ useRequestItemController,
3887
+ useRequestItemRepository,
3888
+ useRequestItemService,
3446
3889
  useStockController,
3447
3890
  useStockRepository,
3448
3891
  useStockService,
3449
3892
  useSupplyController,
3450
3893
  useSupplyRepository,
3451
- useSupplyService,
3452
3894
  useUnitController,
3453
3895
  useUnitRepository,
3454
3896
  useUnitService