tango-app-api-audit 1.0.41 → 1.0.42

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.41",
3
+ "version": "1.0.42",
4
4
  "description": "audit & audit metrics apis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -63,14 +63,6 @@ export async function userAuditHistory( req, res ) {
63
63
  ];
64
64
 
65
65
 
66
- if ( inputData.sortColumnName ) {
67
- const sortBy = inputData.sortBy || -1;
68
- query.push( {
69
- $sort: { [inputData.sortColumName]: sortBy },
70
- },
71
- );
72
- }
73
-
74
66
  query.push( {
75
67
  $lookup: {
76
68
  from: 'stores',
@@ -93,17 +85,50 @@ export async function userAuditHistory( req, res ) {
93
85
 
94
86
  } );
95
87
 
88
+
96
89
  query.push( {
97
90
  $unwind: {
98
91
  path: '$store', preserveNullAndEmptyArrays: true,
99
92
  },
100
93
  } );
101
94
 
95
+ query.push( {
96
+ $lookup: {
97
+ from: 'clients',
98
+ let: { clientId: '$clientId' },
99
+ pipeline: [
100
+ {
101
+ $match: {
102
+ $expr: {
103
+ $eq: [ '$clientId', '$$clientId' ],
104
+ },
105
+ },
106
+ },
107
+ {
108
+ $project: {
109
+ clientName: 1,
110
+ },
111
+ },
112
+ ], as: 'client',
113
+ },
114
+
115
+ } );
116
+
117
+
118
+ query.push( {
119
+ $unwind: {
120
+ path: '$client', preserveNullAndEmptyArrays: true,
121
+ },
122
+ } );
123
+
102
124
  query.push( {
103
125
  $project: {
104
126
  storeId: 1,
105
127
  userId: 1,
106
128
  storeName: '$store.storeName',
129
+ clientId: 1,
130
+ clientName: 'client.clientName',
131
+ fileDate: 1,
107
132
  auditType: 1,
108
133
  zoneName: 1,
109
134
  moduleType: 1,
@@ -112,14 +137,51 @@ export async function userAuditHistory( req, res ) {
112
137
  accuracy: { $round: [
113
138
  {
114
139
  $divide: [ { $multiply: [ '$beforeCount', { $ifNull: [ '$afterCount', 0 ] } ] }, 100 ],
115
- }, 2,
140
+ }, 1,
116
141
  ],
117
142
  },
118
- startTime: 1,
119
- endTime: 1,
120
- timeSpent: { $round: [
121
- { $divide: [ '$timeSpent', 60 ] }, 2,
122
- ] },
143
+ startTime: {
144
+ $dateToString: {
145
+ format: '%Y-%m-%d %H:%M:%S',
146
+ date: '$startTime',
147
+ timezone: 'Asia/Kolkata',
148
+ },
149
+ },
150
+ endTime: {
151
+ $dateToString: {
152
+ format: '%Y-%m-%d %H:%M:%S',
153
+ date: '$endTime',
154
+ timezone: 'Asia/Kolkata',
155
+ },
156
+ },
157
+ // timeSpent: { $round: [
158
+ // { $divide: [ '$timeSpent', 60 ] }, 2,
159
+ // ] },
160
+ timeSpent: {
161
+
162
+ $cond: [
163
+ { $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
164
+ { $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
165
+ {
166
+ $cond: [
167
+ { $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
168
+ {
169
+ $concat: [
170
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
171
+ ' min',
172
+ ],
173
+ },
174
+ {
175
+ $concat: [
176
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
177
+ ' hr',
178
+ ],
179
+ },
180
+ ],
181
+ },
182
+ ],
183
+
184
+ },
123
185
  auditStatus: 1,
124
186
  createdAt: 1,
125
187
  },
@@ -129,17 +191,26 @@ export async function userAuditHistory( req, res ) {
129
191
  query.push( {
130
192
  $match: {
131
193
  $or: [
194
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
195
+ { clientType: { $regex: inputData.searchValue, $options: 'i' } },
132
196
  { zoneName: { $regex: inputData.searchValue, $options: 'i' } },
133
- { storeId: { $regex: inputData.storeId, $options: 'i' } },
134
- { storeName: { $regex: inputData.storeName, $options: 'i' } },
135
- { moduleType: { $regex: inputData.moduleType, $options: 'i' } },
136
- { auditStatus: { $regex: inputData.auditStatus, $options: 'i' } },
197
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
198
+ { storeName: { $regex: inputData.searchValue, $options: 'i' } },
199
+ { moduleType: { $regex: inputData.searchValue, $options: 'i' } },
200
+ { auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
137
201
  ],
138
202
 
139
203
  },
140
204
  } );
141
205
  }
142
206
 
207
+ if ( inputData.sortColumnName ) {
208
+ const sortBy = inputData.sortBy || -1;
209
+ query.push( {
210
+ $sort: { [inputData.sortColumName]: sortBy },
211
+ },
212
+ );
213
+ }
143
214
  const count = await aggregateUserAudit( query );
144
215
  if ( count.length == 0 ) {
145
216
  return res.sendError( 'No Data Found', 204 );
@@ -151,6 +222,8 @@ export async function userAuditHistory( req, res ) {
151
222
  const exportData = [];
152
223
  chunk.forEach( ( element ) => {
153
224
  exportData.push( {
225
+ 'Client Id': element.clientId,
226
+ 'Client Name': element.clientName,
154
227
  'Store Id': element.storeId,
155
228
  'Store Name': element.storeName,
156
229
  'Type': element.auditType,
@@ -163,7 +236,7 @@ export async function userAuditHistory( req, res ) {
163
236
  'End Time': element.endTime,
164
237
  'Time Spent': element.timeSpent,
165
238
  'Audit Status': element.auditStatus,
166
- 'CreatedAt': element.createdAt,
239
+ 'CreatedAt': dayjs( element.createdAt ).format( 'YYYY,MMM D' ),
167
240
 
168
241
  } );
169
242
  } );
@@ -184,7 +257,7 @@ export async function userAuditHistory( req, res ) {
184
257
  } );
185
258
  const result = await aggregateUserAudit( query );
186
259
 
187
- return res.sendSuccess( { result: result } );
260
+ return res.sendSuccess( { result: result, count: count.length } );
188
261
  } catch ( error ) {
189
262
  const err = error.message || 'Internal Server Error';
190
263
  logger.info( { error: error, message: req.body, function: 'userAuditHistory' } );
@@ -214,6 +287,10 @@ export async function storeMetrics( req, res ) {
214
287
  filter.push( { status: { $in: inputData.filterByStatus } } );
215
288
  }
216
289
 
290
+ if ( inputData.filterByType && inputData.filterByType?.length > 0 ) {
291
+ filter.push( { auditType: { $in: inputData.filterByType } } );
292
+ }
293
+
217
294
 
218
295
  const query = [
219
296
  {
@@ -221,16 +298,45 @@ export async function storeMetrics( req, res ) {
221
298
  $and: filter,
222
299
  },
223
300
  },
301
+
302
+ {
303
+ $lookup: {
304
+ from: 'stores',
305
+ let: { storeId: '$storeId' },
306
+ pipeline: [
307
+ {
308
+ $match: {
309
+ $expr: {
310
+ $eq: [ '$storeId', '$$storeId' ],
311
+ },
312
+ },
313
+ },
314
+ {
315
+ $project: {
316
+ _id: 0,
317
+ storeName: 1,
318
+ },
319
+ },
320
+ ], as: 'stores',
321
+ },
322
+ },
323
+ {
324
+ $unwind: {
325
+ path: '$stores',
326
+ preserveNullAndEmptyArrays: true,
327
+ },
328
+ },
224
329
  {
225
330
  $project: {
226
331
  _id: 0,
227
332
  fileDate: 1,
228
333
  storeId: 1,
229
- storeName: '$storeId',
334
+ storeName: '$store.storeName',
335
+ clientName: '',
336
+ clientId: 1,
230
337
  userId: {
231
338
  $arrayElemAt: [ '$userId', { $subtract: [ { $size: '$userId' }, 1 ] } ],
232
339
  },
233
- clientId: 1,
234
340
  auditType: 1,
235
341
  beforeCount: 1,
236
342
  afterCount: { $ifNull: [ '$afterCount', null ] },
@@ -247,56 +353,56 @@ export async function storeMetrics( req, res ) {
247
353
  },
248
354
  {
249
355
  $lookup: {
250
- from: 'stores',
251
- let: { storeId: '$storeId' },
356
+ from: 'users',
357
+ let: { userId: '$userId' },
252
358
  pipeline: [
253
359
  {
254
360
  $match: {
255
361
  $expr: {
256
- $eq: [ '$storeId', '$$storeId' ],
362
+ $eq: [ '$_id', '$$userId' ],
257
363
  },
258
364
  },
259
365
  },
260
366
  {
261
367
  $project: {
262
368
  _id: 0,
263
- storeName: 1,
369
+ userName: 1,
370
+ userEmail: '$email',
264
371
  },
265
372
  },
266
- ], as: 'stores',
373
+ ], as: 'users',
267
374
  },
268
375
  },
269
376
  {
270
377
  $unwind: {
271
- path: '$stores',
378
+ path: '$users',
272
379
  preserveNullAndEmptyArrays: true,
273
380
  },
274
381
  },
275
382
  {
276
383
  $lookup: {
277
- from: 'users',
278
- let: { userId: '$userId' },
384
+ from: 'clients',
385
+ let: { clientId: '$clientId' },
279
386
  pipeline: [
280
387
  {
281
388
  $match: {
282
389
  $expr: {
283
- $eq: [ '$_id', '$$userId' ],
390
+ $eq: [ '$clientId', '$$clientId' ],
284
391
  },
285
392
  },
286
393
  },
287
394
  {
288
395
  $project: {
289
396
  _id: 0,
290
- userName: 1,
291
- userEmail: '$email',
397
+ clientName: 1,
292
398
  },
293
399
  },
294
- ], as: 'users',
400
+ ], as: 'client',
295
401
  },
296
402
  },
297
403
  {
298
404
  $unwind: {
299
- path: '$users',
405
+ path: '$client',
300
406
  preserveNullAndEmptyArrays: true,
301
407
  },
302
408
  },
@@ -308,19 +414,43 @@ export async function storeMetrics( req, res ) {
308
414
  storeName: '$stores.storeName',
309
415
  userName: '$users.userName',
310
416
  userEmail: '$users.userEmail',
311
-
312
417
  clientId: 1,
418
+ clientName: '$client.clientName',
313
419
  auditType: 1,
314
420
  beforeCount: 1,
315
421
  afterCount: { $ifNull: [ '$afterCount', null ] },
316
422
  accuracy: { $round: [
317
423
  { $divide: [
318
424
  { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
319
- ] }, 2,
425
+ ] }, 1,
320
426
  ],
321
427
 
322
428
  },
323
- timeSpent: 1,
429
+ timeSpent: {
430
+
431
+ $cond: [
432
+ { $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
433
+ { $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
434
+ {
435
+ $cond: [
436
+ { $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
437
+ {
438
+ $concat: [
439
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
440
+ ' min',
441
+ ],
442
+ },
443
+ {
444
+ $concat: [
445
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
446
+ ' hr',
447
+ ],
448
+ },
449
+ ],
450
+ },
451
+ ],
452
+
453
+ },
324
454
  status: 1,
325
455
  },
326
456
  },
@@ -333,10 +463,23 @@ export async function storeMetrics( req, res ) {
333
463
  $or: [
334
464
  { clientId: { $regex: inputData.searchValue, $options: 'i' } },
335
465
  { clientName: { $regex: inputData.searchValue, $options: 'i' } },
466
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
467
+ { storeName: { $regex: inputData.searchValue, $options: 'i' } },
468
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
469
+ { status: { $regex: inputData.searchValue, $options: 'i' } },
470
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
336
471
  ],
337
472
  },
338
473
  } );
339
474
  }
475
+
476
+ if ( inputData.sortColumnName ) {
477
+ const sortBy = inputData.sortBy || -1;
478
+ query.push( {
479
+ $sort: { [inputData.sortColumName]: sortBy },
480
+ },
481
+ );
482
+ }
340
483
  const count = await aggregateStoreAudit( query );
341
484
 
342
485
  if ( count.length == 0 ) {
@@ -361,6 +504,7 @@ export async function storeMetrics( req, res ) {
361
504
  'Store Id': element.storeId,
362
505
  'Store Name': element.storeName,
363
506
  'Client Id': element.clientId,
507
+ 'Client Name': element.clientName,
364
508
  'User Name': element.userName,
365
509
  'User Email': element.userEmail,
366
510
  'Audit Type': element.auditType,
@@ -389,6 +533,7 @@ export async function clientMetrics( req, res ) {
389
533
  let filter = [
390
534
  { fileDateISO: { $gte: dateRange.start } },
391
535
  { fileDateISO: { $lte: dateRange.end } },
536
+ { moduleType: { $eq: 'traffic' } },
392
537
 
393
538
  ];
394
539
  if ( inputData?.filterByClient?.length> 0 ) {
@@ -396,11 +541,6 @@ export async function clientMetrics( req, res ) {
396
541
  { clientId: { $in: inputData.filterByClient } },
397
542
  );
398
543
  }
399
- if ( inputData?.filterByAuditType?.length> 0 ) {
400
- filter.push(
401
- { clientId: { $in: inputData.filterByAuditType } },
402
- );
403
- }
404
544
  const query = [
405
545
  {
406
546
  $match: {
@@ -438,6 +578,7 @@ export async function clientMetrics( req, res ) {
438
578
  {
439
579
  $project: {
440
580
  completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
581
+ notAssignedStores: { $cond: [ { $eq: [ '$status', 'not_assign' ] }, 1, 0 ] },
441
582
  inprogressStores: { $cond: [ { $in: [ '$status', [ 'inprogress', 'drafted', 'assigned' ] ] }, 1, 0 ] },
442
583
  },
443
584
  },
@@ -446,6 +587,8 @@ export async function clientMetrics( req, res ) {
446
587
  _id: { clientId: '$clientId', fileDate: '$fileDate' },
447
588
  completedStores: { $sum: '$completedStores' },
448
589
  inprogressStores: { $sum: '$inprogressStores' },
590
+ notAssignedStores: { $sum: '$notAssignedStores' },
591
+ fileCount: { $sum: 1 },
449
592
  },
450
593
  },
451
594
  {
@@ -453,6 +596,8 @@ export async function clientMetrics( req, res ) {
453
596
  _id: 0,
454
597
  completedStores: 1,
455
598
  inprogressStores: 1,
599
+ notAssignedStores: 1,
600
+ fileCount: 1,
456
601
  completionPercentage: { $ifNull: [
457
602
  {
458
603
  $round: [ {
@@ -487,15 +632,18 @@ export async function clientMetrics( req, res ) {
487
632
  clientName: 1,
488
633
  totalFilesCount: 1,
489
634
  installedStore: 1,
635
+ notAssignedStores: '$storeAudit.notAssignedStores',
490
636
  inprogressStoresCount: '$storeAudit.inprogressStores',
637
+ fileCount: '$storeAudit.fileCount',
491
638
  notAssignedCount: 1,
492
- clientStatus: { $cond: [ { $gt: [ '$storeAudit.inprogressStores', 0 ] }, 'not-taken', { $cond: [ { $gt: [ '$notAssignedCount', 0 ] }, 'pending', 'completed' ] } ] },
639
+ clientStatus: { $cond: [ { $eq: [ '$storeAudit.fileCount', 0 ] }, 'not-taken', { $cond: [ { $or: [ { $gt: [ '$notAssignedCount', 0 ] }, { $gt: [ '$storeAudit.notAssignedStores', 0 ] } ] }, 'pending', 'completed' ] } ] },
493
640
  completedStores: '$storeAudit.completedStores',
494
641
  completionPercentage: '$storeAudit.completionPercentage',
495
642
 
496
643
  },
497
644
  },
498
645
  ];
646
+
499
647
  if ( inputData.searchValue && inputData.searchValue!== '' ) {
500
648
  query.push( {
501
649
  $match: {
@@ -537,6 +685,7 @@ export async function clientMetrics( req, res ) {
537
685
  'Audit Stores': '$totalFilesCount',
538
686
  'Inprogress Stores': '$inprogressStoresCount',
539
687
  'Not Assigned': '$notAssignedCount',
688
+ 'Not Assigned Stores': '$notAssignedStores',
540
689
  'Completed': '$completedStores',
541
690
  'Status': '$clientStatus',
542
691
  },
@@ -580,7 +729,7 @@ export async function userMetrics( req, res ) {
580
729
  }
581
730
  if ( inputData?.filterByAuditType?.length> 0 ) {
582
731
  filter.push(
583
- { clientId: { $in: inputData.filterByAuditType } },
732
+ { moduleType: { $in: inputData.filterByAuditType } },
584
733
  );
585
734
  }
586
735
  if ( inputData?.filterByStatus?.length> 0 ) {
@@ -609,9 +758,8 @@ export async function userMetrics( req, res ) {
609
758
  startTime: 1,
610
759
  endTime: 1,
611
760
  totalCompletedFiles: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, 1, 0 ] },
612
- beforeCount: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, '$beforeCount', 0 ] },
761
+ beforeCount: 1,
613
762
  afterCount: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, '$afterCount', 0 ] },
614
- zoneName: 1,
615
763
  },
616
764
  },
617
765
  {
@@ -624,7 +772,6 @@ export async function userMetrics( req, res ) {
624
772
  afterCount: { $sum: '$afterCount' },
625
773
  checkIntime: { $first: '$startTime' },
626
774
  checkOutTime: { $last: '$endTime' },
627
- zoneName: { $last: '$zoneNmae' },
628
775
 
629
776
  },
630
777
  },
@@ -636,7 +783,6 @@ export async function userMetrics( req, res ) {
636
783
  totalCompletedFiles: 1,
637
784
  beforeCount: 1,
638
785
  afterCount: 1,
639
- zoneName: 1,
640
786
  mappingPerc: { $round: [
641
787
  { $multiply: [
642
788
  { $divide: [ '$afterCount', '$beforeCount' ] }, 100,
@@ -658,7 +804,6 @@ export async function userMetrics( req, res ) {
658
804
  afterCount: 1,
659
805
  checkIntime: 1,
660
806
  checkOutTime: 1,
661
- zoneName: 1,
662
807
  mappingPerc: 1,
663
808
  hours: { $floor: { $divide: [ '$differenceInSeconds', 3600 ] } },
664
809
  minutes: { $floor: { $divide: [ { $mod: [ '$differenceInSeconds', 3600 ] }, 60 ] } },
@@ -675,7 +820,6 @@ export async function userMetrics( req, res ) {
675
820
  afterCount: 1,
676
821
  checkIntime: 1,
677
822
  checkOutTime: 1,
678
- zoneName: 1,
679
823
  hours: {
680
824
  $cond: {
681
825
  if: { $lt: [ '$hours', 10 ] },
@@ -748,12 +892,23 @@ export async function userMetrics( req, res ) {
748
892
  userName: '$userInfo.userName',
749
893
  userId: 1,
750
894
  fileDate: 1,
751
- zoneName: 1,
752
895
  totalCompletedFiles: 1,
753
896
  beforeCount: 1,
754
897
  afterCount: 1,
755
- checkIntime: 1,
756
- checkOutTime: 1,
898
+ checkIntime: {
899
+ $dateToString: {
900
+ format: '%Y-%m-%d %H:%M:%S',
901
+ date: '$checkIntime',
902
+ timezone: 'Asia/Kolkata',
903
+ },
904
+ },
905
+ checkOutTime: {
906
+ $dateToString: {
907
+ format: '%Y-%m-%d %H:%M:%S',
908
+ date: '$checkOutTime',
909
+ timezone: 'Asia/Kolkata',
910
+ },
911
+ },
757
912
  workingHours: 1,
758
913
  },
759
914
  },
@@ -762,7 +917,7 @@ export async function userMetrics( req, res ) {
762
917
  query.push( {
763
918
  $match: {
764
919
  $or: [
765
- { clientId: { $regex: inputData.searchValue, $options: 'i' } },
920
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
766
921
  { clientName: { $regex: inputData.searchValue, $options: 'i' } },
767
922
  ],
768
923
 
@@ -794,7 +949,6 @@ export async function userMetrics( req, res ) {
794
949
  'File Date': '$fileDate',
795
950
  'User Name': '$userName',
796
951
  'User Id': '$userId',
797
- 'Zone Name': '$zoneName',
798
952
  'Total Completed Files Count': '$totalCompletedFiles',
799
953
  'Total efore Count': '$beforeCount',
800
954
  'Total After Count': '$afterCount',
@@ -921,6 +921,10 @@ export async function storeMetrics( req, res ) {
921
921
  filter.push( { status: { $in: inputData.filterByStatus } } );
922
922
  }
923
923
 
924
+ if ( inputData.filterByType && inputData.filterByType?.length > 0 ) {
925
+ filter.push( { auditType: { $in: inputData.filterByType } } );
926
+ }
927
+
924
928
  const query = [
925
929
  {
926
930
  $match: {
@@ -958,6 +962,8 @@ export async function storeMetrics( req, res ) {
958
962
  fileDate: 1,
959
963
  storeId: 1,
960
964
  storeName: '$store.storeName',
965
+ clientName: '',
966
+ clientId: 1,
961
967
  userId: {
962
968
  $arrayElemAt: [ '$userId', { $subtract: [ { $size: '$userId' }, 1 ] } ],
963
969
  },
@@ -978,56 +984,56 @@ export async function storeMetrics( req, res ) {
978
984
  },
979
985
  {
980
986
  $lookup: {
981
- from: 'stores',
982
- let: { storeId: '$storeId' },
987
+ from: 'users',
988
+ let: { userId: '$userId' },
983
989
  pipeline: [
984
990
  {
985
991
  $match: {
986
992
  $expr: {
987
- $eq: [ '$storeId', '$$storeId' ],
993
+ $eq: [ '$_id', '$$userId' ],
988
994
  },
989
995
  },
990
996
  },
991
997
  {
992
998
  $project: {
993
999
  _id: 0,
994
- storeName: 1,
1000
+ userName: 1,
1001
+ userEmail: '$email',
995
1002
  },
996
1003
  },
997
- ], as: 'stores',
1004
+ ], as: 'users',
998
1005
  },
999
1006
  },
1000
1007
  {
1001
1008
  $unwind: {
1002
- path: '$stores',
1009
+ path: '$users',
1003
1010
  preserveNullAndEmptyArrays: true,
1004
1011
  },
1005
1012
  },
1006
1013
  {
1007
1014
  $lookup: {
1008
- from: 'users',
1009
- let: { userId: '$userId' },
1015
+ from: 'clients',
1016
+ let: { clientId: '$clientId' },
1010
1017
  pipeline: [
1011
1018
  {
1012
1019
  $match: {
1013
1020
  $expr: {
1014
- $eq: [ '$_id', '$$userId' ],
1021
+ $eq: [ '$clientId', '$$clientId' ],
1015
1022
  },
1016
1023
  },
1017
1024
  },
1018
1025
  {
1019
1026
  $project: {
1020
1027
  _id: 0,
1021
- userName: 1,
1022
- userEmail: '$email',
1028
+ clientName: 1,
1023
1029
  },
1024
1030
  },
1025
- ], as: 'users',
1031
+ ], as: 'client',
1026
1032
  },
1027
1033
  },
1028
1034
  {
1029
1035
  $unwind: {
1030
- path: '$users',
1036
+ path: '$client',
1031
1037
  preserveNullAndEmptyArrays: true,
1032
1038
  },
1033
1039
  },
@@ -1039,19 +1045,43 @@ export async function storeMetrics( req, res ) {
1039
1045
  storeName: '$stores.storeName',
1040
1046
  userName: '$users.userName',
1041
1047
  userEmail: '$users.userEmail',
1042
-
1043
1048
  clientId: 1,
1049
+ clientName: '$client.clientName',
1044
1050
  auditType: 1,
1045
1051
  beforeCount: 1,
1046
1052
  afterCount: { $ifNull: [ '$afterCount', null ] },
1047
1053
  accuracy: { $round: [
1048
1054
  { $divide: [
1049
1055
  { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
1050
- ] }, 2,
1056
+ ] }, 1,
1051
1057
  ],
1052
1058
 
1053
1059
  },
1054
- timeSpent: 1,
1060
+ timeSpent: {
1061
+
1062
+ $cond: [
1063
+ { $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
1064
+ { $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
1065
+ {
1066
+ $cond: [
1067
+ { $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
1068
+ {
1069
+ $concat: [
1070
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
1071
+ ' min',
1072
+ ],
1073
+ },
1074
+ {
1075
+ $concat: [
1076
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
1077
+ ' hr',
1078
+ ],
1079
+ },
1080
+ ],
1081
+ },
1082
+ ],
1083
+
1084
+ },
1055
1085
  status: 1,
1056
1086
  },
1057
1087
  },
@@ -1064,10 +1094,24 @@ export async function storeMetrics( req, res ) {
1064
1094
  $or: [
1065
1095
  { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1066
1096
  { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1097
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
1098
+ { storeName: { $regex: inputData.searchValue, $options: 'i' } },
1099
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
1100
+ { status: { $regex: inputData.searchValue, $options: 'i' } },
1101
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
1067
1102
  ],
1068
1103
  },
1069
1104
  } );
1070
1105
  }
1106
+
1107
+ if ( inputData.sortColumnName ) {
1108
+ const sortBy = inputData.sortBy || -1;
1109
+ query.push( {
1110
+ $sort: { [inputData.sortColumName]: sortBy },
1111
+ },
1112
+ );
1113
+ }
1114
+
1071
1115
  const count = await aggregateStoreZoneAudit( query );
1072
1116
 
1073
1117
  if ( count.length == 0 ) {
@@ -1092,6 +1136,7 @@ export async function storeMetrics( req, res ) {
1092
1136
  'Store Id': element.storeId,
1093
1137
  'Store Name': element.storeName,
1094
1138
  'Client Id': element.clientId,
1139
+ 'Client Name': element.clientName,
1095
1140
  'User Name': element.userName,
1096
1141
  'User Email': element.userEmail,
1097
1142
  'Audit Type': element.auditType,
@@ -1110,3 +1155,186 @@ export async function storeMetrics( req, res ) {
1110
1155
  return res.sendError( err, 500 );
1111
1156
  }
1112
1157
  }
1158
+
1159
+ export async function clientMetrics( req, res ) {
1160
+ try {
1161
+ const inputData = req.body;
1162
+ const limit = inputData.limit || 10;
1163
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
1164
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1165
+ let filter = [
1166
+ { fileDateISO: { $gte: dateRange.start } },
1167
+ { fileDateISO: { $lte: dateRange.end } },
1168
+ { moduleType: { $eq: 'zone' } },
1169
+
1170
+ ];
1171
+ if ( inputData?.filterByClient?.length> 0 ) {
1172
+ filter.push(
1173
+ { clientId: { $in: inputData.filterByClient } },
1174
+ );
1175
+ }
1176
+ const query = [
1177
+ {
1178
+ $match: {
1179
+ $and: filter,
1180
+ },
1181
+ },
1182
+ {
1183
+ $project: {
1184
+ fileDate: 1,
1185
+ clientId: 1,
1186
+ clientName: 1,
1187
+ queueName: 1,
1188
+ installedStore: 1,
1189
+ totalFilesCount: 1,
1190
+ notAssignedCount: { $ifNull: [ 0, 0 ] },
1191
+ clientStatus: { $ifNull: [ '', '' ] },
1192
+ },
1193
+ },
1194
+ {
1195
+ $lookup: {
1196
+ 'from': 'storeZoneAudit',
1197
+ 'let': { clientId: '$clientId', fileDate: '$fileDate', totalAuditFiles: '$totalAuditFiles' },
1198
+ 'pipeline': [
1199
+
1200
+ {
1201
+ $match: {
1202
+ $expr: {
1203
+ $and: [
1204
+ { $eq: [ '$clientId', '$$clientId' ] },
1205
+ { $eq: [ '$fileDate', '$$fileDate' ] },
1206
+ ],
1207
+ },
1208
+ },
1209
+ },
1210
+ {
1211
+ $project: {
1212
+ completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
1213
+ notAssignedStores: { $cond: [ { $eq: [ '$status', 'not_assign' ] }, 1, 0 ] },
1214
+ inprogressStores: { $cond: [ { $in: [ '$status', [ 'inprogress', 'drafted', 'assigned' ] ] }, 1, 0 ] },
1215
+ },
1216
+ },
1217
+ {
1218
+ $group: {
1219
+ _id: { clientId: '$clientId', fileDate: '$fileDate' },
1220
+ completedStores: { $sum: '$completedStores' },
1221
+ inprogressStores: { $sum: '$inprogressStores' },
1222
+ notAssignedStores: { $sum: '$notAssignedStores' },
1223
+ fileCount: { $sum: 1 },
1224
+ },
1225
+ },
1226
+ {
1227
+ $project: {
1228
+ _id: 0,
1229
+ completedStores: 1,
1230
+ inprogressStores: 1,
1231
+ notAssignedStores: 1,
1232
+ fileCount: 1,
1233
+ completionPercentage: { $ifNull: [
1234
+ {
1235
+ $round: [ {
1236
+ $multiply: [
1237
+ 100, {
1238
+ $divide: [
1239
+ '$completedStores', '$$totalAuditFiles',
1240
+ ],
1241
+ },
1242
+ ],
1243
+ }, 1 ],
1244
+
1245
+ },
1246
+ 0,
1247
+ ],
1248
+ },
1249
+ },
1250
+ },
1251
+ ], 'as': 'storeZoneAudit',
1252
+ },
1253
+ },
1254
+ {
1255
+ $unwind: {
1256
+ path: '$storeZoneAudit',
1257
+ preserveNullAndEmptyArrays: true,
1258
+ },
1259
+ },
1260
+ {
1261
+ $project: {
1262
+ fileDate: 1,
1263
+ clientId: 1,
1264
+ clientName: 1,
1265
+ totalFilesCount: 1,
1266
+ installedStore: 1,
1267
+ fileCount: '$storeZoneAudit.fileCount',
1268
+ notAssignedStores: '$storeZoneAudit.notAssignedStores',
1269
+ inprogressStoresCount: '$storeZoneAudit.inprogressStores',
1270
+ notAssignedCount: 1,
1271
+ clientStatus: { $cond: [ { $eq: [ '$storeZoneAudit.fileCount', 0 ] }, 'not-taken', { $cond: [ { $or: [ { $gt: [ '$notAssignedCount', 0 ] }, { $gt: [ '$storeZoneAudit.notAssignedStores', 0 ] } ] }, 'pending', 'completed' ] } ] },
1272
+ completedStores: '$storeZoneAudit.completedStores',
1273
+ completionPercentage: '$storeZoneAudit.completionPercentage',
1274
+
1275
+ },
1276
+ },
1277
+ ];
1278
+
1279
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
1280
+ query.push( {
1281
+ $match: {
1282
+ $or: [
1283
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1284
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1285
+ ],
1286
+
1287
+ },
1288
+ } );
1289
+ }
1290
+ if ( inputData.sortColumnName ) {
1291
+ const sortBy = inputData.sortBy || -1;
1292
+ query.push( {
1293
+ $sort: { [inputData.sortColumName]: sortBy },
1294
+ },
1295
+ );
1296
+ }
1297
+
1298
+ const count = await aggregateAuditClientData( query );
1299
+ if ( count.length == 0 ) {
1300
+ return res.sendError( 'No Data Found', 204 );
1301
+ }
1302
+
1303
+ query.push(
1304
+ { $skip: offset },
1305
+ { $limit: limit },
1306
+ );
1307
+ if ( inputData.isExport ) {
1308
+ query.push(
1309
+ {
1310
+ $project: {
1311
+ '_id': 0,
1312
+ 'File Date': '$fileDate',
1313
+ 'Client Name': '$clientName',
1314
+ 'Client Id': '$clientId',
1315
+ 'Completed Percentage': '$completionPercentage',
1316
+ 'Installed Stores': '$installedStore',
1317
+ 'Audit Stores': '$totalFilesCount',
1318
+ 'Inprogress Stores': '$inprogressStoresCount',
1319
+ 'Not Assigned': '$notAssignedCount',
1320
+ 'Not Assigned Stores': '$notAssignedStores',
1321
+ 'Completed': '$completedStores',
1322
+ 'Status': '$clientStatus',
1323
+ },
1324
+ },
1325
+ );
1326
+ }
1327
+
1328
+
1329
+ const result = await aggregateAuditClientData( query );
1330
+ if ( inputData.isExport ) {
1331
+ await download( result, res );
1332
+ return;
1333
+ }
1334
+ return res.sendSuccess( { result: result, count: count.length } );
1335
+ } catch ( error ) {
1336
+ const err = error.error || 'Internal Server Error';
1337
+ logger.info( { error: error, message: req.body, function: 'clientMetrics' } );
1338
+ return res.sendError( err, 500 );
1339
+ }
1340
+ }
@@ -1,5 +1,5 @@
1
1
  import j2s from 'joi-to-swagger';
2
- import { getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, storeMetricsSchema, workSpaceSchema } from '../dtos/zoneAudit.dtos.js';
2
+ import { clientMetricsSchema, getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, storeMetricsSchema, workSpaceSchema } from '../dtos/zoneAudit.dtos.js';
3
3
 
4
4
  export const zoneAuditDocs = {
5
5
  '/v3/zone-audit/get-file': {
@@ -179,4 +179,27 @@ export const zoneAuditDocs = {
179
179
  },
180
180
  },
181
181
 
182
+ '/v3/zone-audit/metrics/client-metrics': {
183
+ post: {
184
+ tags: [ 'Zone Audit Metrics' ],
185
+ description: `Get list of client wise details with date range`,
186
+ operationId: 'metrics/client-metrics',
187
+ parameters: {},
188
+ requestBody: {
189
+ content: {
190
+ 'application/json': {
191
+ schema: j2s( clientMetricsSchema ).swagger,
192
+ },
193
+ },
194
+ },
195
+ responses: {
196
+ 200: { description: 'Successful' },
197
+ 401: { description: 'Unauthorized User' },
198
+ 422: { description: 'Field Error' },
199
+ 500: { description: 'Server Error' },
200
+ 204: { description: 'Not Found' },
201
+ },
202
+ },
203
+ },
204
+
182
205
  };
@@ -45,7 +45,7 @@ export const storeMetricsSchema = joi.object(
45
45
  filterByClientId: joi.array().required(),
46
46
  filterByStoreId: joi.array().optional(),
47
47
  filterByStatus: joi.array().optional(),
48
- filterByAuditType: joi.array().optional(),
48
+ filterByType: joi.array().optional(),
49
49
  sortColumnName: joi.string().optional(),
50
50
  sortBy: joi.number().optional(),
51
51
  limit: joi.number().optional(),
@@ -62,7 +62,6 @@ export const clientMetricsSchema = joi.object(
62
62
  {
63
63
  fromDate: joi.string().required(),
64
64
  toDate: joi.string().required(),
65
- filterByAuditType: joi.array().optional(),
66
65
  searchValue: joi.string().optional().allow( '' ),
67
66
  filterByClient: joi.array().required(),
68
67
  filterByStatus: joi.array().optional(),
@@ -108,3 +108,22 @@ export const storeMetricsValid = {
108
108
  body: storeMetricsSchema,
109
109
  };
110
110
 
111
+ export const clientMetricsSchema = joi.object(
112
+ {
113
+ fromDate: joi.string().required(),
114
+ toDate: joi.string().required(),
115
+ searchValue: joi.string().optional().allow( '' ),
116
+ filterByClient: joi.array().required(),
117
+ filterByStatus: joi.array().optional(),
118
+ sortColumnName: joi.string().optional(),
119
+ sortBy: joi.number().optional(),
120
+ limit: joi.number().optional(),
121
+ offset: joi.number().optional(),
122
+ isExport: joi.boolean().optional(),
123
+ },
124
+ );
125
+
126
+ export const clientMetricsValid = {
127
+ body: clientMetricsSchema,
128
+ };
129
+
@@ -1,9 +1,8 @@
1
1
  import { Router } from 'express';
2
- import { getDraftedDataValid, getFileValid, saveDraftValid, saveValid, workSpaceValid } from '../dtos/zoneAudit.dtos.js';
2
+ import { clientMetricsValid, getDraftedDataValid, getFileValid, saveDraftValid, saveValid, storeMetricsValid, workSpaceValid } from '../dtos/zoneAudit.dtos.js';
3
3
  import { isExistsQueue, validateUserAudit } from '../validation/audit.validation.js';
4
4
  import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
5
- import { getDraftedData, getZoneAuditFile, save, saveDraft, storeMetrics, workSpace } from '../controllers/zoneAudit.controller.js';
6
- import { storeMetricsValid } from '../dtos/auditMetrics.dtos.js';
5
+ import { clientMetrics, getDraftedData, getZoneAuditFile, save, saveDraft, storeMetrics, workSpace } from '../controllers/zoneAudit.controller.js';
7
6
 
8
7
  export const zoneAuditRouter=Router();
9
8
 
@@ -17,3 +16,4 @@ zoneAuditRouter.get( '/work-space', isAllowedSessionHandler, validate( workSpace
17
16
  // metrics
18
17
 
19
18
  zoneAuditRouter.post( '/metrics/store-metrics', isAllowedSessionHandler, validate( storeMetricsValid ), storeMetrics );
19
+ zoneAuditRouter.post( '/metrics/client-metrics', isAllowedSessionHandler, validate( clientMetricsValid ), clientMetrics );