tango-app-api-analysis-traffic 3.0.0-alpha.53 → 3.0.0-alpha.55

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.0.0-alpha.53",
3
+ "version": "3.0.0-alpha.55",
4
4
  "description": "Traffic Analysis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  "nodemon": "^3.1.4",
25
25
  "swagger-ui-express": "^5.0.1",
26
26
  "tango-api-schema": "^2.2.7",
27
- "tango-app-api-middleware": "3.1.43-alpha.10",
27
+ "tango-app-api-middleware": "^3.1.46",
28
28
  "winston": "^3.13.1",
29
29
  "winston-daily-rotate-file": "^5.0.0"
30
30
  },
@@ -10,7 +10,6 @@ export async function storeList( req, res ) {
10
10
  if ( req.user.userType !== 'superadmin' && inputData?.assignedStores?.length == 0 ) {
11
11
  return res.sendSuccess( { result: [] } );
12
12
  }
13
- logger.info( { assignedStores: inputData?.assignedStores } );
14
13
  let filter = [
15
14
  {
16
15
  clientId: { $eq: req.clientId },
@@ -61,101 +60,26 @@ export async function storeList( req, res ) {
61
60
  export async function addBills( req, res ) {
62
61
  try {
63
62
  let resData=[];
64
- let errorData=[];
65
63
  const openSearch = JSON.parse( process.env.OPENSEARCH );
66
- const inputData = req.body;
67
- if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango'&& ( inputData?.assignedStores?.length == 0 || !inputData?.assignedStores ) ) {
68
- return res.sendError( 'access forbidden', 403 );
69
- }
64
+ const inputData = req.tempInserData;
70
65
 
71
- let filter = [];
72
- if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango' ) {
73
- filter.push( { storeId: { $in: inputData?.assignedStores } } );
74
- }
75
- for ( let i=0; i<inputData?.bills?.length; i++ ) {
76
- filter = [
77
- { clientId: { $eq: req.clientId } },
78
- { status: { $eq: 'active' } },
79
- {
80
- $or: [
81
- { 'storeId': inputData?.bills[i]?.storeCode },
82
- { 'storeProfile.storeCode': inputData?.bills[i]?.storeCode },
83
- ],
84
- },
85
- ];
86
- const query = [
87
- {
88
- $match: {
89
- $and: filter,
90
- },
91
- },
92
- {
93
- $project: {
94
- storeId: 1,
95
- storeName: 1,
96
- storeCode: '$storeProfile.storeCode',
97
-
98
- },
99
- },
100
- ];
101
- let storeData= await aggregateStore( query );
102
- if ( storeData?.length ==0 ) {
103
- errorData.push( { code: 400, storeId: inputData?.bills[i]?.storeId, message: 'Store code is not mapped with tango' } );
66
+ for ( let i=0; i<inputData?.length; i++ ) {
67
+ await updateOneNobBilling( inputData[i]?.query, inputData[i]?.data );
68
+ const getData = await findOneNobBilling( inputData[i]?.query, { _id: 0 } );
69
+ if ( !inputData[i]?.isUpdated ) {
70
+ await insertOpenSearchData( openSearch.nob, getData );
71
+ resData.push( { code: 200, tangoCode: getData.storeId, storeId: inputData[i]?.data?.storeCode, message: 'Data Inserted Successfully' } );
104
72
  } else {
105
- let searchQuery={
106
- 'size': 1,
107
- 'query': {
108
- 'bool': {
109
- 'must': [
110
- {
111
- 'term': {
112
- 'storeId.keyword': storeData[0].storeId,
113
- },
114
- },
115
- {
116
- 'term': {
117
- 'nobDate': dayjs( inputData?.bills[i]?.nobDate ).format( 'YYYY-MM-DD' ),
118
- },
119
- },
120
- ],
121
- },
122
- },
123
- };
124
- let searchData=await getOpenSearchData( openSearch.nob, searchQuery );
125
- let nobDateIso =new Date( inputData?.bills[i]?.nobDate );
126
- nobDateIso.setUTCHours( 0, 0, 0, 0 );
127
- const storeName = storeData[0]?.storeName;
128
- let inserData={
129
- clientId: req?.clientId,
130
- storeId: storeData[0]?.storeId,
131
- storeCode: storeData[0]?.storeCode,
132
- storeName: storeName.toLowerCase(),
133
- nobDate: nobDateIso,
134
- nobCount: inputData?.bills[i]?.nobCount,
135
- dateString: inputData?.bills[i]?.nobDate,
136
- nobAmount: 1.0,
137
- };
138
- const query ={ storeId: storeData[0]?.storeId, nobDate: inputData?.bills[i]?.nobDate };
139
- await updateOneNobBilling( query, inserData );
140
- const getData = await findOneNobBilling( query, { _id: 0 } );
141
- if ( searchData?.body?.hits?.hits?.length==0 || searchData?.body==undefined ) {
142
- await insertOpenSearchData( openSearch.nob, getData );
143
- resData.push( { code: 200, tangoCode: getData.storeId, storeId: inputData?.bills[i]?.storeCode, message: 'Data Inserted Successfully' } );
144
- } else {
145
- await updateOpenSearchData( openSearch.nob, searchData.body.hits.hits[0]._id, { doc: getData } );
146
- resData.push( { code: 200, tangoCode: storeData[0]?.storeId, storeId: inputData?.bills[i]?.storeCode, message: 'Data Updated Successfully' } );
147
- }
73
+ await updateOpenSearchData( openSearch.nob, inputData[i]?.searchData?.body?.hits?.hits[0]?._id, { doc: getData } );
74
+ resData.push( { code: 200, tangoCode: inputData[i]?.data?.storeId, storeId: inputData[i]?.data?.storeCode, message: 'Data Updated Successfully' } );
148
75
  }
149
76
  }
150
- if ( errorData.length > 0 && resData.length == 0 ) {
151
- return res.sendError( 'Store code is not mapped with tango', 400 );
152
- }
153
- logger.info( { resData: resData, errorData: errorData, function: 'nob-addbills' } );
154
- return res.sendSuccess( 'Data has been inserted successfully' );
77
+ logger.info( { resData: resData } );
78
+ return res.sendSuccess( 'Data has been inserted/updated successfully' );
155
79
  } catch ( error ) {
156
80
  const err= error.message || 'Internal Server Error';
157
81
  logger.error( { error: error, message: req.body, function: 'nob-addBills' } );
158
- res.sendError( err, 500 );
82
+ return res.sendError( err, 500 );
159
83
  }
160
84
  }
161
85
 
@@ -193,7 +117,6 @@ export async function getNobData( req, res ) {
193
117
 
194
118
  if ( inputData.searchValue && inputData.searchValue!== '' ) {
195
119
  const searchValue = escapeSpecialChars( inputData.searchValue );
196
- logger.info( { searchvalue: inputData.searchValue, searchValue: searchValue } );
197
120
  temp = {
198
121
 
199
122
  'must': filter,
@@ -238,24 +161,7 @@ export async function getNobData( req, res ) {
238
161
  const getNobData=await getOpenSearchData( openSearch.nob, nobQuery );
239
162
  const nobData = getNobData?.body?.hits?.hits;
240
163
  if ( !nobData ||nobData?.length == 0 ) {
241
- const initialQuery={
242
- 'size': 1,
243
- 'query': {
244
- 'bool': {
245
- 'must': [
246
- {
247
- 'term': {
248
- 'clientId.keyword': req.clientId,
249
- },
250
- },
251
- ],
252
- },
253
- },
254
- };
255
- const getInitialData=await getOpenSearchData( openSearch.nob, initialQuery );
256
- const initialData = getInitialData?.body?.hits?.hits;
257
- logger.info( { initialData: initialData, clientId: req.clientId } );
258
- if ( initialData && initialData.length > 0 ) {
164
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
259
165
  return res.sendError( 'No Data Found', 204 );
260
166
  } else {
261
167
  return res.sendSuccess( { initialInsert: false } );
@@ -288,9 +194,8 @@ export async function getNobData( req, res ) {
288
194
  let temp=[];
289
195
 
290
196
  data._source.isUpdated = data._source.createdAt !== data._source.updatedAt? true : false;
291
-
292
197
  footfall.filter( ( item ) => {
293
- if ( ( data._source.date_string === item._source.dateString ) && ( data._source.store_id === item._source.storeId ) ) {
198
+ if ( ( data._source.dateString === item._source.date_string ) && ( data._source.storeId === item._source.store_id ) ) {
294
199
  count = 1;
295
200
  temp =[
296
201
  {
@@ -303,7 +208,6 @@ export async function getNobData( req, res ) {
303
208
  } );
304
209
 
305
210
  let conversionCount;
306
-
307
211
  if ( count === 1 ) {
308
212
  switch ( getClient?.featureConfigs?.conversionCalculation ) {
309
213
  case 'footfall-count':
@@ -324,7 +228,7 @@ export async function getNobData( req, res ) {
324
228
  footfallCount: temp[0]?.footfallCount || null,
325
229
  engagersCount: temp[0]?.engagersCount || null,
326
230
  potentialBuyers: temp[0]?.potentialBuyers || null,
327
- conversionRate: conversionCount == null ? null :parseFloat( conversionCount.toFixed( 1 ) ),
231
+ conversionRate: conversionCount == null ? null :Math.round( conversionCount ),
328
232
 
329
233
  } );
330
234
  } else {
@@ -368,7 +272,6 @@ export async function getNobData( req, res ) {
368
272
  }
369
273
  element.conversionRate? exportData[index]['Conversion Rate'] = `${element.conversionRate} %` : exportData[index]['Conversion Rate'] =null;
370
274
  } );
371
- logger.info( { exportData: exportData } );
372
275
  return exportData;
373
276
  } );
374
277
  const mappedArrays = await Promise.all( promises );
@@ -7,15 +7,15 @@ export const addBillsSchema = joi.object( {
7
7
  storeCode: joi.string().required().messages( {
8
8
  'string.empty': 'Please enter a valid Store ID',
9
9
  'any.required': 'Store ID is required',
10
- } ),
10
+ } ).allow( null ),
11
11
  nobDate: joi.string().required().messages( {
12
12
  'string.empty': 'Please enter a valid NOB Date',
13
13
  'any.required': 'NOB Date is required',
14
- } ),
14
+ } ).allow( null ),
15
15
  nobCount: joi.number().required().messages( {
16
16
  'string.empty': 'Please enter a valid NOB Count',
17
17
  'any.required': 'NOB Count is required',
18
- } ),
18
+ } ).allow( null ),
19
19
  } ),
20
20
  ).required(),
21
21
 
@@ -1,15 +1,15 @@
1
1
  import express from 'express';
2
- import { accessVerification, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
2
+ import { accessVerification, bulkValidate, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
3
  import { addBillsValid, getNobDataValid, storeListValid } from '../dtos/nob.dtos.js';
4
4
  import { addBills, getNobData, storeList } from '../controllers/nob.controllers.js';
5
- import { clientValidations, roleVerification } from '../validations/nob.validations.js';
5
+ import { clientValidations, fieldValidation, roleVerification } from '../validations/nob.validations.js';
6
6
 
7
7
  const nobRouter=express.Router();
8
8
 
9
9
  // store list
10
10
  nobRouter.get( '/store-list', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( storeListValid ), clientValidations, getAssinedStore, storeList );
11
11
 
12
- nobRouter.post( '/add-bills', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( addBillsValid ), roleVerification, clientValidations, getAssinedStore, addBills );
12
+ nobRouter.post( '/add-bills', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), bulkValidate( addBillsValid ), roleVerification, clientValidations, fieldValidation, getAssinedStore, addBills );
13
13
 
14
14
  nobRouter.post( '/get-nob-data', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( getNobDataValid ), clientValidations, getAssinedStore, getNobData );
15
15
 
@@ -1,3 +1,7 @@
1
+ import { getOpenSearchData, logger } from 'tango-app-api-middleware';
2
+ import dayjs from 'dayjs';
3
+ import { aggregateStore } from '../services/stores.service.js';
4
+
1
5
  export async function clientValidations( req, res, next ) {
2
6
  try {
3
7
  const inputData = req.method === 'POST' ? req.body : req.query;
@@ -26,3 +30,104 @@ export async function roleVerification( req, res, next ) {
26
30
  return res.sendError( error, 500 );
27
31
  }
28
32
  }
33
+
34
+ export async function fieldValidation( req, res, next ) {
35
+ try {
36
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
37
+ const inputData = req.body;
38
+ if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango'&& ( inputData?.assignedStores?.length == 0 || !inputData?.assignedStores ) ) {
39
+ return res.sendError( 'access forbidden', 403 );
40
+ }
41
+ let tempInserData = [];
42
+ let filter = [];
43
+ if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango' ) {
44
+ filter.push( { storeId: { $in: inputData?.assignedStores } } );
45
+ }
46
+ for ( let i=0; i<inputData?.bills?.length; i++ ) {
47
+ if ( inputData?.bills[i]?.storeCode == null ) {
48
+ delete inputData?.bills[i];
49
+ }
50
+ filter = [
51
+ { clientId: { $eq: req.clientId } },
52
+ { status: { $eq: 'active' } },
53
+ {
54
+ $or: [
55
+ { 'storeId': inputData?.bills[i]?.storeCode },
56
+ { 'storeProfile.storeCode': inputData?.bills[i]?.storeCode },
57
+ ],
58
+ },
59
+ ];
60
+ const query = [
61
+ {
62
+ $match: {
63
+ $and: filter,
64
+ },
65
+ },
66
+ {
67
+ $project: {
68
+ storeId: 1,
69
+ storeName: 1,
70
+ storeCode: '$storeProfile.storeCode',
71
+
72
+ },
73
+ },
74
+ ];
75
+ let storeData= await aggregateStore( query );
76
+ if ( storeData?.length ==0 ) {
77
+ return res.sendError( `Error in index ${i+1}: Store code is not mapped with tango`, 403 );
78
+ } else {
79
+ let searchQuery={
80
+ 'size': 1,
81
+ 'query': {
82
+ 'bool': {
83
+ 'must': [
84
+ {
85
+ 'term': {
86
+ 'storeId.keyword': storeData[0].storeId,
87
+ },
88
+ },
89
+ {
90
+ 'term': {
91
+ 'nobDate': dayjs( inputData?.bills[i]?.nobDate ).format( 'YYYY-MM-DD' ),
92
+ },
93
+ },
94
+ ],
95
+ },
96
+ },
97
+ };
98
+ let searchData=await getOpenSearchData( openSearch.nob, searchQuery );
99
+ if ( searchData?.body?.hits?.hits.length > 0 && searchData?.body?.hits?.hits[0]?._source?.createdAt !== searchData?.body?.hits?.hits[0]?._source?.updatedAt ) {
100
+ return res.sendError( `Error in index ${i+1}: Access Forbidden.You are trying to re-upload/edit more than one time `, 403 );
101
+ }
102
+
103
+ let nobDateIso =new Date( inputData?.bills[i]?.nobDate );
104
+ nobDateIso.setUTCHours( 0, 0, 0, 0 );
105
+ const storeName = storeData[0]?.storeName;
106
+ let inserData={
107
+ clientId: req?.clientId,
108
+ storeId: storeData[0]?.storeId,
109
+ storeCode: storeData[0]?.storeCode,
110
+ storeName: storeName.toLowerCase(),
111
+ nobDate: nobDateIso,
112
+ nobCount: inputData?.bills[i]?.nobCount,
113
+ dateString: inputData?.bills[i]?.nobDate,
114
+ };
115
+ const query ={ storeId: storeData[0]?.storeId, nobDate: inputData?.bills[i]?.nobDate };
116
+
117
+ tempInserData.push( { data: inserData, query: query, searchData: searchData, isUpdated: ( searchData?.body?.hits?.hits?.length==0 || searchData?.body==undefined )? false:true } );
118
+ }
119
+
120
+ if ( inputData?.bills?.length == i+1 ) {
121
+ if ( tempInserData.length > 0 ) {
122
+ req.tempInserData = tempInserData;
123
+ return next();
124
+ } else {
125
+ return res.sendError( 'Bad Request', 400 );
126
+ }
127
+ }
128
+ }
129
+ } catch ( error ) {
130
+ logger.error( { error: error, message: req.body, function: 'nob-roleVerification' } );
131
+ return res.sendError( error, 500 );
132
+ }
133
+ }