tango-app-api-trax 1.0.0-alpha.0
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/.eslintrc.cjs +41 -0
- package/README.md +29 -0
- package/index.js +6 -0
- package/package.json +37 -0
- package/src/controllers/traxDashboard.controllers.js +402 -0
- package/src/dtos/validation.dtos.js +226 -0
- package/src/routes/traxDashboard.routes.js +21 -0
- package/src/services/clients.services.js +23 -0
- package/src/services/processedchecklist.services.js +23 -0
- package/src/services/processedchecklistconfig.services.js +23 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = {
|
|
3
|
+
'env': {
|
|
4
|
+
'es2021': true,
|
|
5
|
+
'node': true,
|
|
6
|
+
},
|
|
7
|
+
'extends': 'google',
|
|
8
|
+
'overrides': [
|
|
9
|
+
{
|
|
10
|
+
'env': {
|
|
11
|
+
'node': true,
|
|
12
|
+
},
|
|
13
|
+
'files': [
|
|
14
|
+
'.eslintrc.{js,cjs}',
|
|
15
|
+
],
|
|
16
|
+
'parserOptions': {
|
|
17
|
+
'sourceType': 'script',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
'parserOptions': {
|
|
22
|
+
'ecmaVersion': 'latest',
|
|
23
|
+
'sourceType': 'module',
|
|
24
|
+
},
|
|
25
|
+
'rules': {
|
|
26
|
+
'linebreak-style': [ 'error', 'windows' ],
|
|
27
|
+
'require-jsdoc': 'off',
|
|
28
|
+
'arrow-spacing': 'error',
|
|
29
|
+
'key-spacing': [ 'error', { 'beforeColon': false, 'afterColon': true } ],
|
|
30
|
+
'object-curly-spacing': [ 'error', 'always' ],
|
|
31
|
+
'space-in-parens': [ 'error', 'always' ],
|
|
32
|
+
'keyword-spacing': 'error',
|
|
33
|
+
'array-bracket-spacing': [ 'error', 'always' ],
|
|
34
|
+
'spaced-comment': [ 'error', 'always' ],
|
|
35
|
+
'max-len': [ 'error', { 'code': 700 } ],
|
|
36
|
+
'no-unused-vars': 'error',
|
|
37
|
+
'new-cap': [ 'error', { 'newIsCap': true, 'capIsNew': false } ],
|
|
38
|
+
'prefer-const': 'off',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# README #
|
|
2
|
+
|
|
3
|
+
This README would normally document whatever steps are necessary to get your application up and running.
|
|
4
|
+
|
|
5
|
+
### What is this repository for? ###
|
|
6
|
+
|
|
7
|
+
* Quick summary
|
|
8
|
+
* Version
|
|
9
|
+
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
|
|
10
|
+
|
|
11
|
+
### How do I get set up? ###
|
|
12
|
+
|
|
13
|
+
* Summary of set up
|
|
14
|
+
* Configuration
|
|
15
|
+
* Dependencies
|
|
16
|
+
* Database configuration
|
|
17
|
+
* How to run tests
|
|
18
|
+
* Deployment instructions
|
|
19
|
+
|
|
20
|
+
### Contribution guidelines ###
|
|
21
|
+
|
|
22
|
+
* Writing tests
|
|
23
|
+
* Code review
|
|
24
|
+
* Other guidelines
|
|
25
|
+
|
|
26
|
+
### Who do I talk to? ###
|
|
27
|
+
|
|
28
|
+
* Repo owner or admin
|
|
29
|
+
* Other community or team contact
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tango-app-api-trax",
|
|
3
|
+
"version": "1.0.0-alpha.0",
|
|
4
|
+
"description": "Trax",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "nodemon --exec \"eslint --fix . && node index.js\""
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18.10.0"
|
|
12
|
+
},
|
|
13
|
+
"author": "praveenraj",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"aws-sdk": "^2.1665.0",
|
|
17
|
+
"dayjs": "^1.11.13",
|
|
18
|
+
"dotenv": "^16.4.5",
|
|
19
|
+
"express": "^4.19.2",
|
|
20
|
+
"handlebars": "^4.7.8",
|
|
21
|
+
"lodash": "^4.17.21",
|
|
22
|
+
"mongodb": "^6.8.0",
|
|
23
|
+
"nodemon": "^3.1.4",
|
|
24
|
+
"tango-api-schema": "^2.1.45",
|
|
25
|
+
"tango-app-api-middleware": "^3.1.41",
|
|
26
|
+
"winston": "^3.13.1",
|
|
27
|
+
"winston-daily-rotate-file": "^5.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"eslint": "^8.57.0",
|
|
31
|
+
"eslint-config-google": "^0.14.0",
|
|
32
|
+
"eslint-config-semistandard": "^17.0.0",
|
|
33
|
+
"eslint-config-standard": "^17.1.0",
|
|
34
|
+
"eslint-plugin-import": "^2.29.1",
|
|
35
|
+
"eslint-plugin-promise": "^6.6.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { logger } from 'tango-app-api-middleware';
|
|
2
|
+
import * as processedchecklistService from '../services/processedchecklist.services.js';
|
|
3
|
+
|
|
4
|
+
export const welcome = async ( req, res ) => {
|
|
5
|
+
try {
|
|
6
|
+
let result = {
|
|
7
|
+
'Message': 'Welcome',
|
|
8
|
+
};
|
|
9
|
+
return res.sendSuccess( result );
|
|
10
|
+
} catch ( error ) {
|
|
11
|
+
logger.error( { error: error, message: req.query, function: 'welcome' } );
|
|
12
|
+
return res.sendError( { error: error }, 500 );
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const overallCards = async ( req, res ) => {
|
|
17
|
+
try {
|
|
18
|
+
let reqestData = req.body;
|
|
19
|
+
let fromDate = new Date( reqestData.fromDate );
|
|
20
|
+
let toDate = new Date( reqestData.toDate );
|
|
21
|
+
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
22
|
+
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
23
|
+
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
24
|
+
let activeUnique = 0;
|
|
25
|
+
let total = 0;
|
|
26
|
+
let notSubmitted = 0;
|
|
27
|
+
let open = 0;
|
|
28
|
+
let inprogress = 0;
|
|
29
|
+
let submitted = 0;
|
|
30
|
+
let totalFlags = {
|
|
31
|
+
'count': '',
|
|
32
|
+
'comparisonData': '',
|
|
33
|
+
'ComparisonFlag': '',
|
|
34
|
+
};
|
|
35
|
+
let completionScore = {
|
|
36
|
+
'count': '',
|
|
37
|
+
'comparisonData': '',
|
|
38
|
+
'ComparisonFlag': '',
|
|
39
|
+
};
|
|
40
|
+
let complianceScore = {
|
|
41
|
+
'count': '',
|
|
42
|
+
'comparisonData': '',
|
|
43
|
+
'ComparisonFlag': '',
|
|
44
|
+
};
|
|
45
|
+
let result = {};
|
|
46
|
+
|
|
47
|
+
let overallChecklistDataQuery = [
|
|
48
|
+
{
|
|
49
|
+
$match: {
|
|
50
|
+
client_id: reqestData.clientId,
|
|
51
|
+
$and: [
|
|
52
|
+
{ store_id: { $in: reqestData.storeId } },
|
|
53
|
+
{ date_iso: { $gte: fromDate } },
|
|
54
|
+
{ date_iso: { $lte: toDate } },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
$project: {
|
|
60
|
+
sourceCheckList_id: 1,
|
|
61
|
+
checkListId: 1,
|
|
62
|
+
checklistStatus: 1,
|
|
63
|
+
timeFlag: 1,
|
|
64
|
+
questionFlag: 1,
|
|
65
|
+
mobileDetectionFlag: 1,
|
|
66
|
+
storeOpenCloseFlag: 1,
|
|
67
|
+
uniformDetectionFlag: 1,
|
|
68
|
+
markasread: 1,
|
|
69
|
+
checkListType: 1,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
$group: {
|
|
74
|
+
_id: '',
|
|
75
|
+
totalChecklist: { $sum: 1 },
|
|
76
|
+
notSubmittedChecklist: {
|
|
77
|
+
$sum: {
|
|
78
|
+
$cond: [
|
|
79
|
+
{
|
|
80
|
+
$and: [
|
|
81
|
+
{ $ne: [ '$checklistStatus', 'submit' ] },
|
|
82
|
+
],
|
|
83
|
+
}, 1, 0 ],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
openChecklist: {
|
|
87
|
+
$sum: {
|
|
88
|
+
$cond: [
|
|
89
|
+
{
|
|
90
|
+
$and: [
|
|
91
|
+
{ $eq: [ '$checklistStatus', 'open' ] },
|
|
92
|
+
],
|
|
93
|
+
}, 1, 0 ],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
inprogressChecklist: {
|
|
97
|
+
$sum: {
|
|
98
|
+
$cond: [
|
|
99
|
+
{
|
|
100
|
+
$and: [
|
|
101
|
+
{ $eq: [ '$checklistStatus', 'inprogress' ] },
|
|
102
|
+
],
|
|
103
|
+
}, 1, 0 ],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
submittedChecklist: {
|
|
107
|
+
$sum: {
|
|
108
|
+
$cond: [
|
|
109
|
+
{
|
|
110
|
+
$and: [
|
|
111
|
+
{ $eq: [ '$checklistStatus', 'submit' ] },
|
|
112
|
+
],
|
|
113
|
+
}, 1, 0 ],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
flaggedChecklist: {
|
|
117
|
+
$sum: {
|
|
118
|
+
$cond: [ {
|
|
119
|
+
$or: [
|
|
120
|
+
{ $gt: [ '$timeFlag', 0 ] },
|
|
121
|
+
{ $gt: [ '$mobileDetectionFlag', 0 ] },
|
|
122
|
+
{ $gt: [ '$storeOpenCloseFlag', 0 ] },
|
|
123
|
+
{ $gt: [ '$uniformDetectionFlag', 0 ] },
|
|
124
|
+
],
|
|
125
|
+
}, 1, 0 ],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
let getOverallChecklistData = await processedchecklistService.aggregate( overallChecklistDataQuery );
|
|
132
|
+
let uniqueChecklistDataQuery = [
|
|
133
|
+
{
|
|
134
|
+
$match: {
|
|
135
|
+
client_id: reqestData.clientId,
|
|
136
|
+
$and: [
|
|
137
|
+
{ store_id: { $in: reqestData.storeId } },
|
|
138
|
+
{ date_iso: { $gte: fromDate } },
|
|
139
|
+
{ date_iso: { $lte: toDate } },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
$project: {
|
|
145
|
+
sourceCheckList_id: 1,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
$group: {
|
|
150
|
+
_id: '$sourceCheckList_id',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
$count: 'totalUniqueChecklist',
|
|
155
|
+
},
|
|
156
|
+
];
|
|
157
|
+
let getUniqueChecklistData = await processedchecklistService.aggregate( uniqueChecklistDataQuery );
|
|
158
|
+
if ( !getUniqueChecklistData.length && !getOverallChecklistData.length ) {
|
|
159
|
+
return res.sendError( { error: 'No Data Found' }, 204 );
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if ( getUniqueChecklistData.length && getUniqueChecklistData.length>0 ) {
|
|
163
|
+
if ( getUniqueChecklistData[0].totalUniqueChecklist ) {
|
|
164
|
+
activeUnique = getUniqueChecklistData[0]?.totalUniqueChecklist;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if ( getOverallChecklistData.length && getOverallChecklistData.length>0 ) {
|
|
169
|
+
if ( getOverallChecklistData[0].totalChecklist ) {
|
|
170
|
+
total = getOverallChecklistData[0]?.totalChecklist;
|
|
171
|
+
}
|
|
172
|
+
if ( getOverallChecklistData[0].notSubmittedChecklist ) {
|
|
173
|
+
notSubmitted = getOverallChecklistData[0]?.notSubmittedChecklist;
|
|
174
|
+
}
|
|
175
|
+
if ( getOverallChecklistData[0].openChecklist ) {
|
|
176
|
+
open = getOverallChecklistData[0]?.openChecklist;
|
|
177
|
+
}
|
|
178
|
+
if ( getOverallChecklistData[0].inprogressChecklist ) {
|
|
179
|
+
inprogress = getOverallChecklistData[0]?.inprogressChecklist;
|
|
180
|
+
}
|
|
181
|
+
if ( getOverallChecklistData[0].submittedChecklist ) {
|
|
182
|
+
submitted = getOverallChecklistData[0]?.submittedChecklist;
|
|
183
|
+
}
|
|
184
|
+
if ( getOverallChecklistData[0].flaggedChecklist ) {
|
|
185
|
+
totalFlags.count = getOverallChecklistData[0]?.flaggedChecklist;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
result.overallCards = {
|
|
190
|
+
'activeUnique': activeUnique,
|
|
191
|
+
'total': total,
|
|
192
|
+
'notSubmitted': notSubmitted,
|
|
193
|
+
'open': open,
|
|
194
|
+
'inprogress': inprogress,
|
|
195
|
+
'submitted': submitted,
|
|
196
|
+
'totalFlags': totalFlags,
|
|
197
|
+
'completionScore': completionScore,
|
|
198
|
+
'complianceScore': complianceScore,
|
|
199
|
+
};
|
|
200
|
+
return res.sendSuccess( result );
|
|
201
|
+
} catch ( error ) {
|
|
202
|
+
logger.error( { error: error, message: req.query, function: 'overallCards' } );
|
|
203
|
+
return res.sendError( { error: error }, 500 );
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const checklistPerformance = async ( req, res ) => {
|
|
208
|
+
try {
|
|
209
|
+
let reqestData = req.body;
|
|
210
|
+
let fromDate = new Date( reqestData.fromDate );
|
|
211
|
+
let toDate = new Date( reqestData.toDate );
|
|
212
|
+
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
213
|
+
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
214
|
+
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
215
|
+
let result = {};
|
|
216
|
+
|
|
217
|
+
let findQuery = [];
|
|
218
|
+
let findAndQuery = [];
|
|
219
|
+
findAndQuery.push(
|
|
220
|
+
{ client_id: reqestData.clientId },
|
|
221
|
+
{ store_id: { $in: reqestData.storeId } },
|
|
222
|
+
{ date_iso: { $gte: fromDate } },
|
|
223
|
+
{ date_iso: { $lte: toDate } },
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
findQuery.push( { $match: { $and: findAndQuery } } );
|
|
227
|
+
|
|
228
|
+
if ( reqestData.searchValue && reqestData.searchValue != '' ) {
|
|
229
|
+
findQuery.push( { $match: { $or: [ { checkListName: { $regex: reqestData.searchValue, $options: 'i' } } ] } } );
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
findQuery.push( {
|
|
233
|
+
$project: {
|
|
234
|
+
sourceCheckList_id: 1,
|
|
235
|
+
checkListId: 1,
|
|
236
|
+
checkListName: 1,
|
|
237
|
+
storeCount: 1,
|
|
238
|
+
createdBy: 1,
|
|
239
|
+
createdByName: 1,
|
|
240
|
+
checklistStatus: 1,
|
|
241
|
+
timeFlag: 1,
|
|
242
|
+
questionFlag: 1,
|
|
243
|
+
mobileDetectionFlag: 1,
|
|
244
|
+
storeOpenCloseFlag: 1,
|
|
245
|
+
uniformDetectionFlag: 1,
|
|
246
|
+
checkListType: 1,
|
|
247
|
+
scheduleRepeatedType: 1,
|
|
248
|
+
},
|
|
249
|
+
} );
|
|
250
|
+
|
|
251
|
+
findQuery.push( {
|
|
252
|
+
$group: {
|
|
253
|
+
_id: '$sourceCheckList_id',
|
|
254
|
+
sourceCheckList_id: { $last: '$sourceCheckList_id' },
|
|
255
|
+
checkListName: { $last: '$checkListName' },
|
|
256
|
+
checkListChar: { $last: { $substr: [ '$checkListName', 0, 2 ] } },
|
|
257
|
+
scheduleRepeatedType: { $last: '$scheduleRepeatedType' },
|
|
258
|
+
storeCount: { $max: '$storeCount' },
|
|
259
|
+
submittedChecklist: {
|
|
260
|
+
$sum: {
|
|
261
|
+
$cond: [ { $eq: [ '$checklistStatus', 'submit' ] }, 1, 0 ],
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
flaggedChecklist: {
|
|
265
|
+
$sum: {
|
|
266
|
+
$cond: [ {
|
|
267
|
+
$or: [
|
|
268
|
+
{ $gt: [ '$timeFlag', 0 ] },
|
|
269
|
+
{ $gt: [ '$questionFlag', 0 ] },
|
|
270
|
+
{ $gt: [ '$mobileDetectionFlag', 0 ] },
|
|
271
|
+
{ $gt: [ '$storeOpenCloseFlag', 0 ] },
|
|
272
|
+
{ $gt: [ '$uniformDetectionFlag', 0 ] },
|
|
273
|
+
],
|
|
274
|
+
}, 1, 0 ],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
checkListType: { $last: '$checkListType' },
|
|
278
|
+
},
|
|
279
|
+
} );
|
|
280
|
+
|
|
281
|
+
let getTotalCount = await processedchecklistService.aggregate( findQuery );
|
|
282
|
+
if ( !getTotalCount.length ) {
|
|
283
|
+
return res.sendError( { error: 'No Data Found' }, 204 );
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if ( reqestData.sortColumnName && reqestData.sortColumnName != '' && reqestData.sortBy && reqestData.sortBy !='' ) {
|
|
287
|
+
findQuery.push( { $sort: { [reqestData.sortColumnName]: reqestData.sortBy } } );
|
|
288
|
+
} else {
|
|
289
|
+
findQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let limit = parseInt( reqestData?.limit ) || 10;
|
|
293
|
+
let skip = limit * ( reqestData?.offset ) || 0;
|
|
294
|
+
findQuery.push( { $skip: skip }, { $limit: limit } );
|
|
295
|
+
let getChecklistPerformanceData = await processedchecklistService.aggregate( findQuery );
|
|
296
|
+
|
|
297
|
+
result.totalCount = getTotalCount.length;
|
|
298
|
+
result.checklistPerformance = getChecklistPerformanceData;
|
|
299
|
+
return res.sendSuccess( result );
|
|
300
|
+
} catch ( error ) {
|
|
301
|
+
console.log( 'error =>', error );
|
|
302
|
+
logger.error( { error: error, message: req.query, function: 'checklistPerformance' } );
|
|
303
|
+
return res.sendError( { error: error }, 500 );
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export const storePerformance = async ( req, res ) => {
|
|
308
|
+
try {
|
|
309
|
+
let reqestData = req.body;
|
|
310
|
+
let fromDate = new Date( reqestData.fromDate );
|
|
311
|
+
let toDate = new Date( reqestData.toDate );
|
|
312
|
+
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
313
|
+
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
314
|
+
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
315
|
+
let result = {};
|
|
316
|
+
|
|
317
|
+
let checklistPerformanceQuery = [
|
|
318
|
+
{
|
|
319
|
+
$match: {
|
|
320
|
+
client_id: reqestData.clientId,
|
|
321
|
+
$and: [
|
|
322
|
+
{ store_id: { $in: reqestData.storeId } },
|
|
323
|
+
{ date_iso: { $gte: fromDate } },
|
|
324
|
+
{ date_iso: { $lte: toDate } },
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
$project: {
|
|
330
|
+
sourceCheckList_id: 1,
|
|
331
|
+
checkListId: 1,
|
|
332
|
+
checkListName: 1,
|
|
333
|
+
storeCount: 1,
|
|
334
|
+
createdBy: 1,
|
|
335
|
+
createdByName: 1,
|
|
336
|
+
checklistStatus: 1,
|
|
337
|
+
timeFlag: 1,
|
|
338
|
+
questionFlag: 1,
|
|
339
|
+
mobileDetectionFlag: 1,
|
|
340
|
+
storeOpenCloseFlag: 1,
|
|
341
|
+
uniformDetectionFlag: 1,
|
|
342
|
+
checkListType: 1,
|
|
343
|
+
scheduleRepeatedType: 1,
|
|
344
|
+
store_id: 1,
|
|
345
|
+
storeName: 1,
|
|
346
|
+
userEmail: 1,
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
$group: {
|
|
351
|
+
_id: '$store_id',
|
|
352
|
+
storeName: { $last: '$storeName' },
|
|
353
|
+
userEmail: { $last: '$userEmail' },
|
|
354
|
+
checkListCount: { $sum: '$store_id' },
|
|
355
|
+
flaggedChecklist: {
|
|
356
|
+
$sum: {
|
|
357
|
+
$cond: [ {
|
|
358
|
+
$or: [
|
|
359
|
+
{ $gt: [ '$timeFlag', 0 ] },
|
|
360
|
+
{ $gt: [ '$questionFlag', 0 ] },
|
|
361
|
+
{ $gt: [ '$mobileDetectionFlag', 0 ] },
|
|
362
|
+
{ $gt: [ '$storeOpenCloseFlag', 0 ] },
|
|
363
|
+
{ $gt: [ '$uniformDetectionFlag', 0 ] },
|
|
364
|
+
],
|
|
365
|
+
}, 1, 0 ],
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
submittedChecklist: {
|
|
369
|
+
$sum: {
|
|
370
|
+
$cond: [ { $eq: [ '$checklistStatus', 'submit' ] }, 1, 0 ],
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
checkListType: { $last: '$checkListType' },
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
];
|
|
377
|
+
|
|
378
|
+
let getTotalCount = await processedchecklistService.aggregate( checklistPerformanceQuery );
|
|
379
|
+
if ( !getTotalCount.length ) {
|
|
380
|
+
return res.sendError( { error: 'No Data Found' }, 204 );
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if ( reqestData.sortColumnName && reqestData.sortColumnName != '' && reqestData.sortBy && reqestData.sortBy !='' ) {
|
|
384
|
+
checklistPerformanceQuery.push( { $sort: { [reqestData.sortColumnName]: reqestData.sortBy } } );
|
|
385
|
+
} else {
|
|
386
|
+
checklistPerformanceQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let limit = parseInt( reqestData?.limit ) || 10;
|
|
390
|
+
let skip = limit * ( reqestData?.offset ) || 0;
|
|
391
|
+
checklistPerformanceQuery.push( { $skip: skip }, { $limit: limit } );
|
|
392
|
+
let getChecklistPerformanceData = await processedchecklistService.aggregate( checklistPerformanceQuery );
|
|
393
|
+
|
|
394
|
+
result.totalCount = getTotalCount.length;
|
|
395
|
+
result.checklistPerformance = getChecklistPerformanceData;
|
|
396
|
+
return res.sendSuccess( result );
|
|
397
|
+
} catch ( error ) {
|
|
398
|
+
console.log( 'error =>', error );
|
|
399
|
+
logger.error( { error: error, message: req.query, function: 'storePerformance' } );
|
|
400
|
+
return res.sendError( { error: error }, 500 );
|
|
401
|
+
}
|
|
402
|
+
};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
// Base schema
|
|
4
|
+
const baseSchema = {
|
|
5
|
+
clientId: joi.string().required(),
|
|
6
|
+
storeId: joi.array().required().empty(),
|
|
7
|
+
fromDate: joi.string().required(),
|
|
8
|
+
toDate: joi.string().required(),
|
|
9
|
+
valueType: joi.string().optional().allow( '' ),
|
|
10
|
+
nob: joi.boolean().optional().allow( '' ),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Schema for Card Funnel
|
|
14
|
+
export const validateCardFunnelSchema = joi.object( {
|
|
15
|
+
...baseSchema,
|
|
16
|
+
} );
|
|
17
|
+
|
|
18
|
+
export const validateCardFunnelParams = {
|
|
19
|
+
body: validateCardFunnelSchema,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Schema for Card Graph (extends baseSchema with additional fields)
|
|
23
|
+
export const validateCardGraphSchema = joi.object( {
|
|
24
|
+
...baseSchema,
|
|
25
|
+
dateType: joi.string().required(),
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
export const validateCardGraphParams = {
|
|
29
|
+
body: validateCardGraphSchema,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const validateRecapVideoSchema = joi.object( {
|
|
33
|
+
clientId: joi.string().required(),
|
|
34
|
+
storeId: joi.array().required().empty(),
|
|
35
|
+
recapVideoDate: joi.string().required(),
|
|
36
|
+
valueType: joi.string().optional().allow( '' ),
|
|
37
|
+
nob: joi.boolean().optional().allow( '' ),
|
|
38
|
+
} );
|
|
39
|
+
|
|
40
|
+
export const validateRecapVideoParams = {
|
|
41
|
+
body: validateRecapVideoSchema,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const validateDensityDwellSchema = joi.object( {
|
|
45
|
+
...baseSchema,
|
|
46
|
+
dateRange: joi.number().required(),
|
|
47
|
+
} );
|
|
48
|
+
|
|
49
|
+
export const validateDensityDwellParams = {
|
|
50
|
+
body: validateDensityDwellSchema,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const validateOverallCardsSchema = joi.object( {
|
|
54
|
+
...baseSchema,
|
|
55
|
+
revenue: joi.number().required(),
|
|
56
|
+
processType: joi.string().required(),
|
|
57
|
+
} );
|
|
58
|
+
|
|
59
|
+
export const validateOverallCardsParams = {
|
|
60
|
+
body: validateOverallCardsSchema,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const validateOverallHourlyChartSchema = joi.object( {
|
|
64
|
+
...baseSchema,
|
|
65
|
+
processType: joi.string().required(),
|
|
66
|
+
} );
|
|
67
|
+
|
|
68
|
+
export const validateOverallHourlyChartParams = {
|
|
69
|
+
body: validateOverallHourlyChartSchema,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const validateOverallCharSchema = joi.object( {
|
|
73
|
+
...baseSchema,
|
|
74
|
+
limit: joi.number().required(),
|
|
75
|
+
offset: joi.number().required(),
|
|
76
|
+
processType: joi.string().required(),
|
|
77
|
+
} );
|
|
78
|
+
|
|
79
|
+
export const validateOverallCharParams = {
|
|
80
|
+
body: validateOverallCharSchema,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const validateSingleStoreChartSchema = joi.object( {
|
|
84
|
+
...baseSchema,
|
|
85
|
+
limit: joi.number().required(),
|
|
86
|
+
offset: joi.number().required(),
|
|
87
|
+
processType: joi.string().required(),
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
export const validateSingleStoreChartParams = {
|
|
91
|
+
body: validateSingleStoreChartSchema,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const validateDemographicChartSchema = joi.object( {
|
|
95
|
+
...baseSchema,
|
|
96
|
+
processType: joi.string().required(),
|
|
97
|
+
} );
|
|
98
|
+
|
|
99
|
+
export const validateDemographicChartParams = {
|
|
100
|
+
body: validateDemographicChartSchema,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const validateBuyerChartSchema = joi.object( {
|
|
104
|
+
...baseSchema,
|
|
105
|
+
processType: joi.string().required(),
|
|
106
|
+
} );
|
|
107
|
+
|
|
108
|
+
export const validateBuyerChartParams = {
|
|
109
|
+
body: validateBuyerChartSchema,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const validateFootfallDirectoryFoldersSchema = joi.object( {
|
|
113
|
+
clientId: joi.string().required(),
|
|
114
|
+
storeId: joi.array().required().empty(),
|
|
115
|
+
footfallDate: joi.string().required(),
|
|
116
|
+
processType: joi.string().required(),
|
|
117
|
+
valueType: joi.string().optional().allow( '' ),
|
|
118
|
+
nob: joi.boolean().optional().allow( '' ),
|
|
119
|
+
} );
|
|
120
|
+
|
|
121
|
+
export const validateFootfallDirectoryFoldersParams = {
|
|
122
|
+
body: validateFootfallDirectoryFoldersSchema,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const validateFootfallDirectorySchema = joi.object( {
|
|
126
|
+
clientId: joi.string().required(),
|
|
127
|
+
storeId: joi.array().required().empty(),
|
|
128
|
+
footfallDate: joi.string().required(),
|
|
129
|
+
processType: joi.string().required(),
|
|
130
|
+
folderName: joi.string().required(),
|
|
131
|
+
valueType: joi.string().optional().allow( '' ),
|
|
132
|
+
nob: joi.boolean().optional().allow( '' ),
|
|
133
|
+
} );
|
|
134
|
+
|
|
135
|
+
export const validateFootfallDirectoryParams = {
|
|
136
|
+
body: validateFootfallDirectorySchema,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const validateSummaryTableSchema = joi.object( {
|
|
140
|
+
...baseSchema,
|
|
141
|
+
valueType: joi.string().required(),
|
|
142
|
+
search: joi.string().optional().allow( '' ),
|
|
143
|
+
sortBy: joi.number().optional().allow( '' ),
|
|
144
|
+
sort: joi.string().optional().allow( '' ),
|
|
145
|
+
limit: joi.number().required(),
|
|
146
|
+
offset: joi.number().required(),
|
|
147
|
+
export: joi.boolean().required(),
|
|
148
|
+
} );
|
|
149
|
+
|
|
150
|
+
export const validateSummaryTableParams = {
|
|
151
|
+
body: validateSummaryTableSchema,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const validateFootfallTrendSchema = joi.object( {
|
|
155
|
+
...baseSchema,
|
|
156
|
+
dateType: joi.string().required(),
|
|
157
|
+
filterBy: joi.string().required(),
|
|
158
|
+
processType: joi.string().optional().allow( '' ),
|
|
159
|
+
forecast: joi.boolean().optional(),
|
|
160
|
+
limit: joi.number().required(),
|
|
161
|
+
offset: joi.number().required(),
|
|
162
|
+
sortBy: joi.number().optional().allow( '' ),
|
|
163
|
+
sort: joi.string().optional().allow( '' ),
|
|
164
|
+
} );
|
|
165
|
+
|
|
166
|
+
export const validateFootfallTrendParams = {
|
|
167
|
+
body: validateFootfallTrendSchema,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export const validateStoreOperationSchema = joi.object( {
|
|
171
|
+
...baseSchema,
|
|
172
|
+
} );
|
|
173
|
+
|
|
174
|
+
export const validateStoreOperationParams = {
|
|
175
|
+
body: validateStoreOperationSchema,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const validateStoresMapSchema = joi.object( {
|
|
179
|
+
clientId: joi.string().required(),
|
|
180
|
+
storeId: joi.array().required().empty(),
|
|
181
|
+
storeDate: joi.string().required(),
|
|
182
|
+
nob: joi.boolean().optional().allow( '' ),
|
|
183
|
+
} );
|
|
184
|
+
|
|
185
|
+
export const validateStoresMapParams = {
|
|
186
|
+
body: validateStoresMapSchema,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const validateperformanceMatrixSchema = joi.object( {
|
|
190
|
+
...baseSchema,
|
|
191
|
+
processtype1: joi.string().required(),
|
|
192
|
+
processtype2: joi.string().required(),
|
|
193
|
+
} );
|
|
194
|
+
|
|
195
|
+
export const validateperformanceMatrixParams = {
|
|
196
|
+
body: validateperformanceMatrixSchema,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const validateHeaderSchema = joi.object( {
|
|
200
|
+
clientId: joi.string().required(),
|
|
201
|
+
city: joi.array().required(),
|
|
202
|
+
group: joi.array().required(),
|
|
203
|
+
} );
|
|
204
|
+
|
|
205
|
+
export const validateHeaderParams = {
|
|
206
|
+
body: validateHeaderSchema,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const getMyProductSchema = joi.object( {
|
|
210
|
+
clientId: joi.string().required(),
|
|
211
|
+
storeId: joi.array().optional().empty(),
|
|
212
|
+
} );
|
|
213
|
+
|
|
214
|
+
export const getMyProductParams = {
|
|
215
|
+
body: getMyProductSchema,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export const getStoreCameraImageSchema = joi.object( {
|
|
219
|
+
clientId: joi.string().required(),
|
|
220
|
+
storeId: joi.array().optional().empty(),
|
|
221
|
+
storeDate: joi.string().required(),
|
|
222
|
+
} );
|
|
223
|
+
|
|
224
|
+
export const getStoreCameraImageParams = {
|
|
225
|
+
body: getStoreCameraImageSchema,
|
|
226
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
// import { validate, isAllowedSessionHandler, authorize, isAllowedClient } from 'tango-app-api-middleware';
|
|
3
|
+
// import * as validationDtos from '../dtos/validation.dtos.js';
|
|
4
|
+
|
|
5
|
+
export const traxDashboardRouter = express.Router();
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
welcome,
|
|
9
|
+
overallCards,
|
|
10
|
+
checklistPerformance,
|
|
11
|
+
storePerformance,
|
|
12
|
+
} from '../controllers/traxDashboard.controllers.js';
|
|
13
|
+
|
|
14
|
+
traxDashboardRouter
|
|
15
|
+
.get( '/welcome', welcome )
|
|
16
|
+
.post( '/overallCards', overallCards )
|
|
17
|
+
.post( '/checklistPerformance', checklistPerformance )
|
|
18
|
+
.post( '/storePerformance', storePerformance )
|
|
19
|
+
.post( '/userPerformance', overallCards );
|
|
20
|
+
|
|
21
|
+
export default traxDashboardRouter;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import model from 'tango-api-schema';
|
|
2
|
+
|
|
3
|
+
export const find = ( query = {}, record = {} ) => {
|
|
4
|
+
return model.clientModel.find( query, record );
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findOne = ( query = {}, record = {} ) => {
|
|
8
|
+
return model.clientModel.findOne( query, record ).sort( { updatedAt: -1 } );
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const updateOne = ( query = {}, record = {} ) => {
|
|
12
|
+
return model.clientModel.updateOne( query, { $set: record } );
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const aggregate = ( query = [] ) => {
|
|
16
|
+
return model.clientModel.aggregate( query );
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getClientCount = ( query = {} ) => {
|
|
20
|
+
return model.clientModel.count( query );
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import model from 'tango-api-schema';
|
|
2
|
+
|
|
3
|
+
export const find = ( query = {}, record = {} ) => {
|
|
4
|
+
return model.processedchecklistModel.find( query, record );
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findOne = ( query = {}, record = {} ) => {
|
|
8
|
+
return model.processedchecklistModel.findOne( query, record ).sort( { updatedAt: -1 } );
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const updateOne = ( query = {}, record = {} ) => {
|
|
12
|
+
return model.processedchecklistModel.updateOne( query, { $set: record } );
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const aggregate = ( query = [] ) => {
|
|
16
|
+
return model.processedchecklistModel.aggregate( query );
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getClientCount = ( query = {} ) => {
|
|
20
|
+
return model.processedchecklistModel.count( query );
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import model from 'tango-api-schema';
|
|
2
|
+
|
|
3
|
+
export const find = ( query = {}, record = {} ) => {
|
|
4
|
+
return model.processedchecklistconfigModel.find( query, record );
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findOne = ( query = {}, record = {} ) => {
|
|
8
|
+
return model.processedchecklistconfigModel.findOne( query, record ).sort( { updatedAt: -1 } );
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const updateOne = ( query = {}, record = {} ) => {
|
|
12
|
+
return model.processedchecklistconfigModel.updateOne( query, { $set: record } );
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const aggregate = ( query = [] ) => {
|
|
16
|
+
return model.processedchecklistconfigModel.aggregate( query );
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getClientCount = ( query = {} ) => {
|
|
20
|
+
return model.processedchecklistconfigModel.count( query );
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|