tango-app-api-analysis-traffic 3.8.7-vms.33 → 3.8.7-vms.35

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.33",
3
+ "version": "3.8.7-vms.35",
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.5.14",
26
+ "tango-api-schema": "^2.5.5",
27
27
  "tango-app-api-middleware": "^3.6.5",
28
28
  "winston": "^3.13.1",
29
29
  "winston-daily-rotate-file": "^5.0.0"
@@ -3,7 +3,6 @@ import { aggregateStore } from '../services/stores.service.js';
3
3
  import { findOneNobBilling, updateOneNobBilling } from '../services/nob.service.js';
4
4
  import dayjs from 'dayjs';
5
5
  import { findOne } from '../services/clients.services.js';
6
- import { find } from '../services/tagging.service.js';
7
6
 
8
7
  export async function storeList( req, res ) {
9
8
  try {
@@ -28,7 +27,7 @@ export async function storeList( req, res ) {
28
27
  );
29
28
  }
30
29
 
31
- const query = [
30
+ const query =[
32
31
  {
33
32
  $match: {
34
33
  $and: filter,
@@ -60,12 +59,11 @@ export async function storeList( req, res ) {
60
59
 
61
60
  export async function addBills( req, res ) {
62
61
  try {
63
- let resData = [];
62
+ let resData=[];
64
63
  const openSearch = JSON.parse( process.env.OPENSEARCH );
65
64
  const inputData = req.tempInserData;
66
- console.log( '🚀 ~ addBills ~ inputData:', inputData );
67
65
 
68
- for ( let i = 0; i < inputData?.length; i++ ) {
66
+ for ( let i=0; i<inputData?.length; i++ ) {
69
67
  await updateOneNobBilling( inputData[i]?.query, inputData[i]?.data );
70
68
  const getData = await findOneNobBilling( inputData[i]?.query, { _id: 0 } );
71
69
  if ( !inputData[i]?.isUpdated ) {
@@ -79,7 +77,7 @@ export async function addBills( req, res ) {
79
77
  logger.info( { resData: resData } );
80
78
  return res.sendSuccess( 'Data has been inserted/updated successfully' );
81
79
  } catch ( error ) {
82
- const err = error.message || 'Internal Server Error';
80
+ const err= error.message || 'Internal Server Error';
83
81
  logger.error( { error: error, message: req.body, function: 'nob-addBills' } );
84
82
  return res.sendError( err, 500 );
85
83
  }
@@ -93,7 +91,7 @@ export async function getNobData( req, res ) {
93
91
  return res.sendError( 'No data found', 204 );
94
92
  }
95
93
  const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( new Date( inputData.toDate ) ) );
96
- let temp = {};
94
+ let temp ={};
97
95
  let filter = [
98
96
  {
99
97
  'terms': {
@@ -101,12 +99,8 @@ export async function getNobData( req, res ) {
101
99
  },
102
100
  },
103
101
  {
104
- range: {
105
- nobDate: {
106
- gte: dateRange.start,
107
- lte: dateRange.end,
108
- },
109
- },
102
+ range: { nobDate: { gte: dateRange.start,
103
+ lte: dateRange.end } },
110
104
  },
111
105
  ];
112
106
  if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango' ) {
@@ -122,7 +116,7 @@ export async function getNobData( req, res ) {
122
116
  'must': filter,
123
117
  };
124
118
 
125
- if ( inputData.searchValue && inputData.searchValue !== '' ) {
119
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
126
120
  const searchValue = escapeSpecialChars( inputData.searchValue );
127
121
  temp = {
128
122
 
@@ -155,9 +149,9 @@ export async function getNobData( req, res ) {
155
149
  }
156
150
  const getClient = await findOne( { clientId: req.clientId }, { featureConfigs: 1 } );
157
151
  const openSearch = JSON.parse( process.env.OPENSEARCH );
158
- const limit = inputData.isExport ? 10000 : inputData.limit || 200;
159
- const skip = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
160
- const nobQuery = {
152
+ const limit = inputData.isExport? 10000 : inputData.limit || 200;
153
+ const skip = inputData.offset? ( inputData.offset - 1 ) * limit : 0;
154
+ const nobQuery={
161
155
  'from': skip,
162
156
  'size': limit,
163
157
  'query': {
@@ -165,17 +159,17 @@ export async function getNobData( req, res ) {
165
159
  },
166
160
  };
167
161
 
168
- const getNobData = await getOpenSearchData( openSearch.nob, nobQuery );
162
+ const getNobData=await getOpenSearchData( openSearch.nob, nobQuery );
169
163
  const nobData = getNobData?.body?.hits?.hits;
170
- if ( !nobData || nobData?.length == 0 ) {
171
- if ( inputData.searchValue && inputData.searchValue !== '' || inputData.offset > 1 ) {
164
+ if ( !nobData ||nobData?.length == 0 ) {
165
+ if ( inputData.searchValue && inputData.searchValue!== '' || inputData.offset> 1 ) {
172
166
  return res.sendError( 'No Data Found', 204 );
173
167
  } else {
174
168
  return res.sendSuccess( { initialInsert: false } );
175
169
  }
176
170
  }
177
171
 
178
- const footfallQuery = {
172
+ const footfallQuery={
179
173
  'size': 10000,
180
174
  'query': {
181
175
  'bool': {
@@ -186,33 +180,29 @@ export async function getNobData( req, res ) {
186
180
  },
187
181
  },
188
182
  {
189
- range: {
190
- date_iso: {
191
- gte: `${inputData.fromDate}T00:00:00`,
192
- lte: `${inputData.toDate}T00:00:00`,
193
- },
194
- },
183
+ range: { date_iso: { gte: `${inputData.fromDate}T00:00:00`,
184
+ lte: `${inputData.toDate}T00:00:00` } },
195
185
  },
196
186
  ],
197
187
  },
198
188
  },
199
189
  };
200
190
 
201
- const getFootfall = await getOpenSearchData( openSearch.footfall, footfallQuery );
191
+ const getFootfall= await getOpenSearchData( openSearch.footfall, footfallQuery );
202
192
  const footfall = getFootfall?.body?.hits?.hits;
203
193
  logger.info( { footfall: getFootfall, nobData: nobData } );
204
- let result = [];
194
+ let result=[];
205
195
  nobData.map( async ( data ) => {
206
196
  let count = 0;
207
- let temp = [];
197
+ let temp=[];
208
198
 
209
- data._source.isUpdated = data._source.createdAt !== data._source.updatedAt ? true : false;
210
- !data._source.isUpdated ? isEdit = true : null;
199
+ data._source.isUpdated = data._source.createdAt !== data._source.updatedAt? true : false;
200
+ !data._source.isUpdated ? isEdit = true: null;
211
201
 
212
202
  footfall.map( ( item ) => {
213
203
  if ( ( data._source.dateString === item._source.date_string ) && ( data._source.storeId === item._source.store_id ) ) {
214
204
  count = 1;
215
- temp = [
205
+ temp =[
216
206
  {
217
207
  storeName: item._source.store_name,
218
208
  footfallCount: item._source.footfall_count,
@@ -227,16 +217,16 @@ export async function getNobData( req, res ) {
227
217
  if ( count === 1 ) {
228
218
  switch ( getClient?.featureConfigs?.conversionCalculation ) {
229
219
  case 'footfall-count':
230
- conversionCount = temp[0]?.footfallCount ? ( data?._source?.nobCount / temp[0]?.footfallCount ) * 100 : null;
220
+ conversionCount = temp[0]?.footfallCount? ( data?._source?.nobCount/temp[0]?.footfallCount )*100 : null;
231
221
  break;
232
222
  case 'billable-entities':
233
- conversionCount = temp[0]?.potentialBuyers ? ( data?._source?.nobCount / temp[0]?.potentialBuyers ) * 100 : null;
223
+ conversionCount = temp[0]?.potentialBuyers? ( data?._source?.nobCount/temp[0]?.potentialBuyers )*100 : null;
234
224
  break;
235
225
  case 'engagers-count':
236
- conversionCount = temp[0]?.engagersCount ? ( data?._source?.nobCount / temp[0]?.engagersCount ) * 100 : null;
226
+ conversionCount = temp[0]?.engagersCount? ( data?._source?.nobCount/temp[0]?.engagersCount )*100 : null;
237
227
  break;
238
228
  default:
239
- conversionCount = temp[0]?.engagersCount ? ( data?._source?.nobCount / temp[0]?.engagersCount ) * 100 : null;
229
+ conversionCount = temp[0]?.engagersCount? ( data?._source?.nobCount/temp[0]?.engagersCount )*100 : null;
240
230
  }
241
231
  result.push( {
242
232
 
@@ -245,7 +235,7 @@ export async function getNobData( req, res ) {
245
235
  footfallCount: temp[0]?.footfallCount || null,
246
236
  engagersCount: temp[0]?.engagersCount || null,
247
237
  potentialBuyers: temp[0]?.potentialBuyers || null,
248
- conversionRate: conversionCount == null ? null : `${Math.round( conversionCount )} %`,
238
+ conversionRate: conversionCount == null ? null :`${Math.round( conversionCount )} %`,
249
239
 
250
240
  } );
251
241
  } else {
@@ -289,7 +279,7 @@ export async function getNobData( req, res ) {
289
279
  default:
290
280
  exportData[index]['Engagers Count'] = element.engagersCount;
291
281
  }
292
- element.conversionRate ? exportData[index]['Conversion Rate'] = `${element.conversionRate}` : exportData[index]['Conversion Rate'] = null;
282
+ element.conversionRate? exportData[index]['Conversion Rate'] = `${element.conversionRate}` : exportData[index]['Conversion Rate'] =null;
293
283
  } );
294
284
  return exportData;
295
285
  } );
@@ -311,66 +301,3 @@ export async function getNobData( req, res ) {
311
301
  function escapeSpecialChars( str ) {
312
302
  return str.replace( /[-[\]{}()*+?.,\\^$|#]/g, '\\$&' );
313
303
  }
314
-
315
-
316
- export async function zonelist( req, res ) {
317
- try {
318
- let zonelist = await find( { storeId: { $in: req.body.storeId }, productName: 'tangoZone' }, { tagName: 1 } );
319
- return res.sendSuccess( zonelist );
320
- } catch ( error ) {
321
- const err = error.message || 'Internal Server Error';
322
- logger.error( { error: error, message: req.body, function: 'nob-getNobData' } );
323
- return res.sendError( err, 500 );
324
- }
325
- }
326
- export async function zonetemplate( req, res ) {
327
- try {
328
- if ( req.user.userType === 'tango'||req.user.userType === 'client'&&req.user.role==='superadmin' ) {
329
- let storeList = await aggregateStore(
330
- [
331
- {
332
- $match: {
333
- clientId: req.body.clientId,
334
- },
335
- },
336
- ],
337
- );
338
-
339
-
340
- let stores = storeList.map( ( data ) => data.storeId );
341
-
342
- req.body.assignedStores = stores;
343
- }
344
-
345
-
346
- let exportData = [];
347
- const zonelist = await find(
348
- { storeId: { $in: req.body.assignedStores }, productName: 'tangoZone' },
349
- { tagName: 1, storeId: 1 },
350
- );
351
- let uniqueZone = zonelist.map( ( data ) => data.tagName );
352
-
353
- for ( const element of req.body.assignedStores ) {
354
- const row = {
355
- 'Store Id': element,
356
- 'NoB Date': '',
357
- 'Overall NoB Count': '',
358
- };
359
-
360
- // make tagName as key
361
- uniqueZone.forEach( ( zone ) => {
362
- row[zone] = ''; // or 0 / true / any value you want
363
- } );
364
-
365
- exportData.push( row );
366
- }
367
-
368
-
369
- await download( exportData, res );
370
- return;
371
- } catch ( error ) {
372
- const err = error.message || 'Internal Server Error';
373
- logger.error( { error: error, message: req.body, function: 'nob-getNobData' } );
374
- return res.sendError( err, 500 );
375
- }
376
- }
@@ -3,7 +3,7 @@ import { findOnerevopConfig } from '../services/revopConfig.service.js';
3
3
  import * as clientService from '../services/clients.services.js';
4
4
  import { bulkUpdate, insertWithId, scrollResponse, searchOpenSearchData, upsertWithScript } from 'tango-app-api-middleware/src/utils/openSearch.js';
5
5
  import { findOneVmsStoreRequest } from '../services/vmsStoreRequest.service.js';
6
- // import dayjs from 'dayjs';
6
+ import dayjs from 'dayjs';
7
7
  // Lamda Service Call //
8
8
  async function LamdaServiceCall( url, data ) {
9
9
  try {
@@ -584,12 +584,11 @@ export async function migrateRevopIndex( req, res ) {
584
584
  export async function expireReviewStatus( req, res ) {
585
585
  try {
586
586
  const {
587
- thresholdDate = '2025-12-20',
587
+ thresholdDate = '2025-12-29',
588
588
  batchSize = 500,
589
589
  storeId,
590
590
  dateString,
591
591
  } = req.body;
592
- logger.info( { inputData: req.body, msg: '........1' } );
593
592
  const cutoffDate = new Date( thresholdDate );
594
593
  if ( Number.isNaN( cutoffDate.getTime() ) ) {
595
594
  return res.sendError( 'Invalid thresholdDate', 400 );
@@ -632,7 +631,6 @@ export async function expireReviewStatus( req, res ) {
632
631
 
633
632
  let firstResponse = await searchOpenSearchData( openSearch.footfallDirectory, query );
634
633
  let hitsBatch = firstResponse?.body?.hits?.hits || [];
635
- logger.info( { hitsBatch } );
636
634
  scrollId = firstResponse?.body?._scroll_id;
637
635
 
638
636
  while ( hitsBatch.length > 0 ) {
@@ -642,25 +640,38 @@ export async function expireReviewStatus( req, res ) {
642
640
  const src = hit._source || {};
643
641
  const mappingInfo = Array.isArray( src.mappingInfo ) ? src.mappingInfo : [];
644
642
  let changed = false;
645
- const updatedMapping = mappingInfo.map( ( item ) => {
643
+ let updatedMapping = mappingInfo.map( ( item ) => {
646
644
  if ( item?.type === 'review'&& item?.type !== 'Closed' && item?.dueDate ) {
647
645
  const due = new Date( item.dueDate );
648
646
  logger.info( { due, msg: '..........1', cutoffDate } );
649
647
  if ( !Number.isNaN( due.getTime() ) && due < cutoffDate ) {
650
648
  changed = true;
649
+
651
650
  return { ...item, status: 'Expired' };
652
651
  }
653
652
  }
653
+
654
654
  return item;
655
655
  } );
656
656
 
657
+ if ( changed ) {
658
+ logger.info( { changed, msg: '.......2' } );
659
+ updatedMapping = updatedMapping.map( ( item ) => {
660
+ logger.info( { item, msg: '.......3' } );
661
+ if ( item?.type === 'tagging' ) {
662
+ logger.info( { item: item?.type, msg: '.......4' } );
663
+ return { ...item, status: 'Expired' };
664
+ }
665
+ } );
666
+ }
667
+
657
668
 
658
669
  if ( changed ) {
659
670
  const doc = {
660
671
  mappingInfo: updatedMapping,
661
672
  status: 'Expired',
662
673
  };
663
-
674
+ logger.info( { updatedMapping } );
664
675
  bulkBody.push(
665
676
  { update: { _index: openSearch.footfallDirectory, _id: hit._id } },
666
677
  { doc: doc, doc_as_upsert: true },
@@ -1099,7 +1110,7 @@ export async function footFallImages( req, res ) {
1099
1110
  actionType: type,
1100
1111
  footfall: footfallValue,
1101
1112
  revicedFootfall: mapping.revicedFootfall ?? 0,
1102
- revicedPerc: mapping.revicedPerc ?? '--',
1113
+ revicedPerc: mapping?.reviced?.toString() ?? '--',
1103
1114
  count: countObj,
1104
1115
  createdAt: mapping.createdAt ?? '',
1105
1116
  createdByEmail: mapping.createdByEmail ?? '',
@@ -1114,7 +1125,7 @@ export async function footFallImages( req, res ) {
1114
1125
  actionType: type,
1115
1126
  footfall: footfallValue,
1116
1127
  revicedFootfall: mapping.revicedFootfall ?? 0,
1117
- revicedPerc: mapping.revicedPerc ?? '--',
1128
+ revicedPerc: mapping?.reviced?.toString() ?? '--',
1118
1129
  count: countObj,
1119
1130
  createdAt: mapping.createdAt ?? '',
1120
1131
  createdByEmail: mapping.createdByEmail ?? '',
@@ -1148,8 +1159,15 @@ export async function footFallImages( req, res ) {
1148
1159
 
1149
1160
  export async function tagTempId( req, res ) {
1150
1161
  try {
1151
- const openSearch = JSON.parse( process.env.OPENSEARCH );
1152
1162
  const inputData = req.body;
1163
+ const today = dayjs();
1164
+ const diff = today.diff( inputData.dateString, 'day' );
1165
+ const taggingDueDate = req?.client?.footfallDirectoryConfigs?.allowTangoReview || 0;
1166
+ if ( diff > taggingDueDate ) {
1167
+ return res.sendError( `Tagging is not allowed for a period exceeding ${taggingDueDate} days`, 400 );
1168
+ }
1169
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
1170
+
1153
1171
  const upsertRecord = {
1154
1172
  clientId: inputData.storeId.split( '-' )[0],
1155
1173
  storeId: inputData.storeId,
@@ -21,19 +21,6 @@ export const addBillsSchema = joi.object( {
21
21
  'string.empty': 'Please enter a valid NOB Count',
22
22
  'any.required': 'NOB Count is required',
23
23
  } ).allow( null ),
24
- zonewisenob: joi.array().items(
25
- joi.object( {
26
- zoneName: joi.string().required().messages( {
27
- 'string.empty': 'Zone name is required',
28
- 'any.required': 'Zone name is required',
29
- } ),
30
-
31
- nobCount: joi.number().required().messages( {
32
- 'number.base': 'Please enter a valid Zone NOB Count',
33
- 'any.required': 'Zone NOB Count is required',
34
- } ),
35
- } ),
36
- ).optional(),
37
24
  } ),
38
25
  ).required(),
39
26
 
@@ -48,18 +48,10 @@ export const tagTempIdSchema = joi.object( {
48
48
  storeId: joi.string().required(),
49
49
  dateString: joi.string().required().custom( ( value, helpers ) => {
50
50
  const inputDate = dayjs( value, 'YYYY-MM-DD', true );
51
- const today = dayjs();
52
51
 
53
52
  if ( !inputDate.isValid() ) {
54
53
  return helpers.error( 'any.invalid' );
55
54
  }
56
-
57
- const diff = today.diff( inputDate, 'day' );
58
-
59
- if ( diff > 3 ) {
60
- return helpers.message( 'Tagging is not allowed for a period exceeding 3 days' );
61
- }
62
-
63
55
  return value;
64
56
  } ), // yyyy-mm-dd
65
57
  tempId: joi.number().required(),
@@ -1,7 +1,7 @@
1
1
  import express from 'express';
2
2
  import { accessVerification, bulkValidate, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
3
  import { addBillsValid, getNobDataValid, storeListValid } from '../dtos/nob.dtos.js';
4
- import { addBills, getNobData, storeList, zonelist, zonetemplate } from '../controllers/nob.controllers.js';
4
+ import { addBills, getNobData, storeList } from '../controllers/nob.controllers.js';
5
5
  import { clientValidations, fieldValidation, roleVerification } from '../validations/nob.validations.js';
6
6
 
7
7
  const nobRouter=express.Router();
@@ -13,8 +13,4 @@ nobRouter.post( '/add-bills', isAllowedSessionHandler, accessVerification( { use
13
13
 
14
14
  nobRouter.post( '/get-nob-data', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( getNobDataValid ), clientValidations, getAssinedStore, getNobData );
15
15
 
16
- nobRouter.post( '/zonelist', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), zonelist );
17
-
18
- nobRouter.post( '/zonetemplate', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), getAssinedStore, zonetemplate );
19
-
20
16
  export default nobRouter;
@@ -1,7 +1,6 @@
1
1
  import nobBillingModel from 'tango-api-schema/schema/nobBilling.model.js';
2
2
 
3
3
  export async function updateOneNobBilling( query, record ) {
4
- console.log( '🚀 ~ updateOneNobBilling ~ record:', record );
5
4
  return await nobBillingModel.updateOne( query, { $set: record }, { upsert: true } );
6
5
  }
7
6
 
@@ -121,7 +121,6 @@ export async function fieldValidation( req, res, next ) {
121
121
  nobDate: nobDateIso,
122
122
  nobCount: inputFilter[i]?.nobCount,
123
123
  dateString: inputFilter[i]?.nobDate,
124
- zonewisenob: inputFilter[i]?.zonewisenob?inputFilter[i]?.zonewisenob:[],
125
124
  };
126
125
  const query ={ storeId: storeData[0]?.storeId, nobDate: inputFilter[i]?.nobDate };
127
126
 
@@ -241,6 +241,7 @@ export async function mappingConfig( req, res, next ) {
241
241
  },
242
242
  ];
243
243
  const getConfig = await aggregate( configQuery );
244
+ req.client = getConfig[0];
244
245
  const taggingLimitation = getConfig?.[0]?.effectiveLimitation?.values;
245
246
 
246
247
  // Find the tagging limitation for the given revopsType