@7365admin1/core 3.30.0 → 3.32.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.mjs CHANGED
@@ -36319,7 +36319,6 @@ function usePersonService() {
36319
36319
  }
36320
36320
  return "People added successfully.";
36321
36321
  } catch (error) {
36322
- console.log("error message service", error);
36323
36322
  logger84.error("Error in people service add:", error);
36324
36323
  await session.abortTransaction();
36325
36324
  throw error;
@@ -36476,8 +36475,8 @@ function usePersonService() {
36476
36475
  phoneNumber: person.contact,
36477
36476
  org: person.org.toString(),
36478
36477
  site: person.site.toString(),
36479
- block: person.block ?? void 0,
36480
- level: person.level ?? void 0,
36478
+ block: person.block?.toString() ?? void 0,
36479
+ level: person.level?.toString() ?? void 0,
36481
36480
  unit: person.unit?.toString() ?? void 0,
36482
36481
  nric: person.nric,
36483
36482
  status: "active",
@@ -42321,7 +42320,11 @@ function useBulletinBoardRepo() {
42321
42320
  );
42322
42321
  async function createIndexes() {
42323
42322
  try {
42324
- await collection.createIndexes([{ key: { site: 1, status: 1 } }]);
42323
+ await collection.createIndexes([
42324
+ { key: { site: 1, status: 1, _id: -1 } },
42325
+ { key: { status: 1, startDate: 1 } },
42326
+ { key: { status: 1, endDate: 1 } }
42327
+ ]);
42325
42328
  } catch (error) {
42326
42329
  throw new InternalServerError43("Failed to create index on site.");
42327
42330
  }
@@ -47384,6 +47387,7 @@ function UseAccessManagementRepo() {
47384
47387
  const userType = params.userType;
47385
47388
  const type = params.type;
47386
47389
  const search = params.search;
47390
+ const typeFilter = type.toLowerCase() === "all" ? [] : [{ $eq: ["$type", type] }];
47387
47391
  const query = {
47388
47392
  site: { $in: [site] }
47389
47393
  };
@@ -47410,7 +47414,7 @@ function UseAccessManagementRepo() {
47410
47414
  $lookup: {
47411
47415
  from: "building-levels",
47412
47416
  localField: "_id",
47413
- foreignField: "block",
47417
+ foreignField: "blockId",
47414
47418
  pipeline: [
47415
47419
  { $match: { status: { $ne: "deleted" } } },
47416
47420
  {
@@ -47424,14 +47428,29 @@ function UseAccessManagementRepo() {
47424
47428
  {
47425
47429
  $lookup: {
47426
47430
  from: "access-cards",
47427
- localField: "_id",
47428
- foreignField: "assignedUnit",
47431
+ let: { unit: "$_id" },
47429
47432
  pipeline: [
47430
47433
  {
47431
47434
  $match: {
47432
- isActivated: true,
47433
- userType,
47434
- type
47435
+ $expr: {
47436
+ $and: [
47437
+ {
47438
+ $in: [
47439
+ "$$unit",
47440
+ {
47441
+ $cond: [
47442
+ { $isArray: "$assignedUnit" },
47443
+ "$assignedUnit",
47444
+ ["$assignedUnit"]
47445
+ ]
47446
+ }
47447
+ ]
47448
+ },
47449
+ { $eq: ["$isActivated", true] },
47450
+ { $eq: ["$userType", userType] },
47451
+ ...typeFilter
47452
+ ]
47453
+ }
47435
47454
  }
47436
47455
  },
47437
47456
  {
@@ -47486,7 +47505,7 @@ function UseAccessManagementRepo() {
47486
47505
  {
47487
47506
  $project: {
47488
47507
  _id: 1,
47489
- level: 1,
47508
+ level: "$name",
47490
47509
  units: 1
47491
47510
  }
47492
47511
  }
@@ -47535,10 +47554,11 @@ function UseAccessManagementRepo() {
47535
47554
  },
47536
47555
  {
47537
47556
  $project: {
47538
- name: 1,
47539
- "level.level": 1,
47540
- "level.units.name": 1,
47541
- "level.units.fAccessCards": 1
47557
+ _id: 0,
47558
+ unitId: "$level.units._id",
47559
+ block: "$name",
47560
+ level: "$level.level",
47561
+ unit: "$level.units.name"
47542
47562
  }
47543
47563
  }
47544
47564
  ],
@@ -47549,6 +47569,138 @@ function UseAccessManagementRepo() {
47549
47569
  throw new Error(error.message);
47550
47570
  }
47551
47571
  }
47572
+ async function assignedAccessCardsByUnitRepo(params) {
47573
+ try {
47574
+ const site = new ObjectId97(params.site);
47575
+ const unitId = new ObjectId97(params.unitId);
47576
+ const userType = params.userType;
47577
+ const type = params.type;
47578
+ const search = params.search;
47579
+ const typeFilter = type.toLowerCase() === "all" ? [] : [{ $eq: ["$type", type] }];
47580
+ const searchFilter = search ? [
47581
+ {
47582
+ $or: [
47583
+ { cardNo: { $regex: search.trim(), $options: "i" } },
47584
+ { accessLevel: { $regex: search.trim(), $options: "i" } },
47585
+ { doorName: { $regex: search.trim(), $options: "i" } },
47586
+ { liftName: { $regex: search.trim(), $options: "i" } }
47587
+ ]
47588
+ }
47589
+ ] : [];
47590
+ const result = await collectionName("building-units").aggregate(
47591
+ [
47592
+ {
47593
+ $match: {
47594
+ _id: unitId,
47595
+ site,
47596
+ status: { $ne: "deleted" }
47597
+ }
47598
+ },
47599
+ {
47600
+ $lookup: {
47601
+ from: "building-levels",
47602
+ localField: "level",
47603
+ foreignField: "_id",
47604
+ pipeline: [{ $project: { _id: 1, name: 1 } }],
47605
+ as: "levelInfo"
47606
+ }
47607
+ },
47608
+ {
47609
+ $unwind: {
47610
+ path: "$levelInfo",
47611
+ preserveNullAndEmptyArrays: true
47612
+ }
47613
+ },
47614
+ {
47615
+ $lookup: {
47616
+ from: "buildings",
47617
+ localField: "building",
47618
+ foreignField: "_id",
47619
+ pipeline: [{ $project: { _id: 1, name: 1 } }],
47620
+ as: "buildingInfo"
47621
+ }
47622
+ },
47623
+ {
47624
+ $unwind: {
47625
+ path: "$buildingInfo",
47626
+ preserveNullAndEmptyArrays: true
47627
+ }
47628
+ },
47629
+ {
47630
+ $lookup: {
47631
+ from: "access-cards",
47632
+ let: { unit: "$_id" },
47633
+ pipeline: [
47634
+ {
47635
+ $match: {
47636
+ $expr: {
47637
+ $and: [
47638
+ {
47639
+ $in: [
47640
+ "$$unit",
47641
+ {
47642
+ $cond: [
47643
+ { $isArray: "$assignedUnit" },
47644
+ "$assignedUnit",
47645
+ ["$assignedUnit"]
47646
+ ]
47647
+ }
47648
+ ]
47649
+ },
47650
+ { $eq: ["$site", site] },
47651
+ { $eq: ["$isActivated", true] },
47652
+ { $eq: ["$userType", userType] },
47653
+ ...typeFilter
47654
+ ]
47655
+ },
47656
+ ...searchFilter[0]
47657
+ }
47658
+ },
47659
+ { $sort: { _id: -1 } },
47660
+ {
47661
+ $project: {
47662
+ _id: 1,
47663
+ type: 1,
47664
+ cardNo: 1,
47665
+ accessLevel: 1,
47666
+ accessGroup: 1,
47667
+ accessType: 1,
47668
+ qrData: 1,
47669
+ startDate: 1,
47670
+ endDate: 1,
47671
+ isActivated: 1,
47672
+ isAntiPassBack: 1,
47673
+ isLiftCard: 1,
47674
+ liftAccessLevel: 1,
47675
+ doorName: 1,
47676
+ liftName: 1,
47677
+ replacementStatus: 1,
47678
+ qrTag: 1,
47679
+ qrTagCardNo: 1
47680
+ }
47681
+ }
47682
+ ],
47683
+ as: "accessCards"
47684
+ }
47685
+ },
47686
+ {
47687
+ $project: {
47688
+ _id: 0,
47689
+ unitId: "$_id",
47690
+ block: { $ifNull: ["$buildingInfo.name", "$buildingName"] },
47691
+ level: "$levelInfo.name",
47692
+ unit: "$name",
47693
+ accessCards: 1
47694
+ }
47695
+ }
47696
+ ],
47697
+ { allowDiskUse: true }
47698
+ ).toArray();
47699
+ return result[0] ?? null;
47700
+ } catch (error) {
47701
+ throw new Error(error.message);
47702
+ }
47703
+ }
47552
47704
  async function acknowlegdeCardRepo(params) {
47553
47705
  const session = useAtlas78.getClient()?.startSession();
47554
47706
  try {
@@ -49012,7 +49164,8 @@ function UseAccessManagementRepo() {
49012
49164
  assignees,
49013
49165
  unit,
49014
49166
  type,
49015
- acm_url
49167
+ acm_url,
49168
+ id
49016
49169
  }) {
49017
49170
  const session = useAtlas78.getClient()?.startSession();
49018
49171
  try {
@@ -49027,31 +49180,35 @@ function UseAccessManagementRepo() {
49027
49180
  let availableCards = [];
49028
49181
  let update = [];
49029
49182
  let cards = [];
49030
- availableCards = await collection().aggregate([
49031
- {
49032
- $match: {
49033
- $expr: {
49034
- $and: [
49035
- {
49036
- $in: [
49037
- unit,
49038
- {
49039
- $cond: [
49040
- { $isArray: "$assignedUnit" },
49041
- "$assignedUnit",
49042
- ["$assignedUnit"]
49043
- ]
49044
- }
49045
- ]
49046
- },
49047
- { $eq: ["$userId", null] },
49048
- { $eq: ["$type", type] },
49049
- { $eq: ["$isActivated", true] }
49050
- ]
49183
+ if (id) {
49184
+ availableCards = await collection().find({ _id: new ObjectId97(id) }).toArray();
49185
+ } else {
49186
+ availableCards = await collection().aggregate([
49187
+ {
49188
+ $match: {
49189
+ $expr: {
49190
+ $and: [
49191
+ {
49192
+ $in: [
49193
+ unit,
49194
+ {
49195
+ $cond: [
49196
+ { $isArray: "$assignedUnit" },
49197
+ "$assignedUnit",
49198
+ ["$assignedUnit"]
49199
+ ]
49200
+ }
49201
+ ]
49202
+ },
49203
+ { $eq: ["$userId", null] },
49204
+ { $eq: ["$type", type] },
49205
+ { $eq: ["$isActivated", true] }
49206
+ ]
49207
+ }
49051
49208
  }
49052
49209
  }
49053
- }
49054
- ]).toArray();
49210
+ ]).toArray();
49211
+ }
49055
49212
  if (assignees.length > availableCards.length) {
49056
49213
  throw new Error(`Not enough ${type} cards available.`);
49057
49214
  }
@@ -49107,13 +49264,34 @@ function UseAccessManagementRepo() {
49107
49264
  throw new Error("Command failed, server error.");
49108
49265
  }
49109
49266
  for (const { _id, userId } of update) {
49267
+ const user = userId ? await collectionName("users").findOne(
49268
+ { _id: userId },
49269
+ { projection: { name: 1, email: 1 } }
49270
+ ) : null;
49110
49271
  await collection().updateOne(
49111
49272
  { _id },
49112
49273
  {
49113
- $set: { userId, staffNo: `STAFF-${userId.toString().slice(-10)}` }
49274
+ $set: {
49275
+ userId,
49276
+ staffNo: `STAFF-${userId.toString().slice(-10)}`,
49277
+ userCred: user ? { ...user } : null
49278
+ }
49114
49279
  },
49115
49280
  { session }
49116
49281
  );
49282
+ if (user) {
49283
+ const { _id: userRefId, ...userInfo } = user;
49284
+ await collectionName("access-cards-history").insertOne(
49285
+ {
49286
+ ...userInfo,
49287
+ cardId: _id,
49288
+ userId,
49289
+ createdAt: /* @__PURE__ */ new Date(),
49290
+ type: "assigned"
49291
+ },
49292
+ { session }
49293
+ );
49294
+ }
49117
49295
  }
49118
49296
  await session?.commitTransaction();
49119
49297
  return "Cards assigned successfully.";
@@ -49278,6 +49456,7 @@ function UseAccessManagementRepo() {
49278
49456
  availableAccessCardsRepo,
49279
49457
  userTypeAccessCardsRepo,
49280
49458
  assignedAccessCardsRepo,
49459
+ assignedAccessCardsByUnitRepo,
49281
49460
  acknowlegdeCardRepo,
49282
49461
  accessandLiftCardsRepo,
49283
49462
  replaceCardRepo,
@@ -49329,6 +49508,7 @@ function useAccessManagementSvc() {
49329
49508
  availableAccessCardsRepo,
49330
49509
  userTypeAccessCardsRepo,
49331
49510
  assignedAccessCardsRepo,
49511
+ assignedAccessCardsByUnitRepo,
49332
49512
  acknowlegdeCardRepo,
49333
49513
  accessandLiftCardsRepo,
49334
49514
  replaceCardRepo,
@@ -49503,6 +49683,14 @@ function useAccessManagementSvc() {
49503
49683
  throw new Error(err.message);
49504
49684
  }
49505
49685
  };
49686
+ const assignedAccessCardsByUnitSvc = async (params) => {
49687
+ try {
49688
+ const response = await assignedAccessCardsByUnitRepo({ ...params });
49689
+ return response;
49690
+ } catch (err) {
49691
+ throw new Error(err.message);
49692
+ }
49693
+ };
49506
49694
  const acknowlegdeCardSvc = async (params) => {
49507
49695
  try {
49508
49696
  const response = await acknowlegdeCardRepo({ ...params });
@@ -49718,14 +49906,16 @@ function useAccessManagementSvc() {
49718
49906
  assignees,
49719
49907
  unit,
49720
49908
  type,
49721
- acm_url
49909
+ acm_url,
49910
+ id
49722
49911
  }) => {
49723
49912
  try {
49724
49913
  const response = await assignMultipleCardsRepo({
49725
49914
  assignees,
49726
49915
  unit,
49727
49916
  type,
49728
- acm_url
49917
+ acm_url,
49918
+ id
49729
49919
  });
49730
49920
  return response;
49731
49921
  } catch (err) {
@@ -49819,6 +50009,7 @@ function useAccessManagementSvc() {
49819
50009
  availableAccessCardsSvc,
49820
50010
  userTypeAccessCardsSvc,
49821
50011
  assignedAccessCardsSvc,
50012
+ assignedAccessCardsByUnitSvc,
49822
50013
  acknowlegdeCardSvc,
49823
50014
  accessandLiftCardsSvc,
49824
50015
  replaceCardSvc,
@@ -49868,6 +50059,7 @@ function useAccessManagementController() {
49868
50059
  availableAccessCardsSvc,
49869
50060
  userTypeAccessCardsSvc,
49870
50061
  assignedAccessCardsSvc,
50062
+ assignedAccessCardsByUnitSvc,
49871
50063
  acknowlegdeCardSvc,
49872
50064
  accessandLiftCardsSvc,
49873
50065
  replaceCardSvc,
@@ -50206,6 +50398,47 @@ function useAccessManagementController() {
50206
50398
  });
50207
50399
  }
50208
50400
  };
50401
+ const assignedAccessCardsByUnit = async (req, res) => {
50402
+ try {
50403
+ const {
50404
+ site,
50405
+ unitId,
50406
+ userType,
50407
+ type,
50408
+ search = ""
50409
+ } = req.query;
50410
+ const schema2 = Joi87.object({
50411
+ site: Joi87.string().hex().required(),
50412
+ unitId: Joi87.string().hex().required(),
50413
+ userType: Joi87.string().required(),
50414
+ type: Joi87.string().valid("all", ...Object.values(EAccessCardTypes)).required(),
50415
+ search: Joi87.string().optional().allow("", null)
50416
+ });
50417
+ const { error } = schema2.validate({
50418
+ site,
50419
+ unitId,
50420
+ userType,
50421
+ type,
50422
+ search
50423
+ });
50424
+ if (error) {
50425
+ return res.status(400).json({ message: error.message });
50426
+ }
50427
+ const result = await assignedAccessCardsByUnitSvc({
50428
+ site,
50429
+ unitId,
50430
+ userType,
50431
+ type,
50432
+ search
50433
+ });
50434
+ return res.status(200).json({ message: "Success", data: result });
50435
+ } catch (error) {
50436
+ return res.status(500).json({
50437
+ data: null,
50438
+ message: error.message
50439
+ });
50440
+ }
50441
+ };
50209
50442
  const acknowlegdeCard = async (req, res) => {
50210
50443
  try {
50211
50444
  const { userId, site, cardId } = req.body;
@@ -50850,7 +51083,7 @@ function useAccessManagementController() {
50850
51083
  };
50851
51084
  const assignMultipleCards = async (req, res) => {
50852
51085
  try {
50853
- const { assignees, unit, type, acm_url } = req.body;
51086
+ const { assignees, unit, type, acm_url, id } = req.body;
50854
51087
  const schema2 = Joi87.object({
50855
51088
  assignees: Joi87.array().items(Joi87.string().hex()).required(),
50856
51089
  type: Joi87.string().required(),
@@ -50864,7 +51097,8 @@ function useAccessManagementController() {
50864
51097
  assignees,
50865
51098
  unit,
50866
51099
  type,
50867
- acm_url
51100
+ acm_url,
51101
+ id
50868
51102
  });
50869
51103
  return res.status(200).json({ message: "Success", data: result });
50870
51104
  } catch (error) {
@@ -51045,6 +51279,7 @@ function useAccessManagementController() {
51045
51279
  availableAccessCards,
51046
51280
  userTypeAccessCards,
51047
51281
  assignedAccessCards,
51282
+ assignedAccessCardsByUnit,
51048
51283
  acknowlegdeCard,
51049
51284
  accessandLiftCards,
51050
51285
  replaceCard,
@@ -51474,6 +51709,11 @@ var schemaCreateNfcPatrolLog = Joi89.object({
51474
51709
  startTime: Joi89.string().required(),
51475
51710
  createdBy: Joi89.string().length(24).hex().optional().allow("", null)
51476
51711
  });
51712
+ var schemaSignNfcPatrolLog = Joi89.object({
51713
+ guardName: Joi89.string().required(),
51714
+ guardSignatureFileId: Joi89.string().length(24).hex().required(),
51715
+ signedAt: Joi89.date().optional()
51716
+ });
51477
51717
  var schemaNfcPatrolLog = Joi89.object({
51478
51718
  _id: Joi89.string().length(24).hex().optional().allow(null, ""),
51479
51719
  site: Joi89.string().length(24).hex().required(),
@@ -51512,6 +51752,7 @@ var schemaNfcPatrolLog = Joi89.object({
51512
51752
  skippedRemarks: Joi89.string().required()
51513
51753
  })
51514
51754
  ).min(0).required(),
51755
+ sign: schemaSignNfcPatrolLog.optional(),
51515
51756
  createdBy: Joi89.string().length(24).hex().optional().allow(null, ""),
51516
51757
  createdAt: Joi89.date().optional()
51517
51758
  });
@@ -51547,6 +51788,15 @@ function MNfcPatrolLog(valueArg) {
51547
51788
  throw new BadRequestError149("Invalid route _id format");
51548
51789
  }
51549
51790
  }
51791
+ if (value.sign?.guardSignatureFileId) {
51792
+ try {
51793
+ value.sign.guardSignatureFileId = new ObjectId100(
51794
+ value.sign.guardSignatureFileId
51795
+ );
51796
+ } catch {
51797
+ throw new BadRequestError149("Invalid guardSignatureFileId format");
51798
+ }
51799
+ }
51550
51800
  return {
51551
51801
  _id: value._id ?? new ObjectId100(),
51552
51802
  site: value.site,
@@ -51555,6 +51805,7 @@ function MNfcPatrolLog(valueArg) {
51555
51805
  startDateTime: value.startDateTime,
51556
51806
  endDateTime: value.endDateTime,
51557
51807
  checkPoints: value.checkPoints,
51808
+ sign: value.sign,
51558
51809
  createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
51559
51810
  createdBy: value.createdBy ?? void 0
51560
51811
  };
@@ -52418,25 +52669,13 @@ function useBulletinVideoRepo() {
52418
52669
  }
52419
52670
  async function createIndexes() {
52420
52671
  try {
52421
- await collection.createIndexes([{ key: { site: 1 } }]);
52672
+ await collection.createIndexes([{ key: { site: 1, createdAt: -1 } }]);
52422
52673
  } catch (error) {
52423
52674
  throw new InternalServerError51(
52424
52675
  "Failed to create index on bulletin videos."
52425
52676
  );
52426
52677
  }
52427
52678
  }
52428
- async function createTextIndex() {
52429
- try {
52430
- await collection.createIndex({
52431
- title: "text",
52432
- description: "text"
52433
- });
52434
- } catch (error) {
52435
- throw new InternalServerError51(
52436
- "Failed to create text index on bulletin videos."
52437
- );
52438
- }
52439
- }
52440
52679
  const namespace_collection = "bulletin-videos";
52441
52680
  const collection = db.collection(namespace_collection);
52442
52681
  const { delNamespace, getCache, setCache } = useCache51(namespace_collection);
@@ -52482,26 +52721,16 @@ function useBulletinVideoRepo() {
52482
52721
  startingDate.setUTCHours(0, 0, 0, 0);
52483
52722
  const endingDate = new Date(endDate);
52484
52723
  endingDate.setUTCHours(23, 59, 59, 999);
52485
- const parsedCreatedAt = {
52486
- $dateFromString: {
52487
- dateString: "$createdAt",
52488
- onError: /* @__PURE__ */ new Date(0),
52489
- onNull: /* @__PURE__ */ new Date(0)
52490
- }
52491
- };
52492
52724
  dateExpr = {
52493
- $expr: {
52494
- $and: [
52495
- { $gte: [parsedCreatedAt, startingDate] },
52496
- { $lte: [parsedCreatedAt, endingDate] }
52497
- ]
52725
+ createdAt: {
52726
+ $gte: startingDate.toISOString(),
52727
+ $lte: endingDate.toISOString()
52498
52728
  }
52499
52729
  };
52500
52730
  }
52501
52731
  const query = {
52502
52732
  site,
52503
52733
  status: { $ne: "deleted" },
52504
- ...search && { $text: { $search: search } },
52505
52734
  ...dateExpr
52506
52735
  };
52507
52736
  sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
@@ -52655,8 +52884,7 @@ function useBulletinVideoRepo() {
52655
52884
  getBulletinVideoById,
52656
52885
  updateBulletinVideoById,
52657
52886
  deleteBulletinVideoById,
52658
- createIndexes,
52659
- createTextIndex
52887
+ createIndexes
52660
52888
  };
52661
52889
  }
52662
52890
 
@@ -53033,8 +53261,8 @@ function useStatementOfAccountRepo() {
53033
53261
  async function createIndexes() {
53034
53262
  try {
53035
53263
  await collection.createIndexes([
53036
- { key: { site: 1, status: 1 } },
53037
- { key: { site: 1, unitId: 1, status: 1 } },
53264
+ { key: { site: 1, status: 1, createdAt: -1 } },
53265
+ { key: { site: 1, unitId: 1, status: 1, createdAt: -1 } },
53038
53266
  { key: { createdAt: -1 } }
53039
53267
  ]);
53040
53268
  return `Successfully created indexes for ${namespace_collection}.`;
@@ -53100,12 +53328,7 @@ function useStatementOfAccountRepo() {
53100
53328
  let endDate = new Date(dateTo);
53101
53329
  endDate.setHours(23, 59, 59, 999);
53102
53330
  dateExpr = {
53103
- $expr: {
53104
- $and: [
53105
- { $gte: ["$createdAt", startDate] },
53106
- { $lte: ["$createdAt", endDate] }
53107
- ]
53108
- }
53331
+ createdAt: { $gte: startDate, $lte: endDate }
53109
53332
  };
53110
53333
  }
53111
53334
  const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
@@ -53290,12 +53513,7 @@ function useStatementOfAccountRepo() {
53290
53513
  let endDate = new Date(dateTo);
53291
53514
  endDate.setHours(23, 59, 59, 999);
53292
53515
  dateExpr = {
53293
- $expr: {
53294
- $and: [
53295
- { $gte: ["$createdAt", startDate] },
53296
- { $lte: ["$createdAt", endDate] }
53297
- ]
53298
- }
53516
+ createdAt: { $gte: startDate, $lte: endDate }
53299
53517
  };
53300
53518
  }
53301
53519
  const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
@@ -58237,6 +58455,7 @@ function useNfcPatrolLogRepo() {
58237
58455
  limit = 10,
58238
58456
  site,
58239
58457
  date,
58458
+ type,
58240
58459
  route
58241
58460
  }, session) {
58242
58461
  const pageIndex = page > 0 ? page - 1 : 0;
@@ -58250,7 +58469,18 @@ function useNfcPatrolLogRepo() {
58250
58469
  site: siteId
58251
58470
  };
58252
58471
  if (date) {
58253
- query.date = date;
58472
+ if (type === "month") {
58473
+ const [year, month] = date.split("-").map(Number);
58474
+ const endDay = new Date(year, month, 0).getDate();
58475
+ query.date = {
58476
+ $gte: `${year}-${String(month).padStart(2, "0")}-01`,
58477
+ $lte: `${year}-${String(month).padStart(2, "0")}-${String(
58478
+ endDay
58479
+ ).padStart(2, "0")}`
58480
+ };
58481
+ } else {
58482
+ query.date = date;
58483
+ }
58254
58484
  }
58255
58485
  if (route?._id) {
58256
58486
  query["route._id"] = typeof route._id === "string" ? new ObjectId121(route._id) : route._id;
@@ -58263,13 +58493,17 @@ function useNfcPatrolLogRepo() {
58263
58493
  page: pageIndex,
58264
58494
  limit
58265
58495
  };
58266
- if (date)
58496
+ if (date) {
58267
58497
  cacheOptions.date = date;
58498
+ }
58499
+ if (type) {
58500
+ cacheOptions.type = type;
58501
+ }
58268
58502
  if (route?._id) {
58269
- cacheOptions.routeId = route?._id;
58503
+ cacheOptions.routeId = typeof route._id === "string" ? route._id : route._id.toString();
58270
58504
  }
58271
58505
  if (route?.startTime) {
58272
- cacheOptions.routeStartTime = route?.startTime;
58506
+ cacheOptions.routeStartTime = route.startTime;
58273
58507
  }
58274
58508
  const cacheKey = makeCacheKey58(namespace_collection, cacheOptions);
58275
58509
  const cachedData = await getCache(cacheKey);
@@ -58277,27 +58511,25 @@ function useNfcPatrolLogRepo() {
58277
58511
  logger157.info(`Cache hit for key: ${cacheKey}`);
58278
58512
  return cachedData;
58279
58513
  }
58280
- try {
58281
- const items = await collection.aggregate(
58282
- [
58283
- { $match: query },
58284
- { $sort: { date: -1 } },
58285
- { $skip: pageIndex * limit },
58286
- { $limit: limit }
58287
- ],
58288
- { session }
58289
- ).toArray();
58290
- const length = await collection.countDocuments(query, { session });
58291
- const data = paginate50(items, pageIndex, limit, length);
58292
- setCache(cacheKey, data, 15 * 60).then(() => {
58293
- logger157.info(`Cache set for key: ${cacheKey}`);
58294
- }).catch((err) => {
58295
- logger157.error(`Failed to set cache for key: ${cacheKey}`, err);
58296
- });
58297
- return data;
58298
- } catch (error) {
58299
- throw error;
58300
- }
58514
+ const items = await collection.aggregate(
58515
+ [
58516
+ { $match: query },
58517
+ { $sort: { date: -1 } },
58518
+ { $skip: pageIndex * limit },
58519
+ { $limit: limit }
58520
+ ],
58521
+ { session }
58522
+ ).toArray();
58523
+ const length = await collection.countDocuments(query, {
58524
+ session
58525
+ });
58526
+ const data = paginate50(items, pageIndex, limit, length);
58527
+ setCache(cacheKey, data, 15 * 60).then(() => {
58528
+ logger157.info(`Cache set for key: ${cacheKey}`);
58529
+ }).catch((err) => {
58530
+ logger157.error(`Failed to set cache for key: ${cacheKey}`, err);
58531
+ });
58532
+ return data;
58301
58533
  }
58302
58534
  function delCachedData() {
58303
58535
  delNamespace().then(() => {
@@ -58346,18 +58578,35 @@ function useNfcPatrolLogRepo() {
58346
58578
  delCachedData();
58347
58579
  return res;
58348
58580
  }
58581
+ async function sign(id, value, session) {
58582
+ id = new ObjectId121(id);
58583
+ await collection.updateOne(
58584
+ { _id: id },
58585
+ {
58586
+ $set: {
58587
+ sign: {
58588
+ ...value,
58589
+ signedAt: /* @__PURE__ */ new Date()
58590
+ }
58591
+ }
58592
+ },
58593
+ { session }
58594
+ );
58595
+ }
58349
58596
  return {
58350
58597
  createIndexes,
58351
58598
  add,
58352
58599
  getAllBySite,
58353
58600
  getById,
58354
- updateCheckpoint
58601
+ updateCheckpoint,
58602
+ sign
58355
58603
  };
58356
58604
  }
58357
58605
 
58358
58606
  // src/services/nfc-patrol-log.service.ts
58359
58607
  import {
58360
58608
  BadRequestError as BadRequestError180,
58609
+ NotFoundError as NotFoundError50,
58361
58610
  useAtlas as useAtlas100
58362
58611
  } from "@7365admin1/node-server-utils";
58363
58612
  function useNfcPatrolLogService() {
@@ -58365,7 +58614,8 @@ function useNfcPatrolLogService() {
58365
58614
  add: _add,
58366
58615
  getById,
58367
58616
  updateCheckpoint,
58368
- getAllBySite: _getAllBySite
58617
+ getAllBySite: _getAllBySite,
58618
+ sign: repoSign
58369
58619
  } = useNfcPatrolLogRepo();
58370
58620
  const routeRepo = useNfcPatrolRouteRepo();
58371
58621
  const tagRepo = useNfcPatrolTagRepo();
@@ -58501,9 +58751,26 @@ function useNfcPatrolLogService() {
58501
58751
  await session?.endSession();
58502
58752
  }
58503
58753
  }
58754
+ async function sign(id, value) {
58755
+ const log = await getById(id);
58756
+ if (!log) {
58757
+ throw new NotFoundError50("Patrol log not found.");
58758
+ }
58759
+ const canSign = log.checkPoints.every(
58760
+ (c) => c.status === "Completed" || c.status === "Skipped"
58761
+ );
58762
+ if (!canSign) {
58763
+ throw new BadRequestError180(
58764
+ "All checkpoints must be completed or skipped before signing."
58765
+ );
58766
+ }
58767
+ await repoSign(id, value);
58768
+ return "Successfully signed patrol.";
58769
+ }
58504
58770
  return {
58505
58771
  add,
58506
- completeCheckpoint
58772
+ completeCheckpoint,
58773
+ sign
58507
58774
  };
58508
58775
  }
58509
58776
 
@@ -58514,7 +58781,7 @@ import {
58514
58781
  } from "@7365admin1/node-server-utils";
58515
58782
  import Joi111 from "joi";
58516
58783
  function useNfcPatrolLogController() {
58517
- const { add: _add, completeCheckpoint: _completeCheckpoint } = useNfcPatrolLogService();
58784
+ const { add: _add, completeCheckpoint: _completeCheckpoint, sign: _sign } = useNfcPatrolLogService();
58518
58785
  const { getAllBySite: _getAllBySite, getById: _getById } = useNfcPatrolLogRepo();
58519
58786
  async function add(req, res, next) {
58520
58787
  try {
@@ -58534,17 +58801,16 @@ function useNfcPatrolLogController() {
58534
58801
  }
58535
58802
  async function getAllBySite(req, res, next) {
58536
58803
  const validation = Joi111.object({
58537
- page: Joi111.number().integer().min(1).allow("", null).default(1),
58538
- limit: Joi111.number().integer().min(1).max(100).allow("", null).default(10),
58804
+ page: Joi111.number().integer().min(1).default(1),
58805
+ limit: Joi111.number().integer().min(1).max(100).default(10),
58539
58806
  site: Joi111.string().length(24).hex().required(),
58540
- date: Joi111.string().regex(/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/).required().messages({
58541
- "string.pattern.base": "Date must be in YYYY-MM-DD format (e.g., 2025-12-30)"
58542
- }).required(),
58807
+ date: Joi111.string().pattern(/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/).required().messages({
58808
+ "string.pattern.base": "Date must be in YYYY-MM-DD format (e.g. 2026-07-17)"
58809
+ }),
58810
+ type: Joi111.string().valid("month").optional(),
58543
58811
  route: Joi111.object({
58544
58812
  _id: Joi111.string().length(24).hex().required(),
58545
- startTime: Joi111.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/).messages({
58546
- "string.pattern.base": "Each startTime must be in HH:mm 24-hour format"
58547
- }).required()
58813
+ startTime: Joi111.string().pattern(/^([01]\d|2[0-3]):([0-5]\d)$/).required()
58548
58814
  }).required()
58549
58815
  });
58550
58816
  const query = {
@@ -58606,11 +58872,26 @@ function useNfcPatrolLogController() {
58606
58872
  next(error);
58607
58873
  }
58608
58874
  }
58875
+ async function sign(req, res, next) {
58876
+ try {
58877
+ const value = await schemaSignNfcPatrolLog.validateAsync(req.body);
58878
+ const result = await _sign(
58879
+ req.params.id,
58880
+ value
58881
+ );
58882
+ res.json({
58883
+ message: result
58884
+ });
58885
+ } catch (err) {
58886
+ next(err);
58887
+ }
58888
+ }
58609
58889
  return {
58610
58890
  add,
58611
58891
  getAllBySite,
58612
58892
  completeCheckpoint,
58613
- getLog
58893
+ getLog,
58894
+ sign
58614
58895
  };
58615
58896
  }
58616
58897
 
@@ -64722,7 +65003,7 @@ import {
64722
65003
  logger as logger181,
64723
65004
  getDirectory as getDirectory5,
64724
65005
  BadRequestError as BadRequestError202,
64725
- NotFoundError as NotFoundError52,
65006
+ NotFoundError as NotFoundError53,
64726
65007
  InternalServerError as InternalServerError70,
64727
65008
  useAtlas as useAtlas115,
64728
65009
  hashPassword as hashPassword4
@@ -64853,7 +65134,7 @@ function useVerificationServiceV2() {
64853
65134
  session?.startTransaction();
64854
65135
  const item = await _getByVerificationCode(verificationCode);
64855
65136
  if (!item) {
64856
- throw new NotFoundError52("Verification not found.");
65137
+ throw new NotFoundError53("Verification not found.");
64857
65138
  }
64858
65139
  switch (item.status) {
64859
65140
  case "expired" /* EXPIRED */:
@@ -65091,7 +65372,7 @@ function useVerificationServiceV2() {
65091
65372
  async function resendSignUpVerification(email) {
65092
65373
  const item = await _getPendingVerificationByEmail(email);
65093
65374
  if (!item) {
65094
- throw new NotFoundError52(
65375
+ throw new NotFoundError53(
65095
65376
  "Pending verification not found."
65096
65377
  );
65097
65378
  }
@@ -65411,7 +65692,7 @@ import {
65411
65692
  BadRequestError as BadRequestError205,
65412
65693
  comparePassword as comparePassword3,
65413
65694
  InternalServerError as InternalServerError72,
65414
- NotFoundError as NotFoundError54,
65695
+ NotFoundError as NotFoundError55,
65415
65696
  useCache as useCache68
65416
65697
  } from "@7365admin1/node-server-utils";
65417
65698
  import { v4 as uuidv42 } from "uuid";
@@ -65424,7 +65705,7 @@ import {
65424
65705
  logger as logger183,
65425
65706
  BadRequestError as BadRequestError204,
65426
65707
  paginate as paginate60,
65427
- NotFoundError as NotFoundError53,
65708
+ NotFoundError as NotFoundError54,
65428
65709
  AppError as AppError29,
65429
65710
  useCache as useCache67,
65430
65711
  makeCacheKey as makeCacheKey65,
@@ -65557,7 +65838,7 @@ function useUserRepoV2() {
65557
65838
  ]).toArray();
65558
65839
  const data = results.length > 0 ? results[0] : null;
65559
65840
  if (!data)
65560
- throw new NotFoundError53("User not found.");
65841
+ throw new NotFoundError54("User not found.");
65561
65842
  setCache(cacheKey, data, 15 * 60).then(() => logger183.info(`Cache set for key: ${cacheKey}`)).catch(
65562
65843
  (err) => logger183.error(`Failed to set cache for key: ${cacheKey}`, err)
65563
65844
  );
@@ -65898,7 +66179,7 @@ function useAuthServiceV2() {
65898
66179
  try {
65899
66180
  const user = await getUserByEmail(email);
65900
66181
  if (!user) {
65901
- throw new NotFoundError54(
66182
+ throw new NotFoundError55(
65902
66183
  "Invalid user email. Please check your email and try again."
65903
66184
  );
65904
66185
  }
@@ -65973,7 +66254,7 @@ import {
65973
66254
  comparePassword as comparePassword4,
65974
66255
  hashPassword as hashPassword5,
65975
66256
  InternalServerError as InternalServerError73,
65976
- NotFoundError as NotFoundError55,
66257
+ NotFoundError as NotFoundError56,
65977
66258
  useAtlas as useAtlas117,
65978
66259
  useS3 as useS33
65979
66260
  } from "@7365admin1/node-server-utils";
@@ -66077,14 +66358,14 @@ function useUserServiceV2() {
66077
66358
  try {
66078
66359
  const otpDoc = await _getVerificationById(id);
66079
66360
  if (!otpDoc) {
66080
- throw new NotFoundError55("You are using an invalid reset link.");
66361
+ throw new NotFoundError56("You are using an invalid reset link.");
66081
66362
  }
66082
66363
  if (otpDoc.status === "complete" /* COMPLETE */) {
66083
66364
  throw new BadRequestError206("This link has already been invalidated.");
66084
66365
  }
66085
66366
  const user = await _getUserByEmail(otpDoc.email);
66086
66367
  if (!user) {
66087
- throw new NotFoundError55("User not found.");
66368
+ throw new NotFoundError56("User not found.");
66088
66369
  }
66089
66370
  if (!user._id) {
66090
66371
  throw new InternalServerError73("Invalid user ID.");
@@ -66911,7 +67192,7 @@ function MPost(value) {
66911
67192
  import {
66912
67193
  BadRequestError as BadRequestError212,
66913
67194
  InternalServerError as InternalServerError75,
66914
- NotFoundError as NotFoundError56,
67195
+ NotFoundError as NotFoundError57,
66915
67196
  paginate as paginate61,
66916
67197
  useAtlas as useAtlas119
66917
67198
  } from "@7365admin1/node-server-utils";
@@ -67036,7 +67317,7 @@ function usePostPrelovedRepo() {
67036
67317
  ]).toArray();
67037
67318
  const data = result[0] ?? null;
67038
67319
  if (!data)
67039
- throw new NotFoundError56("Post not found.");
67320
+ throw new NotFoundError57("Post not found.");
67040
67321
  return data;
67041
67322
  } catch (error) {
67042
67323
  throw error;
@@ -67300,7 +67581,7 @@ import { useAtlas as useAtlas121 } from "@7365admin1/node-server-utils";
67300
67581
  import {
67301
67582
  BadRequestError as BadRequestError213,
67302
67583
  InternalServerError as InternalServerError76,
67303
- NotFoundError as NotFoundError57,
67584
+ NotFoundError as NotFoundError58,
67304
67585
  useAtlas as useAtlas120
67305
67586
  } from "@7365admin1/node-server-utils";
67306
67587
  import { ObjectId as ObjectId140 } from "mongodb";
@@ -67386,7 +67667,7 @@ function usePostFavoriteRepo() {
67386
67667
  }
67387
67668
  const result = await collection.findOne({ _id });
67388
67669
  if (!result)
67389
- throw new NotFoundError57("Favorite not found.");
67670
+ throw new NotFoundError58("Favorite not found.");
67390
67671
  return result;
67391
67672
  }
67392
67673
  async function getByPostId(postId) {
@@ -67397,7 +67678,7 @@ function usePostFavoriteRepo() {
67397
67678
  }
67398
67679
  const result = await collection.findOne({ postId });
67399
67680
  if (!result)
67400
- throw new NotFoundError57("Favorite not found.");
67681
+ throw new NotFoundError58("Favorite not found.");
67401
67682
  return result;
67402
67683
  }
67403
67684
  async function updateById(_id, userId, session) {
@@ -67903,7 +68184,7 @@ function MCategoryPreloved(value) {
67903
68184
  import {
67904
68185
  BadRequestError as BadRequestError216,
67905
68186
  InternalServerError as InternalServerError77,
67906
- NotFoundError as NotFoundError58,
68187
+ NotFoundError as NotFoundError59,
67907
68188
  useAtlas as useAtlas123
67908
68189
  } from "@7365admin1/node-server-utils";
67909
68190
  import { ObjectId as ObjectId143 } from "mongodb";
@@ -67946,7 +68227,7 @@ function useCategoryPrelovedRepo() {
67946
68227
  try {
67947
68228
  const data = await collection.findOne({ _id: objectId2 });
67948
68229
  if (!data) {
67949
- throw new NotFoundError58("Category not found.");
68230
+ throw new NotFoundError59("Category not found.");
67950
68231
  }
67951
68232
  return data;
67952
68233
  } catch (error) {
@@ -67975,7 +68256,7 @@ function useCategoryPrelovedRepo() {
67975
68256
  }
67976
68257
  const existing = await collection.findOne({ _id: objectId2 });
67977
68258
  if (!existing)
67978
- throw new NotFoundError58("Category not found.");
68259
+ throw new NotFoundError59("Category not found.");
67979
68260
  const res = await collection.updateOne(
67980
68261
  { _id: objectId2 },
67981
68262
  { $set: { ...value, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } }
@@ -67993,7 +68274,7 @@ function useCategoryPrelovedRepo() {
67993
68274
  }
67994
68275
  const existing = await collection.findOne({ _id: objectId2 });
67995
68276
  if (!existing)
67996
- throw new NotFoundError58("Category not found.");
68277
+ throw new NotFoundError59("Category not found.");
67997
68278
  const res = await collection.deleteOne({ _id: objectId2 });
67998
68279
  if (res.deletedCount === 0)
67999
68280
  throw new InternalServerError77("Unable to delete category.");
@@ -68160,7 +68441,7 @@ function MSubcategoryPreloved(value) {
68160
68441
  import {
68161
68442
  BadRequestError as BadRequestError218,
68162
68443
  InternalServerError as InternalServerError78,
68163
- NotFoundError as NotFoundError59,
68444
+ NotFoundError as NotFoundError60,
68164
68445
  useAtlas as useAtlas124
68165
68446
  } from "@7365admin1/node-server-utils";
68166
68447
  import { ObjectId as ObjectId145 } from "mongodb";
@@ -68211,7 +68492,7 @@ function useSubcategoryPrelovedRepo() {
68211
68492
  try {
68212
68493
  const data = await collection.findOne({ _id: objectId2 });
68213
68494
  if (!data) {
68214
- throw new NotFoundError59("Subcategory not found.");
68495
+ throw new NotFoundError60("Subcategory not found.");
68215
68496
  }
68216
68497
  return data;
68217
68498
  } catch (error) {
@@ -68486,7 +68767,7 @@ function MChatPreloved(value) {
68486
68767
  import {
68487
68768
  BadRequestError as BadRequestError220,
68488
68769
  InternalServerError as InternalServerError79,
68489
- NotFoundError as NotFoundError60,
68770
+ NotFoundError as NotFoundError61,
68490
68771
  useAtlas as useAtlas125
68491
68772
  } from "@7365admin1/node-server-utils";
68492
68773
  import { ObjectId as ObjectId147 } from "mongodb";
@@ -68514,7 +68795,7 @@ function useChatPrelovedRepo() {
68514
68795
  }
68515
68796
  const existing = await collection.findOne({ _id: objectId2 });
68516
68797
  if (!existing)
68517
- throw new NotFoundError60("Chat not found.");
68798
+ throw new NotFoundError61("Chat not found.");
68518
68799
  value.edited = true;
68519
68800
  value.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
68520
68801
  const res = await collection.updateOne({ _id: objectId2 }, { $set: value });
@@ -68531,7 +68812,7 @@ function useChatPrelovedRepo() {
68531
68812
  }
68532
68813
  const existing = await collection.findOne({ _id: objectId2 });
68533
68814
  if (!existing)
68534
- throw new NotFoundError60("Chat not found.");
68815
+ throw new NotFoundError61("Chat not found.");
68535
68816
  const res = await collection.updateOne(
68536
68817
  { _id: objectId2 },
68537
68818
  { $set: { deletedAt: (/* @__PURE__ */ new Date()).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() } }
@@ -69212,7 +69493,7 @@ function MBidPreloved(value) {
69212
69493
  // src/repositories/bid-preloved.repo.ts
69213
69494
  import {
69214
69495
  InternalServerError as InternalServerError82,
69215
- NotFoundError as NotFoundError61,
69496
+ NotFoundError as NotFoundError62,
69216
69497
  useAtlas as useAtlas128
69217
69498
  } from "@7365admin1/node-server-utils";
69218
69499
  import { ObjectId as ObjectId151 } from "mongodb";
@@ -69234,7 +69515,7 @@ function useBidPrelovedRepo() {
69234
69515
  const objectId2 = typeof _id === "string" ? new ObjectId151(_id) : _id;
69235
69516
  const existing = await collection.findOne({ _id: objectId2 });
69236
69517
  if (!existing)
69237
- throw new NotFoundError61("Bid not found.");
69518
+ throw new NotFoundError62("Bid not found.");
69238
69519
  const res = await collection.updateOne(
69239
69520
  { _id: objectId2 },
69240
69521
  { $set: { status, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } }
@@ -69248,7 +69529,7 @@ function useBidPrelovedRepo() {
69248
69529
  _id = new ObjectId151(_id);
69249
69530
  const result = await collection.findOne({ _id });
69250
69531
  if (!result)
69251
- throw new NotFoundError61("Bid not found.");
69532
+ throw new NotFoundError62("Bid not found.");
69252
69533
  return result;
69253
69534
  }
69254
69535
  return { add, getById, updateStatus };
@@ -69529,7 +69810,7 @@ import {
69529
69810
  InternalServerError as InternalServerError84,
69530
69811
  logger as logger197,
69531
69812
  makeCacheKey as makeCacheKey66,
69532
- NotFoundError as NotFoundError62,
69813
+ NotFoundError as NotFoundError63,
69533
69814
  paginate as paginate64,
69534
69815
  useAtlas as useAtlas130,
69535
69816
  useCache as useCache71
@@ -69634,7 +69915,7 @@ function useFormEntryRepo() {
69634
69915
  try {
69635
69916
  const [data] = await collection.aggregate([{ $match: query }]).toArray();
69636
69917
  if (!data) {
69637
- throw new NotFoundError62("Document not found.");
69918
+ throw new NotFoundError63("Document not found.");
69638
69919
  }
69639
69920
  return data;
69640
69921
  } catch (error) {
@@ -69658,11 +69939,11 @@ function useFormEntryRepo() {
69658
69939
  }
69659
69940
  const onlineFormRequest = await collection.findOne({ _id });
69660
69941
  if (!onlineFormRequest) {
69661
- throw new NotFoundError62("Online form not found.");
69942
+ throw new NotFoundError63("Online form not found.");
69662
69943
  }
69663
69944
  const user = await getUserById(onlineFormRequest.userId.toString());
69664
69945
  if (!user || !user._id) {
69665
- throw new NotFoundError62("User not found.");
69946
+ throw new NotFoundError63("User not found.");
69666
69947
  }
69667
69948
  const userId = user._id.toString();
69668
69949
  await NotificationService.onlineFormRequestStatusUpdated({
@@ -72043,6 +72324,7 @@ export {
72043
72324
  schemaPostFavorite,
72044
72325
  schemaServiceProvider,
72045
72326
  schemaServiceProviderBilling,
72327
+ schemaSignNfcPatrolLog,
72046
72328
  schemaSiteCamera,
72047
72329
  schemaSiteFacility,
72048
72330
  schemaSiteFacilityBooking,