tango-app-api-audit 1.0.40 → 1.0.41

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.40",
3
+ "version": "1.0.41",
4
4
  "description": "audit & audit metrics apis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -36,9 +36,9 @@ export async function userAuditHistory( req, res ) {
36
36
  );
37
37
  }
38
38
 
39
- if ( inputData.auditType?.length > 0 ) {
39
+ if ( inputData.filterByAuditType?.length > 0 ) {
40
40
  filter.push( {
41
- moduleType: { $in: inputData.auditType },
41
+ moduleType: { $in: inputData.filterByAuditType },
42
42
  } );
43
43
  }
44
44
 
@@ -396,6 +396,11 @@ export async function clientMetrics( req, res ) {
396
396
  { clientId: { $in: inputData.filterByClient } },
397
397
  );
398
398
  }
399
+ if ( inputData?.filterByAuditType?.length> 0 ) {
400
+ filter.push(
401
+ { clientId: { $in: inputData.filterByAuditType } },
402
+ );
403
+ }
399
404
  const query = [
400
405
  {
401
406
  $match: {
@@ -573,6 +578,11 @@ export async function userMetrics( req, res ) {
573
578
 
574
579
  );
575
580
  }
581
+ if ( inputData?.filterByAuditType?.length> 0 ) {
582
+ filter.push(
583
+ { clientId: { $in: inputData.filterByAuditType } },
584
+ );
585
+ }
576
586
  if ( inputData?.filterByStatus?.length> 0 ) {
577
587
  filter.push(
578
588
  { auditStatus: { $in: inputData.filterByStatus } },
@@ -601,6 +611,7 @@ export async function userMetrics( req, res ) {
601
611
  totalCompletedFiles: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, 1, 0 ] },
602
612
  beforeCount: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, '$beforeCount', 0 ] },
603
613
  afterCount: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, '$afterCount', 0 ] },
614
+ zoneName: 1,
604
615
  },
605
616
  },
606
617
  {
@@ -613,6 +624,7 @@ export async function userMetrics( req, res ) {
613
624
  afterCount: { $sum: '$afterCount' },
614
625
  checkIntime: { $first: '$startTime' },
615
626
  checkOutTime: { $last: '$endTime' },
627
+ zoneName: { $last: '$zoneNmae' },
616
628
 
617
629
  },
618
630
  },
@@ -624,6 +636,7 @@ export async function userMetrics( req, res ) {
624
636
  totalCompletedFiles: 1,
625
637
  beforeCount: 1,
626
638
  afterCount: 1,
639
+ zoneName: 1,
627
640
  mappingPerc: { $round: [
628
641
  { $multiply: [
629
642
  { $divide: [ '$afterCount', '$beforeCount' ] }, 100,
@@ -645,6 +658,7 @@ export async function userMetrics( req, res ) {
645
658
  afterCount: 1,
646
659
  checkIntime: 1,
647
660
  checkOutTime: 1,
661
+ zoneName: 1,
648
662
  mappingPerc: 1,
649
663
  hours: { $floor: { $divide: [ '$differenceInSeconds', 3600 ] } },
650
664
  minutes: { $floor: { $divide: [ { $mod: [ '$differenceInSeconds', 3600 ] }, 60 ] } },
@@ -661,6 +675,7 @@ export async function userMetrics( req, res ) {
661
675
  afterCount: 1,
662
676
  checkIntime: 1,
663
677
  checkOutTime: 1,
678
+ zoneName: 1,
664
679
  hours: {
665
680
  $cond: {
666
681
  if: { $lt: [ '$hours', 10 ] },
@@ -694,6 +709,7 @@ export async function userMetrics( req, res ) {
694
709
  beforeCount: 1,
695
710
  afterCount: 1,
696
711
  checkIntime: 1,
712
+ zoneName: 1,
697
713
  checkOutTime: 1,
698
714
  workingHours: {
699
715
  $concat: [ '$hours', ':', '$minutes', ':', '$seconds' ],
@@ -732,6 +748,7 @@ export async function userMetrics( req, res ) {
732
748
  userName: '$userInfo.userName',
733
749
  userId: 1,
734
750
  fileDate: 1,
751
+ zoneName: 1,
735
752
  totalCompletedFiles: 1,
736
753
  beforeCount: 1,
737
754
  afterCount: 1,
@@ -775,8 +792,9 @@ export async function userMetrics( req, res ) {
775
792
  $project: {
776
793
  '_id': 0,
777
794
  'File Date': '$fileDate',
778
- 'zuser Name': '$userName',
795
+ 'User Name': '$userName',
779
796
  'User Id': '$userId',
797
+ 'Zone Name': '$zoneName',
780
798
  'Total Completed Files Count': '$totalCompletedFiles',
781
799
  'Total efore Count': '$beforeCount',
782
800
  'Total After Count': '$afterCount',
@@ -1152,7 +1170,8 @@ export async function overAllAuditSummary( req, res ) {
1152
1170
  let filters =[
1153
1171
  { fileDateISO: { $gte: dateRange.start } },
1154
1172
  { fileDateISO: { $lte: dateRange.end } },
1155
-
1173
+ { moduleType: { $eq: inputData.moduleType },
1174
+ },
1156
1175
  ];
1157
1176
  if ( inputData.clientId.length > 0 ) {
1158
1177
  filters.push( { clientId: { $in: inputData.clientId } } );
@@ -1,4 +1,4 @@
1
- import { chunkArray, download, fileUpload, getJsonFileData, getUTC, insertOpenSearchData, listFileByPath, sendMessageToQueue, signedUrl, sqsReceive } from 'tango-app-api-middleware';
1
+ import { download, fileUpload, getJsonFileData, getUTC, insertOpenSearchData, listFileByPath, sendMessageToQueue, signedUrl, sqsReceive } from 'tango-app-api-middleware';
2
2
  import { aggregateZoneUserAudit, createZoneUserAudit, findOneZoneUserAudit } from '../service/zoneUserAudit.service.js';
3
3
  import { logger } from 'tango-app-api-middleware';
4
4
  import { aggregateAssignZoneAudit } from '../service/assignZoneAudit.service.js';
@@ -899,40 +899,26 @@ export async function workSpace( req, res ) {
899
899
  }
900
900
  }
901
901
 
902
- export async function userZoneAuditHistory( req, res ) {
902
+ export async function storeMetrics( req, res ) {
903
903
  try {
904
904
  const inputData = req.body;
905
- const userId = inputData.userId || req.user._id;
906
905
  const limit = inputData.limit || 10;
907
906
  const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
908
907
  const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
909
908
  let filter = [
910
-
911
- { userId: { $eq: userId } },
912
- { moduleType: 'zone' },
913
-
909
+ { fileDateISO: { $gte: dateRange.start } },
910
+ { fileDateISO: { $lte: dateRange.end } },
914
911
  ];
915
- if ( inputData.fileType == 'fileDate' ) {
916
- filter.push(
917
- { fileDateISO: { $gte: dateRange.start } },
918
- { fileDateISO: { $lte: dateRange.end } },
919
- );
920
- } else {
921
- filter.push(
922
- { createdAt: { $gte: dateRange.start } },
923
- { createdAt: { $lte: dateRange.end } },
924
- );
912
+ if ( inputData.filterByClientId && inputData.filterByClientId?.length > 0 ) {
913
+ filter.push( { clientId: { $in: inputData.filterByClientId } } );
925
914
  }
926
- if ( inputData.filterByStoreId?.length > 0 ) {
927
- filter.push( {
928
- storeId: { $in: inputData.filterByStoreId },
929
- } );
915
+
916
+ if ( inputData.filterByStoreId && inputData.filterByStoreId?.length > 0 ) {
917
+ filter.push( { storeId: { $in: inputData.filterByStoreId } } );
930
918
  }
931
919
 
932
- if ( inputData.filterByStatus?.length > 0 ) {
933
- filter.push( {
934
- auditStatus: { $in: inputData.filterByStatus },
935
- } );
920
+ if ( inputData.filterByStatus && inputData.filterByStatus?.length > 0 ) {
921
+ filter.push( { status: { $in: inputData.filterByStatus } } );
936
922
  }
937
923
 
938
924
  const query = [
@@ -941,129 +927,186 @@ export async function userZoneAuditHistory( req, res ) {
941
927
  $and: filter,
942
928
  },
943
929
  },
944
- ];
945
-
946
- if ( inputData.searchValue && inputData.searchValue!== '' ) {
947
- query.push( {
948
- $match: {
949
- $or: [
950
- { clientId: { $regex: inputData.searchValue, $options: 'i' } },
951
- { clientName: { $regex: inputData.searchValue, $options: 'i' } },
930
+ {
931
+ $lookup: {
932
+ from: 'stores',
933
+ let: { storeId: '$storeId' },
934
+ pipeline: [
935
+ {
936
+ $match: {
937
+ $expr: {
938
+ $eq: [ '$storeId', '$$storeId' ],
939
+ },
940
+ },
941
+ },
942
+ {
943
+ $project: {
944
+ storeName: 1,
945
+ },
946
+ },
947
+ ], as: 'store',
948
+ },
949
+ },
950
+ {
951
+ $unwind: {
952
+ path: '$store', preserveNullAndEmptyArrays: true,
953
+ },
954
+ },
955
+ {
956
+ $project: {
957
+ _id: 0,
958
+ fileDate: 1,
959
+ storeId: 1,
960
+ storeName: '$store.storeName',
961
+ userId: {
962
+ $arrayElemAt: [ '$userId', { $subtract: [ { $size: '$userId' }, 1 ] } ],
963
+ },
964
+ clientId: 1,
965
+ auditType: 1,
966
+ beforeCount: 1,
967
+ afterCount: { $ifNull: [ '$afterCount', null ] },
968
+ accuracy: { $round: [
969
+ { $divide: [
970
+ { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
971
+ ] }, 2,
952
972
  ],
953
973
 
974
+ },
975
+ timeSpent: 1,
976
+ status: 1,
954
977
  },
955
- } );
956
- }
957
- if ( inputData.sortColumnName ) {
958
- const sortBy = inputData.sortBy || -1;
959
- query.push( {
960
- $sort: { [inputData.sortColumName]: sortBy },
961
978
  },
962
- );
963
- }
964
-
965
- query.push( {
966
- $lookup: {
967
- from: 'stores',
968
- let: { storeId: '$storeId' },
969
- pipeline: [
970
- {
971
- $match: {
972
- $expr: {
973
- $eq: [ '$storeId', '$$storeId' ],
979
+ {
980
+ $lookup: {
981
+ from: 'stores',
982
+ let: { storeId: '$storeId' },
983
+ pipeline: [
984
+ {
985
+ $match: {
986
+ $expr: {
987
+ $eq: [ '$storeId', '$$storeId' ],
988
+ },
974
989
  },
975
990
  },
976
- },
977
- {
978
- $project: {
979
- storeName: 1,
991
+ {
992
+ $project: {
993
+ _id: 0,
994
+ storeName: 1,
995
+ },
980
996
  },
981
- },
982
- ], as: 'store',
997
+ ], as: 'stores',
998
+ },
983
999
  },
984
-
985
- } );
986
-
987
- query.push( {
988
- $unwind: {
989
- path: '$store', preserveNullAndEmptyArrays: true,
1000
+ {
1001
+ $unwind: {
1002
+ path: '$stores',
1003
+ preserveNullAndEmptyArrays: true,
1004
+ },
990
1005
  },
991
- } );
992
-
1006
+ {
1007
+ $lookup: {
1008
+ from: 'users',
1009
+ let: { userId: '$userId' },
1010
+ pipeline: [
1011
+ {
1012
+ $match: {
1013
+ $expr: {
1014
+ $eq: [ '$_id', '$$userId' ],
1015
+ },
1016
+ },
1017
+ },
1018
+ {
1019
+ $project: {
1020
+ _id: 0,
1021
+ userName: 1,
1022
+ userEmail: '$email',
1023
+ },
1024
+ },
1025
+ ], as: 'users',
1026
+ },
1027
+ },
1028
+ {
1029
+ $unwind: {
1030
+ path: '$users',
1031
+ preserveNullAndEmptyArrays: true,
1032
+ },
1033
+ },
1034
+ {
1035
+ $project: {
1036
+ _id: 0,
1037
+ fileDate: 1,
1038
+ storeId: 1,
1039
+ storeName: '$stores.storeName',
1040
+ userName: '$users.userName',
1041
+ userEmail: '$users.userEmail',
993
1042
 
994
- query.push( {
1043
+ clientId: 1,
1044
+ auditType: 1,
1045
+ beforeCount: 1,
1046
+ afterCount: { $ifNull: [ '$afterCount', null ] },
1047
+ accuracy: { $round: [
1048
+ { $divide: [
1049
+ { $multiply: [ { $ifNull: [ '$afterCount', 0 ] }, '$beforeCount' ] }, 100,
1050
+ ] }, 2,
1051
+ ],
995
1052
 
996
- $project: {
997
- storeId: 1,
998
- userId: 1,
999
- storeName: '$store.storeName',
1000
- zoneName: 1,
1001
- auditType: 1,
1002
- beforeCount: 1,
1003
- afterCount: 1,
1004
- accuracy: { $round: [
1005
- {
1006
- $divide: [ { $multiply: [ '$beforeCount', { $ifNull: [ '$afterCount', 0 ] } ] }, 100 ],
1007
- }, 2,
1008
- ],
1053
+ },
1054
+ timeSpent: 1,
1055
+ status: 1,
1009
1056
  },
1010
- startTime: 1,
1011
- endTime: 1,
1012
- timeSpent: { $round: [
1013
- { $divide: [ '$timeSpent', 60 ] }, 2,
1014
- ] },
1015
- auditStatus: 1,
1016
- createdAt: 1,
1017
1057
  },
1018
1058
 
1019
- } );
1059
+ ];
1020
1060
 
1021
- const count = await aggregateUserAudit( query );
1022
- if ( count.length == 0 ) {
1023
- return res.sendError( 'No Data Found', 204 );
1061
+ if ( inputData.searchValue && inputData.searchValue !== '' ) {
1062
+ query.push( {
1063
+ $match: {
1064
+ $or: [
1065
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1066
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1067
+ ],
1068
+ },
1069
+ } );
1024
1070
  }
1071
+ const count = await aggregateStoreZoneAudit( query );
1025
1072
 
1073
+ if ( count.length == 0 ) {
1074
+ return res.sendError( 'No data Found', 204 );
1075
+ }
1076
+ if ( !inputData.isExport ) {
1077
+ query.push( {
1078
+ $skip: offset,
1079
+ },
1080
+ {
1081
+ $limit: limit,
1082
+ } );
1083
+ } else {
1084
+ query.push( { $limit: 10000 } );
1085
+ }
1086
+ const result = await aggregateStoreZoneAudit( query );
1026
1087
  if ( inputData.isExport ) {
1027
- const chunkedMappingData = await chunkArray( count, 10 );
1028
- const promises = chunkedMappingData.map( async ( chunk ) => {
1029
- const exportData = [];
1030
- chunk.forEach( ( element ) => {
1031
- exportData.push( {
1032
- 'storeId': element.storeId,
1033
- 'storeName': element.storeName,
1034
- 'auditType': element.auditType,
1035
- 'beforeCount': element.beforeCount,
1036
- 'afterCount': element.afterCount,
1037
- 'accuracy': element.accuracy,
1038
- 'startTime': element.startTime,
1039
- 'endTime': element.endTime,
1040
- 'timeSpent': element.timeSpent,
1041
- 'auditStatus': element.auditStatus,
1042
- 'createdAt': element.createdAt,
1043
-
1044
- } );
1088
+ const exportdata = [];
1089
+ result.forEach( ( element ) => {
1090
+ exportdata.push( {
1091
+ 'File Date': element.fileDate,
1092
+ 'Store Id': element.storeId,
1093
+ 'Store Name': element.storeName,
1094
+ 'Client Id': element.clientId,
1095
+ 'User Name': element.userName,
1096
+ 'User Email': element.userEmail,
1097
+ 'Audit Type': element.auditType,
1098
+ 'Accuracy': element.accuracy,
1099
+ 'Time Spent': element.timeSpent,
1100
+ 'Status': element.status,
1045
1101
  } );
1046
- return exportData;
1047
1102
  } );
1048
- const mappedArrays = await Promise.all( promises );
1049
- mappedArrays.flat();
1050
-
1051
- await download( mappedArrays, res );
1103
+ await download( exportdata, res );
1052
1104
  return;
1053
1105
  }
1054
-
1055
- query.push( {
1056
- $skip: offset,
1057
- },
1058
- {
1059
- $limit: limit,
1060
- } );
1061
- const result = await aggregateUserAudit( query );
1062
-
1063
- return res.sendSuccess( { result: result } );
1106
+ return res.sendSuccess( { result: result, count: count.length } );
1064
1107
  } catch ( error ) {
1065
1108
  const err = error.message || 'Internal Server Error';
1066
- logger.info( { error: error, message: req.body, function: 'userZoneAuditHistory' } );
1109
+ logger.error( { error: error, data: req.body, function: 'storeMetrics' } );
1067
1110
  return res.sendError( err, 500 );
1068
1111
  }
1069
1112
  }
@@ -1,5 +1,5 @@
1
1
  import j2s from 'joi-to-swagger';
2
- import { getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, workSpaceSchema } from '../dtos/zoneAudit.dtos.js';
2
+ import { 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': {
@@ -155,4 +155,28 @@ export const zoneAuditDocs = {
155
155
  },
156
156
  },
157
157
 
158
+ // metrics
159
+ '/v3/zone-audit/metrics/store-metrics': {
160
+ post: {
161
+ tags: [ 'Zone Audit Metrics' ],
162
+ description: `Get store level zone metrics`,
163
+ operationId: 'save',
164
+ parameters: {},
165
+ requestBody: {
166
+ content: {
167
+ 'application/json': {
168
+ schema: j2s( storeMetricsSchema ).swagger,
169
+ },
170
+ },
171
+ },
172
+ responses: {
173
+ 200: { description: 'Successful' },
174
+ 401: { description: 'Unauthorized User' },
175
+ 422: { description: 'Field Error' },
176
+ 500: { description: 'Server Error' },
177
+ 204: { description: 'Not Found' },
178
+ },
179
+ },
180
+ },
181
+
158
182
  };
@@ -21,6 +21,7 @@ export const userAuditHistorySchema = joi.object(
21
21
  fileType: joi.string().required(),
22
22
  filterByStoreId: joi.array().required(),
23
23
  filterByType: joi.array().optional(),
24
+ filterByAuditType: joi.array().optional(),
24
25
  filterByStatus: joi.array().optional(),
25
26
  searchValue: joi.string().optional().allow( '' ),
26
27
  limit: joi.number().optional(),
@@ -61,6 +62,7 @@ export const clientMetricsSchema = joi.object(
61
62
  {
62
63
  fromDate: joi.string().required(),
63
64
  toDate: joi.string().required(),
65
+ filterByAuditType: joi.array().optional(),
64
66
  searchValue: joi.string().optional().allow( '' ),
65
67
  filterByClient: joi.array().required(),
66
68
  filterByStatus: joi.array().optional(),
@@ -83,6 +85,7 @@ export const userMetricsSchema = joi.object(
83
85
  fileType: joi.string().required(),
84
86
  searchValue: joi.string().optional().allow( '' ),
85
87
  filterByUser: joi.array().optional(),
88
+ filterByAuditType: joi.array().optional(),
86
89
  filterByStatus: joi.array().optional(),
87
90
  sortColumnName: joi.string().optional(),
88
91
  sortBy: joi.number().optional(),
@@ -145,6 +148,7 @@ export const overAllAuditSummarySchema = joi.object(
145
148
  fromDate: joi.string().required(),
146
149
  toDate: joi.string().required(),
147
150
  clientId: joi.array().optional(),
151
+ moduleType: joi.string().required(),
148
152
  },
149
153
  );
150
154
 
@@ -87,3 +87,24 @@ export const workSpaceValid = {
87
87
  query: workSpaceSchema,
88
88
  };
89
89
 
90
+ export const storeMetricsSchema = joi.object(
91
+ {
92
+ fromDate: joi.string().required(),
93
+ toDate: joi.string().required(),
94
+ searchValue: joi.string().optional().allow( '' ),
95
+ filterByClientId: joi.array().required(),
96
+ filterByStoreId: joi.array().optional(),
97
+ filterByStatus: joi.array().optional(),
98
+ filterByType: joi.array().optional(),
99
+ sortColumnName: joi.string().optional(),
100
+ sortBy: joi.number().optional(),
101
+ limit: joi.number().optional(),
102
+ offset: joi.number().optional(),
103
+ isExport: joi.boolean().optional(),
104
+ },
105
+ );
106
+
107
+ export const storeMetricsValid = {
108
+ body: storeMetricsSchema,
109
+ };
110
+
@@ -2,7 +2,8 @@ import { Router } from 'express';
2
2
  import { getDraftedDataValid, getFileValid, saveDraftValid, saveValid, 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, workSpace } from '../controllers/zoneAudit.controller.js';
5
+ import { getDraftedData, getZoneAuditFile, save, saveDraft, storeMetrics, workSpace } from '../controllers/zoneAudit.controller.js';
6
+ import { storeMetricsValid } from '../dtos/auditMetrics.dtos.js';
6
7
 
7
8
  export const zoneAuditRouter=Router();
8
9
 
@@ -12,3 +13,7 @@ zoneAuditRouter.post( '/save-draft', isAllowedSessionHandler, validate( saveDraf
12
13
  zoneAuditRouter.get( '/get-drafted-data', isAllowedSessionHandler, validate( getDraftedDataValid ), getDraftedData );
13
14
  zoneAuditRouter.post( '/save', isAllowedSessionHandler, validate( saveValid ), validateUserAudit, save );
14
15
  zoneAuditRouter.get( '/work-space', isAllowedSessionHandler, validate( workSpaceValid ), workSpace );
16
+
17
+ // metrics
18
+
19
+ zoneAuditRouter.post( '/metrics/store-metrics', isAllowedSessionHandler, validate( storeMetricsValid ), storeMetrics );