tango-app-api-infra 3.9.5-vms.80 → 3.9.5-vms.82

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.80",
3
+ "version": "3.9.5-vms.82",
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",
@@ -304,7 +304,7 @@ export async function tangoReviewTicket( req, res ) {
304
304
  revicedPerc: inputData.mappingInfo?.revicedPerc,
305
305
  count: inputData.mappingInfo?.count,
306
306
  revisedDetail: inputData.mappingInfo?.revisedDetail,
307
- status: 'Closed',
307
+ status: 'Open - Accuracy Issue',
308
308
  createdByEmail: req?.user?.email,
309
309
  createdByUserName: req?.user?.userName,
310
310
  createdByRole: req?.user?.role,
@@ -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,7 +277,75 @@ 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
+ // Filter limitations based on effectiveFrom <= date
288
+ {
289
+ $addFields: {
290
+ matchedLimitation: {
291
+ $filter: {
292
+ input: '$footfallDirectoryConfigs.taggingLimitation',
293
+ as: 'item',
294
+ cond: { $lte: [ '$$item.effectiveFrom', inputData.dateString ] },
295
+ },
296
+ },
297
+ },
298
+ },
299
+
300
+ // Pick latest effective record
301
+ {
302
+ $addFields: {
303
+ effectiveLimitation: {
304
+ $arrayElemAt: [
305
+ {
306
+ $slice: [
307
+ {
308
+ $sortArray: {
309
+ input: '$matchedLimitation',
310
+ sortBy: { effectiveFrom: -1 },
311
+ },
312
+ },
313
+ 1,
314
+ ],
315
+ },
316
+ 0,
317
+ ],
318
+ },
319
+ },
320
+ },
321
+
322
+ // Remove originals before final merge
323
+ {
324
+ $project: {
325
+ 'config.taggingLimitation': 0,
326
+ 'matchedLimitation': 0,
327
+ },
328
+ },
329
+
330
+ // Attach effective limitation INSIDE config
331
+ {
332
+ $addFields: {
333
+ 'config.effectiveLimitation': '$effectiveLimitation',
334
+ },
335
+ },
336
+
337
+ // Remove temporary field
338
+ {
339
+ $project: {
340
+ footfallDirectoryConfigs: 1,
341
+ clientId: 1,
342
+ },
343
+ },
344
+ ];
345
+
346
+
347
+ const config = await aggregateClient( configQuery );
348
+ const getConfig = config[0];
281
349
  if ( !getConfig || getConfig == null ) {
282
350
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
283
351
  }
@@ -286,7 +354,7 @@ export async function ticketCreation( req, res, next ) {
286
354
  const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
287
355
  // Initialize count object from taggingLimitation
288
356
  const tempAcc = [];
289
- taggingLimitation?.reduce( ( acc, item ) => {
357
+ taggingLimitation[taggingLimitation?.length - 1]?.values?.reduce( ( acc, item ) => {
290
358
  if ( item?.type ) {
291
359
  // Convert type to camelCase with "Count" suffix
292
360
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -384,6 +452,7 @@ export async function ticketCreation( req, res, next ) {
384
452
  const totalCount = Array.isArray( tempAcc ) ?
385
453
  tempAcc.reduce( ( sum, acc ) => sum + ( acc.value || 0 ), 0 ) :
386
454
  0;
455
+
387
456
  const footfallCount = hits?.[0]?._source?.footfall_count || 0;
388
457
  const revisedFootfall = Math.max( 0, footfallCount - totalCount );
389
458
  if ( footfallCount - revisedFootfall == 0 ) {
@@ -920,7 +989,75 @@ export async function ticketReview( req, res, next ) {
920
989
  }
921
990
 
922
991
  // get category details from the client level configuration
923
- const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1 } );
992
+ const configQuery = [
993
+ {
994
+ $match: {
995
+ clientId: getstoreName?.clientId,
996
+ },
997
+ },
998
+
999
+ // Filter limitations based on effectiveFrom <= date
1000
+ {
1001
+ $addFields: {
1002
+ matchedLimitation: {
1003
+ $filter: {
1004
+ input: '$footfallDirectoryConfigs.taggingLimitation',
1005
+ as: 'item',
1006
+ cond: { $lte: [ '$$item.effectiveFrom', inputData.dateString ] },
1007
+ },
1008
+ },
1009
+ },
1010
+ },
1011
+
1012
+ // Pick latest effective record
1013
+ {
1014
+ $addFields: {
1015
+ effectiveLimitation: {
1016
+ $arrayElemAt: [
1017
+ {
1018
+ $slice: [
1019
+ {
1020
+ $sortArray: {
1021
+ input: '$matchedLimitation',
1022
+ sortBy: { effectiveFrom: -1 },
1023
+ },
1024
+ },
1025
+ 1,
1026
+ ],
1027
+ },
1028
+ 0,
1029
+ ],
1030
+ },
1031
+ },
1032
+ },
1033
+
1034
+ // Remove originals before final merge
1035
+ {
1036
+ $project: {
1037
+ 'config.taggingLimitation': 0,
1038
+ 'matchedLimitation': 0,
1039
+ },
1040
+ },
1041
+
1042
+ // Attach effective limitation INSIDE config
1043
+ {
1044
+ $addFields: {
1045
+ 'config.effectiveLimitation': '$effectiveLimitation',
1046
+ },
1047
+ },
1048
+
1049
+ // Remove temporary field
1050
+ {
1051
+ $project: {
1052
+ footfallDirectoryConfigs: 1,
1053
+ clientId: 1,
1054
+ },
1055
+ },
1056
+ ];
1057
+
1058
+
1059
+ const config = await aggregateClient( configQuery );
1060
+ const getConfig = config[0];
924
1061
  if ( !getConfig || getConfig == null ) {
925
1062
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
926
1063
  }
@@ -929,7 +1066,7 @@ export async function ticketReview( req, res, next ) {
929
1066
  const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
930
1067
  // Initialize count object from taggingLimitation
931
1068
  const tempAcc = [];
932
- taggingLimitation?.reduce( ( acc, item ) => {
1069
+ taggingLimitation[taggingLimitation?.length - 1]?.values?.reduce( ( acc, item ) => {
933
1070
  if ( item?.type ) {
934
1071
  // Convert type to camelCase with "Count" suffix
935
1072
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -1454,7 +1591,75 @@ export async function ticketApprove( req, res, next ) {
1454
1591
  }
1455
1592
 
1456
1593
  // get category details from the client level configuration
1457
- const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1 } );
1594
+ const configQuery = [
1595
+ {
1596
+ $match: {
1597
+ clientId: getstoreName?.clientId,
1598
+ },
1599
+ },
1600
+
1601
+ // Filter limitations based on effectiveFrom <= date
1602
+ {
1603
+ $addFields: {
1604
+ matchedLimitation: {
1605
+ $filter: {
1606
+ input: '$footfallDirectoryConfigs.taggingLimitation',
1607
+ as: 'item',
1608
+ cond: { $lte: [ '$$item.effectiveFrom', inputData.dateString ] },
1609
+ },
1610
+ },
1611
+ },
1612
+ },
1613
+
1614
+ // Pick latest effective record
1615
+ {
1616
+ $addFields: {
1617
+ effectiveLimitation: {
1618
+ $arrayElemAt: [
1619
+ {
1620
+ $slice: [
1621
+ {
1622
+ $sortArray: {
1623
+ input: '$matchedLimitation',
1624
+ sortBy: { effectiveFrom: -1 },
1625
+ },
1626
+ },
1627
+ 1,
1628
+ ],
1629
+ },
1630
+ 0,
1631
+ ],
1632
+ },
1633
+ },
1634
+ },
1635
+
1636
+ // Remove originals before final merge
1637
+ {
1638
+ $project: {
1639
+ 'config.taggingLimitation': 0,
1640
+ 'matchedLimitation': 0,
1641
+ },
1642
+ },
1643
+
1644
+ // Attach effective limitation INSIDE config
1645
+ {
1646
+ $addFields: {
1647
+ 'config.effectiveLimitation': '$effectiveLimitation',
1648
+ },
1649
+ },
1650
+
1651
+ // Remove temporary field
1652
+ {
1653
+ $project: {
1654
+ footfallDirectoryConfigs: 1,
1655
+ clientId: 1,
1656
+ },
1657
+ },
1658
+ ];
1659
+
1660
+
1661
+ const config = await aggregateClient( configQuery );
1662
+ const getConfig = config[0];
1458
1663
  if ( !getConfig || getConfig == null ) {
1459
1664
  return res.sendError( 'The Client ID is either not configured or not found', 400 );
1460
1665
  }
@@ -1463,7 +1668,7 @@ export async function ticketApprove( req, res, next ) {
1463
1668
  const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
1464
1669
  // Initialize count object from taggingLimitation
1465
1670
  const tempAcc = [];
1466
- taggingLimitation?.reduce( ( acc, item ) => {
1671
+ taggingLimitation[taggingLimitation?.length - 1]?.values?.reduce( ( acc, item ) => {
1467
1672
  if ( item?.type ) {
1468
1673
  // Convert type to camelCase with "Count" suffix
1469
1674
  // e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
@@ -1553,9 +1758,9 @@ export async function ticketApprove( req, res, next ) {
1553
1758
  0;
1554
1759
  const footfallCount = hits?.[0]?._source?.footfall_count || 0;
1555
1760
  const revisedFootfall = Math.max( 0, footfallCount - totalCount );
1556
- logger.info( { footfallCount, revisedFootfall } );
1761
+
1557
1762
  if ( footfallCount - revisedFootfall == 0 ) {
1558
- return res.sendError( 'Cannot review a ticket because footfall hasn’t changed', 400 );
1763
+ return res.sendError( 'Cannot approve a ticket because footfall hasn’t changed', 400 );
1559
1764
  }
1560
1765
 
1561
1766
  const taggingData = {
@@ -1621,7 +1826,7 @@ export async function ticketApprove( req, res, next ) {
1621
1826
  if ( !ticketData || ticketData?.length == 0 ) {
1622
1827
  return res.sendError( 'You don’t have any tagged images right now', 400 );
1623
1828
  }
1624
- logger.info( { ticketData, getFootfallticketData } );
1829
+
1625
1830
  const record = {
1626
1831
 
1627
1832
  status: 'Approver-Closed',
@@ -1641,12 +1846,10 @@ export async function ticketApprove( req, res, next ) {
1641
1846
  let autoCloseAccuracy = getConfig?.footfallDirectoryConfigs?.autoCloseAccuracy;
1642
1847
 
1643
1848
  const getNumber = autoCloseAccuracy.split( '%' )[0];
1644
- logger.info( { getNumber } );
1645
1849
  let autoCloseAccuracyValue = parseFloat( ( autoCloseAccuracy || getNumber ).replace( '%', '' ) );
1646
1850
  let revisedPercentage = Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 );
1647
1851
  const revised = Number( Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 ) );
1648
1852
  const tangoReview = Number( getConfig?.footfallDirectoryConfigs?.tangoReview?.split( '%' )[0] );
1649
- logger.info( { tangoReview, revised } );
1650
1853
  // If autoclose enabled and revisedPercentage meets/exceeds threshold, close ticket and skip revision
1651
1854
  if (
1652
1855
  isAutoCloseEnable === true &&