tango-app-api-audit 1.0.23 → 1.0.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-audit",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "audit & audit metrics apis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -2,7 +2,6 @@ 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';
6
5
  import { aggregateStoreAudit } from '../service/storeAudit.service.js';
7
6
  // import { listQueue } from 'tango-app-api-middleware/src/utils/aws/sqs.js';
8
7
 
@@ -103,16 +102,27 @@ export async function userAuditHistory( req, res ) {
103
102
 
104
103
  export async function storeMetrics( req, res ) {
105
104
  try {
106
- const yesterday = dayjs().subtract( 1, 'days' ).format( 'YYYY-MM-DD' );
107
105
  const inputData = req.body;
106
+ const limit = inputData.limit || 10;
107
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
108
108
  const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
109
109
  let filter = [
110
110
  { fileDateISO: { $gte: dateRange.start } },
111
111
  { fileDateISO: { $lte: dateRange.end } },
112
112
  ];
113
- if ( inputData.filterByClient && inputData.filterByClient?.length > 0 ) {
114
- filter.push( { clientId: { $in: inputData.filterByClient } } );
113
+ if ( inputData.filterByClientId && inputData.filterByClientId?.length > 0 ) {
114
+ filter.push( { clientId: { $in: inputData.filterByClientId } } );
115
+ }
116
+
117
+ if ( inputData.filterByStoreId && inputData.filterByStoreId?.length > 0 ) {
118
+ filter.push( { storeId: { $in: inputData.filterByStoreId } } );
119
+ }
120
+
121
+ if ( inputData.filterByStatus && inputData.filterByStatus?.length > 0 ) {
122
+ filter.push( { status: { $in: inputData.filterByStatus } } );
115
123
  }
124
+
125
+
116
126
  const query = [
117
127
  {
118
128
  $match: {
@@ -121,99 +131,109 @@ export async function storeMetrics( req, res ) {
121
131
  },
122
132
  {
123
133
  $project: {
134
+ _id: 0,
124
135
  fileDate: 1,
125
- fileDateISO: 1,
126
- clientName: 1,
136
+ storeId: 1,
137
+ storeName: '$storeId',
138
+ userId: {
139
+ $arrayElemAt: [ '$userId', { $subtract: [ { $size: '$userId' }, 1 ] } ],
140
+ },
127
141
  clientId: 1,
128
- installedStore: 1,
129
- totalFilesCount: 1,
130
- queueName: 1,
142
+ auditType: 1,
143
+ beforeCount: 1,
144
+ afterCount: { $ifNull: [ '$afterCount', null ] },
145
+ accuracy: { $round: [
146
+ { $divide: [
147
+ { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
148
+ ] }, 2,
149
+ ],
150
+
151
+ },
152
+ timeSpent: 1,
153
+ status: 1,
131
154
  },
132
155
  },
133
156
  {
134
157
  $lookup: {
135
- 'from': 'storeAudit',
136
- 'let': { 'clientId': '$clientId', 'fileDate': '$fileDate', 'totalFilesCount': '$totalFilesCount' },
137
- 'pipeline': [
138
-
158
+ from: 'stores',
159
+ let: { storeId: '$storeId' },
160
+ pipeline: [
139
161
  {
140
162
  $match: {
141
163
  $expr: {
142
- $and: [
143
- { $eq: [ '$clientId', '$$clientId' ] },
144
- { $eq: [ '$fileDate', '$$fileDate' ] },
145
- ],
164
+ $eq: [ '$storeId', '$$storeId' ],
146
165
  },
147
166
  },
148
167
  },
149
168
  {
150
169
  $project: {
151
- completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
152
- assignedStores: { $cond: [ { $ne: [ '$status', [ 'completed' ] ] }, 1, 0 ] },
170
+ _id: 0,
171
+ storeName: 1,
153
172
  },
154
173
  },
174
+ ], as: 'stores',
175
+ },
176
+ },
177
+ {
178
+ $unwind: {
179
+ path: '$stores',
180
+ preserveNullAndEmptyArrays: true,
181
+ },
182
+ },
183
+ {
184
+ $lookup: {
185
+ from: 'users',
186
+ let: { userId: '$userId' },
187
+ pipeline: [
155
188
  {
156
- $group: {
157
- _id: { clientId: '$clientId', fileDate: '$fileDate' },
158
- completedStores: { $sum: '$completedStores' },
159
- assignedStores: { $sum: '$assignedStores' },
160
- fileCount: { $sum: 1 },
161
-
189
+ $match: {
190
+ $expr: {
191
+ $eq: [ '$_id', '$$userId' ],
192
+ },
162
193
  },
163
194
  },
164
195
  {
165
196
  $project: {
166
197
  _id: 0,
167
- fileDateISO: 1,
168
- completedStores: 1,
169
- assignedStores: 1,
170
- completePercentage: {
171
- $round: [ {
172
- $multiply: [
173
- 100, {
174
- $divide: [
175
- '$completedStores', '$$totalFilesCount',
176
- ],
177
- },
178
- ],
179
- }, 1 ],
180
-
181
- },
182
- fileCount: 1,
198
+ userName: 1,
199
+ userEmail: '$email',
183
200
  },
184
-
185
201
  },
186
- ], 'as': 'audit',
202
+ ], as: 'users',
187
203
  },
188
204
  },
189
205
  {
190
- $unwind: { path: '$audit', preserveNullAndEmptyArrays: true },
206
+ $unwind: {
207
+ path: '$users',
208
+ preserveNullAndEmptyArrays: true,
209
+ },
191
210
  },
192
211
  {
193
212
  $project: {
194
213
  _id: 0,
195
- clientId: 1,
196
- clientName: 1,
197
214
  fileDate: 1,
198
- fileDateISO: 1,
199
- installedStore: 1,
200
- totalFilesCount: 1,
201
- queueName: 1,
202
- completedStores: { $ifNull: [ '$audit.completedStores', 0 ] },
203
- assignedStores: { $ifNull: [ '$audit.assignedStores', 0 ] },
204
- completePercentage: { $ifNull: [ '$audit.completePercentage', 0 ] },
205
- notAssigned: '',
206
- status: '',
207
- fileCount: { $ifNull: [ '$audit.fileCount', 0 ] },
215
+ storeId: 1,
216
+ storeName: '$stores.storeName',
217
+ userName: '$users.userName',
218
+ userEmail: '$users.userEmail',
219
+
220
+ clientId: 1,
221
+ auditType: 1,
222
+ beforeCount: 1,
223
+ afterCount: { $ifNull: [ '$afterCount', null ] },
224
+ accuracy: { $round: [
225
+ { $divide: [
226
+ { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
227
+ ] }, 2,
228
+ ],
229
+
230
+ },
231
+ timeSpent: 1,
232
+ status: 1,
208
233
  },
209
234
  },
210
235
 
211
236
  ];
212
- query.push( {
213
- $sort: {
214
- fileDateISO: -1,
215
- },
216
- } );
217
237
 
218
238
  if ( inputData.searchValue && inputData.searchValue !== '' ) {
219
239
  query.push( {
@@ -225,85 +245,42 @@ export async function storeMetrics( req, res ) {
225
245
  },
226
246
  } );
227
247
  }
228
- const result = await aggregateAuditClientData( query );
248
+ const count = await aggregateStoreAudit( query );
229
249
 
230
- if ( result.length == 0 ) {
250
+ if ( count.length == 0 ) {
231
251
  return res.sendError( 'No data Found', 204 );
232
252
  }
233
- let count;
234
- if ( inputData.filterByStatus && inputData.filterByStatus.length > 0 ) {
235
- let testCount;
236
- for ( let i = 0; i < result.length; i++ ) {
237
- const item = result[i];
238
- if ( inputData.fromDate === inputData.toDate && inputData.fromDate === yesterday ) {
239
- const temp = await listQueue( item.queueName );
240
- item.notAssigned = Number( temp );
241
- } else {
242
- item.notAssigned = 'No Data';
243
- }
244
- item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
245
- item.fileCount > 0 ? 'pending' : 'not_taken';
246
- delete item.fileCount;
247
- testCount = result.filter( ( i ) => inputData.filterByStatus.includes( i.status ) );
248
- count = testCount.length;
249
- }
250
- if ( !inputData.isExport ) {
251
- const skip = ( inputData.offset - 1 ) * inputData.limit;
252
- testCount = testCount.slice( skip, skip + inputData.limit );
253
- }
254
- if ( inputData.isExport ) {
255
- const exportdata = [];
256
- testCount.forEach( ( element ) => {
257
- exportdata.push( {
258
- 'File Date': element.fileDate,
259
- 'Client Name': element.clientName,
260
- 'Client Id': element.clientId,
261
- 'Completed Percentage': element.completePercentage + ' %',
262
- 'Installed Stores': element.installedStore,
263
- 'Audit Stores': element.totalFilesCount,
264
- 'Inprogress Stores': element.assignedStores,
265
- 'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
266
- 'Completed': element.completedStores,
267
- 'Status': element.status,
268
- } );
269
- } );
270
- await download( exportdata, res );
271
- return;
272
- }
273
- return res.sendSuccess( { result: testCount, count: count } );
274
- }
275
- for ( let i = 0; i < result.length; i++ ) {
276
- const item = result[i];
277
- if ( inputData.fromDate === inputData.toDate && inputData.fromDate === yesterday ) {
278
- const temp = await listQueue( item.queueName );
279
- item.notAssigned = Number( temp );
280
- } else {
281
- item.notAssigned = 'No Data';
282
- }
283
- item.status = ( item.totalFilesCount === item.completedStores && item.assignedStores === 0 && ( item.notAssigned == 0 || item.notAssigned === 'No Data' ) ) ? 'completed' :
284
- item.fileCount > 0 ? 'pending' : 'not_taken';
285
- delete item.fileCount;
253
+ if ( !inputData.isExport ) {
254
+ query.push( {
255
+ $skip: offset,
256
+ },
257
+ {
258
+ $limit: limit,
259
+ } );
260
+ } else {
261
+ query.push( { $limit: 10000 } );
286
262
  }
263
+ const result = await aggregateStoreAudit( query );
287
264
  if ( inputData.isExport ) {
288
265
  const exportdata = [];
289
266
  result.forEach( ( element ) => {
290
267
  exportdata.push( {
291
268
  'File Date': element.fileDate,
292
- 'Client Name': element.clientName,
269
+ 'Store Id': element.storeId,
270
+ 'Store Name': element.storeName,
293
271
  'Client Id': element.clientId,
294
- 'Completed Percentage': element.completePercentage + ' %',
295
- 'Installed Stores': element.installedStore,
296
- 'Audit Stores': element.totalFilesCount,
297
- 'Assigned Stores': element.assignedStores,
298
- 'Not Assigned': element.notAssigned && element.notAssigned == 'No Data' ? 0 : element.notAssigned,
299
- 'Completed': element.completedStores,
272
+ 'User Name': element.userName,
273
+ 'User Email': element.userEmail,
274
+ 'Audit Type': element.auditType,
275
+ 'Accuracy': element.accuracy,
276
+ 'Time Spent': element.timeSpent,
300
277
  'Status': element.status,
301
278
  } );
302
279
  } );
303
280
  await download( exportdata, res );
304
281
  return;
305
282
  }
306
- return res.sendSuccess( { result: result, count: count } );
283
+ return res.sendSuccess( { result: result, count: count.length } );
307
284
  } catch ( error ) {
308
285
  const err = error.message || 'Internal Server Error';
309
286
  logger.error( { error: error, data: req.body, function: 'storeMetrics' } );
@@ -823,9 +800,10 @@ export async function summarySplit( req, res ) {
823
800
  auditInprogress: 0,
824
801
  reAuditInprogress: 0,
825
802
  draft: 0,
826
- notAssigned: 0,
803
+ assigned: 0,
827
804
  auditCompleted: 0,
828
805
  reAuditCompleted: 0,
806
+ completedCount: 0,
829
807
  };
830
808
 
831
809
  const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
@@ -908,7 +886,6 @@ export async function summarySplit( req, res ) {
908
886
  completedCount: 1,
909
887
  reAuditCompleted: 1,
910
888
  auditCompleted: 1,
911
- completedCount: 1,
912
889
 
913
890
  },
914
891
  },
@@ -1061,3 +1038,118 @@ export async function overViewTable( req, res ) {
1061
1038
  return res.sendError( err, 500 );
1062
1039
  }
1063
1040
  }
1041
+
1042
+ export async function overAllAuditSummary( req, res ) {
1043
+ try {
1044
+ const inputData = req.body;
1045
+ let temp = {
1046
+ installedStores: 0,
1047
+ auditStores: 0,
1048
+ inprogreseStores: 0,
1049
+ completedStores: 0,
1050
+ auditInprogress: 0,
1051
+ reAuditInprogress: 0,
1052
+ draft: 0,
1053
+ assigned: 0,
1054
+ notAssigned: 0,
1055
+ auditCompleted: 0,
1056
+ reAuditCompleted: 0,
1057
+
1058
+ };
1059
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1060
+ let filters =[
1061
+ { fileDateISO: { $gte: dateRange.start } },
1062
+ { fileDateISO: { $lte: dateRange.end } },
1063
+
1064
+ ];
1065
+ if ( inputData.clientId.length > 0 ) {
1066
+ filters.push( { clientId: { $in: inputData.clientId } } );
1067
+ }
1068
+ const storeQuery = inputData.clientId.length? { 'edge.firstFile': true, 'clientId': { $in: inputData. clientId } } : { 'edge.firstFile': true };
1069
+ temp.installedStores = await countDocumentsStore( storeQuery );
1070
+ const auditClientDataQuery =[
1071
+ {
1072
+ $match: {
1073
+ $and: filters,
1074
+ },
1075
+
1076
+ },
1077
+ {
1078
+ $group: {
1079
+ _id: null,
1080
+ totalFilesCount: { $sum: '$totalFilesCount' },
1081
+ },
1082
+ },
1083
+ ];
1084
+ const auditClientData = await aggregateAuditClientData( auditClientDataQuery );
1085
+ if ( auditClientData.length >0 ) {
1086
+ temp.auditStores = auditClientData[0].totalFilesCount;
1087
+ }
1088
+ const storeAuditQuery =[
1089
+ {
1090
+ $match: {
1091
+ $and: filters,
1092
+ },
1093
+
1094
+ },
1095
+ {
1096
+ $project: {
1097
+ completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
1098
+ auditInprogress: { $cond: [ { $and: [ { $in: [ '$status', [ 'inprogress' ] ] }, { $eq: [ '$auditType', 'Audit' ] } ] }, 1, 0 ] },
1099
+ reAuditInprogress: { $cond: [ { $and: [ { $in: [ '$status', [ 'inprogress' ] ] }, { $eq: [ '$auditType', 'ReAudit' ] } ] }, 1, 0 ] },
1100
+ draft: { $cond: [ { $eq: [ '$status', 'drafted' ] }, 1, 0 ] },
1101
+ assigned: { $cond: [ { $eq: [ '$status', 'drafted' ] }, 1, 0 ] },
1102
+ exceptNoAssigned: { $cond: [ { $in: [ '$status', [ 'skipped', 'not_assign' ] ] }, 1, 0 ] },
1103
+ auditCompleted: { $cond: [ { $and: [ { $in: [ '$status', [ 'completed' ] ] }, { $eq: [ '$auditType', 'Audit' ] } ] }, 1, 0 ] },
1104
+ reAuditCompleted: { $cond: [ { $and: [ { $in: [ '$status', [ 'completed' ] ] }, { $eq: [ '$auditType', 'ReAudit' ] } ] }, 1, 0 ] },
1105
+
1106
+
1107
+ },
1108
+ },
1109
+ {
1110
+ $group: {
1111
+ _id: null,
1112
+ completedStores: { $sum: '$completedStores' },
1113
+ auditInprogress: { $sum: '$auditInprogress' },
1114
+ reAuditInprogress: { $sum: '$reAuditInprogress' },
1115
+ draft: { $sum: '$draft' },
1116
+ assigned: { $sum: '$assigned' },
1117
+ exceptNoAssigned: { $sum: '$exceptNoAssigned' },
1118
+ auditCompleted: { $sum: '$auditCompleted' },
1119
+ reAuditCompleted: { $sum: '$reAuditCompleted' },
1120
+ },
1121
+ },
1122
+ {
1123
+ $project: {
1124
+ completedStores: 1,
1125
+ inprogressStores: { $subtract: [ temp.auditStores, '$completedStores' ] },
1126
+ auditInprogress: 1,
1127
+ reAuditInprogress: 1,
1128
+ draft: 1,
1129
+ assigned: 1,
1130
+ exceptNoAssigned: { $subtract: [ temp.auditStores, '$exceptNoAssigned' ] },
1131
+ auditCompleted: 1,
1132
+ reAuditCompleted: 1,
1133
+ },
1134
+ },
1135
+ ];
1136
+ const storeAudit = await aggregateStoreAudit( storeAuditQuery );
1137
+ if ( storeAudit.length > 0 ) {
1138
+ temp.inprogreseStores= storeAudit[0].inprogreseStores;
1139
+ temp.completedStores = storeAudit[0].completedStores;
1140
+ temp.auditInprogress = storeAudit[0].auditInprogress;
1141
+ temp.reAuditInprogress = storeAudit[0].reAuditInprogress;
1142
+ temp.draft = storeAudit[0].draft;
1143
+ temp.assigned = storeAudit[0].assigned;
1144
+ temp.notAssigned = storeAudit[0].exceptNoAssigned;
1145
+ temp.auditCompleted = storeAudit[0].auditCompleted;
1146
+ temp.reAuditCompleted = storeAudit[0].reAuditCompleted;
1147
+ }
1148
+
1149
+ return res.sendSuccess( { result: temp } );
1150
+ } catch ( error ) {
1151
+ const err = error.message || 'Internal Server Error';
1152
+ logger.error( { error: error, message: req.body, function: 'summarySplit' } );
1153
+ return res.sendError( err, 500 );
1154
+ }
1155
+ }
@@ -138,3 +138,15 @@ export const overViewTableSchema = joi.object(
138
138
  export const overViewTableValid = {
139
139
  body: overViewTableSchema,
140
140
  };
141
+
142
+ export const overAllAuditSummarySchema = joi.object(
143
+ {
144
+ fromDate: joi.string().required(),
145
+ toDate: joi.string().required(),
146
+ clientId: joi.array().optional(),
147
+ },
148
+ );
149
+
150
+ export const overAllAuditSummaryValid = {
151
+ body: overAllAuditSummarySchema,
152
+ };
@@ -1,8 +1,8 @@
1
1
 
2
2
  import express from 'express';
3
3
  import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
4
- import { clientMetrics, overViewCard, overViewTable, storeMetrics, summarySplit, userAuditHistory, userMetrics } from '../controllers/auditMetrics.controllers.js';
5
- import { clientMetricsValid, overViewCardValid, overViewTableValid, storeMetricsValid, summarySplitValid, userAuditHistoryValid, userMetricsValid } from '../dtos/auditMetrics.dtos.js';
4
+ import { clientMetrics, overAllAuditSummary, overViewCard, overViewTable, storeMetrics, summarySplit, userAuditHistory, userMetrics } from '../controllers/auditMetrics.controllers.js';
5
+ import { clientMetricsValid, overAllAuditSummaryValid, overViewCardValid, overViewTableValid, storeMetricsValid, summarySplitValid, userAuditHistoryValid, userMetricsValid } from '../dtos/auditMetrics.dtos.js';
6
6
 
7
7
  export const auditMetricsRouter = express.Router();
8
8
 
@@ -13,5 +13,6 @@ auditMetricsRouter.post( '/user-metrics', isAllowedSessionHandler, validate( use
13
13
  auditMetricsRouter.post( '/overview-card', isAllowedSessionHandler, validate( overViewCardValid ), overViewCard );
14
14
  auditMetricsRouter.post( '/summary-split-up', isAllowedSessionHandler, validate( summarySplitValid ), summarySplit );
15
15
  auditMetricsRouter.post( '/overview-table', isAllowedSessionHandler, validate( overViewTableValid ), overViewTable );
16
+ auditMetricsRouter.post( '/overall-audit-summary', isAllowedSessionHandler, validate( overAllAuditSummaryValid, overAllAuditSummary ) );
16
17
 
17
18
  export default auditMetricsRouter;
@@ -5,6 +5,10 @@ export function findOneStore( query, fields ) {
5
5
  return storeModel.findOne( query, fields );
6
6
  }
7
7
 
8
+ export function countDocumentsStore( query ) {
9
+ return storeModel.countDocuments( query );
10
+ }
11
+
8
12
  export function aggregateStore( query, fields ) {
9
13
  return storeModel.aggregate( query, fields );
10
14
  }