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.
|
|
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.
|
|
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.
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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.
|
|
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 :
|
|
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 );
|
package/src/dtos/nob.dtos.js
CHANGED
|
@@ -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
|
|
package/src/routes/nob.routes.js
CHANGED
|
@@ -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' ] } ),
|
|
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
|
+
}
|