@7365admin1/core 3.32.2-staging.43 → 3.32.2-staging.46

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as mongodb from 'mongodb';
2
- import { ObjectId, ClientSession, Db, Collection, Document } from 'mongodb';
2
+ import { ObjectId, ClientSession, Db, Collection, Document, AggregateOptions } from 'mongodb';
3
3
  import Joi from 'joi';
4
4
  import { Request, Response, NextFunction } from 'express';
5
5
  import * as bson from 'bson';
@@ -2443,6 +2443,7 @@ declare function useVehicleRepo(): {
2443
2443
  }>;
2444
2444
  getVehicleBySiteAndPlateNumber: (plateNumber: string, site: string | ObjectId, category: string | ObjectId, status: string) => Promise<TVehicle | null>;
2445
2445
  getBlocklistedVehicleByPlateNumber: (plateNumber: string, site?: string) => Promise<bson.Document>;
2446
+ findOne: (query: Record<string, any>) => Promise<TVehicle | null>;
2446
2447
  };
2447
2448
 
2448
2449
  declare function formatDahuaDate(date: Date): string;
@@ -2537,16 +2538,20 @@ declare function useSiteCameraRepo(): {
2537
2538
  direction?: string | string[];
2538
2539
  page?: number;
2539
2540
  limit?: number;
2541
+ status?: string;
2540
2542
  }) => Promise<{
2541
2543
  pageRange: string;
2542
2544
  pages: number;
2543
2545
  items: Array<TSiteCamera>;
2544
2546
  }>;
2547
+ findMany: (query: object, project?: object, options?: AggregateOptions) => Promise<Document[]>;
2548
+ findOne: (query: object, project?: object, options?: AggregateOptions) => Promise<Document | null>;
2545
2549
  };
2546
2550
 
2547
2551
  declare function useSiteCameraService(): {
2548
2552
  add: (value: TSiteCamera) => Promise<"CCTV(s) added successfully." | "ANPR(s) added successfully.">;
2549
2553
  listenToCapturedPlateNumber: (onDetected?: ((data: any) => void) | undefined) => Promise<void>;
2554
+ updateById: (id: string, value: Partial<TSiteCamera>) => Promise<string>;
2550
2555
  };
2551
2556
 
2552
2557
  declare function useSiteCameraController(): {
@@ -2713,7 +2718,7 @@ declare function useAttendanceSettingsController(): {
2713
2718
  declare function useAttendanceRepository(): {
2714
2719
  createIndex: () => Promise<void>;
2715
2720
  checkInAttendance: (value: TAttendanceCheckIn, session?: ClientSession) => Promise<ObjectId>;
2716
- getAllAttendances: ({ page, limit, search, site, serviceType, }: TGetAttendancesQuery) => Promise<{}>;
2721
+ getAllAttendances: ({ page, limit, search, site, startDate, endDate, serviceType, }: TGetAttendancesQuery) => Promise<{}>;
2717
2722
  getAttendanceByUser: ({ page, limit, search, site, startDate, endDate, serviceType, user, }: TGetAttendancesByUserQuery) => Promise<{}>;
2718
2723
  getAttendanceById: (_id: string | ObjectId, session?: ClientSession) => Promise<{}>;
2719
2724
  getRawAttendanceById: (_id: string | ObjectId, session?: ClientSession) => Promise<TAttendance>;
package/dist/index.js CHANGED
@@ -23405,6 +23405,7 @@ function useVehicleRepo() {
23405
23405
  if (error) {
23406
23406
  throw new import_node_server_utils71.BadRequestError(error.details[0].message);
23407
23407
  }
23408
+ console.log("getVehicleByPlateNumber plateNumber", plateNumber);
23408
23409
  try {
23409
23410
  const data = await collection.findOne(
23410
23411
  { plateNumber, status: "active" },
@@ -23417,6 +23418,14 @@ function useVehicleRepo() {
23417
23418
  );
23418
23419
  }
23419
23420
  }
23421
+ async function findOne(query) {
23422
+ try {
23423
+ const data = await collection.findOne(query);
23424
+ return data;
23425
+ } catch (error) {
23426
+ throw new import_node_server_utils71.InternalServerError("Failed to fetch findOne vehicle." + error);
23427
+ }
23428
+ }
23420
23429
  async function getVehicleBySiteAndPlateNumber(plateNumber, site, category, status) {
23421
23430
  const { error } = import_joi39.default.string().required().validate(plateNumber);
23422
23431
  if (error) {
@@ -23725,7 +23734,8 @@ function useVehicleRepo() {
23725
23734
  getSpecificVehicleById,
23726
23735
  getBlocklistedVehicles,
23727
23736
  getVehicleBySiteAndPlateNumber,
23728
- getBlocklistedVehicleByPlateNumber
23737
+ getBlocklistedVehicleByPlateNumber,
23738
+ findOne
23729
23739
  };
23730
23740
  }
23731
23741
 
@@ -23804,12 +23814,13 @@ async function useDahuaDigestWithRetry({
23804
23814
  headers = {},
23805
23815
  timeout = 1e4,
23806
23816
  streaming = false,
23807
- retries = 3,
23817
+ retries = 10,
23808
23818
  retryDelayMs = 0
23809
23819
  }) {
23810
23820
  let lastError;
23811
23821
  for (let attempt = 1; attempt <= retries; attempt++) {
23812
23822
  try {
23823
+ const effectiveTimeout = streaming ? 0 : timeout;
23813
23824
  const response = await useDahuaDigest({
23814
23825
  host,
23815
23826
  username,
@@ -23817,16 +23828,23 @@ async function useDahuaDigestWithRetry({
23817
23828
  endpoint,
23818
23829
  method,
23819
23830
  headers,
23820
- timeout,
23831
+ timeout: effectiveTimeout,
23821
23832
  streaming
23822
23833
  });
23823
- const text = getDahuaResponseText(response);
23824
23834
  const statusCode = getDahuaStatusCode(response);
23825
- const isOk = statusCode === 200 && text.includes("OK");
23826
- if (isOk) {
23827
- return response;
23835
+ if (streaming) {
23836
+ if (statusCode === 200) {
23837
+ return response;
23838
+ }
23839
+ } else {
23840
+ const text = getDahuaResponseText(response);
23841
+ const isOk = statusCode === 200 && text.includes("OK");
23842
+ if (isOk) {
23843
+ return response;
23844
+ }
23828
23845
  }
23829
- const shouldRetry = isDahuaInvalidAuthority(text);
23846
+ const errorText = streaming ? `HTTP ${statusCode}` : getDahuaResponseText(response);
23847
+ const shouldRetry = isDahuaInvalidAuthority(errorText);
23830
23848
  if (shouldRetry && attempt < retries) {
23831
23849
  loggerDahua.warn(
23832
23850
  `[${host}] Dahua Invalid Authority. Retrying ${attempt}/${retries}`
@@ -23836,7 +23854,7 @@ async function useDahuaDigestWithRetry({
23836
23854
  }
23837
23855
  continue;
23838
23856
  }
23839
- throw new Error(`Dahua response: ${text || `HTTP ${statusCode}`}`);
23857
+ throw new Error(`Dahua response: ${errorText || `HTTP ${statusCode}`}`);
23840
23858
  } catch (error) {
23841
23859
  lastError = error;
23842
23860
  const message = error?.message || String(error);
@@ -24219,6 +24237,7 @@ function useDahuaService() {
24219
24237
  if (camera.status !== "active") {
24220
24238
  if (cameraRegistry.has(cameraId)) {
24221
24239
  loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Camera is ${camera.status}. Stopping connection.`);
24240
+ console.log(`[${camera?.siteName}-${camera?.direction}] Camera is ${camera.status}. Stopping connection.`);
24222
24241
  cameraRegistry.get(cameraId)?.abort();
24223
24242
  cameraRegistry.delete(cameraId);
24224
24243
  }
@@ -24226,6 +24245,7 @@ function useDahuaService() {
24226
24245
  }
24227
24246
  if (cameraRegistry.has(cameraId)) {
24228
24247
  loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Stopping existing connection for update.`);
24248
+ console.log(`[${camera?.siteName}-${camera?.direction}] Stopping existing connection for update.`);
24229
24249
  cameraRegistry.get(cameraId)?.abort();
24230
24250
  cameraRegistry.delete(cameraId);
24231
24251
  }
@@ -24245,11 +24265,14 @@ function useDahuaService() {
24245
24265
  }
24246
24266
  async function getTrafficJunction(camera, signal, onDetected) {
24247
24267
  console.log(`getTrafficJunction camera object`, camera);
24268
+ let authFailureCount = 0;
24269
+ const MAX_AUTH_RETRIES = 10;
24248
24270
  while (!signal.aborted) {
24249
24271
  let bufferQueue = null;
24250
24272
  let response = null;
24273
+ let isAuthFailure = false;
24251
24274
  try {
24252
- response = await useDahuaDigest({
24275
+ response = await useDahuaDigestWithRetry({
24253
24276
  host: camera?.host,
24254
24277
  username: camera?.username,
24255
24278
  password: camera?.password,
@@ -24257,16 +24280,32 @@ function useDahuaService() {
24257
24280
  timeout: 2e4,
24258
24281
  streaming: true
24259
24282
  });
24260
- if (response.statusCode === 401) {
24261
- loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] 401 Unauthorized. Potential handshake or wrong credentials.`);
24262
- continue;
24263
- } else if ([400, 401, 403, 500].includes(response.statusCode)) {
24264
- loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] Connection error: ${response.statusCode}`);
24283
+ const statusCode = getDahuaStatusCode(response);
24284
+ if (statusCode === 401) {
24285
+ loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] 401 Unauthorized - Handshake or Wrong Credentials`);
24286
+ console.log(`[${camera?.siteName}-${camera?.direction}] 401 Unauthorized - Handshake or Wrong Credentials`);
24287
+ throw new Error("401 Unauthorized - Handshake or Wrong Credentials");
24288
+ } else if (statusCode === 403) {
24289
+ loggerDahua.error(
24290
+ `[${camera?.siteName}-${camera?.direction}] 403 Forbidden. Account locked or invalid permissions.`
24291
+ );
24292
+ if (onDetected) {
24293
+ onDetected({
24294
+ site: camera?.site,
24295
+ direction: camera?.direction,
24296
+ messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password and try after 10 minutes.`
24297
+ });
24298
+ }
24299
+ return;
24300
+ } else if ([400, 500].includes(statusCode)) {
24301
+ loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] Connection error: ${statusCode}`);
24265
24302
  if (onDetected) {
24266
- onDetected({ site: camera?.site, messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password.` });
24303
+ onDetected({ site: camera?.site, messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Possible Not Authorized.` });
24267
24304
  }
24268
24305
  return;
24269
24306
  }
24307
+ authFailureCount = 0;
24308
+ isAuthFailure = false;
24270
24309
  loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Successfully connected to ANPR.`);
24271
24310
  const contentType = response.res.headers["content-type"];
24272
24311
  const boundaryMatch = contentType?.match(/boundary=(.*)$/i);
@@ -24311,15 +24350,53 @@ function useDahuaService() {
24311
24350
  loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Connection closed by system (Abort).`);
24312
24351
  break;
24313
24352
  }
24314
- loggerDahua.error(
24315
- `[${camera?.siteName}-${camera?.direction}] Connection lost or error: ${error.message || error}. Retrying in 10 seconds...`
24316
- );
24317
- if (onDetected) {
24318
- onDetected({
24319
- site: camera?.site,
24320
- direction: camera?.direction,
24321
- message: `Camera in [${camera?.siteName}-${camera?.direction}] Connection Lost. Retrying in 10 seconds. Check the camera if this issue persists, Or set the camera to Inactive to stop this notification.`
24322
- });
24353
+ const errMsg = String(error?.message || error);
24354
+ if (errMsg.includes("403") || errMsg.includes("Forbidden")) {
24355
+ loggerDahua.error(
24356
+ `[${camera?.siteName}-${camera?.direction}] 403 Forbidden thrown by Dahua client. Account locked or invalid credentials.`
24357
+ );
24358
+ if (onDetected) {
24359
+ onDetected({
24360
+ site: camera?.site,
24361
+ direction: camera?.direction,
24362
+ messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password and try after 10 minutes.`
24363
+ });
24364
+ }
24365
+ return;
24366
+ }
24367
+ const isAuthError = errMsg.includes("401") || errMsg.includes("Unauthorized") || errMsg.includes("Invalid Authority");
24368
+ if (isAuthError) {
24369
+ authFailureCount++;
24370
+ isAuthFailure = true;
24371
+ loggerDahua.warn(
24372
+ `[${camera?.siteName}-${camera?.direction}] Auth attempt ${authFailureCount}/${MAX_AUTH_RETRIES}`
24373
+ );
24374
+ if (authFailureCount >= MAX_AUTH_RETRIES) {
24375
+ loggerDahua.error(
24376
+ `[${camera?.siteName}-${camera?.direction}] Max auth failures reached (${MAX_AUTH_RETRIES}). Wrong credentials.`
24377
+ );
24378
+ if (onDetected) {
24379
+ onDetected({
24380
+ site: camera?.site,
24381
+ direction: camera?.direction,
24382
+ messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password.`
24383
+ });
24384
+ }
24385
+ return;
24386
+ }
24387
+ } else {
24388
+ authFailureCount = 0;
24389
+ isAuthFailure = false;
24390
+ loggerDahua.error(
24391
+ `[${camera?.siteName}-${camera?.direction}] Connection lost or error: ${error.message || error}. Retrying in 10 seconds...`
24392
+ );
24393
+ if (onDetected) {
24394
+ onDetected({
24395
+ site: camera?.site,
24396
+ direction: camera?.direction,
24397
+ message: `Camera in [${camera?.siteName}-${camera?.direction}] Connection Lost. Retrying in 10 seconds. Check the camera if this issue persists, Or set the camera to Inactive to stop this notification.`
24398
+ });
24399
+ }
24323
24400
  }
24324
24401
  } finally {
24325
24402
  if (bufferQueue?.destroy) {
@@ -24341,7 +24418,8 @@ function useDahuaService() {
24341
24418
  }
24342
24419
  }
24343
24420
  if (!signal.aborted) {
24344
- await new Promise((res) => setTimeout(res, 1e4));
24421
+ const waitMs = isAuthFailure ? 1e3 : 1e4;
24422
+ await new Promise((res) => setTimeout(res, waitMs));
24345
24423
  }
24346
24424
  }
24347
24425
  loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] ANPR Listener stopped.`);
@@ -25012,7 +25090,8 @@ function useSiteCameraRepo() {
25012
25090
  throw new import_node_server_utils73.BadRequestError("Site camera not found.");
25013
25091
  }
25014
25092
  if (result?._id) {
25015
- const result2 = await findOne({ _id: new import_mongodb45.ObjectId(result._id) });
25093
+ const result2 = await findOne({ _id: new import_mongodb45.ObjectId(result._id) }, void 0, { session });
25094
+ console.log("updateById result2", result2);
25016
25095
  if (result2?._id) {
25017
25096
  const { listenToCamera } = useDahuaService();
25018
25097
  await listenToCamera(result2);
@@ -25077,6 +25156,9 @@ function useSiteCameraRepo() {
25077
25156
  throw new import_node_server_utils73.BadRequestError("Invalid site ID format");
25078
25157
  }
25079
25158
  }
25159
+ if (value.status) {
25160
+ query.status = value.status;
25161
+ }
25080
25162
  try {
25081
25163
  const items = await collection.aggregate([
25082
25164
  {
@@ -25147,7 +25229,7 @@ function useSiteCameraRepo() {
25147
25229
  throw new import_node_server_utils73.BadRequestError("Failed to retrieve site cameras.");
25148
25230
  }
25149
25231
  }
25150
- async function findOne(query, project = {}) {
25232
+ async function findOne(query, project = {}, options = {}) {
25151
25233
  try {
25152
25234
  const pipeline = [
25153
25235
  { $match: query },
@@ -25196,14 +25278,14 @@ function useSiteCameraRepo() {
25196
25278
  if (Object.keys(project).length > 0) {
25197
25279
  pipeline.push({ $project: project });
25198
25280
  }
25199
- const result = await collection.aggregate(pipeline).toArray();
25281
+ const result = await collection.aggregate(pipeline, options).toArray();
25200
25282
  return result.length > 0 ? result[0] : null;
25201
25283
  } catch (error) {
25202
25284
  console.error("Error in findOne aggregation:", error);
25203
25285
  throw error;
25204
25286
  }
25205
25287
  }
25206
- async function findMany(query, project = {}) {
25288
+ async function findMany(query, project = {}, options = {}) {
25207
25289
  try {
25208
25290
  const pipeline = [
25209
25291
  { $match: query },
@@ -25252,10 +25334,10 @@ function useSiteCameraRepo() {
25252
25334
  if (Object.keys(project).length > 0) {
25253
25335
  pipeline.push({ $project: project });
25254
25336
  }
25255
- const result = await collection.aggregate(pipeline).toArray();
25337
+ const result = await collection.aggregate(pipeline, options).toArray();
25256
25338
  return result.length > 0 ? result : [];
25257
25339
  } catch (error) {
25258
- console.error("Error in findOne aggregation:", error);
25340
+ console.error("Error in findMany aggregation:", error);
25259
25341
  throw error;
25260
25342
  }
25261
25343
  }
@@ -25272,7 +25354,9 @@ function useSiteCameraRepo() {
25272
25354
  getBySiteGuardPost,
25273
25355
  updateById,
25274
25356
  deleteById,
25275
- getAllCameraWithPassword
25357
+ getAllCameraWithPassword,
25358
+ findMany,
25359
+ findOne
25276
25360
  };
25277
25361
  }
25278
25362
 
@@ -27185,7 +27269,8 @@ function useVehicleService() {
27185
27269
  deleteExpiredVehicles: _deleteExpiredVehicles,
27186
27270
  getVehicleByPlateNumber: _getVehicleByPlateNumber,
27187
27271
  getAllExpiredVehicles: _getAllExpiredVehicles,
27188
- bulkUpsertVehicles: _bulkUpsertVehicles
27272
+ bulkUpsertVehicles: _bulkUpsertVehicles,
27273
+ findOne
27189
27274
  } = useVehicleRepo();
27190
27275
  const {
27191
27276
  addPlateNumber: _addPlateNumber,
@@ -27209,15 +27294,18 @@ function useVehicleService() {
27209
27294
  throw new Error("Unable to start session for vehicle service.");
27210
27295
  }
27211
27296
  }
27297
+ console.log("add vehicle service value.plateNumber", value.plateNumber);
27212
27298
  const [_vehiclePlateNumber] = value.plateNumber;
27213
- const [existingPlateNumber, org] = await Promise.all([
27214
- _getVehicleByPlateNumber(_vehiclePlateNumber),
27299
+ console.log("add vehicle service plateNumber", _vehiclePlateNumber);
27300
+ const [
27301
+ // existingPlateNumber,
27302
+ org
27303
+ ] = await Promise.all([
27304
+ // _getVehicleByPlateNumber(_vehiclePlateNumber),
27215
27305
  _getById(value.org)
27216
27306
  ]);
27217
27307
  if (!org)
27218
27308
  throw new import_node_server_utils78.BadRequestError("Org not found");
27219
- if (existingPlateNumber)
27220
- throw new import_node_server_utils78.BadRequestError("Vehicle plate number already exists");
27221
27309
  if (!Object.values(OrgNature).includes(org.nature)) {
27222
27310
  throw new import_node_server_utils78.BadRequestError(
27223
27311
  "This organization is not allowed to add vehicles."
@@ -27230,7 +27318,6 @@ function useVehicleService() {
27230
27318
  user,
27231
27319
  org: value.org
27232
27320
  });
27233
- console.log("userPermissions vehicle.service.ts", userPermissions);
27234
27321
  const hasSecurityBypass = addedBySecurity && Array.isArray(userPermissions) && (userPermissions.includes("*") || userPermissions.includes("vehicleManagement:approve-vehicle"));
27235
27322
  if (hasSecurityBypass) {
27236
27323
  addedByPM = true;
@@ -27289,17 +27376,16 @@ function useVehicleService() {
27289
27376
  const siteCameraReq = await _getAllSiteCameras({
27290
27377
  site: value.site,
27291
27378
  type: "anpr",
27292
- direction: ["both", "entry"],
27379
+ direction: ["both", "entry", "residents"],
27293
27380
  page,
27294
- limit
27381
+ limit,
27382
+ status: "active"
27295
27383
  });
27296
27384
  pages = siteCameraReq.pages || 1;
27297
27385
  siteCameras.push(...siteCameraReq.items);
27298
27386
  page++;
27299
27387
  } while (page <= pages);
27300
- if (!siteCameras.length) {
27301
- throw new import_node_server_utils78.BadRequestError("No site cameras found.");
27302
- }
27388
+ console.log("add vehicle service siteCameras", siteCameras);
27303
27389
  }
27304
27390
  for (const plateNumber of plateNumbers) {
27305
27391
  const vehicleValue = {
@@ -31948,6 +32034,7 @@ function useSiteCameraService() {
31948
32034
  const { add: _add, getAllCameraWithPassword: _getAllCameraWithPassword } = useSiteCameraRepo();
31949
32035
  const { updateById: _updateById } = useSiteRepo();
31950
32036
  const dahuaService = useDahuaService();
32037
+ const { updateById: _siteCameraUpdateById } = useSiteCameraRepo();
31951
32038
  let cleanupTask = null;
31952
32039
  async function add(value) {
31953
32040
  const { error } = schemaSiteCamera.validate(value);
@@ -31981,6 +32068,7 @@ function useSiteCameraService() {
31981
32068
  type: "anpr",
31982
32069
  page,
31983
32070
  limit
32071
+ // site: "6923d6664150ca6a69b9f2b2"
31984
32072
  });
31985
32073
  pages = siteCameraReq.pages || 1;
31986
32074
  siteCameras.push(...siteCameraReq.items);
@@ -31996,9 +32084,27 @@ function useSiteCameraService() {
31996
32084
  }
31997
32085
  }
31998
32086
  }
32087
+ async function updateById(id, value) {
32088
+ const session = import_node_server_utils93.useAtlas.getClient()?.startSession();
32089
+ if (!session) {
32090
+ throw new Error("Unable to start session for site camera service.");
32091
+ }
32092
+ try {
32093
+ session.startTransaction();
32094
+ const result = await _siteCameraUpdateById(id, value, session);
32095
+ await session.commitTransaction();
32096
+ return result;
32097
+ } catch (error) {
32098
+ await session.abortTransaction();
32099
+ throw error;
32100
+ } finally {
32101
+ session.endSession();
32102
+ }
32103
+ }
31999
32104
  return {
32000
32105
  add,
32001
- listenToCapturedPlateNumber
32106
+ listenToCapturedPlateNumber,
32107
+ updateById
32002
32108
  };
32003
32109
  }
32004
32110
 
@@ -32006,10 +32112,9 @@ function useSiteCameraService() {
32006
32112
  var import_node_server_utils94 = require("@7365admin1/node-server-utils");
32007
32113
  var import_joi49 = __toESM(require("joi"));
32008
32114
  function useSiteCameraController() {
32009
- const { add: _add } = useSiteCameraService();
32115
+ const { add: _add, updateById: _updateById } = useSiteCameraService();
32010
32116
  const {
32011
32117
  getAll: _getAll,
32012
- updateById: _updateById,
32013
32118
  deleteById: _deleteById
32014
32119
  } = useSiteCameraRepo();
32015
32120
  async function add(req, res, next) {
@@ -33236,6 +33341,8 @@ function useAttendanceRepository() {
33236
33341
  limit = 10,
33237
33342
  search = "",
33238
33343
  site,
33344
+ startDate = "",
33345
+ endDate = "",
33239
33346
  serviceType
33240
33347
  }) {
33241
33348
  page = page > 0 ? page - 1 : 0;
@@ -33255,6 +33362,37 @@ function useAttendanceRepository() {
33255
33362
  if (search) {
33256
33363
  cacheOptions.search = search;
33257
33364
  }
33365
+ const singaporeTz = "Asia/Singapore";
33366
+ const normalizedStartDate = typeof startDate === "string" ? startDate : (0, import_moment_timezone2.default)(startDate).tz(singaporeTz).format("YYYY-MM-DD");
33367
+ const normalizedEndDate = typeof endDate === "string" ? endDate : (0, import_moment_timezone2.default)(endDate).tz(singaporeTz).format("YYYY-MM-DD");
33368
+ if (startDate && endDate) {
33369
+ const startOfDay = import_moment_timezone2.default.tz(normalizedStartDate, "YYYY-MM-DD", singaporeTz).startOf("day").toDate();
33370
+ const endOfDay = import_moment_timezone2.default.tz(normalizedEndDate, "YYYY-MM-DD", singaporeTz).endOf("day").toDate();
33371
+ query.$expr = {
33372
+ $and: [
33373
+ { $gte: [{ $toDate: "$checkIn.timestamp" }, startOfDay] },
33374
+ { $lte: [{ $toDate: "$checkIn.timestamp" }, endOfDay] }
33375
+ ]
33376
+ };
33377
+ cacheOptions.startDate = normalizedStartDate;
33378
+ cacheOptions.endDate = normalizedEndDate;
33379
+ } else if (startDate) {
33380
+ query.$expr = {
33381
+ $gte: [
33382
+ { $toDate: "$checkIn.timestamp" },
33383
+ import_moment_timezone2.default.tz(normalizedStartDate, "YYYY-MM-DD", singaporeTz).startOf("day").toDate()
33384
+ ]
33385
+ };
33386
+ cacheOptions.startDate = normalizedStartDate;
33387
+ } else if (endDate) {
33388
+ query.$expr = {
33389
+ $lte: [
33390
+ { $toDate: "$checkIn.timestamp" },
33391
+ import_moment_timezone2.default.tz(normalizedEndDate, "YYYY-MM-DD", singaporeTz).endOf("day").toDate()
33392
+ ]
33393
+ };
33394
+ cacheOptions.endDate = normalizedEndDate;
33395
+ }
33258
33396
  const cacheKey = (0, import_node_server_utils103.makeCacheKey)(namespace_collection, cacheOptions);
33259
33397
  const cachedData = await getCache(cacheKey);
33260
33398
  if (cachedData) {
@@ -33790,7 +33928,9 @@ function useAttendanceController() {
33790
33928
  limit: import_joi56.default.number().min(1).optional().allow("", null),
33791
33929
  search: import_joi56.default.string().optional().allow("", null),
33792
33930
  site: import_joi56.default.string().hex().required(),
33793
- serviceType: import_joi56.default.string().valid(...Object.values(AppServiceType)).required()
33931
+ serviceType: import_joi56.default.string().valid(...Object.values(AppServiceType)).required(),
33932
+ dateFrom: import_joi56.default.alternatives().try(import_joi56.default.date(), import_joi56.default.string()).optional().allow("", null),
33933
+ dateTo: import_joi56.default.alternatives().try(import_joi56.default.date(), import_joi56.default.string()).optional().allow("", null)
33794
33934
  });
33795
33935
  const { error } = validation.validate(query);
33796
33936
  if (error) {
@@ -33803,13 +33943,17 @@ function useAttendanceController() {
33803
33943
  const search = req.query.search ?? "";
33804
33944
  const site = req.params.site ?? "";
33805
33945
  const serviceType = req.query.serviceType ?? "";
33946
+ const startDate = req.query.dateFrom ?? "";
33947
+ const endDate = req.query.dateTo ?? "";
33806
33948
  try {
33807
33949
  const data = await _getAllAttendances({
33808
33950
  page,
33809
33951
  limit,
33810
33952
  search,
33811
33953
  site,
33812
- serviceType
33954
+ serviceType,
33955
+ startDate,
33956
+ endDate
33813
33957
  });
33814
33958
  res.json(data);
33815
33959
  return;