@7365admin1/core 3.7.0 → 3.8.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
@@ -6030,7 +6030,6 @@ __export(src_exports, {
6030
6030
  building_units_namespace_collection: () => building_units_namespace_collection,
6031
6031
  buildings_namespace_collection: () => buildings_namespace_collection,
6032
6032
  bulletin_boards_namespace_collection: () => bulletin_boards_namespace_collection,
6033
- calculatePercentage: () => calculatePercentage,
6034
6033
  chatSchema: () => chatSchema,
6035
6034
  createManpowerRemarksDaily: () => createManpowerRemarksDaily,
6036
6035
  customerSchema: () => customerSchema,
@@ -6041,7 +6040,6 @@ __export(src_exports, {
6041
6040
  feedbacks2_namespace_collection: () => feedbacks2_namespace_collection,
6042
6041
  feedbacks_namespace_collection: () => feedbacks_namespace_collection,
6043
6042
  formatDahuaDate: () => formatDahuaDate,
6044
- getPeriodRangeWithPrevious: () => getPeriodRangeWithPrevious,
6045
6043
  guests_namespace_collection: () => guests_namespace_collection,
6046
6044
  incidentReportLog: () => incidentReportLog,
6047
6045
  incidents_namespace_collection: () => incidents_namespace_collection,
@@ -12253,9 +12251,7 @@ function useVerificationService() {
12253
12251
  ...metadata,
12254
12252
  app
12255
12253
  },
12256
- expireAt: new Date(
12257
- Date.now() + 72 * 60 * 60 * 1e3
12258
- ).toISOString(),
12254
+ expireAt: new Date(Date.now() + 72 * 60 * 60 * 1e3).toISOString(),
12259
12255
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12260
12256
  };
12261
12257
  const createdId = await add(value);
@@ -12274,10 +12270,7 @@ function useVerificationService() {
12274
12270
  hasPestControl: app === "pest_control_services",
12275
12271
  hasPoolMaintenance: app === "pool_maintenance_services"
12276
12272
  },
12277
- filePath: (0, import_node_server_utils21.getDirectory)(
12278
- __dirname,
12279
- "./public/handlebars/user-invite"
12280
- )
12273
+ filePath: (0, import_node_server_utils21.getDirectory)(__dirname, "./public/handlebars/user-invite")
12281
12274
  });
12282
12275
  await mailer.sendMail({
12283
12276
  to: email,
@@ -12420,7 +12413,15 @@ function useVerificationService() {
12420
12413
  throw error2;
12421
12414
  }
12422
12415
  }
12423
- async function createSimpleServiceProviderInvite({ email, app, name, role, orgId, siteId, siteName }) {
12416
+ async function createSimpleServiceProviderInvite({
12417
+ email,
12418
+ app,
12419
+ name,
12420
+ role,
12421
+ orgId,
12422
+ siteId,
12423
+ siteName
12424
+ }) {
12424
12425
  const schema2 = import_joi11.default.object({
12425
12426
  email: import_joi11.default.string().email().lowercase().required(),
12426
12427
  app: import_joi11.default.string().allow("", null),
@@ -12462,7 +12463,10 @@ function useVerificationService() {
12462
12463
  };
12463
12464
  try {
12464
12465
  const id = await _add(value);
12465
- const filePath = (0, import_node_server_utils21.getDirectory)(__dirname, `./public/handlebars/${value.type}`);
12466
+ const filePath = (0, import_node_server_utils21.getDirectory)(
12467
+ __dirname,
12468
+ `./public/handlebars/${value.type}`
12469
+ );
12466
12470
  const link = `${APP_MAIN}/verify/${value.type}/${id}`;
12467
12471
  const emailContent = (0, import_node_server_utils21.compileHandlebar)({
12468
12472
  context: {
@@ -21254,6 +21258,15 @@ async function convertObjectIdUtil(id) {
21254
21258
  return Promise.reject("Invalid ID conversion to ObjectId");
21255
21259
  }
21256
21260
  }
21261
+ async function convertObjectIdUtil2(id, fieldName) {
21262
+ try {
21263
+ if (!id)
21264
+ throw new Error(`Invalid ID conversion to ObjectId of ${fieldName}.`);
21265
+ return new import_mongodb40.ObjectId(id);
21266
+ } catch (_) {
21267
+ throw new Error(`Invalid ID conversion to ObjectId of ${fieldName}.`);
21268
+ }
21269
+ }
21257
21270
 
21258
21271
  // src/repositories/visitor-transaction.repo.ts
21259
21272
  var import_moment_timezone = __toESM(require("moment-timezone"));
@@ -23047,6 +23060,38 @@ function useVehicleRepo() {
23047
23060
  throw error;
23048
23061
  }
23049
23062
  }
23063
+ async function getBlocklistedVehicleByPlateNumber(plateNumber, site) {
23064
+ if (!plateNumber) {
23065
+ throw new import_node_server_utils71.BadRequestError("Plate number is required");
23066
+ }
23067
+ const baseQuery = {
23068
+ type: "blocklist" /* BLOCKLIST */,
23069
+ plateNumber,
23070
+ ...site && {
23071
+ site: typeof site === "string" ? new import_mongodb43.ObjectId(site) : site
23072
+ }
23073
+ };
23074
+ try {
23075
+ const pipeline = [
23076
+ { $match: baseQuery },
23077
+ {
23078
+ $addFields: {
23079
+ latestDate: { $max: ["$createdAt", "$updatedAt"] }
23080
+ }
23081
+ },
23082
+ { $sort: { latestDate: -1 } },
23083
+ {
23084
+ $project: {
23085
+ latestDate: 0
23086
+ }
23087
+ }
23088
+ ];
23089
+ const [result] = await collection.aggregate(pipeline).toArray();
23090
+ return result;
23091
+ } catch (error) {
23092
+ throw error;
23093
+ }
23094
+ }
23050
23095
  return {
23051
23096
  createIndex,
23052
23097
  createTextIndex,
@@ -23065,7 +23110,8 @@ function useVehicleRepo() {
23065
23110
  bulkUpsertVehicles,
23066
23111
  getSpecificVehicleById,
23067
23112
  getBlocklistedVehicles,
23068
- getVehicleBySiteAndPlateNumber
23113
+ getVehicleBySiteAndPlateNumber,
23114
+ getBlocklistedVehicleByPlateNumber
23069
23115
  };
23070
23116
  }
23071
23117
 
@@ -33400,6 +33446,241 @@ var KeyRepo = class {
33400
33446
  return Promise.reject("Failed to delete key");
33401
33447
  }
33402
33448
  }
33449
+ static async getById2(id) {
33450
+ return this.collection().aggregate([
33451
+ { $match: { _id: new import_mongodb61.ObjectId(id) } },
33452
+ {
33453
+ $lookup: {
33454
+ from: "qr-code-templates",
33455
+ localField: "template",
33456
+ foreignField: "_id",
33457
+ as: "QRTemplateInfo"
33458
+ }
33459
+ },
33460
+ {
33461
+ $unwind: {
33462
+ path: "$QRTemplateInfo",
33463
+ preserveNullAndEmptyArrays: true
33464
+ }
33465
+ },
33466
+ {
33467
+ $addFields: {
33468
+ prefixPass: { $toUpper: "$QRTemplateInfo.prefixPass" },
33469
+ prefixKey: { $toUpper: "$QRTemplateInfo.prefixKey" },
33470
+ templateName: "$QRTemplateInfo.name"
33471
+ }
33472
+ },
33473
+ {
33474
+ $addFields: {
33475
+ prefixAndName: {
33476
+ $cond: {
33477
+ if: { $or: [{ $not: "$prefixPass" }, { $not: "$prefixKey" }] },
33478
+ then: "$name",
33479
+ else: {
33480
+ $cond: {
33481
+ if: { $eq: ["$passType", "pass-key"] },
33482
+ then: { $concat: ["$prefixKey", "$name"] },
33483
+ else: { $concat: ["$prefixPass", "$name"] }
33484
+ }
33485
+ }
33486
+ }
33487
+ }
33488
+ }
33489
+ }
33490
+ ]).toArray().then((results) => results.length ? results[0] : null);
33491
+ }
33492
+ static async checkPassKeyAvailability(visitorPass, passKeys) {
33493
+ if (Array.isArray(visitorPass) && visitorPass.length > 0) {
33494
+ for (let i = 0; i < visitorPass.length; i++) {
33495
+ let pass = await convertObjectIdUtil2(visitorPass[i].keyId, "Pass ID");
33496
+ const getPass = await this.getById2(pass);
33497
+ if (!getPass)
33498
+ throw new Error("Pass not found");
33499
+ if (getPass?.status && getPass?.status.toLowerCase() != "Available".toLowerCase())
33500
+ throw new Error(`Pass ${getPass?.prefixAndName} is ${getPass?.status}`);
33501
+ }
33502
+ }
33503
+ if (Array.isArray(passKeys) && passKeys.length > 0) {
33504
+ for (let i = 0; i < passKeys.length; i++) {
33505
+ let key = await convertObjectIdUtil2(passKeys[i].keyId, "Key ID");
33506
+ const getPass = await this.getById2(key);
33507
+ if (!getPass)
33508
+ throw new Error(`Key not found`);
33509
+ if (getPass?.status && getPass?.status.toLowerCase() != "Available".toLowerCase())
33510
+ throw new Error(`Pass ${getPass?.prefixAndName} is ${getPass?.status}`);
33511
+ }
33512
+ }
33513
+ }
33514
+ };
33515
+
33516
+ // src/services/notification.service.ts
33517
+ var import_iservice365_expo_notifications = require("iservice365-expo-notifications");
33518
+
33519
+ // src/repositories/push-token.repository.ts
33520
+ var PushTokenRepo = class {
33521
+ static collection() {
33522
+ return getDB().collection("push_tokens");
33523
+ }
33524
+ static async createIndexes() {
33525
+ await Promise.all([
33526
+ this.collection().createIndex({ token: 1 }, { unique: true }),
33527
+ this.collection().createIndex({ userId: 1, platform: 1 }),
33528
+ this.collection().createIndex({ siteId: 1 })
33529
+ ]);
33530
+ }
33531
+ static async upsert(userId, token, platform, siteId, projectId, appSlug) {
33532
+ const now = /* @__PURE__ */ new Date();
33533
+ const p = platform;
33534
+ const existing = await this.collection().findOne({ token });
33535
+ if (existing) {
33536
+ await this.collection().updateOne(
33537
+ { token },
33538
+ {
33539
+ $set: {
33540
+ userId,
33541
+ platform: p,
33542
+ siteId,
33543
+ projectId,
33544
+ appSlug,
33545
+ updatedAt: now
33546
+ }
33547
+ }
33548
+ );
33549
+ return;
33550
+ }
33551
+ await this.collection().deleteMany({ userId, platform: p });
33552
+ await this.collection().insertOne({
33553
+ userId,
33554
+ siteId,
33555
+ token,
33556
+ platform: p,
33557
+ projectId,
33558
+ appSlug,
33559
+ createdAt: now,
33560
+ updatedAt: now
33561
+ });
33562
+ }
33563
+ static async remove(token) {
33564
+ await this.collection().deleteMany({ token });
33565
+ }
33566
+ static async findTokensByUserIds(userIds, appSlug) {
33567
+ const docs = await this.collection().find({ userId: { $in: userIds }, appSlug: { $eq: appSlug } }).toArray();
33568
+ return docs.map((d) => d.token);
33569
+ }
33570
+ };
33571
+
33572
+ // src/services/notification.service.ts
33573
+ function toStringArray(recipient) {
33574
+ const arr = Array.isArray(recipient) ? recipient : [recipient];
33575
+ return arr.map((r) => r.toString());
33576
+ }
33577
+ async function send(userIds, title, body, data, isForMAMobileApp = false, appSlug) {
33578
+ try {
33579
+ let tokens = [];
33580
+ if (isForMAMobileApp) {
33581
+ tokens = await PushTokenRepo.findTokensByUserIds(userIds, appSlug);
33582
+ } else {
33583
+ tokens = await PushTokenRepo.findTokensByUserIds(userIds);
33584
+ }
33585
+ if (!tokens.length)
33586
+ return;
33587
+ for (const token of tokens) {
33588
+ await (0, import_iservice365_expo_notifications.sendExpoPushNotifications)([token], { title, body, data });
33589
+ }
33590
+ } catch (error) {
33591
+ console.warn("[NotificationService]", error);
33592
+ }
33593
+ }
33594
+ var NotificationService = class {
33595
+ static async bulletinBoardCreated(payload) {
33596
+ await send(
33597
+ toStringArray(payload.to),
33598
+ "Bulletin Board",
33599
+ `There is new ${payload.status} bulletin board.`,
33600
+ {
33601
+ bulletinId: payload.bulletinId.toString(),
33602
+ status: payload.status,
33603
+ module: "feedback",
33604
+ screen: "/(user)/bulletinInfo",
33605
+ params: {
33606
+ id: payload.bulletinId.toString()
33607
+ }
33608
+ },
33609
+ false,
33610
+ "iservice365-resident-mobile-app"
33611
+ );
33612
+ }
33613
+ static async prelovedMarketplacePostCreation(payload) {
33614
+ await send(
33615
+ toStringArray(payload.to),
33616
+ "Preloved Marketplace",
33617
+ `New preloved marketplace post added.`,
33618
+ {
33619
+ prelovedId: payload.prelovedId.toString(),
33620
+ status: payload.status,
33621
+ module: "prelovedMarketplace",
33622
+ screen: "/(user)/(marketplace)/prelovedPostInfo",
33623
+ params: {
33624
+ id: payload.prelovedId.toString()
33625
+ }
33626
+ },
33627
+ false,
33628
+ "iservice365-resident-mobile-app"
33629
+ );
33630
+ }
33631
+ static async bulletinBoardCreatedForMA(payload) {
33632
+ await send(
33633
+ toStringArray(payload.to),
33634
+ "Bulletin Board",
33635
+ `There is new ${payload.status} bulletin board.`,
33636
+ {
33637
+ bulletinId: payload.bulletinId.toString(),
33638
+ status: payload.status,
33639
+ module: "feedback",
33640
+ screen: "/(user)/(bulletin-board)",
33641
+ params: {
33642
+ id: payload.bulletinId.toString()
33643
+ }
33644
+ },
33645
+ true,
33646
+ "iservice365-ma-mobile-app"
33647
+ );
33648
+ }
33649
+ static async eventCreatedForMA(payload) {
33650
+ await send(
33651
+ toStringArray(payload.to),
33652
+ "Event",
33653
+ `There is new ${payload.status} event.`,
33654
+ {
33655
+ eventId: payload.eventId.toString(),
33656
+ status: payload.status,
33657
+ module: "event",
33658
+ screen: "/(user)/(events)",
33659
+ params: {
33660
+ id: payload.eventId.toString()
33661
+ }
33662
+ },
33663
+ true,
33664
+ "iservice365-ma-mobile-app"
33665
+ );
33666
+ }
33667
+ static async invitedVisitorCheckOutForMa(payload) {
33668
+ await send(
33669
+ toStringArray(payload.to),
33670
+ "Invited Visitor Check Out",
33671
+ `The invited visitor ${payload.name}, has been checked out.`,
33672
+ {
33673
+ visitorTransactionId: payload._id.toString(),
33674
+ module: "visitors",
33675
+ screen: "/(user)/visitor-management",
33676
+ params: {
33677
+ id: payload._id.toString()
33678
+ }
33679
+ },
33680
+ true,
33681
+ "iservice365-ma-mobile-app"
33682
+ );
33683
+ }
33403
33684
  };
33404
33685
 
33405
33686
  // src/services/visitor-transaction.service.ts
@@ -33436,8 +33717,11 @@ function useVisitorTransactionService() {
33436
33717
  } = useDahuaService();
33437
33718
  const { getAllSites: _getAllSites } = useSiteRepo();
33438
33719
  const { getByUserId: _getByUserId } = usePersonRepo();
33439
- const { add: addVehicle } = useVehicleRepo();
33720
+ const {
33721
+ getBlocklistedVehicleByPlateNumber: _getBlocklistedVehicleByPlateNumber
33722
+ } = useVehicleRepo();
33440
33723
  const { getById: _getUnitById } = useBuildingUnitRepo();
33724
+ const { getUsersBySiteId } = useMemberRepo();
33441
33725
  function extractKeyId(item) {
33442
33726
  if (!item)
33443
33727
  return null;
@@ -33514,6 +33798,13 @@ function useVisitorTransactionService() {
33514
33798
  const start = value.checkIn ? new Date(value.checkIn) : /* @__PURE__ */ new Date();
33515
33799
  try {
33516
33800
  session?.startTransaction();
33801
+ if (value.plateNumber) {
33802
+ const result2 = await _getBlocklistedVehicleByPlateNumber(
33803
+ value.plateNumber
33804
+ );
33805
+ if (result2)
33806
+ throw new import_node_server_utils106.BadRequestError("Plate number is blocklisted");
33807
+ }
33517
33808
  let camera;
33518
33809
  if (value.site && value.plateNumber) {
33519
33810
  try {
@@ -33579,6 +33870,10 @@ function useVisitorTransactionService() {
33579
33870
  for (let i = 0; i < value.members.length; i += chunkSize) {
33580
33871
  const chunk = value.members.slice(i, i + chunkSize);
33581
33872
  for (const member of chunk) {
33873
+ await KeyRepo.checkPassKeyAvailability(
33874
+ member.visitorPass,
33875
+ member.passKeys
33876
+ );
33582
33877
  if (member.visitorPass && Array.isArray(member.visitorPass) && member.visitorPass.length > 0) {
33583
33878
  for (const vp of member.visitorPass) {
33584
33879
  try {
@@ -33665,6 +33960,7 @@ function useVisitorTransactionService() {
33665
33960
  if (found === 1)
33666
33961
  throw new import_node_server_utils106.BadRequestError("This plate number is blocklisted");
33667
33962
  }
33963
+ await KeyRepo.checkPassKeyAvailability(value.visitorPass, value.passKeys);
33668
33964
  if (value.visitorPass && Array.isArray(value.visitorPass) && value.visitorPass.length > 0 && value.visitorPass) {
33669
33965
  for (const vp of value.visitorPass) {
33670
33966
  try {
@@ -33712,7 +34008,9 @@ function useVisitorTransactionService() {
33712
34008
  password,
33713
34009
  plateNumber: value?.plateNumber
33714
34010
  });
33715
- import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
34011
+ import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, {
34012
+ response: openBarrier
34013
+ });
33716
34014
  } catch (error) {
33717
34015
  import_node_server_utils106.logger.error(
33718
34016
  `Failed to open barrier at host ${host}. Critical system error:`,
@@ -33852,7 +34150,9 @@ function useVisitorTransactionService() {
33852
34150
  password,
33853
34151
  plateNumber: value?.plateNumber
33854
34152
  });
33855
- import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
34153
+ import_node_server_utils106.logger.info(`Barrier command sent successfully to ${host}`, {
34154
+ response: openBarrier
34155
+ });
33856
34156
  } catch (error) {
33857
34157
  import_node_server_utils106.logger.error(
33858
34158
  `Failed to open barrier at host ${host}. Critical system error:`,
@@ -33862,6 +34162,28 @@ function useVisitorTransactionService() {
33862
34162
  }
33863
34163
  }
33864
34164
  console.log("Open barrier response:", openBarrier);
34165
+ const visitorTransaction = await _getVisitorTransactionById(
34166
+ id.toString()
34167
+ );
34168
+ if (!visitorTransaction) {
34169
+ throw new Error("Visitor transaction not found.");
34170
+ }
34171
+ if (value.checkOut && visitorTransaction.type === "guest" /* GUEST */) {
34172
+ const users = await getUsersBySiteId({
34173
+ status: "active",
34174
+ siteId: visitorTransaction.site.toString()
34175
+ });
34176
+ if (users?.length > 0) {
34177
+ const userIds = Array.from(
34178
+ new Set(users.map((item) => item.user.toString()))
34179
+ );
34180
+ NotificationService.invitedVisitorCheckOutForMa({
34181
+ to: userIds,
34182
+ name: visitorTransaction.name,
34183
+ _id: id.toString()
34184
+ });
34185
+ }
34186
+ }
33865
34187
  await session?.commitTransaction();
33866
34188
  return "Successfully updated visitor transaction.";
33867
34189
  } catch (error) {
@@ -34065,7 +34387,12 @@ function useVisitorTransactionController() {
34065
34387
  return;
34066
34388
  } catch (error) {
34067
34389
  import_node_server_utils107.logger.log({ level: "error", message: error.message });
34068
- next(error);
34390
+ console.log("error", error);
34391
+ if (error?.message) {
34392
+ next(new import_node_server_utils107.BadRequestError(error?.message));
34393
+ } else {
34394
+ next(error);
34395
+ }
34069
34396
  return;
34070
34397
  }
34071
34398
  }
@@ -40914,120 +41241,6 @@ function useBulletinBoardRepo() {
40914
41241
  // src/services/bulletin-board.service.ts
40915
41242
  var import_node_server_utils140 = require("@7365admin1/node-server-utils");
40916
41243
  var import_mongodb85 = require("mongodb");
40917
-
40918
- // src/services/notification.service.ts
40919
- var import_iservice365_expo_notifications = require("iservice365-expo-notifications");
40920
-
40921
- // src/repositories/push-token.repository.ts
40922
- var PushTokenRepo = class {
40923
- static collection() {
40924
- return getDB().collection("push_tokens");
40925
- }
40926
- static async createIndexes() {
40927
- await Promise.all([
40928
- this.collection().createIndex({ token: 1 }, { unique: true }),
40929
- this.collection().createIndex({ userId: 1, platform: 1 }),
40930
- this.collection().createIndex({ siteId: 1 })
40931
- ]);
40932
- }
40933
- static async upsert(userId, token, platform, siteId, projectId, appSlug) {
40934
- const now = /* @__PURE__ */ new Date();
40935
- const p = platform;
40936
- const existing = await this.collection().findOne({ token });
40937
- if (existing) {
40938
- await this.collection().updateOne(
40939
- { token },
40940
- {
40941
- $set: {
40942
- userId,
40943
- platform: p,
40944
- siteId,
40945
- projectId,
40946
- appSlug,
40947
- updatedAt: now
40948
- }
40949
- }
40950
- );
40951
- return;
40952
- }
40953
- await this.collection().deleteMany({ userId, platform: p });
40954
- await this.collection().insertOne({
40955
- userId,
40956
- siteId,
40957
- token,
40958
- platform: p,
40959
- projectId,
40960
- appSlug,
40961
- createdAt: now,
40962
- updatedAt: now
40963
- });
40964
- }
40965
- static async remove(token) {
40966
- await this.collection().deleteMany({ token });
40967
- }
40968
- static async findTokensByUserIds(userIds, appSlug) {
40969
- const docs = await this.collection().find({ userId: { $in: userIds }, appSlug: { $eq: appSlug } }).toArray();
40970
- return docs.map((d) => d.token);
40971
- }
40972
- };
40973
-
40974
- // src/services/notification.service.ts
40975
- function toStringArray(recipient) {
40976
- const arr = Array.isArray(recipient) ? recipient : [recipient];
40977
- return arr.map((r) => r.toString());
40978
- }
40979
- async function send(userIds, title, body, data, appSlug) {
40980
- try {
40981
- const tokens = Array.from(
40982
- new Set(await PushTokenRepo.findTokensByUserIds(userIds, appSlug))
40983
- );
40984
- if (!tokens.length)
40985
- return;
40986
- for (const token of tokens) {
40987
- await (0, import_iservice365_expo_notifications.sendExpoPushNotifications)([token], { title, body, data });
40988
- }
40989
- } catch (error) {
40990
- console.warn("[NotificationService]", error);
40991
- }
40992
- }
40993
- var NotificationService = class {
40994
- static async bulletinBoardCreated(payload) {
40995
- await send(
40996
- toStringArray(payload.to),
40997
- "Bulletin Board",
40998
- `There is new ${payload.status} bulletin board.`,
40999
- {
41000
- bulletinId: payload.bulletinId.toString(),
41001
- status: payload.status,
41002
- module: "feedback",
41003
- screen: "/(user)/bulletinInfo",
41004
- params: {
41005
- id: payload.bulletinId.toString()
41006
- }
41007
- },
41008
- "iservice365-resident-mobile-app"
41009
- );
41010
- }
41011
- static async prelovedMarketplacePostCreation(payload) {
41012
- await send(
41013
- toStringArray(payload.to),
41014
- "Preloved Marketplace",
41015
- `New preloved marketplace post added.`,
41016
- {
41017
- prelovedId: payload.prelovedId.toString(),
41018
- status: payload.status,
41019
- module: "prelovedMarketplace",
41020
- screen: "/(user)/(marketplace)/prelovedPostInfo",
41021
- params: {
41022
- id: payload.prelovedId.toString()
41023
- }
41024
- },
41025
- "iservice365-resident-mobile-app"
41026
- );
41027
- }
41028
- };
41029
-
41030
- // src/services/bulletin-board.service.ts
41031
41244
  function useBulletinBoardService() {
41032
41245
  const {
41033
41246
  add: _add,
@@ -41094,6 +41307,12 @@ function useBulletinBoardService() {
41094
41307
  status: bulletinBoardStatus
41095
41308
  });
41096
41309
  }
41310
+ NotificationService.bulletinBoardCreatedForMA({
41311
+ to: userIds,
41312
+ bulletinId: bulletinBoardId,
41313
+ subject: "Bulletin Board",
41314
+ status: bulletinBoardStatus
41315
+ });
41097
41316
  }
41098
41317
  await session?.commitTransaction();
41099
41318
  return "Successfully added bulletin board.";
@@ -43021,11 +43240,27 @@ function useEventManagementService() {
43021
43240
  updateEventManagementById: _updateEventManagementById,
43022
43241
  processCompletedEvents: _processCompletedEvents
43023
43242
  } = useEventManagementRepo();
43243
+ const { getUsersBySiteId } = useMemberRepo();
43024
43244
  async function add(value) {
43025
43245
  const session = import_node_server_utils151.useAtlas.getClient()?.startSession();
43026
43246
  try {
43027
43247
  session?.startTransaction();
43028
- await _add(value, session);
43248
+ const response = await _add(value, session);
43249
+ console.log("response", response);
43250
+ const users = await getUsersBySiteId({
43251
+ status: "active",
43252
+ siteId: value.site
43253
+ });
43254
+ if (users?.length > 0) {
43255
+ const userIds = Array.from(
43256
+ new Set(users.map((item) => item.user.toString()))
43257
+ );
43258
+ NotificationService.eventCreatedForMA({
43259
+ to: userIds,
43260
+ eventId: response,
43261
+ status: value.status
43262
+ });
43263
+ }
43029
43264
  await session?.commitTransaction();
43030
43265
  return "Successfully added event.";
43031
43266
  } catch (error) {
@@ -56381,73 +56616,6 @@ var Period = /* @__PURE__ */ ((Period2) => {
56381
56616
  Period2["THIS_MONTH"] = "thisMonth";
56382
56617
  return Period2;
56383
56618
  })(Period || {});
56384
- function getPeriodRangeWithPrevious(period) {
56385
- const now = /* @__PURE__ */ new Date();
56386
- let currentStart = /* @__PURE__ */ new Date();
56387
- let currentEnd = /* @__PURE__ */ new Date();
56388
- let previousStart = /* @__PURE__ */ new Date();
56389
- let previousEnd = /* @__PURE__ */ new Date();
56390
- if (period === "today" /* TODAY */) {
56391
- currentStart.setHours(0, 0, 0, 0);
56392
- currentEnd.setHours(23, 59, 59, 999);
56393
- previousStart = new Date(currentStart);
56394
- previousStart.setDate(previousStart.getDate() - 1);
56395
- previousEnd = new Date(currentEnd);
56396
- previousEnd.setDate(previousEnd.getDate() - 1);
56397
- } else if (period === "thisWeek" /* THIS_WEEK */) {
56398
- const day = now.getDay();
56399
- const diffToMonday = day === 0 ? -6 : 1 - day;
56400
- currentStart = new Date(now);
56401
- currentStart.setDate(now.getDate() + diffToMonday);
56402
- currentStart.setHours(0, 0, 0, 0);
56403
- currentEnd = new Date(currentStart);
56404
- currentEnd.setDate(currentStart.getDate() + 6);
56405
- currentEnd.setHours(23, 59, 59, 999);
56406
- previousStart = new Date(currentStart);
56407
- previousStart.setDate(previousStart.getDate() - 7);
56408
- previousEnd = new Date(currentEnd);
56409
- previousEnd.setDate(previousEnd.getDate() - 7);
56410
- } else if (period === "thisMonth" /* THIS_MONTH */) {
56411
- currentStart = new Date(now.getFullYear(), now.getMonth(), 1);
56412
- currentEnd = new Date(
56413
- now.getFullYear(),
56414
- now.getMonth() + 1,
56415
- 0,
56416
- 23,
56417
- 59,
56418
- 59,
56419
- 999
56420
- );
56421
- previousStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
56422
- previousEnd = new Date(
56423
- now.getFullYear(),
56424
- now.getMonth(),
56425
- 0,
56426
- 23,
56427
- 59,
56428
- 59,
56429
- 999
56430
- );
56431
- } else {
56432
- throw new import_node_server_utils199.BadRequestError("Invalid period.");
56433
- }
56434
- return {
56435
- current: {
56436
- start: currentStart.toISOString(),
56437
- end: currentEnd.toISOString()
56438
- },
56439
- previous: {
56440
- start: previousStart.toISOString(),
56441
- end: previousEnd.toISOString()
56442
- }
56443
- };
56444
- }
56445
- function calculatePercentage(current, previous) {
56446
- if (previous === 0) {
56447
- return current === 0 ? 0 : 100;
56448
- }
56449
- return Number(((current - previous) / previous * 100).toFixed(2));
56450
- }
56451
56619
  function useNewDashboardRepo() {
56452
56620
  const db = import_node_server_utils199.useAtlas.getDb();
56453
56621
  if (!db) {
@@ -56956,7 +57124,8 @@ function useNewDashboardRepo() {
56956
57124
  currentlyOnSiteCount,
56957
57125
  facilityReport,
56958
57126
  yesterdayFacilityReport,
56959
- todayFacilityReport
57127
+ todayFacilityReport,
57128
+ workOrderStatusReport
56960
57129
  ] = await Promise.all([
56961
57130
  workOrderCollection.aggregate([
56962
57131
  {
@@ -57146,6 +57315,20 @@ function useNewDashboardRepo() {
57146
57315
  }
57147
57316
  },
57148
57317
  { $count: "count" }
57318
+ ]).toArray(),
57319
+ workOrderCollection.aggregate([
57320
+ {
57321
+ $match: {
57322
+ site: { $in: [siteIdObj, siteId] },
57323
+ createdAt: periodRange
57324
+ }
57325
+ },
57326
+ {
57327
+ $group: {
57328
+ _id: "$status",
57329
+ count: { $sum: 1 }
57330
+ }
57331
+ }
57149
57332
  ]).toArray()
57150
57333
  ]);
57151
57334
  const wFacet = workOrderReport[0] ?? { total: [], inProgress: [] };
@@ -57154,6 +57337,23 @@ function useNewDashboardRepo() {
57154
57337
  ongoing: [],
57155
57338
  waitingApproval: []
57156
57339
  };
57340
+ const workOrderStatus = {
57341
+ pending: 0,
57342
+ inProgress: 0,
57343
+ completed: 0
57344
+ };
57345
+ for (const item of workOrderStatusReport || []) {
57346
+ const rawStatus = String(item._id || "").toLowerCase().trim();
57347
+ if (rawStatus === "to-do" || rawStatus === "for-review") {
57348
+ workOrderStatus.pending += item.count || 0;
57349
+ } else if (rawStatus === "in-progress") {
57350
+ workOrderStatus.inProgress += item.count || 0;
57351
+ } else if (rawStatus === "completed") {
57352
+ workOrderStatus.completed += item.count || 0;
57353
+ } else {
57354
+ workOrderStatus.pending += item.count || 0;
57355
+ }
57356
+ }
57157
57357
  const data = {
57158
57358
  openWorkOrder: {
57159
57359
  count: wFacet.total[0]?.count ?? 0,
@@ -57188,6 +57388,7 @@ function useNewDashboardRepo() {
57188
57388
  yesterdayFacilityReport[0]?.count ?? 0
57189
57389
  )
57190
57390
  },
57391
+ workOrderStatus,
57191
57392
  upcomingEvents,
57192
57393
  todayReminders,
57193
57394
  todayAttentions
@@ -65768,7 +65969,8 @@ var schemaUpdateChatPreloved = import_joi141.default.object({
65768
65969
  reactions: import_joi141.default.string().optional().allow("", null)
65769
65970
  });
65770
65971
  var schemaChatPreloved = import_joi141.default.object({
65771
- channelId: import_joi141.default.string().hex().length(24).required(),
65972
+ channelId: import_joi141.default.string().hex().length(24).optional().allow("", null),
65973
+ receiverId: import_joi141.default.string().hex().length(24).optional().allow("", null),
65772
65974
  senderId: import_joi141.default.string().hex().length(24).required(),
65773
65975
  postId: import_joi141.default.string().hex().length(24).optional().allow("", null),
65774
65976
  message: schemaMessage.required(),
@@ -65815,7 +66017,7 @@ function MChatPreloved(value) {
65815
66017
  }
65816
66018
  return {
65817
66019
  _id: new import_mongodb145.ObjectId(),
65818
- channelId: value.channelId ?? "",
66020
+ channelId: value.channelId ?? null,
65819
66021
  senderId: value.senderId ?? "",
65820
66022
  postId: value.postId ?? null,
65821
66023
  message: {
@@ -66045,7 +66247,130 @@ function useChannelPrelovedRepo() {
66045
66247
  throw error;
66046
66248
  }
66047
66249
  }
66048
- return { add, getByParticipants, getChannelMessages };
66250
+ async function getChatLists(currentUserId, page = 1, limit = 10, search) {
66251
+ const normalizedPage = page > 0 ? page - 1 : 0;
66252
+ const normalizedLimit = limit || 10;
66253
+ const _currentUserId = new import_mongodb148.ObjectId(currentUserId);
66254
+ const escapedSearch = search ? search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") : null;
66255
+ const pipeline = [
66256
+ {
66257
+ $match: {
66258
+ $or: [{ receiverId: _currentUserId }, { senderId: _currentUserId }]
66259
+ }
66260
+ },
66261
+ {
66262
+ $lookup: {
66263
+ from: "users",
66264
+ localField: "senderId",
66265
+ foreignField: "_id",
66266
+ pipeline: [
66267
+ {
66268
+ $project: {
66269
+ name: 1,
66270
+ profile: 1,
66271
+ type: 1
66272
+ }
66273
+ }
66274
+ ],
66275
+ as: "senderId"
66276
+ }
66277
+ },
66278
+ { $unwind: { path: "$senderId", preserveNullAndEmptyArrays: true } },
66279
+ {
66280
+ $lookup: {
66281
+ from: "post-preloved",
66282
+ localField: "postId",
66283
+ foreignField: "_id",
66284
+ pipeline: [
66285
+ {
66286
+ $project: {
66287
+ title: 1,
66288
+ description: 1,
66289
+ attachments: 1,
66290
+ price: 1,
66291
+ status: 1,
66292
+ createdBy: 1,
66293
+ reserverId: 1
66294
+ }
66295
+ }
66296
+ ],
66297
+ as: "postDetails"
66298
+ }
66299
+ },
66300
+ { $unwind: { path: "$postDetails", preserveNullAndEmptyArrays: true } },
66301
+ ...escapedSearch ? [
66302
+ {
66303
+ $match: {
66304
+ $or: [
66305
+ {
66306
+ "senderId.name": {
66307
+ $regex: new RegExp(escapedSearch, "i")
66308
+ }
66309
+ },
66310
+ {
66311
+ "postDetails.title": {
66312
+ $regex: new RegExp(escapedSearch, "i")
66313
+ }
66314
+ }
66315
+ ]
66316
+ }
66317
+ }
66318
+ ] : [],
66319
+ {
66320
+ $lookup: {
66321
+ from: "chat-preloved",
66322
+ localField: "_id",
66323
+ foreignField: "channelId",
66324
+ pipeline: [
66325
+ { $match: { deletedAt: null } },
66326
+ { $sort: { createdAt: -1 } },
66327
+ { $limit: 1 }
66328
+ ],
66329
+ as: "latestChat"
66330
+ }
66331
+ },
66332
+ { $unwind: { path: "$latestChat", preserveNullAndEmptyArrays: true } },
66333
+ { $addFields: { lastMessageDate: "$latestChat.createdAt" } },
66334
+ {
66335
+ $lookup: {
66336
+ from: "bid-preloved",
66337
+ localField: "postId",
66338
+ foreignField: "postId",
66339
+ pipeline: [
66340
+ { $sort: { createdAt: -1 } },
66341
+ { $limit: 1 },
66342
+ { $project: { price: 1, message: 1, status: 1, type: 1 } }
66343
+ ],
66344
+ as: "latestBidDetails"
66345
+ }
66346
+ },
66347
+ {
66348
+ $unwind: {
66349
+ path: "$latestBidDetails",
66350
+ preserveNullAndEmptyArrays: true
66351
+ }
66352
+ },
66353
+ { $sort: { lastMessageDate: -1 } },
66354
+ {
66355
+ $facet: {
66356
+ totalCount: [{ $count: "count" }],
66357
+ items: [
66358
+ { $skip: normalizedPage * normalizedLimit },
66359
+ { $limit: normalizedLimit }
66360
+ ]
66361
+ }
66362
+ }
66363
+ ];
66364
+ try {
66365
+ const result = await collection.aggregate(pipeline).toArray();
66366
+ const totalCount = result[0].totalCount[0]?.count ?? 0;
66367
+ const items = result[0].items;
66368
+ return (0, import_node_server_utils246.paginate)(items, normalizedPage, normalizedLimit, totalCount);
66369
+ } catch (error) {
66370
+ throw error;
66371
+ }
66372
+ }
66373
+ return { add, getByParticipants, getChatLists, getChannelMessages };
66049
66374
  }
66050
66375
 
66051
66376
  // src/services/chat-preloved.service.ts
@@ -66163,7 +66488,12 @@ function useChatPrelovedController() {
66163
66488
  var import_node_server_utils249 = require("@7365admin1/node-server-utils");
66164
66489
  var import_joi144 = __toESM(require("joi"));
66165
66490
  function useChannelPrelovedController() {
66166
- const { add: _add, getChannelMessages: _getChannelMessages } = useChannelPrelovedRepo();
66491
+ const {
66492
+ add: _add,
66493
+ getByParticipants: _getByParticipants,
66494
+ getChatLists: _getChatLists,
66495
+ getChannelMessages: _getChannelMessages
66496
+ } = useChannelPrelovedRepo();
66167
66497
  async function add(req, res, next) {
66168
66498
  const { error, value } = schemaChannelPreloved.validate(req.body, {
66169
66499
  abortEarly: false
@@ -66200,9 +66530,7 @@ function useChannelPrelovedController() {
66200
66530
  next(new import_node_server_utils249.BadRequestError(paramError.message));
66201
66531
  return;
66202
66532
  }
66203
- const { error: queryError, value: query } = querySchema.validate(
66204
- req.query
66205
- );
66533
+ const { error: queryError, value: query } = querySchema.validate(req.query);
66206
66534
  if (queryError) {
66207
66535
  import_node_server_utils249.logger.log({ level: "error", message: queryError.message });
66208
66536
  next(new import_node_server_utils249.BadRequestError(queryError.message));
@@ -66222,7 +66550,57 @@ function useChannelPrelovedController() {
66222
66550
  next(error);
66223
66551
  }
66224
66552
  }
66225
- return { add, getChannelMessages };
66553
+ async function getChannel(req, res, next) {
66554
+ const querySchema = import_joi144.default.object({
66555
+ postId: import_joi144.default.string().hex().length(24).required(),
66556
+ receiverId: import_joi144.default.string().hex().length(24).required(),
66557
+ senderId: import_joi144.default.string().hex().length(24).required()
66558
+ });
66559
+ const { error, value } = querySchema.validate(req.query);
66560
+ if (error) {
66561
+ import_node_server_utils249.logger.log({ level: "error", message: error.message });
66562
+ next(new import_node_server_utils249.BadRequestError(error.message));
66563
+ return;
66564
+ }
66565
+ try {
66566
+ const data = await _getByParticipants(
66567
+ value.senderId,
66568
+ value.receiverId,
66569
+ value.postId
66570
+ );
66571
+ res.status(200).json(data);
66572
+ } catch (error2) {
66573
+ import_node_server_utils249.logger.log({ level: "error", message: error2.message });
66574
+ next(error2);
66575
+ }
66576
+ }
66577
+ async function getChatLists(req, res, next) {
66578
+ const querySchema = import_joi144.default.object({
66579
+ currentUserId: import_joi144.default.string().hex().length(24).required(),
66580
+ page: import_joi144.default.number().integer().min(1).default(1),
66581
+ limit: import_joi144.default.number().integer().min(1).max(100).default(10),
66582
+ search: import_joi144.default.string().optional().allow("", null)
66583
+ });
66584
+ const { error, value } = querySchema.validate(req.query);
66585
+ if (error) {
66586
+ import_node_server_utils249.logger.log({ level: "error", message: error.message });
66587
+ next(new import_node_server_utils249.BadRequestError(error.message));
66588
+ return;
66589
+ }
66590
+ try {
66591
+ const data = await _getChatLists(
66592
+ value.currentUserId,
66593
+ value.page,
66594
+ value.limit,
66595
+ value.search || void 0
66596
+ );
66597
+ res.status(200).json(data);
66598
+ } catch (error2) {
66599
+ import_node_server_utils249.logger.log({ level: "error", message: error2.message });
66600
+ next(error2);
66601
+ }
66602
+ }
66603
+ return { add, getChannel, getChatLists, getChannelMessages };
66226
66604
  }
66227
66605
 
66228
66606
  // src/models/online-forms-v2.model.ts
@@ -66446,7 +66824,23 @@ function useFormEntryRepo() {
66446
66824
  { $match: query },
66447
66825
  { $sort: sort },
66448
66826
  { $skip: page * limit },
66449
- { $limit: limit }
66827
+ { $limit: limit },
66828
+ {
66829
+ $lookup: {
66830
+ from: "users",
66831
+ localField: "userId",
66832
+ foreignField: "_id",
66833
+ as: "user",
66834
+ pipeline: [{ $project: { name: 1 } }]
66835
+ }
66836
+ },
66837
+ { $unwind: { path: "$user", preserveNullAndEmptyArrays: true } },
66838
+ {
66839
+ $addFields: {
66840
+ name: { $ifNull: ["$user.name", "$name"] }
66841
+ }
66842
+ },
66843
+ { $project: { user: 0 } }
66450
66844
  ]).toArray();
66451
66845
  const length = await collection.countDocuments(query);
66452
66846
  const data = (0, import_node_server_utils250.paginate)(items, page, limit, length);
@@ -67217,7 +67611,6 @@ function useBuildingLevelController() {
67217
67611
  building_units_namespace_collection,
67218
67612
  buildings_namespace_collection,
67219
67613
  bulletin_boards_namespace_collection,
67220
- calculatePercentage,
67221
67614
  chatSchema,
67222
67615
  createManpowerRemarksDaily,
67223
67616
  customerSchema,
@@ -67228,7 +67621,6 @@ function useBuildingLevelController() {
67228
67621
  feedbacks2_namespace_collection,
67229
67622
  feedbacks_namespace_collection,
67230
67623
  formatDahuaDate,
67231
- getPeriodRangeWithPrevious,
67232
67624
  guests_namespace_collection,
67233
67625
  incidentReportLog,
67234
67626
  incidents_namespace_collection,