tango-app-api-trax 3.7.56 → 3.7.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.7.56",
3
+ "version": "3.7.58",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,11 +23,12 @@
23
23
  "firebase-admin": "^13.0.0",
24
24
  "fs": "^0.0.1-security",
25
25
  "handlebars": "^4.7.8",
26
+ "html-pdf": "^3.0.1",
26
27
  "lodash": "^4.17.21",
27
28
  "mongodb": "^6.8.0",
28
29
  "nodemon": "^3.1.4",
29
30
  "path": "^0.12.7",
30
- "tango-api-schema": "^2.5.59",
31
+ "tango-api-schema": "^2.5.61",
31
32
  "tango-app-api-middleware": "^3.5.2",
32
33
  "url": "^0.11.4",
33
34
  "winston": "^3.13.1",
@@ -0,0 +1,11 @@
1
+ import Handlebars from 'handlebars';
2
+
3
+ Handlebars.registerHelper( 'eq', function( arg1, arg2, options ) {
4
+ return ( arg1 == arg2 ) ? options.fn( this ) : options.inverse( this );
5
+ } );
6
+
7
+ Handlebars.registerHelper( 'neq', function( a, b, options ) {
8
+ return a !== b ? options.fn( this ) : options.inverse( this );
9
+ } );
10
+
11
+ export default Handlebars;
@@ -3203,9 +3203,37 @@ export async function checklistTaskSubmissionDetails( req, res ) {
3203
3203
  }
3204
3204
  let details = [];
3205
3205
  if ( req.body.type == 'checklist' ) {
3206
- details = await processedchecklist.find( { sourceCheckList_id: req.body.checklistId, date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, { submitTime: '$submitTime_string', status: '$checklistStatus', approvalStatus: '$approvalStatus', approvalTime: '$approvalTime_string', _id: 0 } );
3206
+ details = await processedchecklist.find( { sourceCheckList_id: req.body.checklistId, checklistStatus: 'submit', date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
3207
+ date_string: 1,
3208
+ checkListName: 1,
3209
+ createdByName: 1,
3210
+ store_id: 1,
3211
+ storeName: 1,
3212
+ submmitedBy: '$userName',
3213
+ submmitedByEmail: '$userEmail',
3214
+ checklistStatus: 1,
3215
+ submitTime: 1,
3216
+ approvalTime: 1,
3217
+ approvalTime_string: 1,
3218
+ approvalByName: 1,
3219
+ approvalByEmail: 1,
3220
+ } );
3207
3221
  } else {
3208
- details = await processedTaskService.find( { sourceCheckList_id: req.body.checklistId, date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, { submitTime: '$submitTime_string', status: '$checklistStatus', approvalStatus: '$approvalStatus', approvalTime: '$approvalTime_string', _id: 0 } );
3222
+ details = await processedTaskService.find( { sourceCheckList_id: req.body.checklistId, checklistStatus: 'submit', date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
3223
+ date_string: 1,
3224
+ checkListName: 1,
3225
+ createdByName: 1,
3226
+ store_id: 1,
3227
+ storeName: 1,
3228
+ submmitedBy: '$userName',
3229
+ submmitedByEmail: '$userEmail',
3230
+ checklistStatus: 1,
3231
+ submitTime: 1,
3232
+ approvalTime: 1,
3233
+ approvalTime_string: 1,
3234
+ approvalByName: 1,
3235
+ approvalByEmail: 1,
3236
+ } );
3209
3237
  }
3210
3238
  return res.sendSuccess( details );
3211
3239
  } catch ( e ) {
@@ -21,12 +21,19 @@ import * as clientService from '../services/clients.services.js';
21
21
  import { create } from '../services/authentication.service.js';
22
22
  import { readFileSync } from 'fs';
23
23
  import { join } from 'path';
24
- import handlebars from 'handlebars';
24
+ // import handlebars from 'handlebars';
25
25
  dayjs.extend( customParseFormat );
26
26
  dayjs.extend( timeZone );
27
27
  import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js';
28
28
  import * as cameraService from '../services/camera.service.js';
29
29
  dayjs.extend( isSameOrBefore );
30
+ import * as pdf from 'html-pdf';
31
+ import handlebars from './handlebar-helper.js';
32
+ import fs from 'fs';
33
+ import { fileURLToPath } from 'url';
34
+ import path from 'path';
35
+ const __filename = fileURLToPath( import.meta.url );
36
+ const __dirname = path.dirname( __filename );
30
37
 
31
38
  export async function storeList( req, res ) {
32
39
  try {
@@ -1082,7 +1089,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1082
1089
 
1083
1090
  if ( requestData.submittype == 'submit' ) {
1084
1091
  reqAnswers.forEach( ( reqA ) => {
1085
- if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( reqA?.answerType ) ) {
1092
+ if ( ![ 'multiplechoicemultiple', 'multipleImage', 'image/video' ].includes( reqA?.answerType ) && ( reqA.answerType == 'dropDown' && !reqA.allowMultiple ) ) {
1086
1093
  if ( ( !reqA.linkType && ( reqA.answer == null || reqA.answer == '' ) ) || ( reqA.linkType && reqA.linkquestionenabled && ( reqA.answer == null || reqA.answer == '' ) ) ) {
1087
1094
  return res.sendError( 'Please Fill All Fields', 400 );
1088
1095
  }
@@ -1220,7 +1227,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1220
1227
  structure.redoComment = qaAnswers[j]?.redoComment;
1221
1228
  };
1222
1229
  newArray.push( structure );
1223
- } else if ( qaAnswers[j].answerType == 'multiplechoicesingle' ) {
1230
+ } else if ( qaAnswers[j].answerType == 'multiplechoicesingle' || ( qaAnswers[j].answerType == 'dropdown' && !qaAnswers[j].allowMultiple ) ) {
1224
1231
  let qaans = qaAnswers[j].answers;
1225
1232
  let ms = [];
1226
1233
  for ( let k = 0; k < qaans.length; k++ ) {
@@ -1261,6 +1268,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1261
1268
  structure.questionReferenceImage = qaAnswers[j].questionReferenceImage || '';
1262
1269
  structure.multiQuestionReferenceImage = qaAnswers[j].multiQuestionReferenceImage || [];
1263
1270
  structure.descriptivetype = qaAnswers[j].descriptivetype;
1271
+ structure.allowMultiple = qaAnswers[j].allowMultiple;
1264
1272
  // structure.parentQuestion = requestSection[i]?.parentQuestion || qaAnswers[j].qno;
1265
1273
  structure.oldQname = qaAnswers[j]?.oldQname || qaAnswers[j].qname;
1266
1274
  if ( qaAnswers[j]?.taskId ) {
@@ -1276,7 +1284,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1276
1284
  structure.redoComment = qaAnswers[j]?.redoComment;
1277
1285
  };
1278
1286
  newArray.push( structure );
1279
- } else if ( qaAnswers[j].answerType == 'multiplechoicemultiple' ) {
1287
+ } else if ( qaAnswers[j].answerType == 'multiplechoicemultiple' || ( qaAnswers[j].answerType == 'dropdown' && qaAnswers[j].allowMultiple ) ) {
1280
1288
  let qaans = qaAnswers[j].answers;
1281
1289
  let mcmo = [];
1282
1290
  for ( let k = 0; k < qaans.length; k++ ) {
@@ -1321,6 +1329,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1321
1329
  structure.questionReferenceImage = qaAnswers[j].questionReferenceImage || '';
1322
1330
  structure.multiQuestionReferenceImage = qaAnswers[j].multiQuestionReferenceImage || [];
1323
1331
  structure.descriptivetype = qaAnswers[j].descriptivetype;
1332
+ structure.allowMultiple = qaAnswers[j].allowMultiple;
1324
1333
  // structure.parentQuestion = requestSection[i]?.parentQuestion || qaAnswers[j].qno;
1325
1334
  structure.oldQname = qaAnswers[j]?.oldQname || qaAnswers[j].qname;
1326
1335
  if ( qaAnswers[j]?.taskId ) {
@@ -1336,7 +1345,7 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1336
1345
  structure.redoComment = qaAnswers[j]?.redoComment;
1337
1346
  };
1338
1347
  newArray.push( structure );
1339
- } else if ( qaAnswers[j].answerType == 'multipleImage' ) {
1348
+ } else if ( [ 'image/video', 'multipleImage' ].includes( qaAnswers[j].answerType ) ) {
1340
1349
  let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
1341
1350
  let mcmi = [];
1342
1351
  // for (let k = 0; k < qaans.length; k++) {
@@ -1366,6 +1375,9 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1366
1375
  newAnswer.runAI = qaAnswers[j].answers[0]?.runAI || false;
1367
1376
  newAnswer.runAIFeatures = qaAnswers[j].answers[0]?.runAIFeatures || [];
1368
1377
  newAnswer.runAIDescription = qaAnswers[j].answers[0]?.runAIDescription || '';
1378
+ if ( qaAnswers[j].answerType == 'image/video' ) {
1379
+ newAnswer.answerType = separatedArray[s].answerType;
1380
+ }
1369
1381
  mcmi.push( newAnswer );
1370
1382
  }
1371
1383
  }
@@ -2002,6 +2014,32 @@ export async function submitChecklist( req, res ) {
2002
2014
  };
2003
2015
  console.log( 'inserttraxlogs =>', inserttraxlogs );
2004
2016
  insertOpenSearchData( openSearch.traxActivityLog, inserttraxlogs );
2017
+ let checklistDetails = await checklistService.findOne( { _id: getchecklist[0].sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
2018
+ if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
2019
+ let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.flatMap( ( ele ) => ele?.value ): [];
2020
+ emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.notifyType?.users.flatMap( ( ele ) => ele?.value ) ];
2021
+ let data = {
2022
+ storeName: getchecklist[0].storeName,
2023
+ flagCount: updateData.questionFlag,
2024
+ checklistName: getchecklist[0].checkListName,
2025
+ submittedBy: getchecklist[0].userName,
2026
+ time: updateData.submitMobileTime,
2027
+ domain: JSON.parse( process.env.URL ).domain,
2028
+ };
2029
+ const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/trialExtentionEmail.hbs', 'utf8' );
2030
+ const template = Handlebars.compile( templateHtml );
2031
+ const html = template( { data: data } );
2032
+ emailList.forEach( ( email ) => {
2033
+ let params = {
2034
+ toEmail: email,
2035
+ mailSubject: 'TangoEye | Checklist Flag',
2036
+ htmlBody: html,
2037
+ attachment: '',
2038
+ sourceEmail: JSON.parse( process.env.SES ).adminEmail,
2039
+ };
2040
+ sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
2041
+ } );
2042
+ }
2005
2043
  }
2006
2044
 
2007
2045
  return res.sendSuccess( 'Checklist Updated Successfully' );
@@ -3230,6 +3268,7 @@ export async function questionList( req, res ) {
3230
3268
  startTime: { $ifNull: [ '$startTime', '' ] },
3231
3269
  submitTime: { $ifNull: [ '$submitTime', '' ] },
3232
3270
  allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
3271
+ sourceCheckList_id: 1,
3233
3272
  // allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
3234
3273
  allowedStoreLocation: {
3235
3274
  $cond: {
@@ -3285,7 +3324,7 @@ export async function questionList( req, res ) {
3285
3324
  }
3286
3325
 
3287
3326
  for ( let [ ansIndex, answer ] of question.answers.entries() ) {
3288
- if ( question.answerType == 'multiplechoicemultiple' ) {
3327
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
3289
3328
  let checkvalidation = null;
3290
3329
  if ( answer.validationAnswer && answer.validationAnswer !='' ) {
3291
3330
  if ( answer.validationType != 'Descriptive Answer' ) {
@@ -3339,24 +3378,24 @@ export async function questionList( req, res ) {
3339
3378
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].multiReferenceImage = userAns.multiReferenceImage;
3340
3379
  }
3341
3380
 
3342
- if ( question.answerType == 'multiplechoicemultiple' ) {
3381
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
3343
3382
  let ansIndex = Multianswer.findIndex( ( item ) => item.answer == userAns.answer );
3344
3383
  if ( ansIndex ) {
3345
3384
  Multianswer[ansIndex].validationAnswer = userAns.validationAnswer;
3346
3385
  }
3347
3386
  }
3348
- if ( question.answerType == 'multipleImage' ) {
3387
+ if ( [ 'image/video', 'multipleImage' ].includes( question.answerType ) ) {
3349
3388
  if ( userAns && userAns.answer && userAns.answer !='' ) {
3350
3389
  // let manswer = await signedUrl( { file_path: decodeURIComponent( userAns.answer ), Bucket: bucket.sop } );
3351
3390
  let manswer = `${cdnurl.TraxAnswerCDN}${userAns.answer}`;
3352
- Multianswer.push( { 'answer': manswer, 'no': userAnsIndex, 'validationAnswer': '' } );
3391
+ Multianswer.push( { 'answer': manswer, 'no': userAnsIndex, 'validationAnswer': '', ...( question.answerType == 'image/video' && { answerType: userAns?.answerType } ) } );
3353
3392
  } else {
3354
3393
 
3355
3394
  }
3356
3395
  }
3357
3396
  }
3358
3397
  }
3359
- if ( question.answerType == 'multiplechoicemultiple' ) {
3398
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
3360
3399
  Multianswer.forEach( ( item ) => {
3361
3400
  if ( item.validationAnswer == null ) {
3362
3401
  item.answer = null;
@@ -3368,11 +3407,11 @@ export async function questionList( req, res ) {
3368
3407
  question.Multianswer = Multianswer;
3369
3408
  }
3370
3409
  }
3371
- if ( question.answerType == 'multipleImage' ) {
3410
+ if ( [ 'image/video', 'multipleImage' ].includes( question.answerType ) ) {
3372
3411
  if ( Multianswer.length ) {
3373
3412
  question.Multianswer = Multianswer;
3374
3413
  } else {
3375
- Multianswer.push( { 'answer': null, 'no': 0, 'validationAnswer': null } );
3414
+ Multianswer.push( { 'answer': null, 'no': 0, 'validationAnswer': null, ...( question.answerType == 'image/video' && { answerType: null } ) } );
3376
3415
  question.Multianswer = Multianswer;
3377
3416
  }
3378
3417
  }
@@ -3417,6 +3456,11 @@ export async function questionList( req, res ) {
3417
3456
  }
3418
3457
  }
3419
3458
 
3459
+ let checklisDetails = await checklistService.findOne( { _id: getchecklist?.[0]?.sourceCheckList_id }, { export: 1 } );
3460
+ if ( checklisDetails ) {
3461
+ getchecklist[0]['export'] = checklisDetails.export;
3462
+ }
3463
+
3420
3464
  return res.sendSuccess( getchecklist );
3421
3465
  }
3422
3466
  } catch ( e ) {
@@ -4238,6 +4282,7 @@ export async function questionListV1( req, res ) {
4238
4282
  startTime: { $ifNull: [ '$startTime', '' ] },
4239
4283
  submitTime: { $ifNull: [ '$submitTime', '' ] },
4240
4284
  allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
4285
+ sourceCheckList_id: { $ifNull: [ '$sourceCheckList_id', '' ] },
4241
4286
  // allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
4242
4287
  allowedStoreLocation: {
4243
4288
  $cond: {
@@ -4293,7 +4338,7 @@ export async function questionListV1( req, res ) {
4293
4338
  }
4294
4339
 
4295
4340
  for ( let [ ansIndex, answer ] of question.answers.entries() ) {
4296
- if ( question.answerType == 'multiplechoicemultiple' ) {
4341
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
4297
4342
  let checkvalidation = null;
4298
4343
  if ( answer.validationAnswer && answer.validationAnswer !='' ) {
4299
4344
  if ( answer.validationType != 'Descriptive Answer' ) {
@@ -4345,13 +4390,13 @@ export async function questionListV1( req, res ) {
4345
4390
 
4346
4391
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].multiReferenceImage = userAns.multiReferenceImage;
4347
4392
  }
4348
- if ( question.answerType == 'multiplechoicemultiple' ) {
4393
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
4349
4394
  let ansIndex = Multianswer.findIndex( ( item ) => item.answer == userAns.answer );
4350
4395
  if ( ansIndex ) {
4351
4396
  Multianswer[ansIndex].validationAnswer = userAns.validationAnswer;
4352
4397
  }
4353
4398
  }
4354
- if ( question.answerType == 'multipleImage' ) {
4399
+ if ( question.answerType == 'multipleImage' || question.answerType == 'image/video' ) {
4355
4400
  if ( userAns && userAns.answer && userAns.answer !='' ) {
4356
4401
  let manswer = `${cdnurl.TraxAnswerCDN}${userAns.answer}`;
4357
4402
  Multianswer.push( { 'answer': manswer, 'no': userAnsIndex, 'validationAnswer': '' } );
@@ -4361,7 +4406,7 @@ export async function questionListV1( req, res ) {
4361
4406
  }
4362
4407
  }
4363
4408
  }
4364
- if ( question.answerType == 'multiplechoicemultiple' ) {
4409
+ if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType == 'dropdown' && question.allowMultiple ) ) {
4365
4410
  Multianswer.forEach( ( item ) => {
4366
4411
  if ( item.validationAnswer == null ) {
4367
4412
  item.answer = null;
@@ -4373,7 +4418,7 @@ export async function questionListV1( req, res ) {
4373
4418
  question.Multianswer = Multianswer;
4374
4419
  }
4375
4420
  }
4376
- if ( question.answerType == 'multipleImage' ) {
4421
+ if ( question.answerType == 'multipleImage' || question.answerType == 'image/video' ) {
4377
4422
  if ( Multianswer.length ) {
4378
4423
  question.Multianswer = Multianswer;
4379
4424
  } else {
@@ -4422,6 +4467,11 @@ export async function questionListV1( req, res ) {
4422
4467
  }
4423
4468
  }
4424
4469
 
4470
+ let checklisDetails = await checklistService.findOne( { _id: getchecklist?.[0]?.sourceCheckList_id }, { export: 1 } );
4471
+ if ( checklisDetails ) {
4472
+ getchecklist[0]['export'] = checklisDetails.export;
4473
+ }
4474
+
4425
4475
  return res.sendSuccess( getchecklist );
4426
4476
  }
4427
4477
  } catch ( e ) {
@@ -4484,3 +4534,135 @@ export async function chunkUpload( req, res ) {
4484
4534
  return res.sendError( e, 500 );
4485
4535
  }
4486
4536
  }
4537
+
4538
+ export async function downloadChecklist( req, res ) {
4539
+ try {
4540
+ let requestData = req.body;
4541
+
4542
+ if ( !requestData.checklistId ) {
4543
+ res.sendBadRequest( 'checklistId is Required' );
4544
+ }
4545
+
4546
+ let checklistDetails;
4547
+
4548
+ if ( requestData.type == 'checklist' ) {
4549
+ checklistDetails = await processedchecklist.findOne( { _id: requestData.checklistId, checklistStatus: 'submit' } );
4550
+ } else {
4551
+ checklistDetails = await processedTask.findOne( { _id: requestData.checklistId, checklistStatus: 'submit' } );
4552
+ }
4553
+
4554
+ if ( !checklistDetails ) {
4555
+ return res.sendError( 'No data found', 204 );
4556
+ }
4557
+
4558
+ let storeDetails = await storeService.findOne( { storeId: checklistDetails.store_id }, { storeProfile: 1 } );
4559
+ if ( !storeDetails ) {
4560
+ return res.sendError( 'No data found', 204 );
4561
+ }
4562
+
4563
+ let clientDetails = await clientService.findOne( { clientId: checklistDetails.client_id } );
4564
+
4565
+ if ( !clientDetails ) {
4566
+ return res.sendError( 'No client found', 204 );
4567
+ }
4568
+
4569
+ checklistDetails = { ...checklistDetails.toObject(), ...storeDetails?.toObject()?.storeProfile };
4570
+
4571
+
4572
+ let scheduleDateTime = dayjs( checklistDetails.submitTime );
4573
+ checklistDetails.submitDate = scheduleDateTime.format( 'DD MMM, YYYY' );
4574
+ checklistDetails.submitTime = scheduleDateTime.format( 'hh:mm A' );
4575
+ if ( clientDetails?.profileDetails?.logo ) {
4576
+ let bucketpath = checklistDetails.client_id + '/logo';
4577
+
4578
+ let params = {
4579
+ Bucket: JSON.parse( process.env.BUCKET )?.assets,
4580
+ file_path: `${bucketpath}/${clientDetails?.profileDetails?.logo}`,
4581
+ };
4582
+ let url = await signedUrl( params );
4583
+ let brandImage = await convertUrltoBase64( url );
4584
+ if ( brandImage ) {
4585
+ checklistDetails['brandLogo'] = brandImage;
4586
+ }
4587
+ }
4588
+ checklistDetails['brandName'] = clientDetails?.clientName;
4589
+ for ( let section of checklistDetails.questionAnswers ) {
4590
+ for ( let question of section.questions ) {
4591
+ question.remarks = question.remarks == null || question.remarks == 'null' ? '' : question.remarks;
4592
+ for ( let answer of question.userAnswer ) {
4593
+ if ( answer?.referenceImage?.trim() ) {
4594
+ let inputData = {
4595
+ Bucket: JSON.parse( process.env.BUCKET )?.sop,
4596
+ file_path: answer.referenceImage,
4597
+ };
4598
+ let url = await signedUrl( inputData );
4599
+ const base64Image = await convertUrltoBase64( url );
4600
+ if ( base64Image ) {
4601
+ answer.referenceImage = base64Image;
4602
+ }
4603
+ }
4604
+ if ( answer.validationType == 'Capture Image' && answer?.validationAnswer?.trim() ) {
4605
+ let inputData = {
4606
+ Bucket: JSON.parse( process.env.BUCKET )?.sop,
4607
+ file_path: answer.validationAnswer,
4608
+ };
4609
+ let url = await signedUrl( inputData );
4610
+ const base64Image = await convertUrltoBase64( url );
4611
+ if ( base64Image ) {
4612
+ answer.validationAnswer = base64Image;
4613
+ }
4614
+ }
4615
+ if ( answer?.answer?.trim() && [ 'image', 'descriptiveImage', 'multipleImage', 'image/video' ].includes( question.answerType ) ) {
4616
+ let inputData = {
4617
+ Bucket: JSON.parse( process.env.BUCKET )?.sop,
4618
+ file_path: answer.answer,
4619
+ };
4620
+ let url = await signedUrl( inputData );
4621
+ const base64Image = await convertUrltoBase64( url );
4622
+ if ( base64Image ) {
4623
+ answer.answer = base64Image;
4624
+ }
4625
+ }
4626
+ }
4627
+ }
4628
+ }
4629
+ const targetFolder = path.join( __dirname, '..', '/hbs/template.hbs' );
4630
+ const templateHtml = fs.readFileSync( targetFolder, 'utf8' );
4631
+ const template = handlebars.compile( templateHtml );
4632
+ const html = template( { data: checklistDetails } );
4633
+ pdf.create( html ).toBuffer( ( err, buffer ) => {
4634
+ if ( err ) {
4635
+ res.status( 500 ).send( 'Error Generating PDF' );
4636
+ } else {
4637
+ res.setHeader( 'Content-Disposition', 'attachment; filename=checkListDetails.pdf' );
4638
+ res.contentType( 'application/pdf' );
4639
+ res.send( buffer );
4640
+ }
4641
+ } );
4642
+ } catch ( e ) {
4643
+ console.log( 'getChecklistQuestionAnswers =>', e );
4644
+ return false;
4645
+ }
4646
+ }
4647
+
4648
+ async function convertUrltoBase64( url ) {
4649
+ try {
4650
+ const response = await fetch( url );
4651
+
4652
+ if ( !response.ok ) {
4653
+ throw new Error( 'Failed to fetch image' );
4654
+ }
4655
+
4656
+ const contentType = response.headers.get( 'content-type' );
4657
+ const arrayBuffer = await response.arrayBuffer();
4658
+
4659
+ const base64Image =
4660
+ `data:${contentType};base64,` +
4661
+ Buffer.from( arrayBuffer ).toString( 'base64' );
4662
+
4663
+ return base64Image;
4664
+ } catch ( error ) {
4665
+ // console.error( 'Error fetching image:', error.message );
4666
+ return false;
4667
+ }
4668
+ }
@@ -26,6 +26,7 @@ import * as teamsServices from '../services/teams.service.js';
26
26
  import * as runAIFeatureServices from '../services/runAIFeatures.services.js';
27
27
  import * as runAIRequestServices from '../services/runAIRequest.services.js';
28
28
  import * as processedTaskService from '../services/processedTaskList.service.js';
29
+ import ExcelJS from 'exceljs';
29
30
 
30
31
 
31
32
  export const checklist = async ( req, res ) => {
@@ -5075,3 +5076,71 @@ export async function updateOSProcessedData( req, res ) {
5075
5076
  return res.sendError( error, 500 );
5076
5077
  }
5077
5078
  }
5079
+
5080
+ export async function downloadQuestionTemplate( req, res ) {
5081
+ try {
5082
+ let questionDetails = await questionService.find( { checkListId: req.body.checklistId } );
5083
+ let answerType = {
5084
+ 'descriptive': 'Descriptive Answer',
5085
+ 'yes/no': 'A/B Question',
5086
+ 'multiplechoicesingle': 'Multiple Choice Single',
5087
+ 'multiplechoicemultiple': 'Multiple Choice Multiple',
5088
+ 'descriptiveImage': 'Capture Image with Description',
5089
+ 'image': 'Capture Image as answer',
5090
+ 'video': 'Capture video as answer',
5091
+ 'multipleImage': 'Capture Multiple Image',
5092
+ 'date': 'Date',
5093
+ 'linearscale': 'Linear Scale',
5094
+ 'image/video': 'Capture Image/Video as Answer',
5095
+ 'time': 'Time',
5096
+ 'dropdown': 'Dropdown',
5097
+ };
5098
+ const workbook = new ExcelJS.Workbook();
5099
+ const sheet = workbook.addWorksheet( 'Fixture Library' );
5100
+
5101
+ sheet.getRow( 1 ).values = [ 'Section Name', 'Question', 'Answer Type', 'Answer Options' ];
5102
+
5103
+ let rowStart = 2;
5104
+
5105
+ questionDetails.forEach( ( section ) => {
5106
+ section.question.forEach( ( qn ) => {
5107
+ sheet.getRow( rowStart ).values = [ section.section, qn.qname, answerType[`${qn.answerType}`], [ 'multiplechoicesingle', 'multiplechoicemultiple', 'dropdown' ].includes( qn.answerType ) ? qn.answers.map( ( ans ) => ans.answer )?.toString() : '' ];
5108
+ rowStart += 1;
5109
+ } );
5110
+ } );
5111
+
5112
+
5113
+ const maxRows = 500000;
5114
+
5115
+ let dropDownRange = [ { key: `C2:C${maxRows}`, optionList: [ '"Descriptive Answer,A/B Question,Multiple Choice Single,Multiple Choice Multiple,Capture Image with Description,Capture Image as answer,Capture video as answer,Capture Multiple Image,Date,Linear Scale,Capture Image/Video as Answer,Time,Dropdown,"' ] } ];
5116
+
5117
+ dropDownRange.forEach( ( ele ) => {
5118
+ sheet.dataValidations.add( ele.key, {
5119
+ type: 'list',
5120
+ allowBlank: true,
5121
+ formulae: ele.optionList,
5122
+ showErrorMessage: true,
5123
+ errorTitle: 'Invalid Choice',
5124
+ error: 'Please select from the dropdown list.',
5125
+ } );
5126
+ } );
5127
+
5128
+ sheet.columns.forEach( ( column ) => {
5129
+ let maxLength = 10;
5130
+ column.eachCell( { includeEmpty: true }, ( cell ) => {
5131
+ const cellValue = cell.value ? cell.value.toString() : '';
5132
+ if ( cellValue.length > maxLength ) {
5133
+ maxLength = cellValue.length;
5134
+ }
5135
+ } );
5136
+ column.width = maxLength + 2;
5137
+ } );
5138
+ const buffer = await workbook.xlsx.writeBuffer();
5139
+ res.setHeader( 'Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' );
5140
+ res.setHeader( 'Content-Disposition', 'attachment; filename="Checklist Question.xlsx"' );
5141
+ return res.send( buffer );
5142
+ } catch ( e ) {
5143
+ logger.error( { functionName: 'downloadQuestionTemplate', error: e } );
5144
+ return res.sendError( e, 500 );
5145
+ }
5146
+ }