@7365admin1/core 2.76.0 → 2.77.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
@@ -3737,6 +3737,20 @@ function useMemberRepo() {
3737
3737
  { $sort: { _id: -1 } },
3738
3738
  { $skip: page * limit },
3739
3739
  { $limit: limit },
3740
+ {
3741
+ $lookup: {
3742
+ from: "organizations",
3743
+ localField: "org",
3744
+ foreignField: "_id",
3745
+ as: "orgData"
3746
+ }
3747
+ },
3748
+ {
3749
+ $unwind: {
3750
+ path: "$orgData",
3751
+ preserveNullAndEmptyArrays: true
3752
+ }
3753
+ },
3740
3754
  {
3741
3755
  $lookup: {
3742
3756
  from: "organizations",
@@ -3756,7 +3770,16 @@ function useMemberRepo() {
3756
3770
  _id: "$org",
3757
3771
  text: { $first: "$orgName" },
3758
3772
  value: { $first: "$org" },
3759
- defaultSite: { $first: "$defaultSite.defaultSite" }
3773
+ defaultSite: { $first: "$defaultSite.defaultSite" },
3774
+ onboardingRequired: {
3775
+ $first: "$orgData.onboardingRequired"
3776
+ },
3777
+ onboardingCompleted: {
3778
+ $first: "$orgData.onboardingCompleted"
3779
+ },
3780
+ onboardingCompletedAt: {
3781
+ $first: "$orgData.onboardingCompletedAt"
3782
+ }
3760
3783
  }
3761
3784
  },
3762
3785
  {
@@ -3764,15 +3787,16 @@ function useMemberRepo() {
3764
3787
  _id: 0,
3765
3788
  text: 1,
3766
3789
  value: 1,
3767
- defaultSite: 1
3790
+ defaultSite: 1,
3791
+ onboardingRequired: 1,
3792
+ onboardingCompleted: 1,
3793
+ onboardingCompletedAt: 1
3768
3794
  }
3769
3795
  }
3770
3796
  ]).toArray();
3771
3797
  const length = await collection.distinct("org", query).then((orgs) => orgs.length);
3772
3798
  const data = (0, import_node_server_utils12.paginate)(items, page, limit, length);
3773
- setCache(cacheKey, data, 15 * 60).then(() => {
3774
- import_node_server_utils12.logger.info(`Cache set for key: ${cacheKey}`);
3775
- }).catch((err) => {
3799
+ setCache(cacheKey, data, 15 * 60).catch((err) => {
3776
3800
  import_node_server_utils12.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
3777
3801
  });
3778
3802
  return data;
@@ -4620,6 +4644,9 @@ var orgSchema = import_joi8.default.object({
4620
4644
  busInst: import_joi8.default.string().optional().allow("", null),
4621
4645
  status: import_joi8.default.string().optional().allow("", null),
4622
4646
  defaultSite: import_joi8.default.string().hex().optional().allow("", null),
4647
+ onboardingRequired: import_joi8.default.boolean().optional(),
4648
+ onboardingCompleted: import_joi8.default.boolean().optional(),
4649
+ onboardingCompletedAt: import_joi8.default.date().optional().allow(null),
4623
4650
  terms: import_joi8.default.string().optional().allow("", null),
4624
4651
  policies: import_joi8.default.string().optional().allow("", null),
4625
4652
  createdAt: import_joi8.default.string().optional().allow("", null),
@@ -4649,6 +4676,9 @@ function MOrg(value) {
4649
4676
  busInst: value.busInst,
4650
4677
  status: value.status || "active",
4651
4678
  defaultSite: value.defaultSite,
4679
+ onboardingRequired: value.onboardingRequired || false,
4680
+ onboardingCompleted: value.onboardingCompleted || false,
4681
+ onboardingCompletedAt: value.onboardingCompletedAt || null,
4652
4682
  terms: value.terms ?? "",
4653
4683
  policies: value.policies ?? "",
4654
4684
  createdAt: value.createdAt || /* @__PURE__ */ new Date(),
@@ -9350,7 +9380,7 @@ function useOrgController() {
9350
9380
  return;
9351
9381
  }
9352
9382
  try {
9353
- const _id = await _add(req.body);
9383
+ const _id = await _add({ ...req.body, onboardingRequired: true, onboardingCompleted: false, onboardingCompletedAt: null });
9354
9384
  const data = await _getById(_id);
9355
9385
  res.status(201).json({
9356
9386
  message: "Successfully created organization.",
@@ -15639,10 +15669,10 @@ var import_node_server_utils71 = require("@7365admin1/node-server-utils");
15639
15669
  var import_node_server_utils70 = require("@7365admin1/node-server-utils");
15640
15670
  var import_joi38 = __toESM(require("joi"));
15641
15671
  var import_mongodb41 = require("mongodb");
15642
- var VehicleType = /* @__PURE__ */ ((VehicleType2) => {
15643
- VehicleType2["WHITELIST"] = "whitelist";
15644
- VehicleType2["BLOCKLIST"] = "blocklist";
15645
- return VehicleType2;
15672
+ var VehicleType = /* @__PURE__ */ ((VehicleType3) => {
15673
+ VehicleType3["WHITELIST"] = "whitelist";
15674
+ VehicleType3["BLOCKLIST"] = "blocklist";
15675
+ return VehicleType3;
15646
15676
  })(VehicleType || {});
15647
15677
  var VehicleCategory = /* @__PURE__ */ ((VehicleCategory2) => {
15648
15678
  VehicleCategory2["RESIDENT"] = "resident";
@@ -16702,6 +16732,77 @@ function useDahuaDigest({
16702
16732
  streaming
16703
16733
  });
16704
16734
  }
16735
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
16736
+ function isDahuaInvalidAuthority(value) {
16737
+ const text = String(value || "").toLowerCase();
16738
+ return text.includes("invalid authority");
16739
+ }
16740
+ function getDahuaResponseText(response) {
16741
+ return response?.data?.toString?.("utf-8") ?? "";
16742
+ }
16743
+ function getDahuaStatusCode(response) {
16744
+ return response?.statusCode || response?.status || response?.res?.status;
16745
+ }
16746
+ async function useDahuaDigestWithRetry({
16747
+ host,
16748
+ username,
16749
+ password,
16750
+ endpoint,
16751
+ method = "GET",
16752
+ headers = {},
16753
+ timeout = 1e4,
16754
+ streaming = false,
16755
+ retries = 3,
16756
+ retryDelayMs = 0
16757
+ }) {
16758
+ let lastError;
16759
+ for (let attempt = 1; attempt <= retries; attempt++) {
16760
+ try {
16761
+ const response = await useDahuaDigest({
16762
+ host,
16763
+ username,
16764
+ password,
16765
+ endpoint,
16766
+ method,
16767
+ headers,
16768
+ timeout,
16769
+ streaming
16770
+ });
16771
+ const text = getDahuaResponseText(response);
16772
+ const statusCode = getDahuaStatusCode(response);
16773
+ const isOk = statusCode === 200 && text.includes("OK");
16774
+ if (isOk) {
16775
+ return response;
16776
+ }
16777
+ const shouldRetry = isDahuaInvalidAuthority(text);
16778
+ if (shouldRetry && attempt < retries) {
16779
+ loggerDahua.warn(
16780
+ `[${host}] Dahua Invalid Authority. Retrying ${attempt}/${retries}`
16781
+ );
16782
+ if (retryDelayMs > 0) {
16783
+ await sleep(retryDelayMs);
16784
+ }
16785
+ continue;
16786
+ }
16787
+ throw new Error(`Dahua response: ${text || `HTTP ${statusCode}`}`);
16788
+ } catch (error) {
16789
+ lastError = error;
16790
+ const message = error?.message || String(error);
16791
+ const shouldRetry = isDahuaInvalidAuthority(message);
16792
+ if (shouldRetry && attempt < retries) {
16793
+ loggerDahua.warn(
16794
+ `[${host}] Dahua Invalid Authority error. Retrying ${attempt}/${retries}`
16795
+ );
16796
+ if (retryDelayMs > 0) {
16797
+ await sleep(retryDelayMs);
16798
+ }
16799
+ continue;
16800
+ }
16801
+ throw error;
16802
+ }
16803
+ }
16804
+ throw lastError;
16805
+ }
16705
16806
  function createFileNameFromEvent(utcSeconds, utcMilliseconds) {
16706
16807
  const date = new Date(utcSeconds * 1e3 + utcMilliseconds);
16707
16808
  const year = date.getUTCFullYear();
@@ -17352,6 +17453,50 @@ function useDahuaService() {
17352
17453
  );
17353
17454
  }
17354
17455
  }
17456
+ async function openBarrier(value) {
17457
+ const validation = import_joi40.default.object({
17458
+ host: import_joi40.default.string().required(),
17459
+ username: import_joi40.default.string().required(),
17460
+ password: import_joi40.default.string().required(),
17461
+ plateNumber: import_joi40.default.string().required(),
17462
+ channel: import_joi40.default.number().integer().min(1).default(1)
17463
+ });
17464
+ const { error, value: payload } = validation.validate(value, {
17465
+ stripUnknown: true
17466
+ });
17467
+ if (error) {
17468
+ throw new import_node_server_utils72.BadRequestError(`Validation error: ${error.message}`);
17469
+ }
17470
+ try {
17471
+ const query = new URLSearchParams({
17472
+ action: "openStrobe",
17473
+ channel: String(payload.channel),
17474
+ "info.openType": "Normal",
17475
+ "info.plateNumber": payload.plateNumber || "VISITOR"
17476
+ });
17477
+ const endpoint = `/cgi-bin/trafficSnap.cgi?${query.toString()}`;
17478
+ const response = await useDahuaDigestWithRetry({
17479
+ host: payload.host,
17480
+ username: payload.username,
17481
+ password: payload.password,
17482
+ endpoint,
17483
+ retries: 10,
17484
+ retryDelayMs: 0
17485
+ });
17486
+ const text = response?.data?.toString?.("utf-8") ?? "";
17487
+ if (!text.includes("OK")) {
17488
+ throw new Error(`Failed to open barrier. Dahua response: ${text}`);
17489
+ }
17490
+ return {
17491
+ success: true,
17492
+ message: "Barrier opened successfully",
17493
+ raw: text
17494
+ };
17495
+ } catch (error2) {
17496
+ loggerDahua.error(`[${value.host}] Error opening barrier:`, error2);
17497
+ throw error2;
17498
+ }
17499
+ }
17355
17500
  return {
17356
17501
  getSnapshot,
17357
17502
  listenToCamera,
@@ -17359,7 +17504,8 @@ function useDahuaService() {
17359
17504
  removePlateNumber,
17360
17505
  updatePlateNumber,
17361
17506
  getPlateNumber,
17362
- bulkInsertPlateNumber
17507
+ bulkInsertPlateNumber,
17508
+ openBarrier
17363
17509
  };
17364
17510
  }
17365
17511
 
@@ -17566,6 +17712,43 @@ function useSiteCameraRepo() {
17566
17712
  throw new import_node_server_utils73.BadRequestError("Failed to retrieve site cameras.");
17567
17713
  }
17568
17714
  }
17715
+ async function getVisitorsInBySite(site) {
17716
+ try {
17717
+ const pipeline = [
17718
+ { $match: { site: (0, import_node_server_utils73.toObjectId)(site), type: "anpr", status: "active", direction: { $in: ["visitors", "entry", "both"] } } },
17719
+ { $limit: 1 },
17720
+ {
17721
+ $lookup: {
17722
+ from: "anpr-settings",
17723
+ localField: "site",
17724
+ foreignField: "site",
17725
+ as: "anprSettingsDetails"
17726
+ }
17727
+ },
17728
+ {
17729
+ $unwind: {
17730
+ path: "$anprSettingsDetails",
17731
+ preserveNullAndEmptyArrays: true
17732
+ }
17733
+ },
17734
+ {
17735
+ $addFields: {
17736
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17737
+ }
17738
+ },
17739
+ {
17740
+ $project: { anprSettingsDetails: 0 }
17741
+ }
17742
+ ];
17743
+ const cameras = await collection.aggregate(pipeline).toArray();
17744
+ return cameras?.find((cam) => cam.direction === "visitors" || cam.direction === "entry" || cam.direction === "both");
17745
+ } catch (error) {
17746
+ if (error instanceof import_node_server_utils73.BadRequestError) {
17747
+ throw error;
17748
+ }
17749
+ throw new import_node_server_utils73.BadRequestError("Failed to retrieve site cameras.");
17750
+ }
17751
+ }
17569
17752
  async function getBySiteGuardPost(site, guardPost) {
17570
17753
  try {
17571
17754
  site = new import_mongodb43.ObjectId(site);
@@ -17920,6 +18103,7 @@ function useSiteCameraRepo() {
17920
18103
  getAll,
17921
18104
  findSiteCameras,
17922
18105
  getBySite,
18106
+ getVisitorsInBySite,
17923
18107
  getBySites,
17924
18108
  delCachedData,
17925
18109
  getBySiteGuardPost,
@@ -26114,13 +26298,14 @@ function useVisitorTransactionService() {
26114
26298
  getByNRIC,
26115
26299
  updateById: _updateById
26116
26300
  } = usePersonRepo();
26117
- const { getBySite: _getBySite } = useSiteCameraRepo();
26301
+ const { getBySite: _getBySite, getVisitorsInBySite: _getVisitorsInBySite } = useSiteCameraRepo();
26118
26302
  const { getSiteById: _getSiteById } = useSiteRepo();
26119
26303
  const {
26120
26304
  addPlateNumber: _addPlateNumber,
26121
26305
  removePlateNumber: _removePlateNumber,
26122
26306
  getPlateNumber: _getPlateNumber,
26123
- updatePlateNumber: _updatePlateNumber
26307
+ updatePlateNumber: _updatePlateNumber,
26308
+ openBarrier: _openBarrier
26124
26309
  } = useDahuaService();
26125
26310
  const { getAllSites: _getAllSites } = useSiteRepo();
26126
26311
  const { getByUserId: _getByUserId } = usePersonRepo();
@@ -26196,28 +26381,30 @@ function useVisitorTransactionService() {
26196
26381
  "contractor" /* CONTRACTOR */,
26197
26382
  "walk-in" /* WALK_IN */,
26198
26383
  "guest" /* GUEST */,
26199
- "delivery" /* DELIVERY */,
26200
- "pick-up" /* PICK_UP */
26384
+ "delivery" /* DELIVERY */
26385
+ // PersonTypes.PICK_UP,
26201
26386
  ];
26202
26387
  const start = value.checkIn ? new Date(value.checkIn) : /* @__PURE__ */ new Date();
26203
26388
  try {
26204
26389
  session?.startTransaction();
26205
26390
  let camera;
26206
- let site;
26207
- if (value.site) {
26208
- [camera, site] = await Promise.all([
26209
- _getBySite(value.site, { type: "anpr" /* ANPR */ }),
26210
- _getSiteById(value.site)
26211
- ]);
26391
+ if (value.site && value.plateNumber) {
26392
+ try {
26393
+ camera = await _getVisitorsInBySite(value.site);
26394
+ if (!camera) {
26395
+ import_node_server_utils106.logger.warn(`No camera document found for site: ${value.site}`);
26396
+ }
26397
+ } catch (error) {
26398
+ import_node_server_utils106.logger.error(
26399
+ `Error _getVisitorsInBySite camera for site ${value.site}:`,
26400
+ error
26401
+ );
26402
+ }
26212
26403
  }
26213
26404
  if (!value.unitName && value.unit) {
26214
26405
  const unit = await _getUnitById(value.unit);
26215
26406
  value.unitName = unit?.name;
26216
26407
  }
26217
- const hourExpiration = site?.dahuaTimeExpiration ? site?.dahuaTimeExpiration : 24 * 60;
26218
- const end = value.checkOut ? new Date(value.checkOut) : new Date(start.getTime() + hourExpiration * 60 * 1e3);
26219
- const startDahuaDate = formatDahuaDate(start);
26220
- const endDahuaDate = formatDahuaDate(end);
26221
26408
  if (allowedPersonTypes.includes(value?.type)) {
26222
26409
  const nric = value?.nric || "";
26223
26410
  const person = await getByNRIC(nric);
@@ -26254,7 +26441,7 @@ function useVisitorTransactionService() {
26254
26441
  block,
26255
26442
  level,
26256
26443
  unit,
26257
- site: site2,
26444
+ site,
26258
26445
  org,
26259
26446
  type,
26260
26447
  company,
@@ -26310,14 +26497,14 @@ function useVisitorTransactionService() {
26310
26497
  level,
26311
26498
  unit,
26312
26499
  unitName,
26313
- site: site2,
26500
+ site,
26314
26501
  org,
26315
26502
  type,
26316
26503
  company,
26317
26504
  remarks,
26318
26505
  contractorType,
26319
26506
  checkIn: start,
26320
- expiredAt: end,
26507
+ // expiredAt: end,
26321
26508
  visitorPass: visitorPass ?? [],
26322
26509
  passKeys: passKeys ?? [],
26323
26510
  status: "registered" /* REGISTERED */
@@ -26328,11 +26515,13 @@ function useVisitorTransactionService() {
26328
26515
  );
26329
26516
  }
26330
26517
  }
26518
+ let host;
26519
+ let username;
26520
+ let password;
26331
26521
  if (camera && value.plateNumber && camera.host && camera.username && camera.password) {
26332
- const host = camera.host;
26333
- const username = camera.username;
26334
- const password = camera.password;
26335
- const redlist = "TrafficRedList" /* TRAFFIC_REDLIST */;
26522
+ host = camera.host;
26523
+ username = camera.username;
26524
+ password = camera.password;
26336
26525
  const blacklist = "TrafficBlackList" /* TRAFFIC_BLACKLIST */;
26337
26526
  const _plateNumber = value.plateNumber;
26338
26527
  const dahuaBlocklistQuery = {
@@ -26348,74 +26537,6 @@ function useVisitorTransactionService() {
26348
26537
  const found = foundMatch ? Number(foundMatch[1]) : 0;
26349
26538
  if (found === 1)
26350
26539
  throw new import_node_server_utils106.BadRequestError("This plate number is blocklisted");
26351
- const dahuaQuery = {
26352
- host,
26353
- username,
26354
- password,
26355
- plateNumber: _plateNumber,
26356
- mode: redlist
26357
- };
26358
- const raw = await _getPlateNumber(dahuaQuery);
26359
- const parsed = parseDahuaFind(raw);
26360
- if (!parsed.exists) {
26361
- const dahuaPayload = {
26362
- host,
26363
- username,
26364
- password,
26365
- plateNumber: _plateNumber,
26366
- mode: redlist,
26367
- start: startDahuaDate,
26368
- end: endDahuaDate,
26369
- owner: value.name ?? "",
26370
- isOpenGate: site?.isOpenGate ?? true
26371
- };
26372
- const dahuaResponse = await _addPlateNumber(dahuaPayload);
26373
- if (dahuaResponse?.statusCode !== 200) {
26374
- throw new import_node_server_utils106.BadRequestError(
26375
- `Failed to add plate number to ANPR whitelist`
26376
- );
26377
- }
26378
- const responseData = dahuaResponse?.data?.toString("utf-8") ?? "";
26379
- value.recNo = responseData.split("=")[1]?.trim();
26380
- value.checkIn = start;
26381
- value.expiredAt = end;
26382
- const vehiclePayload = {
26383
- name: value.name ?? "",
26384
- category: value.type,
26385
- org: value.org,
26386
- site: value.site,
26387
- plateNumber: value.plateNumber,
26388
- type: "whitelist" /* WHITELIST */,
26389
- nric: value.nric,
26390
- start,
26391
- end,
26392
- recNo: value.recNo,
26393
- ...value.block && { block: value.block },
26394
- ...value.level && { level: value.level },
26395
- ...value.unit && { unit: value.unit }
26396
- };
26397
- await addVehicle(vehiclePayload);
26398
- } else {
26399
- const dahuaPayload = {
26400
- host,
26401
- username,
26402
- password,
26403
- plateNumber: _plateNumber,
26404
- recno: parsed.recNo,
26405
- mode: redlist,
26406
- start: startDahuaDate,
26407
- end: endDahuaDate,
26408
- owner: value.name ?? "",
26409
- isOpenGate: site?.isOpenGate ?? true
26410
- };
26411
- const dahuaResponse = await _updatePlateNumber(dahuaPayload);
26412
- if (dahuaResponse?.statusCode !== 200) {
26413
- throw new import_node_server_utils106.BadRequestError(
26414
- `Failed to update plate number to ANPR ${"whitelist" /* WHITELIST */}`
26415
- );
26416
- }
26417
- value.recNo = parsed.recNo;
26418
- }
26419
26540
  }
26420
26541
  if (value.visitorPass && Array.isArray(value.visitorPass) && value.visitorPass.length > 0 && value.visitorPass) {
26421
26542
  for (const vp of value.visitorPass) {
@@ -26453,6 +26574,27 @@ function useVisitorTransactionService() {
26453
26574
  }
26454
26575
  const result = await _add(value, session);
26455
26576
  await session?.commitTransaction();
26577
+ let openBarrier = null;
26578
+ const isOpenBarrier = allowedPersonTypes.includes(value?.type) || camera?.ANPRSwitches?.openBarrierPickUpDropOff == true;
26579
+ if (isOpenBarrier && value.plateNumber && host && username && password) {
26580
+ try {
26581
+ import_node_server_utils106.logger.info(`Attempting to open barrier at host: ${host}`);
26582
+ openBarrier = await _openBarrier({
26583
+ host,
26584
+ username,
26585
+ password,
26586
+ plateNumber: value?.plateNumber
26587
+ });
26588
+ import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
26589
+ } catch (error) {
26590
+ import_node_server_utils106.logger.error(
26591
+ `Failed to open barrier at host ${host}. Critical system error:`,
26592
+ error
26593
+ );
26594
+ openBarrier = { success: false, error: error?.message };
26595
+ }
26596
+ }
26597
+ console.log("Open barrier response:", openBarrier);
26456
26598
  return result;
26457
26599
  } catch (error) {
26458
26600
  await session?.abortTransaction();
@@ -26465,6 +26607,43 @@ function useVisitorTransactionService() {
26465
26607
  const session = import_node_server_utils106.useAtlas.getClient()?.startSession();
26466
26608
  session?.startTransaction();
26467
26609
  try {
26610
+ let camera;
26611
+ let host;
26612
+ let username;
26613
+ let password;
26614
+ if (value.site && value.plateNumber) {
26615
+ try {
26616
+ camera = await _getVisitorsInBySite(value.site);
26617
+ if (!camera) {
26618
+ import_node_server_utils106.logger.warn(`No camera document found for site: ${value.site}`);
26619
+ }
26620
+ } catch (error) {
26621
+ import_node_server_utils106.logger.error(
26622
+ `Error _getVisitorsInBySite camera for site ${value.site}:`,
26623
+ error
26624
+ );
26625
+ }
26626
+ }
26627
+ if (camera && value.plateNumber && camera.host && camera.username && camera.password) {
26628
+ host = camera.host;
26629
+ username = camera.username;
26630
+ password = camera.password;
26631
+ const blacklist = "TrafficBlackList" /* TRAFFIC_BLACKLIST */;
26632
+ const _plateNumber = value.plateNumber;
26633
+ const dahuaBlocklistQuery = {
26634
+ host,
26635
+ username,
26636
+ password,
26637
+ plateNumber: _plateNumber,
26638
+ mode: blacklist
26639
+ };
26640
+ const isBlocklistedRaw = await _getPlateNumber(dahuaBlocklistQuery);
26641
+ const rawString = isBlocklistedRaw?.toString?.("utf-8") ?? String(isBlocklistedRaw);
26642
+ const foundMatch = rawString.match(/found=(\d+)/);
26643
+ const found = foundMatch ? Number(foundMatch[1]) : 0;
26644
+ if (found === 1)
26645
+ throw new import_node_server_utils106.BadRequestError("This plate number is blocklisted");
26646
+ }
26468
26647
  if (Array.isArray(value.visitorPass) && value.visitorPass.length > 0) {
26469
26648
  const keptVisitorPass = [];
26470
26649
  for (const vp of value.visitorPass) {
@@ -26528,6 +26707,34 @@ function useVisitorTransactionService() {
26528
26707
  value.unitName = unit?.name;
26529
26708
  }
26530
26709
  await _updateVisitorTansactionById(id, value, session);
26710
+ const allowedPersonTypes = [
26711
+ "contractor" /* CONTRACTOR */,
26712
+ "walk-in" /* WALK_IN */,
26713
+ "guest" /* GUEST */,
26714
+ "delivery" /* DELIVERY */
26715
+ // PersonTypes.PICK_UP,
26716
+ ];
26717
+ let openBarrier = null;
26718
+ const isOpenBarrier = allowedPersonTypes.includes(value?.type) || camera?.ANPRSwitches?.openBarrierPickUpDropOff == true;
26719
+ if (isOpenBarrier && value.plateNumber && host && username && password) {
26720
+ try {
26721
+ import_node_server_utils106.logger.info(`Attempting to open barrier at host: ${host}`);
26722
+ openBarrier = await _openBarrier({
26723
+ host,
26724
+ username,
26725
+ password,
26726
+ plateNumber: value?.plateNumber
26727
+ });
26728
+ import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
26729
+ } catch (error) {
26730
+ import_node_server_utils106.logger.error(
26731
+ `Failed to open barrier at host ${host}. Critical system error:`,
26732
+ error
26733
+ );
26734
+ openBarrier = { success: false, error: error?.message };
26735
+ }
26736
+ }
26737
+ console.log("Open barrier response:", openBarrier);
26531
26738
  await session?.commitTransaction();
26532
26739
  return "Successfully updated visitor transaction.";
26533
26740
  } catch (error) {
@@ -49447,7 +49654,7 @@ function filterByStatus(attendance, shiftData, timezone, format2, status) {
49447
49654
  }
49448
49655
  });
49449
49656
  }
49450
- function sleep(ms) {
49657
+ function sleep2(ms) {
49451
49658
  return new Promise((resolve) => setTimeout(resolve, ms));
49452
49659
  }
49453
49660
  async function fetchSites({ siteUrl, token }) {
@@ -49474,7 +49681,7 @@ async function fetchSites({ siteUrl, token }) {
49474
49681
  }
49475
49682
  if (attempt < maxRetries) {
49476
49683
  const delay = 1e3 * attempt;
49477
- await sleep(delay);
49684
+ await sleep2(delay);
49478
49685
  }
49479
49686
  }
49480
49687
  } while (attempt < maxRetries);
@@ -55925,7 +56132,7 @@ function usePostPrelovedController() {
55925
56132
  import_joi134.default.string().valid(...Object.values(PostStatus))
55926
56133
  ).optional().allow(null),
55927
56134
  category: import_joi134.default.string().hex().length(24).optional().allow("", null),
55928
- subcategory: import_joi134.default.alternatives().try(import_joi134.default.array().items(import_joi134.default.string())).optional().allow(null, ""),
56135
+ subcategory: import_joi134.default.array().items(import_joi134.default.string()).single().optional().allow(null),
55929
56136
  userId: import_joi134.default.string().optional().allow("", null)
55930
56137
  });
55931
56138
  const { error, value } = validation.validate(req.query, {
@@ -56130,6 +56337,17 @@ function usePostFavoriteRepo() {
56130
56337
  throw new import_node_server_utils237.NotFoundError("Favorite not found.");
56131
56338
  return result;
56132
56339
  }
56340
+ async function getByPostId(postId) {
56341
+ try {
56342
+ postId = new import_mongodb135.ObjectId(postId);
56343
+ } catch {
56344
+ throw new import_node_server_utils237.BadRequestError("Invalid post ID format.");
56345
+ }
56346
+ const result = await collection.findOne({ postId });
56347
+ if (!result)
56348
+ throw new import_node_server_utils237.NotFoundError("Favorite not found.");
56349
+ return result;
56350
+ }
56133
56351
  async function updateById(_id, userId, session) {
56134
56352
  try {
56135
56353
  _id = new import_mongodb135.ObjectId(_id);
@@ -56155,6 +56373,7 @@ function usePostFavoriteRepo() {
56155
56373
  return {
56156
56374
  addFavorite,
56157
56375
  getById,
56376
+ getByPostId,
56158
56377
  updateById
56159
56378
  };
56160
56379
  }
@@ -56202,7 +56421,7 @@ var import_node_server_utils239 = require("@7365admin1/node-server-utils");
56202
56421
  var import_joi136 = __toESM(require("joi"));
56203
56422
  function usePostFavoriteController() {
56204
56423
  const { addFavorite: _addFavorite, toggleFavorite: _toggleFavorite } = usePostFavoriteService();
56205
- const { getById: _getById } = usePostFavoriteRepo();
56424
+ const { getById: _getById, getByPostId: _getByPostId } = usePostFavoriteRepo();
56206
56425
  async function addFavorite(req, res, next) {
56207
56426
  const { error, value } = schemaPostFavorite.validate(req.body, {
56208
56427
  abortEarly: false
@@ -56243,6 +56462,26 @@ function usePostFavoriteController() {
56243
56462
  return;
56244
56463
  }
56245
56464
  }
56465
+ async function getByPostId(req, res, next) {
56466
+ const schema2 = import_joi136.default.object({
56467
+ postId: import_joi136.default.string().hex().length(24).required()
56468
+ });
56469
+ const { error, value } = schema2.validate({ postId: req.params.postId });
56470
+ if (error) {
56471
+ import_node_server_utils239.logger.log({ level: "error", message: error.message });
56472
+ next(new import_node_server_utils239.BadRequestError(error.message));
56473
+ return;
56474
+ }
56475
+ try {
56476
+ const data = await _getByPostId(value.postId);
56477
+ res.status(200).json(data);
56478
+ return;
56479
+ } catch (error2) {
56480
+ import_node_server_utils239.logger.log({ level: "error", message: error2.message });
56481
+ next(error2);
56482
+ return;
56483
+ }
56484
+ }
56246
56485
  async function updateById(req, res, next) {
56247
56486
  const paramsSchema = import_joi136.default.object({
56248
56487
  _id: import_joi136.default.string().hex().length(24).required()
@@ -56272,6 +56511,7 @@ function usePostFavoriteController() {
56272
56511
  return {
56273
56512
  addFavorite,
56274
56513
  getById,
56514
+ getByPostId,
56275
56515
  updateById
56276
56516
  };
56277
56517
  }
@@ -56568,7 +56808,50 @@ function useSubcategoryPrelovedRepo() {
56568
56808
  throw error;
56569
56809
  }
56570
56810
  }
56571
- return { getAll, getById, addSubcategory };
56811
+ async function updateById(_id, value, session) {
56812
+ let objectId2;
56813
+ try {
56814
+ objectId2 = new import_mongodb139.ObjectId(_id);
56815
+ } catch {
56816
+ throw new import_node_server_utils242.BadRequestError("Invalid subcategory ID format.");
56817
+ }
56818
+ if (value.category_id && typeof value.category_id === "string") {
56819
+ try {
56820
+ value.category_id = new import_mongodb139.ObjectId(value.category_id);
56821
+ } catch {
56822
+ throw new import_node_server_utils242.BadRequestError("Invalid category ID format.");
56823
+ }
56824
+ }
56825
+ if (value.site && typeof value.site === "string") {
56826
+ try {
56827
+ value.site = new import_mongodb139.ObjectId(value.site);
56828
+ } catch {
56829
+ throw new import_node_server_utils242.BadRequestError("Invalid site ID format.");
56830
+ }
56831
+ }
56832
+ value.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
56833
+ const res = await collection.updateOne(
56834
+ { _id: objectId2 },
56835
+ { $set: value },
56836
+ { session }
56837
+ );
56838
+ if (res.modifiedCount === 0)
56839
+ throw new import_node_server_utils242.InternalServerError("Unable to update subcategory.");
56840
+ return res;
56841
+ }
56842
+ async function deleteById(_id, session) {
56843
+ let objectId2;
56844
+ try {
56845
+ objectId2 = new import_mongodb139.ObjectId(_id);
56846
+ } catch {
56847
+ throw new import_node_server_utils242.BadRequestError("Invalid subcategory ID format.");
56848
+ }
56849
+ const res = await collection.deleteOne({ _id: objectId2 }, { session });
56850
+ if (res.deletedCount === 0)
56851
+ throw new import_node_server_utils242.InternalServerError("Unable to delete subcategory.");
56852
+ return res.deletedCount;
56853
+ }
56854
+ return { getAll, getById, addSubcategory, updateById, deleteById };
56572
56855
  }
56573
56856
 
56574
56857
  // src/controllers/subcategory-preloved.controller.ts
@@ -56578,7 +56861,9 @@ function useSubcategoryPrelovedController() {
56578
56861
  const {
56579
56862
  getAll: _getAll,
56580
56863
  getById: _getById,
56581
- addSubcategory: _addSubcategory
56864
+ addSubcategory: _addSubcategory,
56865
+ updateById: _updateById,
56866
+ deleteById: _deleteById
56582
56867
  } = useSubcategoryPrelovedRepo();
56583
56868
  async function getAll(req, res, next) {
56584
56869
  const schema2 = import_joi140.default.object({
@@ -56641,7 +56926,50 @@ function useSubcategoryPrelovedController() {
56641
56926
  next(error2);
56642
56927
  }
56643
56928
  }
56644
- return { getAll, getById, addSubcategory };
56929
+ async function updateById(req, res, next) {
56930
+ const paramsSchema = import_joi140.default.object({
56931
+ _id: import_joi140.default.string().hex().length(24).required()
56932
+ });
56933
+ const { error: paramsError, value: paramsValue } = paramsSchema.validate({
56934
+ _id: req.params.id
56935
+ });
56936
+ if (paramsError) {
56937
+ next(new import_node_server_utils243.BadRequestError(paramsError.message));
56938
+ return;
56939
+ }
56940
+ const { error: bodyError, value: bodyValue } = schemaUpdateSubcategoryPreloved.validate(req.body, { abortEarly: false });
56941
+ if (bodyError) {
56942
+ const messages = bodyError.details.map((d) => d.message).join(", ");
56943
+ import_node_server_utils243.logger.log({ level: "error", message: messages });
56944
+ next(new import_node_server_utils243.BadRequestError(messages));
56945
+ return;
56946
+ }
56947
+ try {
56948
+ const data = await _updateById(paramsValue._id, bodyValue);
56949
+ res.status(200).json(data);
56950
+ } catch (error) {
56951
+ import_node_server_utils243.logger.log({ level: "error", message: error.message });
56952
+ next(error);
56953
+ }
56954
+ }
56955
+ async function deleteById(req, res, next) {
56956
+ const schema2 = import_joi140.default.object({
56957
+ _id: import_joi140.default.string().hex().length(24).required()
56958
+ });
56959
+ const { error, value } = schema2.validate({ _id: req.params.id });
56960
+ if (error) {
56961
+ next(new import_node_server_utils243.BadRequestError(error.message));
56962
+ return;
56963
+ }
56964
+ try {
56965
+ const data = await _deleteById(value._id);
56966
+ res.status(200).json(data);
56967
+ } catch (error2) {
56968
+ import_node_server_utils243.logger.log({ level: "error", message: error2.message });
56969
+ next(error2);
56970
+ }
56971
+ }
56972
+ return { getAll, getById, addSubcategory, updateById, deleteById };
56645
56973
  }
56646
56974
 
56647
56975
  // src/models/online-forms-v2.model.ts
@@ -56735,6 +57063,7 @@ function MFormEntry(value) {
56735
57063
 
56736
57064
  // src/repositories/online-forms-v2.repository.ts
56737
57065
  var import_node_server_utils244 = require("@7365admin1/node-server-utils");
57066
+ var import_mongodb141 = require("mongodb");
56738
57067
  var online_forms_namespace_collection = "online-forms";
56739
57068
  function useFormEntryRepo() {
56740
57069
  const db = import_node_server_utils244.useAtlas.getDb();
@@ -56779,18 +57108,105 @@ function useFormEntryRepo() {
56779
57108
  throw error;
56780
57109
  }
56781
57110
  }
57111
+ async function getAll({
57112
+ search = "",
57113
+ page = 1,
57114
+ limit = 10,
57115
+ sort = {},
57116
+ status = "active",
57117
+ org = "",
57118
+ site = ""
57119
+ }) {
57120
+ page = page > 0 ? page - 1 : 0;
57121
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
57122
+ const cacheOptions = {
57123
+ page,
57124
+ limit,
57125
+ status,
57126
+ sort: JSON.stringify(sort),
57127
+ ...site && { site },
57128
+ ...search && { search }
57129
+ };
57130
+ const query = {
57131
+ ...status ? { $and: [{ status }, { status: { $ne: "deleted" } }] } : { status: { $ne: "deleted" } },
57132
+ ...site && { site: new import_mongodb141.ObjectId(site) },
57133
+ ...search && { search: [{ name: { $regex: search, $options: "i" } }] }
57134
+ };
57135
+ const cacheKey = (0, import_node_server_utils244.makeCacheKey)(
57136
+ online_forms_namespace_collection,
57137
+ cacheOptions
57138
+ );
57139
+ const cachedData = await getCache(cacheKey);
57140
+ if (cachedData) {
57141
+ import_node_server_utils244.logger.info(`Cache hit for key: ${cacheKey}`);
57142
+ return cachedData;
57143
+ }
57144
+ try {
57145
+ const items = await collection.aggregate([
57146
+ { $match: query },
57147
+ { $sort: sort },
57148
+ { $skip: page * limit },
57149
+ { $limit: limit }
57150
+ ]).toArray();
57151
+ const length = await collection.countDocuments(query);
57152
+ const data = (0, import_node_server_utils244.paginate)(items, page, limit, length);
57153
+ setCache(cacheKey, data, 15 * 60).then(() => {
57154
+ import_node_server_utils244.logger.info(`Cache set for key: ${cacheKey}`);
57155
+ }).catch((err) => {
57156
+ import_node_server_utils244.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
57157
+ });
57158
+ return data;
57159
+ } catch (error) {
57160
+ throw error;
57161
+ }
57162
+ }
57163
+ async function getFormEntryById(_id) {
57164
+ const cacheKey = (0, import_node_server_utils244.makeCacheKey)(online_forms_namespace_collection, { _id });
57165
+ const cachedData = await getCache(cacheKey);
57166
+ if (cachedData) {
57167
+ import_node_server_utils244.logger.info(`Cache hit for key: ${cacheKey}`);
57168
+ return cachedData;
57169
+ }
57170
+ try {
57171
+ _id = new import_mongodb141.ObjectId(_id);
57172
+ } catch (error) {
57173
+ throw new import_node_server_utils244.BadRequestError("Invalid online form ID format.");
57174
+ }
57175
+ const query = { _id, status: { $ne: "deleted" } };
57176
+ try {
57177
+ const [data] = await collection.aggregate([{ $match: query }]).toArray();
57178
+ if (!data) {
57179
+ throw new import_node_server_utils244.NotFoundError("Document not found.");
57180
+ }
57181
+ setCache(cacheKey, data, 15 * 60).then(() => {
57182
+ import_node_server_utils244.logger.info(`Cache set for key: ${cacheKey}`);
57183
+ }).catch((err) => {
57184
+ import_node_server_utils244.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
57185
+ });
57186
+ return data;
57187
+ } catch (error) {
57188
+ throw error;
57189
+ }
57190
+ }
56782
57191
  return {
56783
57192
  add,
57193
+ getAll,
57194
+ getFormEntryById,
56784
57195
  createTextIndex
56785
57196
  };
56786
57197
  }
56787
57198
 
56788
57199
  // src/controllers/online-forms-v2.controller.ts
56789
57200
  var import_node_server_utils245 = require("@7365admin1/node-server-utils");
57201
+ var import_joi142 = __toESM(require("joi"));
56790
57202
  var import_exceljs3 = __toESM(require("exceljs"));
56791
57203
  var import_fs6 = __toESM(require("fs"));
56792
57204
  function useFormEntryController() {
56793
- const { add: _add } = useFormEntryRepo();
57205
+ const {
57206
+ add: _add,
57207
+ getAll: _getAll,
57208
+ getFormEntryById: _getFormEntryById
57209
+ } = useFormEntryRepo();
56794
57210
  function toCamelCase(str) {
56795
57211
  return str.replace(/\s(.)/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "").replace(/^(.)/, (_, char) => char.toLowerCase());
56796
57212
  }
@@ -56852,8 +57268,59 @@ function useFormEntryController() {
56852
57268
  next(error);
56853
57269
  }
56854
57270
  }
57271
+ async function getAll(req, res, next) {
57272
+ try {
57273
+ const schema2 = import_joi142.default.object({
57274
+ search: import_joi142.default.string().optional().allow("", null),
57275
+ page: import_joi142.default.number().integer().min(1).allow("", null).default(1),
57276
+ limit: import_joi142.default.number().integer().min(1).max(100).allow("", null).default(10),
57277
+ status: import_joi142.default.string().optional().allow(null, ""),
57278
+ org: import_joi142.default.string().hex().optional().allow("", null),
57279
+ site: import_joi142.default.string().hex().optional().allow("", null)
57280
+ });
57281
+ const { error, value } = schema2.validate(req.query);
57282
+ if (error) {
57283
+ const messages = error.details.map((d) => d.message).join(", ");
57284
+ import_node_server_utils245.logger.log({ level: "error", message: messages });
57285
+ next(new import_node_server_utils245.BadRequestError(messages));
57286
+ return;
57287
+ }
57288
+ const { search, page, limit, status, org, site } = value;
57289
+ const data = await _getAll({ search, page, limit, status, org, site });
57290
+ res.json(data);
57291
+ return;
57292
+ } catch (error) {
57293
+ import_node_server_utils245.logger.log({ level: "error", message: error.message });
57294
+ next(error);
57295
+ return;
57296
+ }
57297
+ }
57298
+ async function getFormEntryById(req, res, next) {
57299
+ try {
57300
+ const schema2 = import_joi142.default.object({
57301
+ _id: import_joi142.default.string().hex().length(24).required()
57302
+ });
57303
+ const { error, value } = schema2.validate({ _id: req.params.id });
57304
+ if (error) {
57305
+ const messages = error.details.map((d) => d.message).join(", ");
57306
+ import_node_server_utils245.logger.log({ level: "error", message: messages });
57307
+ next(new import_node_server_utils245.BadRequestError(messages));
57308
+ return;
57309
+ }
57310
+ const { _id } = value;
57311
+ const data = await _getFormEntryById(_id);
57312
+ res.json(data);
57313
+ return;
57314
+ } catch (error) {
57315
+ import_node_server_utils245.logger.log({ level: "error", message: error.message });
57316
+ next(error);
57317
+ return;
57318
+ }
57319
+ }
56855
57320
  return {
56856
- uploadFormEntrys
57321
+ uploadFormEntrys,
57322
+ getAll,
57323
+ getFormEntryById
56857
57324
  };
56858
57325
  }
56859
57326
 
@@ -56897,7 +57364,7 @@ function useBuildingLevelService() {
56897
57364
 
56898
57365
  // src/controllers/building-level.controller.ts
56899
57366
  var import_node_server_utils247 = require("@7365admin1/node-server-utils");
56900
- var import_joi142 = __toESM(require("joi"));
57367
+ var import_joi143 = __toESM(require("joi"));
56901
57368
  function useBuildingLevelController() {
56902
57369
  const { add: _add, updateLevelById: _updateLevelById } = useBuildingLevelService();
56903
57370
  const {
@@ -56924,12 +57391,12 @@ function useBuildingLevelController() {
56924
57391
  }
56925
57392
  async function getAll(req, res, next) {
56926
57393
  try {
56927
- const validation = import_joi142.default.object({
56928
- page: import_joi142.default.number().min(1).optional().default(1),
56929
- limit: import_joi142.default.number().min(1).optional().default(20),
56930
- search: import_joi142.default.string().optional().allow("", null),
56931
- site: import_joi142.default.string().hex().length(24).optional().allow("", null),
56932
- status: import_joi142.default.string().valid(...Object.values(BuildingLevelStatus)).default("active" /* ACTIVE */)
57394
+ const validation = import_joi143.default.object({
57395
+ page: import_joi143.default.number().min(1).optional().default(1),
57396
+ limit: import_joi143.default.number().min(1).optional().default(20),
57397
+ search: import_joi143.default.string().optional().allow("", null),
57398
+ site: import_joi143.default.string().hex().length(24).optional().allow("", null),
57399
+ status: import_joi143.default.string().valid(...Object.values(BuildingLevelStatus)).default("active" /* ACTIVE */)
56933
57400
  });
56934
57401
  const { error, value } = validation.validate(req.query, {
56935
57402
  abortEarly: false
@@ -56956,8 +57423,8 @@ function useBuildingLevelController() {
56956
57423
  }
56957
57424
  async function getById(req, res, next) {
56958
57425
  try {
56959
- const schema2 = import_joi142.default.object({
56960
- id: import_joi142.default.string().hex().length(24).required()
57426
+ const schema2 = import_joi143.default.object({
57427
+ id: import_joi143.default.string().hex().length(24).required()
56961
57428
  });
56962
57429
  const { error, value } = schema2.validate({ id: req.params.id });
56963
57430
  if (error) {
@@ -56995,8 +57462,8 @@ function useBuildingLevelController() {
56995
57462
  }
56996
57463
  async function deleteById(req, res, next) {
56997
57464
  try {
56998
- const schema2 = import_joi142.default.object({
56999
- id: import_joi142.default.string().hex().required()
57465
+ const schema2 = import_joi143.default.object({
57466
+ id: import_joi143.default.string().hex().required()
57000
57467
  });
57001
57468
  const { error, value } = schema2.validate({ id: req.params.id });
57002
57469
  if (error) {