tango-app-api-audit 1.0.35 → 1.0.36

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/.eslintrc.cjs CHANGED
@@ -36,7 +36,7 @@ module.exports = {
36
36
  'no-unused-vars': 'error',
37
37
  'new-cap': [ 'error', { 'newIsCap': true, 'capIsNew': false } ],
38
38
  'prefer-const': 'off',
39
- // 'no-console': 'error',
39
+ 'no-console': 'error',
40
40
  },
41
41
  };
42
42
 
package/README.md CHANGED
@@ -1,29 +1,29 @@
1
- # README #
2
-
3
- This README would normally document whatever steps are necessary to get your application up and running.
4
-
5
- ### What is this repository for? ###
6
-
7
- * Quick summary
8
- * Version
9
- * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
10
-
11
- ### How do I get set up? ###
12
-
13
- * Summary of set up
14
- * Configuration
15
- * Dependencies
16
- * Database configuration
17
- * How to run tests
18
- * Deployment instructions
19
-
20
- ### Contribution guidelines ###
21
-
22
- * Writing tests
23
- * Code review
24
- * Other guidelines
25
-
26
- ### Who do I talk to? ###
27
-
28
- * Repo owner or admin
1
+ # README #
2
+
3
+ This README would normally document whatever steps are necessary to get your application up and running.
4
+
5
+ ### What is this repository for? ###
6
+
7
+ * Quick summary
8
+ * Version
9
+ * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
10
+
11
+ ### How do I get set up? ###
12
+
13
+ * Summary of set up
14
+ * Configuration
15
+ * Dependencies
16
+ * Database configuration
17
+ * How to run tests
18
+ * Deployment instructions
19
+
20
+ ### Contribution guidelines ###
21
+
22
+ * Writing tests
23
+ * Code review
24
+ * Other guidelines
25
+
26
+ ### Who do I talk to? ###
27
+
28
+ * Repo owner or admin
29
29
  * Other community or team contact
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "tango-app-api-audit",
3
- "version": "1.0.35",
4
- "description": "audit & audit metrics apis",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && app index.js\""
9
- },
10
- "engines": {
11
- "node": ">=18.10.0"
12
- },
13
- "author": "praveenraj",
14
- "license": "ISC",
15
- "dependencies": {
16
- "adm-zip": "^0.5.15",
17
- "aws-sdk": "^2.1643.0",
18
- "dayjs": "^1.11.11",
19
- "dotenv": "^16.4.5",
20
- "express": "^4.19.2",
21
- "handlebars": "^4.7.8",
22
- "joi-to-swagger": "^6.2.0",
23
- "lodash": "^4.17.21",
24
- "mongodb": "^6.7.0",
25
- "nodemon": "^3.1.3",
26
- "swagger-ui-express": "^5.0.1",
27
- "tango-api-schema": "^2.0.143",
28
- "tango-app-api-middleware": "^3.1.28",
29
- "winston": "^3.13.0",
30
- "winston-daily-rotate-file": "^5.0.0"
31
- },
32
- "devDependencies": {
33
- "eslint": "^8.57.0",
34
- "eslint-config-google": "^0.14.0",
35
- "eslint-config-semistandard": "^17.0.0",
36
- "eslint-config-standard": "^17.1.0",
37
- "eslint-plugin-import": "^2.29.1",
38
- "eslint-plugin-promise": "^6.2.0"
39
- }
40
- }
1
+ {
2
+ "name": "tango-app-api-audit",
3
+ "version": "1.0.36",
4
+ "description": "audit & audit metrics apis",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
+ },
10
+ "engines": {
11
+ "node": ">=18.10.0"
12
+ },
13
+ "author": "praveenraj",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "adm-zip": "^0.5.15",
17
+ "aws-sdk": "^2.1643.0",
18
+ "dayjs": "^1.11.11",
19
+ "dotenv": "^16.4.5",
20
+ "express": "^4.19.2",
21
+ "handlebars": "^4.7.8",
22
+ "joi-to-swagger": "^6.2.0",
23
+ "lodash": "^4.17.21",
24
+ "mongodb": "^6.7.0",
25
+ "nodemon": "^3.1.3",
26
+ "swagger-ui-express": "^5.0.1",
27
+ "tango-api-schema": "^2.0.144",
28
+ "tango-app-api-middleware": "^3.1.28",
29
+ "winston": "^3.13.0",
30
+ "winston-daily-rotate-file": "^5.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "eslint": "^8.57.0",
34
+ "eslint-config-google": "^0.14.0",
35
+ "eslint-config-semistandard": "^17.0.0",
36
+ "eslint-config-standard": "^17.1.0",
37
+ "eslint-plugin-import": "^2.29.1",
38
+ "eslint-plugin-promise": "^6.2.0"
39
+ }
40
+ }
@@ -1,11 +1,15 @@
1
- import { getUTC, insertOpenSearchData, listFileByPath, signedUrl, sqsReceive } from 'tango-app-api-middleware';
1
+ import { 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';
5
- import { createStoreZoneAudit } from '../service/storeZoneAudit.service.js';
5
+ import { aggregateStoreZoneAudit, createStoreZoneAudit, findOneStoreZoneAudit, updateOneStoreZoneAudit } from '../service/storeZoneAudit.service.js';
6
6
  import { findOneUser } from '../service/user.service.js';
7
7
  import { findOneStore } from '../service/store.service.js';
8
8
  import dayjs from 'dayjs';
9
+ import { aggregateUserAudit, findOneUserAudit, updateOneUserAudit } from '../service/userAudit.service.js';
10
+ import { aggregateAssignAudit } from '../service/assignAudit.service.js';
11
+ import { createAuditLog, findOneAuditLog } from '../service/auditLog.service.js';
12
+ import { mapCustomer, mapEmployee, mapJunk, splitB20000, splitE0, splitG20000 } from '../validation/audit.validation.js';
9
13
 
10
14
  export async function getZoneAuditFile( req, res ) {
11
15
  try {
@@ -39,7 +43,6 @@ export async function getZoneAuditFile( req, res ) {
39
43
  },
40
44
  ];
41
45
  const userDetails = await aggregateZoneUserAudit( userQuery );
42
- console.log( userDetails, 'zoneAuditStatus==>' );
43
46
  const zoneAuditStatus =
44
47
  userDetails && userDetails.length > 0 ? userDetails[0].auditStatus : null;
45
48
 
@@ -64,13 +67,11 @@ export async function getZoneAuditFile( req, res ) {
64
67
  ];
65
68
 
66
69
  const userAssign = await aggregateAssignZoneAudit( query );
67
- console.log( userAssign, 'userAssign' );
68
70
  if ( userAssign.length > 0 ) {
69
71
  logger.info( 'Hit in user assign', { inputData } );
70
72
  } else {
71
73
  logger.info( 'Hit in new file', { inputData } );
72
74
  const consumer = await sqsReceive( inputData.queueName );
73
- console.log( consumer, 'consumer' );
74
75
  if ( !consumer ) {
75
76
  logger.error( {
76
77
  error: consumer,
@@ -194,13 +195,10 @@ export async function getZoneAuditFile( req, res ) {
194
195
  zoneName: msg.zone_id,
195
196
 
196
197
  };
197
- console.log( record );
198
- console.log( storeRecord );
199
198
  insertData = await createZoneUserAudit( record );
200
199
  await createStoreZoneAudit( storeRecord );
201
200
  } else {
202
201
  insertData = userDetails[0];
203
- console.log( insertData );
204
202
  }
205
203
  } else {
206
204
  logger.error( {
@@ -316,7 +314,7 @@ export async function saveDraft( req, res ) {
316
314
  const logData = {
317
315
  userId: req.user._id,
318
316
  userName: req.user.userName,
319
- logType: 'audit',
317
+ logType: 'zoneAudit',
320
318
  logSubType: 'auditDraft',
321
319
  logData: {
322
320
  auditType: inputData.auditType,
@@ -331,7 +329,7 @@ export async function saveDraft( req, res ) {
331
329
  }
332
330
  await createAuditLog( inputData );
333
331
  await updateOneUserAudit( userQuery, userRecord );
334
- await updateOneStoreAudit( storeQuery, storeRecord );
332
+ await updateOneStoreZoneAudit( storeQuery, storeRecord );
335
333
  return res.sendSuccess( {
336
334
  result: 'The file has been drafted successfully',
337
335
  } );
@@ -341,3 +339,558 @@ export async function saveDraft( req, res ) {
341
339
  return res.sendError( err, 500 );
342
340
  }
343
341
  }
342
+
343
+ export async function getDraftedData( req, res ) {
344
+ try {
345
+ const inputData = req.query;
346
+ const userId = inputData.userId || req.user._id;
347
+ const query = {
348
+ fileDate: inputData.fileDate,
349
+ storeId: inputData.storeId,
350
+ zoneName: inputData.zoneName,
351
+ moduleType: 'zone',
352
+ userId: userId,
353
+ };
354
+ const result = await findOneAuditLog( query, {}, { createdAt: -1 }, 1 );
355
+
356
+ if ( result.length == 0 ) {
357
+ return res.sendError( 'No Data Found', 500 );
358
+ }
359
+ return res.sendSuccess( { result: result } );
360
+ } catch ( error ) {
361
+ const err = error.message || 'Internal Server Error';
362
+ logger.error( {
363
+ error: error,
364
+ message: req.query,
365
+ function: 'getDraftedData',
366
+ } );
367
+ return res.sendError( err, 500 );
368
+ }
369
+ }
370
+
371
+ export async function save( req, res ) {
372
+ try {
373
+ const bucket = JSON.parse( process.env.BUCKET );
374
+ const sqs = JSON.parse( process.env.SQS );
375
+
376
+ const inputData = req.body;
377
+ const params = {
378
+ Key: `${inputData.storeId}/${inputData.zoneName}/${inputData.fileDate}/${bucket.masterJsonFile}`,
379
+ };
380
+
381
+ if ( inputData.auditType === 'ReAudit' ) {
382
+ params.Bucket = bucket.auditUploadBucket;
383
+ } else {
384
+ params.Bucket = bucket.masterJson;
385
+ }
386
+ const fileData = await getJsonFileData( params );
387
+
388
+ if ( fileData?.statusCode ) {
389
+ logger.error( {
390
+ error: `ERROR IN UPLOAD PATH: ${inputData.storeId}/${inputData.zoneName}/${inputData.fileDate}/${bucket.masterJsonFile}`,
391
+ type: 'UPLOAD_ERROR',
392
+ } );
393
+ return res.sendError( fileData, 500 );
394
+ }
395
+
396
+ const masterJsonData = JSON.parse( fileData.toString( 'utf-8' ) );
397
+
398
+ const [ G20000, B20000, E0 ] = await Promise.all( [
399
+ splitG20000( masterJsonData.person_data ),
400
+ splitB20000( masterJsonData.person_data ),
401
+ splitE0( masterJsonData.person_data ),
402
+ ] );
403
+
404
+ const [ mappingData ] = await Promise.all( [
405
+ mapEmployee( B20000, inputData.employee ),
406
+ mapJunk( B20000, inputData.junk ),
407
+ mapCustomer( B20000, inputData.customer ),
408
+ ] );
409
+
410
+ const tempData = _.sortBy( [ ...mappingData, ...G20000, ...E0 ], 'index' );
411
+
412
+ const tempObject = { person_data: tempData };
413
+
414
+ const uploadDataParams = {
415
+ Bucket: bucket.auditUploadBucket,
416
+ Key: `${inputData.storeId}/${inputData.zoneName}/${inputData.fileDate}/`,
417
+ ContentType: 'application/json',
418
+ fileName: `${bucket.masterJsonFile}`,
419
+ body: JSON.stringify( tempObject ),
420
+ };
421
+ const mappingUpload = await fileUpload( uploadDataParams );
422
+
423
+ if ( mappingUpload?.statusCode ) {
424
+ logger.error( {
425
+ error: `ERROR IN UPLOAD PATH: ${inputData.storeId}/${inputData.fileDate}/${bucket.masterJsonFile}`,
426
+ type: 'UPLOAD_ERROR',
427
+ } );
428
+ return res.sendError( mappingUpload, 500 );
429
+ }
430
+
431
+ let getUserAuditData = await findOneUserAudit( {
432
+ _id: new mongoose.Types.ObjectId( inputData.auditId ),
433
+ } );
434
+ const isoDate = getUserAuditData.startTime;
435
+ const currentTime = dayjs();
436
+ const isoDateTime = dayjs( isoDate );
437
+ const timeDifferenceInMinutes = currentTime.diff( isoDateTime, 'seconds' );
438
+
439
+ await updateOneUserAudit(
440
+ { _id: new mongoose.Types.ObjectId( inputData.auditId ) },
441
+ {
442
+ auditStatus: 'completed',
443
+ endTime: Date.now(),
444
+ isDraft: false,
445
+ afterCount: inputData.customerCount,
446
+ timeSpent: timeDifferenceInMinutes,
447
+ },
448
+ );
449
+
450
+ /** *
451
+ *
452
+ * logs need to be added
453
+ *
454
+ *
455
+ */
456
+
457
+ let storeConfig = await findOneStore(
458
+ {
459
+ storeId: getUserAuditData.storeId,
460
+ },
461
+ {
462
+ auditConfigs: 1,
463
+ clientId: 1,
464
+ },
465
+ );
466
+ let storeAuditData = await findOneStoreZoneAudit( {
467
+ storeId: inputData.storeId,
468
+ zoneName: inputData.zoneName,
469
+ fileDate: inputData.fileDate,
470
+ } );
471
+
472
+ let clientData = await findClient( { clientId: storeConfig.clientId } );
473
+
474
+ if ( (
475
+ ( storeAuditData.beforeCount - inputData.customerCount ) /
476
+ storeAuditData.beforeCount <
477
+ storeConfig.auditConfigs.ratio
478
+ ) && inputData.auditType == 'Audit' ) {
479
+ logger.info(
480
+ `Hit in Reaudit pushing queue Store Id=${inputData.storeId},File Date=${inputData.fileDate}, /n \nQueue Name = ${clientData[0].auditConfigs.queueName}`,
481
+ 'Reaudit',
482
+ );
483
+
484
+ const sqsProduceQueue = {
485
+ QueueUrl: `${sqs.url}${clientData[0].auditConfigs.queueName}`,
486
+ MessageBody: JSON.stringify( {
487
+ store_id: inputData.storeId,
488
+ zone_id: inputData.zoneName,
489
+ audit_type: 'ReAudit',
490
+ curr_date: inputData.fileDate,
491
+ total_count: inputData.customerCount,
492
+ before_count: storeAuditData.beforeCount,
493
+ } ),
494
+ };
495
+ const sqsQueue = await sendMessageToQueue( sqsProduceQueue.QueueUrl, sqsProduceQueue.MessageBody );
496
+ logger.info( { sqsQueue: sqsQueue } );
497
+
498
+ if ( sqsQueue.statusCode ) {
499
+ logger.error( {
500
+ error: `ERROR IN UPLOAD PATH: ${inputData.storeId}/${inputData.fileDate}/${bucket.masterJsonFile}`,
501
+ type: 'UPLOAD_ERROR',
502
+ } );
503
+ return res.sendError( mappingUpload, 500 );
504
+ }
505
+
506
+ await updateOneStoreZoneAudit( { storeId: inputData.storeId, zoneName: inputData.zoneName },
507
+ {
508
+ status: 'not_assign',
509
+ afterCount: inputData.customerCount,
510
+ auditType: 'ReAudit',
511
+ timeSpent: timeDifferenceInMinutes,
512
+ } );
513
+ } else {
514
+ logger.info( 'Hit in Features', { data: ( _.omit( inputData, [ 'junk', 'employee', 'customer' ] ) ) } );
515
+ await updateOneStoreZoneAudit( { storeId: inputData.storeId, zoneName: inputData.zoneName },
516
+ {
517
+ status: 'completed',
518
+ afterCount: inputData.customerCount,
519
+ timeSpent: timeDifferenceInMinutes,
520
+ } );
521
+
522
+ const sqsProduceQueue = {
523
+ QueueUrl: `${sqs.url}${sqs.feature}`,
524
+
525
+ MessageBody: JSON.stringify( {
526
+ store_id: inputData.storeId,
527
+ zone_id: inputData.zoneName,
528
+ store_date: inputData.fileDate,
529
+ bucket_name: `${bucket.auditUploadBucket}`,
530
+ process_type: 'audit',
531
+ } ),
532
+ };
533
+ logger.info( { sqsProduceQueue: sqsProduceQueue } );
534
+ const sqsQueue = await sendMessageToQueue( sqsProduceQueue.QueueUrl, sqsProduceQueue.MessageBody );
535
+ logger.info( { sqsQueue: sqsQueue } );
536
+ }
537
+
538
+ return res.sendSuccess( { result: 'Updated Successfully' } );
539
+ } catch ( error ) {
540
+ const err = error.message || 'Internal Server Error';
541
+ logger.error( { error: error, message: req.body, function: 'save' } );
542
+ return res.sendError( err );
543
+ }
544
+ }
545
+
546
+ export async function workSpace( req, res ) {
547
+ try {
548
+ const inputData = req.query;
549
+ const limit = inputData.limit || 10;
550
+ const offset = inputData.offset ?
551
+ ( inputData.offset - 1 ) * inputData.limit : 0;
552
+ const dateRange = await getUTC( new Date(), new Date() );
553
+
554
+ const temp = [];
555
+ const clientQuery = [
556
+ {
557
+ $match: {
558
+ $and: [
559
+ { status: { $in: [ 'active', 'hold' ] } },
560
+ { 'auditConfigs.audit': { $eq: true } }, // NOTE: modified the code need to check for enable zone
561
+ ],
562
+ },
563
+ },
564
+ {
565
+ $project: {
566
+ clientName: '$clientName',
567
+ clientId: '$clientId',
568
+ },
569
+ },
570
+ ];
571
+
572
+ if ( inputData.searchValue && inputData.searchValue !== '' ) {
573
+ clientQuery.push( {
574
+ $match: {
575
+ $or: [
576
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
577
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
578
+ ],
579
+ },
580
+ } );
581
+ }
582
+ const count = await aggregateClient( clientQuery );
583
+ logger.info( { count: count } );
584
+ if ( count?.length == 0 ) {
585
+ return res.sendError( 'No Data Found', 204 );
586
+ }
587
+
588
+ if ( inputData.limit && !inputData.isExport ) {
589
+ clientQuery.push( { $skip: offset }, { $limit: limit } );
590
+ }
591
+
592
+ const clientDetails = await aggregateClient( clientQuery );
593
+ const clientList = clientDetails.map( ( i ) => i.clientId );
594
+ const query = [
595
+ {
596
+ $match: {
597
+ $and: [
598
+ {
599
+ clientId: { $in: clientList },
600
+ },
601
+ {
602
+ moduleType: 'zone',
603
+ },
604
+ ],
605
+
606
+ },
607
+ },
608
+ {
609
+ $group: {
610
+ _id: '$clientId',
611
+ clientId: { $last: '$clientId' },
612
+ totalFilesCount: { $last: '$totalFilesCount' },
613
+ clientName: { $last: '$clientName' },
614
+ queueName: { $last: '$queueName' },
615
+ },
616
+ },
617
+ {
618
+ $project: {
619
+ clientId: 1,
620
+ totalFilesCount: 1,
621
+ clientName: 1,
622
+ queueName: 1,
623
+ },
624
+ },
625
+ ];
626
+
627
+ const fileDate = dayjs( dateRange.start ).subtract( 1, 'days' );
628
+
629
+ const completedFiles = [
630
+ {
631
+ $match: {
632
+ $and: [
633
+ { clientId: { $in: clientList } },
634
+ { fileDateISO: { $eq: new Date( fileDate ) } },
635
+ ],
636
+ },
637
+ },
638
+ {
639
+ $project: {
640
+ clientId: 1,
641
+ completed: {
642
+ $cond: [ { $eq: [ '$status', 'completed' ] }, 1, 0 ],
643
+ },
644
+ },
645
+ },
646
+ {
647
+ $group: {
648
+ _id: { clientId: '$clientId', storeId: '$storeId' },
649
+ clientId: { $first: '$clientId' },
650
+ completedCount: { $sum: '$completed' },
651
+ },
652
+ },
653
+ {
654
+ $group: {
655
+ _id: '$clientId',
656
+ clientId: { $first: '$clientId' },
657
+ completedCount: { $first: '$completedCount' },
658
+ },
659
+ },
660
+ ];
661
+
662
+ const auditFiles = [
663
+ {
664
+ $match: {
665
+ $and: [
666
+ { clientId: { $in: clientList } },
667
+ { moduleType: { $eq: 'zone' } },
668
+ { createdAt: { $gte: dateRange.start } },
669
+ { createdAt: { $lte: dateRange.end } },
670
+ ],
671
+ },
672
+ },
673
+ {
674
+ $project: {
675
+ clientId: 1,
676
+ pending: {
677
+ $cond: [
678
+ { $or: [ { $in: [ '$auditStatus', [ 'inprogress', 'drafted' ] ] } ] },
679
+ 1,
680
+ 0,
681
+ ],
682
+ },
683
+ },
684
+ },
685
+ {
686
+ $group: {
687
+ _id: { clientId: '$clientId', storeId: '$storeId' },
688
+ clientId: { $first: '$clientId' },
689
+ pendingCount: { $sum: '$pending' },
690
+ totalCount: { $sum: 1 },
691
+ },
692
+ },
693
+ {
694
+ $group: {
695
+ _id: '$clientId',
696
+ clientId: { $first: '$clientId' },
697
+ pendingCount: { $first: { $ifNull: [ '$pendingCount', 0 ] } },
698
+ totalCount: { $first: '$totalCount' },
699
+ },
700
+ },
701
+ ];
702
+
703
+ const draftedFiles = [
704
+ {
705
+ $match: {
706
+ $and: [
707
+ { clientId: { $in: clientList } },
708
+ { moduleType: { $eq: 'zone' } },
709
+ { userId: { $eq: inputData.userId } },
710
+ { createdAt: { $gte: dateRange.start } },
711
+ { createdAt: { $lte: dateRange.end } },
712
+ ],
713
+ },
714
+ },
715
+ {
716
+ $sort: {
717
+ updatedAt: -1,
718
+ },
719
+ },
720
+ {
721
+ $project: {
722
+ clientId: 1,
723
+ isDraft: 1,
724
+ draft: {
725
+ $cond: [ { $eq: [ '$auditStatus', 'drafted' ] }, 1, 0 ],
726
+ },
727
+ inprogress: {
728
+ $cond: [ { $eq: [ '$auditStatus', 'inprogress' ] }, 1, 0 ],
729
+ },
730
+ },
731
+ },
732
+ {
733
+ $group: {
734
+ _id: '$clientId',
735
+ clientId: { $first: '$clientId' },
736
+ isDrafted: { $first: '$isDraft' },
737
+ draftCount: { $sum: '$draft' },
738
+ inprogressCount: { $sum: '$inprogress' },
739
+ },
740
+ },
741
+ ];
742
+
743
+ const userAsign = [
744
+ {
745
+ $match: {
746
+ $and: [
747
+ { userId: { $eq: req.user._id } },
748
+ { isCompleted: false },
749
+ { clientId: { $in: clientList } },
750
+ { moduleType: { $eq: 'zone' } } ],
751
+ },
752
+ },
753
+ {
754
+ $group: {
755
+ _id: '$clientId',
756
+ clientId: { $first: '$clientId' },
757
+ asignedCount: { $sum: 1 },
758
+ },
759
+ },
760
+ {
761
+ $project: {
762
+ _id: 0,
763
+ clientId: 1,
764
+ asignedCount: 1,
765
+ },
766
+ },
767
+ ];
768
+
769
+ const clientAssign = [
770
+ {
771
+ $match: {
772
+ $and: [
773
+ { isCompleted: false },
774
+ { moduleType: { $eq: 'zone' } },
775
+ { clientId: { $in: clientList } },
776
+ ],
777
+ },
778
+ },
779
+ {
780
+ $group: {
781
+ _id: '$clientId',
782
+ clientId: { $first: '$clientId' },
783
+ ClientAsignedCount: { $sum: 1 },
784
+ },
785
+ },
786
+ {
787
+ $project: {
788
+ _id: 0,
789
+ clientId: 1,
790
+ ClientAsignedCount: { $ifNull: [ '$ClientAsignedCount', 0 ] },
791
+ },
792
+ },
793
+ ];
794
+
795
+ const auditDetails = await aggregateAuditClientData( query );
796
+ const auditCount = await aggregateUserAudit( auditFiles );
797
+ const draftedCount = await aggregateUserAudit( draftedFiles );
798
+ const CompletedCount = await aggregateStoreZoneAudit( completedFiles );
799
+
800
+ const clientAssignresult = await aggregateAssignAudit( clientAssign );
801
+ const userAsignCount = await aggregateAssignAudit( userAsign );
802
+ const mergeAll = _.merge(
803
+ _.keyBy( clientDetails, 'clientId' ),
804
+ _.keyBy( auditCount, 'clientId' ),
805
+ _.keyBy( draftedCount, 'clientId' ),
806
+ _.keyBy( clientAssignresult, 'clientId' ),
807
+ );
808
+ const finalResult = _.values( mergeAll );
809
+ const merge = _.values(
810
+ _.merge(
811
+ _.keyBy( finalResult, 'clientId' ),
812
+ _.keyBy( auditDetails, 'clientId' ),
813
+ _.keyBy( userAsignCount, 'clientId' ),
814
+ _.keyBy( CompletedCount, 'clientId' ),
815
+ ),
816
+ );
817
+ logger.info( { merge: merge } );
818
+ let totalStores = 0;
819
+ for ( let i = 0; i < merge.length; i++ ) {
820
+ totalStores = totalStores + merge[i].totalFilesCount;
821
+
822
+ const pending = await listQueue( merge[i].queueName );
823
+
824
+ if ( !pending.statusCode ) {
825
+ temp.push( {
826
+ clientId: merge[i].clientId,
827
+ clientName: merge[i].clientName,
828
+ completedCount: merge[i].completedCount ?
829
+ Number( merge[i].completedCount ) :
830
+ 0,
831
+ pendingByQueue: Number( pending ),
832
+ pendingByUser:
833
+ merge[i].pendingCount >= 0 ?
834
+ Number( merge[i].pendingCount ) +
835
+ ( merge[i].ClientAsignedCount ?
836
+ Number( merge[i].ClientAsignedCount ) :
837
+ 0 ) :
838
+ 0,
839
+ totalCount: merge[i].totalFilesCount,
840
+ queueName: merge[i].queueName,
841
+ isDraft: merge[i].isDrafted ? merge[i].isDrafted : false,
842
+ isEnable:
843
+ Number( pending ) > 0 ||
844
+ merge[i].isDrafted ||
845
+ ( merge[i].asignedCount && merge[i].asignedCount > 0 ) ||
846
+ ( merge[i].inprogressCount && merge[i].inprogressCount > 0 ) ?
847
+ true :
848
+ false,
849
+ completedRatio: merge[i].totalFilesCount ?
850
+ merge[i].completedCount ?
851
+ Math.round(
852
+ ( Number( merge[i].completedCount ) /
853
+ Number( merge[i].totalFilesCount ) ) *
854
+ 100,
855
+ ) :
856
+ 0 :
857
+ 0,
858
+ isAssigned:
859
+ merge[i].asignedCount && merge[i].asignedCount > 0 ? true : false,
860
+ Assignedcount:
861
+ merge[i].asignedCount && merge[i].asignedCount > 0 ?
862
+ merge[i].asignedCount :
863
+ 0,
864
+ } );
865
+ }
866
+ }
867
+
868
+ if ( inputData.isExport ) {
869
+ const exportdata = [];
870
+ temp.forEach( ( element ) => {
871
+ exportdata.push( {
872
+ 'Client Name': element.clientName,
873
+ 'Client Id': element.clientId,
874
+ 'Completed Percentage': element.completedRatio + ' %',
875
+ 'Pending Queue': element.pendingByQueue,
876
+ 'Pending User': element.pendingByUser,
877
+ 'Completed': element.completedCount,
878
+ 'Draft': element.isDraft ? 1 : 0,
879
+ 'Assigned': element.Assignedcount,
880
+ } );
881
+ } );
882
+ await download( exportdata, res );
883
+ return;
884
+ } else {
885
+ return res.sendSuccess( {
886
+ result: temp,
887
+ count: count.length,
888
+ totalStores: totalStores,
889
+ } );
890
+ }
891
+ } catch ( error ) {
892
+ const err = error.message || 'Internal Server Error';
893
+ logger.info( { error: error, message: req.query, function: 'workSpace' } );
894
+ return res.sendError( err, 500 );
895
+ }
896
+ }
@@ -1,10 +1,10 @@
1
1
  import j2s from 'joi-to-swagger';
2
- import { getFileSchema, saveDraftSchema } from '../dtos/zoneAudit.dtos.js';
2
+ import { getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, workSpaceSchema } from '../dtos/zoneAudit.dtos.js';
3
3
 
4
4
  export const zoneAuditDocs = {
5
- '/v3/zone/get-file': {
5
+ '/v3/zone-audit/get-file': {
6
6
  get: {
7
- tags: [ 'Zone' ],
7
+ tags: [ 'Zone Audit' ],
8
8
  description: 'Get a file via queue message',
9
9
  operationId: 'get-file',
10
10
  parameters: [
@@ -36,9 +36,9 @@ export const zoneAuditDocs = {
36
36
  },
37
37
  },
38
38
  },
39
- '/v3/audit/save-draft': {
39
+ '/v3/zone-audit/save-draft': {
40
40
  post: {
41
- tags: [ 'Zone' ],
41
+ tags: [ 'Zone Audit' ],
42
42
  description: `saved zone audited file. which is save in the mongo db`,
43
43
  operationId: 'save-draft',
44
44
  parameters: {},
@@ -58,95 +58,95 @@ export const zoneAuditDocs = {
58
58
  },
59
59
  },
60
60
  },
61
- // '/v3/audit/get-drafted-data': {
62
- // get: {
63
- // tags: [ 'Audit' ],
64
- // description: 'Get a saved file via DB',
65
- // operationId: 'get-drafted-data',
66
- // parameters: [
67
- // {
68
- // in: 'query',
69
- // name: 'fileDate',
70
- // scema: j2s( getDraftedDataSchema ).swagger,
71
- // require: true,
72
- // },
73
- // {
74
- // in: 'query',
75
- // name: 'storeId',
76
- // scema: j2s( getDraftedDataSchema ).swagger,
77
- // require: false,
78
- // },
79
- // ],
80
- // responses: {
81
- // 200: { description: 'Successful' },
82
- // 401: { description: 'Unauthorized User' },
83
- // 422: { description: 'Field Error' },
84
- // 500: { description: 'Server Error' },
85
- // 204: { description: 'Not Found' },
86
- // },
87
- // },
88
- // },
89
- // '/v3/audit/save': {
90
- // post: {
91
- // tags: [ 'Audit' ],
92
- // description: `submit the audit file. which is store in the bucket in the json format`,
93
- // operationId: 'save',
94
- // parameters: {},
95
- // requestBody: {
96
- // content: {
97
- // 'application/json': {
98
- // schema: j2s( saveSchema ).swagger,
99
- // },
100
- // },
101
- // },
102
- // responses: {
103
- // 200: { description: 'The Audited file has been submited successfully ' },
104
- // 401: { description: 'Unauthorized User' },
105
- // 422: { description: 'Field Error' },
106
- // 500: { description: 'Server Error' },
107
- // 204: { description: 'Not Found' },
108
- // },
109
- // },
110
- // },
111
- // '/v3/audit/work-space': {
112
- // get: {
113
- // tags: [ 'Audit' ],
114
- // description: 'queue wise info of audit files ',
115
- // operationId: 'work-space',
116
- // parameters: [
117
- // {
118
- // in: 'query',
119
- // name: 'searchValue',
120
- // scema: j2s( workSpaceSchema ).swagger,
121
- // require: false,
122
- // },
123
- // {
124
- // in: 'query',
125
- // name: 'offset',
126
- // scema: j2s( workSpaceSchema ).swagger,
127
- // require: false,
128
- // },
129
- // {
130
- // in: 'query',
131
- // name: 'limit',
132
- // scema: j2s( workSpaceSchema ).swagger,
133
- // require: false,
134
- // },
135
- // {
136
- // in: 'query',
137
- // name: 'isExport',
138
- // scema: j2s( workSpaceSchema ).swagger,
139
- // require: false,
140
- // },
141
- // ],
142
- // responses: {
143
- // 200: { description: 'Successful' },
144
- // 401: { description: 'Unauthorized User' },
145
- // 422: { description: 'Field Error' },
146
- // 500: { description: 'Server Error' },
147
- // 204: { description: 'Not Found' },
148
- // },
149
- // },
150
- // },
61
+ '/v3/zone-audit/get-drafted-data': {
62
+ get: {
63
+ tags: [ 'Zone Audit' ],
64
+ description: 'Get a saved file via DB',
65
+ operationId: 'get-drafted-data',
66
+ parameters: [
67
+ {
68
+ in: 'query',
69
+ name: 'fileDate',
70
+ scema: j2s( getDraftedDataSchema ).swagger,
71
+ require: true,
72
+ },
73
+ {
74
+ in: 'query',
75
+ name: 'storeId',
76
+ scema: j2s( getDraftedDataSchema ).swagger,
77
+ require: false,
78
+ },
79
+ ],
80
+ responses: {
81
+ 200: { description: 'Successful' },
82
+ 401: { description: 'Unauthorized User' },
83
+ 422: { description: 'Field Error' },
84
+ 500: { description: 'Server Error' },
85
+ 204: { description: 'Not Found' },
86
+ },
87
+ },
88
+ },
89
+ '/v3/zone-audit/save': {
90
+ post: {
91
+ tags: [ 'Zone Audit' ],
92
+ description: `submit the audit file. which is store in the bucket in the json format`,
93
+ operationId: 'save',
94
+ parameters: {},
95
+ requestBody: {
96
+ content: {
97
+ 'application/json': {
98
+ schema: j2s( saveSchema ).swagger,
99
+ },
100
+ },
101
+ },
102
+ responses: {
103
+ 200: { description: 'The Audited file has been submited successfully ' },
104
+ 401: { description: 'Unauthorized User' },
105
+ 422: { description: 'Field Error' },
106
+ 500: { description: 'Server Error' },
107
+ 204: { description: 'Not Found' },
108
+ },
109
+ },
110
+ },
111
+ '/v3/zone-audit/work-space': {
112
+ get: {
113
+ tags: [ 'Zone Audit' ],
114
+ description: 'queue wise info of audit files ',
115
+ operationId: 'work-space',
116
+ parameters: [
117
+ {
118
+ in: 'query',
119
+ name: 'searchValue',
120
+ scema: j2s( workSpaceSchema ).swagger,
121
+ require: false,
122
+ },
123
+ {
124
+ in: 'query',
125
+ name: 'offset',
126
+ scema: j2s( workSpaceSchema ).swagger,
127
+ require: false,
128
+ },
129
+ {
130
+ in: 'query',
131
+ name: 'limit',
132
+ scema: j2s( workSpaceSchema ).swagger,
133
+ require: false,
134
+ },
135
+ {
136
+ in: 'query',
137
+ name: 'isExport',
138
+ scema: j2s( workSpaceSchema ).swagger,
139
+ require: false,
140
+ },
141
+ ],
142
+ responses: {
143
+ 200: { description: 'Successful' },
144
+ 401: { description: 'Unauthorized User' },
145
+ 422: { description: 'Field Error' },
146
+ 500: { description: 'Server Error' },
147
+ 204: { description: 'Not Found' },
148
+ },
149
+ },
150
+ },
151
151
 
152
152
  };
@@ -38,3 +38,51 @@ export const saveDraftSchema = joi.object(
38
38
  export const saveDraftValid = {
39
39
  body: saveDraftSchema,
40
40
  };
41
+
42
+
43
+ export const saveSchema = joi.object(
44
+ {
45
+ auditId: joi.string().required(),
46
+ storeId: joi.string().required(),
47
+ zoneName: joi.string().required(),
48
+ fileDate: joi.string().required(),
49
+ auditType: joi.string().required(),
50
+ beforeCount: joi.number().required(),
51
+ junkCount: joi.number().required(),
52
+ junk: joi.array().required(),
53
+ employeeCount: joi.number().required(),
54
+ employee: joi.array().required(),
55
+ customerCount: joi.number().required(),
56
+ customer: joi.array().required(),
57
+ },
58
+ );
59
+
60
+ export const saveValid = {
61
+ body: saveSchema,
62
+ };
63
+
64
+ export const getDraftedDataSchema = joi.object(
65
+ {
66
+ storeId: joi.string().required(),
67
+ zoneName: joi.string().required(),
68
+ fileDate: joi.string().required(),
69
+ userId: joi.string().optional(),
70
+ },
71
+ );
72
+
73
+ export const getDraftedDataValid = {
74
+ query: getDraftedDataSchema,
75
+ };
76
+
77
+ export const workSpaceSchema = joi.object(
78
+ {
79
+ searchValue: joi.string().optional().allow( '' ),
80
+ offset: joi.string().optional(),
81
+ limit: joi.number().optional(),
82
+ isExport: joi.boolean().optional(),
83
+ },
84
+ );
85
+
86
+ export const workSpaceValid = {
87
+ query: workSpaceSchema,
88
+ };
@@ -1,11 +1,15 @@
1
1
  import { Router } from 'express';
2
- import { getFileValid, saveDraftValid } from '../dtos/zoneAudit.dtos.js';
3
- import { isExistsQueue } from '../validation/audit.validation.js';
2
+ import { getDraftedDataValid, getFileValid, saveDraftValid, saveValid, workSpaceValid } from '../dtos/zoneAudit.dtos.js';
3
+ import { isExistsQueue, validateUserAudit } from '../validation/audit.validation.js';
4
4
  import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
5
- import { getZoneAuditFile, saveDraft } from '../controllers/zoneAudit.controller.js';
5
+ import { getDraftedData, getZoneAuditFile, save, saveDraft, workSpace } from '../controllers/zoneAudit.controller.js';
6
6
 
7
7
  export const zoneAuditRouter=Router();
8
8
 
9
9
 
10
10
  zoneAuditRouter.get( '/get-file', isAllowedSessionHandler, validate( getFileValid ), isExistsQueue, getZoneAuditFile );
11
11
  zoneAuditRouter.post( '/save-draft', isAllowedSessionHandler, validate( saveDraftValid ), saveDraft );
12
+ zoneAuditRouter.get( '/get-drafted-data', isAllowedSessionHandler, validate( getDraftedDataValid ), getDraftedData );
13
+ zoneAuditRouter.post( '/save', isAllowedSessionHandler, validate( saveValid ), validateUserAudit, save );
14
+ zoneAuditRouter.get( '/work-space', isAllowedSessionHandler, validate( workSpaceValid ), workSpace );
15
+