tango-app-api-audit 1.0.13 → 1.0.15
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 +3 -2
- package/package.json +1 -1
- package/src/controllers/audit.controllers.js +42 -1
- package/src/controllers/auditMetrics.controllers.js +201 -201
- package/src/controllers/client.controllers.js +1 -1
- package/src/controllers/store.controllers.js +77 -0
- package/src/docs/auditMetrics.docs.js +23 -1
- package/src/docs/store.docs.js +45 -0
- package/src/dtos/audit.dtos.js +10 -0
- package/src/dtos/auditMetrics.dtos.js +9 -2
- package/src/dtos/store.dtos.js +15 -0
- package/src/routes/auditMetrics.routes.js +1 -0
- package/src/routes/store.routes.js +10 -0
- package/src/validation/audit.validation.js +104 -0
package/index.js
CHANGED
|
@@ -6,8 +6,9 @@ import { auditMetricsDocs } from './src/docs/auditMetrics.docs.js';
|
|
|
6
6
|
import { auditDocs } from './src/docs/audit.docs.js';
|
|
7
7
|
import clientRouter from './src/routes/client.routes.js';
|
|
8
8
|
import { clientDocs } from './src/docs/client.docs.js';
|
|
9
|
+
import { storeRouter } from './src/routes/store.routes.js';
|
|
10
|
+
import { storeDocs } from './src/docs/store.docs.js';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
export { auditRouter, auditMetricsRouter, auditMetricsDocs, auditDocs, clientRouter, clientDocs };
|
|
12
|
+
export { auditRouter, auditMetricsRouter, auditMetricsDocs, auditDocs, clientRouter, clientDocs, storeRouter, storeDocs };
|
|
12
13
|
|
|
13
14
|
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import { aggregateAuditClientData } from '../service/auditClientData.service.js'
|
|
|
11
11
|
import _ from 'lodash';
|
|
12
12
|
import { createAuditLog, findOneAuditLog } from '../service/auditLog.service.js';
|
|
13
13
|
import { findOneStore } from '../service/store.service.js';
|
|
14
|
+
import { mapCustomer, mapEmployee, mapJunk, splitB20000, splitE0, splitG20000 } from '../validation/audit.validation.js';
|
|
14
15
|
|
|
15
16
|
export async function getAuditFile( req, res ) {
|
|
16
17
|
try {
|
|
@@ -881,8 +882,48 @@ export async function getDraftedData( req, res ) {
|
|
|
881
882
|
|
|
882
883
|
export async function save( req, res ) {
|
|
883
884
|
try {
|
|
885
|
+
const bucket = JSON.parse( process.env.BUCKET );
|
|
884
886
|
const inputData = req.body;
|
|
885
|
-
|
|
887
|
+
const params = {
|
|
888
|
+
Key: `${inputData.storeId}/${inputData.fileDate}/${ bucket.masterJsonFile}`,
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
if ( inputData.auditType === 'ReAudit' ) {
|
|
892
|
+
params.Bucket = bucket.auditUploadBucket;
|
|
893
|
+
} else {
|
|
894
|
+
params.Bucket = bucket.masterJson;
|
|
895
|
+
}
|
|
896
|
+
logger.info( { params: params } );
|
|
897
|
+
const fileData = await getJsonFileData( params );
|
|
898
|
+
const masterJsonData = JSON.parse( fileData.toString( 'utf-8' ) );
|
|
899
|
+
logger.info( { masterJsonData: masterJsonData, length: masterJsonData.person_data.length } );
|
|
900
|
+
|
|
901
|
+
const [ G20000, B20000, E0 ] = await Promise.all( [
|
|
902
|
+
splitG20000( masterJsonData.person_data ),
|
|
903
|
+
splitB20000( masterJsonData.person_data ),
|
|
904
|
+
splitE0( masterJsonData.person_data ),
|
|
905
|
+
] );
|
|
906
|
+
|
|
907
|
+
const [ mappingData ] = await Promise.all( [
|
|
908
|
+
mapEmployee( B20000, inputData.employee ),
|
|
909
|
+
mapJunk( B20000, inputData.junk ),
|
|
910
|
+
mapCustomer( B20000, inputData.customer ),
|
|
911
|
+
] );
|
|
912
|
+
|
|
913
|
+
const tempData = _.sortBy( [ ...mappingData, ...G20000, ...E0 ], 'index' );
|
|
914
|
+
|
|
915
|
+
const tempObject = { person_data: tempData };
|
|
916
|
+
|
|
917
|
+
const uploadDataParams = {
|
|
918
|
+
Bucket: bucket.auditUploadBucket,
|
|
919
|
+
Key: `${inputData.storeId}/${inputData.fileDate}/${bucket.masterJsonFile}`,
|
|
920
|
+
ContentType: 'application/json',
|
|
921
|
+
Body: JSON.stringify( tempObject ),
|
|
922
|
+
};
|
|
923
|
+
logger.info( { uploadDataParams: uploadDataParams } );
|
|
924
|
+
const mappingUpload = await fileUpload( uploadDataParams );
|
|
925
|
+
logger.info( { mappingUpload: mappingUpload } );
|
|
926
|
+
return res.sendSuccess( { result: mappingUpload } );
|
|
886
927
|
} catch ( error ) {
|
|
887
928
|
const err= error.message || 'Internal Server Error';
|
|
888
929
|
logger.error( { error: error, message: req.body, function: 'save' } );
|
|
@@ -2,6 +2,7 @@ import { download, getUTC, logger } from 'tango-app-api-middleware';
|
|
|
2
2
|
import { aggregateAuditClientData } from '../service/auditClientData.service.js';
|
|
3
3
|
import { aggregateUserAudit } from '../service/userAudit.service.js';
|
|
4
4
|
import mongoose from 'mongoose';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
5
6
|
// import { listQueue } from 'tango-app-api-middleware/src/utils/aws/sqs.js';
|
|
6
7
|
|
|
7
8
|
|
|
@@ -112,214 +113,213 @@ export async function userAuditHistory( req, res ) {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
export async function storeMetrics( req, res ) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// 'let': { 'client_id': '$clientId', 'file_date': '$fileDate', 'total_files_count': '$totalFilesCount' },
|
|
149
|
-
// 'pipeline': [
|
|
116
|
+
try {
|
|
117
|
+
const yesterday = dayjs().subtract( 1, 'days' ).format( 'YYYY-MM-DD' );
|
|
118
|
+
const inputData = req.body;
|
|
119
|
+
const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
|
|
120
|
+
let filter = [
|
|
121
|
+
{ fileDateISO: { $gte: dateRange.start } },
|
|
122
|
+
{ fileDateISO: { $lte: dateRange.end } },
|
|
123
|
+
];
|
|
124
|
+
if ( inputData.filterByClient && inputData.filterByClient?.length > 0 ) {
|
|
125
|
+
filter.push( { clientId: { $in: inputData.filterByClient } } );
|
|
126
|
+
}
|
|
127
|
+
const query = [
|
|
128
|
+
{
|
|
129
|
+
$match: {
|
|
130
|
+
$and: filter,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
$project: {
|
|
135
|
+
fileDate: 1,
|
|
136
|
+
fileDateISO: 1,
|
|
137
|
+
clientName: 1,
|
|
138
|
+
clientId: 1,
|
|
139
|
+
installedStore: 1,
|
|
140
|
+
totalFilesCount: 1,
|
|
141
|
+
queueName: 1,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
$lookup: {
|
|
146
|
+
'from': 'storeAudit',
|
|
147
|
+
'let': { 'clientId': '$clientId', 'fileDate': '$fileDate', 'totalFilesCount': '$totalFilesCount' },
|
|
148
|
+
'pipeline': [
|
|
150
149
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
150
|
+
{
|
|
151
|
+
$match: {
|
|
152
|
+
$expr: {
|
|
153
|
+
$and: [
|
|
154
|
+
{ $eq: [ '$clientId', '$$clientId' ] },
|
|
155
|
+
{ $eq: [ '$fileDate', '$$fileDate' ] },
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
$project: {
|
|
162
|
+
completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
|
|
163
|
+
assignedStores: { $cond: [ { $ne: [ '$status', [ 'completed' ] ] }, 1, 0 ] },
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
$group: {
|
|
168
|
+
_id: { clientId: '$clientId', fileDate: '$fileDate' },
|
|
169
|
+
completedStores: { $sum: '$completedStores' },
|
|
170
|
+
assignedStores: { $sum: '$assignedStores' },
|
|
171
|
+
fileCount: { $sum: 1 },
|
|
173
172
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
$project: {
|
|
177
|
+
_id: 0,
|
|
178
|
+
fileDateISO: 1,
|
|
179
|
+
completedStores: 1,
|
|
180
|
+
assignedStores: 1,
|
|
181
|
+
completePercentage: {
|
|
182
|
+
$round: [ {
|
|
183
|
+
$multiply: [
|
|
184
|
+
100, {
|
|
185
|
+
$divide: [
|
|
186
|
+
'$completedStores', '$$totalFilesCount',
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
}, 1 ],
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
},
|
|
193
|
+
fileCount: 1,
|
|
194
|
+
},
|
|
196
195
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
196
|
+
},
|
|
197
|
+
], 'as': 'audit',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
$unwind: { path: '$audit', preserveNullAndEmptyArrays: true },
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
$project: {
|
|
205
|
+
_id: 0,
|
|
206
|
+
clientId: 1,
|
|
207
|
+
clientName: 1,
|
|
208
|
+
fileDate: 1,
|
|
209
|
+
fileDateISO: 1,
|
|
210
|
+
installedStore: 1,
|
|
211
|
+
totalFilesCount: 1,
|
|
212
|
+
queueName: 1,
|
|
213
|
+
completedStores: { $ifNull: [ '$audit.completedStores', 0 ] },
|
|
214
|
+
assignedStores: { $ifNull: [ '$audit.assignedStores', 0 ] },
|
|
215
|
+
completePercentage: { $ifNull: [ '$audit.completePercentage', 0 ] },
|
|
216
|
+
notAssigned: '',
|
|
217
|
+
status: '',
|
|
218
|
+
fileCount: { $ifNull: [ '$audit.fileCount', 0 ] },
|
|
219
|
+
},
|
|
220
|
+
},
|
|
222
221
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
222
|
+
];
|
|
223
|
+
query.push( {
|
|
224
|
+
$sort: {
|
|
225
|
+
fileDateISO: -1,
|
|
226
|
+
},
|
|
227
|
+
} );
|
|
229
228
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
229
|
+
if ( inputData.searchValue && inputData.searchValue !== '' ) {
|
|
230
|
+
query.push( {
|
|
231
|
+
$match: {
|
|
232
|
+
$or: [
|
|
233
|
+
{ clientId: { $regex: inputData.searchValue, $options: 'i' } },
|
|
234
|
+
{ clientName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
} );
|
|
238
|
+
}
|
|
239
|
+
const result = await aggregateAuditClientData( query );
|
|
241
240
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
241
|
+
if ( result.length == 0 ) {
|
|
242
|
+
return res.sendError( 'No data Found', 204 );
|
|
243
|
+
}
|
|
244
|
+
let count;
|
|
245
|
+
if ( inputData.filterByStatus && inputData.filterByStatus.length > 0 ) {
|
|
246
|
+
let testCount;
|
|
247
|
+
for ( let i = 0; i < result.length; i++ ) {
|
|
248
|
+
const item = result[i];
|
|
249
|
+
if ( inputData.fromDate === inputData.toDate && inputData.fromDate === yesterday ) {
|
|
250
|
+
const temp = await listQueue( item.queueName );
|
|
251
|
+
item.notAssigned = Number( temp );
|
|
252
|
+
} else {
|
|
253
|
+
item.notAssigned = 'No Data';
|
|
254
|
+
}
|
|
255
|
+
item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
|
|
256
|
+
item.fileCount > 0 ? 'pending' : 'not_taken';
|
|
257
|
+
delete item.fileCount;
|
|
258
|
+
testCount = result.filter( ( i ) => inputData.filterByStatus.includes( i.status ) );
|
|
259
|
+
count = testCount.length;
|
|
260
|
+
}
|
|
261
|
+
if ( !inputData.isExport ) {
|
|
262
|
+
const skip = ( inputData.offset - 1 ) * inputData.limit;
|
|
263
|
+
testCount = testCount.slice( skip, skip + inputData.limit );
|
|
264
|
+
}
|
|
265
|
+
if ( inputData.isExport ) {
|
|
266
|
+
const exportdata = [];
|
|
267
|
+
testCount.forEach( ( element ) => {
|
|
268
|
+
exportdata.push( {
|
|
269
|
+
'File Date': element.fileDate,
|
|
270
|
+
'Client Name': element.clientName,
|
|
271
|
+
'Client Id': element.clientId,
|
|
272
|
+
'Completed Percentage': element.completePercentage + ' %',
|
|
273
|
+
'Installed Stores': element.installedStore,
|
|
274
|
+
'Audit Stores': element.totalFilesCount,
|
|
275
|
+
'Inprogress Stores': element.assignedStores,
|
|
276
|
+
'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
|
|
277
|
+
'Completed': element.completedStores,
|
|
278
|
+
'Status': element.status,
|
|
279
|
+
} );
|
|
280
|
+
} );
|
|
281
|
+
await download( exportdata, res );
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
return res.sendSuccess( { result: testCount, count: count } );
|
|
285
|
+
}
|
|
286
|
+
for ( let i = 0; i < result.length; i++ ) {
|
|
287
|
+
const item = result[i];
|
|
288
|
+
if ( inputData.fromDate === inputData.toDate && inputData.fromDate === yesterday ) {
|
|
289
|
+
const temp = await listQueue( item.queueName );
|
|
290
|
+
item.notAssigned = Number( temp );
|
|
291
|
+
} else {
|
|
292
|
+
item.notAssigned = 'No Data';
|
|
293
|
+
}
|
|
294
|
+
item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
|
|
295
|
+
item.fileCount > 0 ? 'pending' : 'not_taken';
|
|
296
|
+
delete item.fileCount;
|
|
297
|
+
}
|
|
298
|
+
if ( inputData.isExport ) {
|
|
299
|
+
const exportdata = [];
|
|
300
|
+
result.forEach( ( element ) => {
|
|
301
|
+
exportdata.push( {
|
|
302
|
+
'File Date': element.fileDate,
|
|
303
|
+
'Client Name': element.clientName,
|
|
304
|
+
'Client Id': element.clientId,
|
|
305
|
+
'Completed Percentage': element.completePercentage + ' %',
|
|
306
|
+
'Installed Stores': element.installedStore,
|
|
307
|
+
'Audit Stores': element.totalFilesCount,
|
|
308
|
+
'Assigned Stores': element.assignedStores,
|
|
309
|
+
'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
|
|
310
|
+
'Completed': element.completedStores,
|
|
311
|
+
'Status': element.status,
|
|
312
|
+
} );
|
|
313
|
+
} );
|
|
314
|
+
await download( exportdata, res );
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
return res.sendSuccess( { result: result, count: count } );
|
|
318
|
+
} catch ( error ) {
|
|
319
|
+
const err = error.message || 'Internal Server Error';
|
|
320
|
+
logger.error( { error: error, data: req.body, function: 'storeMetrics' } );
|
|
321
|
+
return res.sendError( err, 500 );
|
|
322
|
+
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
export async function clientMetrics( req, res ) {
|
|
@@ -22,7 +22,7 @@ export async function clients( req, res ) {
|
|
|
22
22
|
|
|
23
23
|
const count = await aggregateClient( query );
|
|
24
24
|
if ( count.length == 0 ) {
|
|
25
|
-
return res.
|
|
25
|
+
return res.sendSuccess( { result: [], count: 0 } );
|
|
26
26
|
}
|
|
27
27
|
if ( inputData.limit ) {
|
|
28
28
|
const offset = inputData.offset ? ( inputData.offset - 1 ) * inputData.limit : 0;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { logger } from 'tango-app-api-middleware';
|
|
2
|
+
import { aggregateAuditClientData } from '../service/auditClientData.service.js';
|
|
3
|
+
|
|
4
|
+
export async function auditStoreList( req, res ) {
|
|
5
|
+
try {
|
|
6
|
+
const inputData = req.query;
|
|
7
|
+
const query =[
|
|
8
|
+
{
|
|
9
|
+
$match: {
|
|
10
|
+
clientId: { $eq: inputData.clientId },
|
|
11
|
+
fileDate: { $eq: inputData.fileDate },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
$project: {
|
|
16
|
+
_id: 0,
|
|
17
|
+
clientName: 1,
|
|
18
|
+
clientId: 1,
|
|
19
|
+
storeList: 1,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
$lookup: {
|
|
24
|
+
from: 'stores',
|
|
25
|
+
let: { storeList: '$storeList' },
|
|
26
|
+
pipeline: [
|
|
27
|
+
{
|
|
28
|
+
$match: {
|
|
29
|
+
$expr: {
|
|
30
|
+
$in: [ '$storeId', '$$storeList' ],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
$project: {
|
|
36
|
+
_id: 1,
|
|
37
|
+
storeId: 1,
|
|
38
|
+
storeName: 1,
|
|
39
|
+
clientId: 1,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
], as: 'stores',
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
$unwind: { path: '$stores', preserveNullAndEmptyArrays: true },
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
$project: {
|
|
51
|
+
storeName: '$stores.storeName',
|
|
52
|
+
storeId: '$stores.storeId',
|
|
53
|
+
clientId: '$clientId',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const count = await aggregateAuditClientData( query );
|
|
59
|
+
if ( count.length == 0 ) {
|
|
60
|
+
return res.sendSuccess( { result: [], count: 0 } );
|
|
61
|
+
}
|
|
62
|
+
if ( inputData.limit ) {
|
|
63
|
+
const offset = inputData.offset ? ( inputData.offset - 1 ) * inputData.limit : 0;
|
|
64
|
+
query.push(
|
|
65
|
+
{ $skip: offset },
|
|
66
|
+
{ $limit: limit },
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const getAuditClients = await aggregateAuditClientData( query );
|
|
70
|
+
|
|
71
|
+
return res.sendSuccess( { result: getAuditClients, count: count.length } );
|
|
72
|
+
} catch ( error ) {
|
|
73
|
+
const err = error.message || 'Internal Server Error';
|
|
74
|
+
logger.info( { error: error, messgae: req.query, function: 'auditStoreList' } );
|
|
75
|
+
return res.sendError( err, 500 );
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import j2s from 'joi-to-swagger';
|
|
2
|
-
import { clientMetricsSchema, getAuditImagesSchema, userAuditHistorySchema } from '../dtos/auditMetrics.dtos.js';
|
|
2
|
+
import { clientMetricsSchema, getAuditImagesSchema, storeMetricsSchema, userAuditHistorySchema } from '../dtos/auditMetrics.dtos.js';
|
|
3
3
|
|
|
4
4
|
export const auditMetricsDocs = {
|
|
5
5
|
|
|
@@ -69,4 +69,26 @@ export const auditMetricsDocs = {
|
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
},
|
|
72
|
+
'/v3/audit-metrics/store-metrics': {
|
|
73
|
+
post: {
|
|
74
|
+
tags: [ 'Audit Metrics' ],
|
|
75
|
+
description: `Get list of store wise details with date range and client Id`,
|
|
76
|
+
operationId: 'store-metrics',
|
|
77
|
+
parameters: {},
|
|
78
|
+
requestBody: {
|
|
79
|
+
content: {
|
|
80
|
+
'application/json': {
|
|
81
|
+
schema: j2s( storeMetricsSchema ).swagger,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
responses: {
|
|
86
|
+
200: { description: 'Successful' },
|
|
87
|
+
401: { description: 'Unauthorized User' },
|
|
88
|
+
422: { description: 'Field Error' },
|
|
89
|
+
500: { description: 'Server Error' },
|
|
90
|
+
204: { description: 'Not Found' },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
72
94
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import j2s from 'joi-to-swagger';
|
|
2
|
+
import { auditStoreSchema } from '../dtos/store.dtos.js';
|
|
3
|
+
|
|
4
|
+
export const storeDocs = {
|
|
5
|
+
'/v3/audit/store/audit-stores': {
|
|
6
|
+
get: {
|
|
7
|
+
tags: [ 'Audit/Store' ],
|
|
8
|
+
description: 'Get client list which is enable for audit',
|
|
9
|
+
operationId: 'clients',
|
|
10
|
+
parameters: [
|
|
11
|
+
{
|
|
12
|
+
in: 'query',
|
|
13
|
+
name: 'clientId',
|
|
14
|
+
scema: j2s( auditStoreSchema ).swagger,
|
|
15
|
+
require: true,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
in: 'query',
|
|
19
|
+
name: 'fileDate',
|
|
20
|
+
scema: j2s( auditStoreSchema ).swagger,
|
|
21
|
+
require: true,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
in: 'query',
|
|
25
|
+
name: 'limit',
|
|
26
|
+
scema: j2s( auditStoreSchema ).swagger,
|
|
27
|
+
require: false,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
in: 'query',
|
|
31
|
+
name: 'offset',
|
|
32
|
+
scema: j2s( auditStoreSchema ).swagger,
|
|
33
|
+
require: false,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
responses: {
|
|
37
|
+
200: { description: 'Successful' },
|
|
38
|
+
401: { description: 'Unauthorized User' },
|
|
39
|
+
422: { description: 'Field Error' },
|
|
40
|
+
500: { description: 'Server Error' },
|
|
41
|
+
204: { description: 'Not Found' },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
package/src/dtos/audit.dtos.js
CHANGED
|
@@ -54,6 +54,16 @@ export const saveSchema = joi.object(
|
|
|
54
54
|
auditId: joi.string().required(),
|
|
55
55
|
storeId: joi.string().required(),
|
|
56
56
|
fileDate: joi.string().required(),
|
|
57
|
+
auditType: joi.string().required(),
|
|
58
|
+
fileDate: joi.string().required(),
|
|
59
|
+
beforeCount: joi.number().required(),
|
|
60
|
+
junkCount: joi.number().required(),
|
|
61
|
+
junk: joi.array().required(),
|
|
62
|
+
employeeCount: joi.number().required(),
|
|
63
|
+
employee: joi.array().required(),
|
|
64
|
+
customerCount: joi.number().required(),
|
|
65
|
+
customer: joi.array().required(),
|
|
66
|
+
queueName: joi.string().required(),
|
|
57
67
|
},
|
|
58
68
|
);
|
|
59
69
|
|
|
@@ -40,8 +40,15 @@ export const storeMetricsSchema = joi.object(
|
|
|
40
40
|
{
|
|
41
41
|
fromDate: joi.string().required(),
|
|
42
42
|
toDate: joi.string().required(),
|
|
43
|
-
searchValue: joi.string().optional(),
|
|
44
|
-
|
|
43
|
+
searchValue: joi.string().optional().allow( '' ),
|
|
44
|
+
filterByClientId: joi.array().required(),
|
|
45
|
+
filterByStoreId: joi.array().optional(),
|
|
46
|
+
filterByStatus: joi.array().optional(),
|
|
47
|
+
sortColumnName: joi.string().optional(),
|
|
48
|
+
sortBy: joi.number().optional(),
|
|
49
|
+
limit: joi.number().optional(),
|
|
50
|
+
offset: joi.number().optional(),
|
|
51
|
+
isExport: joi.boolean().optional(),
|
|
45
52
|
},
|
|
46
53
|
);
|
|
47
54
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const auditStoreSchema = joi.object(
|
|
5
|
+
{
|
|
6
|
+
clientId: joi.string().required(),
|
|
7
|
+
fileDate: joi.string().required(),
|
|
8
|
+
limit: joi.number().optional(),
|
|
9
|
+
offset: joi.number().optional(),
|
|
10
|
+
},
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const auditStoreValid = {
|
|
14
|
+
query: auditStoreSchema,
|
|
15
|
+
};
|
|
@@ -10,4 +10,5 @@ auditMetricsRouter.post( '/get-audit-images', validate( getAuditImagesValid ), g
|
|
|
10
10
|
auditMetricsRouter.post( '/user-audit-history', validate( userAuditHistoryValid ), isAllowedSessionHandler, userAuditHistory );
|
|
11
11
|
auditMetricsRouter.post( '/store-metrics', validate( storeMetricsValid ), isAllowedSessionHandler, storeMetrics );
|
|
12
12
|
auditMetricsRouter.post( '/client-metrics', validate( clientMetricsValid ), isAllowedSessionHandler, clientMetrics );
|
|
13
|
+
|
|
13
14
|
export default auditMetricsRouter;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
3
|
+
import { auditStoreList } from '../controllers/store.controllers.js';
|
|
4
|
+
import { auditStoreValid } from '../dtos/store.dtos.js';
|
|
5
|
+
|
|
6
|
+
export const storeRouter = Router();
|
|
7
|
+
|
|
8
|
+
storeRouter.get( '/audit-stores', isAllowedSessionHandler, validate( auditStoreValid ), auditStoreList );
|
|
9
|
+
|
|
10
|
+
export default storeRouter;
|
|
@@ -55,4 +55,108 @@ export async function isMasterJsonExists( req, res, next ) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
export async function splitG20000( data ) {
|
|
59
|
+
try {
|
|
60
|
+
const dData = data.filter( ( resData ) => resData.temp_ids >= 20000 );
|
|
61
|
+
return dData;
|
|
62
|
+
} catch ( error ) {
|
|
63
|
+
const err = error.message || 'Internal Server Error';
|
|
64
|
+
logger.error( { error: error, message: req.query, function: 'splitG20000' } );
|
|
65
|
+
return res.sendError( err, 500 );
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function splitB20000( data ) {
|
|
70
|
+
try {
|
|
71
|
+
const dData = data.filter(
|
|
72
|
+
( resData ) => resData.temp_ids < 20000 && resData.temp_ids > 0,
|
|
73
|
+
);
|
|
74
|
+
return dData;
|
|
75
|
+
} catch ( error ) {
|
|
76
|
+
const err = error.message || 'Internal Server Error';
|
|
77
|
+
logger.error( { error: error, message: req.query, function: 'splitB20000' } );
|
|
78
|
+
return res.sendError( err, 500 );
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function splitE0( data ) {
|
|
83
|
+
try {
|
|
84
|
+
const dData = data.filter( ( resData ) => ( resData.temp_ids == 0 ) );
|
|
85
|
+
return dData;
|
|
86
|
+
} catch ( error ) {
|
|
87
|
+
const err = error.message || 'Internal Server Error';
|
|
88
|
+
logger.error( { error: error, message: req.query, function: 'splitE0' } );
|
|
89
|
+
return res.sendError( err, 500 );
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function mapEmployee( sourceMappingData, employeeData ) {
|
|
94
|
+
try {
|
|
95
|
+
employeeData.filter( ( emp ) => {
|
|
96
|
+
sourceMappingData.find( ( map ) => {
|
|
97
|
+
if ( map.temp_ids === emp.img_name ) {
|
|
98
|
+
map.person_status = 'e';
|
|
99
|
+
}
|
|
100
|
+
} );
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
return sourceMappingData;
|
|
104
|
+
} catch ( error ) {
|
|
105
|
+
logger.error( error );
|
|
106
|
+
return res.sendError( error, 500 );
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function mapJunk( sourceMappingData, junkData ) {
|
|
111
|
+
try {
|
|
112
|
+
junkData.filter( ( emp ) => {
|
|
113
|
+
sourceMappingData.find( ( map ) => {
|
|
114
|
+
if ( map.temp_ids === emp.img_name ) {
|
|
115
|
+
map.person_status = 'j';
|
|
116
|
+
}
|
|
117
|
+
} );
|
|
118
|
+
} );
|
|
119
|
+
return sourceMappingData;
|
|
120
|
+
} catch ( error ) {
|
|
121
|
+
logger.error( error );
|
|
122
|
+
return res.sendError( error, 500 );
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function mapCustomer( sourceMappingData, customerData ) {
|
|
127
|
+
try {
|
|
128
|
+
const filterCustomerData = await filteredCustomerMap( customerData );
|
|
129
|
+
logger.info( { filterCustomerData: filterCustomerData } );
|
|
130
|
+
const chunkedMappingData = await chunkArray( sourceMappingData, 10 );
|
|
131
|
+
|
|
132
|
+
const promises = chunkedMappingData.map( async ( chunk ) => {
|
|
133
|
+
return mapFunction( chunk, filterCustomerData );
|
|
134
|
+
} );
|
|
135
|
+
const mappedArrays = await Promise.all( promises );
|
|
136
|
+
return mappedArrays.flat();
|
|
137
|
+
} catch ( error ) {
|
|
138
|
+
logger.error( { error: error, type: 'mapCustomer' } );
|
|
139
|
+
return error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const filteredCustomerMap = async ( data ) => {
|
|
144
|
+
return data.filter( ( map ) => map.count >= 1 );
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const mapFunction = async ( chunkData, filterData ) => {
|
|
148
|
+
for ( const data of filterData ) {
|
|
149
|
+
const mappedIds = data.mappedid;
|
|
150
|
+
for ( const mappedId of mappedIds ) {
|
|
151
|
+
chunkData.find( ( item ) => {
|
|
152
|
+
if ( mappedId.img_name === item.temp_ids ) {
|
|
153
|
+
item.temp_ids = data.img_name;
|
|
154
|
+
item.query_status = '';
|
|
155
|
+
}
|
|
156
|
+
} );
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return chunkData;
|
|
160
|
+
};
|
|
161
|
+
|
|
58
162
|
|