@7365admin1/core 3.26.0 → 3.27.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ad3a683: release changes today
8
+
3
9
  ## 3.26.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -174,6 +174,12 @@ declare function useUserRepo(): {
174
174
  sid: string;
175
175
  }, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
176
176
  updateUserOrgById: (id: string | ObjectId, org: string | ObjectId, session?: ClientSession) => Promise<string>;
177
+ updateUserUnitById: (id: string | ObjectId, value: {
178
+ block?: ObjectId | null;
179
+ level?: ObjectId | null;
180
+ unitId?: ObjectId | null;
181
+ unitName?: string;
182
+ }, session?: ClientSession) => Promise<"No user unit fields to update." | "Successfully updated user unit information.">;
177
183
  };
178
184
 
179
185
  declare function useUserController(): {
@@ -2874,6 +2880,7 @@ type TVisitorTransaction = {
2874
2880
  inviterId?: string | ObjectId;
2875
2881
  createdBy?: string | ObjectId;
2876
2882
  updatedBy?: string | ObjectId;
2883
+ isMembersAdded?: boolean;
2877
2884
  };
2878
2885
  declare const schemaVisitorTransaction: Joi.ObjectSchema<any>;
2879
2886
  declare const schemaUpdateVisTrans: Joi.ObjectSchema<any>;
@@ -5087,6 +5094,7 @@ declare function useNfcPatrolTagRepo(): {
5087
5094
  },
5088
5095
  ClientSession?
5089
5096
  ]) => Promise<mongodb.UpdateResult<bson.Document>>;
5097
+ getById: (_id: string | ObjectId, session?: ClientSession) => Promise<mongodb.WithId<bson.Document>>;
5090
5098
  };
5091
5099
 
5092
5100
  declare enum DOBStatus {
@@ -6036,15 +6044,24 @@ declare function useNfcPatrolLogRepo(): {
6036
6044
  pages: number;
6037
6045
  pageRange: string;
6038
6046
  } | TNfcPatrolLog>;
6047
+ getById: (id: string | ObjectId, session?: ClientSession) => Promise<mongodb.WithId<bson.Document> | null>;
6048
+ updateCheckpoint: (id: string | ObjectId, checkpointIndex: number, payload: any, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
6039
6049
  };
6040
6050
 
6041
6051
  declare function useNfcPatrolLogService(): {
6042
6052
  add: (value: TNfcPatrolLog) => Promise<string>;
6053
+ completeCheckpoint: (logId: string, payload: {
6054
+ checkpointIndex: number;
6055
+ uid: string;
6056
+ action: "complete" | "skip";
6057
+ skippedRemarks?: string;
6058
+ }) => Promise<string>;
6043
6059
  };
6044
6060
 
6045
6061
  declare function useNfcPatrolLogController(): {
6046
6062
  add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6047
6063
  getAllBySite: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6064
+ completeCheckpoint: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6048
6065
  };
6049
6066
 
6050
6067
  declare function useAddressRepo(): {
package/dist/index.js CHANGED
@@ -9141,6 +9141,31 @@ function useUserRepo() {
9141
9141
  throw new import_node_server_utils10.InternalServerError("Failed to update user organization.");
9142
9142
  }
9143
9143
  }
9144
+ async function updateUserUnitById(id, value, session) {
9145
+ const _id = (0, import_node_server_utils10.toObjectId)(id);
9146
+ const update = {};
9147
+ if ("block" in value)
9148
+ update.block = value.block ?? null;
9149
+ if ("level" in value)
9150
+ update.level = value.level ?? null;
9151
+ if ("unitId" in value)
9152
+ update.unitId = value.unitId ?? null;
9153
+ if ("unitName" in value)
9154
+ update.unitName = value.unitName ?? "";
9155
+ if (Object.keys(update).length === 0) {
9156
+ return "No user unit fields to update.";
9157
+ }
9158
+ try {
9159
+ await collection.updateOne(
9160
+ { _id },
9161
+ { $set: { ...update, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
9162
+ { session }
9163
+ );
9164
+ return "Successfully updated user unit information.";
9165
+ } catch (error) {
9166
+ throw new import_node_server_utils10.InternalServerError("Failed to update user unit information.");
9167
+ }
9168
+ }
9144
9169
  return {
9145
9170
  createIndex,
9146
9171
  createTextIndex,
@@ -9159,7 +9184,8 @@ function useUserRepo() {
9159
9184
  getUserByEmailStatus,
9160
9185
  updateUserSIDById,
9161
9186
  resetPassword,
9162
- updateUserOrgById
9187
+ updateUserOrgById,
9188
+ updateUserUnitById
9163
9189
  };
9164
9190
  }
9165
9191
 
@@ -25401,6 +25427,10 @@ function usePersonRepo() {
25401
25427
  }
25402
25428
  async function getByNRIC(value) {
25403
25429
  try {
25430
+ if (!value || value.trim() === "") {
25431
+ import_node_server_utils74.logger.warn("getByNRIC called with an empty or invalid NRIC value.");
25432
+ return null;
25433
+ }
25404
25434
  const cacheKey = (0, import_node_server_utils74.makeCacheKey)(site_people_namespace_collection, {
25405
25435
  nric: value
25406
25436
  });
@@ -25449,8 +25479,11 @@ function usePersonRepo() {
25449
25479
  unit
25450
25480
  }, session) {
25451
25481
  try {
25482
+ if (!unit || !import_mongodb45.ObjectId.isValid(unit)) {
25483
+ throw new import_node_server_utils74.BadRequestError("Invalid unit ID.");
25484
+ }
25452
25485
  const query = {
25453
- unit,
25486
+ unit: new import_mongodb45.ObjectId(unit),
25454
25487
  status,
25455
25488
  ...Array.isArray(type) && type.length > 0 && {
25456
25489
  type: { $in: type }
@@ -26419,18 +26452,7 @@ function useBuildingUnitRepo() {
26419
26452
  } catch (error) {
26420
26453
  throw new import_node_server_utils76.BadRequestError("Invalid ID.");
26421
26454
  }
26422
- const cacheKey = (0, import_node_server_utils76.makeCacheKey)(building_units_namespace_collection, {
26423
- _id: String(_id)
26424
- });
26425
26455
  try {
26426
- const cached = await getCache(cacheKey);
26427
- if (cached) {
26428
- import_node_server_utils76.logger.log({
26429
- level: "info",
26430
- message: `Cache hit for getById building unit: ${cacheKey}`
26431
- });
26432
- return cached;
26433
- }
26434
26456
  const result = await collection.findOne({
26435
26457
  _id,
26436
26458
  deletedAt: { $in: ["", null] }
@@ -26438,17 +26460,6 @@ function useBuildingUnitRepo() {
26438
26460
  if (!result) {
26439
26461
  throw new import_node_server_utils76.BadRequestError("Building unit not found.");
26440
26462
  }
26441
- setCache(cacheKey, result, 300).then(() => {
26442
- import_node_server_utils76.logger.log({
26443
- level: "info",
26444
- message: `Cache set for building unit by id: ${cacheKey}`
26445
- });
26446
- }).catch((err) => {
26447
- import_node_server_utils76.logger.log({
26448
- level: "error",
26449
- message: `Failed to set cache for building unit by id: ${err.message}`
26450
- });
26451
- });
26452
26463
  return result;
26453
26464
  } catch (error) {
26454
26465
  if (error instanceof import_node_server_utils76.AppError) {
@@ -34904,7 +34915,7 @@ function useVisitorTransactionService() {
34904
34915
  const unit = await _getUnitById(value.unit);
34905
34916
  value.unitName = unit?.name;
34906
34917
  }
34907
- if (allowedPersonTypes.includes(value?.type)) {
34918
+ if (allowedPersonTypes.includes(value?.type) && value?.nric) {
34908
34919
  const nric = value?.nric || "";
34909
34920
  const person = await getByNRIC(nric);
34910
34921
  const existingCompanyName = person?.companyName?.includes(
@@ -35136,6 +35147,103 @@ function useVisitorTransactionService() {
35136
35147
  let host;
35137
35148
  let username;
35138
35149
  let password;
35150
+ if (value.checkIn) {
35151
+ const parsed = new Date(value.checkIn);
35152
+ value.checkIn = isNaN(parsed.getTime()) ? null : parsed;
35153
+ }
35154
+ if (value.isMembersAdded != true && Array.isArray(value.members) && value.members.length > 0) {
35155
+ const chunkSize = 10;
35156
+ const {
35157
+ block,
35158
+ level,
35159
+ unit,
35160
+ site,
35161
+ org,
35162
+ type,
35163
+ company,
35164
+ remarks,
35165
+ contractorType,
35166
+ unitName
35167
+ } = value;
35168
+ for (let i = 0; i < value.members.length; i += chunkSize) {
35169
+ const chunk = value.members.slice(i, i + chunkSize);
35170
+ await Promise.all(
35171
+ chunk.map(async (member) => {
35172
+ const clonedMember = structuredClone(member);
35173
+ const { visitorPass, passKeys } = clonedMember;
35174
+ const preparedVisitorPass = Array.isArray(visitorPass) ? visitorPass.map((item) => ({
35175
+ ...item,
35176
+ receivedDate: /* @__PURE__ */ new Date(),
35177
+ status: "Not Returned" /* NOT_RETURNED */,
35178
+ lastUpdate: null,
35179
+ remarks: ""
35180
+ })) : [];
35181
+ const preparedPassKeys = Array.isArray(passKeys) ? passKeys.map((item) => ({
35182
+ ...item,
35183
+ receivedDate: /* @__PURE__ */ new Date(),
35184
+ status: "Not Returned" /* NOT_RETURNED */,
35185
+ lastUpdate: null,
35186
+ remarks: ""
35187
+ })) : [];
35188
+ const visitorId = await _add(
35189
+ {
35190
+ ...clonedMember,
35191
+ block,
35192
+ level,
35193
+ unit,
35194
+ unitName,
35195
+ site,
35196
+ org,
35197
+ type,
35198
+ company,
35199
+ remarks,
35200
+ contractorType,
35201
+ checkIn: value.checkIn,
35202
+ visitorPass: preparedVisitorPass,
35203
+ passKeys: preparedPassKeys,
35204
+ status: "registered" /* REGISTERED */
35205
+ },
35206
+ session
35207
+ );
35208
+ console.log("visitorId service", visitorId);
35209
+ for (const item of preparedVisitorPass) {
35210
+ await KeyRepo.checkPassOrKeyAvailability(item.keyId, "Pass", session);
35211
+ await KeyRepo.updateKeyById(
35212
+ item.keyId,
35213
+ {
35214
+ status: "In Use" /* IN_USE */,
35215
+ updatedBy: value.createdBy
35216
+ },
35217
+ value.site,
35218
+ session,
35219
+ void 0,
35220
+ visitorId,
35221
+ void 0,
35222
+ true
35223
+ );
35224
+ }
35225
+ for (const item of preparedPassKeys) {
35226
+ await KeyRepo.checkPassOrKeyAvailability(item.keyId, "Key", session);
35227
+ await KeyRepo.updateKeyById(
35228
+ item.keyId,
35229
+ {
35230
+ status: "In Use" /* IN_USE */,
35231
+ updatedBy: value.createdBy,
35232
+ visitorId
35233
+ },
35234
+ value.site,
35235
+ session,
35236
+ void 0,
35237
+ visitorId,
35238
+ void 0,
35239
+ true
35240
+ );
35241
+ }
35242
+ })
35243
+ );
35244
+ }
35245
+ value.isMembersAdded = true;
35246
+ }
35139
35247
  if (value.site && value.plateNumber) {
35140
35248
  try {
35141
35249
  camera = await _getVisitorsInBySite(value.site);
@@ -35169,10 +35277,6 @@ function useVisitorTransactionService() {
35169
35277
  if (found === 1)
35170
35278
  throw new import_node_server_utils107.BadRequestError("This plate number is blocklisted");
35171
35279
  }
35172
- if (value.checkIn) {
35173
- const parsed = new Date(value.checkIn);
35174
- value.checkIn = isNaN(parsed.getTime()) ? null : parsed;
35175
- }
35176
35280
  if (value.checkOut) {
35177
35281
  const parsed = new Date(value.checkOut);
35178
35282
  value.checkOut = isNaN(parsed.getTime()) ? null : parsed;
@@ -36216,7 +36320,8 @@ function usePersonService() {
36216
36320
  getUserByEmail,
36217
36321
  updateUserFieldById: _updateUserFieldById,
36218
36322
  getUserById,
36219
- updateUserOrgById: _updateUserOrgById
36323
+ updateUserOrgById: _updateUserOrgById,
36324
+ updateUserUnitById: _updateUserUnitById
36220
36325
  } = useUserRepo();
36221
36326
  const { add: addMember } = useMemberRepo();
36222
36327
  const { getById: _getUnitById, updateById: updateUnitById } = useBuildingUnitRepo();
@@ -36363,6 +36468,10 @@ function usePersonService() {
36363
36468
  value.unit = new import_mongodb66.ObjectId(value.unit);
36364
36469
  }
36365
36470
  const isOrgChanged = value.org && person.org?.toString() !== value.org.toString();
36471
+ const toKey = (v) => v === null || v === void 0 || v === "" ? "" : v.toString();
36472
+ const isBlockChanged = "block" in value && toKey(value.block) !== toKey(person.block);
36473
+ const isLevelChanged = "level" in value && toKey(value.level) !== toKey(person.level);
36474
+ const isUnitChanged = "unit" in value && toKey(value.unit) !== toKey(person.unit);
36366
36475
  await _updateById(_id, value, session);
36367
36476
  if (isOrgChanged && person.user) {
36368
36477
  await _updateUserOrgById(
@@ -36371,6 +36480,26 @@ function usePersonService() {
36371
36480
  session
36372
36481
  );
36373
36482
  }
36483
+ if ((isBlockChanged || isLevelChanged || isUnitChanged) && person.user) {
36484
+ const userUnitPayload = {};
36485
+ if (isBlockChanged) {
36486
+ userUnitPayload.block = value.block ?? null;
36487
+ }
36488
+ if (isLevelChanged) {
36489
+ userUnitPayload.level = value.level ?? null;
36490
+ }
36491
+ if (isUnitChanged) {
36492
+ userUnitPayload.unitId = value.unit ?? null;
36493
+ if ("unitName" in value) {
36494
+ userUnitPayload.unitName = value.unitName ?? "";
36495
+ }
36496
+ }
36497
+ await _updateUserUnitById(
36498
+ person.user.toString(),
36499
+ userUnitPayload,
36500
+ session
36501
+ );
36502
+ }
36374
36503
  if (value.unit && (isNameUpdated || isOwnerChanged || value.isOwner)) {
36375
36504
  const unit = await _getUnitById(value.unit.toString());
36376
36505
  if (unit) {
@@ -36400,6 +36529,16 @@ function usePersonService() {
36400
36529
  }
36401
36530
  }
36402
36531
  }
36532
+ if (isUnitChanged && person.isOwner && person.unit) {
36533
+ const previousUnit = await _getUnitById(person.unit.toString());
36534
+ if (previousUnit && previousUnit._id && previousUnit.owner?.toString() === person?._id?.toString()) {
36535
+ await updateUnitById(
36536
+ previousUnit._id.toString(),
36537
+ { owner: "", ownerName: "" },
36538
+ session
36539
+ );
36540
+ }
36541
+ }
36403
36542
  await session.commitTransaction();
36404
36543
  return "Person updated successfully.";
36405
36544
  } catch (error) {
@@ -45304,7 +45443,6 @@ function useSiteUnitBillingService() {
45304
45443
  const { getAll, updateById: _updateById } = useSiteBillingItemRepo();
45305
45444
  const { getBuildingUnitsWithOwner: _getBuildingUnitsWithOwner } = useBuildingUnitRepo();
45306
45445
  async function processBilling() {
45307
- console.log("Starting billing process...");
45308
45446
  const billing_items = await getAll({
45309
45447
  search: "",
45310
45448
  page: 1,
@@ -45347,7 +45485,7 @@ function useSiteUnitBillingService() {
45347
45485
  const buildUnitBilling = (unit) => ({
45348
45486
  site: billing_item.site.toString(),
45349
45487
  org: billing_item.org.toString(),
45350
- billItem: billing_item._id,
45488
+ billItem: billing_item._id?.toString(),
45351
45489
  billName: billing_item.name,
45352
45490
  unitId: unit._id.toString(),
45353
45491
  unit: unit.blockName + " / " + unit.levelName + " / " + unit.name,
@@ -45381,6 +45519,9 @@ function useSiteUnitBillingService() {
45381
45519
  level: "error",
45382
45520
  message: `Failed to proccess cron billing: ${error.message}`
45383
45521
  });
45522
+ if (session.inTransaction()) {
45523
+ await session.abortTransaction();
45524
+ }
45384
45525
  continue;
45385
45526
  } finally {
45386
45527
  session.endSession();
@@ -45435,6 +45576,7 @@ function useSiteUnitBillingService() {
45435
45576
  const billingMonth = Number(billing_item.month);
45436
45577
  const billingDay = Number(billing_item.date);
45437
45578
  if (billing_item.frequency === "monthly" /* MONTHLY */) {
45579
+ console.log("billing_item", billing_item.name);
45438
45580
  return todayDate === billingDay;
45439
45581
  }
45440
45582
  if (billing_item.frequency === "quarterly" /* QAURTERLY */) {
@@ -46566,7 +46708,7 @@ function UseAccessManagementRepo() {
46566
46708
  $lookup: {
46567
46709
  from: "building-levels",
46568
46710
  localField: "_id",
46569
- foreignField: "block",
46711
+ foreignField: "blockId",
46570
46712
  pipeline: [
46571
46713
  { $match: { status: { $ne: "deleted" } } },
46572
46714
  {
@@ -46587,7 +46729,7 @@ function UseAccessManagementRepo() {
46587
46729
  {
46588
46730
  $project: {
46589
46731
  _id: 1,
46590
- level: 1,
46732
+ name: 1,
46591
46733
  units: 1
46592
46734
  }
46593
46735
  }
@@ -46748,7 +46890,7 @@ function UseAccessManagementRepo() {
46748
46890
  $project: {
46749
46891
  _id: "$level.units._id",
46750
46892
  name: "$level.units.name",
46751
- level: { _id: "$level._id", level: "$level.level" },
46893
+ level: { _id: "$level._id", level: "$level.name" },
46752
46894
  block: { _id: "$_id", name: "$name", block: "$block" },
46753
46895
  site: "$site",
46754
46896
  unit_owner: { $arrayElemAt: ["$unitOwner", 0] },
@@ -48357,7 +48499,7 @@ function UseAccessManagementRepo() {
48357
48499
  $lookup: {
48358
48500
  from: "building-levels",
48359
48501
  localField: "_id",
48360
- foreignField: "block",
48502
+ foreignField: "blockId",
48361
48503
  as: "levels",
48362
48504
  pipeline: [
48363
48505
  {
@@ -50843,11 +50985,24 @@ function useNfcPatrolTagRepo() {
50843
50985
  });
50844
50986
  });
50845
50987
  }
50988
+ async function getById(_id, session) {
50989
+ try {
50990
+ _id = typeof _id === "string" ? new import_mongodb99.ObjectId(_id) : _id;
50991
+ } catch {
50992
+ throw new import_node_server_utils161.BadRequestError("Invalid NFC Patrol Tag ID.");
50993
+ }
50994
+ const tag = await collection.findOne({ _id }, { session });
50995
+ if (!tag) {
50996
+ throw new import_node_server_utils161.NotFoundError("NFC Patrol Tag not found.");
50997
+ }
50998
+ return tag;
50999
+ }
50846
51000
  return {
50847
51001
  createIndexes,
50848
51002
  add,
50849
51003
  getAll,
50850
- updateNfcPatrolTagBySite
51004
+ updateNfcPatrolTagBySite,
51005
+ getById
50851
51006
  };
50852
51007
  }
50853
51008
 
@@ -57479,7 +57634,7 @@ var schemaNfcPatrolLog = import_joi110.default.object({
57479
57634
  checkPoints: import_joi110.default.array().items(
57480
57635
  import_joi110.default.object({
57481
57636
  nfcTag_id: import_joi110.default.string().length(24).hex().required(),
57482
- nfcTag_name: import_joi110.default.string().length(24).hex().required(),
57637
+ nfcTag_name: import_joi110.default.string().required(),
57483
57638
  travelTime: import_joi110.default.number().integer().min(0).required(),
57484
57639
  startDateTime: import_joi110.default.date().required().messages({
57485
57640
  "date.base": "startDateTime must be a valid date or ISO string"
@@ -57487,7 +57642,7 @@ var schemaNfcPatrolLog = import_joi110.default.object({
57487
57642
  endDateTime: import_joi110.default.date().required().messages({
57488
57643
  "date.base": "endDateTime must be a valid date or ISO string"
57489
57644
  }),
57490
- status: import_joi110.default.string().valid("Completed", "Skipped").required(),
57645
+ status: import_joi110.default.string().valid("Pending", "Completed", "Skipped").required(),
57491
57646
  skippedRemarks: import_joi110.default.string().required()
57492
57647
  })
57493
57648
  ).min(0).required(),
@@ -57664,17 +57819,59 @@ function useNfcPatrolLogRepo() {
57664
57819
  });
57665
57820
  });
57666
57821
  }
57822
+ async function getById(id, session) {
57823
+ try {
57824
+ id = new import_mongodb121.ObjectId(id);
57825
+ } catch {
57826
+ throw new import_node_server_utils198.BadRequestError("Invalid Log ID.");
57827
+ }
57828
+ return collection.findOne(
57829
+ { _id: id },
57830
+ { session }
57831
+ );
57832
+ }
57833
+ async function updateCheckpoint(id, checkpointIndex, payload, session) {
57834
+ try {
57835
+ id = new import_mongodb121.ObjectId(id);
57836
+ } catch {
57837
+ throw new import_node_server_utils198.BadRequestError("Invalid Log ID.");
57838
+ }
57839
+ const setData = {
57840
+ [`checkPoints.${checkpointIndex}.status`]: payload.action === "complete" ? "Completed" : "Skipped",
57841
+ [`checkPoints.${checkpointIndex}.endDateTime`]: /* @__PURE__ */ new Date()
57842
+ };
57843
+ if (payload.action === "skip") {
57844
+ setData[`checkPoints.${checkpointIndex}.skippedRemarks`] = payload.skippedRemarks;
57845
+ }
57846
+ const res = await collection.updateOne(
57847
+ { _id: id },
57848
+ {
57849
+ $set: setData
57850
+ },
57851
+ { session }
57852
+ );
57853
+ delCachedData();
57854
+ return res;
57855
+ }
57667
57856
  return {
57668
57857
  createIndexes,
57669
57858
  add,
57670
- getAllBySite
57859
+ getAllBySite,
57860
+ getById,
57861
+ updateCheckpoint
57671
57862
  };
57672
57863
  }
57673
57864
 
57674
57865
  // src/services/nfc-patrol-log.service.ts
57675
57866
  var import_node_server_utils199 = require("@7365admin1/node-server-utils");
57676
57867
  function useNfcPatrolLogService() {
57677
- const { add: _add } = useNfcPatrolLogRepo();
57868
+ const {
57869
+ add: _add,
57870
+ getById,
57871
+ updateCheckpoint
57872
+ } = useNfcPatrolLogRepo();
57873
+ const routeRepo = useNfcPatrolRouteRepo();
57874
+ const tagRepo = useNfcPatrolTagRepo();
57678
57875
  async function add(value) {
57679
57876
  const session = import_node_server_utils199.useAtlas.getClient()?.startSession();
57680
57877
  session?.startTransaction();
@@ -57689,8 +57886,59 @@ function useNfcPatrolLogService() {
57689
57886
  session?.endSession();
57690
57887
  }
57691
57888
  }
57889
+ async function completeCheckpoint(logId, payload) {
57890
+ const session = import_node_server_utils199.useAtlas.getClient()?.startSession();
57891
+ session?.startTransaction();
57892
+ try {
57893
+ const log = await getById(logId, session);
57894
+ if (!log) {
57895
+ throw new import_node_server_utils199.BadRequestError("Patrol Log not found.");
57896
+ }
57897
+ const route = await routeRepo.getById(log.route._id);
57898
+ if (!route) {
57899
+ throw new import_node_server_utils199.BadRequestError("Route not found.");
57900
+ }
57901
+ const checkpoint = route.checkPoints[payload.checkpointIndex];
57902
+ if (!checkpoint) {
57903
+ throw new import_node_server_utils199.BadRequestError("Checkpoint not found.");
57904
+ }
57905
+ const logCheckpoint = log.checkPoints[payload.checkpointIndex];
57906
+ if (!logCheckpoint) {
57907
+ throw new import_node_server_utils199.BadRequestError("Checkpoint log not found.");
57908
+ }
57909
+ if (logCheckpoint.status === "Completed") {
57910
+ throw new import_node_server_utils199.BadRequestError("Checkpoint already completed.");
57911
+ }
57912
+ if (payload.action === "skip" && !payload.skippedRemarks?.trim()) {
57913
+ throw new import_node_server_utils199.BadRequestError("Skipped remarks are required.");
57914
+ }
57915
+ if (payload.action === "complete") {
57916
+ const tag = await tagRepo.getById(checkpoint.nfcTag_id, session);
57917
+ if (!tag.tagUID) {
57918
+ throw new import_node_server_utils199.BadRequestError("NFC Tag has not been configured.");
57919
+ }
57920
+ if (tag.tagUID !== payload.uid) {
57921
+ throw new import_node_server_utils199.BadRequestError("Invalid NFC Tag.");
57922
+ }
57923
+ }
57924
+ await updateCheckpoint(
57925
+ logId,
57926
+ payload.checkpointIndex,
57927
+ payload,
57928
+ session
57929
+ );
57930
+ await session?.commitTransaction();
57931
+ return "Checkpoint updated.";
57932
+ } catch (error) {
57933
+ await session?.abortTransaction();
57934
+ throw error;
57935
+ } finally {
57936
+ session?.endSession();
57937
+ }
57938
+ }
57692
57939
  return {
57693
- add
57940
+ add,
57941
+ completeCheckpoint
57694
57942
  };
57695
57943
  }
57696
57944
 
@@ -57698,7 +57946,7 @@ function useNfcPatrolLogService() {
57698
57946
  var import_node_server_utils200 = require("@7365admin1/node-server-utils");
57699
57947
  var import_joi111 = __toESM(require("joi"));
57700
57948
  function useNfcPatrolLogController() {
57701
- const { add: _add } = useNfcPatrolLogService();
57949
+ const { add: _add, completeCheckpoint: _completeCheckpoint } = useNfcPatrolLogService();
57702
57950
  const { getAllBySite: _getAllBySite } = useNfcPatrolLogRepo();
57703
57951
  async function add(req, res, next) {
57704
57952
  const payload = { ...req.body };
@@ -57761,9 +58009,27 @@ function useNfcPatrolLogController() {
57761
58009
  return;
57762
58010
  }
57763
58011
  }
58012
+ async function completeCheckpoint(req, res, next) {
58013
+ const { id } = req.params;
58014
+ const payload = {
58015
+ checkpointIndex: req.body.checkpointIndex,
58016
+ uid: req.body.uid,
58017
+ action: req.body.action,
58018
+ skippedRemarks: req.body.skippedRemarks
58019
+ };
58020
+ try {
58021
+ const data = await _completeCheckpoint(id, payload);
58022
+ res.status(200).json(data);
58023
+ return;
58024
+ } catch (error) {
58025
+ import_node_server_utils200.logger.error(error.message);
58026
+ next(error);
58027
+ }
58028
+ }
57764
58029
  return {
57765
58030
  add,
57766
- getAllBySite
58031
+ getAllBySite,
58032
+ completeCheckpoint
57767
58033
  };
57768
58034
  }
57769
58035