tango-app-api-trax 3.9.33 → 3.9.34

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 (51) hide show
  1. package/index.js +2 -1
  2. package/package.json +1 -1
  3. package/src/controllers/internalTrax.controller.js +112 -73
  4. package/src/controllers/mobileTrax.controller.js +69 -29
  5. package/src/controllers/trax.controller.js +7 -1
  6. package/src/controllers/traxDashboard.controllers.js +63 -54
  7. package/src/hbs/flag.hbs +1 -1
  8. package/src/hbs/login-otp.hbs +943 -943
  9. package/src/hbs/template.hbs +7 -0
  10. package/src/hbs/visit-checklist.hbs +51 -1
  11. package/src/logging/activityLogFlusher.js +59 -0
  12. package/src/logging/activityLogMiddleware.js +45 -0
  13. package/src/logging/activityLogStore.js +91 -0
  14. package/src/logging/compressBatches.js +83 -0
  15. package/src/logging/config.js +24 -0
  16. package/src/logging/createLoggableService.js +46 -0
  17. package/src/logging/logExternalCall.js +37 -0
  18. package/src/services/app.service.js +15 -9
  19. package/src/services/approver.service.js +23 -15
  20. package/src/services/authentication.service.js +9 -3
  21. package/src/services/camera.service.js +19 -13
  22. package/src/services/checklist.service.js +35 -27
  23. package/src/services/checklistAssign.service.js +43 -38
  24. package/src/services/checklistQuestion.service.js +39 -34
  25. package/src/services/checklistlog.service.js +39 -34
  26. package/src/services/clientRequest.service.js +9 -2
  27. package/src/services/clients.services.js +23 -18
  28. package/src/services/cluster.service.js +31 -23
  29. package/src/services/domain.service.js +23 -18
  30. package/src/services/download.services.js +35 -25
  31. package/src/services/group.service.js +23 -17
  32. package/src/services/lenskartEmployeeMapping.service.js +15 -10
  33. package/src/services/locus.service.js +35 -28
  34. package/src/services/notification.service.js +35 -26
  35. package/src/services/otp.service.js +20 -13
  36. package/src/services/planogram.service.js +9 -2
  37. package/src/services/processedTaskConfig.service.js +35 -27
  38. package/src/services/processedTaskList.service.js +32 -26
  39. package/src/services/processedchecklist.services.js +55 -47
  40. package/src/services/processedchecklistconfig.services.js +39 -34
  41. package/src/services/recurringFlagTracker.service.js +39 -32
  42. package/src/services/runAIFeatures.services.js +32 -27
  43. package/src/services/runAIRequest.services.js +43 -38
  44. package/src/services/store.service.js +32 -27
  45. package/src/services/tagging.service.js +9 -2
  46. package/src/services/taskConfig.service.js +35 -27
  47. package/src/services/teams.service.js +35 -24
  48. package/src/services/ticket.service.js +15 -10
  49. package/src/services/user.service.js +27 -20
  50. package/src/services/userAssignedstores.service.js +12 -5
  51. package/src/utils/visitChecklistPdf.utils.js +114 -11
package/index.js CHANGED
@@ -9,5 +9,6 @@ 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';
12
13
 
13
- export { traxDashboardRouter, traxFlagRouter, traxRouter, galleryRouter, downloadRouter, mobileRouter, internalTraxRouter, locusOrderRouter, traxActivityLogRouter };
14
+ export { traxDashboardRouter, traxFlagRouter, traxRouter, galleryRouter, downloadRouter, mobileRouter, internalTraxRouter, locusOrderRouter, traxActivityLogRouter, traxActivityLogMiddleware };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.9.33",
3
+ "version": "3.9.34",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -624,6 +624,7 @@ 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;
627
628
  }
628
629
  if ( userIdList.length ) {
629
630
  allQuestion = allQuestion.filter( ( item ) => typeof item._id == 'undefined' );
@@ -1383,40 +1384,40 @@ export async function insertTimeDelayFlags( req, res ) {
1383
1384
  let updatedDetails = await processedchecklist.updateMany( { _id: { $in: checklistId } }, { timeFlag: 1 } );
1384
1385
 
1385
1386
 
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
- }
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
+ // }
1420
1421
 
1421
1422
  if ( updatedDetails ) {
1422
1423
  return res.sendSuccess( { message: 'Time Delay Updated Successfully' } );
@@ -2700,10 +2701,57 @@ export async function countUpdateRunAI( req, res ) {
2700
2701
  runAIFlag: req.body.runAICount,
2701
2702
  };
2702
2703
 
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
+
2703
2751
  await processedchecklist.updateOne( { _id: req.body.id }, updateData );
2704
2752
  return res.sendSuccess( 'RunAI Count updated successfully' );
2705
2753
  } catch ( e ) {
2706
- logger.error( { functionName: 'updateRunAI', error: e } );
2754
+ logger.error( { functionName: 'countUpdateRunAI', error: e } );
2707
2755
  return res.sendError( e, 500 );
2708
2756
  }
2709
2757
  }
@@ -3540,47 +3588,38 @@ export async function runAIFlag( req, res ) {
3540
3588
  ],
3541
3589
  },
3542
3590
  }, { _id: 1, notifyFlags: 1, approver: 1 } );
3543
- let date = dayjs().subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
3591
+ let date = dayjs().format( 'YYYY-MM-DD' );
3544
3592
  if ( checklistDetails.length ) {
3545
3593
  await Promise.all( checklistDetails.map( async ( ele ) => {
3546
- let submitDetails = await processedchecklist.find( { sourceCheckList_id: ele._id, checklistStatus: 'submit', date_string: date }, { storeName: 1, checkListName: 1, questionAnswers: 1 } );
3594
+ 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 } );
3595
+ let emailList = ele?.notifyFlags?.notifyType.includes( 'approver' ) ? ele.approver.map( ( approver ) => approver?.value ): [];
3596
+ emailList = [ ...emailList, ...ele?.notifyFlags?.users?.map( ( user ) => user?.value ) ];
3547
3597
  await Promise.all( submitDetails.map( ( store ) => {
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
- }
3598
+ let data = {
3599
+ storeName: store.storeName,
3600
+ flagCount: store.timeFlag ? 1 : store?.runAIFlag + store?.questionFlag,
3601
+ runAIFlag: store?.runAIFlag,
3602
+ questionFlag: store?.questionFlag,
3603
+ checklistName: store.checkListName?.trim(),
3604
+ submittedBy: store?.userName,
3605
+ time: store?.submitTime_string ?? '--',
3606
+ domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
3607
+ status: store.checklistStatus,
3608
+ };
3609
+ const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
3610
+ const htmlContent = handlebars.compile( fileContent );
3611
+ const html = htmlContent( { data: data } );
3612
+ emailList.forEach( ( email ) => {
3613
+ console.log( email );
3614
+ let params = {
3615
+ toEmail: email,
3616
+ mailSubject: 'TangoEye | Checklist Flag',
3617
+ htmlBody: html,
3618
+ attachment: '',
3619
+ sourceEmail: JSON.parse( process.env.SES ).adminEmail,
3620
+ };
3621
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
3622
+ } );
3584
3623
  } ) );
3585
3624
  } ) );
3586
3625
  }
@@ -1765,6 +1765,7 @@ 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']=[];
1768
1769
  if ( requestSection[i].validationImage.length ) {
1769
1770
  for ( let image of requestSection[i].validationImage ) {
1770
1771
  let validationAnswer = decodeURIComponent( image.split( '?' )[0] );
@@ -1777,6 +1778,18 @@ export async function sopMobilechecklistMultiSectionFormatterv2( req, res, next
1777
1778
  };
1778
1779
  }
1779
1780
  }
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
+ }
1780
1793
  }
1781
1794
  // qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
1782
1795
  qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
@@ -2127,12 +2140,18 @@ export async function sopMobilechecklistMultiSectionFormatterv2( req, res, next
2127
2140
  logger.error( { message: requestData.questionAnswers, error: 'QuestionanswersPayload' } );
2128
2141
 
2129
2142
  if ( requestData.submittype == 'submit' ) {
2143
+ requestData.userComplianceCount = 0;
2130
2144
  for ( let section of sectionFormat ) {
2131
2145
  for ( let question of section.questions ) {
2132
2146
  let mustValidate = !question.linkType || ( question.linkType && question.linkquestionenabled );
2133
2147
  if ( mustValidate && ( !question.userAnswer || !question.userAnswer.length ) ) {
2134
2148
  return res.sendError( 'Please Fill All Fields', 400 );
2135
2149
  }
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
+ }
2136
2155
  }
2137
2156
  }
2138
2157
  }
@@ -2776,6 +2795,15 @@ export async function submitChecklist( req, res ) {
2776
2795
  updateData.checklistStatus = 'submit';
2777
2796
  updateData.updatedAt = dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format();
2778
2797
  updateData.submitMobileTime = requestData?.currentTime;
2798
+ updateData.userComplianceCount = requestData?.userComplianceCount;
2799
+ updateData.userSignature = requestData?.userSignature;
2800
+ if ( requestData?.userImage ) {
2801
+ let splitImgUrl = requestData?.userImage.split( '/' );
2802
+ if ( splitImgUrl.length > 1 ) {
2803
+ splitImgUrl.splice( 0, 3 );
2804
+ updateData.userImage = splitImgUrl.join( '/' ) || '';
2805
+ }
2806
+ }
2779
2807
  }
2780
2808
  // updateData.questionAnswers.forEach( ( section ) => {
2781
2809
  // section.questions.forEach( ( question ) => {
@@ -2876,34 +2904,34 @@ export async function submitChecklist( req, res ) {
2876
2904
  userType: req.user.userType,
2877
2905
  };
2878
2906
  insertOpenSearchData( openSearch.traxActivityLog, inserttraxlogs );
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
- }
2907
+ // if ( updateData.questionFlag ) {
2908
+ // let checklistDetails = await checklistService.findOne( { _id: getchecklist[0].sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
2909
+ // if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
2910
+ // let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
2911
+ // emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
2912
+ // let data = {
2913
+ // storeName: getchecklist[0].storeName,
2914
+ // flagCount: updateData.questionFlag,
2915
+ // checklistName: getchecklist[0].checkListName,
2916
+ // submittedBy: getchecklist[0].userName,
2917
+ // time: updateData.submitTime_string,
2918
+ // domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags?date=${dayjs().format( 'YYYY-MM-DD' )}`,
2919
+ // };
2920
+ // const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
2921
+ // const htmlContent = handlebars.compile( fileContent );
2922
+ // const html = htmlContent( { data: data } );
2923
+ // emailList.forEach( ( email ) => {
2924
+ // let params = {
2925
+ // toEmail: email,
2926
+ // mailSubject: 'TangoEye | Checklist Flag',
2927
+ // htmlBody: html,
2928
+ // attachment: '',
2929
+ // sourceEmail: JSON.parse( process.env.SES ).adminEmail,
2930
+ // };
2931
+ // sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
2932
+ // } );
2933
+ // }
2934
+ // }
2907
2935
  }
2908
2936
  if ( getchecklist?.[0]?.redoEdit?.toString() != requestData?.redoEdit ) {
2909
2937
  return res.sendSuccess( 'New Questions Added So,Checklist moved back to In Progress. Please complete the updated checklist.' );
@@ -4177,6 +4205,9 @@ export async function questionList( req, res ) {
4177
4205
  streamId: { $ifNull: [ '$streamId', '' ] },
4178
4206
  export: { $ifNull: [ '$export', false ] },
4179
4207
  redoEdit: 1,
4208
+ userVerification: 1,
4209
+ userSignature: 1,
4210
+ userImage: 1,
4180
4211
  },
4181
4212
  } );
4182
4213
 
@@ -4187,6 +4218,7 @@ export async function questionList( req, res ) {
4187
4218
  logger.info( `v5 => Checklist Continue => store Name: ${getchecklist[0].storeName}, User Email: ${getchecklist[0].userEmail}, Checklist Name: ${getchecklist[0].checkListName}` );
4188
4219
  // let bucket = JSON.parse( process.env.BUCKET );
4189
4220
  let cdnurl = JSON.parse( process.env.CDNURL );
4221
+ getchecklist[0].userImage = `${cdnurl}/${getchecklist[0].userImage}`;
4190
4222
  for ( let [ secIndex, section ] of getchecklist[0].questionAnswers.entries() ) {
4191
4223
  for ( let [ questionIndex, question ] of section.questions.entries() ) {
4192
4224
  let Multianswer = [];
@@ -4242,10 +4274,15 @@ export async function questionList( req, res ) {
4242
4274
  }
4243
4275
  if ( userAns.validationType == 'Capture Multiple Image with description' ) {
4244
4276
  let imageAnswers = userAns.validationImage;
4245
- userAns.validationImage = [];
4277
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationImage = [];
4246
4278
  for ( let image of imageAnswers ) {
4247
4279
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationImage.push( `${cdnurl.TraxAnswerCDN}${image}` );
4248
4280
  }
4281
+ let videoAnswer = userAns.validationVideo;
4282
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationVideo = [];
4283
+ for ( let image of videoAnswer ) {
4284
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationVideo.push( `${cdnurl.TraxAnswerCDN}${image}` );
4285
+ }
4249
4286
  }
4250
4287
  if ( [ 'image', 'descriptiveImage', 'video' ].includes( question.answerType ) && userAns.answer != '' ) {
4251
4288
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].answer =`${cdnurl.TraxAnswerCDN}${userAns.answer}`;
@@ -5490,6 +5527,9 @@ export async function downloadChecklist( req, res ) {
5490
5527
  if ( [ 'Capture Multiple Image with description' ].includes( answer.validationType ) && answer?.validationImage?.length ) {
5491
5528
  answer.validationImage = answer?.validationImage?.map( ( ele ) => JSON.parse( process.env.CDNURL )?.TraxAnswerCDN+ele );
5492
5529
  }
5530
+ if ( [ 'Capture Multiple Image with description' ].includes( answer.validationType ) && answer?.validationVideo?.length ) {
5531
+ answer.validationVideo = answer?.validationVideo?.map( ( ele ) => JSON.parse( process.env.CDNURL )?.TraxAnswerCDN+ele );
5532
+ }
5493
5533
  if ( answer?.answer?.trim() && [ 'image', 'descriptiveImage', 'multipleImage', 'image/video', 'video' ].includes( question.answerType ) ) {
5494
5534
  answer.answer = JSON.parse( process.env.CDNURL )?.TraxAnswerCDN+answer.answer;
5495
5535
  }
@@ -616,10 +616,16 @@ export const zoneList = async ( req, res ) => {
616
616
  'Retail Shelf Monitoring',
617
617
  'Store Mopping Compliance Checklist',
618
618
  'Occupancy Detection',
619
+ 'Unattended Detection',
620
+ 'Employee Monitoring',
621
+ 'Customer Unattended',
622
+
623
+
619
624
  ];
620
625
  const allowedChecklistsStreams = [
621
626
  'Camera Angle Change Compliance',
622
627
  ];
628
+ console.log( allowedChecklists.includes( inputBody.checkListName ) );
623
629
 
624
630
  if ( inputBody.checkListName && allowedChecklists.includes( inputBody.checkListName ) ) {
625
631
  console.log( '==================' );
@@ -1914,7 +1920,6 @@ export const updateConfigure = async ( req, res ) => {
1914
1920
 
1915
1921
  export const updateConfigurev1 = async ( req, res ) => {
1916
1922
  try {
1917
- console.log( '123' );
1918
1923
  let inputBody = req.body;
1919
1924
  let id;
1920
1925
  let checklistDetails;
@@ -3972,6 +3977,7 @@ async function insertPCBulkV4( getCLconfig, checklistId, currentdate, updatedche
3972
3977
  element4.rawVideoUpload = getCLconfig?.rawVideoUpload || false;
3973
3978
  element4.videoUploadTimeLimit = getCLconfig?.videoUploadTimeLimit || 0;
3974
3979
  element4.complianceCount = getCLconfig?.complianceCount || 0;
3980
+ element4.userVerification = getCLconfig?.userVerification;
3975
3981
  assignUserList.push( { ...element4 } );
3976
3982
  }
3977
3983
  } ) );
@@ -276,29 +276,10 @@ 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 = [];
280
279
 
281
280
  let limit = parseInt( requestData?.limit ) || 10;
282
281
  let skip = limit * ( requestData?.offset ) || 0;
283
282
 
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
-
302
283
  // Get User Based Checklist //
303
284
  // let loginUser = { clientId: requestData.clientId, role: req.user.role, userType: req.user.userType, userEmail: req.user.email };
304
285
  // let getUserEmails = await getChecklistUsers( loginUser );
@@ -314,10 +295,6 @@ export const checklistPerformance = async ( req, res ) => {
314
295
  { $or: [ { store_id: { $in: requestData.storeId } }, { store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } } ] },
315
296
  );
316
297
 
317
- if ( requestData?.sortColumnName == 'questionCompliance' ) {
318
- findAndQuery.push( { sourceCheckList_id: { $in: checklistIdList } } );
319
- }
320
-
321
298
  findQuery.push( { $match: { $and: findAndQuery } } );
322
299
 
323
300
  if ( requestData.searchValue && requestData.searchValue != '' ) {
@@ -367,6 +344,16 @@ export const checklistPerformance = async ( req, res ) => {
367
344
  timeFlag: { $sum: '$timeFlag' },
368
345
  questionFlagCount: { $sum: '$questionFlag' },
369
346
  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' },
370
357
  checkListType: { $last: '$checkListType' },
371
358
  redo: { $sum: { $cond: [ { $eq: [ '$redoStatus', true ] }, 1, 0 ] } },
372
359
  task: {
@@ -426,6 +413,36 @@ export const checklistPerformance = async ( req, res ) => {
426
413
  checkListType: 1,
427
414
  redo: 1,
428
415
  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
+ },
429
446
  },
430
447
  } );
431
448
 
@@ -450,14 +467,6 @@ export const checklistPerformance = async ( req, res ) => {
450
467
  return res.sendError( 'no data found', 204 );
451
468
  }
452
469
 
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
-
461
470
  if ( requestData.export ) {
462
471
  const exportdata = [];
463
472
  getChecklistPerformanceData[0].data.forEach( ( element ) => {
@@ -4335,26 +4344,26 @@ function escapeRegex( text ) {
4335
4344
  // }
4336
4345
  // }
4337
4346
 
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
- }
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
+ // }
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}}</td>
179
+ <td class="flagText">{{data.flagCount}}{{#eq data.status 'submit'}}(RunAIFlag:{{data.runAIFlag}},QuestionFlag:{{data.questionFlag}}){{/eq}}</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>