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

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.0",
3
+ "version": "3.8.7-vms.1",
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.9",
26
+ "tango-api-schema": "^2.4.23",
27
27
  "tango-app-api-middleware": "^3.6.5",
28
28
  "winston": "^3.13.1",
29
29
  "winston-daily-rotate-file": "^5.0.0"
@@ -2,7 +2,8 @@ import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData }
2
2
  import { findOnerevopConfig } from '../services/revopConfig.service.js';
3
3
  import * as clientService from '../services/clients.services.js';
4
4
  import { bulkUpdate, upsertWithScript } from 'tango-app-api-middleware/src/utils/openSearch.js';
5
- import dayjs from 'dayjs';
5
+ import { findOneVmsStoreRequest } from '../services/vmsStoreRequest.service.js';
6
+ // import dayjs from 'dayjs';
6
7
  // Lamda Service Call //
7
8
  async function LamdaServiceCall( url, data ) {
8
9
  try {
@@ -211,44 +212,135 @@ export async function storeProcessedData( req, res ) {
211
212
  try {
212
213
  const openSearch = JSON.parse( process.env.OPENSEARCH );
213
214
  const inputData = req.query;
214
- const previousDate = dayjs( inputData.dateString ).subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
215
- const dateString = `${inputData.storeId}_${inputData.dateString}`;
216
- const dateStringPrevious = `${inputData.storeId}_${previousDate}`;
217
- const getQuery = {
218
- query: {
219
- terms: {
220
- _id: [ dateString, dateStringPrevious ],
221
- },
222
- },
223
- _source: [ 'footfall', 'date_string', 'store_id', 'down_time', 'footfall_count' ],
224
- sort: [
225
- {
226
- date_iso: {
227
- order: 'desc',
215
+ const { fromDate, toDate, storeId } = inputData;
216
+
217
+ // Multi-date range handling for a single store
218
+ if ( fromDate && toDate && storeId ) {
219
+ const dayjs = ( await import( 'dayjs' ) ).default;
220
+ const isSameOrBefore = ( await import( 'dayjs/plugin/isSameOrBefore.js' ) ).default;
221
+ dayjs.extend( isSameOrBefore );
222
+
223
+ let start = dayjs( fromDate );
224
+ let end = dayjs( toDate );
225
+
226
+ if ( !start.isValid() || !end.isValid() ) {
227
+ return res.sendError( 'Invalid date range supplied', 400 );
228
+ }
229
+
230
+ if ( end.isBefore( start ) ) {
231
+ [ start, end ] = [ end, start ];
232
+ }
233
+
234
+ const allDateStrings = [];
235
+ const orderedDates = [];
236
+
237
+ while ( start.isSameOrBefore( end ) ) {
238
+ const formatted = start.format( 'YYYY-MM-DD' );
239
+ orderedDates.push( formatted );
240
+ allDateStrings.push( `${storeId}_${formatted}` );
241
+ start = start.add( 1, 'day' );
242
+ }
243
+
244
+ if ( allDateStrings.length === 0 ) {
245
+ return res.sendSuccess( [] );
246
+ }
247
+
248
+ const footfallQuery = {
249
+ query: {
250
+ terms: {
251
+ _id: allDateStrings,
228
252
  },
229
253
  },
230
- ],
231
- };
254
+ _source: [ 'footfall', 'date_string', 'store_id', 'down_time', 'footfall_count' ],
255
+ sort: [
256
+ { date_iso: { order: 'asc' } },
257
+ ],
258
+ size: allDateStrings.length,
259
+ };
232
260
 
233
- const getData = await getOpenSearchData( openSearch.footfall, getQuery );
234
- const hits = getData?.body?.hits?.hits || [];
261
+ const multiGet = await getOpenSearchData( openSearch.footfall, footfallQuery );
262
+ const multiHits = multiGet?.body?.hits?.hits || [];
263
+ const hitsMap = new Map();
264
+ multiHits.forEach( ( hit ) => {
265
+ hitsMap.set( hit?._id, hit?._source || null );
266
+ } );
235
267
 
236
- const processedData = hits.find( ( d ) => d._id === dateString )?._source || null;
237
- const previousData = hits.find( ( d ) => d._id === dateStringPrevious )?._source || null;
268
+ const responseArray = [];
238
269
 
239
- let footfallCountTrend = 0;
270
+ for ( let i = 0; i < orderedDates.length; i++ ) {
271
+ const currentDate = orderedDates[i];
272
+ const currentId = `${storeId}_${currentDate}`;
273
+ const processedData = hitsMap.get( currentId );
274
+ if ( !processedData ) {
275
+ responseArray.push( {
276
+ date: currentDate,
277
+ footfallCount: 0,
278
+ footfallCountTrend: 0,
279
+ downtime: 0,
280
+ } );
281
+ continue;
282
+ }
240
283
 
241
- if ( processedData && previousData && previousData.footfall_count ) {
242
- footfallCountTrend = Math.round(
243
- ( ( processedData.footfall_count - previousData.footfall_count ) / previousData.footfall_count ) * 100,
244
- );
245
- }
284
+ const prevDate = dayjs( currentDate ).subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
285
+ const prevId = `${storeId}_${prevDate}`;
286
+ const previousData = hitsMap.get( prevId );
246
287
 
247
- return res.sendSuccess( {
248
- footfallCount: processedData?.footfall_count || 0,
249
- footfallCountTrend,
250
- downtime: processedData?.down_time || 0,
251
- } );
288
+ let footfallCountTrend = 0;
289
+ if ( previousData && previousData.footfall_count ) {
290
+ footfallCountTrend = Math.round(
291
+ ( ( processedData.footfall_count - previousData.footfall_count ) / previousData.footfall_count ) * 100,
292
+ );
293
+ }
294
+ // Add ticket status from openSearch.footfallDirectory (_source.status)
295
+ let ticketStatus = null;
296
+ // Try to find a matching footfallDirectory record for this date+storeId
297
+ // const ticketKey = `${storeId}_${currentDate}`;
298
+ const footfallDirQuery = {
299
+ query: {
300
+ bool: {
301
+ must: [
302
+ { term: { 'storeId.keyword': storeId } },
303
+ { term: { 'dateString': currentDate } },
304
+ { term: { 'ticketName.keyword': 'footfall-directory' } },
305
+ ],
306
+ },
307
+ },
308
+ size: 1,
309
+ _source: [ 'status' ],
310
+ };
311
+ try {
312
+ const footfallDirRes = await getOpenSearchData( openSearch.footfallDirectory, footfallDirQuery );
313
+ const hit = footfallDirRes?.body?.hits?.hits?.[0];
314
+ ticketStatus = hit?._source?.status || null;
315
+ } catch ( err ) {
316
+ logger.warn( { message: 'Could not get ticket status from footfallDirectory', error: err } );
317
+ }
318
+ // Check if request status ("raised") should be enabled or disabled by querying MongoDB config
319
+ // We'll assume findOnerevopConfig can fetch the record with status for this storeId and dateString
320
+ let raisedStatusEnabled = 'reset'; // default: enabled
321
+ try {
322
+ const mongoConfig = await findOneVmsStoreRequest( { storeId: storeId, dateString: currentDate } );
323
+ if ( mongoConfig && mongoConfig.status ) {
324
+ raisedStatusEnabled = mongoConfig.status;
325
+ }
326
+ } catch ( err ) {
327
+ logger.warn( { message: 'Could not get request status from MongoDB', error: err } );
328
+ // Leave raisedStatusEnabled as default
329
+ }
330
+
331
+ responseArray.push( {
332
+ date: processedData?.date_string || currentDate,
333
+ footfallCount: processedData?.footfall_count || 0,
334
+ footfallCountTrend,
335
+ downtime: processedData?.down_time || 0,
336
+ ticketStatus,
337
+ raisedStatusEnabled,
338
+ } );
339
+ }
340
+
341
+ return res.sendSuccess( responseArray );
342
+ }
343
+ return res.sendError( 'Required parameters missing', 400 );
252
344
  } catch ( error ) {
253
345
  logger.error( { message: error, data: req.query, function: 'storeProcessedData' } );
254
346
  const err = error.message || 'Internal Server Error';
@@ -4,7 +4,8 @@ import dayjs from 'dayjs';
4
4
  export const storeProcessedDataSchema = joi.object( {
5
5
 
6
6
  storeId: joi.string().required(),
7
- dateString: joi.string().required(),
7
+ fromDate: joi.string().required(),
8
+ toDate: joi.string().required(),
8
9
 
9
10
  } );
10
11
 
@@ -0,0 +1,5 @@
1
+ import vmsStoreRequestModel from 'tango-api-schema/schema/vmsStoreRequest.model.js';
2
+
3
+ export async function findOneVmsStoreRequest( query = {} ) {
4
+ return await vmsStoreRequestModel.findOne( query );
5
+ };