tango-app-api-audit 3.4.0-alpha.0 → 3.4.0-alpha.10

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.
@@ -1,7 +1,16 @@
1
- import { checkFileExist, getDate, insertOpenSearchData, listFileByPath, logger, signedUrl, sqsReceive } from 'tango-app-api-middleware';
2
- import { aggregateBinaryAuditModel, createBinaryAudit } from '../service/binaryAudit.service.js';
3
- import { findOneStore } from '../service/store.service.js';
1
+ import { checkFileExist, download, getDate, getDateWithCustomizeTime, getUTC, insertOpenSearchData, listFileByPath, logger, signedUrl, sqsReceive } from 'tango-app-api-middleware';
2
+ import { aggregateBinaryAudit, createBinaryAudit, updateOneBinaryAuditModel } from '../service/binaryAudit.service.js';
3
+ import { countDocumentsStore, findOneStore } from '../service/store.service.js';
4
4
  import { findOneUser } from '../service/user.service.js';
5
+ import { aggregateUserEmpDetection, createUserEmpDetection } from '../service/userEmpDetection.service.js';
6
+ import { aggregateTraxAuditData, findOneTraxAuditData } from '../service/traxAuditData.service.js';
7
+ import { aggregateClient } from '../service/client.service.js';
8
+ import dayjs from 'dayjs';
9
+ import { aggregateAssignAudit } from '../service/assignAudit.service.js';
10
+ import { aggregateStoreEmpDetection } from '../service/storeEmpDetection.service.js';
11
+ import { listQueue } from 'tango-app-api-middleware/src/utils/aws/sqs.js';
12
+ import _ from 'lodash';
13
+ import mongoose from 'mongoose';
5
14
 
6
15
 
7
16
  export async function getDetectionAuditFile( req, res ) {
@@ -37,7 +46,7 @@ export async function getDetectionAuditFile( req, res ) {
37
46
  },
38
47
  ];
39
48
 
40
- const userDetails = await aggregateUserAudit( userQuery );
49
+ const userDetails = await aggregateUserEmpDetection( userQuery );
41
50
  logger.info( { userDetails: userDetails, function: 'userDetails' } );
42
51
  const auditStatus =
43
52
  userDetails && userDetails.length > 0 ? userDetails[0].auditStatus : null;
@@ -380,7 +389,7 @@ export async function getDetectionAuditFile( req, res ) {
380
389
  moduleType: inputData.moduleType,
381
390
  };
382
391
 
383
- insertData = await createUserAudit( record );
392
+ insertData = await createUserEmpDetection( record );
384
393
  await updateManyStoreAudit( query, storeRecord );
385
394
  } else {
386
395
  insertData = userDetails[0];
@@ -451,6 +460,403 @@ export async function getDetectionAuditFile( req, res ) {
451
460
  }
452
461
  }
453
462
 
463
+ export async function workSpace( req, res ) {
464
+ try {
465
+ const inputData = req.body;
466
+ const limit = inputData.limit || 10;
467
+ const offset = inputData.offset ?
468
+ ( inputData.offset - 1 ) * limit :
469
+ 0;
470
+ const dateRange = await getDate( new Date(), new Date() );
471
+ const filter =[
472
+ { status: { $in: [ 'active', 'hold' ] } },
473
+ { 'auditConfigs.audit': { $eq: true } },
474
+ ];
475
+ if ( inputData?.clientId?.length > 0 ) {
476
+ filter.push( { clientId: { $in: inputData.clientId } } );
477
+ }
478
+ const temp = [];
479
+ const clientQuery = [
480
+ {
481
+ $match: {
482
+ $and: filter,
483
+ },
484
+ },
485
+ {
486
+ $project: {
487
+ clientName: 1,
488
+ clientId: 1,
489
+ queueName: {
490
+ $cond: [
491
+ { $eq: [ inputData.moduleType, 'unattended-customer' ] }, '$auditConfigs.traxQueueName.unattendedCustomer',
492
+ { $cond: [
493
+ { $eq: [ inputData.moduleType, 'left-in-middle' ] }, '$auditConfigs.traxQueueName.leftInMiddle',
494
+ {
495
+ $cond: [
496
+ { $eq: [ inputData.moduleType, 'uniform-detection' ] }, '$auditConfigs.traxQueueName.uniformDetection',
497
+ {
498
+ $cond: [
499
+ { $eq: [ inputData.moduleType, 'mobile-detection' ] }, '$auditConfigs.traxQueueName.mobileDetection', '$auditConfigs.traxQueueName.cameraAngleChange',
500
+ ],
501
+ },
502
+ ],
503
+ },
504
+ ],
505
+ },
506
+ ],
507
+ },
508
+ },
509
+ },
510
+ ];
511
+
512
+
513
+ if ( inputData.searchValue && inputData.searchValue !== '' ) {
514
+ clientQuery.push( {
515
+ $match: {
516
+ $or: [
517
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
518
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
519
+ ],
520
+ },
521
+ } );
522
+ }
523
+ if ( inputData.sortColumnName ) {
524
+ const sortBy = inputData.sortBy || -1;
525
+ const sortColumn = inputData.sortColumnName;
526
+ clientQuery.push( {
527
+ $sort: { [sortColumn]: sortBy },
528
+ },
529
+ );
530
+ }
531
+
532
+ const count = await aggregateClient( clientQuery );
533
+ if ( count?.length == 0 ) {
534
+ return res.sendError( 'No Data Found', 204 );
535
+ }
536
+
537
+ if ( !inputData.isExport ) {
538
+ clientQuery.push( { $skip: offset }, { $limit: limit } );
539
+ }
540
+
541
+ const clientDetails = await aggregateClient( clientQuery );
542
+ const clientList = clientDetails.map( ( i ) => i.clientId );
543
+ const fileDate = dayjs( dateRange.start ).subtract( 1, 'days' );
544
+ const getStoreData = await findOneTraxAuditData(
545
+ {},
546
+ { fileDate: 1 },
547
+ { createdAt: -1 },
548
+ );
549
+ const latestDate = getStoreData?.fileDate || dayjs( fileDate ).format( 'DD-MM-YYYY' );
550
+ const auditStoreDataQuery = [
551
+ {
552
+ $match: {
553
+ clientId: { $in: clientList },
554
+ moduleType: { $eq: inputData.moduleType },
555
+ fileDate: { $eq: latestDate },
556
+ },
557
+ },
558
+ {
559
+ $group: {
560
+ _id: '$clientId',
561
+ clientId: { $last: '$clientId' },
562
+ clientName: { $last: '$clientName' },
563
+ installedStore: { $last: '$installedStore' },
564
+ // queueName: { $last: '$queueName' },
565
+ totalCount: { $sum: 1 },
566
+ },
567
+ },
568
+ {
569
+ $project: {
570
+ _id: 0,
571
+ clientId: 1,
572
+ clientName: 1,
573
+ installedStore: 1,
574
+ queueName: 1,
575
+ totalCount: 1,
576
+ },
577
+ },
578
+ ];
579
+
580
+ const completedStores = [
581
+ {
582
+ $match: {
583
+ $and: [
584
+ { clientId: { $in: clientList } },
585
+ { fileDate: { $eq: latestDate } },
586
+ { moduleType: { $eq: inputData.moduleType } },
587
+ ],
588
+ },
589
+ },
590
+ {
591
+ $project: {
592
+ clientId: 1,
593
+ completed: {
594
+ $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ],
595
+ },
596
+ },
597
+ },
598
+ // {
599
+ // $group: {
600
+ // _id: { clientId: '$clientId', storeId: '$storeId' },
601
+ // clientId: { $first: '$clientId' },
602
+ // completedStoresCount: { $sum: '$completed' },
603
+ // },
604
+ // },
605
+ {
606
+ $group: {
607
+ _id: '$clientId',
608
+ clientId: { $first: '$clientId' },
609
+ // completedStoresCount: { $first: '$completedStoresCount' },
610
+ completedStoresCount: { $sum: '$completed' },
611
+ },
612
+ },
613
+ {
614
+ $project: {
615
+ _id: 0,
616
+ clientId: 1,
617
+ completedStoresCount: 1,
618
+ },
619
+ },
620
+ ];
621
+
622
+ const auditFiles = [
623
+ {
624
+ $match: {
625
+ $and: [
626
+ { clientId: { $in: clientList } },
627
+ { createdAt: { $gte: dateRange.start } },
628
+ { createdAt: { $lte: dateRange.end } },
629
+ { moduleType: { $eq: inputData.moduleType } },
630
+ ],
631
+ },
632
+ },
633
+ {
634
+ $project: {
635
+ clientId: 1,
636
+ pending: {
637
+ $cond: [
638
+ { $or: [ { $in: [ '$auditStatus', [ 'inprogress', 'drafted' ] ] } ] },
639
+ 1,
640
+ 0,
641
+ ],
642
+ },
643
+ },
644
+ },
645
+ {
646
+ $group: {
647
+ _id: { clientId: '$clientId', storeId: '$storeId' },
648
+ clientId: { $first: '$clientId' },
649
+ pendingCount: { $sum: '$pending' },
650
+ totalFilesCount: { $sum: 1 },
651
+ },
652
+ },
653
+ {
654
+ $group: {
655
+ _id: '$clientId',
656
+ clientId: { $first: '$clientId' },
657
+ pendingCount: { $first: { $ifNull: [ '$pendingCount', 0 ] } },
658
+ totalFilesCount: { $first: '$totalFilesCount' },
659
+ },
660
+ },
661
+ ];
662
+ const userIncompleteFiles = [
663
+ {
664
+ $match: {
665
+ $and: [
666
+ { clientId: { $in: clientList } },
667
+ { userId: { $eq: req.user._id } },
668
+ { moduleType: { $eq: inputData.moduleType } },
669
+ { createdAt: { $gte: dateRange.start } },
670
+ { createdAt: { $lte: dateRange.end } },
671
+ ],
672
+ },
673
+ },
674
+ {
675
+ $sort: {
676
+ updatedAt: -1,
677
+ },
678
+ },
679
+ {
680
+ $project: {
681
+ clientId: 1,
682
+ isDraft: 1,
683
+ draft: {
684
+ $cond: [ { $eq: [ '$auditStatus', 'drafted' ] }, 1, 0 ],
685
+ },
686
+ inprogress: {
687
+ $cond: [ { $eq: [ '$auditStatus', 'inprogress' ] }, 1, 0 ],
688
+ },
689
+ },
690
+ },
691
+ {
692
+ $group: {
693
+ _id: '$clientId',
694
+ clientId: { $first: '$clientId' },
695
+ isDrafted: { $first: '$isDraft' },
696
+ userDraftCount: { $sum: '$draft' },
697
+ userInprogressCount: { $sum: '$inprogress' },
698
+ },
699
+ },
700
+ ];
701
+
702
+ const userAsignAudit = [
703
+ {
704
+ $match: {
705
+ $and: [
706
+ { userId: { $eq: req.user._id } },
707
+ { isCompleted: false },
708
+ { clientId: { $in: clientList } },
709
+ { moduleType: { $eq: inputData.moduleType } },
710
+ ],
711
+ },
712
+ },
713
+ {
714
+ $group: {
715
+ _id: '$clientId',
716
+ clientId: { $first: '$clientId' },
717
+ userAsignedCount: { $sum: 1 },
718
+ },
719
+ },
720
+ {
721
+ $project: {
722
+ _id: 0,
723
+ clientId: 1,
724
+ userAsignedCount: 1,
725
+ },
726
+ },
727
+ ];
728
+
729
+ const clientAssign = [
730
+ {
731
+ $match: {
732
+ $and: [ { isCompleted: false },
733
+ { clientId: { $in: clientList } },
734
+ { moduleType: { $eq: inputData.moduleType } },
735
+ ],
736
+ },
737
+ },
738
+ {
739
+ $group: {
740
+ _id: '$clientId',
741
+ clientId: { $first: '$clientId' },
742
+ clientAsignedCount: { $sum: 1 },
743
+ },
744
+ },
745
+ {
746
+ $project: {
747
+ _id: 0,
748
+ clientId: 1,
749
+ clientAsignedCount: { $ifNull: [ '$clientAsignedCount', 0 ] },
750
+ },
751
+ },
752
+ ];
753
+
754
+ const auditUserCount = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( auditFiles ) : await aggregateBinaryAudit( auditFiles );
755
+ const userIncompleteFilesCount = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( userIncompleteFiles ) : await aggregateBinaryAudit( userIncompleteFiles );
756
+ const userAsignAuditCount = await aggregateAssignAudit( userAsignAudit );
757
+ const completedStoresCount = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateStoreEmpDetection( completedStores ) : await aggregateBinaryAudit( completedStores );
758
+ const clientAssignedCount = await aggregateAssignAudit( clientAssign );
759
+ const auditStoreData = await aggregateTraxAuditData(
760
+ auditStoreDataQuery,
761
+ );
762
+
763
+ const mergeAll = _.merge(
764
+ _.keyBy( clientDetails, 'clientId' ),
765
+ _.keyBy( auditUserCount, 'clientId' ),
766
+ _.keyBy( userIncompleteFilesCount, 'clientId' ),
767
+ _.keyBy( clientAssignedCount, 'clientId' ),
768
+ );
769
+ const finalResult = _.values( mergeAll );
770
+ const merge = _.values(
771
+ _.merge(
772
+ _.keyBy( finalResult, 'clientId' ),
773
+ _.keyBy( auditStoreData, 'clientId' ),
774
+ _.keyBy( userAsignAuditCount, 'clientId' ),
775
+ _.keyBy( completedStoresCount, 'clientId' ),
776
+ ),
777
+ );
778
+ let totalStores = 0;
779
+ for ( let i = 0; i < merge.length; i++ ) {
780
+ totalStores = merge[i]?.totalCount || 0;
781
+
782
+ const pending = await listQueue( merge[i].queueName );
783
+
784
+ if ( !pending.statusCode ) {
785
+ temp.push( {
786
+ clientId: merge[i].clientId,
787
+ clientName: merge[i].clientName,
788
+ completedStoresCount: merge[i].completedStoresCount ?
789
+ Number( merge[i].completedStoresCount ) :
790
+ 0,
791
+ pendingByQueue: Number( pending ),
792
+ pendingByUser:
793
+ merge[i].pendingCount >= 0 ?
794
+ Number( merge[i].pendingCount ) +
795
+ ( merge[i].clientAsignedCount ?
796
+ Number( merge[i].clientAsignedCount ) :
797
+ 0 ) :
798
+ 0,
799
+ totalCount: merge[i].totalCount,
800
+ queueName: merge[i].queueName,
801
+ isDraft: merge[i]?.isDrafted || false,
802
+ isEnable:
803
+ Number( pending ) > 0 ||
804
+ merge[i].isDrafted ||
805
+ ( merge[i].userAsignedCount && merge[i].userAsignedCount > 0 ) ||
806
+ ( merge[i].userInprogressCount && merge[i].userInprogressCount > 0 ) ?
807
+ 1 :
808
+ 0,
809
+ completedRatio: merge[i].totalCount ?
810
+ merge[i].completedStoresCount ?
811
+ Math.round(
812
+ ( Number( merge[i].completedStoresCount ) /
813
+ Number( merge[i].totalCount ) ) *
814
+ 100,
815
+ ) :
816
+ 0 :
817
+ 0,
818
+ isAssigned:
819
+ merge[i].userAsignedCount && merge[i].userAsignedCount > 0 ?
820
+ true :
821
+ false,
822
+ Assignedcount:
823
+ merge[i].userAsignedCount && merge[i].userAsignedCount > 0 ?
824
+ merge[i].userAsignedCount :
825
+ 0,
826
+ } );
827
+ }
828
+ }
829
+
830
+ if ( inputData.isExport ) {
831
+ const exportdata = [];
832
+ temp.forEach( ( element ) => {
833
+ exportdata.push( {
834
+ 'Client Name': element.clientName,
835
+ 'Client Id': element.clientId,
836
+ 'Completed stores Count': element.completedStoresCount,
837
+ 'Completed Percentage': element.completedRatio + ' %',
838
+ 'Pending Queue': element.pendingByQueue,
839
+ 'Pending User': element.pendingByUser,
840
+ 'Draft': element.isDraft ? 1 : 0,
841
+ 'Assigned': element.Assignedcount,
842
+ } );
843
+ } );
844
+ await download( exportdata, res );
845
+ return;
846
+ } else {
847
+ return res.sendSuccess( {
848
+ result: temp,
849
+ count: count.length,
850
+ totalStores: totalStores,
851
+ } );
852
+ }
853
+ } catch ( error ) {
854
+ const err = error.message || 'Internal Server Error';
855
+ logger.info( { error: error, message: req.query, function: 'workSpace' } );
856
+ return res.sendError( err, 500 );
857
+ }
858
+ }
859
+
454
860
  export async function getAuditFile( req, res ) {
455
861
  try {
456
862
  const inputData = req.query;
@@ -480,7 +886,7 @@ export async function getAuditFile( req, res ) {
480
886
  },
481
887
  ];
482
888
 
483
- const userDetails = await aggregateBinaryAuditModel( userQuery );
889
+ const userDetails = await aggregateBinaryAudit( userQuery );
484
890
  logger.info( { userDetails: userDetails, function: 'userDetails' } );
485
891
  const auditStatus = userDetails && userDetails.length > 0 ? userDetails[0].auditStatus : null;
486
892
 
@@ -666,6 +1072,7 @@ export async function getAuditFile( req, res ) {
666
1072
  fileDate: msg.fileDate,
667
1073
  queueName: inputData.queueName,
668
1074
  auditStatus: 'inprogress',
1075
+ auditType: 'Audit',
669
1076
  fileDateISO: start,
670
1077
  timeSpent: 0,
671
1078
  startTime: new Date(),
@@ -728,6 +1135,7 @@ export async function getAuditFile( req, res ) {
728
1135
  question: msg.question,
729
1136
  questionType: msg.questionType,
730
1137
  streamName: msg.streamName,
1138
+ auditId: insertData._id,
731
1139
  } );
732
1140
  } catch ( error ) {
733
1141
  const err = error.message || 'Internal Server Error';
@@ -735,3 +1143,1878 @@ export async function getAuditFile( req, res ) {
735
1143
  return res.sendError( err, 500 );
736
1144
  }
737
1145
  }
1146
+
1147
+ export async function saveBinary( req, res ) {
1148
+ try {
1149
+ const inputData = req.body;
1150
+ const isoDate = req.userAudit?.startTime;
1151
+ const currentTime = dayjs();
1152
+ const isoDateTime = dayjs( isoDate );
1153
+ const timeDifferenceInMinutes = currentTime.diff( isoDateTime, 'seconds' );
1154
+ switch ( inputData.moduleType ) {
1155
+ case 'unattended-customer':
1156
+ let unattendedquery ={
1157
+ _id: inputData.auditId,
1158
+ storeId: inputData.storeId,
1159
+ fileDate: inputData.fileDate,
1160
+ tempId: inputData.tempId,
1161
+ moduleType: inputData.moduleType,
1162
+ };
1163
+
1164
+ let update={
1165
+ auditStatus: 'completed',
1166
+ answer: inputData.answer,
1167
+ userComments: inputData.userComments || '',
1168
+ endTime: new Date(),
1169
+ timeSpent: timeDifferenceInMinutes,
1170
+ };
1171
+ let updatDataunattended= await updateOneBinaryAuditModel( unattendedquery, update );
1172
+ if ( updatDataunattended.modifiedCount==0 ) {
1173
+ return res.sendError( updatDataunattended, 204 );
1174
+ }
1175
+ logger.info( 'update in binary data', { query: unattendedquery, update: update } );
1176
+ res.sendSuccess( `Successfully update in ${inputData.moduleType} ` );
1177
+
1178
+ break;
1179
+
1180
+ case 'left-in-middle':
1181
+ let leftquery ={
1182
+ _id: inputData.auditId,
1183
+ storeId: inputData.storeId,
1184
+ fileDate: inputData.fileDate,
1185
+ question: inputData.question,
1186
+ moduleType: inputData.moduleType,
1187
+ };
1188
+ let leftupdate={
1189
+ auditStatus: 'completed',
1190
+ answer: inputData.answer,
1191
+ userComments: inputData.userComments || '',
1192
+ endTime: new Date(),
1193
+ timeSpent: timeDifferenceInMinutes,
1194
+ };
1195
+ let updatDataleft= await updateOneBinaryAuditModel( leftquery, leftupdate );
1196
+ if ( updatDataleft.modifiedCount==0 ) {
1197
+ return res.sendError( updatDataleft, 204 );
1198
+ }
1199
+ logger.info( 'update in binary data', { query: leftquery, update: leftupdate } );
1200
+ res.sendSuccess( `Successfully update in ${inputData.moduleType} ` );
1201
+
1202
+ break;
1203
+
1204
+ case 'camera-angle-change':
1205
+ let cameraquery ={
1206
+ _id: inputData.auditId,
1207
+ storeId: inputData.storeId,
1208
+ fileDate: inputData.fileDate,
1209
+ streamName: inputData.streamName,
1210
+ moduleType: inputData.moduleType,
1211
+ };
1212
+ let cameraupdate={
1213
+ auditStatus: 'completed',
1214
+ answer: inputData.answer,
1215
+ userComments: inputData.userComments || '',
1216
+ endTime: new Date(),
1217
+ timeSpent: timeDifferenceInMinutes,
1218
+ };
1219
+ let updatDatacamera= await updateOneBinaryAuditModel( cameraquery, cameraupdate );
1220
+ if ( updatDatacamera.modifiedCount==0 ) {
1221
+ return res.sendError( updatDatacamera, 204 );
1222
+ }
1223
+ logger.info( 'update in binary data', { query: cameraquery, update: cameraupdate } );
1224
+ res.sendSuccess( `Successfully update in ${inputData.moduleType} ` );
1225
+
1226
+ break;
1227
+
1228
+ default:
1229
+ res.sendError( 'no data', 204 );
1230
+ break
1231
+ ;
1232
+ }
1233
+ } catch ( error ) {
1234
+ const err = error.mesage || 'Internal Server Error';
1235
+ logger.error( { error: error, data: req.body, function: 'saveBinary' } );
1236
+ return res.sendError( err, 500 );
1237
+ }
1238
+ }
1239
+
1240
+ export async function userAuditHistory( req, res ) {
1241
+ try {
1242
+ const inputData = req.body;
1243
+ const userId = inputData.userId? new mongoose.Types.ObjectId( inputData.userId ) : req.user._id;
1244
+ const limit = inputData.limit || 10;
1245
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
1246
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1247
+ const dateRangeCreatedAt = await getDateWithCustomizeTime( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1248
+ let filter = [
1249
+ { userId: { $eq: userId } },
1250
+ { moduleType: { $eq: inputData.moduleType } },
1251
+ ];
1252
+
1253
+ if ( inputData.dateType == 'fileDate' ) {
1254
+ filter.push(
1255
+ { fileDateISO: { $gte: dateRange.start } },
1256
+ { fileDateISO: { $lte: dateRange.end } },
1257
+ );
1258
+ } else {
1259
+ filter.push(
1260
+ { createdAt: { $gte: dateRangeCreatedAt.start } },
1261
+ { createdAt: { $lte: dateRangeCreatedAt.end } },
1262
+ );
1263
+ }
1264
+
1265
+
1266
+ if ( inputData.filterByAuditType?.length > 0 ) {
1267
+ filter.push( {
1268
+ auditType: { $in: inputData.filterByAuditType },
1269
+ } );
1270
+ }
1271
+
1272
+ if ( inputData.filterByStoreId?.length > 0 ) {
1273
+ filter.push( {
1274
+ storeId: { $in: inputData.filterByStoreId },
1275
+ } );
1276
+ }
1277
+
1278
+ if ( inputData.filterByStatus?.length > 0 ) {
1279
+ filter.push( {
1280
+ auditStatus: { $in: inputData.filterByStatus },
1281
+ } );
1282
+ }
1283
+ if ( inputData?.clientId?.length > 0 ) {
1284
+ filter.push( { clientId: { $in: inputData.clientId } } );
1285
+ }
1286
+ const query = [
1287
+ {
1288
+ $match: {
1289
+ $and: filter,
1290
+ },
1291
+ },
1292
+ {
1293
+ $lookup: {
1294
+ from: 'stores',
1295
+ let: { storeId: '$storeId' },
1296
+ pipeline: [
1297
+ {
1298
+ $match: {
1299
+ $expr: {
1300
+ $eq: [ '$storeId', '$$storeId' ],
1301
+ },
1302
+ },
1303
+ },
1304
+ {
1305
+ $project: {
1306
+ storeName: 1,
1307
+ },
1308
+ },
1309
+ ], as: 'store',
1310
+ },
1311
+ },
1312
+ {
1313
+ $unwind: {
1314
+ path: '$store', preserveNullAndEmptyArrays: true,
1315
+ },
1316
+ },
1317
+ {
1318
+ $lookup: {
1319
+ from: 'clients',
1320
+ let: { clientId: '$clientId' },
1321
+ pipeline: [
1322
+ {
1323
+ $match: {
1324
+ $expr: {
1325
+ $eq: [ '$clientId', '$$clientId' ],
1326
+ },
1327
+ },
1328
+ },
1329
+ {
1330
+ $project: {
1331
+ clientName: 1,
1332
+ },
1333
+ },
1334
+ ], as: 'client',
1335
+ },
1336
+
1337
+ },
1338
+ {
1339
+ $unwind: {
1340
+ path: '$client', preserveNullAndEmptyArrays: true,
1341
+ },
1342
+ },
1343
+ {
1344
+ $project: {
1345
+ storeId: 1,
1346
+ userId: 1,
1347
+ tempId: 1,
1348
+ streamName: 1,
1349
+ question: 1,
1350
+ questionType: 1,
1351
+ answer: 1,
1352
+ userComments: 1,
1353
+ storeName: '$store.storeName',
1354
+ clientId: 1,
1355
+ clientName: '$client.clientName',
1356
+ fileDate: 1,
1357
+ auditType: 1,
1358
+ moduleType: 1,
1359
+ value: {
1360
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
1361
+ },
1362
+ beforeCount: 1,
1363
+ afterCount: 1,
1364
+ accuracy: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, { $round: [
1365
+ {
1366
+ $multiply: [ { $divide: [ '$afterCount', '$beforeCount' ] }, 100 ],
1367
+ }, 1,
1368
+ ],
1369
+ }, null ] },
1370
+
1371
+ startTime: {
1372
+ $dateToString: {
1373
+ format: '%Y-%m-%d %H:%M:%S',
1374
+ date: '$startTime',
1375
+ timezone: 'Asia/Kolkata',
1376
+ },
1377
+ },
1378
+ endTime: {
1379
+ $dateToString: {
1380
+ format: '%Y-%m-%d %H:%M:%S',
1381
+ date: '$endTime',
1382
+ timezone: 'Asia/Kolkata',
1383
+ },
1384
+ },
1385
+ // timeSpent: { $round: [
1386
+ // { $divide: [ '$timeSpent', 60 ] }, 2,
1387
+ // ] },
1388
+ timeSpent: {
1389
+
1390
+ $cond: [
1391
+ { $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
1392
+ { $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
1393
+ {
1394
+ $cond: [
1395
+ { $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
1396
+ {
1397
+ $concat: [
1398
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
1399
+ ' min',
1400
+ ],
1401
+ },
1402
+ {
1403
+ $concat: [
1404
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
1405
+ ' hr',
1406
+ ],
1407
+ },
1408
+ ],
1409
+ },
1410
+ ],
1411
+
1412
+ },
1413
+ auditStatus: 1,
1414
+ createdAt: 1,
1415
+ },
1416
+ },
1417
+ ];
1418
+
1419
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
1420
+ query.push( {
1421
+ $match: {
1422
+ $or: [
1423
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1424
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1425
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
1426
+ { storeName: { $regex: inputData.searchValue, $options: 'i' } },
1427
+ { streamName: { $regex: inputData.searchValue, $options: 'i' } },
1428
+ { value: { $regex: inputData.searchValue, $options: 'i' } },
1429
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
1430
+ { auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
1431
+ { tempId: { $regex: inputData.searchValue, $options: 'i' } },
1432
+ { question: { $regex: inputData.searchValue, $options: 'i' } },
1433
+ { userComments: { $regex: inputData.searchValue, $options: 'i' } },
1434
+ ],
1435
+
1436
+ },
1437
+ } );
1438
+ }
1439
+
1440
+ if ( inputData.sortColumnName ) {
1441
+ const sortBy = inputData.sortBy || -1;
1442
+ const sortColumn = inputData.sortColumnName;
1443
+ query.push( {
1444
+ $sort: { [sortColumn]: sortBy },
1445
+ },
1446
+ );
1447
+ }
1448
+ const count = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
1449
+ if ( count.length == 0 ) {
1450
+ return res.sendError( 'No Data Found', 204 );
1451
+ }
1452
+
1453
+ if ( inputData.isExport ) {
1454
+ const chunkedMappingData = await chunkArray( count, 10 );
1455
+ const promises = chunkedMappingData.map( async ( chunk ) => {
1456
+ const exportData = [];
1457
+ chunk.forEach( ( element ) => {
1458
+ const temp ={
1459
+
1460
+ 'File Date': element.fileDate,
1461
+ 'Brand ID': element.clientId,
1462
+ 'Brand Name': element.clientName,
1463
+ 'Store ID': element.storeId,
1464
+ 'Store Name': element.storeName,
1465
+ 'Audit Type': element.auditType,
1466
+ 'Product Type': element.value,
1467
+ 'Start Time': element.startTime,
1468
+ 'End Time': element.endTime || '',
1469
+ 'Time Spent': element.timeSpent,
1470
+ 'Status': element.auditStatus,
1471
+ 'Audited Date': dayjs( element.createdAt ).format( 'YYYY,MMM D' ),
1472
+ 'Result': element.answer,
1473
+
1474
+
1475
+ };
1476
+ switch ( inputData.moduleType ) {
1477
+ case 'camera-angle-change':
1478
+ temp['stream Name'] = element.streamName;
1479
+ temp['User Comments'] = element.userCommands;
1480
+ break;
1481
+ case 'unattended-customer':
1482
+ temp['Customer ID'] = element.tempId;
1483
+ temp['Question'] = element.question;
1484
+ temp['User Comments'] = element.userCommands;
1485
+ break;
1486
+ case 'left-in-middle':
1487
+ temp['Question'] = element.question;
1488
+ temp['User Comments'] = element.userCommands;
1489
+ break;
1490
+ case 'uniform-detection':
1491
+ temp['Before Count'] = element.beforeCount;
1492
+ temp['After Count'] = element.afterCount;
1493
+ temp['Accuracy'] = element.accuracy || '';
1494
+ break;
1495
+ case 'mobile-detection':
1496
+ temp['Before Count'] = element.beforeCount;
1497
+ temp['After Count'] = element.afterCount;
1498
+ temp['Accuracy'] = element.accuracy || '';
1499
+ break;
1500
+ }
1501
+ exportData.push( temp );
1502
+ } );
1503
+ return exportData;
1504
+ } );
1505
+ const mappedArrays = await Promise.all( promises );
1506
+ mappedArrays.flat();
1507
+ logger.info( { mappedArrays: mappedArrays[0] } );
1508
+ await download( mappedArrays[0], res );
1509
+ return;
1510
+ }
1511
+
1512
+ query.push( {
1513
+ $skip: offset,
1514
+ },
1515
+ {
1516
+ $limit: limit,
1517
+ } );
1518
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
1519
+
1520
+ return res.sendSuccess( { result: result, count: count.length } );
1521
+ } catch ( error ) {
1522
+ const err = error.message || 'Internal Server Error';
1523
+ logger.info( { error: error, message: req.body, function: 'userAuditHistory' } );
1524
+ return res.sendError( err, 500 );
1525
+ }
1526
+ }
1527
+
1528
+ export async function clientMetrics( req, res ) {
1529
+ try {
1530
+ const inputData = req.body;
1531
+ const limit = inputData.limit || 10;
1532
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
1533
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1534
+ let filter = [
1535
+ { fileDateISO: { $gte: dateRange.start } },
1536
+ { fileDateISO: { $lte: dateRange.end } },
1537
+ { moduleType: { $eq: inputData.moduleType } },
1538
+ ];
1539
+
1540
+ let storeAuditFilter = [
1541
+ { $eq: [ '$clientId', '$$clientId' ] },
1542
+ { $eq: [ '$fileDate', '$$fileDate' ] },
1543
+ { $eq: [ '$moduleType', inputData.moduleType ] },
1544
+
1545
+ ];
1546
+
1547
+ if ( inputData?.filterByClient?.length> 0 ) {
1548
+ filter.push(
1549
+ { clientId: { $in: inputData.filterByClient } },
1550
+ );
1551
+ }
1552
+ const query = [
1553
+ {
1554
+ $match: {
1555
+ $and: filter,
1556
+ },
1557
+ },
1558
+ {
1559
+ $group: {
1560
+ _id: { clientId: '$clientId', fileDate: '$fileDate', moduleType: '$moduleType' },
1561
+ fileDate: { $last: '$fileDate' },
1562
+ clientId: { $last: '$clientId' },
1563
+ clientName: { $last: '$clientName' },
1564
+ moduleType: { $last: '$moduleType' },
1565
+ installedStore: { $last: '$installedStore' },
1566
+ queueName: { $last: '$queueName' },
1567
+ totalFilesCount: { $sum: 1 },
1568
+ },
1569
+ },
1570
+ {
1571
+ $project: {
1572
+ fileDate: 1,
1573
+ clientId: 1,
1574
+ clientName: 1,
1575
+ queueName: 1,
1576
+ installedStore: 1,
1577
+ totalFilesCount: 1,
1578
+ moduleType: 1,
1579
+ notAssignedCount: { $ifNull: [ 0, 0 ] },
1580
+ clientStatus: { $ifNull: [ '', '' ] },
1581
+ },
1582
+ },
1583
+ {
1584
+ $lookup: {
1585
+ 'from': 'binaryAudit',
1586
+ 'let': { clientId: '$clientId', fileDate: '$fileDate', totalAuditFiles: '$totalFilesCount' },
1587
+ 'pipeline': [
1588
+
1589
+ {
1590
+ $match: {
1591
+ $expr: {
1592
+ $and: storeAuditFilter,
1593
+ },
1594
+ },
1595
+ },
1596
+ {
1597
+ $project: {
1598
+ completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
1599
+ notAssignedStores: { $cond: [ { $eq: [ '$status', 'not_assign' ] }, 1, 0 ] },
1600
+ inprogressStores: { $cond: [ { $in: [ '$status', [ 'inprogress', 'drafted', 'assigned' ] ] }, 1, 0 ] },
1601
+ },
1602
+ },
1603
+ {
1604
+ $group: {
1605
+ _id: { clientId: '$clientId', fileDate: '$fileDate' },
1606
+ completedStores: { $sum: '$completedStores' },
1607
+ inprogressStores: { $sum: '$inprogressStores' },
1608
+ notAssignedStores: { $sum: '$notAssignedStores' },
1609
+ fileCount: { $sum: 1 },
1610
+ },
1611
+ },
1612
+ {
1613
+ $project: {
1614
+ _id: 0,
1615
+ completedStores: 1,
1616
+ inprogressStores: 1,
1617
+ notAssignedStores: 1,
1618
+ fileCount: { $ifNull: [ '$fileCount', 0 ] },
1619
+ completionPercentage: { $ifNull: [
1620
+ {
1621
+ $round: [ {
1622
+ $multiply: [
1623
+ 100, {
1624
+ $divide: [
1625
+ '$completedStores', '$$totalAuditFiles',
1626
+ ],
1627
+ },
1628
+ ],
1629
+ }, 1 ],
1630
+
1631
+ },
1632
+ 0,
1633
+ ],
1634
+ },
1635
+ },
1636
+ },
1637
+ ], 'as': 'binaryAudit',
1638
+ },
1639
+ },
1640
+ {
1641
+ $unwind: {
1642
+ path: '$binaryAudit',
1643
+ preserveNullAndEmptyArrays: true,
1644
+ },
1645
+ },
1646
+ {
1647
+ $project: {
1648
+ _id: 0,
1649
+ fileDate: 1,
1650
+ clientId: 1,
1651
+ clientName: 1,
1652
+ totalFilesCount: 1,
1653
+ moduleType: 1,
1654
+ value: {
1655
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' }, // Replacing "-" with " "
1656
+ },
1657
+ installedStore: 1,
1658
+ // notAssignedStores: '$binaryAudit.notAssignedStores',
1659
+ inprogressStoresCount: '$binaryAudit.inprogressStores',
1660
+ // fileCount: '$binaryAudit.fileCount',
1661
+ notAssignedCount: { $subtract: [ '$totalFilesCount', { $subtract: [ { $ifNull: [ '$binaryAudit.fileCount', 0 ] }, { $ifNull: [ '$binaryAudit.notAssignedStores', 0 ] } ] } ] },
1662
+ clientStatus: { $cond: [ { $eq: [ { $ifNull: [ '$binaryAudit.fileCount', 0 ] }, 0 ] }, 'not-taken', { $cond: [ { $gte: [ '$binaryAudit.completedStores', '$totalFilesCount' ] }, 'completed', 'pending' ] } ] }, // { $cond: [ { $or: [ { $gt: [ '$notAssignedCount', 0 ] }, { $gt: [ '$binaryAudit.notAssignedStores', 0 ] } ] }
1663
+ completedStores: '$binaryAudit.completedStores',
1664
+ completionPercentage: '$binaryAudit.completionPercentage',
1665
+
1666
+ },
1667
+ },
1668
+ ];
1669
+
1670
+ if ( inputData?.filterByStatus?.length> 0 ) {
1671
+ query.push(
1672
+ {
1673
+ $match: { clientStatus: { $in: inputData.filterByStatus } },
1674
+ },
1675
+
1676
+ );
1677
+ }
1678
+
1679
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
1680
+ query.push( {
1681
+ $match: {
1682
+ $or: [
1683
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1684
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1685
+ { moduleType: { $regex: inputData.searchValue, $options: 'i' } },
1686
+ { clientStatus: { $regex: inputData.searchValue, $options: 'i' } },
1687
+ ],
1688
+
1689
+ },
1690
+ } );
1691
+ }
1692
+ if ( inputData.sortColumnName ) {
1693
+ const sortBy = inputData.sortBy || -1;
1694
+ const sortColumn = inputData.sortColumnName;
1695
+ query.push( {
1696
+ $sort: { [sortColumn]: sortBy },
1697
+ },
1698
+ );
1699
+ }
1700
+
1701
+ const count = await aggregateTraxAuditData( query );
1702
+ logger.info( { count: count } );
1703
+ if ( count.length == 0 ) {
1704
+ return res.sendError( 'No Data Found', 204 );
1705
+ }
1706
+
1707
+ query.push(
1708
+ { $skip: offset },
1709
+ { $limit: limit },
1710
+ );
1711
+ if ( inputData.isExport ) {
1712
+ query.push(
1713
+ {
1714
+ $project: {
1715
+ '_id': 0,
1716
+ 'File Date': '$fileDate',
1717
+ 'Client Name': '$clientName',
1718
+ 'Client Id': '$clientId',
1719
+ 'Product Type': '$value',
1720
+ 'Completed Percentage': '$completionPercentage',
1721
+ 'Installed Stores': '$installedStore',
1722
+ 'Audit Stores': '$totalFilesCount',
1723
+ 'Inprogress Stores': '$inprogressStoresCount',
1724
+ 'Not Assigned': '$notAssignedCount',
1725
+ // 'Not Assigned Stores': '$notAssignedStores',
1726
+ 'Completed': '$completedStores',
1727
+ 'Status': '$clientStatus',
1728
+ },
1729
+ },
1730
+ );
1731
+ }
1732
+
1733
+ logger.info( { query: query } );
1734
+ const result = await aggregateTraxAuditData( query );
1735
+ if ( result.length == 0 ) {
1736
+ return res.sendError( 'No Data Found', 204 );
1737
+ }
1738
+ if ( inputData.isExport ) {
1739
+ await download( result, res );
1740
+ return;
1741
+ }
1742
+ return res.sendSuccess( { result: result, count: count.length } );
1743
+ } catch ( error ) {
1744
+ const err = error.error || 'Internal Server Error';
1745
+ logger.info( { error: error, message: req.body, function: 'clientMetrics' } );
1746
+ return res.sendError( err, 500 );
1747
+ }
1748
+ }
1749
+
1750
+ export async function storeMetrics( req, res ) {
1751
+ try {
1752
+ const inputData = req.body;
1753
+ const limit = inputData.limit || 10;
1754
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
1755
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
1756
+ let filter = [
1757
+ { fileDateISO: { $gte: dateRange.start } },
1758
+ { fileDateISO: { $lte: dateRange.end } },
1759
+ { moduleType: { $eq: inputData.moduleType } },
1760
+
1761
+ ];
1762
+ if ( inputData.filterByClientId && inputData.filterByClientId?.length > 0 ) {
1763
+ filter.push( { clientId: { $in: inputData.filterByClientId } } );
1764
+ }
1765
+
1766
+ if ( inputData.filterByStoreId && inputData.filterByStoreId?.length > 0 ) {
1767
+ filter.push( { storeId: { $in: inputData.filterByStoreId } } );
1768
+ }
1769
+
1770
+ if ( inputData.filterByStatus && inputData.filterByStatus?.length > 0 ) {
1771
+ filter.push( { status: { $in: inputData.filterByStatus } } );
1772
+ }
1773
+
1774
+ if ( inputData.filterByAuditType && inputData.filterByAuditType?.length > 0 ) {
1775
+ filter.push( { auditType: { $in: inputData.filterByAuditType } } );
1776
+ }
1777
+
1778
+
1779
+ const query = [
1780
+ {
1781
+ $match: {
1782
+ $and: filter,
1783
+ },
1784
+ },
1785
+
1786
+ {
1787
+ $lookup: {
1788
+ from: 'stores',
1789
+ let: { storeId: '$storeId' },
1790
+ pipeline: [
1791
+ {
1792
+ $match: {
1793
+ $expr: {
1794
+ $eq: [ '$storeId', '$$storeId' ],
1795
+ },
1796
+ },
1797
+ },
1798
+ {
1799
+ $project: {
1800
+ _id: 0,
1801
+ storeName: 1,
1802
+ },
1803
+ },
1804
+ ], as: 'stores',
1805
+ },
1806
+ },
1807
+ {
1808
+ $unwind: {
1809
+ path: '$stores',
1810
+ preserveNullAndEmptyArrays: true,
1811
+ },
1812
+ },
1813
+ {
1814
+ $project: {
1815
+ auditId: '$_id',
1816
+ _id: 0,
1817
+ fileDate: 1,
1818
+ storeId: 1,
1819
+ storeName: '$stores.storeName',
1820
+ clientName: '',
1821
+ clientId: 1,
1822
+ moduleType: 1,
1823
+ value: {
1824
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
1825
+ },
1826
+ tempId: 1,
1827
+ streamName: 1,
1828
+ question: 1,
1829
+ questionType: 1,
1830
+ answer: 1,
1831
+ // userId: {
1832
+ // $arrayElemAt: [ '$userId', { $subtract: [ { $size: '$userId' }, 1 ] } ], //need to check if no data
1833
+ // },
1834
+ userId: 1,
1835
+ auditType: 1,
1836
+ beforeCount: 1,
1837
+ afterCount: { $ifNull: [ '$afterCount', null ] },
1838
+ accuracy: { $cond: [ { $eq: [ '$status', 'completed' ] }, { $round: [
1839
+ {
1840
+ $multiply: [ { $divide: [ '$afterCount', '$beforeCount' ] }, 100 ],
1841
+ }, 1,
1842
+ ],
1843
+ }, null ] },
1844
+ timeSpent: 1,
1845
+ status: 1,
1846
+ auditStatus: 1,
1847
+ },
1848
+ },
1849
+ {
1850
+ $lookup: {
1851
+ from: 'users',
1852
+ let: { userId: '$userId' },
1853
+ pipeline: [
1854
+ {
1855
+ $match: {
1856
+ $expr: {
1857
+ $eq: [ '$_id', '$$userId' ],
1858
+ },
1859
+ },
1860
+ },
1861
+ {
1862
+ $project: {
1863
+ _id: 0,
1864
+ userName: 1,
1865
+ userEmail: '$email',
1866
+ },
1867
+ },
1868
+ ], as: 'users',
1869
+ },
1870
+ },
1871
+ {
1872
+ $unwind: {
1873
+ path: '$users',
1874
+ preserveNullAndEmptyArrays: true,
1875
+ },
1876
+ },
1877
+ {
1878
+ $lookup: {
1879
+ from: 'clients',
1880
+ let: { clientId: '$clientId' },
1881
+ pipeline: [
1882
+ {
1883
+ $match: {
1884
+ $expr: {
1885
+ $eq: [ '$clientId', '$$clientId' ],
1886
+ },
1887
+ },
1888
+ },
1889
+ {
1890
+ $project: {
1891
+ _id: 0,
1892
+ clientName: 1,
1893
+ },
1894
+ },
1895
+ ], as: 'client',
1896
+ },
1897
+ },
1898
+ {
1899
+ $unwind: {
1900
+ path: '$client',
1901
+ preserveNullAndEmptyArrays: true,
1902
+ },
1903
+ },
1904
+ {
1905
+ $project: {
1906
+ auditId: 1,
1907
+ fileDate: 1,
1908
+ storeId: 1,
1909
+ storeName: 1,
1910
+ userName: '$users.userName',
1911
+ userEmail: '$users.userEmail',
1912
+ clientId: 1,
1913
+ clientName: '$client.clientName',
1914
+ tempId: 1,
1915
+ streamName: 1,
1916
+ question: 1,
1917
+ questionType: 1,
1918
+ answer: 1,
1919
+ moduleType: 1,
1920
+ value: 1,
1921
+ auditType: 1,
1922
+ beforeCount: 1,
1923
+ afterCount: { $ifNull: [ '$afterCount', null ] },
1924
+ accuracy: { $cond: [ { $eq: [ '$status', 'completed' ] }, { $round: [
1925
+ {
1926
+ $multiply: [ { $divide: [ '$afterCount', '$beforeCount' ] }, 100 ],
1927
+ }, 1,
1928
+ ],
1929
+ }, null ] },
1930
+ timeSpent: {
1931
+
1932
+ $cond: [
1933
+ { $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
1934
+ { $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
1935
+ {
1936
+ $cond: [
1937
+ { $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
1938
+ {
1939
+ $concat: [
1940
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
1941
+ ' min',
1942
+ ],
1943
+ },
1944
+ {
1945
+ $concat: [
1946
+ { $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
1947
+ ' hr',
1948
+ ],
1949
+ },
1950
+ ],
1951
+ },
1952
+ ],
1953
+
1954
+ },
1955
+ status: 1,
1956
+ auditStatus: 1,
1957
+ },
1958
+ },
1959
+
1960
+ ];
1961
+
1962
+ if ( inputData.searchValue && inputData.searchValue !== '' ) {
1963
+ query.push( {
1964
+ $match: {
1965
+ $or: [
1966
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1967
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1968
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
1969
+ { storeName: { $regex: inputData.searchValue, $options: 'i' } },
1970
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
1971
+ { status: { $regex: inputData.searchValue, $options: 'i' } },
1972
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
1973
+ { value: { $regex: inputData.searchValue, $options: 'i' } },
1974
+ { tempId: { $regex: inputData.searchValue, $options: 'i' } },
1975
+ { question: { $regex: inputData.searchValue, $options: 'i' } },
1976
+ { answer: { $regex: inputData.searchValue, $options: 'i' } },
1977
+ { auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
1978
+ ],
1979
+ },
1980
+ } );
1981
+ }
1982
+
1983
+ if ( inputData.sortColumnName ) {
1984
+ const sortBy = inputData.sortBy || -1;
1985
+ const sortColumn = inputData.sortColumnName;
1986
+ query.push( {
1987
+ $sort: { [sortColumn]: sortBy },
1988
+ },
1989
+ );
1990
+ }
1991
+ const count = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateStoreEmpDetection( query ) : await aggregateBinaryAudit( query );
1992
+
1993
+ if ( count.length == 0 ) {
1994
+ return res.sendError( 'No data Found', 204 );
1995
+ }
1996
+ if ( !inputData.isExport ) {
1997
+ query.push( {
1998
+ $skip: offset,
1999
+ },
2000
+ {
2001
+ $limit: limit,
2002
+ } );
2003
+ } else {
2004
+ query.push( { $limit: 10000 } );
2005
+ }
2006
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2007
+ if ( inputData.isExport ) {
2008
+ const exportdata = [];
2009
+ result.forEach( ( element ) => {
2010
+ const temp ={
2011
+ 'File Date': element.fileDate,
2012
+ 'Store ID': element.storeId,
2013
+ 'Store Name': element.storeName,
2014
+ 'Client Id': element.clientId,
2015
+ 'Client Name': element.clientName,
2016
+ 'User Name': element.userName,
2017
+ 'User Email': element.userEmail,
2018
+ 'Audit Type': element.auditType,
2019
+ 'Time Spent': element.timeSpent,
2020
+ 'Result': element.answer,
2021
+ };
2022
+ switch ( inputData.moduleType ) {
2023
+ case 'camera-angle-change':
2024
+ temp['stream Name'] = element.streamName;
2025
+ temp['User Comments'] = element.auditStatus;
2026
+ break;
2027
+ case 'unattended-customer':
2028
+ temp['Customer ID'] = element.tempId;
2029
+ temp['Question'] = element.question;
2030
+ temp['User Comments'] = element.auditStatus;
2031
+ break;
2032
+ case 'left-in-middle':
2033
+ temp['Question'] = element.question;
2034
+ temp['User Comments'] = element.userCommands;
2035
+ temp['Status'] = element.auditStatus;
2036
+ break;
2037
+ case 'mobile-detection':
2038
+ temp['Before Count'] = element.beforeCount;
2039
+ temp['After Count'] = element.afterCount;
2040
+ temp['Status'] = element.status;
2041
+ temp['Accuracy'] = element.accuracy;
2042
+ break;
2043
+ case 'uniform-detection':
2044
+ temp['Before Count'] = element.beforeCount;
2045
+ temp['After Count'] = element.afterCount;
2046
+ temp['Status'] = element.status;
2047
+ temp['Accuracy'] = element.accuracy;
2048
+ break;
2049
+ }
2050
+ exportdata.push( temp );
2051
+ } );
2052
+ await download( exportdata, res );
2053
+ return;
2054
+ }
2055
+ return res.sendSuccess( { result: result, count: count.length } );
2056
+ } catch ( error ) {
2057
+ const err = error.message || 'Internal Server Error';
2058
+ logger.error( { error: error, data: req.body, function: 'storeMetrics' } );
2059
+ return res.sendError( err, 500 );
2060
+ }
2061
+ }
2062
+
2063
+ export async function userMetrics( req, res ) {
2064
+ try {
2065
+ const inputData = req.body;
2066
+ const limit = inputData.limit || 10;
2067
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
2068
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2069
+ const dateRangeUpdatedAt = await getDateWithCustomizeTime( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2070
+ let filter = [
2071
+ { moduleType: { $eq: inputData.moduleType } },
2072
+ ];
2073
+ if ( inputData.dateType == 'auditedDate' ) {
2074
+ filter.push(
2075
+ { updatedAt: { $gte: dateRangeUpdatedAt.start } },
2076
+ { updatedAt: { $lte: dateRangeUpdatedAt.end } },
2077
+
2078
+ );
2079
+ } else {
2080
+ filter.push(
2081
+ { fileDateISO: { $gte: dateRange.start } },
2082
+ { fileDateISO: { $lte: dateRange.end } },
2083
+
2084
+ );
2085
+ }
2086
+ if ( inputData?.filterByStatus?.length> 0 ) {
2087
+ filter.push(
2088
+ { auditStatus: { $in: inputData.filterByStatus } },
2089
+ );
2090
+ }
2091
+ if ( inputData?.filterByUser?.length> 0 ) {
2092
+ const temp = inputData.filterByUser.map( ( item ) => new mongoose.Types.ObjectId( item ) );
2093
+ logger.info( { temp: temp } );
2094
+ filter.push(
2095
+ { userId: { $in: temp } },
2096
+ );
2097
+ }
2098
+
2099
+ const query = [
2100
+ {
2101
+ $match: {
2102
+ $and: filter,
2103
+ },
2104
+ },
2105
+ {
2106
+ $project: {
2107
+ userId: 1,
2108
+ fileDate: 1,
2109
+ startTime: 1,
2110
+ beforeCount: 1,
2111
+ moduleType: 1,
2112
+ afterCount: 1,
2113
+ checkIntime: 1,
2114
+ checkOutTime: 1,
2115
+ totalCompletedFiles: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, 1, 0 ] },
2116
+ beforeCount: 1,
2117
+ afterCount: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, '$afterCount', 0 ] },
2118
+
2119
+ value: {
2120
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
2121
+ } },
2122
+ },
2123
+ {
2124
+ $group: {
2125
+ _id: { userId: '$userId', fileDate: '$fileDate' },
2126
+ userId: { $first: '$userId' },
2127
+ fileDate: { $first: '$fileDate' },
2128
+ totalCompletedFiles: { $sum: '$totalCompletedFiles' },
2129
+ beforeCount: { $sum: '$beforeCount' },
2130
+ afterCount: { $sum: '$afterCount' },
2131
+ checkIntime: { $first: '$startTime' },
2132
+ checkOutTime: { $last: '$endTime' },
2133
+ moduleType: { $last: '$moduleType' },
2134
+ value: { $last: '$value' },
2135
+ },
2136
+ },
2137
+ {
2138
+ $project: {
2139
+ _id: 0,
2140
+ userId: 1,
2141
+ fileDate: 1,
2142
+ totalCompletedFiles: 1,
2143
+ moduleType: 1,
2144
+ value: 1,
2145
+ beforeCount: 1,
2146
+ afterCount: 1,
2147
+ // mappingPerc: { $round: [
2148
+ // { $multiply: [
2149
+ // { $divide: [ '$afterCount', '$beforeCount' ] }, 100,
2150
+ // ] }, 2,
2151
+ // ] },
2152
+ checkIntime: 1,
2153
+ checkOutTime: 1,
2154
+ differenceInSeconds: {
2155
+ $divide: [ { $subtract: [ '$checkOutTime', '$checkIntime' ] }, 1000 ],
2156
+ },
2157
+ },
2158
+ },
2159
+ {
2160
+ $project: {
2161
+ userId: 1,
2162
+ fileDate: 1,
2163
+ totalCompletedFiles: 1,
2164
+ beforeCount: 1,
2165
+ afterCount: 1,
2166
+ checkIntime: 1,
2167
+ checkOutTime: 1,
2168
+ moduleType: 1,
2169
+ value: 1,
2170
+ // mappingPerc: 1,
2171
+ hours: { $floor: { $divide: [ '$differenceInSeconds', 3600 ] } },
2172
+ minutes: { $floor: { $divide: [ { $mod: [ '$differenceInSeconds', 3600 ] }, 60 ] } },
2173
+ seconds: { $mod: [ '$differenceInSeconds', 60 ] },
2174
+ },
2175
+ },
2176
+ {
2177
+ $project: {
2178
+ event: 1,
2179
+ userId: 1,
2180
+ fileDate: 1,
2181
+ totalCompletedFiles: 1,
2182
+ beforeCount: 1,
2183
+ afterCount: 1,
2184
+ checkIntime: 1,
2185
+ checkOutTime: 1,
2186
+ moduleType: 1,
2187
+ value: 1,
2188
+ // mappingPerc: 1,
2189
+ hours: {
2190
+ $cond: {
2191
+ if: { $lt: [ '$hours', 10 ] },
2192
+ then: { $concat: [ '0', { $toString: { $round: [ '$hours', 0 ] } } ] },
2193
+ else: { $toString: { $round: [ '$hours', 0 ] } },
2194
+ },
2195
+ },
2196
+ minutes: {
2197
+ $cond: {
2198
+ if: { $lt: [ '$minutes', 10 ] },
2199
+ then: { $concat: [ '0', { $toString: { $round: [ '$minutes', 0 ] } } ] },
2200
+ else: { $toString: { $round: [ '$minutes', 0 ] } },
2201
+ },
2202
+ },
2203
+ seconds: {
2204
+ $cond: {
2205
+ if: { $lt: [ '$seconds', 10 ] },
2206
+ then: { $concat: [ '0', { $toString: { $round: [ '$seconds', 0 ] } } ] },
2207
+ else: { $toString: { $round: [ '$seconds', 0 ] } },
2208
+ },
2209
+ },
2210
+ },
2211
+ },
2212
+ {
2213
+ $project: {
2214
+ event: 1,
2215
+ userId: 1,
2216
+ fileDate: 1,
2217
+ totalCompletedFiles: 1,
2218
+ beforeCount: 1,
2219
+ afterCount: 1,
2220
+ checkIntime: 1,
2221
+ checkOutTime: 1,
2222
+ moduleType: 1,
2223
+ value: {
2224
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
2225
+ },
2226
+ // mappingPerc: 1,
2227
+ workingHours: {
2228
+ $concat: [ '$hours', ':', '$minutes', ':', '$seconds' ],
2229
+ },
2230
+ },
2231
+ },
2232
+ {
2233
+ $lookup: {
2234
+ from: 'users',
2235
+ let: { userId: '$userId' },
2236
+ pipeline: [
2237
+ {
2238
+ $match: {
2239
+ $expr: {
2240
+ $eq: [ '$_id', '$$userId' ],
2241
+ },
2242
+ },
2243
+ },
2244
+ {
2245
+ $project: {
2246
+ _id: 0,
2247
+ userName: 1,
2248
+ },
2249
+ },
2250
+ ], as: 'userInfo',
2251
+ },
2252
+ },
2253
+ {
2254
+ $unwind: {
2255
+ path: '$userInfo', preserveNullAndEmptyArrays: true,
2256
+ },
2257
+ },
2258
+ {
2259
+ $project: {
2260
+ event: 1,
2261
+ userName: '$userInfo.userName',
2262
+ userId: 1,
2263
+ fileDate: 1,
2264
+ totalCompletedFiles: 1,
2265
+ beforeCount: 1,
2266
+ afterCount: 1,
2267
+ moduleType: 1,
2268
+ value: {
2269
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
2270
+ },
2271
+ // mappingPerc: 1,
2272
+ checkIntime: {
2273
+ $dateToString: {
2274
+ format: '%Y-%m-%d %H:%M:%S',
2275
+ date: '$checkIntime',
2276
+ timezone: 'Asia/Kolkata',
2277
+ },
2278
+ },
2279
+ checkOutTime: {
2280
+ $dateToString: {
2281
+ format: '%Y-%m-%d %H:%M:%S',
2282
+ date: '$checkOutTime',
2283
+ timezone: 'Asia/Kolkata',
2284
+ },
2285
+ },
2286
+ workingHours: 1,
2287
+ },
2288
+ },
2289
+ ];
2290
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
2291
+ query.push( {
2292
+ $match: {
2293
+ $or: [
2294
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
2295
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
2296
+ ],
2297
+
2298
+ },
2299
+ } );
2300
+ }
2301
+ if ( inputData.sortColumnName ) {
2302
+ const sortBy = inputData.sortBy || -1;
2303
+ const sortColumn = inputData.sortColumnName;
2304
+ query.push( {
2305
+ $sort: { [sortColumn]: sortBy },
2306
+ },
2307
+ );
2308
+ }
2309
+
2310
+ const count = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2311
+ if ( count.length == 0 ) {
2312
+ return res.sendError( 'No Data Found', 204 );
2313
+ }
2314
+
2315
+ query.push(
2316
+ { $skip: offset },
2317
+ { $limit: limit },
2318
+ );
2319
+ if ( inputData.isExport ) {
2320
+ const detection = {
2321
+ '_id': 0,
2322
+ 'File Date': '$fileDate',
2323
+ 'User Name': '$userName',
2324
+ 'Total Completed Files Count': '$totalCompletedFiles',
2325
+ 'Total Before Count': '$beforeCount',
2326
+ 'Total After Count': '$afterCount',
2327
+ 'check Intime': '$checkIntime',
2328
+ 'check OutTime': '$checkOutTime',
2329
+ 'working Hours': '$workingHours',
2330
+ 'Product Type': '$value',
2331
+ // 'Mapping Percentage': '$mappingPerc',
2332
+ };
2333
+ const YesNo = {
2334
+ '_id': 0,
2335
+ 'File Date': '$fileDate',
2336
+ 'User Name': '$userName',
2337
+ 'Total Completed Files Count': '$totalCompletedFiles',
2338
+ 'check Intime': '$checkIntime',
2339
+ 'check OutTime': '$checkOutTime',
2340
+ 'working Hours': '$workingHours',
2341
+ 'Product Type': '$value',
2342
+ // 'Mapping Percentage': '$mappingPerc',
2343
+ };
2344
+ inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?
2345
+ query.push(
2346
+ {
2347
+ $project: detection,
2348
+ },
2349
+ ) :
2350
+ query.push(
2351
+ {
2352
+ $project: YesNo,
2353
+ },
2354
+ );
2355
+ }
2356
+
2357
+
2358
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2359
+ if ( inputData.isExport ) {
2360
+ await download( result, res );
2361
+ return;
2362
+ }
2363
+ return res.sendSuccess( { result: result, count: count.length } );
2364
+ } catch ( error ) {
2365
+ const err = error.error || 'Internal Server Error';
2366
+ logger.info( { error: error, message: req.body, function: 'userMetrics' } );
2367
+ return res.sendError( err, 500 );
2368
+ }
2369
+ }
2370
+
2371
+ export async function pendingSummaryTable( req, res ) {
2372
+ try {
2373
+ const inputData = req.body;
2374
+ const limit = inputData.limit || 10;
2375
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
2376
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2377
+ let filters =[
2378
+ { fileDateISO: { $gte: dateRange.start } },
2379
+ { fileDateISO: { $lte: dateRange.end } },
2380
+ { auditStatus: { $ne: 'completed' } },
2381
+ { moduleType: { $eq: inputData.moduleType } },
2382
+
2383
+ ];
2384
+
2385
+ if ( inputData.clientId.length > 0 ) {
2386
+ filters.push( { clientId: { $in: inputData.clientId } } );
2387
+ }
2388
+
2389
+ if ( inputData.filterByAuditType.length > 0 ) {
2390
+ filters.push( { auditType: { $in: inputData.filterByAuditType } } );
2391
+ }
2392
+
2393
+ if ( inputData.filterByStatus.length > 0 ) {
2394
+ filters.push( { auditStatus: { $in: inputData.filterByStatus } } );
2395
+ }
2396
+ const query =[
2397
+ {
2398
+ $match: {
2399
+ $and: filters,
2400
+ },
2401
+
2402
+ },
2403
+ {
2404
+ $project: {
2405
+ _id: 0,
2406
+ storeId: 1,
2407
+ streamName: 1,
2408
+ tempId: 1,
2409
+ question: 1,
2410
+ questionType: 1,
2411
+ answer: 1,
2412
+ userComments: 1,
2413
+ fileDate: 1,
2414
+ moduleType: 1,
2415
+ value: {
2416
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
2417
+ },
2418
+ beforeCount: 1,
2419
+ startTime: { $dateToString: {
2420
+ format: '%Y-%m-%d %H:%M:%S',
2421
+ date: '$startTime',
2422
+ timezone: 'Asia/Kolkata',
2423
+ },
2424
+
2425
+ },
2426
+ auditType: 1,
2427
+ auditStatus: 1,
2428
+ userId: 1,
2429
+ },
2430
+ },
2431
+ {
2432
+ $lookup: {
2433
+ from: 'users',
2434
+ let: { userId: '$userId' },
2435
+ pipeline: [
2436
+ {
2437
+ $match: {
2438
+ $expr: {
2439
+ $eq: [ '$_id', '$$userId' ],
2440
+ },
2441
+ },
2442
+ },
2443
+ {
2444
+ $project: {
2445
+ userName: 1,
2446
+ userEmail: '$email',
2447
+ },
2448
+ },
2449
+ ], as: 'user',
2450
+ },
2451
+ },
2452
+ {
2453
+ $unwind: {
2454
+ path: '$user',
2455
+ preserveNullAndEmptyArrays: true,
2456
+ },
2457
+ },
2458
+ {
2459
+ $project: {
2460
+ storeId: 1,
2461
+ streamName: 1,
2462
+ tempId: 1,
2463
+ question: 1,
2464
+ questionType: 1,
2465
+ answer: 1,
2466
+ userComments: 1,
2467
+ fileDate: 1,
2468
+ moduleType: 1,
2469
+ value: 1,
2470
+ beforeCount: 1,
2471
+ startTime: 1,
2472
+ endTime: 1,
2473
+ auditType: 1,
2474
+ auditStatus: 1,
2475
+ userName: '$user.userName',
2476
+ userEmail: '$user.userEmail',
2477
+
2478
+ },
2479
+ },
2480
+ ];
2481
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
2482
+ query.push( {
2483
+ $match: {
2484
+ $or: [
2485
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
2486
+ { fileDate: { $regex: inputData.searchValue, $options: 'i' } },
2487
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
2488
+ { auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
2489
+ { userName: { $regex: inputData.searchValue, $options: 'i' } },
2490
+ { userEmail: { $regex: inputData.searchValue, $options: 'i' } },
2491
+ { value: { $regex: inputData.searchValue, $options: 'i' } },
2492
+ ],
2493
+
2494
+ },
2495
+ } );
2496
+ }
2497
+ if ( inputData.sortColumnName ) {
2498
+ const sortBy = inputData.sortBy || -1;
2499
+ const sortColumn = inputData.sortColumnName;
2500
+ query.push( {
2501
+ $sort: { [sortColumn]: sortBy },
2502
+ },
2503
+ );
2504
+ }
2505
+ const count = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2506
+ if ( count.length == 0 ) {
2507
+ return res.sendError( 'No Data Found', 204 );
2508
+ }
2509
+
2510
+ if ( inputData.isExport ) {
2511
+ query.push( { $limit: 10000 } );
2512
+ } else {
2513
+ query.push( {
2514
+ $skip: offset,
2515
+ },
2516
+ {
2517
+ $limit: limit,
2518
+ } );
2519
+ }
2520
+
2521
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2522
+ if ( inputData.isExport ) {
2523
+ const exportdata = [];
2524
+ result.forEach( ( element ) => {
2525
+ const temp = {
2526
+ 'Store ID': element.storeId,
2527
+ 'Result': element.answer,
2528
+ 'userComments': element.userComments,
2529
+ 'File Date': element.fileDate,
2530
+ 'Product Type': element.value,
2531
+ 'Audit Type': element.auditType,
2532
+ 'Start Time': element.startTime,
2533
+ 'User Name': element.userName,
2534
+ 'User Email': element.userEmail,
2535
+ 'Status': element.auditStatus,
2536
+ };
2537
+ switch ( inputData.moduleType ) {
2538
+ case 'camera-angle-change':
2539
+ temp['stream Name'] = element.streamName;
2540
+ temp['User Comments'] = element.userCommands;
2541
+ break;
2542
+ case 'unattended-customer':
2543
+ temp['Customer ID'] = element.tempId;
2544
+ temp['Question'] = element.question;
2545
+ temp['User Comments'] = element.userCommands;
2546
+ break;
2547
+ case 'left-in-middle':
2548
+ temp['Question'] = element.question;
2549
+ temp['User Comments'] = element.userCommands;
2550
+ break;
2551
+ case 'mobile-detection':
2552
+ temp['Before Count'] = element.beforeCount;
2553
+ break;
2554
+ case 'uniform-detection':
2555
+ temp['Before Count'] = element.beforeCount;
2556
+ break;
2557
+ }
2558
+ exportdata.push( temp );
2559
+ } );
2560
+ await download( exportdata, res );
2561
+ return;
2562
+ }
2563
+ return res.sendSuccess( { result: result, count: count.length } );
2564
+ } catch ( error ) {
2565
+ const err = error.message || 'Internal Server Error';
2566
+ logger.error( { error: error, message: req.body, function: 'pendingSummaryTable' } );
2567
+ return res.sendError( err, 500 );
2568
+ }
2569
+ }
2570
+
2571
+ export async function overAllAuditSummary( req, res ) {
2572
+ try {
2573
+ const inputData = req.body;
2574
+ let temp = {
2575
+ installedStores: 0,
2576
+ auditStores: 0,
2577
+ inprogressStores: 0,
2578
+ completedStores: 0,
2579
+ auditInprogress: 0,
2580
+ reAuditInprogress: 0,
2581
+ draft: 0,
2582
+ assigned: 0,
2583
+ notAssigned: 0,
2584
+ auditCompleted: 0,
2585
+ reAuditCompleted: 0,
2586
+
2587
+ };
2588
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2589
+ let filters =[
2590
+ { fileDateISO: { $gte: dateRange.start } },
2591
+ { fileDateISO: { $lte: dateRange.end } },
2592
+ { moduleType: { $eq: inputData.moduleType },
2593
+ },
2594
+ ];
2595
+ if ( inputData.clientId.length > 0 ) {
2596
+ filters.push( { clientId: { $in: inputData.clientId } } );
2597
+ }
2598
+ const storeQuery = inputData.clientId.length? { 'edge.firstFile': true, 'clientId': { $in: inputData. clientId } } : { 'edge.firstFile': true };
2599
+ temp.installedStores = await countDocumentsStore( storeQuery );
2600
+ const auditClientDataQuery =[
2601
+ {
2602
+ $match: {
2603
+ $and: filters,
2604
+ },
2605
+
2606
+ },
2607
+ {
2608
+ $group: {
2609
+ _id: null,
2610
+ totalFilesCount: { $sum: 1 },
2611
+ },
2612
+ },
2613
+ {
2614
+ $project: {
2615
+ _id: 0,
2616
+ totalFilesCount: 1,
2617
+ },
2618
+ },
2619
+ ];
2620
+ const auditClientData = await aggregateTraxAuditData( auditClientDataQuery );
2621
+ if ( auditClientData.length >0 ) {
2622
+ temp.auditStores = auditClientData[0].totalFilesCount;
2623
+ }
2624
+ const storeAuditQuery =[
2625
+ {
2626
+ $match: {
2627
+ $and: filters,
2628
+ },
2629
+
2630
+ },
2631
+ {
2632
+ $project: {
2633
+ completedStores: { $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ] },
2634
+ auditInprogress: { $cond: [ { $and: [ { $in: [ '$status', [ 'inprogress' ] ] }, { $eq: [ '$auditType', 'Audit' ] } ] }, 1, 0 ] },
2635
+ reAuditInprogress: { $cond: [ { $and: [ { $in: [ '$status', [ 'inprogress' ] ] }, { $eq: [ '$auditType', 'ReAudit' ] } ] }, 1, 0 ] },
2636
+ draft: { $cond: [ { $eq: [ '$status', 'drafted' ] }, 1, 0 ] },
2637
+ assigned: { $cond: [ { $eq: [ '$status', 'assigned' ] }, 1, 0 ] },
2638
+ exceptNoAssigned: { $cond: { if: { $not: { $in: [ '$status', [ 'skipped', 'not_assign' ] ] } }, then: 1, else: 0 } },
2639
+ auditCompleted: { $cond: [ { $and: [ { $in: [ '$status', [ 'completed' ] ] }, { $eq: [ '$auditType', 'Audit' ] } ] }, 1, 0 ] },
2640
+ reAuditCompleted: { $cond: [ { $and: [ { $in: [ '$status', [ 'completed' ] ] }, { $eq: [ '$auditType', 'ReAudit' ] } ] }, 1, 0 ] },
2641
+
2642
+
2643
+ },
2644
+ },
2645
+ {
2646
+ $group: {
2647
+ _id: null,
2648
+ completedStores: { $sum: '$completedStores' },
2649
+ auditInprogress: { $sum: '$auditInprogress' },
2650
+ reAuditInprogress: { $sum: '$reAuditInprogress' },
2651
+ draft: { $sum: '$draft' },
2652
+ assigned: { $sum: '$assigned' },
2653
+ exceptNoAssigned: { $sum: '$exceptNoAssigned' },
2654
+ auditCompleted: { $sum: '$auditCompleted' },
2655
+ reAuditCompleted: { $sum: '$reAuditCompleted' },
2656
+ },
2657
+ },
2658
+ {
2659
+ $project: {
2660
+ completedStores: 1,
2661
+ inprogressStores: { $subtract: [ temp.auditStores, '$completedStores' ] },
2662
+ auditInprogress: 1,
2663
+ reAuditInprogress: 1,
2664
+ draft: 1,
2665
+ assigned: 1,
2666
+ exceptNoAssigned: { $subtract: [ temp.auditStores, '$exceptNoAssigned' ] },
2667
+ auditCompleted: 1,
2668
+ reAuditCompleted: 1,
2669
+ },
2670
+ },
2671
+ ];
2672
+ const storeAudit = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )?await aggregateStoreEmpDetection( storeAuditQuery ) : await aggregateBinaryAudit( storeAuditQuery );
2673
+ if ( storeAudit.length > 0 ) {
2674
+ temp.inprogressStores= storeAudit[0].inprogressStores;
2675
+ temp.completedStores = storeAudit[0].completedStores;
2676
+ temp.auditInprogress = storeAudit[0].auditInprogress;
2677
+ temp.reAuditInprogress = storeAudit[0].reAuditInprogress;
2678
+ temp.draft = storeAudit[0].draft;
2679
+ temp.assigned = storeAudit[0].assigned;
2680
+ temp.notAssigned = storeAudit[0].exceptNoAssigned;
2681
+ temp.auditCompleted = storeAudit[0].auditCompleted;
2682
+ temp.reAuditCompleted = storeAudit[0].reAuditCompleted;
2683
+ }
2684
+
2685
+ return res.sendSuccess( { result: temp } );
2686
+ } catch ( error ) {
2687
+ const err = error.message || 'Internal Server Error';
2688
+ logger.error( { error: error, message: req.body, function: 'overAllAuditSummary' } );
2689
+ return res.sendError( err, 500 );
2690
+ }
2691
+ }
2692
+
2693
+ export async function summarySplit( req, res ) {
2694
+ try {
2695
+ const inputData = req.body;
2696
+ const temp = {
2697
+ total: 0,
2698
+ auditInprogress: 0,
2699
+ reAuditInprogress: 0,
2700
+ draft: 0,
2701
+ assigned: 0,
2702
+ auditCompleted: 0,
2703
+ reAuditCompleted: 0,
2704
+ };
2705
+
2706
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2707
+ let filters =[
2708
+ { fileDateISO: { $gte: dateRange.start } },
2709
+ { fileDateISO: { $lte: dateRange.end } },
2710
+ { moduleType: { $eq: inputData.moduleType } },
2711
+ ];
2712
+ if ( inputData.clientId.length > 0 ) {
2713
+ filters.push( { clientId: { $in: inputData.clientId } } );
2714
+ }
2715
+ const query =[
2716
+ {
2717
+ $match: {
2718
+ $and: filters,
2719
+ },
2720
+
2721
+ },
2722
+ {
2723
+ $project: {
2724
+ auditInprogress: {
2725
+ $cond: [
2726
+ { $and: [ { $eq: [ '$auditType', 'Audit' ] }, { $eq: [ '$status', 'inprogress' ] } ] }, 1, 0,
2727
+ ],
2728
+ },
2729
+ reAuditInprogress: {
2730
+ $cond: [
2731
+ { $and: [ { $eq: [ '$auditType', 'ReAudit' ] }, { $eq: [ '$status', 'inprogress' ] } ] }, 1, 0,
2732
+ ],
2733
+ },
2734
+ draft: {
2735
+ $cond: [
2736
+ { $eq: [ '$status', 'drafted' ] }, 1, 0,
2737
+ ],
2738
+ },
2739
+ assigned: {
2740
+ $cond: [
2741
+ { $eq: [ '$status', 'assigned' ] }, 1, 0,
2742
+ ],
2743
+ },
2744
+
2745
+ reAuditCompleted: {
2746
+ $cond: [
2747
+ { $and: [ { $eq: [ '$auditType', 'ReAudit' ] }, { $eq: [ '$status', 'completed' ] } ] }, 1, 0,
2748
+ ],
2749
+ },
2750
+ auditCompleted: {
2751
+ $cond: [
2752
+ { $and: [ { $eq: [ '$auditType', 'Audit' ] }, { $eq: [ '$status', 'completed' ] } ] }, 1, 0,
2753
+ ],
2754
+ },
2755
+ },
2756
+ },
2757
+ {
2758
+ $group: {
2759
+ _id: null,
2760
+ auditInprogress: { $sum: '$auditInprogress' },
2761
+ reAuditInprogress: { $sum: '$reAuditInprogress' },
2762
+ draft: { $sum: '$draft' },
2763
+ assigned: { $sum: '$assigned' },
2764
+ reAuditCompleted: { $sum: '$reAuditCompleted' },
2765
+ auditCompleted: { $sum: '$auditCompleted' },
2766
+
2767
+ },
2768
+ },
2769
+ {
2770
+ $project: {
2771
+ _id: 0,
2772
+ totalInprogress: 1,
2773
+ auditInprogress: 1,
2774
+ reAuditInprogress: 1,
2775
+ draft: 1,
2776
+ assigned: 1,
2777
+ reAuditCompleted: 1,
2778
+ auditCompleted: 1,
2779
+ totalCount: { $ifNull: [ 0, 0 ] },
2780
+
2781
+ },
2782
+ },
2783
+ ];
2784
+ const totalQuery = [
2785
+ {
2786
+ $match: {
2787
+ $and: filters,
2788
+ },
2789
+
2790
+ },
2791
+ {
2792
+ $group: {
2793
+ _id: null,
2794
+ total: { $sum: 1 },
2795
+ },
2796
+ },
2797
+ {
2798
+ $project: {
2799
+ _id: 0,
2800
+ total: 1,
2801
+ },
2802
+ },
2803
+ ];
2804
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateUserEmpDetection( query ) : await aggregateBinaryAudit( query );
2805
+ const totalCount = await aggregateTraxAuditData( totalQuery );
2806
+ result[0].totalCount = totalCount[0]?.total;
2807
+ return res.sendSuccess( { result: result.length> 0? result[0]: temp } );
2808
+ } catch ( error ) {
2809
+ const err = error.message || 'Internal Server Error';
2810
+ logger.error( { error: error, message: req.body, function: 'summarySplit' } );
2811
+ return res.sendError( err, 500 );
2812
+ }
2813
+ }
2814
+
2815
+ export async function overviewTable( req, res ) {
2816
+ try {
2817
+ const inputData = req.body;
2818
+ const limit = inputData.limit || 10;
2819
+ const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
2820
+ const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
2821
+ let filters =[
2822
+ { fileDateISO: { $gte: dateRange.start } },
2823
+ { fileDateISO: { $lte: dateRange.end } },
2824
+ { moduleType: { $eq: inputData.moduleType } },
2825
+
2826
+ ];
2827
+
2828
+ if ( inputData.clientId.length > 0 ) {
2829
+ filters.push( { clientId: { $in: inputData.clientId } } );
2830
+ }
2831
+
2832
+ if ( inputData.filterByAuditType.length > 0 ) {
2833
+ filters.push( { auditType: { $in: inputData.filterByAuditType } } );
2834
+ }
2835
+
2836
+ if ( inputData.filterByStatus.length > 0 ) {
2837
+ filters.push( { status: { $in: inputData.filterByStatus } } );
2838
+ }
2839
+
2840
+ const query =[
2841
+ {
2842
+ $match: {
2843
+ $and: filters,
2844
+ },
2845
+
2846
+ },
2847
+ {
2848
+ $project: {
2849
+ _id: 0,
2850
+ storeId: 1,
2851
+ clientId: 1,
2852
+ streamName: 1,
2853
+ tempId: 1,
2854
+ question: 1,
2855
+ questionType: 1,
2856
+ answer: 1,
2857
+ userComments: 1,
2858
+ fileDate: 1,
2859
+ moduleType: 1,
2860
+
2861
+ value: {
2862
+ $replaceAll: { input: '$moduleType', find: '-', replacement: ' ' },
2863
+ },
2864
+ beforeCount: 1,
2865
+ afterCount: 1,
2866
+ auditType: 1,
2867
+ status: 1,
2868
+ auditStatus: 1,
2869
+ // userId: 1,
2870
+ },
2871
+ },
2872
+ // {
2873
+ // $lookup: {
2874
+ // from: 'users',
2875
+ // let: { userId: '$userId' },
2876
+ // pipeline: [
2877
+ // {
2878
+ // $match: {
2879
+ // $expr: {
2880
+ // $eq: [ '$_id', '$$userId' ],
2881
+ // },
2882
+ // },
2883
+ // },
2884
+ // {
2885
+ // $project: {
2886
+ // userName: 1,
2887
+ // userEmail: '$email',
2888
+ // },
2889
+ // },
2890
+ // ], as: 'user',
2891
+ // },
2892
+ // },
2893
+ // {
2894
+ // $unwind: {
2895
+ // path: '$user',
2896
+ // preserveNullAndEmptyArrays: true,
2897
+ // },
2898
+ // },
2899
+ {
2900
+ $project: {
2901
+ storeId: 1,
2902
+ clientId: 1,
2903
+ streamName: 1,
2904
+ tempId: 1,
2905
+ question: 1,
2906
+ questionType: 1,
2907
+ answer: 1,
2908
+ userComments: 1,
2909
+ fileDate: 1,
2910
+ moduleType: 1,
2911
+ value: 1,
2912
+ beforeCount: 1,
2913
+ afterCount: 1,
2914
+ auditType: 1,
2915
+ status: 1,
2916
+ auditStatus: 1,
2917
+ // userName: '$user.userName',
2918
+ // userEmail: '$user.userEmail',
2919
+
2920
+ },
2921
+ },
2922
+ ];
2923
+ if ( inputData.searchValue && inputData.searchValue!== '' ) {
2924
+ query.push( {
2925
+ $match: {
2926
+ $or: [
2927
+ { storeId: { $regex: inputData.searchValue, $options: 'i' } },
2928
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
2929
+ { fileDate: { $regex: inputData.searchValue, $options: 'i' } },
2930
+ { auditType: { $regex: inputData.searchValue, $options: 'i' } },
2931
+ { status: { $regex: inputData.searchValue, $options: 'i' } },
2932
+ { auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
2933
+ { value: { $regex: inputData.searchValue, $options: 'i' } },
2934
+ { streamName: { $regex: inputData.searchValue, $options: 'i' } },
2935
+ { tempId: { $regex: inputData.searchValue, $options: 'i' } },
2936
+ { question: { $regex: inputData.searchValue, $options: 'i' } },
2937
+ { answer: { $regex: inputData.searchValue, $options: 'i' } },
2938
+ { userComments: { $regex: inputData.searchValue, $options: 'i' } },
2939
+ // { userName: { $regex: inputData.searchValue, $options: 'i' } },
2940
+ // { userEmail: { $regex: inputData.searchValue, $options: 'i' } },
2941
+ ],
2942
+
2943
+ },
2944
+ } );
2945
+ }
2946
+ if ( inputData.sortColumnName ) {
2947
+ const sortBy = inputData.sortBy || -1;
2948
+ const sortColumn = inputData.sortColumnName;
2949
+ query.push( {
2950
+ $sort: { [sortColumn]: sortBy },
2951
+ },
2952
+ );
2953
+ }
2954
+ const count = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateStoreEmpDetection( query ) : await aggregateBinaryAudit( query );
2955
+ if ( count.length == 0 ) {
2956
+ return res.sendError( 'No Data Found', 204 );
2957
+ }
2958
+
2959
+ if ( inputData.isExport ) {
2960
+ query.push( { $limit: 10000 } );
2961
+ } else {
2962
+ query.push( {
2963
+ $skip: offset,
2964
+ },
2965
+ {
2966
+ $limit: limit,
2967
+ } );
2968
+ }
2969
+ const result = inputData.moduleType.includes( [ 'uniform-detection', 'mobile-detection' ] )? await aggregateStoreEmpDetection( query ) : await aggregateBinaryAudit( query );
2970
+ if ( inputData.isExport ) {
2971
+ const exportdata = [];
2972
+ result.forEach( ( element ) => {
2973
+ const temp ={
2974
+ 'Store ID': element.storeId,
2975
+ 'Brand ID': element.clientId,
2976
+ 'File Date': element.fileDate,
2977
+ 'Result': element.answer,
2978
+ 'Product Type': element.value,
2979
+ 'Audit Type': element.auditType,
2980
+ // 'User Name': element.userName,
2981
+ // 'User Email': element.userEmail,
2982
+ 'Status': element.status,
2983
+ 'Audit Status': element.status,
2984
+ };
2985
+
2986
+ switch ( inputData.moduleType ) {
2987
+ case 'camera-angle-change':
2988
+ temp['stream Name'] = element.streamName;
2989
+ temp['User Comments'] = element.userCommands;
2990
+ break;
2991
+ case 'unattended-customer':
2992
+ temp['Customer ID'] = element.tempId;
2993
+ temp['Question'] = element.question;
2994
+ temp['User Comments'] = element.userCommands;
2995
+ break;
2996
+ case 'left-in-middle':
2997
+ temp['Question'] = element.question;
2998
+ temp['User Comments'] = element.userCommands;
2999
+ break;
3000
+ case 'mobile-detection':
3001
+ temp['Before Count'] = element.beforeCount;
3002
+ temp['After Count'] = element.afterCount;
3003
+ break;
3004
+ case 'uniform-detection':
3005
+ temp['Before Count'] = element.beforeCount;
3006
+ temp['After Count'] = element.afterCount;
3007
+ break;
3008
+ }
3009
+ exportdata.push( temp );
3010
+ } );
3011
+ await download( exportdata, res );
3012
+ return;
3013
+ }
3014
+ return res.sendSuccess( { result: result, count: count.length } );
3015
+ } catch ( error ) {
3016
+ const err = error.message || 'Internal Server Error';
3017
+ logger.error( { error: error, message: req.body, function: 'overviewTable' } );
3018
+ return res.sendError( err, 500 );
3019
+ }
3020
+ }