tango-app-api-analysis-traffic 3.8.7-vms.1 → 3.8.7-vms.10

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-analysis-traffic",
3
- "version": "3.8.7-vms.1",
3
+ "version": "3.8.7-vms.10",
4
4
  "description": "Traffic Analysis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  "mongodb": "^6.8.0",
24
24
  "nodemon": "^3.1.4",
25
25
  "swagger-ui-express": "^5.0.1",
26
- "tango-api-schema": "^2.4.23",
26
+ "tango-api-schema": "^2.4.29",
27
27
  "tango-app-api-middleware": "^3.6.5",
28
28
  "winston": "^3.13.1",
29
29
  "winston-daily-rotate-file": "^5.0.0"
@@ -221,6 +221,9 @@ export async function storeProcessedData( req, res ) {
221
221
  dayjs.extend( isSameOrBefore );
222
222
 
223
223
  let start = dayjs( fromDate );
224
+ // get start value from the before day one
225
+ // Move start one day back so we can access "day before" when looping
226
+ start = start.subtract( 1, 'day' );
224
227
  let end = dayjs( toDate );
225
228
 
226
229
  if ( !start.isValid() || !end.isValid() ) {
@@ -267,10 +270,12 @@ export async function storeProcessedData( req, res ) {
267
270
 
268
271
  const responseArray = [];
269
272
 
270
- for ( let i = 0; i < orderedDates.length; i++ ) {
273
+ for ( let i = 1; i < orderedDates.length; i++ ) {
271
274
  const currentDate = orderedDates[i];
272
275
  const currentId = `${storeId}_${currentDate}`;
276
+ logger.info( { currentId, currentDate } );
273
277
  const processedData = hitsMap.get( currentId );
278
+ logger.info( { processedData } );
274
279
  if ( !processedData ) {
275
280
  responseArray.push( {
276
281
  date: currentDate,
@@ -283,13 +288,17 @@ export async function storeProcessedData( req, res ) {
283
288
 
284
289
  const prevDate = dayjs( currentDate ).subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
285
290
  const prevId = `${storeId}_${prevDate}`;
291
+ logger.info( { prevId, prevDate } );
286
292
  const previousData = hitsMap.get( prevId );
287
293
 
288
294
  let footfallCountTrend = 0;
295
+ logger.info( { previousData, previoucubr1: previousData?.footfall_count } );
289
296
  if ( previousData && previousData.footfall_count ) {
297
+ logger.info( { previousData, previoucubr: previousData?.footfall_count } );
290
298
  footfallCountTrend = Math.round(
291
- ( ( processedData.footfall_count - previousData.footfall_count ) / previousData.footfall_count ) * 100,
299
+ ( ( processedData.footfall_count - previousData?.footfall_count ) / previousData.footfall_count ) * 100,
292
300
  );
301
+ logger.info( { footfallCountTrend } );
293
302
  }
294
303
  // Add ticket status from openSearch.footfallDirectory (_source.status)
295
304
  let ticketStatus = null;
@@ -306,12 +315,19 @@ export async function storeProcessedData( req, res ) {
306
315
  },
307
316
  },
308
317
  size: 1,
309
- _source: [ 'status' ],
318
+ _source: [ 'status', 'mappingInfo' ],
310
319
  };
311
320
  try {
312
321
  const footfallDirRes = await getOpenSearchData( openSearch.footfallDirectory, footfallDirQuery );
313
322
  const hit = footfallDirRes?.body?.hits?.hits?.[0];
314
- ticketStatus = hit?._source?.status || null;
323
+ if ( hit?._source?.mappingInfo && Array.isArray( hit._source.mappingInfo ) ) {
324
+ for ( let i = 0; i < hit._source.mappingInfo.length; i++ ) {
325
+ if ( hit._source.mappingInfo[i].type === 'tagging' ) {
326
+ ticketStatus = hit._source.mappingInfo[i].status;
327
+ break;
328
+ }
329
+ }
330
+ }
315
331
  } catch ( err ) {
316
332
  logger.warn( { message: 'Could not get ticket status from footfallDirectory', error: err } );
317
333
  }
@@ -335,7 +351,27 @@ export async function storeProcessedData( req, res ) {
335
351
  downtime: processedData?.down_time || 0,
336
352
  ticketStatus,
337
353
  raisedStatusEnabled,
354
+
338
355
  } );
356
+
357
+ if ( raisedStatusEnabled === 'block' ) {
358
+ // Calculate the number of days from currentDate + 1 to the end of the month
359
+ // Assume currentDate is in format 'YYYY-MM-DD'
360
+ const currentDateObj = new Date( currentDate );
361
+ // Move to next day
362
+ const nextDay = new Date( currentDateObj );
363
+ nextDay.setDate( currentDateObj.getDate() + 1 );
364
+
365
+ // Get the last date of the current month
366
+ const endOfMonth = new Date( currentDateObj.getFullYear(), currentDateObj.getMonth() + 1, 0 );
367
+
368
+ // Calculate number of days (inclusive of end date, exclusive of nextDay)
369
+ let noOfBlockedDays = Math.floor( ( endOfMonth - nextDay ) / ( 1000 * 60 * 60 * 24 ) ) + 1;
370
+ if ( noOfBlockedDays < 0 ) noOfBlockedDays = 0;
371
+
372
+ // Add to response
373
+ responseArray[responseArray.length - 1].noOfBlockedDays = noOfBlockedDays;
374
+ }
339
375
  }
340
376
 
341
377
  return res.sendSuccess( responseArray );
@@ -379,40 +415,177 @@ export async function footFallImages( req, res ) {
379
415
  ],
380
416
  },
381
417
  },
382
- '_source': [ 'dateString', 'storeId', 'duplicateCount', 'footfallCount', 'employeeCount', 'houseKeepingCount', 'junkCount', 'status', 'ticketId', 'comments', 'userName', 'role', 'createdAt', 'email', 'houseKeepingACCount', 'duplicateACCount', 'employeeACCount', 'junkACCount', 'approverEmail', 'approverRole', 'approverUserName' ],
418
+ '_source': [ 'dateString', 'storeId', 'mappingInfo', 'revicedFootfall', 'revicedPerc', 'createdAt', 'updatedAt', 'footfallCount' ],
383
419
 
384
420
  };
385
421
 
386
422
  const getData = await getOpenSearchData( opensearch.footfallDirectory, query );
387
423
  const ticketDetails = getData?.body?.hits?.hits[0];
388
424
  let temp = [];
389
- ticketDetails?._source? temp.push( ticketDetails?._source ) :null;
390
- // temp[0].status = 'open';
391
- if ( ticketDetails?._source?.status == 'closed' ) {
392
- delete temp[0].status;
393
- temp.push( { ...ticketDetails?._source, status: 'closed' } );
394
-
395
- temp[1].userName = getData?.body?.hits?.hits?.[0]?._source?.approverUserName;
396
- temp[1].email = getData?.body?.hits?.hits?.[0]?._source?.approverEmail;
397
- temp[1].role = getData?.body?.hits?.hits?.[0]?._source?.approverRole;
398
- temp[1].employeeCount = getData?.body?.hits?.hits?.[0]?._source?.employeeACCount;
399
- temp[1].houseKeepingCount = getData?.body?.hits?.hits?.[0]?._source?.houseKeepingACCount;
400
- temp[1].duplicateCount = getData?.body?.hits?.hits?.[0]?._source?.duplicateACCount;
401
- temp[1].junkCount = getData?.body?.hits?.hits?.[0]?._source?.junkACCount;
402
- }
403
- const LamdaURL = revop.getImages;
404
- let resultData = await LamdaServiceCall( LamdaURL, inputData );
405
- logger.info( { resultData: resultData } );
406
- if ( resultData ) {
407
- temp.length? temp[0].status = 'open': null;
408
- if ( resultData.status_code == '200' ) {
409
- return res.sendSuccess( { ...resultData, ticketStatus: temp?.length > 0? temp : null, config: req?.store?.revopTagging } );
410
- } else {
411
- return res.sendError( 'No Content', 204 );
412
- }
413
- } else {
414
- return res.sendError( 'No Content', 204 );
415
- }
425
+ const footfallValue = ticketDetails?._source?.footfallCount ?? 0;
426
+ const mappingInfoArray = ticketDetails?._source?.mappingInfo ?? [];
427
+ // Helper to get mappingInfo for an actionType
428
+ function getMappingForType( type ) {
429
+ return mappingInfoArray.find( ( m ) => m.type === type ) || {};
430
+ }
431
+
432
+ // List of actionTypes to process in sequence
433
+
434
+ if ( req.user.userType !== 'tango' && req.user.role !== 'superadmin' ) {
435
+ switch ( req.user.role ) {
436
+ case 'user':
437
+ const actionTypesUser = [ 'tagging', 'finalreview' ];
438
+
439
+ temp = [];
440
+ actionTypesUser.forEach( ( type ) => {
441
+ const mapping = getMappingForType( type );
442
+ if ( type === 'tagging' ) {
443
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
444
+ const revisedPerc =
445
+ footfallValue > 0 ?
446
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
447
+ '0';
448
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
449
+ temp.push( {
450
+ actionType: type,
451
+ footfall: footfallValue,
452
+ revicedFootfall: revisedFootfall,
453
+ revicedPerc: revisedPerc,
454
+ count: countObj,
455
+ createdAt: mapping.createdAt ?? '',
456
+ createdByEmail: mapping.createdByEmail ?? '',
457
+ createdByUserName: mapping.createdByUserName ?? '',
458
+ createdByRole: mapping.createdByRole ?? '',
459
+ isUp: false,
460
+ } );
461
+ } else if ( type !== 'tagging' && mapping.status === 'closed' ) {
462
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
463
+ const revisedPerc =
464
+ footfallValue > 0 ?
465
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
466
+ '0';
467
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
468
+ temp.push( {
469
+ actionType: type,
470
+ footfall: footfallValue,
471
+ revicedFootfall: revisedFootfall,
472
+ revicedPerc: revisedPerc,
473
+ count: countObj,
474
+ createdAt: mapping.createdAt ?? '',
475
+ createdByEmail: mapping.createdByEmail ?? '',
476
+ createdByUserName: mapping.createdByUserName ?? '',
477
+ createdByRole: mapping.createdByRole ?? '',
478
+ } );
479
+ }
480
+ } );
481
+ break;
482
+ case 'admin':
483
+ const actionTypesAdmin = [ 'tagging', 'review', 'finalreview' ];
484
+ temp = [];
485
+ actionTypesAdmin.forEach( ( type ) => {
486
+ const mapping = getMappingForType( type );
487
+ if ( type === 'tagging' ) {
488
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
489
+ const revisedPerc =
490
+ footfallValue > 0 ?
491
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
492
+ '0';
493
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
494
+ temp.push( {
495
+ actionType: type,
496
+ footfall: footfallValue,
497
+ revicedFootfall: revisedFootfall,
498
+ revicedPerc: revisedPerc,
499
+ count: countObj,
500
+ createdAt: mapping.createdAt ?? '',
501
+ createdByEmail: mapping.createdByEmail ?? '',
502
+ createdByUserName: mapping.createdByUserName ?? '',
503
+ createdByRole: mapping.createdByRole ?? '',
504
+ isUp: false,
505
+ } );
506
+ } else if ( type !== 'tagging' && mapping.status === 'closed' ) {
507
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
508
+ const revisedPerc =
509
+ footfallValue > 0 ?
510
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
511
+ '0';
512
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
513
+ temp.push( {
514
+ actionType: type,
515
+ footfall: footfallValue,
516
+ revicedFootfall: revisedFootfall,
517
+ revicedPerc: revisedPerc,
518
+ count: countObj,
519
+ createdAt: mapping.createdAt ?? '',
520
+ createdByEmail: mapping.createdByEmail ?? '',
521
+ createdByUserName: mapping.createdByUserName ?? '',
522
+ createdByRole: mapping.createdByRole ?? '',
523
+ } );
524
+ }
525
+ } );
526
+ }
527
+ } else {
528
+ const actionTypes = [ 'tagging', 'review', 'approve', 'finalreview' ];
529
+
530
+ // Dynamically add to temp only if actionType matches and status is 'closed',
531
+ // except for 'tagging' where status must be 'raised'
532
+ temp = [];
533
+ actionTypes.forEach( ( type ) => {
534
+ const mapping = getMappingForType( type );
535
+ if ( type === 'tagging' ) {
536
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
537
+ const revisedPerc =
538
+ footfallValue > 0 ?
539
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
540
+ '0';
541
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
542
+ temp.push( {
543
+ actionType: type,
544
+ footfall: footfallValue,
545
+ revicedFootfall: revisedFootfall,
546
+ revicedPerc: revisedPerc,
547
+ count: countObj,
548
+ createdAt: mapping.createdAt ?? '',
549
+ createdByEmail: mapping.createdByEmail ?? '',
550
+ createdByUserName: mapping.createdByUserName ?? '',
551
+ createdByRole: mapping.createdByRole ?? '',
552
+ isUp: false,
553
+ } );
554
+ } else if ( type !== 'tagging' && mapping.status === 'closed' ) {
555
+ const revisedFootfall = mapping.revicedFootfall ?? 0;
556
+ const revisedPerc =
557
+ footfallValue > 0 ?
558
+ `${Math.round( ( revisedFootfall / footfallValue ) * 100 )}` :
559
+ '0';
560
+ const countObj = mapping.count ? [ ...mapping.count ] : [];
561
+ temp.push( {
562
+ actionType: type,
563
+ footfall: footfallValue,
564
+ revicedFootfall: revisedFootfall,
565
+ revicedPerc: revisedPerc,
566
+ count: countObj,
567
+ createdAt: mapping.createdAt ?? '',
568
+ createdByEmail: mapping.createdByEmail ?? '',
569
+ createdByUserName: mapping.createdByUserName ?? '',
570
+ createdByRole: mapping.createdByRole ?? '',
571
+ } );
572
+ }
573
+ } );
574
+ }
575
+
576
+
577
+ const LamdaURL = revop.getImages;
578
+ let resultData = await LamdaServiceCall( LamdaURL, inputData );
579
+ if ( resultData ) {
580
+ // temp.length? temp[0].status = 'open': null;
581
+ if ( resultData.status_code == '200' ) {
582
+ return res.sendSuccess( { ...resultData, ticketStatus: temp?.length > 0 && ticketDetails? temp : null, config: req?.store?.footfallDirectoryConfigs } );
583
+ } else {
584
+ return res.sendError( 'No Content', 204 );
585
+ }
586
+ } else {
587
+ return res.sendError( 'No Content', 204 );
588
+ }
416
589
  } catch ( error ) {
417
590
  logger.error( { message: error, data: req.query, function: 'storeProcessedData' } );
418
591
  const err = error.message || 'Internal Server Error';
@@ -440,6 +613,13 @@ export async function tagTempId( req, res ) {
440
613
  description: '',
441
614
  isChecked: inputData.isChecked,
442
615
  duplicateImage: inputData?.duplicateImage?.length>0? inputData?.duplicateImage :[],
616
+ // Add id to each object in duplicateImage if it exists and is an array
617
+ duplicateImage: Array.isArray( inputData?.duplicateImage ) ?
618
+ inputData.duplicateImage.map( ( img ) => ( {
619
+ ...img,
620
+ id: `${inputData?.storeId}_${inputData?.dateString}_${img?.tempId}`,
621
+ } ) ) :
622
+ [],
443
623
  type: 'tagging-reflect',
444
624
  ticketStatus: 'submitted',
445
625
  isParent: inputData?.revopsType === 'duplicate'? true : false,
@@ -449,6 +629,7 @@ export async function tagTempId( req, res ) {
449
629
  action: 'submitted',
450
630
  },
451
631
  ],
632
+ comments: inputData.comments || '',
452
633
  createdAt: new Date(),
453
634
  updatedAt: new Date(),
454
635
 
@@ -502,6 +683,7 @@ export async function tagTempId( req, res ) {
502
683
  isParent: false,
503
684
  type: 'tagging-reflect',
504
685
  ticketStatus: 'submitted',
686
+ comments: inputData.comments || '',
505
687
  actions: [
506
688
  {
507
689
  actionType: 'tagging',
@@ -66,6 +66,9 @@ export const tagTempIdSchema = joi.object( {
66
66
  revopsType: joi.string().required(),
67
67
  timeRange: joi.string().required(),
68
68
  isChecked: joi.boolean().required().allow( null ),
69
+ mode: joi.string().valid( 'web', 'mobile' ).required().messages( {
70
+ 'any.only': 'type must be one of [mobile,web]',
71
+ } ),
69
72
  duplicateImage: joi.array().items( joi.object(
70
73
  {
71
74
  tempId: joi.number().required(),
@@ -81,6 +84,7 @@ export const tagTempIdSchema = joi.object( {
81
84
  entryTime: joi.string().required(),
82
85
  exitTime: joi.string().required(),
83
86
  filePath: joi.string().required(),
87
+ comments: joi.string().optional().allow( '' ),
84
88
 
85
89
  } );
86
90
 
@@ -1,11 +1,24 @@
1
1
  import { getOpenSearchCount, logger } from 'tango-app-api-middleware';
2
- import { findOneStore } from '../services/stores.service.js';
3
- import { deleteByQuery } from 'tango-app-api-middleware/src/utils/openSearch.js';
2
+ import { deleteByQuery, getOpenSearchData } from 'tango-app-api-middleware/src/utils/openSearch.js';
3
+ import { findOne } from '../services/clients.services.js';
4
4
 
5
5
  export async function getTaggingConfig( req, res, next ) {
6
6
  try {
7
7
  const inputData= req.query;
8
- const getData = await findOneStore( { storeId: inputData.storeId }, { revopTagging: 1 } );
8
+ const clientId = inputData.storeId.split( '-' )[0];
9
+ const getData = await findOne( { clientId: clientId }, { footfallDirectoryConfigs: 1 } );
10
+
11
+ // Convert "taggingLimitation" array (if present) to "config" object with expected key-value pairs
12
+ let config = {};
13
+ if ( getData && Array.isArray( getData.taggingLimitation ) ) {
14
+ for ( const item of getData.taggingLimitation ) {
15
+ if ( item && item.type && typeof item.value !== 'undefined' && item.unit ) {
16
+ config[item.type] = `${item.value}${item.unit}`;
17
+ }
18
+ }
19
+ }
20
+ getData.config = config;
21
+
9
22
  req.store = getData;
10
23
  next();
11
24
  } catch ( error ) {
@@ -51,41 +64,54 @@ export async function getFootfallCount( req, res, next ) {
51
64
  export async function mappingConfig( req, res, next ) {
52
65
  try {
53
66
  const inputData = req.body;
67
+
54
68
  const openSearch = JSON.parse( process.env.OPENSEARCH );
55
- const config =await findOneStore( { storeId: inputData.storeId }, { revopTagging: 1 } );
56
- if ( inputData.revopsType == 'employee' ) {
57
- const getQuery = {
58
- query: {
59
- bool: {
60
- must: [
61
- {
62
- term: {
63
- 'storeId.keyword': inputData.storeId,
64
- },
65
- },
66
- {
67
- term: {
68
- 'dateString': inputData.dateString,
69
- },
69
+ const footfallQuery ={
70
+ query: {
71
+ bool: {
72
+ must: [
73
+ {
74
+ term: {
75
+ 'store_id.keyword': inputData.storeId,
70
76
  },
71
- {
72
- term: {
73
- 'revopsType.keyword': inputData.revopsType,
74
- },
77
+ },
78
+ {
79
+ term: {
80
+ 'date_string': inputData.dateString,
75
81
  },
76
- ],
77
- },
82
+ },
83
+
84
+ ],
78
85
  },
79
- };
86
+ },
87
+ };
80
88
 
81
- const getData = await getOpenSearchCount( openSearch.revop, getQuery );
82
- if ( getData && getData?.body?.count >= config?.revopTagging?.employee ) {
83
- return res.sendError( `Select up to ${config?.revopTagging?.employee} items only`, 400 );
84
- } else {
85
- next();
86
- }
87
- } else if ( inputData.revopsType == 'house-keeping' ) {
88
- const getQuery = {
89
+
90
+ const footfallOutput = await getOpenSearchData( openSearch.footfall, footfallQuery );
91
+ if ( footfallOutput?.body?.hits?.hits?.length === 0 ) {
92
+ return res.sendError( 'No updated footfall for this date', 400 );
93
+ }
94
+ const getFootfallCount = footfallOutput?.body?.hits?.hits;
95
+ const footfall = getFootfallCount?.[0]?._source?.footfall_count;
96
+
97
+ const getConfig = await findOne( { clientId: inputData?.storeId?.split( '-' )[0] }, { footfallDirectoryConfigs: 1 } );
98
+ const taggingLimitation = getConfig?.footfallDirectoryConfigs?.taggingLimitation;
99
+ // Find the tagging limitation for the given revopsType
100
+ let matchedLimitation = null;
101
+ if ( Array.isArray( taggingLimitation ) ) {
102
+ matchedLimitation = taggingLimitation.find(
103
+ ( l ) => l.type === inputData.revopsType,
104
+ );
105
+ }
106
+
107
+ if ( matchedLimitation ) {
108
+ // Determine the limit value
109
+ let limitValue = Number( matchedLimitation.value ) || 0;
110
+ let unit = matchedLimitation.unit;
111
+
112
+ // Assuming getData and/or getOpenSearchCount provides the actual tagged count for revopsType
113
+ // Query OpenSearch for current tagged count for this revopsType
114
+ const taggedCountQuery = {
89
115
  query: {
90
116
  bool: {
91
117
  must: [
@@ -104,92 +130,51 @@ export async function mappingConfig( req, res, next ) {
104
130
  'revopsType.keyword': inputData.revopsType,
105
131
  },
106
132
  },
133
+ {
134
+ term: {
135
+ 'isParent': false,
136
+ },
137
+ },
107
138
  ],
108
139
  },
109
140
  },
110
141
  };
111
- const getData = await getOpenSearchCount( openSearch.revop, getQuery );
112
- if ( getData && getData?.body?.count >= config?.revopTagging?.houseKeeping ) {
113
- return res.sendError( `Select up to ${config?.revopTagging?.houseKeeping} items only`, 400 );
142
+ const taggedData = await getOpenSearchCount( openSearch.revop, taggedCountQuery );
143
+ const taggedValue = ( taggedData?.body?.count || 0 )+ ( inputData.revopsType == 'duplicate'? inputData?.duplicateImage?.length : 1 );
144
+ // If the unit is %, compare percentage of taggedValue/footfall, otherwise compare taggedValue to limitValue directly
145
+ let isLimitExceeded = false;
146
+ if ( unit === '%' ) {
147
+ // footfall may be undefined, treat as 0 (avoid division by zero)
148
+ const totalFootfall = Number( footfall ) || 0;
149
+ const taggedPercent = totalFootfall > 0 ? ( taggedValue / totalFootfall ) * 100 : 0;
150
+ isLimitExceeded = taggedPercent > limitValue;
151
+ logger.info( {
152
+ limitType: 'PERCENT',
153
+ taggedValue,
154
+ totalFootfall,
155
+ taggedPercent,
156
+ limitValue,
157
+ isLimitExceeded,
158
+ forRevopsType: inputData.revopsType,
159
+ } );
114
160
  } else {
115
- next();
161
+ // Non-percent, treat limitValue as an absolute number
162
+ isLimitExceeded = taggedValue > limitValue;
163
+ logger.info( {
164
+ limitType: 'ABSOLUTE',
165
+ taggedValue,
166
+ limitValue,
167
+ isLimitExceeded,
168
+ forRevopsType: inputData.revopsType,
169
+ } );
116
170
  }
117
- } else if ( inputData.revopsType === 'junk' ) {
118
- if ( ( req?.user?.userType == 'client' && req?.user?.userType !== 'user ' ) || req?.user?.userType === 'tango' ) {
119
- next();
120
- return;
121
- } else {
122
- return res.sendError( 'Forbidden to junk mapping', 500 );
171
+ if ( isLimitExceeded ) {
172
+ return res.sendError( `Limit exceed: Only ${limitValue}${unit || ''} items allowed for ${inputData.revopsType}`, 400 );
123
173
  }
174
+ return next();
124
175
  } else {
125
- next();
176
+ return next();
126
177
  }
127
- // else if ( inputData.revopsType == 'duplicate' ) {
128
- // const getFootfallQuery = {
129
- // query: {
130
- // terms: {
131
- // _id: [ inputData?.dateString ],
132
- // },
133
- // },
134
- // _source: [ 'footfall', 'date_string', 'store_id', 'down_time', 'footfall_count' ],
135
- // sort: [
136
- // {
137
- // date_iso: {
138
- // order: 'desc',
139
- // },
140
- // },
141
- // ],
142
- // };
143
-
144
- // const getFootfall = await getOpenSearchData( openSearch.footfall, getFootfallQuery );
145
- // const footfall = getFootfall?.body?.hites?.hits?.[0]?._source?.footfall_count;
146
- // const getQuery = {
147
- // query: {
148
- // bool: {
149
- // must: [
150
- // {
151
- // term: {
152
- // 'storeId.keyword': inputData.storeId,
153
- // },
154
- // },
155
- // {
156
- // term: {
157
- // 'dateString': inputData.dateString,
158
- // },
159
- // },
160
- // {
161
- // term: {
162
- // 'revopsType.keyword': inputData.revopsType,
163
- // },
164
- // },
165
- // {
166
- // term: {
167
- // 'parent.keyword': null,
168
- // },
169
- // },
170
- // ],
171
- // },
172
- // },
173
- // };
174
- // const getData = await getOpenSearchCount( openSearch.revop, getQuery );
175
- // logger.info( { getData: getData, footfall: footfall, duplicate: config?.revopTagging?.duplicate } );
176
- // if ( getData && footfall && config?.revopTagging?.duplicate ) {
177
- // const data = config?.revopTagging?.duplicate;
178
- // // Convert "20%" → 0.2 (handle both "20%" and 20)
179
- // const percentStr = typeof data === 'string' ? data.replace( '%', '' ) : data;
180
- // logger.info( { percentStr: percentStr } );
181
- // const percentValue =percentStr / 100;
182
-
183
- // const result = percentValue * footfall;
184
-
185
- // logger.info( { result: result, footfall: footfall } );
186
- // }
187
- // if ( getData && getData?.body?.count >= Math.round( result ) ) {
188
- // return res.sendError( `Select up to ${config?.revopTagging?.duplicate} items only`, 400 );
189
- // } else {
190
- // next();
191
- // }
192
- // }
193
178
  } catch ( error ) {
194
179
  logger.error( { error: error, message: req.body, function: 'traffic-revop-getTaggingConfig' } );
195
180
  next();