tango-app-api-analysis-traffic 3.3.1-alpha.2 → 3.3.1-alpha.21
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/index.js +2 -1
- package/package.json +2 -2
- package/src/controllers/revop.controller.js +115 -0
- package/src/controllers/tangoTrafficV3.controllers.js +46 -8
- package/src/dtos/nob.dtos.js +9 -4
- package/src/dtos/validation.dtos.js +2 -0
- package/src/routes/revop.routes.js +13 -0
- package/src/services/revopConfig.service.js +16 -0
package/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
import { analysisTrafficRouter } from './src/routes/traffic.routes.js';
|
|
4
|
+
import { revopRouter } from './src/routes/revop.routes.js';
|
|
4
5
|
import { mobileTrafficAnalysisRouter } from './src/routes/mobileTraffic.routes.js';
|
|
5
6
|
import { nobDocs } from './src/docs/nob.docs.js';
|
|
6
7
|
import nobRouter from './src/routes/nob.routes.js';
|
|
7
8
|
|
|
8
|
-
export { analysisTrafficRouter, mobileTrafficAnalysisRouter, nobDocs, nobRouter };
|
|
9
|
+
export { analysisTrafficRouter, mobileTrafficAnalysisRouter, nobDocs, nobRouter, revopRouter };
|
|
9
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-analysis-traffic",
|
|
3
|
-
"version": "3.3.1-alpha.
|
|
3
|
+
"version": "3.3.1-alpha.21",
|
|
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.2.
|
|
26
|
+
"tango-api-schema": "^2.2.109",
|
|
27
27
|
"tango-app-api-middleware": "^3.1.55",
|
|
28
28
|
"winston": "^3.13.1",
|
|
29
29
|
"winston-daily-rotate-file": "^5.0.0"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData } from 'tango-app-api-middleware';
|
|
2
|
+
import { findOnerevopConfig } from '../services/revopConfig.service.js';
|
|
3
|
+
|
|
4
|
+
export async function getconfig( req, res ) {
|
|
5
|
+
try {
|
|
6
|
+
let result = await findOnerevopConfig( { clientId: req.query.clientId } );
|
|
7
|
+
if ( result===null ) {
|
|
8
|
+
return res.sendError( 'no data found', 204 );
|
|
9
|
+
}
|
|
10
|
+
return res.sendSuccess( result );
|
|
11
|
+
} catch ( error ) {
|
|
12
|
+
logger.error( { error: error, message: req.query, function: 'getconfig' } );
|
|
13
|
+
return res.sendError( { error: error }, 500 );
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function revoptagging( req, res ) {
|
|
18
|
+
try {
|
|
19
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
20
|
+
console.log( req.body );
|
|
21
|
+
for ( let item of req.body ) {
|
|
22
|
+
let searchQuery={
|
|
23
|
+
'size': 1,
|
|
24
|
+
'query': {
|
|
25
|
+
'bool': {
|
|
26
|
+
'must': [
|
|
27
|
+
{
|
|
28
|
+
'term': {
|
|
29
|
+
'storeId.keyword': item.storeId,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
'term': {
|
|
34
|
+
'dateString': item.dateString,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
'term': {
|
|
39
|
+
'tempId': item.tempId,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
let respo= await getOpenSearchData( openSearch.revops, searchQuery );
|
|
47
|
+
const revopData = respo?.body?.hits?.hits;
|
|
48
|
+
console.log( '====>', revopData );
|
|
49
|
+
if ( revopData&& revopData.length>0 ) {
|
|
50
|
+
let result= await updateOpenSearchData( openSearch.revops, revopData[0]._id, { doc: item } );
|
|
51
|
+
console.log( result );
|
|
52
|
+
return res.sendSuccess( 'Customer has been tagged successfully' );
|
|
53
|
+
} else {
|
|
54
|
+
item.createdAt = new Date();
|
|
55
|
+
item.updatedAt = new Date();
|
|
56
|
+
await insertOpenSearchData( openSearch.revops, item );
|
|
57
|
+
return res.sendSuccess( 'Customer has been tagged successfully.' );
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch ( error ) {
|
|
61
|
+
logger.error( { error: error, message: req.query, function: 'revoptagging' } );
|
|
62
|
+
return res.sendError( { error: error }, 500 );
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function getrevoptagging( req, res ) {
|
|
66
|
+
try {
|
|
67
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
68
|
+
console.log( req.body );
|
|
69
|
+
let searchQuery={
|
|
70
|
+
'size': 1,
|
|
71
|
+
'query': {
|
|
72
|
+
'bool': {
|
|
73
|
+
'must': [
|
|
74
|
+
{
|
|
75
|
+
'term': {
|
|
76
|
+
'storeId.keyword': req.body.storeId,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
'term': {
|
|
81
|
+
'processType': req.body.processType,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
'term': {
|
|
86
|
+
'dateString': req.body.dateString,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
// {
|
|
90
|
+
// 'term': {
|
|
91
|
+
// 'timeStamp': req.body.timeStamp,
|
|
92
|
+
// },
|
|
93
|
+
// },
|
|
94
|
+
{
|
|
95
|
+
'term': {
|
|
96
|
+
'tempId': req.body.tempId,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
let respo= await getOpenSearchData( openSearch.revops, searchQuery );
|
|
104
|
+
const revopData = respo?.body?.hits?.hits;
|
|
105
|
+
console.log( revopData );
|
|
106
|
+
if ( revopData.length>0 ) {
|
|
107
|
+
return res.sendSuccess( revopData[0]._source );
|
|
108
|
+
} else {
|
|
109
|
+
return res.sendError( 'no data found', 204 );
|
|
110
|
+
}
|
|
111
|
+
} catch ( error ) {
|
|
112
|
+
logger.error( { error: error, message: req.query, function: 'getrevoptagging' } );
|
|
113
|
+
return res.sendError( { error: error }, 500 );
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -567,7 +567,8 @@ export const footfallDirectoryV3 = async ( req, res ) => {
|
|
|
567
567
|
return res.sendError( 'Invalid Client Id', 400 );
|
|
568
568
|
}
|
|
569
569
|
reqestData.featureConfigs = getClientData.featureConfigs;
|
|
570
|
-
let LamdaURL = 'https://
|
|
570
|
+
let LamdaURL = 'https://cncmzszloku7y3bewxbpiy6nkm0yunqe.lambda-url.ap-south-1.on.aws/';
|
|
571
|
+
console.log( LamdaURL );
|
|
571
572
|
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
572
573
|
if ( resultData ) {
|
|
573
574
|
if ( resultData.status_code == '200' ) {
|
|
@@ -588,6 +589,19 @@ export const summaryTableV3 = async ( req, res ) => {
|
|
|
588
589
|
try {
|
|
589
590
|
let reqestData = req.body;
|
|
590
591
|
let getClientData = await getClientConfig( reqestData.clientId );
|
|
592
|
+
let featureConfigs = getClientData?.featureConfigs || {};
|
|
593
|
+
const engagersLabel = featureConfigs?.bouncedLimit?.value ?
|
|
594
|
+
`More than ${featureConfigs.bouncedLimit.value} mins` :
|
|
595
|
+
'Engagers';
|
|
596
|
+
const bouncedLabel = featureConfigs?.bouncedLimit?.value ?
|
|
597
|
+
`Less than ${featureConfigs.bouncedLimit.value} mins Footfall` :
|
|
598
|
+
'Bounced Footfall';
|
|
599
|
+
const conversionLabel = featureConfigs?.conversion?.value ?
|
|
600
|
+
`More than ${featureConfigs.conversion.value} mins Rate` :
|
|
601
|
+
'Conversion Rate';
|
|
602
|
+
const missedlabel = featureConfigs?.bouncedLimit?.value && featureConfigs?.conversion?.value ?
|
|
603
|
+
`${featureConfigs.bouncedLimit.value} - ${featureConfigs.conversion.value} mins` :
|
|
604
|
+
'Missed Opportunity';
|
|
591
605
|
if ( !getClientData ) {
|
|
592
606
|
return res.sendError( 'Invalid Client Id', 400 );
|
|
593
607
|
}
|
|
@@ -619,7 +633,7 @@ export const summaryTableV3 = async ( req, res ) => {
|
|
|
619
633
|
if ( resultData ) {
|
|
620
634
|
if ( resultData.status_code == '200' ) {
|
|
621
635
|
if ( reqestData.export ) {
|
|
622
|
-
if ( resultData.summaryData.length>0 ) {
|
|
636
|
+
if ( resultData.summaryData.length > 0 ) {
|
|
623
637
|
const exportdata = [];
|
|
624
638
|
resultData.summaryData.forEach( ( element ) => {
|
|
625
639
|
if ( reqestData.clientId === '193' ) {
|
|
@@ -628,14 +642,14 @@ export const summaryTableV3 = async ( req, res ) => {
|
|
|
628
642
|
'Store ID': element.storeId,
|
|
629
643
|
...( req.body.storeId.length ==1 ) ? { Date: element['date'] }:{},
|
|
630
644
|
'Footfall': element.footfallCount,
|
|
631
|
-
'Bounced
|
|
645
|
+
'Bounced Footfall': element.bouncedCount,
|
|
632
646
|
'Engagers': element.engagersCount,
|
|
633
|
-
'
|
|
647
|
+
'Missed Opportunity': element.missedOpportunityCount,
|
|
634
648
|
'Potential Buyers': element.potentialBuyersCount,
|
|
635
|
-
'Conversion Rate': element.conversionRate,
|
|
636
649
|
'NOB Count': element.NOBCount,
|
|
637
650
|
'Avg.Dwell Time': element.avgDwellTime,
|
|
638
651
|
'Avg.Infra DownTime': element.avgInfraDowntime,
|
|
652
|
+
...( element.passerBy_count !== undefined ? { 'Passer By': element.passerBy_count } : {} ),
|
|
639
653
|
'Below12': element.below12,
|
|
640
654
|
'13-19': element['13-19'],
|
|
641
655
|
'20-30': element['20-30'],
|
|
@@ -646,20 +660,44 @@ export const summaryTableV3 = async ( req, res ) => {
|
|
|
646
660
|
'Male': element.male,
|
|
647
661
|
'Female': element.female,
|
|
648
662
|
} );
|
|
663
|
+
} else if ( reqestData.clientId === '452' ) {
|
|
664
|
+
exportdata.push( {
|
|
665
|
+
'Store Name': element.storeName,
|
|
666
|
+
'Store ID': element.storeId,
|
|
667
|
+
...( req.body.storeId.length ==1 ) ? { Date: element['date'] }:{},
|
|
668
|
+
'Footfall': element.footfallCount,
|
|
669
|
+
...( bouncedLabel ? { [bouncedLabel]: element.bouncedCount } : {} ),
|
|
670
|
+
...( engagersLabel ? { [engagersLabel]: element.engagersCount } : {} ),
|
|
671
|
+
...( missedlabel ? { [missedlabel]: element.missedOpportunityCount } : {} ),
|
|
672
|
+
...( conversionLabel ? { [conversionLabel]: element.conversionRate } : {} ),
|
|
673
|
+
'NOB Count': element.NOBCount,
|
|
674
|
+
'Avg.Dwell Time': element.avgDwellTime,
|
|
675
|
+
'Avg.Infra DownTime': element.avgInfraDowntime,
|
|
676
|
+
...( element.passerBy_count !== undefined ? { 'Passer By': element.passerBy_count } : {} ),
|
|
677
|
+
'Below12': element.below12,
|
|
678
|
+
'13-19': element['13-19'],
|
|
679
|
+
'20-30': element['20-30'],
|
|
680
|
+
'31-45': element['31-45'],
|
|
681
|
+
'46-59': element['46-59'],
|
|
682
|
+
'60 above': element['60 above'],
|
|
683
|
+
'Male': element.male,
|
|
684
|
+
'Female': element.female,
|
|
685
|
+
} );
|
|
649
686
|
} else {
|
|
650
687
|
exportdata.push( {
|
|
651
688
|
'Store Name': element.storeName,
|
|
652
689
|
'Store ID': element.storeId,
|
|
653
690
|
...( req.body.storeId.length ==1 ) ? { Date: element['date'] }:{},
|
|
654
691
|
'Footfall': element.footfallCount,
|
|
655
|
-
'Bounced
|
|
692
|
+
'Bounced Footfall': element.bouncedCount,
|
|
656
693
|
'Engagers': element.engagersCount,
|
|
657
|
-
'
|
|
694
|
+
'Missed Opportunity': element.missedOpportunityCount,
|
|
658
695
|
'Potential Buyers': element.potentialBuyersCount,
|
|
659
696
|
'Conversion Rate': element.conversionRate,
|
|
660
697
|
'NOB Count': element.NOBCount,
|
|
661
698
|
'Avg.Dwell Time': element.avgDwellTime,
|
|
662
699
|
'Avg.Infra DownTime': element.avgInfraDowntime,
|
|
700
|
+
...( element.passerBy_count !== undefined ? { 'Passer By': element.passerBy_count } : {} ),
|
|
663
701
|
'Below12': element.below12,
|
|
664
702
|
'13-19': element['13-19'],
|
|
665
703
|
'20-30': element['20-30'],
|
|
@@ -2005,7 +2043,7 @@ async function getGroupStoresIds( userClientId, storeIds, getRole, getUserType,
|
|
|
2005
2043
|
|
|
2006
2044
|
async function getClientConfig( clientId ) {
|
|
2007
2045
|
try {
|
|
2008
|
-
let getClientData = await clientService.findOne( { clientId: clientId }, { 'paymentInvoice.currencyType': 1, 'averageTransactionValue': 1, 'featureConfigs.billableCalculation': 1, 'featureConfigs.missedOpportunityCalculation': 1, 'featureConfigs.conversionCalculation': 1, 'featureConfigs.open': 1, 'featureConfigs.close': 1, 'isFootfallAuditStores': 1 } );
|
|
2046
|
+
let getClientData = await clientService.findOne( { clientId: clientId }, { 'paymentInvoice.currencyType': 1, 'averageTransactionValue': 1, 'featureConfigs.billableCalculation': 1, 'featureConfigs.missedOpportunityCalculation': 1, 'featureConfigs.conversionCalculation': 1, 'featureConfigs.open': 1, 'featureConfigs.close': 1, 'isFootfallAuditStores': 1, 'featureConfigs.bouncedLimit': 1, 'featureConfigs.conversion': 1 } );
|
|
2009
2047
|
if ( !getClientData ) {
|
|
2010
2048
|
return false;
|
|
2011
2049
|
}
|
package/src/dtos/nob.dtos.js
CHANGED
|
@@ -8,10 +8,15 @@ export const addBillsSchema = joi.object( {
|
|
|
8
8
|
'string.empty': 'Please enter a valid Store ID',
|
|
9
9
|
'any.required': 'Store ID is required',
|
|
10
10
|
} ).allow( null ),
|
|
11
|
-
nobDate: joi.string()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
nobDate: joi.string()
|
|
12
|
+
.pattern( /^\d{4}-\d{2}-\d{2}$/ ) // Ensures format YYYY-MM-DD
|
|
13
|
+
.required()
|
|
14
|
+
.messages( {
|
|
15
|
+
'string.pattern.base': 'NOB Date must be in YYYY-MM-DD format',
|
|
16
|
+
'string.empty': 'Please enter a valid NOB Date',
|
|
17
|
+
'any.required': 'NOB Date is required',
|
|
18
|
+
} )
|
|
19
|
+
.allow( null ),
|
|
15
20
|
nobCount: joi.number().required().messages( {
|
|
16
21
|
'string.empty': 'Please enter a valid NOB Count',
|
|
17
22
|
'any.required': 'NOB Count is required',
|
|
@@ -10,6 +10,7 @@ const baseSchema = {
|
|
|
10
10
|
nob: joi.boolean().optional().allow( '' ),
|
|
11
11
|
dateType: joi.string().optional().allow( '' ),
|
|
12
12
|
normalize: joi.boolean().optional().allow( '' ),
|
|
13
|
+
conversiontype: joi.string().optional().allow( '' ),
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
// Schema for Card Funnel
|
|
@@ -37,6 +38,7 @@ export const validateRecapVideoSchema = joi.object( {
|
|
|
37
38
|
recapVideoDate: joi.string().required(),
|
|
38
39
|
valueType: joi.string().optional().allow( '' ),
|
|
39
40
|
nob: joi.boolean().optional().allow( '' ),
|
|
41
|
+
conversiontype: joi.string().optional().allow( '' ),
|
|
40
42
|
} );
|
|
41
43
|
|
|
42
44
|
export const validateRecapVideoParams = {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { getconfig, revoptagging, getrevoptagging } from '../controllers/revop.controller.js';
|
|
4
|
+
import { isAllowedSessionHandler } from 'tango-app-api-middleware';
|
|
5
|
+
|
|
6
|
+
export const revopRouter = express.Router();
|
|
7
|
+
|
|
8
|
+
revopRouter
|
|
9
|
+
.get( '/getconfig', isAllowedSessionHandler, getconfig )
|
|
10
|
+
.post( '/tagging', isAllowedSessionHandler, revoptagging )
|
|
11
|
+
.post( '/getrevoptagging', isAllowedSessionHandler, getrevoptagging );
|
|
12
|
+
|
|
13
|
+
export default revopRouter;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import revopConfigModel from 'tango-api-schema/schema/revopConfig.model.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export async function createrevopConfig( field = {} ) {
|
|
5
|
+
return await revopConfigModel.create( field );
|
|
6
|
+
};
|
|
7
|
+
export async function findOnerevopConfig( query = {} ) {
|
|
8
|
+
return await revopConfigModel.findOne( query );
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export async function updaterevopConfig( data={}, field = {} ) {
|
|
12
|
+
return await revopConfigModel.updateOne( data, { $set: field } );
|
|
13
|
+
};
|
|
14
|
+
export async function aggregaterevopconfig( data ) {
|
|
15
|
+
return await revopConfigModel.aggregate( data );
|
|
16
|
+
};
|