@7365admin1/core 2.72.0 → 2.74.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
@@ -3649,6 +3649,51 @@ function useMemberRepo() {
3649
3649
  throw error;
3650
3650
  }
3651
3651
  }
3652
+ async function getByUserIdTypeOrg(user, type, org) {
3653
+ try {
3654
+ user = new ObjectId11(user);
3655
+ } catch {
3656
+ throw new BadRequestError11("Invalid user ID format.");
3657
+ }
3658
+ try {
3659
+ org = new ObjectId11(org);
3660
+ } catch {
3661
+ throw new BadRequestError11("Invalid organization ID format.");
3662
+ }
3663
+ const cacheKey = makeCacheKey6(namespace_collection, {
3664
+ user: user.toString(),
3665
+ type,
3666
+ org: org.toString()
3667
+ });
3668
+ const cachedData = await getCache(cacheKey);
3669
+ if (cachedData) {
3670
+ logger8.info(`Cache hit for key: ${cacheKey}`);
3671
+ return cachedData;
3672
+ }
3673
+ try {
3674
+ const data = await collection.findOne({
3675
+ user,
3676
+ type,
3677
+ org
3678
+ });
3679
+ if (!data) {
3680
+ throw new NotFoundError5("Member not found.");
3681
+ }
3682
+ setCache(cacheKey, data, 15 * 60).then(() => {
3683
+ logger8.info(`Cache set for key: ${cacheKey}`);
3684
+ }).catch((err) => {
3685
+ logger8.error(`Failed to set cache for key: ${cacheKey}`, err);
3686
+ });
3687
+ return data;
3688
+ } catch (error) {
3689
+ if (error instanceof AppError2) {
3690
+ throw error;
3691
+ }
3692
+ throw new InternalServerError6(
3693
+ "Internal server error, failed to retrieve member."
3694
+ );
3695
+ }
3696
+ }
3652
3697
  return {
3653
3698
  createIndex,
3654
3699
  createUniqueIndex,
@@ -3669,7 +3714,8 @@ function useMemberRepo() {
3669
3714
  countUserMembershipById,
3670
3715
  updateRoleById,
3671
3716
  getByRoles,
3672
- updateSiteById
3717
+ updateSiteById,
3718
+ getByUserIdTypeOrg
3673
3719
  };
3674
3720
  }
3675
3721
 
@@ -4147,6 +4193,8 @@ var orgSchema = Joi8.object({
4147
4193
  busInst: Joi8.string().optional().allow("", null),
4148
4194
  status: Joi8.string().optional().allow("", null),
4149
4195
  defaultSite: Joi8.string().hex().optional().allow("", null),
4196
+ terms: Joi8.string().optional().allow("", null),
4197
+ policies: Joi8.string().optional().allow("", null),
4150
4198
  createdAt: Joi8.string().optional().allow("", null),
4151
4199
  updatedAt: Joi8.string().optional().allow("", null),
4152
4200
  deletedAt: Joi8.string().optional().allow("", null)
@@ -4174,6 +4222,8 @@ function MOrg(value) {
4174
4222
  busInst: value.busInst,
4175
4223
  status: value.status || "active",
4176
4224
  defaultSite: value.defaultSite,
4225
+ terms: value.terms ?? "",
4226
+ policies: value.policies ?? "",
4177
4227
  createdAt: value.createdAt || /* @__PURE__ */ new Date(),
4178
4228
  updatedAt: "",
4179
4229
  deletedAt: ""
@@ -4189,6 +4239,7 @@ function useOrgRepo() {
4189
4239
  }
4190
4240
  const namespace_collection = "organizations";
4191
4241
  const collection = db.collection(namespace_collection);
4242
+ const rolesCollection = db.collection("roles");
4192
4243
  const { delNamespace, getCache, setCache } = useCache9(namespace_collection);
4193
4244
  async function createIndex() {
4194
4245
  try {
@@ -4668,6 +4719,26 @@ function useOrgRepo() {
4668
4719
  throw error;
4669
4720
  }
4670
4721
  }
4722
+ async function getAdminOrgForResident() {
4723
+ const role = await rolesCollection.findOne({ type: "admin" });
4724
+ if (!role)
4725
+ throw new NotFoundError7("Admin role not found.");
4726
+ let orgId;
4727
+ try {
4728
+ orgId = new ObjectId15(role.org);
4729
+ } catch {
4730
+ throw new InternalServerError9(
4731
+ "Invalid organization reference in admin role."
4732
+ );
4733
+ }
4734
+ const org = await collection.findOne(
4735
+ { _id: orgId },
4736
+ { projection: { terms: 1, policies: 1, _id: 0 } }
4737
+ );
4738
+ if (!org)
4739
+ throw new NotFoundError7("Organization not found.");
4740
+ return org;
4741
+ }
4671
4742
  return {
4672
4743
  createIndex,
4673
4744
  createTextIndex,
@@ -4682,7 +4753,8 @@ function useOrgRepo() {
4682
4753
  updateStatusById,
4683
4754
  deleteById,
4684
4755
  getOrgsByEmail,
4685
- getOrganizationsWithSubscription
4756
+ getOrganizationsWithSubscription,
4757
+ getAdminOrgForResident
4686
4758
  };
4687
4759
  }
4688
4760
 
@@ -5301,7 +5373,7 @@ function useSiteRepo() {
5301
5373
  try {
5302
5374
  const items = await collection.aggregate([
5303
5375
  ...basePipeline,
5304
- { $project: { _id: 1, name: 1, orgId: 1 } },
5376
+ { $project: { _id: 1, name: 1, orgId: 1, category: 1 } },
5305
5377
  { $skip: page * limit },
5306
5378
  { $limit: limit }
5307
5379
  ]).toArray();
@@ -7933,6 +8005,7 @@ function useMemberController() {
7933
8005
  getAll: _getAll,
7934
8006
  getOrgsByMembership: _getOrgsByMembership,
7935
8007
  getByUserIdType: _getByUserIdType,
8008
+ getByUserIdTypeOrg: _getByUserIdTypeOrg,
7936
8009
  updateMemberStatus: _updateMemberStatus,
7937
8010
  updateStatusByUserId: _updateStatusByUserId,
7938
8011
  updateSiteById: _updateSiteById
@@ -8203,17 +8276,57 @@ function useMemberController() {
8203
8276
  next(error2);
8204
8277
  }
8205
8278
  }
8279
+ async function getByUserIdTypeOrg(req, res, next) {
8280
+ const validation = Joi15.object({
8281
+ id: Joi15.string().hex().required(),
8282
+ type: Joi15.string().required(),
8283
+ org: Joi15.string().hex().required()
8284
+ });
8285
+ const params = {
8286
+ ...req.params,
8287
+ ...req.query
8288
+ };
8289
+ const { error } = validation.validate(params);
8290
+ if (error) {
8291
+ logger21.log({
8292
+ level: "error",
8293
+ message: error.message
8294
+ });
8295
+ next(new BadRequestError30(error.message));
8296
+ return;
8297
+ }
8298
+ const user = req.params.id;
8299
+ const type = req.params.type;
8300
+ const org = req.query.org;
8301
+ try {
8302
+ const data = await _getByUserIdTypeOrg(
8303
+ user,
8304
+ type,
8305
+ org
8306
+ );
8307
+ res.json(data);
8308
+ return;
8309
+ } catch (error2) {
8310
+ logger21.log({
8311
+ level: "error",
8312
+ message: error2.message
8313
+ });
8314
+ next(error2);
8315
+ return;
8316
+ }
8317
+ }
8206
8318
  return {
8207
8319
  createMember,
8208
8320
  getByUserId,
8209
8321
  getByUserIdType,
8210
8322
  getAll,
8323
+ getAllByUser,
8211
8324
  getOrgsByMembership,
8212
8325
  updateMemberStatus,
8213
8326
  updateRoleById,
8214
8327
  createMemberDirect,
8215
8328
  updateSiteById,
8216
- getAllByUser
8329
+ getByUserIdTypeOrg
8217
8330
  };
8218
8331
  }
8219
8332
 
@@ -8783,7 +8896,8 @@ function useOrgController() {
8783
8896
  getAll: _getAll,
8784
8897
  add: _add,
8785
8898
  update: _update,
8786
- getOrgsByEmail: _getOrgsByEmail
8899
+ getOrgsByEmail: _getOrgsByEmail,
8900
+ getAdminOrgForResident: _getAdminOrgForResident
8787
8901
  } = useOrgRepo();
8788
8902
  async function add(req, res, next) {
8789
8903
  const validation = Joi18.object({
@@ -8791,7 +8905,9 @@ function useOrgController() {
8791
8905
  type: Joi18.string().required(),
8792
8906
  nature: Joi18.string().valid(...allowedNatures).required(),
8793
8907
  email: Joi18.string().email().optional().allow("", null),
8794
- contact: Joi18.string().optional().allow("", null)
8908
+ contact: Joi18.string().optional().allow("", null),
8909
+ terms: Joi18.string().optional().allow("", null),
8910
+ policies: Joi18.string().optional().allow("", null)
8795
8911
  });
8796
8912
  const { error } = validation.validate(req.body);
8797
8913
  if (error) {
@@ -8997,7 +9113,9 @@ function useOrgController() {
8997
9113
  type: Joi18.string().optional(),
8998
9114
  nature: Joi18.string().valid(...allowedNatures).optional(),
8999
9115
  email: Joi18.string().email().allow("", null).optional(),
9000
- contact: Joi18.string().allow("", null).optional()
9116
+ contact: Joi18.string().allow("", null).optional(),
9117
+ terms: Joi18.string().optional().allow("", null),
9118
+ policies: Joi18.string().optional().allow("", null)
9001
9119
  });
9002
9120
  const { error } = validation.validate(req.body);
9003
9121
  if (error) {
@@ -9016,6 +9134,15 @@ function useOrgController() {
9016
9134
  next(err);
9017
9135
  }
9018
9136
  }
9137
+ async function getAdminOrgForResident(_req, res, next) {
9138
+ try {
9139
+ const data = await _getAdminOrgForResident();
9140
+ res.status(200).json(data);
9141
+ } catch (error) {
9142
+ logger25.log({ level: "error", message: error.message });
9143
+ next(error);
9144
+ }
9145
+ }
9019
9146
  return {
9020
9147
  add,
9021
9148
  addOnboardingOrg,
@@ -9025,7 +9152,8 @@ function useOrgController() {
9025
9152
  getById,
9026
9153
  getByEmail,
9027
9154
  update,
9028
- getOrgsByEmail
9155
+ getOrgsByEmail,
9156
+ getAdminOrgForResident
9029
9157
  };
9030
9158
  }
9031
9159
 
@@ -14279,7 +14407,8 @@ function MSiteCamera(value) {
14279
14407
  name: value.name ?? "",
14280
14408
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
14281
14409
  updatedAt: value.updatedAt ?? "",
14282
- deletedAt: value.deletedAt ?? ""
14410
+ deletedAt: value.deletedAt ?? "",
14411
+ ANPRSwitches: value.ANPRSwitches ?? void 0
14283
14412
  };
14284
14413
  }
14285
14414
 
@@ -14375,7 +14504,8 @@ var schemaPerson = Joi36.object({
14375
14504
  plateNumber: Joi36.string().optional().allow(null, ""),
14376
14505
  platform: Joi36.string().valid("web", "mobile").optional().allow(null, ""),
14377
14506
  approvedBy: schemaApprover.optional().allow(null, ""),
14378
- countryCode: Joi36.string().optional().allow(null, "")
14507
+ countryCode: Joi36.string().optional().allow(null, ""),
14508
+ callingCode: Joi36.string().optional().allow(null, "")
14379
14509
  });
14380
14510
  var schemaUpdatePerson = Joi36.object({
14381
14511
  _id: Joi36.string().hex().required(),
@@ -14399,7 +14529,8 @@ var schemaUpdatePerson = Joi36.object({
14399
14529
  plateNumber: Joi36.string().optional().allow(null, ""),
14400
14530
  platform: Joi36.string().valid("web", "mobile").optional().allow(null, ""),
14401
14531
  approvedBy: schemaApprover.optional().allow(null, ""),
14402
- countryCode: Joi36.string().optional().allow(null, "")
14532
+ countryCode: Joi36.string().optional().allow(null, ""),
14533
+ callingCode: Joi36.string().optional().allow(null, "")
14403
14534
  });
14404
14535
  function MPerson(value) {
14405
14536
  const { error } = schemaPerson.validate(value);
@@ -14473,6 +14604,7 @@ function MPerson(value) {
14473
14604
  platForm: value.platform ?? "",
14474
14605
  approvedBy: value.approvedBy ?? { id: "", name: "" },
14475
14606
  countryCode: value.countryCode ?? "",
14607
+ callingCode: value.callingCode ?? "",
14476
14608
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
14477
14609
  updatedAt: value.updatedAt,
14478
14610
  deletedAt: value.deletedAt
@@ -15276,6 +15408,7 @@ var VehicleSort = /* @__PURE__ */ ((VehicleSort2) => {
15276
15408
  var OrgNature = /* @__PURE__ */ ((OrgNature2) => {
15277
15409
  OrgNature2["PROPERTY_MANAGEMENT_AGENCY"] = "property_management_agency";
15278
15410
  OrgNature2["SECURITY_AGENCY"] = "security_agency";
15411
+ OrgNature2["REAL_ESTATE_DEVELOPER"] = "real_estate_developer";
15279
15412
  return OrgNature2;
15280
15413
  })(OrgNature || {});
15281
15414
  var ANPRMode = /* @__PURE__ */ ((ANPRMode2) => {
@@ -16404,39 +16537,70 @@ function useDahuaService() {
16404
16537
  loggerDahua.error("checkOutBySiteAndPlate catch error: ", error);
16405
16538
  }
16406
16539
  }
16407
- async function addTransaction(plateNumber2, site, cameraType, onDetected2) {
16540
+ async function addTransaction(plateNumber2, site, cameraType, ANPRSwitches, onDetected2) {
16408
16541
  if (!plateNumber2 || !site)
16409
- return;
16410
- const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16542
+ return null;
16411
16543
  let insert = null;
16412
- if (resident?._id && (cameraType == "entry" || cameraType == "residents")) {
16544
+ if (cameraType == "entry") {
16413
16545
  await checkOutBySiteAndPlate(camera.site, plateNumber2);
16414
- insert = await add({
16415
- site,
16416
- plateNumber: plateNumber2,
16417
- name: resident?.name,
16418
- nric: resident?.nric,
16419
- contact: resident?.phoneNumber,
16420
- block: Number(resident?.block),
16421
- level: resident?.level,
16422
- unit: resident?.unit?.toString(),
16423
- unitName: resident?.unitName,
16424
- type: resident?.category,
16425
- status: "registered" /* REGISTERED */
16426
- // expiredAt: resident?.end,
16427
- }, void 0, true);
16428
- loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16429
- } else if (!resident?._id && (cameraType == "entry" || cameraType == "visitors")) {
16430
- if (!plateNumber2 || !site)
16431
- return;
16546
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16547
+ if (resident?._id) {
16548
+ insert = await add({
16549
+ site,
16550
+ plateNumber: plateNumber2,
16551
+ name: resident?.name,
16552
+ nric: resident?.nric,
16553
+ contact: resident?.phoneNumber,
16554
+ block: Number(resident?.block),
16555
+ level: resident?.level,
16556
+ unit: resident?.unit?.toString(),
16557
+ unitName: resident?.unitName,
16558
+ type: resident?.category,
16559
+ status: "registered" /* REGISTERED */
16560
+ // expiredAt: resident?.end,
16561
+ }, void 0, true);
16562
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16563
+ } else if (ANPRSwitches?.enableUnregistered) {
16564
+ insert = await add({
16565
+ site,
16566
+ plateNumber: plateNumber2,
16567
+ status: "unregistered" /* UNREGISTERED */
16568
+ // expiredAt: resident?.end,
16569
+ }, void 0, true);
16570
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16571
+ }
16572
+ } else if (cameraType == "residents") {
16432
16573
  await checkOutBySiteAndPlate(camera.site, plateNumber2);
16433
- insert = await add({
16434
- site,
16435
- plateNumber: plateNumber2,
16436
- status: "unregistered" /* UNREGISTERED */
16437
- // expiredAt: resident?.end,
16438
- }, void 0, true);
16439
- loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16574
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16575
+ if (resident?._id) {
16576
+ insert = await add({
16577
+ site,
16578
+ plateNumber: plateNumber2,
16579
+ name: resident?.name,
16580
+ nric: resident?.nric,
16581
+ contact: resident?.phoneNumber,
16582
+ block: Number(resident?.block),
16583
+ level: resident?.level,
16584
+ unit: resident?.unit?.toString(),
16585
+ unitName: resident?.unitName,
16586
+ type: resident?.category,
16587
+ status: "registered" /* REGISTERED */
16588
+ // expiredAt: resident?.end,
16589
+ }, void 0, true);
16590
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16591
+ }
16592
+ } else if (cameraType == "visitors" && ANPRSwitches?.enableUnregistered) {
16593
+ await checkOutBySiteAndPlate(camera.site, plateNumber2);
16594
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16595
+ if (!resident?._id) {
16596
+ insert = await add({
16597
+ site,
16598
+ plateNumber: plateNumber2,
16599
+ status: "unregistered" /* UNREGISTERED */
16600
+ // expiredAt: resident?.end,
16601
+ }, void 0, true);
16602
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16603
+ }
16440
16604
  }
16441
16605
  if (insert?._id && insert?.site && onDetected2) {
16442
16606
  onDetected2({ _id: insert?._id, site: insert?.site?.toString(), plateNumber: insert?.plateNumber, cameraDirection: camera?.direction, direction });
@@ -16449,10 +16613,12 @@ function useDahuaService() {
16449
16613
  );
16450
16614
  if ((camera?.direction == "entry" || camera?.direction == "visitors" || camera?.direction == "residents") && plateNumber) {
16451
16615
  try {
16452
- const result = await addTransaction(plateNumber, camera?.site, camera?.direction, onDetected2);
16453
- const transactionId = result?._id;
16454
- currentTransactionId = transactionId?.toString();
16455
- currentSnapshotField = "snapshotEntryImage";
16616
+ const result = await addTransaction(plateNumber, camera?.site, camera?.direction, camera?.ANPRSwitches, onDetected2);
16617
+ if (camera?.ANPRSwitches?.vehicleSnapshot && result?._id) {
16618
+ const transactionId = result?._id;
16619
+ currentTransactionId = transactionId?.toString();
16620
+ currentSnapshotField = "snapshotEntryImage";
16621
+ }
16456
16622
  } catch (error) {
16457
16623
  console.log("failed to create visitor transaction", error);
16458
16624
  loggerDahua.error(
@@ -16462,23 +16628,25 @@ function useDahuaService() {
16462
16628
  }
16463
16629
  } else if (camera?.direction == "exit" && plateNumber) {
16464
16630
  const existingOpenTransaction = await checkOutBySiteAndPlate(camera?.site, plateNumber, onDetected2);
16465
- if (existingOpenTransaction?._id) {
16631
+ if (existingOpenTransaction?._id && camera?.ANPRSwitches?.vehicleSnapshot) {
16466
16632
  currentTransactionId = existingOpenTransaction._id.toString();
16467
16633
  currentSnapshotField = "snapshotExitImage";
16468
16634
  }
16469
16635
  } else if (camera?.direction == "both" && plateNumber) {
16470
16636
  if (direction.toLowerCase() === "leave") {
16471
16637
  const existingOpenTransaction = await checkOutBySiteAndPlate(camera?.site, plateNumber, onDetected2);
16472
- if (existingOpenTransaction?._id) {
16638
+ if (existingOpenTransaction?._id && camera?.ANPRSwitches?.vehicleSnapshot) {
16473
16639
  currentTransactionId = existingOpenTransaction._id.toString();
16474
16640
  currentSnapshotField = "snapshotExitImage";
16475
16641
  }
16476
16642
  } else if (direction.toLowerCase() === "approach") {
16477
16643
  try {
16478
- const result = await addTransaction(plateNumber, camera?.site, "entry", onDetected2);
16479
- const transactionId = result?._id;
16480
- currentTransactionId = transactionId?.toString();
16481
- currentSnapshotField = "snapshotEntryImage";
16644
+ const result = await addTransaction(plateNumber, camera?.site, "entry", camera?.ANPRSwitches, onDetected2);
16645
+ if (camera?.ANPRSwitches?.vehicleSnapshot && result?._id) {
16646
+ const transactionId = result?._id;
16647
+ currentTransactionId = transactionId?.toString();
16648
+ currentSnapshotField = "snapshotEntryImage";
16649
+ }
16482
16650
  } catch (error) {
16483
16651
  console.log("failed to create visitor transaction", error);
16484
16652
  loggerDahua.error(
@@ -16517,7 +16685,7 @@ function useDahuaService() {
16517
16685
  if (plateNumber && UTCData) {
16518
16686
  await processVehicleTransaction(onDetected2);
16519
16687
  }
16520
- } else if (part.includes("Content-Type: image/jpeg")) {
16688
+ } else if (part.includes("Content-Type: image/jpeg") && camera?.ANPRSwitches?.vehicleSnapshot) {
16521
16689
  const [headers, ...imageParts] = part.split("\r\n\r\n");
16522
16690
  const imageChunk = Buffer.from(imageParts.join("\r\n\r\n"), "binary");
16523
16691
  const lengthMatch = headers.match(/Content-Length:\s*(\d+)/i);
@@ -17332,6 +17500,30 @@ function useSiteCameraRepo() {
17332
17500
  $project: {
17333
17501
  siteDetails: 0
17334
17502
  }
17503
+ },
17504
+ {
17505
+ $lookup: {
17506
+ from: "anpr-settings",
17507
+ localField: "site",
17508
+ foreignField: "site",
17509
+ as: "anprSettingsDetails"
17510
+ }
17511
+ },
17512
+ {
17513
+ $unwind: {
17514
+ path: "$anprSettingsDetails",
17515
+ preserveNullAndEmptyArrays: true
17516
+ }
17517
+ },
17518
+ {
17519
+ $addFields: {
17520
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17521
+ }
17522
+ },
17523
+ {
17524
+ $project: {
17525
+ anprSettingsDetails: 0
17526
+ }
17335
17527
  }
17336
17528
  ]).toArray();
17337
17529
  const length = await collection.countDocuments(query);
@@ -17367,9 +17559,29 @@ function useSiteCameraRepo() {
17367
17559
  $addFields: {
17368
17560
  siteName: "$siteDetails.name"
17369
17561
  }
17562
+ },
17563
+ {
17564
+ $lookup: {
17565
+ from: "anpr-settings",
17566
+ localField: "site",
17567
+ foreignField: "site",
17568
+ as: "anprSettingsDetails"
17569
+ }
17570
+ },
17571
+ {
17572
+ $unwind: {
17573
+ path: "$anprSettingsDetails",
17574
+ preserveNullAndEmptyArrays: true
17575
+ }
17576
+ },
17577
+ {
17578
+ $addFields: {
17579
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17580
+ }
17370
17581
  }
17371
17582
  ];
17372
17583
  pipeline.push({ $project: { siteDetails: 0 } });
17584
+ pipeline.push({ $project: { anprSettingsDetails: 0 } });
17373
17585
  if (Object.keys(project).length > 0) {
17374
17586
  pipeline.push({ $project: project });
17375
17587
  }
@@ -17380,6 +17592,62 @@ function useSiteCameraRepo() {
17380
17592
  throw error;
17381
17593
  }
17382
17594
  }
17595
+ async function findMany(query, project = {}) {
17596
+ try {
17597
+ const pipeline = [
17598
+ { $match: query },
17599
+ { $limit: 1 },
17600
+ {
17601
+ $lookup: {
17602
+ from: "sites",
17603
+ localField: "site",
17604
+ foreignField: "_id",
17605
+ as: "siteDetails"
17606
+ }
17607
+ },
17608
+ {
17609
+ $unwind: {
17610
+ path: "$siteDetails",
17611
+ preserveNullAndEmptyArrays: true
17612
+ }
17613
+ },
17614
+ {
17615
+ $addFields: {
17616
+ siteName: "$siteDetails.name"
17617
+ }
17618
+ },
17619
+ {
17620
+ $lookup: {
17621
+ from: "anpr-settings",
17622
+ localField: "site",
17623
+ foreignField: "site",
17624
+ as: "anprSettingsDetails"
17625
+ }
17626
+ },
17627
+ {
17628
+ $unwind: {
17629
+ path: "$anprSettingsDetails",
17630
+ preserveNullAndEmptyArrays: true
17631
+ }
17632
+ },
17633
+ {
17634
+ $addFields: {
17635
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17636
+ }
17637
+ }
17638
+ ];
17639
+ pipeline.push({ $project: { siteDetails: 0 } });
17640
+ pipeline.push({ $project: { anprSettingsDetails: 0 } });
17641
+ if (Object.keys(project).length > 0) {
17642
+ pipeline.push({ $project: project });
17643
+ }
17644
+ const result = await collection.aggregate(pipeline).toArray();
17645
+ return result.length > 0 ? result : [];
17646
+ } catch (error) {
17647
+ console.error("Error in findOne aggregation:", error);
17648
+ throw error;
17649
+ }
17650
+ }
17383
17651
  return {
17384
17652
  createIndexes,
17385
17653
  add,
@@ -39380,6 +39648,32 @@ function UseAccessManagementRepo() {
39380
39648
  throw new Error(error.message);
39381
39649
  }
39382
39650
  }
39651
+ async function qrCodeListRepo({ type, search, site, page, limit, isLift, userId }) {
39652
+ try {
39653
+ page = page ? page - 1 : 0;
39654
+ let defaultQuery = {};
39655
+ let searchQuery = {};
39656
+ site = new ObjectId92(site);
39657
+ userId = new ObjectId92(userId);
39658
+ if (search) {
39659
+ searchQuery = {
39660
+ $or: [{ fullName: { $regex: search, $options: "i" } }, { cardNo: { $regex: search, $options: "i" } }]
39661
+ };
39662
+ }
39663
+ defaultQuery = { site, isLiftCard: isLift, userId, userType: { $in: ["Visitor/Resident", "Resident/Tenant"] } };
39664
+ const result = collection().aggregate([
39665
+ {
39666
+ $match: { ...defaultQuery, ...searchQuery }
39667
+ },
39668
+ { $sort: { _id: -1 } },
39669
+ { $skip: page * limit },
39670
+ { $limit: limit }
39671
+ ]).toArray();
39672
+ return result;
39673
+ } catch (error) {
39674
+ throw new Error(error.message);
39675
+ }
39676
+ }
39383
39677
  return {
39384
39678
  createIndexes,
39385
39679
  createIndexForEntrypass,
@@ -39418,7 +39712,8 @@ function UseAccessManagementRepo() {
39418
39712
  uploadTemplateRepo,
39419
39713
  getResidentsRepo,
39420
39714
  userAccessCardsRepo,
39421
- removeTemplateRepo
39715
+ removeTemplateRepo,
39716
+ qrCodeListRepo
39422
39717
  };
39423
39718
  }
39424
39719
 
@@ -39465,7 +39760,8 @@ function useAccessManagementSvc() {
39465
39760
  uploadTemplateRepo,
39466
39761
  getResidentsRepo,
39467
39762
  userAccessCardsRepo,
39468
- removeTemplateRepo
39763
+ removeTemplateRepo,
39764
+ qrCodeListRepo
39469
39765
  } = UseAccessManagementRepo();
39470
39766
  const addPhysicalCardSvc = async (payload) => {
39471
39767
  try {
@@ -39851,6 +40147,14 @@ function useAccessManagementSvc() {
39851
40147
  throw new Error(err.message);
39852
40148
  }
39853
40149
  };
40150
+ const qrCodeListSvc = async ({ type, search, site, page, limit, isLift, userId }) => {
40151
+ try {
40152
+ const response = await qrCodeListRepo({ type, search, site, page, limit, isLift, userId });
40153
+ return response;
40154
+ } catch (err) {
40155
+ throw new Error(err.message);
40156
+ }
40157
+ };
39854
40158
  return {
39855
40159
  addPhysicalCardSvc,
39856
40160
  addNonPhysicalCardSvc,
@@ -39892,7 +40196,8 @@ function useAccessManagementSvc() {
39892
40196
  uploadTemplateSvc,
39893
40197
  getResidentsSvc,
39894
40198
  userAccessCardsSvc,
39895
- removeTemplateSvc
40199
+ removeTemplateSvc,
40200
+ qrCodeListSvc
39896
40201
  };
39897
40202
  }
39898
40203
 
@@ -39939,7 +40244,8 @@ function useAccessManagementController() {
39939
40244
  uploadTemplateSvc,
39940
40245
  getResidentsSvc,
39941
40246
  userAccessCardsSvc,
39942
- removeTemplateSvc
40247
+ removeTemplateSvc,
40248
+ qrCodeListSvc
39943
40249
  } = useAccessManagementSvc();
39944
40250
  const addPhysicalCard = async (req, res) => {
39945
40251
  try {
@@ -41008,6 +41314,47 @@ function useAccessManagementController() {
41008
41314
  });
41009
41315
  }
41010
41316
  };
41317
+ const qrCodeList = async (req, res) => {
41318
+ try {
41319
+ const {
41320
+ type,
41321
+ site,
41322
+ page,
41323
+ limit = 10,
41324
+ search = "",
41325
+ isLift,
41326
+ userId
41327
+ } = req.query;
41328
+ const schema2 = Joi87.object({
41329
+ type: Joi87.string().required(),
41330
+ site: Joi87.string().hex().required(),
41331
+ page: Joi87.number().optional().default(1),
41332
+ limit: Joi87.number().optional().default(10),
41333
+ search: Joi87.string().optional().allow("", null),
41334
+ isLift: Joi87.boolean().optional().default(false),
41335
+ userId: Joi87.string().required()
41336
+ });
41337
+ const { error } = schema2.validate({ type, site, page, limit, search, isLift, userId });
41338
+ if (error) {
41339
+ return res.status(400).json({ message: error.message });
41340
+ }
41341
+ const result = await qrCodeListSvc({
41342
+ type,
41343
+ site,
41344
+ page: Number(page),
41345
+ limit: Number(limit),
41346
+ search,
41347
+ isLift: Boolean(isLift),
41348
+ userId
41349
+ });
41350
+ return res.status(200).json({ data: result });
41351
+ } catch (error) {
41352
+ return res.status(400).json({
41353
+ data: null,
41354
+ message: error.message
41355
+ });
41356
+ }
41357
+ };
41011
41358
  return {
41012
41359
  addPhysicalCard,
41013
41360
  addNonPhysicalCard,
@@ -41047,7 +41394,8 @@ function useAccessManagementController() {
41047
41394
  uploadTemplate,
41048
41395
  getResidents,
41049
41396
  userAccessCards,
41050
- removeTemplate
41397
+ removeTemplate,
41398
+ qrCodeList
41051
41399
  };
41052
41400
  }
41053
41401
 
@@ -55538,7 +55886,8 @@ function usePostPrelovedRepo() {
55538
55886
  site,
55539
55887
  status,
55540
55888
  category,
55541
- subcategory
55889
+ subcategory,
55890
+ userId
55542
55891
  }, session) {
55543
55892
  page = page > 0 ? page - 1 : 0;
55544
55893
  if (site) {
@@ -55581,7 +55930,34 @@ function usePostPrelovedRepo() {
55581
55930
  ...categoryId && { category: categoryId },
55582
55931
  ...subcategoryIds && { subcategory: { $in: subcategoryIds } }
55583
55932
  };
55933
+ let userObjectId = null;
55934
+ if (userId) {
55935
+ try {
55936
+ userObjectId = new ObjectId132(userId);
55937
+ } catch {
55938
+ throw new BadRequestError212("Invalid user ID format.");
55939
+ }
55940
+ }
55584
55941
  const sortObj = buildSortObj(filter);
55942
+ const FAVORITE_COUNT_LOOKUP = {
55943
+ $lookup: {
55944
+ from: "post-favorites",
55945
+ localField: "_id",
55946
+ foreignField: "postId",
55947
+ pipeline: [{ $project: { userIds: 1 } }],
55948
+ as: "favoriteData"
55949
+ }
55950
+ };
55951
+ const favoriteUserIds = {
55952
+ $ifNull: [{ $arrayElemAt: ["$favoriteData.userIds", 0] }, []]
55953
+ };
55954
+ const FAVORITE_COUNT_ADD_FIELD = {
55955
+ $addFields: {
55956
+ favoriteCount: { $size: favoriteUserIds },
55957
+ isFavorited: userObjectId ? { $in: [userObjectId, favoriteUserIds] } : false
55958
+ }
55959
+ };
55960
+ const FAVORITE_COUNT_UNSET = { $unset: "favoriteData" };
55585
55961
  try {
55586
55962
  const items = await collection.aggregate(
55587
55963
  [
@@ -55589,6 +55965,9 @@ function usePostPrelovedRepo() {
55589
55965
  USER_LOOKUP,
55590
55966
  USER_UNWIND,
55591
55967
  CATEGORY_LOOKUP,
55968
+ FAVORITE_COUNT_LOOKUP,
55969
+ FAVORITE_COUNT_ADD_FIELD,
55970
+ FAVORITE_COUNT_UNSET,
55592
55971
  { $sort: sortObj },
55593
55972
  { $skip: page * limit },
55594
55973
  { $limit: limit }
@@ -55741,7 +56120,8 @@ function usePostPrelovedController() {
55741
56120
  Joi134.string().valid(...Object.values(PostStatus))
55742
56121
  ).optional().allow(null),
55743
56122
  category: Joi134.string().hex().length(24).optional().allow("", null),
55744
- subcategory: Joi134.alternatives().try(Joi134.array().items(Joi134.string())).optional().allow(null, "")
56123
+ subcategory: Joi134.alternatives().try(Joi134.array().items(Joi134.string())).optional().allow(null, ""),
56124
+ userId: Joi134.string().optional().allow("", null)
55745
56125
  });
55746
56126
  const { error, value } = validation.validate(req.query, {
55747
56127
  abortEarly: false
@@ -55752,7 +56132,17 @@ function usePostPrelovedController() {
55752
56132
  next(new BadRequestError213(messages));
55753
56133
  return;
55754
56134
  }
55755
- const { page, limit, search, filter, site, status, category, subcategory } = value;
56135
+ const {
56136
+ page,
56137
+ limit,
56138
+ search,
56139
+ filter,
56140
+ site,
56141
+ status,
56142
+ category,
56143
+ subcategory,
56144
+ userId
56145
+ } = value;
55756
56146
  try {
55757
56147
  const data = await _getAll({
55758
56148
  page,
@@ -55762,7 +56152,8 @@ function usePostPrelovedController() {
55762
56152
  site,
55763
56153
  status: status ? Array.isArray(status) ? status : [status] : void 0,
55764
56154
  category: category ?? void 0,
55765
- subcategory: subcategory ? Array.isArray(subcategory) ? subcategory : [subcategory] : void 0
56155
+ subcategory: subcategory ? Array.isArray(subcategory) ? subcategory : [subcategory] : void 0,
56156
+ userId
55766
56157
  });
55767
56158
  res.status(200).json(data);
55768
56159
  return;
@@ -56120,7 +56511,7 @@ function MCategoryPreloved(value) {
56120
56511
  name: value.name ?? "",
56121
56512
  createdBy: value.createdBy ?? "",
56122
56513
  site: value.site ?? null,
56123
- createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
56514
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
56124
56515
  updatedAt: value.updatedAt ?? null
56125
56516
  };
56126
56517
  }
@@ -56180,14 +56571,26 @@ function useCategoryPrelovedRepo() {
56180
56571
  throw error;
56181
56572
  }
56182
56573
  }
56183
- return { getAll, getById };
56574
+ async function addCategory(item, session) {
56575
+ const doc = MCategoryPreloved(item);
56576
+ try {
56577
+ const res = await collection.insertOne(doc, { session });
56578
+ return res.insertedId;
56579
+ } catch (error) {
56580
+ const isDuplicated = error.message?.includes("duplicate");
56581
+ if (isDuplicated)
56582
+ throw new BadRequestError216("Category already exists.");
56583
+ throw error;
56584
+ }
56585
+ }
56586
+ return { getAll, getById, addCategory };
56184
56587
  }
56185
56588
 
56186
56589
  // src/controllers/category-preloved.controller.ts
56187
56590
  import { BadRequestError as BadRequestError217, logger as logger190 } from "@7365admin1/node-server-utils";
56188
56591
  import Joi138 from "joi";
56189
56592
  function useCategoryPrelovedController() {
56190
- const { getAll: _getAll, getById: _getById } = useCategoryPrelovedRepo();
56593
+ const { getAll: _getAll, getById: _getById, addCategory: _addCategory } = useCategoryPrelovedRepo();
56191
56594
  async function getAll(req, res, next) {
56192
56595
  const schema2 = Joi138.object({
56193
56596
  search: Joi138.string().optional().allow("", null),
@@ -56230,7 +56633,25 @@ function useCategoryPrelovedController() {
56230
56633
  return;
56231
56634
  }
56232
56635
  }
56233
- return { getAll, getById };
56636
+ async function addCategory(req, res, next) {
56637
+ const { error, value } = schemaCategoryPreloved.validate(req.body, {
56638
+ abortEarly: false
56639
+ });
56640
+ if (error) {
56641
+ const messages = error.details.map((d) => d.message).join(", ");
56642
+ logger190.log({ level: "error", message: messages });
56643
+ next(new BadRequestError217(messages));
56644
+ return;
56645
+ }
56646
+ try {
56647
+ const data = await _addCategory(value);
56648
+ res.status(201).json(data);
56649
+ } catch (error2) {
56650
+ logger190.log({ level: "error", message: error2.message });
56651
+ next(error2);
56652
+ }
56653
+ }
56654
+ return { getAll, getById, addCategory };
56234
56655
  }
56235
56656
 
56236
56657
  // src/models/subcategory-preloved.model.ts
@@ -56411,6 +56832,11 @@ var FormEntryStatus = /* @__PURE__ */ ((FormEntryStatus2) => {
56411
56832
  var schemaFormEntry = Joi141.object({
56412
56833
  _id: Joi141.string().hex().optional().allow("", null),
56413
56834
  formType: Joi141.string().required(),
56835
+ block: Joi141.string().optional().allow(null, ""),
56836
+ level: Joi141.string().optional().allow(null, ""),
56837
+ unit: Joi141.string().optional().allow(null, ""),
56838
+ name: Joi141.string().optional().allow(null, ""),
56839
+ phoneNumber: Joi141.string().optional().allow(null, ""),
56414
56840
  fields: Joi141.object().pattern(
56415
56841
  Joi141.string(),
56416
56842
  Joi141.alternatives().try(
@@ -56572,15 +56998,22 @@ function useFormEntryController() {
56572
56998
  }
56573
56999
  const headerRow = worksheet.getRow(1);
56574
57000
  const headers = headerRow.values.slice(1).map((h) => String(h ?? "").trim());
57001
+ const knownKeys = ["block", "level", "unit", "name", "phoneNumber"];
57002
+ const topLevel = {};
56575
57003
  const fields = {};
56576
57004
  headers.forEach((header) => {
56577
- fields[header] = null;
57005
+ const normalized = toCamelCase(header);
57006
+ if (knownKeys.includes(normalized)) {
57007
+ topLevel[normalized] = null;
57008
+ } else {
57009
+ fields[normalized] = null;
57010
+ }
56578
57011
  });
56579
57012
  const formType = req.file.originalname.replace(/\.[^/.]+$/, "");
56580
- const normalizedFields = normalizeKeys(fields);
56581
57013
  const payload = {
56582
57014
  formType,
56583
- fields: normalizedFields,
57015
+ ...topLevel,
57016
+ fields,
56584
57017
  status: "active" /* ACTIVE */
56585
57018
  };
56586
57019
  const { error, value } = schemaFormEntry.validate(payload, {