tango-app-api-trax 3.9.29 → 3.9.30

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.
Files changed (48) hide show
  1. package/index.js +1 -2
  2. package/package.json +2 -2
  3. package/src/controllers/internalTrax.controller.js +73 -114
  4. package/src/controllers/mobileTrax.controller.js +29 -54
  5. package/src/controllers/trax.controller.js +1 -2
  6. package/src/controllers/traxDashboard.controllers.js +54 -63
  7. package/src/hbs/flag.hbs +1 -1
  8. package/src/hbs/login-otp.hbs +943 -943
  9. package/src/services/app.service.js +14 -20
  10. package/src/services/approver.service.js +20 -28
  11. package/src/services/authentication.service.js +6 -12
  12. package/src/services/camera.service.js +18 -24
  13. package/src/services/checklist.service.js +31 -36
  14. package/src/services/checklistAssign.service.js +39 -44
  15. package/src/services/checklistQuestion.service.js +35 -40
  16. package/src/services/checklistlog.service.js +35 -40
  17. package/src/services/clientRequest.service.js +5 -12
  18. package/src/services/clients.services.js +18 -23
  19. package/src/services/cluster.service.js +28 -36
  20. package/src/services/domain.service.js +28 -33
  21. package/src/services/download.services.js +38 -48
  22. package/src/services/group.service.js +22 -28
  23. package/src/services/lenskartEmployeeMapping.service.js +15 -20
  24. package/src/services/locus.service.js +34 -41
  25. package/src/services/notification.service.js +31 -40
  26. package/src/services/otp.service.js +17 -24
  27. package/src/services/planogram.service.js +5 -12
  28. package/src/services/processedTaskConfig.service.js +32 -40
  29. package/src/services/processedTaskList.service.js +30 -36
  30. package/src/services/processedchecklist.services.js +48 -56
  31. package/src/services/processedchecklistconfig.services.js +35 -40
  32. package/src/services/recurringFlagTracker.service.js +33 -40
  33. package/src/services/runAIFeatures.services.js +31 -36
  34. package/src/services/runAIRequest.services.js +39 -44
  35. package/src/services/store.service.js +31 -36
  36. package/src/services/tagging.service.js +5 -12
  37. package/src/services/taskConfig.service.js +32 -40
  38. package/src/services/teams.service.js +30 -41
  39. package/src/services/ticket.service.js +15 -20
  40. package/src/services/user.service.js +25 -32
  41. package/src/services/userAssignedstores.service.js +10 -17
  42. package/src/logging/activityLogFlusher.js +0 -59
  43. package/src/logging/activityLogMiddleware.js +0 -45
  44. package/src/logging/activityLogStore.js +0 -91
  45. package/src/logging/compressBatches.js +0 -83
  46. package/src/logging/config.js +0 -24
  47. package/src/logging/createLoggableService.js +0 -46
  48. package/src/logging/logExternalCall.js +0 -37
package/index.js CHANGED
@@ -9,6 +9,5 @@ import { mobileRouter } from './src/routes/mobileTrax.routes.js';
9
9
  import { internalTraxRouter } from './src/routes/internalTraxApi.router.js';
10
10
  import { locusOrderRouter } from './src/routes/locus.router.js';
11
11
  import { traxActivityLogRouter } from './src/routes/activityLog.router.js';
12
- import traxActivityLogMiddleware from './src/logging/activityLogMiddleware.js';
13
12
 
14
- export { traxDashboardRouter, traxFlagRouter, traxRouter, galleryRouter, downloadRouter, mobileRouter, internalTraxRouter, locusOrderRouter, traxActivityLogRouter, traxActivityLogMiddleware };
13
+ export { traxDashboardRouter, traxFlagRouter, traxRouter, galleryRouter, downloadRouter, mobileRouter, internalTraxRouter, locusOrderRouter, traxActivityLogRouter };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.9.29",
3
+ "version": "3.9.30",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "path": "^0.12.7",
31
31
  "puppeteer": "^24.39.1",
32
32
  "swagger-ui-express": "^5.0.1",
33
- "tango-api-schema": "^2.6.12",
33
+ "tango-api-schema": "^2.6.15",
34
34
  "tango-app-api-middleware": "^3.5.2",
35
35
  "url": "^0.11.4",
36
36
  "winston": "^3.13.1",
@@ -624,7 +624,6 @@ export async function PCLconfigCreation( req, res ) {
624
624
  element4.rawImageUpload = getCLconfig?.rawImageUpload || false;
625
625
  element4.rawVideoUpload = getCLconfig?.rawVideoUpload || false;
626
626
  element4.videoUploadTimeLimit = getCLconfig?.videoUploadTimeLimit || 0;
627
- element4.userVerification = getCLconfig?.userVerification;
628
627
  }
629
628
  if ( userIdList.length ) {
630
629
  allQuestion = allQuestion.filter( ( item ) => typeof item._id == 'undefined' );
@@ -1384,40 +1383,40 @@ export async function insertTimeDelayFlags( req, res ) {
1384
1383
  let updatedDetails = await processedchecklist.updateMany( { _id: { $in: checklistId } }, { timeFlag: 1 } );
1385
1384
 
1386
1385
 
1387
- // let notifyStores = await processedchecklist.find( { _id: { $in: checklistId }, notify: { $exists: false } } );
1388
-
1389
- // if ( notifyStores.length ) {
1390
- // Promise.all( notifyStores.map( async ( store ) => {
1391
- // let checklistDetails = await CLconfig.findOne( { _id: store.sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
1392
- // if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
1393
- // let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
1394
- // emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
1395
- // let data = {
1396
- // storeName: store.storeName,
1397
- // flagCount: 1,
1398
- // checklistName: store.checkListName?.trim(),
1399
- // submittedBy: '--',
1400
- // time: '--',
1401
- // domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
1402
- // type: 'delay',
1403
- // };
1404
- // const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
1405
- // const htmlContent = handlebars.compile( fileContent );
1406
- // const html = htmlContent( { data: data } );
1407
- // emailList.forEach( ( email ) => {
1408
- // let params = {
1409
- // toEmail: email,
1410
- // mailSubject: 'TangoEye | Checklist Flag',
1411
- // htmlBody: html,
1412
- // attachment: '',
1413
- // sourceEmail: JSON.parse( process.env.SES ).adminEmail,
1414
- // };
1415
- // sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1416
- // } );
1417
- // }
1418
- // await processedchecklist.updateOne( { _id: store._id }, { notify: true } );
1419
- // } ) );
1420
- // }
1386
+ let notifyStores = await processedchecklist.find( { _id: { $in: checklistId }, notify: { $exists: false } } );
1387
+
1388
+ if ( notifyStores.length ) {
1389
+ Promise.all( notifyStores.map( async ( store ) => {
1390
+ let checklistDetails = await CLconfig.findOne( { _id: store.sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
1391
+ if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
1392
+ let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
1393
+ emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
1394
+ let data = {
1395
+ storeName: store.storeName,
1396
+ flagCount: 1,
1397
+ checklistName: store.checkListName?.trim(),
1398
+ submittedBy: '--',
1399
+ time: '--',
1400
+ domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
1401
+ type: 'delay',
1402
+ };
1403
+ const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
1404
+ const htmlContent = handlebars.compile( fileContent );
1405
+ const html = htmlContent( { data: data } );
1406
+ emailList.forEach( ( email ) => {
1407
+ let params = {
1408
+ toEmail: email,
1409
+ mailSubject: 'TangoEye | Checklist Flag',
1410
+ htmlBody: html,
1411
+ attachment: '',
1412
+ sourceEmail: JSON.parse( process.env.SES ).adminEmail,
1413
+ };
1414
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
1415
+ } );
1416
+ }
1417
+ await processedchecklist.updateOne( { _id: store._id }, { notify: true } );
1418
+ } ) );
1419
+ }
1421
1420
 
1422
1421
  if ( updatedDetails ) {
1423
1422
  return res.sendSuccess( { message: 'Time Delay Updated Successfully' } );
@@ -2701,57 +2700,10 @@ export async function countUpdateRunAI( req, res ) {
2701
2700
  runAIFlag: req.body.runAICount,
2702
2701
  };
2703
2702
 
2704
- // complianceCount is already populated for the other answer types; add the image/video scores on top.
2705
- let complianceCount = getDetails.userComplianceCount || 0;
2706
-
2707
- // Pull every "Matched/Not Matched" verdict out of a runAIData array, tolerating both shapes we store:
2708
- // 1) [ { answerImage, results: [ { featureName, value } ] } ] (verdict nested under results)
2709
- // 2) [ { featureName, value } ] (flat verdict)
2710
- const extractMatchValues = ( runAIData ) => {
2711
- if ( !Array.isArray( runAIData ) ) return [];
2712
- const values = [];
2713
- runAIData.forEach( ( entry ) => {
2714
- const results = Array.isArray( entry?.results ) ? entry.results : [ entry ];
2715
- results.forEach( ( r ) => {
2716
- if ( r?.featureName === 'Matched/Not Matched' ) values.push( r?.value );
2717
- } );
2718
- } );
2719
- return values;
2720
- };
2721
-
2722
- getDetails.questionAnswers.forEach( ( section ) => {
2723
- section.questions.forEach( ( question ) => {
2724
- if ( question.compliance && [ 'image', 'image/video' ].includes( question.answerType ) ) {
2725
- // For 'image/video' each userAnswer carries its own answerType and runAIData only lives on
2726
- // the image entries; a pure 'image' question keeps runAIData directly on every userAnswer.
2727
- const aiAnswers = question.answerType === 'image/video' ?
2728
- ( question.userAnswer || [] ).filter( ( ua ) => ua?.answerType === 'image' ) :
2729
- ( question.userAnswer || [] );
2730
-
2731
- // Compliance comes from the first configured answer: every "Matched/Not Matched" verdict
2732
- // across the image answers must be True to count as matched, otherwise it's not matched.
2733
- const matchValues = aiAnswers.flatMap( ( ua ) => extractMatchValues( ua?.runAIData ) );
2734
- const allMatched = matchValues.length > 0 && matchValues.every( ( v ) => v === 'True' || v === true );
2735
- const score = allMatched ?
2736
- ( question.answers?.[0]?.matchedCount ?? 0 ) :
2737
- ( question.answers?.[0]?.notMatchedCount ?? 0 );
2738
-
2739
- // Persist the derived score back onto each userAnswer so PDF/dashboard reads stay consistent.
2740
- ( question.userAnswer || [] ).forEach( ( ua ) => {
2741
- ua.complianceScore = score;
2742
- } );
2743
-
2744
- complianceCount += score;
2745
- }
2746
- } );
2747
- } );
2748
-
2749
- updateData.complianceCount = complianceCount;
2750
-
2751
2703
  await processedchecklist.updateOne( { _id: req.body.id }, updateData );
2752
2704
  return res.sendSuccess( 'RunAI Count updated successfully' );
2753
2705
  } catch ( e ) {
2754
- logger.error( { functionName: 'countUpdateRunAI', error: e } );
2706
+ logger.error( { functionName: 'updateRunAI', error: e } );
2755
2707
  return res.sendError( e, 500 );
2756
2708
  }
2757
2709
  }
@@ -3588,40 +3540,47 @@ export async function runAIFlag( req, res ) {
3588
3540
  ],
3589
3541
  },
3590
3542
  }, { _id: 1, notifyFlags: 1, approver: 1 } );
3591
- console.log( checklistDetails );
3592
- let date = dayjs().format( 'YYYY-MM-DD' );
3543
+ let date = dayjs().subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
3593
3544
  if ( checklistDetails.length ) {
3594
3545
  await Promise.all( checklistDetails.map( async ( ele ) => {
3595
- let submitDetails = await processedchecklist.find( { sourceCheckList_id: ele._id, date_string: date, $or: [ { timeFlag: { $gt: 0 } }, { questionFlag: { $gt: 0 } }, { runAIFlag: { $gt: 0 } } ] }, { storeName: 1, checkListName: 1, userName: 1, submitTime_string: 1, runAIFlag: 1, questionFlag: 1, checklistStatus: 1 } );
3596
- console.log( submitDetails );
3597
- let emailList = ele?.notifyFlags?.notifyType.includes( 'approver' ) ? ele.approver.map( ( approver ) => approver?.value ): [];
3598
- emailList = [ ...emailList, ...ele?.notifyFlags?.users?.map( ( user ) => user?.value ) ];
3546
+ let submitDetails = await processedchecklist.find( { sourceCheckList_id: ele._id, checklistStatus: 'submit', date_string: date }, { storeName: 1, checkListName: 1, questionAnswers: 1 } );
3599
3547
  await Promise.all( submitDetails.map( ( store ) => {
3600
- let data = {
3601
- storeName: store.storeName,
3602
- flagCount: store.timeFlag ? 1 : store?.runAIFlag + store?.questionFlag,
3603
- runAIFlag: store?.runAIFlag,
3604
- questionFlag: store?.questionFlag,
3605
- checklistName: store.checkListName?.trim(),
3606
- submittedBy: store?.userName,
3607
- time: store?.submitTime_string ?? '--',
3608
- domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
3609
- status: store.checklistStatus,
3610
- };
3611
- const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
3612
- const htmlContent = handlebars.compile( fileContent );
3613
- const html = htmlContent( { data: data } );
3614
- emailList.forEach( ( email ) => {
3615
- console.log( email );
3616
- let params = {
3617
- toEmail: email,
3618
- mailSubject: 'TangoEye | Checklist Flag',
3619
- htmlBody: html,
3620
- attachment: '',
3621
- sourceEmail: JSON.parse( process.env.SES ).adminEmail,
3622
- };
3623
- sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
3624
- } );
3548
+ if ( store.questionAnswers.length ) {
3549
+ let runAIFlag = 0;
3550
+ store.questionAnswers.forEach( ( section ) => {
3551
+ section.questions.forEach( ( question ) => {
3552
+ if ( question.answerType == 'image' && ( question?.userAnswer?.[0]?.runAIData?.value == 'False' || !question?.userAnswer?.[0]?.runAIData?.value ) ) {
3553
+ runAIFlag++;
3554
+ }
3555
+ } );
3556
+ } );
3557
+ if ( runAIFlag ) {
3558
+ let emailList = ele?.notifyFlags?.notifyType.includes( 'approver' ) ? ele.approver.map( ( approver ) => approver?.value ): [];
3559
+ emailList = [ ...emailList, ...ele?.notifyFlags?.users?.map( ( user ) => user?.value ) ];
3560
+ let data = {
3561
+ storeName: store.storeName,
3562
+ flagCount: 1,
3563
+ checklistName: store.checkListName?.trim(),
3564
+ submittedBy: '--',
3565
+ time: '--',
3566
+ domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
3567
+ type: 'delay',
3568
+ };
3569
+ const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
3570
+ const htmlContent = handlebars.compile( fileContent );
3571
+ const html = htmlContent( { data: data } );
3572
+ emailList.forEach( ( email ) => {
3573
+ let params = {
3574
+ toEmail: email,
3575
+ mailSubject: 'TangoEye | Checklist Flag',
3576
+ htmlBody: html,
3577
+ attachment: '',
3578
+ sourceEmail: JSON.parse( process.env.SES ).adminEmail,
3579
+ };
3580
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
3581
+ } );
3582
+ }
3583
+ }
3625
3584
  } ) );
3626
3585
  } ) );
3627
3586
  }
@@ -1765,7 +1765,6 @@ export async function sopMobilechecklistMultiSectionFormatterv2( req, res, next
1765
1765
  } else {
1766
1766
  if ( qaans[k].validationType == 'Capture Multiple Image with description' ) {
1767
1767
  qaans[k]['validationImage']=[];
1768
- qaans[k]['validationVideo']=[];
1769
1768
  if ( requestSection[i].validationImage.length ) {
1770
1769
  for ( let image of requestSection[i].validationImage ) {
1771
1770
  let validationAnswer = decodeURIComponent( image.split( '?' )[0] );
@@ -1778,18 +1777,6 @@ export async function sopMobilechecklistMultiSectionFormatterv2( req, res, next
1778
1777
  };
1779
1778
  }
1780
1779
  }
1781
- if ( requestSection[i]?.validationVideo?.length ) {
1782
- for ( let video of requestSection[i].validationVideo ) {
1783
- let validationAnswer = decodeURIComponent( video.split( '?' )[0] );
1784
- if ( validationAnswer.length ) {
1785
- let splitImgUrl = validationAnswer.split( '/' );
1786
- if ( splitImgUrl.length > 1 ) {
1787
- splitImgUrl.splice( 0, 3 );
1788
- qaans[k].validationVideo.push( splitImgUrl.join( '/' ) || '' );
1789
- }
1790
- };
1791
- }
1792
- }
1793
1780
  }
1794
1781
  // qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
1795
1782
  qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
@@ -2140,18 +2127,12 @@ export async function sopMobilechecklistMultiSectionFormatterv2( req, res, next
2140
2127
  logger.error( { message: requestData.questionAnswers, error: 'QuestionanswersPayload' } );
2141
2128
 
2142
2129
  if ( requestData.submittype == 'submit' ) {
2143
- requestData.userComplianceCount = 0;
2144
2130
  for ( let section of sectionFormat ) {
2145
2131
  for ( let question of section.questions ) {
2146
2132
  let mustValidate = !question.linkType || ( question.linkType && question.linkquestionenabled );
2147
2133
  if ( mustValidate && ( !question.userAnswer || !question.userAnswer.length ) ) {
2148
2134
  return res.sendError( 'Please Fill All Fields', 400 );
2149
2135
  }
2150
- if ( question.compliance ) {
2151
- const scores = ( question.userAnswer || [] ).map( ( ua ) => ua?.complianceScore ?? 0 );
2152
- let score = scores.length ? Math.max( ...scores ) : 0;
2153
- requestData.userComplianceCount += score;
2154
- }
2155
2136
  }
2156
2137
  }
2157
2138
  }
@@ -2795,7 +2776,6 @@ export async function submitChecklist( req, res ) {
2795
2776
  updateData.checklistStatus = 'submit';
2796
2777
  updateData.updatedAt = dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format();
2797
2778
  updateData.submitMobileTime = requestData?.currentTime;
2798
- updateData.userComplianceCount = requestData?.userComplianceCount;
2799
2779
  }
2800
2780
  // updateData.questionAnswers.forEach( ( section ) => {
2801
2781
  // section.questions.forEach( ( question ) => {
@@ -2896,34 +2876,34 @@ export async function submitChecklist( req, res ) {
2896
2876
  userType: req.user.userType,
2897
2877
  };
2898
2878
  insertOpenSearchData( openSearch.traxActivityLog, inserttraxlogs );
2899
- // if ( updateData.questionFlag ) {
2900
- // let checklistDetails = await checklistService.findOne( { _id: getchecklist[0].sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
2901
- // if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
2902
- // let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
2903
- // emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
2904
- // let data = {
2905
- // storeName: getchecklist[0].storeName,
2906
- // flagCount: updateData.questionFlag,
2907
- // checklistName: getchecklist[0].checkListName,
2908
- // submittedBy: getchecklist[0].userName,
2909
- // time: updateData.submitTime_string,
2910
- // domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
2911
- // };
2912
- // const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
2913
- // const htmlContent = handlebars.compile( fileContent );
2914
- // const html = htmlContent( { data: data } );
2915
- // emailList.forEach( ( email ) => {
2916
- // let params = {
2917
- // toEmail: email,
2918
- // mailSubject: 'TangoEye | Checklist Flag',
2919
- // htmlBody: html,
2920
- // attachment: '',
2921
- // sourceEmail: JSON.parse( process.env.SES ).adminEmail,
2922
- // };
2923
- // sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
2924
- // } );
2925
- // }
2926
- // }
2879
+ if ( updateData.questionFlag ) {
2880
+ let checklistDetails = await checklistService.findOne( { _id: getchecklist[0].sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
2881
+ if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
2882
+ let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
2883
+ emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
2884
+ let data = {
2885
+ storeName: getchecklist[0].storeName,
2886
+ flagCount: updateData.questionFlag,
2887
+ checklistName: getchecklist[0].checkListName,
2888
+ submittedBy: getchecklist[0].userName,
2889
+ time: updateData.submitTime_string,
2890
+ domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
2891
+ };
2892
+ const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
2893
+ const htmlContent = handlebars.compile( fileContent );
2894
+ const html = htmlContent( { data: data } );
2895
+ emailList.forEach( ( email ) => {
2896
+ let params = {
2897
+ toEmail: email,
2898
+ mailSubject: 'TangoEye | Checklist Flag',
2899
+ htmlBody: html,
2900
+ attachment: '',
2901
+ sourceEmail: JSON.parse( process.env.SES ).adminEmail,
2902
+ };
2903
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
2904
+ } );
2905
+ }
2906
+ }
2927
2907
  }
2928
2908
  if ( getchecklist?.[0]?.redoEdit?.toString() != requestData?.redoEdit ) {
2929
2909
  return res.sendSuccess( 'New Questions Added So,Checklist moved back to In Progress. Please complete the updated checklist.' );
@@ -4262,15 +4242,10 @@ export async function questionList( req, res ) {
4262
4242
  }
4263
4243
  if ( userAns.validationType == 'Capture Multiple Image with description' ) {
4264
4244
  let imageAnswers = userAns.validationImage;
4265
- getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationImage = [];
4245
+ userAns.validationImage = [];
4266
4246
  for ( let image of imageAnswers ) {
4267
4247
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationImage.push( `${cdnurl.TraxAnswerCDN}${image}` );
4268
4248
  }
4269
- let videoAnswer = userAns.validationVideo;
4270
- getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationVideo = [];
4271
- for ( let image of videoAnswer ) {
4272
- getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationVideo.push( `${cdnurl.TraxAnswerCDN}${image}` );
4273
- }
4274
4249
  }
4275
4250
  if ( [ 'image', 'descriptiveImage', 'video' ].includes( question.answerType ) && userAns.answer != '' ) {
4276
4251
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].answer =`${cdnurl.TraxAnswerCDN}${userAns.answer}`;
@@ -620,7 +620,6 @@ export const zoneList = async ( req, res ) => {
620
620
  const allowedChecklistsStreams = [
621
621
  'Camera Angle Change Compliance',
622
622
  ];
623
- console.log( allowedChecklists.includes( inputBody.checkListName ) );
624
623
 
625
624
  if ( inputBody.checkListName && allowedChecklists.includes( inputBody.checkListName ) ) {
626
625
  console.log( '==================' );
@@ -1915,6 +1914,7 @@ export const updateConfigure = async ( req, res ) => {
1915
1914
 
1916
1915
  export const updateConfigurev1 = async ( req, res ) => {
1917
1916
  try {
1917
+ console.log( '123' );
1918
1918
  let inputBody = req.body;
1919
1919
  let id;
1920
1920
  let checklistDetails;
@@ -3972,7 +3972,6 @@ async function insertPCBulkV4( getCLconfig, checklistId, currentdate, updatedche
3972
3972
  element4.rawVideoUpload = getCLconfig?.rawVideoUpload || false;
3973
3973
  element4.videoUploadTimeLimit = getCLconfig?.videoUploadTimeLimit || 0;
3974
3974
  element4.complianceCount = getCLconfig?.complianceCount || 0;
3975
- element4.userVerification = getCLconfig?.userVerification;
3976
3975
  assignUserList.push( { ...element4 } );
3977
3976
  }
3978
3977
  } ) );
@@ -276,10 +276,29 @@ export const checklistPerformance = async ( req, res ) => {
276
276
  toDate = new Date( toDate.getTime() - userTimezoneOffset );
277
277
  toDate.setUTCHours( 23, 59, 59, 59 );
278
278
  let result = {};
279
+ let checklistIdList = [];
279
280
 
280
281
  let limit = parseInt( requestData?.limit ) || 10;
281
282
  let skip = limit * ( requestData?.offset ) || 0;
282
283
 
284
+ const detectionPayload = {
285
+ 'fromDate': requestData.fromDate,
286
+ 'toDate': requestData.toDate,
287
+ 'clientId': requestData.clientId,
288
+ 'sortColumnName': requestData.sortColumnName,
289
+ 'sortBy': requestData.sortBy,
290
+ 'storeId': requestData.storeId,
291
+ };
292
+
293
+
294
+ let complianceURL = JSON.parse( process.env.LAMBDAURL ).complianceURL;
295
+ const complianceData = await LamdaServiceCall( complianceURL, detectionPayload );
296
+ if ( complianceData?.data?.length && requestData?.sortColumnName == 'questionCompliance' ) {
297
+ const end = skip + requestData?.limit;
298
+ checklistIdList = complianceData.data.slice( skip, end )?.map( ( ele ) => ele?.sourceCheckList_id );
299
+ }
300
+
301
+
283
302
  // Get User Based Checklist //
284
303
  // let loginUser = { clientId: requestData.clientId, role: req.user.role, userType: req.user.userType, userEmail: req.user.email };
285
304
  // let getUserEmails = await getChecklistUsers( loginUser );
@@ -295,6 +314,10 @@ export const checklistPerformance = async ( req, res ) => {
295
314
  { $or: [ { store_id: { $in: requestData.storeId } }, { store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } } ] },
296
315
  );
297
316
 
317
+ if ( requestData?.sortColumnName == 'questionCompliance' ) {
318
+ findAndQuery.push( { sourceCheckList_id: { $in: checklistIdList } } );
319
+ }
320
+
298
321
  findQuery.push( { $match: { $and: findAndQuery } } );
299
322
 
300
323
  if ( requestData.searchValue && requestData.searchValue != '' ) {
@@ -344,16 +367,6 @@ export const checklistPerformance = async ( req, res ) => {
344
367
  timeFlag: { $sum: '$timeFlag' },
345
368
  questionFlagCount: { $sum: '$questionFlag' },
346
369
  runAIFlagCount: { $sum: '$runAIFlag' },
347
- userComplianceCountTotal: {
348
- $sum: {
349
- $cond: [
350
- { $eq: [ '$checklistStatus', 'submit' ] },
351
- { $ifNull: [ '$userComplianceCount', 0 ] },
352
- 0,
353
- ],
354
- },
355
- },
356
- complianceCount: { $first: '$complianceCount' },
357
370
  checkListType: { $last: '$checkListType' },
358
371
  redo: { $sum: { $cond: [ { $eq: [ '$redoStatus', true ] }, 1, 0 ] } },
359
372
  task: {
@@ -413,36 +426,6 @@ export const checklistPerformance = async ( req, res ) => {
413
426
  checkListType: 1,
414
427
  redo: 1,
415
428
  task: 1,
416
- questionCompliance: {
417
- $let: {
418
- vars: {
419
- divisor: {
420
- $cond: [
421
- { $gt: [ '$submittedChecklist', 1 ] },
422
- { $multiply: [ { $ifNull: [ '$complianceCount', 0 ] }, '$submittedChecklist' ] },
423
- { $ifNull: [ '$complianceCount', 0 ] },
424
- ],
425
- },
426
- },
427
- in: {
428
- $cond: [
429
- { $gt: [ '$$divisor', 0 ] },
430
- {
431
- $round: [
432
- {
433
- $multiply: [
434
- { $divide: [ '$userComplianceCountTotal', '$$divisor' ] },
435
- 100,
436
- ],
437
- },
438
- 0,
439
- ],
440
- },
441
- 0,
442
- ],
443
- },
444
- },
445
- },
446
429
  },
447
430
  } );
448
431
 
@@ -467,6 +450,14 @@ export const checklistPerformance = async ( req, res ) => {
467
450
  return res.sendError( 'no data found', 204 );
468
451
  }
469
452
 
453
+ getChecklistPerformanceData?.[0]?.data.forEach( ( ele ) => {
454
+ let findCompliance;
455
+ if ( complianceData?.data?.length ) {
456
+ findCompliance = complianceData?.data?.find( ( data ) => data.sourceCheckList_id == ele?.sourceCheckList_id );
457
+ }
458
+ ele['questionComplianceRate'] = findCompliance?.compliancePercentage ?? 0;
459
+ } );
460
+
470
461
  if ( requestData.export ) {
471
462
  const exportdata = [];
472
463
  getChecklistPerformanceData[0].data.forEach( ( element ) => {
@@ -4344,26 +4335,26 @@ function escapeRegex( text ) {
4344
4335
  // }
4345
4336
  // }
4346
4337
 
4347
- // async function LamdaServiceCall( url, data ) {
4348
- // try {
4349
- // const requestOptions = {
4350
- // method: 'POST',
4351
- // headers: {
4352
- // 'Content-Type': 'application/json',
4353
- // },
4354
- // body: JSON.stringify( data ),
4355
- // };
4356
- // console.log( data );
4357
- // const response = await fetch( url, requestOptions );
4358
- // if ( !response.ok ) {
4359
- // throw new Error( `Response status: ${response.status}` );
4360
- // return false;
4361
- // }
4362
- // const json = await response.json();
4363
- // return json;
4364
- // } catch ( error ) {
4365
- // console.log( error );
4366
- // logger.error( { error: error, message: data, function: 'LamdaServiceCall' } );
4367
- // return false;
4368
- // }
4369
- // }
4338
+ async function LamdaServiceCall( url, data ) {
4339
+ try {
4340
+ const requestOptions = {
4341
+ method: 'POST',
4342
+ headers: {
4343
+ 'Content-Type': 'application/json',
4344
+ },
4345
+ body: JSON.stringify( data ),
4346
+ };
4347
+ console.log( data );
4348
+ const response = await fetch( url, requestOptions );
4349
+ if ( !response.ok ) {
4350
+ throw new Error( `Response status: ${response.status}` );
4351
+ return false;
4352
+ }
4353
+ const json = await response.json();
4354
+ return json;
4355
+ } catch ( error ) {
4356
+ console.log( error );
4357
+ logger.error( { error: error, message: data, function: 'LamdaServiceCall' } );
4358
+ return false;
4359
+ }
4360
+ }
package/src/hbs/flag.hbs CHANGED
@@ -176,7 +176,7 @@
176
176
  <td class="flagText" style="padding-left:30px; line-height: 24px;">No of Flags :</td>
177
177
  <td></td>
178
178
  <td></td>
179
- <td class="flagText">{{data.flagCount}}{{#eq data.status 'submit'}}(RunAIFlag:{{data.runAIFlag}},QuestionFlag:{{data.questionFlag}}){{/eq}}</td>
179
+ <td class="flagText">{{data.flagCount}}</td>
180
180
  </tr>
181
181
  <tr bgcolor="#ffffff" style="border:none;margin-top:3px;">
182
182
  <td class="flagText" style="padding-left:30px; line-height: 24px;">Submitted By :</td>