tango-app-api-audit 1.0.12 → 1.0.14

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/app.js ADDED
@@ -0,0 +1,46 @@
1
+
2
+ import express from 'express';
3
+ import { auditRouter, clientRouter } from './index.js';
4
+
5
+ import dotenv from 'dotenv';
6
+ import { logger } from 'tango-app-api-middleware';
7
+ import { connectdb } from './config/database/database.js';
8
+ import responseMiddleware from './config/response/response.js';
9
+ import errorMiddleware from './config/response/error.js';
10
+ import pkg from 'body-parser';
11
+ import { auditMetricsRouter } from './index.js';
12
+ import { swaggerConfig } from './config/swagger/swagger.js';
13
+ import swagger from 'swagger-ui-express';
14
+ import storeRouter from './src/routes/store.routes.js';
15
+
16
+ const { json, urlencoded } = pkg;
17
+ const env=dotenv.config();
18
+
19
+ const app = express();
20
+ const PORT = process.env.PORT || 3000;
21
+
22
+
23
+ app.use( json( { limit: '500mb' } ) );
24
+ app.use(
25
+ urlencoded( {
26
+ extended: true,
27
+ } ),
28
+ );
29
+ app.use( responseMiddleware );
30
+ app.use( errorMiddleware );
31
+
32
+ if ( env.error ) {
33
+ logger.error( '.env not found' );
34
+ process.exit( 1 );
35
+ }
36
+ app.use( '/api-docs', swagger.serve, swagger.setup( swaggerConfig ) );
37
+ app.use( '/v3/audit', auditRouter );
38
+ app.use( '/v3/audit/client', clientRouter );
39
+ app.use( '/v3/audit/store', storeRouter );
40
+ app.use( '/v3/audit-metrics', auditMetricsRouter );
41
+
42
+ app.listen( PORT, () => {
43
+ logger.info( `server is running on port= ${PORT} ` );
44
+ connectdb();
45
+ } );
46
+
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
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "tango-app-api-audit",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "audit & audit metrics apis",
5
- "main": "index.js",
5
+ "main": "app.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && node index.js\""
8
+ "start": "nodemon --exec \"eslint --fix . && node app.js\""
9
9
  },
10
10
  "engines": {
11
11
  "node": ">=18.10.0"
@@ -23,7 +23,7 @@
23
23
  "mongodb": "^6.7.0",
24
24
  "nodemon": "^3.1.3",
25
25
  "swagger-ui-express": "^5.0.1",
26
- "tango-api-schema": "^2.0.121",
26
+ "tango-api-schema": "^2.0.122",
27
27
  "tango-app-api-middleware": "^3.1.24",
28
28
  "winston": "^3.13.0",
29
29
  "winston-daily-rotate-file": "^5.0.0"
@@ -10,6 +10,8 @@ import { aggregateStoreAudit, createStoreAudit, updateOneStoreAudit } from '../s
10
10
  import { aggregateAuditClientData } from '../service/auditClientData.service.js';
11
11
  import _ from 'lodash';
12
12
  import { createAuditLog, findOneAuditLog } from '../service/auditLog.service.js';
13
+ import { findOneStore } from '../service/store.service.js';
14
+ import { mapCustomer, mapEmployee, mapJunk, splitB20000, splitE0, splitG20000 } from '../validation/audit.validation.js';
13
15
 
14
16
  export async function getAuditFile( req, res ) {
15
17
  try {
@@ -94,7 +96,7 @@ export async function getAuditFile( req, res ) {
94
96
  storeId: userDetails[0].storeId,
95
97
  totalCount: userDetails[0].beforeCount,
96
98
  }, {}, { createdAt: -1 } );
97
- if ( log.length == 0 ) {
99
+ if ( !log ) {
98
100
  await updateOneUserAudit( { _id: userDetails[0]._id }, { $set: { isDraft: false, auditStatus: 'skipped' } } );
99
101
  logger.info( 'audit update in drafted', { _id: userDetails[0]._id, isDraft: false, auditStatus: 'skipped' } );
100
102
  return res.sendError( 'User saved data has been deleted', 204 );
@@ -104,25 +106,25 @@ export async function getAuditFile( req, res ) {
104
106
  store_id: userDetails[0].storeId,
105
107
  file_date: userDetails[0].fileDate,
106
108
  type: userDetails[0].auditType,
107
- queueName: log[0].queueName,
108
- userId: log[0].userId,
109
+ queueName: log.queueName,
110
+ userId: log.userId,
109
111
  };
110
112
  const result = {
111
- junk: log[0].junk,
112
- junk_count: log[0].junkCount,
113
- employee: log[0].employee,
114
- employee_count: log[0].employeeCount,
115
- customer: log[0].customer,
116
- customer_count: log[0].customerCount,
117
- retag_image: log[0].retagImage,
118
- retag_count: log[0].retagCount,
119
- total_count: log[0].totalCount,
113
+ junk: log.junk,
114
+ junk_count: log.junkCount,
115
+ employee: log.employee,
116
+ employee_count: log.employeeCount,
117
+ customer: log.customer,
118
+ customer_count: log.customerCount,
119
+ retag_image: log.retagImage,
120
+ retag_count: log.retagCount,
121
+ total_count: log.totalCount,
120
122
  };
121
123
 
122
- const userdata = await findOneUser( { _id: log[0].userId } );
124
+ const userdata = await findOneUser( { _id: log.userId } );
123
125
  if ( !inputData.nextId || inputData.nextId === '' || inputData.nextId == null ) {
124
126
  const logData = {
125
- userId: log[0].userId,
127
+ userId: log.userId,
126
128
  userName: userdata.name,
127
129
  logType: 'audit',
128
130
  logSubType: 'auditStart',
@@ -130,17 +132,28 @@ export async function getAuditFile( req, res ) {
130
132
  file_date: userDetails[0].fileDate,
131
133
  auditType: userDetails[0].auditType,
132
134
  storeId: userDetails[0].storeId,
133
- clientName: log[0].queueName,
135
+ clientName: log.queueName,
134
136
  auditId: userDetails[0]._id,
135
137
  },
136
138
  };
137
139
  logger.info( { logData: logData } );
138
140
  await insertOpenSearchData( openSearch.activityLog, logData );
139
- // await savelogs( logData ); Note : insert to os
140
141
  }
142
+ const storeQuery = {
143
+ storeId: userDetails[0].storeId,
144
+ };
145
+ const storeFields = {
146
+ storeId: 1,
147
+ storeName: 1,
148
+ address: '$storeProfile.address',
149
+ };
150
+ const storeDetails = await findOneStore( storeQuery, storeFields );
141
151
  return res.sendSuccess( {
142
152
  result: result,
143
- count: log[0].totalCount,
153
+ storeId: storeDetails?.storeId,
154
+ storeName: storeDetails?.storeName,
155
+ address: storeDetails?.address || '',
156
+ count: log.totalCount,
144
157
  file: file,
145
158
  isDraft: userDetails[0].isDraft,
146
159
  } );
@@ -221,14 +234,25 @@ export async function getAuditFile( req, res ) {
221
234
  auditId: reauditInsert._id,
222
235
  },
223
236
  };
224
- logger.info( { logData: logData } );
225
- // await savelogs( logData ); need to change
237
+ await insertOpenSearchData( openSearch.activityLog, logData );
226
238
  }
227
239
 
240
+ const storeQuery = {
241
+ storeId: msg.store_id,
242
+ };
243
+ const storeFields = {
244
+ storeId: 1,
245
+ storeName: 1,
246
+ address: '$storeProfile.address',
247
+ };
248
+ const storeInfo = await findOneStore( storeQuery, storeFields );
228
249
  return res.sendSuccess(
229
250
  {
230
251
  result: reauditImg,
231
252
  count: reauditImg.length,
253
+ storeId: storeInfo?.storeId,
254
+ storeName: storeInfo?.storeName,
255
+ address: storeInfo?.address || '',
232
256
  file: {
233
257
  store_id: msg.store_id,
234
258
  file_date: msg.curr_date,
@@ -323,6 +347,14 @@ export async function getAuditFile( req, res ) {
323
347
  return res.sendError( 'Bucket is Empty', 204 );
324
348
  }
325
349
  const userdata = await findOneUser( { _id: insertData.userId } );
350
+ const storeQuery = {
351
+ storeId: storeId,
352
+ };
353
+ const storeFields = {
354
+ storeName: 1,
355
+ address: '$storeProfile.address',
356
+ };
357
+ const storeInfo = await findOneStore( storeQuery, storeFields );
326
358
  if ( inputData.nextId ) {
327
359
  const logData = {
328
360
  userId: insertData.userId,
@@ -337,13 +369,15 @@ export async function getAuditFile( req, res ) {
337
369
  auditId: insertData._id,
338
370
  },
339
371
  };
340
- logger.info( logData );
341
- // await savelogs( logData );
372
+ await insertOpenSearchData( openSearch.activityLog, logData );
342
373
  }
343
-
374
+ logger.info( { storeInfo: storeInfo } );
344
375
  return res.sendSuccess( {
345
376
  result: files,
346
377
  count: msg.total_count,
378
+ storeId: storeId,
379
+ storeName: storeInfo?.storeName,
380
+ address: storeInfo?.address,
347
381
  file: {
348
382
  queueName: inputData.queueName,
349
383
  store_id: storeId,
@@ -848,8 +882,48 @@ export async function getDraftedData( req, res ) {
848
882
 
849
883
  export async function save( req, res ) {
850
884
  try {
885
+ const bucket = JSON.parse( process.env.BUCKET );
851
886
  const inputData = req.body;
852
- return res.sendSuccess( { result: inputData } );
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 } );
853
927
  } catch ( error ) {
854
928
  const err= error.message || 'Internal Server Error';
855
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
- // try {
116
- // const today = moment().subtract( 1, 'days' ).format( 'YYYY-MM-DD' );
117
- // const inputData = req.body;
118
- // const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
119
- // const start = dateRange.start;
120
- // const end = dateRange.end;
121
- // const filter = [
122
- // { fileDateISO: { $gte: start } },
123
- // { fileDateISO: { $lte: end } },
124
- // ];
125
- // if ( inputData.filterByClient && inputData.filterByClient?.length > 0 ) {
126
- // filter.push( { clientId: { $in: inputData.filterByClient } } );
127
- // }
128
- // const query = [
129
- // {
130
- // $match: {
131
- // $and: filter,
132
- // },
133
- // },
134
- // {
135
- // $project: {
136
- // fileDate: 1,
137
- // fileDateISO: 1,
138
- // clientName: 1,
139
- // clientId: 1,
140
- // installedStore: 1,
141
- // totalFilesCount: 1,
142
- // queueName: 1,
143
- // },
144
- // },
145
- // {
146
- // $lookup: {
147
- // 'from': 'audit',
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
- // $match: {
153
- // $expr: {
154
- // $and: [
155
- // { $eq: [ '$clientId', '$$client_id' ] },
156
- // { $eq: [ '$fileDate', '$$file_date' ] },
157
- // ],
158
- // },
159
- // },
160
- // },
161
- // {
162
- // $project: {
163
- // completedStores: { $cond: [ { $eq: [ '$storeStatus', 'completed' ] }, 1, 0 ] },
164
- // assignedStores: { $cond: [ { $or: [ { $in: [ '$auditStatus', [ 'inprogress', 'drafted' ] ] }, { $in: [ '$storeStatus', [ 'skipped' ] ] } ] }, 1, 0 ] },
165
- // },
166
- // },
167
- // {
168
- // $group: {
169
- // _id: { clientId: '$clientId', fileDate: '$fileDate' },
170
- // completedStores: { $sum: '$completedStores' },
171
- // assignedStores: { $sum: '$assignedStores' },
172
- // fileCount: { $sum: 1 },
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
- // $project: {
178
- // _id: 0,
179
- // fileDateISO: 1,
180
- // completedStores: 1,
181
- // assignedStores: 1,
182
- // completePercentage: {
183
- // $round: [ {
184
- // $multiply: [
185
- // 100, {
186
- // $divide: [
187
- // '$completedStores', '$$total_files_count',
188
- // ],
189
- // },
190
- // ],
191
- // }, 1 ],
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
- // fileCount: 1,
195
- // },
192
+ },
193
+ fileCount: 1,
194
+ },
196
195
 
197
- // },
198
- // ], 'as': 'audit',
199
- // },
200
- // },
201
- // {
202
- // $unwind: { path: '$audit', preserveNullAndEmptyArrays: true },
203
- // },
204
- // {
205
- // $project: {
206
- // _id: 0,
207
- // clientId: 1,
208
- // clientName: 1,
209
- // fileDate: 1,
210
- // fileDateISO: 1,
211
- // installedStore: 1,
212
- // totalFilesCount: 1,
213
- // queueName: 1,
214
- // completedStores: { $ifNull: [ '$audit.completedStores', 0 ] },
215
- // assignedStores: { $ifNull: [ '$audit.assignedStores', 0 ] },
216
- // completePercentage: { $ifNull: [ '$audit.completePercentage', 0 ] },
217
- // notAssigned: '',
218
- // status: '',
219
- // fileCount: { $ifNull: [ '$audit.fileCount', 0 ] },
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
- // query.push( {
225
- // $sort: {
226
- // fileDateISO: -1,
227
- // },
228
- // } );
222
+ ];
223
+ query.push( {
224
+ $sort: {
225
+ fileDateISO: -1,
226
+ },
227
+ } );
229
228
 
230
- // if ( inputData.searchValue && inputData.searchValue !== '' ) {
231
- // query.push( {
232
- // $match: {
233
- // $or: [
234
- // { clientId: { $regex: inputData.searchValue, $options: 'i' } },
235
- // { clientName: { $regex: inputData.searchValue, $options: 'i' } },
236
- // ],
237
- // },
238
- // } );
239
- // }
240
- // const result = await auditFilesCount.aggregate( query );
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
- // if ( result.length == 0 ) {
243
- // return res.sendError( 'No data Found', 204 );
244
- // }
245
- // let count;
246
- // if ( inputData.filterByStatus && inputData.filterByStatus.length > 0 ) {
247
- // let testCount;
248
- // for ( let i = 0; i < result.length; i++ ) {
249
- // const item = result[i];
250
- // if ( inputData.fromDate === inputData.toDate && inputData.fromDate === today ) {
251
- // const temp = await listQueue( item.queueName );
252
- // item.notAssigned = Number( temp );
253
- // } else {
254
- // item.notAssigned = 'No Data';
255
- // }
256
- // item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
257
- // item.fileCount > 0 ? 'pending' : 'not_taken';
258
- // delete item.fileCount;
259
- // testCount = result.filter( ( i ) => inputData.filterByStatus.includes( i.status ) );
260
- // count = testCount.length;
261
- // }
262
- // if ( !inputData.export ) {
263
- // const skip = ( inputData.offset - 1 ) * inputData.limit;
264
- // testCount = testCount.slice( skip, skip + inputData.limit );
265
- // }
266
- // if ( inputData.export ) {
267
- // const exportdata = [];
268
- // testCount.forEach( ( element ) => {
269
- // exportdata.push( {
270
- // 'File Date': element.fileDate,
271
- // 'Client Name': element.clientName,
272
- // 'Client Id': element.clientId,
273
- // 'Completed Percentage': element.completePercentage + ' %',
274
- // 'Installed Stores': element.installedStore,
275
- // 'Audit Stores': element.totalFilesCount,
276
- // 'Inprogress Stores': element.assignedStores,
277
- // 'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
278
- // 'Completed': element.completedStores,
279
- // 'Status': element.status,
280
- // } );
281
- // } );
282
- // await download( exportdata, res );
283
- // return;
284
- // }
285
- // return res.sendSuccess( { result: testCount, count: count } );
286
- // }
287
- // for ( let i = 0; i < result.length; i++ ) {
288
- // const item = result[i];
289
- // if ( inputData.fromDate === inputData.toDate && inputData.fromDate === today ) {
290
- // const temp = await listQueue( item.queueName );
291
- // item.notAssigned = Number( temp );
292
- // } else {
293
- // item.notAssigned = 'No Data';
294
- // }
295
- // item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
296
- // item.fileCount > 0 ? 'pending' : 'not_taken';
297
- // delete item.fileCount;
298
- // }
299
- // if ( inputData.export ) {
300
- // const exportdata = [];
301
- // result.forEach( ( element ) => {
302
- // exportdata.push( {
303
- // 'File Date': element.fileDate,
304
- // 'Client Name': element.clientName,
305
- // 'Client Id': element.clientId,
306
- // 'Completed Percentage': element.completePercentage + ' %',
307
- // 'Installed Stores': element.installedStore,
308
- // 'Audit Stores': element.totalFilesCount,
309
- // 'Assigned Stores': element.assignedStores,
310
- // 'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
311
- // 'Completed': element.completedStores,
312
- // 'Status': element.status,
313
- // } );
314
- // } );
315
- // await download( exportdata, res );
316
- // return;
317
- // }
318
- // return res.sendSuccess( { result: result, count: count } );
319
- // } catch ( error ) {
320
- // logger.error( { error: error, data: req.body, function: 'storeMetrics' } );
321
- // return res.sendError( error, 500 );
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.sendError( 'No Data Found', 204 );
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
+ };
@@ -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
- clientId: joi.array().required(),
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;
@@ -0,0 +1,6 @@
1
+ import storeModel from 'tango-api-schema/schema/store.model.js';
2
+
3
+
4
+ export function findOneStore( query, fields ) {
5
+ return storeModel.findOne( query, fields );
6
+ }
@@ -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