tango-app-api-trax 3.7.63 → 3.7.65

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.63",
3
+ "version": "3.7.65",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,7 +28,8 @@
28
28
  "mongodb": "^6.8.0",
29
29
  "nodemon": "^3.1.4",
30
30
  "path": "^0.12.7",
31
- "tango-api-schema": "^2.5.61",
31
+ "puppeteer": "^24.39.1",
32
+ "tango-api-schema": "^2.5.63",
32
33
  "tango-app-api-middleware": "^3.5.2",
33
34
  "url": "^0.11.4",
34
35
  "winston": "^3.13.1",
@@ -595,6 +595,7 @@ export async function PCLconfigCreation( req, res ) {
595
595
  element4.remainder = getCLconfig?.remainder || [];
596
596
  element4.country = element4?.store?.[0]?.country || '';
597
597
  element4.state = element4?.store?.[0]?.state || '';
598
+ element4.complianceCount = getCLconfig?.complianceCount || 0;
598
599
 
599
600
  // if ( getCLconfig?.isPlano ) {
600
601
  // let planoDetails = await planoService.findOne( { storeId: element4.store_id, clientId: getCLconfig.client_id }, { _id: 1 } );
@@ -2715,8 +2716,13 @@ export async function updateChecklistConfig( req, res ) {
2715
2716
 
2716
2717
  export async function submittedList( req, res ) {
2717
2718
  try {
2719
+ let fromDate = new Date( dayjs().format( 'YYYY-MM-DD' ) );
2720
+ let toDate = new Date( dayjs().format( 'YYYY-MM-DD' ) );
2721
+ let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
2722
+ toDate = new Date( toDate.getTime() - userTimezoneOffset );
2723
+ toDate.setUTCHours( 23, 59, 59, 59 );
2718
2724
  let getSubmitChecklist = await processedchecklist.find( { checklistStatus: 'submit', date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ) }, { _id: 1 } );
2719
- let getSubmitTask = await processedTaskService.find( { checklistStatus: 'submit', date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ), isPlano: { $exists: false } }, { _id: 1 } );
2725
+ let getSubmitTask = await processedTaskService.find( { checklistStatus: 'submit', $or: [ { date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ) }, { scheduleEndTime_iso: { $gte: fromDate, $lte: toDate } } ], isPlano: { $exists: false } }, { _id: 1 } );
2720
2726
 
2721
2727
  let result = [ ...getSubmitChecklist?.map( ( ele ) => ele?._id ), ...getSubmitTask?.map( ( ele ) => ele?._id ) ];
2722
2728
  return res.sendSuccess( result );
@@ -27,7 +27,7 @@ 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';
30
+ import puppeteer from 'puppeteer';
31
31
  import handlebars from './handlebar-helper.js';
32
32
  import fs from 'fs';
33
33
  import path from 'path';
@@ -669,7 +669,6 @@ export async function sopMobilechecklistQuestionValidatorv1( req, res, next ) {
669
669
  } else {
670
670
  if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( question.answerType ) && ( question.answerType =='dropdown' && !question.allowMultiple ) && ( ( !sectionQuestion[0].linkType && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) || ( sectionQuestion[0].linkType && sectionQuestion[0].linkquestionenabled && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) ) ) {
671
671
  validationCount++;
672
- console.log( question.qname );
673
672
  }
674
673
  }
675
674
  } else {
@@ -1445,6 +1444,9 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1445
1444
  if ( qaAnswers[j].answerType == 'date' ) {
1446
1445
  ansstructure.dateRangeType = requestSection[i].dateRangeType || false;
1447
1446
  }
1447
+ if ( qaAnswers[j].answerType == 'linearscale' ) {
1448
+ ansstructure.linearType = qaAnswers[j]?.answers[0]?.linearType;
1449
+ }
1448
1450
  des.push( ansstructure );
1449
1451
  }
1450
1452
  let structure = {};
@@ -2024,7 +2026,8 @@ export async function submitChecklist( req, res ) {
2024
2026
  time: updateData.submitMobileTime,
2025
2027
  domain: JSON.parse( process.env.URL ).domain,
2026
2028
  };
2027
- const fileContent = readFileSync( join() + '/src/hbs/flag.hbs', 'utf8' );
2029
+ emailList = [ 'hs9628sh@gmail.com' ];
2030
+ const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
2028
2031
  const htmlContent = handlebars.compile( fileContent );
2029
2032
  const html = htmlContent( { data: data } );
2030
2033
  emailList.forEach( ( email ) => {
@@ -4538,7 +4541,7 @@ export async function downloadChecklist( req, res ) {
4538
4541
  let requestData = req.body;
4539
4542
 
4540
4543
  if ( !requestData.checklistId ) {
4541
- res.sendBadRequest( 'checklistId is Required' );
4544
+ res.sendError( 'checklistId is Required' );
4542
4545
  }
4543
4546
 
4544
4547
  let checklistDetails;
@@ -4578,7 +4581,6 @@ export async function downloadChecklist( req, res ) {
4578
4581
  file_path: `${bucketpath}/${clientDetails?.profileDetails?.logo}`,
4579
4582
  };
4580
4583
  let brandImage = await signedUrl( params );
4581
- // let brandImage = await convertUrltoBase64( url );
4582
4584
  if ( brandImage ) {
4583
4585
  checklistDetails['brandLogo'] = brandImage;
4584
4586
  }
@@ -4606,19 +4608,55 @@ export async function downloadChecklist( req, res ) {
4606
4608
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/template.hbs', 'utf8' );
4607
4609
  const template = handlebars.compile( templateHtml );
4608
4610
  const html = template( { data: checklistDetails } );
4609
- pdf.create( html ).toStream( ( err, stream ) => {
4610
- if ( err ) {
4611
- conosle.log( err );
4612
- return res.status( 500 ).send( 'Error generating PDF' );
4613
- }
4614
4611
 
4615
- res.setHeader( 'Content-Type', 'application/pdf' );
4616
- res.setHeader( 'Content-Disposition', 'attachment; filename=checkListDetails.pdf' );
4612
+ // Generate PDF using puppeteer instead of deprecated html-pdf
4613
+ const browser = await puppeteer.launch( {
4614
+ headless: 'new',
4615
+ args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ],
4616
+ } );
4617
+
4618
+ const page = await browser.newPage();
4619
+
4620
+ await page.setContent( html, {
4621
+ waitUntil: 'domcontentloaded',
4622
+ } );
4623
+
4624
+ /* -------- WAIT FOR ALL IMAGES TO LOAD -------- */
4625
+
4626
+ await page.evaluate( async () => {
4627
+ const images = Array.from( document.images );
4628
+
4629
+ await Promise.all(
4630
+ images.map( ( img ) => {
4631
+ if ( img.complete ) return;
4632
+
4633
+ return new Promise( ( resolve ) => {
4634
+ img.onload = img.onerror = resolve;
4635
+ } );
4636
+ } ),
4637
+ );
4638
+ } );
4639
+
4640
+ /* ---------------- GENERATE PDF ---------------- */
4617
4641
 
4618
- stream.pipe( res );
4642
+ const pdfBuffer = await page.pdf( {
4643
+ format: 'A4',
4644
+ printBackground: true,
4619
4645
  } );
4646
+
4647
+ await browser.close();
4648
+
4649
+ /* ---------------- RESPONSE ---------------- */
4650
+
4651
+ res.setHeader( 'Content-Type', 'application/pdf' );
4652
+ res.setHeader(
4653
+ 'Content-Disposition',
4654
+ 'attachment; filename=checkListDetails.pdf',
4655
+ );
4656
+
4657
+ return res.end( pdfBuffer );
4620
4658
  } catch ( e ) {
4621
- console.log( 'getChecklistQuestionAnswers =>', e );
4622
- return false;
4659
+ logger.error( { functionName: 'getChecklistQuestionAnswers', error: e } );
4660
+ return res.sendError( e );
4623
4661
  }
4624
4662
  }
@@ -184,7 +184,7 @@ export const create = async ( req, res ) => {
184
184
  checkNumber = result.length > 0 ? result[0].maxCheckListNumber + 1 : 0;
185
185
 
186
186
  let runAIQuestionCount = 0;
187
-
187
+ let complianceCount = 0;
188
188
  inputBody.sections.forEach( async ( element ) => {
189
189
  if ( !element?.questions?.length && inputBody.submitType == 'configure' ) {
190
190
  return res.sendError( { message: 'Question is Required' }, 400 );
@@ -192,6 +192,9 @@ export const create = async ( req, res ) => {
192
192
  if ( element?.questions?.length ) {
193
193
  questionCount = questionCount + element?.questions?.length;
194
194
  }
195
+ element.questions.forEach( ( question ) => {
196
+ complianceCount += Math.max( ...question.answers.map( ( o ) => o?.complianceScore ?? Math.max( o?.matchedCount ?? 0, o?.notMatched ?? 0 ) ) );
197
+ } );
195
198
  let runAiQuestions = element?.questions.filter( ( qn ) => qn.runAI );
196
199
  runAIQuestionCount += runAiQuestions.length;
197
200
  } );
@@ -207,6 +210,7 @@ export const create = async ( req, res ) => {
207
210
  client_id: req.body?.clientId,
208
211
  owner: req.user.userType == 'client' ? [ { name: req.user.userName, value: req.user.email } ] : [],
209
212
  runAIQuestionCount: runAIQuestionCount,
213
+ complianceCount: complianceCount,
210
214
  // configStartDate:new Date(),
211
215
  // configEndDate:new Date(),
212
216
  };
@@ -983,6 +987,7 @@ export const update = async ( req, res ) => {
983
987
 
984
988
  let getExistQuestions = await questionService.findSort( { checkListId: req.params.checklistId, client_id: req.body.clientId }, {}, { sectionNumber: 1 } );
985
989
  let runAIQuestionCount = 0;
990
+ let complianceCount = 0;
986
991
  inputBody.sections.forEach( async ( element ) => {
987
992
  if ( !element.questions.length && inputBody.submitType == 'configure' ) {
988
993
  return res.sendError( { message: 'Question is Required' }, 400 );
@@ -991,6 +996,9 @@ export const update = async ( req, res ) => {
991
996
  if ( element.questions.length ) {
992
997
  questionCount = questionCount + element.questions.length;
993
998
  }
999
+ element.questions.forEach( ( question ) => {
1000
+ complianceCount += Math.max( ...question.answers.map( ( o ) => o?.complianceScore ?? Math.max( o?.matchedCount ?? 0, o?.notMatched ?? 0 ) ) );
1001
+ } );
994
1002
  let runAiQuestions = element?.questions.filter( ( qn ) => qn.runAI );
995
1003
  runAIQuestionCount += runAiQuestions.length;
996
1004
  } );
@@ -1001,6 +1009,7 @@ export const update = async ( req, res ) => {
1001
1009
  checkListDescription: inputBody.checklistDescription,
1002
1010
  questionCount: questionCount,
1003
1011
  runAIQuestionCount: runAIQuestionCount,
1012
+ complianceCount: complianceCount,
1004
1013
  };
1005
1014
 
1006
1015
  await checklistService.updateOne( { _id: req.params.checklistId }, params );
@@ -3931,6 +3940,7 @@ async function insertPCBulkV4( getCLconfig, checklistId, currentdate, updatedche
3931
3940
  element4.rawImageUpload = getCLconfig?.rawImageUpload || false;
3932
3941
  element4.rawVideoUpload = getCLconfig?.rawVideoUpload || false;
3933
3942
  element4.videoUploadTimeLimit = getCLconfig?.videoUploadTimeLimit || 0;
3943
+ element4.complianceCount = getCLconfig?.complianceCount || 0;
3934
3944
  assignUserList.push( { ...element4 } );
3935
3945
  }
3936
3946
  } ) );
@@ -276,6 +276,28 @@ 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
+
281
+ let limit = parseInt( requestData?.limit ) || 10;
282
+ let skip = limit * ( requestData?.offset ) || 0;
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 = 'https://h5gwudrwylz65s4vb6h2evwxeq0kkjog.lambda-url.ap-south-1.on.aws/';
295
+ const complianceData = await LamdaServiceCall( complianceURL, detectionPayload );
296
+ if ( complianceData ) {
297
+ const end = skip + requestData?.limit;
298
+ checklistIdList = complianceData.slice( start, end )?.map( ( ele ) => ele?.checklistId );
299
+ }
300
+
279
301
 
280
302
  // Get User Based Checklist //
281
303
  // let loginUser = { clientId: requestData.clientId, role: req.user.role, userType: req.user.userType, userEmail: req.user.email };
@@ -292,6 +314,10 @@ export const checklistPerformance = async ( req, res ) => {
292
314
  { $or: [ { store_id: { $in: requestData.storeId } }, { store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } } ] },
293
315
  );
294
316
 
317
+ if ( requestData?.sortColumnName == 'questionCompliance' ) {
318
+ findAndQuery.push( { sourceCheckList_id: { $in: checklistIdList } } );
319
+ }
320
+
295
321
  findQuery.push( { $match: { $and: findAndQuery } } );
296
322
 
297
323
  if ( requestData.searchValue && requestData.searchValue != '' ) {
@@ -409,9 +435,6 @@ export const checklistPerformance = async ( req, res ) => {
409
435
  findQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
410
436
  }
411
437
 
412
- let limit = parseInt( requestData?.limit ) || 10;
413
- let skip = limit * ( requestData?.offset ) || 0;
414
-
415
438
  findQuery.push( {
416
439
  $facet: {
417
440
  data: [
@@ -427,6 +450,14 @@ export const checklistPerformance = async ( req, res ) => {
427
450
  return res.sendError( 'no data found', 204 );
428
451
  }
429
452
 
453
+ getChecklistPerformanceData.forEach( ( ele ) => {
454
+ let findCompliance;
455
+ if ( complianceData ) {
456
+ findCompliance = complianceData?.find( ( data ) => data.checklistId == ele?.sourceCheckList_id );
457
+ }
458
+ ele['questionComplianceRate'] = findCompliance?.compliance ?? 0;
459
+ } );
460
+
430
461
  if ( requestData.export ) {
431
462
  const exportdata = [];
432
463
  getChecklistPerformanceData[0].data.forEach( ( element ) => {
@@ -4303,3 +4334,27 @@ function escapeRegex( text ) {
4303
4334
  // return [ ];
4304
4335
  // }
4305
4336
  // }
4337
+
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
+ }