tango-app-api-infra 3.9.5-vms.81 → 3.9.5-vms.83

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-infra",
3
- "version": "3.9.5-vms.81",
3
+ "version": "3.9.5-vms.83",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "mongodb": "^6.4.0",
28
28
  "nodemon": "^3.1.0",
29
29
  "swagger-ui-express": "^5.0.0",
30
- "tango-api-schema": "^2.5.1",
30
+ "tango-api-schema": "^2.5.2",
31
31
  "tango-app-api-infra": "^3.9.5-vms.56",
32
32
  "tango-app-api-middleware": "^3.1.93",
33
33
  "winston": "^3.12.0",
@@ -2,7 +2,7 @@ import { bulkUpdate, getOpenSearchCount, getOpenSearchData, insertWithId, logger
2
2
  import { aggregateCluster } from '../services/cluster.service.js';
3
3
  import { findOneRevopDownload } from '../services/revopDownload.service.js';
4
4
  import { findOneStore } from '../services/store.service.js';
5
- import { findOneClient } from '../services/client.service.js';
5
+ import { aggregateClient, findOneClient } from '../services/client.service.js';
6
6
  import { updateOneUpsertVmsStoreRequest } from '../services/vmsStoreRequest.service.js';
7
7
  import { findOneUser, aggregateUser } from '../services/user.service.js';
8
8
  import { findteams } from '../services/teams.service.js';
@@ -277,16 +277,90 @@ export async function ticketCreation( req, res, next ) {
277
277
  }
278
278
 
279
279
  // get category details from the client level configuration
280
- const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1, clientId: 1 } );
280
+ const configQuery = [
281
+ {
282
+ $match: {
283
+ clientId: getstoreName?.clientId,
284
+ },
285
+ },
286
+
287
+ // Convert all effectiveFrom to proper Date
288
+ {
289
+ $addFields: {
290
+ taggingLimitationWithDate: {
291
+ $map: {
292
+ input: '$footfallDirectoryConfigs.taggingLimitation',
293
+ as: 'item',
294
+ in: {
295
+ effectiveFrom: { $toDate: '$$item.effectiveFrom' },
296
+ values: '$$item.values',
297
+ },
298
+ },
299
+ },
300
+ },
301
+ },
302
+
303
+ // Filter items <= input date
304
+ {
305
+ $addFields: {
306
+ matchedLimitation: {
307
+ $filter: {
308
+ input: '$taggingLimitationWithDate',
309
+ as: 'item',
310
+ cond: {
311
+ $lte: [
312
+ '$$item.effectiveFrom',
313
+ { $toDate: inputData.dateString },
314
+ ],
315
+ },
316
+ },
317
+ },
318
+ },
319
+ },
320
+
321
+ // Sort DESC and pick ONLY top 1 -> latest effective record
322
+ {
323
+ $addFields: {
324
+ effectiveLimitation: {
325
+ $arrayElemAt: [
326
+ {
327
+ $slice: [
328
+ {
329
+ $sortArray: {
330
+ input: '$matchedLimitation',
331
+ sortBy: { effectiveFrom: -1 },
332
+ },
333
+ },
334
+ 1,
335
+ ],
336
+ },
337
+ 0,
338
+ ],
339
+ },
340
+ },
341
+ },
342
+
343
+ {
344
+ $project: {
345
+ config: 1,
346
+ effectiveLimitation: 1,
347
+ footfallDirectoryConfigs: 1,
348
+ },
349
+ },
350
+ ];
351
+
352
+
353
+ const config = await aggregateClient( configQuery );
354
+ const getConfig = config[0];
281
355
  if ( !getConfig || getConfig == null ) {
282
356
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
283
357
  }
284
358
 
285
359
  // Get taggingLimitation from config (check both possible paths)
286
- const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
360
+ const taggingLimitation = getConfig?.effectiveLimitation?.values;
287
361
  // Initialize count object from taggingLimitation
288
362
  const tempAcc = [];
289
- taggingLimitation?.reduce( ( acc, item ) => {
363
+ taggingLimitation.reduce( ( acc, item ) => {
290
364
  if ( item?.type ) {
291
365
  // Convert type to camelCase with "Count" suffix
292
366
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -384,6 +458,7 @@ export async function ticketCreation( req, res, next ) {
384
458
  const totalCount = Array.isArray( tempAcc ) ?
385
459
  tempAcc.reduce( ( sum, acc ) => sum + ( acc.value || 0 ), 0 ) :
386
460
  0;
461
+
387
462
  const footfallCount = hits?.[0]?._source?.footfall_count || 0;
388
463
  const revisedFootfall = Math.max( 0, footfallCount - totalCount );
389
464
  if ( footfallCount - revisedFootfall == 0 ) {
@@ -920,16 +995,90 @@ export async function ticketReview( req, res, next ) {
920
995
  }
921
996
 
922
997
  // get category details from the client level configuration
923
- const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1 } );
998
+ const configQuery = [
999
+ {
1000
+ $match: {
1001
+ clientId: getstoreName?.clientId,
1002
+ },
1003
+ },
1004
+
1005
+ // Convert all effectiveFrom to proper Date
1006
+ {
1007
+ $addFields: {
1008
+ taggingLimitationWithDate: {
1009
+ $map: {
1010
+ input: '$footfallDirectoryConfigs.taggingLimitation',
1011
+ as: 'item',
1012
+ in: {
1013
+ effectiveFrom: { $toDate: '$$item.effectiveFrom' },
1014
+ values: '$$item.values',
1015
+ },
1016
+ },
1017
+ },
1018
+ },
1019
+ },
1020
+
1021
+ // Filter items <= input date
1022
+ {
1023
+ $addFields: {
1024
+ matchedLimitation: {
1025
+ $filter: {
1026
+ input: '$taggingLimitationWithDate',
1027
+ as: 'item',
1028
+ cond: {
1029
+ $lte: [
1030
+ '$$item.effectiveFrom',
1031
+ { $toDate: inputData.dateString },
1032
+ ],
1033
+ },
1034
+ },
1035
+ },
1036
+ },
1037
+ },
1038
+
1039
+ // Sort DESC and pick ONLY top 1 -> latest effective record
1040
+ {
1041
+ $addFields: {
1042
+ effectiveLimitation: {
1043
+ $arrayElemAt: [
1044
+ {
1045
+ $slice: [
1046
+ {
1047
+ $sortArray: {
1048
+ input: '$matchedLimitation',
1049
+ sortBy: { effectiveFrom: -1 },
1050
+ },
1051
+ },
1052
+ 1,
1053
+ ],
1054
+ },
1055
+ 0,
1056
+ ],
1057
+ },
1058
+ },
1059
+ },
1060
+
1061
+ {
1062
+ $project: {
1063
+ config: 1,
1064
+ effectiveLimitation: 1,
1065
+ footfallDirectoryConfigs: 1,
1066
+ },
1067
+ },
1068
+ ];
1069
+
1070
+
1071
+ const config = await aggregateClient( configQuery );
1072
+ const getConfig = config[0];
924
1073
  if ( !getConfig || getConfig == null ) {
925
1074
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
926
1075
  }
927
1076
 
928
1077
  // Get taggingLimitation from config (check both possible paths)
929
- const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
1078
+ const taggingLimitation = getConfig?.effectiveLimitation?.values;
930
1079
  // Initialize count object from taggingLimitation
931
1080
  const tempAcc = [];
932
- taggingLimitation?.reduce( ( acc, item ) => {
1081
+ taggingLimitation.reduce( ( acc, item ) => {
933
1082
  if ( item?.type ) {
934
1083
  // Convert type to camelCase with "Count" suffix
935
1084
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -1454,16 +1603,90 @@ export async function ticketApprove( req, res, next ) {
1454
1603
  }
1455
1604
 
1456
1605
  // get category details from the client level configuration
1457
- const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1 } );
1606
+ const configQuery = [
1607
+ {
1608
+ $match: {
1609
+ clientId: getstoreName?.clientId,
1610
+ },
1611
+ },
1612
+
1613
+ // Convert all effectiveFrom to proper Date
1614
+ {
1615
+ $addFields: {
1616
+ taggingLimitationWithDate: {
1617
+ $map: {
1618
+ input: '$footfallDirectoryConfigs.taggingLimitation',
1619
+ as: 'item',
1620
+ in: {
1621
+ effectiveFrom: { $toDate: '$$item.effectiveFrom' },
1622
+ values: '$$item.values',
1623
+ },
1624
+ },
1625
+ },
1626
+ },
1627
+ },
1628
+
1629
+ // Filter items <= input date
1630
+ {
1631
+ $addFields: {
1632
+ matchedLimitation: {
1633
+ $filter: {
1634
+ input: '$taggingLimitationWithDate',
1635
+ as: 'item',
1636
+ cond: {
1637
+ $lte: [
1638
+ '$$item.effectiveFrom',
1639
+ { $toDate: inputData.dateString },
1640
+ ],
1641
+ },
1642
+ },
1643
+ },
1644
+ },
1645
+ },
1646
+
1647
+ // Sort DESC and pick ONLY top 1 -> latest effective record
1648
+ {
1649
+ $addFields: {
1650
+ effectiveLimitation: {
1651
+ $arrayElemAt: [
1652
+ {
1653
+ $slice: [
1654
+ {
1655
+ $sortArray: {
1656
+ input: '$matchedLimitation',
1657
+ sortBy: { effectiveFrom: -1 },
1658
+ },
1659
+ },
1660
+ 1,
1661
+ ],
1662
+ },
1663
+ 0,
1664
+ ],
1665
+ },
1666
+ },
1667
+ },
1668
+
1669
+ {
1670
+ $project: {
1671
+ config: 1,
1672
+ effectiveLimitation: 1,
1673
+ footfallDirectoryConfigs: 1,
1674
+ },
1675
+ },
1676
+ ];
1677
+
1678
+
1679
+ const config = await aggregateClient( configQuery );
1680
+ const getConfig = config[0];
1458
1681
  if ( !getConfig || getConfig == null ) {
1459
1682
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
1460
1683
  }
1461
1684
 
1462
1685
  // Get taggingLimitation from config (check both possible paths)
1463
- const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
1686
+ const taggingLimitation = getConfig?.effectiveLimitation?.values;
1464
1687
  // Initialize count object from taggingLimitation
1465
1688
  const tempAcc = [];
1466
- taggingLimitation?.reduce( ( acc, item ) => {
1689
+ taggingLimitation.reduce( ( acc, item ) => {
1467
1690
  if ( item?.type ) {
1468
1691
  // Convert type to camelCase with "Count" suffix
1469
1692
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -1553,9 +1776,9 @@ export async function ticketApprove( req, res, next ) {
1553
1776
  0;
1554
1777
  const footfallCount = hits?.[0]?._source?.footfall_count || 0;
1555
1778
  const revisedFootfall = Math.max( 0, footfallCount - totalCount );
1556
- logger.info( { footfallCount, revisedFootfall } );
1779
+
1557
1780
  if ( footfallCount - revisedFootfall == 0 ) {
1558
- return res.sendError( 'Cannot review a ticket because footfall hasn’t changed', 400 );
1781
+ return res.sendError( 'Cannot approve a ticket because footfall hasn’t changed', 400 );
1559
1782
  }
1560
1783
 
1561
1784
  const taggingData = {
@@ -1621,7 +1844,7 @@ export async function ticketApprove( req, res, next ) {
1621
1844
  if ( !ticketData || ticketData?.length == 0 ) {
1622
1845
  return res.sendError( 'You don’t have any tagged images right now', 400 );
1623
1846
  }
1624
- logger.info( { ticketData, getFootfallticketData } );
1847
+
1625
1848
  const record = {
1626
1849
 
1627
1850
  status: 'Approver-Closed',
@@ -1641,12 +1864,10 @@ export async function ticketApprove( req, res, next ) {
1641
1864
  let autoCloseAccuracy = getConfig?.footfallDirectoryConfigs?.autoCloseAccuracy;
1642
1865
 
1643
1866
  const getNumber = autoCloseAccuracy.split( '%' )[0];
1644
- logger.info( { getNumber } );
1645
1867
  let autoCloseAccuracyValue = parseFloat( ( autoCloseAccuracy || getNumber ).replace( '%', '' ) );
1646
1868
  let revisedPercentage = Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 );
1647
1869
  const revised = Number( Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 ) );
1648
1870
  const tangoReview = Number( getConfig?.footfallDirectoryConfigs?.tangoReview?.split( '%' )[0] );
1649
- logger.info( { tangoReview, revised } );
1650
1871
  // If autoclose enabled and revisedPercentage meets/exceeds threshold, close ticket and skip revision
1651
1872
  if (
1652
1873
  isAutoCloseEnable === true &&