tango-app-api-analysis-traffic 3.0.0-alpha.40 → 3.0.0-alpha.41

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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  import { analysisTrafficRouter } from './src/routes/traffic.routes.js';
4
4
  import { mobileTrafficAnalysisRouter } from './src/routes/mobileTraffic.routes.js';
5
+ import { nobDocs } from './src/docs/nob.docs.js';
6
+ import nobRouter from './src/routes/nob.routes.js';
5
7
 
6
- export { analysisTrafficRouter, mobileTrafficAnalysisRouter };
8
+ export { analysisTrafficRouter, mobileTrafficAnalysisRouter, nobDocs, nobRouter };
7
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-analysis-traffic",
3
- "version": "3.0.0-alpha.40",
3
+ "version": "3.0.0-alpha.41",
4
4
  "description": "Traffic Analysis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -18,11 +18,13 @@
18
18
  "dotenv": "^16.4.5",
19
19
  "express": "^4.19.2",
20
20
  "handlebars": "^4.7.8",
21
+ "joi-to-swagger": "^6.2.0",
21
22
  "lodash": "^4.17.21",
22
23
  "mongodb": "^6.8.0",
23
24
  "nodemon": "^3.1.4",
24
- "tango-api-schema": "^2.0.131",
25
- "tango-app-api-middleware": "^3.1.43-alpha.8",
25
+ "swagger-ui-express": "^5.0.1",
26
+ "tango-api-schema": "^2.1.95",
27
+ "tango-app-api-middleware": "^3.1.43-alpha.10",
26
28
  "winston": "^3.13.1",
27
29
  "winston-daily-rotate-file": "^5.0.0"
28
30
  },
@@ -0,0 +1,198 @@
1
+ import { getOpenSearchData, getUTC, insertOpenSearchData, logger, updateOpenSearchData } from 'tango-app-api-middleware';
2
+ import { aggregateStore } from '../services/stores.service.js';
3
+ import { findOneNobBilling, updateOneNobBilling } from '../services/nob.service.js';
4
+ import dayjs from 'dayjs';
5
+
6
+ export async function storeList( req, res ) {
7
+ try {
8
+ const inputData = req.body;
9
+ if ( req.user.userType !== 'superadmin' && inputData?.assignedStores?.length == 0 ) {
10
+ return res.sendSuccess( { result: [] } );
11
+ }
12
+ logger.info( { assignedStores: inputData?.assignedStores } );
13
+ let filter = [
14
+ {
15
+ clientId: { $eq: req.clientId },
16
+ },
17
+ {
18
+ status: 'active',
19
+ },
20
+ {
21
+ 'edge.firstFile': { $eq: true },
22
+ },
23
+ ];
24
+ if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango' ) {
25
+ filter.push(
26
+ { storeId: { $in: inputData?.assignedStores } },
27
+ );
28
+ }
29
+
30
+ const query =[
31
+ {
32
+ $match: {
33
+ $and: filter,
34
+ },
35
+ },
36
+
37
+ {
38
+ $project: {
39
+ _id: 0,
40
+ storeId: 1,
41
+ storeName: 1,
42
+ storeCode: '$storeProfile.storeCode',
43
+ },
44
+ },
45
+ ];
46
+ const result = await aggregateStore( query );
47
+ if ( result?.length == 0 ) {
48
+ return res.sendError( 'No Data found', 204 );
49
+ }
50
+ if ( result ) {
51
+ return res.sendSuccess( { result: result } );
52
+ }
53
+ } catch ( error ) {
54
+ const err = error.message || 'Internal Server Error';
55
+ logger.error( { error: error, message: req.query, function: 'nob-storeList' } );
56
+ return res.sendError( err, 500 );
57
+ }
58
+ }
59
+
60
+ export async function addBills( req, res ) {
61
+ try {
62
+ let resData=[];
63
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
64
+ const inputData = req.body;
65
+ for ( let i=0; i<inputData?.bills?.length; i++ ) {
66
+ const query = [
67
+ {
68
+ $match: {
69
+ $and: [
70
+ { clientId: { $eq: req.user.clientId } },
71
+ { status: { $eq: 'active' } },
72
+ {
73
+ $or: [
74
+ { 'storeId': inputData?.bills[i]?.storeId },
75
+ { 'storeProfile.storeCode': inputData?.bills[i]?.storeId },
76
+ ],
77
+ },
78
+ ],
79
+ },
80
+ },
81
+ ];
82
+ let storeData= await aggregateStore( query );
83
+ if ( storeData?.length ==0 ) {
84
+ resData.push( { code: 400, storeId: inputData?.bills[i]?.storeId, message: 'Store code is not mapped with tango' } );
85
+ } else {
86
+ let searchQuery={
87
+ 'size': 1,
88
+ 'query': {
89
+ 'bool': {
90
+ 'must': [
91
+ {
92
+ 'term': {
93
+ 'storeId.keyword': storeData[0].storeId,
94
+ },
95
+ },
96
+ {
97
+ 'term': {
98
+ 'nobDate': dayjs( inputData?.bills[i]?.nobDate ).format( 'YYYY-MM-DD' ),
99
+ },
100
+ },
101
+ ],
102
+ },
103
+ },
104
+ };
105
+ let searchData=await getOpenSearchData( openSearch.nob, searchQuery );
106
+
107
+ let inserData={
108
+ clientId: req?.user?.clientId,
109
+ storeId: storeData[0]?.storeId,
110
+ storeCode: storeData[0]?.storeProfile?.storeCode,
111
+ storeName: inputData?.bills[i]?.storeName,
112
+ nobDate: inputData?.bills[i]?.nobDate,
113
+ nobCount: inputData?.bills[i]?.nobCount,
114
+ nobAmount: 1.0,
115
+ };
116
+ const query ={ storeId: storeData[0]?.storeId, nobDate: inputData?.bills[i]?.nobDate };
117
+ await updateOneNobBilling( query, inserData );
118
+ const getData = await findOneNobBilling( query, { _id: 0 } );
119
+ logger.info( { searchData: searchData } );
120
+ if ( searchData?.body?.hits?.hits?.length==0 || searchData?.body==undefined ) {
121
+ logger.info( { getData: getData } );
122
+ await insertOpenSearchData( openSearch.nob, getData );
123
+ resData.push( { code: 200, tangoCode: getData.storeId, storeId: inputData?.bills[i]?.storeId, message: 'Data Inserted Successfully' } );
124
+ } else {
125
+ await updateOpenSearchData( openSearch.nob, searchData.body.hits.hits[0]._id, { doc: getData } );
126
+ resData.push( { code: 200, tangoCode: storeData.id, storeId: inputData?.bills[i]?.storeId, message: 'Data Updated Successfully' } );
127
+ }
128
+ }
129
+ }
130
+ return res.sendSuccess( { result: resData } );
131
+ } catch ( error ) {
132
+ const err= error.message || 'Internal Server Error';
133
+ logger.error( { error: error, message: req.body, function: 'nob-addBills' } );
134
+ res.sendError( err, 500 );
135
+ }
136
+ }
137
+
138
+ export async function getNobData( req, res ) {
139
+ try {
140
+ const inputData = req.body;
141
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
142
+ const limit =inputData.limit || 200;
143
+ const skip = inputData.offset? ( inputData.offset - 1 ) * limit : 0;
144
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( new Date( inputData.toDate ) ) );
145
+ const nobQuery={
146
+ 'from': skip,
147
+ 'size': limit,
148
+ 'query': {
149
+ 'bool': {
150
+ 'must': [
151
+ {
152
+ 'terms': {
153
+ 'storeId.keyword': inputData.storeId,
154
+ },
155
+ },
156
+ {
157
+ range: { nobDate: { gte: dateRange.start,
158
+ lt: dateRange.end } },
159
+ },
160
+ ],
161
+ },
162
+ },
163
+ };
164
+
165
+ const getNobData=await getOpenSearchData( openSearch.nob, nobQuery );
166
+ if ( getNobData?.body?.hits?.hits?.length == 0 ) {
167
+ return res.sendError( 'No Data Found', 204 );
168
+ }
169
+
170
+ const footfallQuery={
171
+ // 'from': skip,
172
+ // 'size': limit,
173
+ 'query': {
174
+ 'bool': {
175
+ 'must': [
176
+ {
177
+ 'terms': {
178
+ 'store_id.keyword': inputData.storeId,
179
+ },
180
+ },
181
+ {
182
+ range: { date_iso: { gte: `${inputData.fromDate}T00:00:00`,
183
+ lte: `${inputData.toDate}T00:00:00` } },
184
+ },
185
+ ],
186
+ },
187
+ },
188
+ };
189
+
190
+ const getFootfall= await getOpenSearchData( openSearch.footfall, footfallQuery );
191
+ logger.info( { getFootfall: getFootfall } );
192
+ return res.sendSuccess( { result: getNobData?.body?.hits?.hits, getFootfall: getFootfall?.body?.hits?.hits, count: getNobData?.body?.hits?.total?.value } );
193
+ } catch ( error ) {
194
+ const err = error.message || 'Internal Server Error';
195
+ logger.error( { error: error, message: req.body, function: 'nob-getNobData' } );
196
+ return res.sendError( err, 500 );
197
+ }
198
+ }
@@ -0,0 +1,77 @@
1
+ import j2s from 'joi-to-swagger';
2
+ import { addBillsSchema, getNobDataSchema, storeListSchema } from '../dtos/nob.dtos.js';
3
+
4
+ export const nobDocs = {
5
+
6
+ '/v3/nob/store-list': {
7
+ get: {
8
+ tags: [ 'NOB' ],
9
+ description: 'To get a store list which contains store id, name & storecode',
10
+ operationId: 'store-list',
11
+ parameters: [
12
+ {
13
+ in: 'query',
14
+ name: 'clientId',
15
+ scema: j2s( storeListSchema ).swagger,
16
+ required: false,
17
+ },
18
+ ],
19
+ responses: {
20
+ 200: { description: 'Successfully' },
21
+ 401: { description: 'Unauthorized User' },
22
+ 422: { description: 'Field Error' },
23
+ 500: { description: 'Server Error' },
24
+ 204: { description: 'Not Found' },
25
+ },
26
+ },
27
+ },
28
+
29
+ '/v3/nob/add-bills': {
30
+ post: {
31
+ tags: [ 'NOB' ],
32
+ description: 'To add single or multiple bills',
33
+ operationId: 'add-bills',
34
+ parameters: [],
35
+ requestBody: {
36
+ content: {
37
+ 'application/json': {
38
+ schema: j2s( addBillsSchema ).swagger,
39
+ },
40
+ },
41
+ },
42
+ responses: {
43
+ 200: { description: 'Bills has been add successfully' },
44
+ 401: { description: 'Unauthorized User' },
45
+ 422: { description: 'Field Error' },
46
+ 500: { description: 'Server Error' },
47
+ 204: { description: 'Not Found' },
48
+ },
49
+ },
50
+ },
51
+
52
+
53
+ '/v3/nob/get-nob-data': {
54
+ post: {
55
+ tags: [ 'NOB' ],
56
+ description: `Get list of store's nob data, footfall conevrsion rate`,
57
+ operationId: 'get-nob-data',
58
+ parameters: {},
59
+ requestBody: {
60
+ content: {
61
+ 'application/json': {
62
+ schema: j2s( getNobDataSchema ).swagger,
63
+ },
64
+ },
65
+ },
66
+ responses: {
67
+ 200: { description: 'Template has been add successfully' },
68
+ 401: { description: 'Unauthorized User' },
69
+ 422: { description: 'Field Error' },
70
+ 500: { description: 'Server Error' },
71
+ 204: { description: 'Not Found' },
72
+ },
73
+ },
74
+ },
75
+
76
+
77
+ };
@@ -0,0 +1,47 @@
1
+ import joi from 'joi';
2
+
3
+ export const addBillsSchema = joi.object( {
4
+
5
+ bills: joi.array().items(
6
+ joi.object( {
7
+ storeId: joi.string().required(),
8
+ storeCode: joi.string().required(),
9
+ storeName: joi.string().required(),
10
+ nobDate: joi.string().required(),
11
+ nobCount: joi.number().required(),
12
+ } ),
13
+ ).required(),
14
+
15
+ clientId: joi.string().optional(),
16
+
17
+ } );
18
+
19
+ export const addBillsValid = {
20
+ body: addBillsSchema,
21
+ };
22
+
23
+ export const storeListSchema = joi.object( {
24
+
25
+ clientId: joi.string().optional(),
26
+
27
+ } );
28
+
29
+ export const storeListValid = {
30
+ query: storeListSchema,
31
+ };
32
+
33
+ export const getNobDataSchema = joi.object( {
34
+
35
+ storeId: joi.array().items( joi.string().required() ).required(),
36
+ fromDate: joi.string().required(),
37
+ toDate: joi.string().required(),
38
+ limit: joi.number().optional(),
39
+ offset: joi.number().optional(),
40
+
41
+ } );
42
+
43
+
44
+ export const getNobDataValid = {
45
+ body: getNobDataSchema,
46
+ };
47
+
@@ -0,0 +1,16 @@
1
+ import express from 'express';
2
+ import { accessVerification, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
+ import { addBillsValid, getNobDataValid, storeListValid } from '../dtos/nob.dtos.js';
4
+ import { addBills, getNobData, storeList } from '../controllers/nob.controllers.js';
5
+ import { clientValidations } from '../validations/nob.validations.js';
6
+
7
+ const nobRouter=express.Router();
8
+
9
+ // store list
10
+ nobRouter.get( '/store-list', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( storeListValid ), clientValidations, getAssinedStore, storeList );
11
+
12
+ nobRouter.post( '/add-bills', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( addBillsValid ), addBills );
13
+
14
+ nobRouter.post( '/get-nob-data', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( getNobDataValid ), getAssinedStore, getNobData );
15
+
16
+ export default nobRouter;
@@ -0,0 +1,9 @@
1
+ import nobBillingModel from 'tango-api-schema/schema/nobBilling.model.js';
2
+
3
+ export async function updateOneNobBilling( query, record ) {
4
+ return await nobBillingModel.updateOne( query, { $set: record }, { upsert: true } );
5
+ }
6
+
7
+ export async function findOneNobBilling( query, fields ) {
8
+ return await nobBillingModel.findOne( query, fields );
9
+ }
@@ -0,0 +1,15 @@
1
+ export async function clientValidations( req, res, next ) {
2
+ try {
3
+ const inputData = req.query;
4
+ const clientId = req.user.userType === 'client' ? inputData.clientId :req.user.clientId;
5
+ if ( !clientId ) {
6
+ return res.sendError( 'Give valid clientId', 400 );
7
+ }
8
+ req.clientId = clientId;
9
+ return next();
10
+ } catch ( error ) {
11
+ const err = error.message || 'Internal Server Error';
12
+ logger.error( { error: error, message: req.query, function: 'nob-clientValidations' } );
13
+ return res.sendError( err, 500 );
14
+ }
15
+ }