tango-app-api-trax 3.7.62 → 3.7.64

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.62",
3
+ "version": "3.7.64",
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';
@@ -664,7 +664,7 @@ export async function sopMobilechecklistQuestionValidatorv1( req, res, next ) {
664
664
  // question.answers.forEach( ( answer ) => {
665
665
  let sectionQuestion = requestSection.filter( ( secQuestion ) => secQuestion.qname == question.oldQname || secQuestion.qname == question.qname );
666
666
  if ( sectionQuestion.length ) {
667
- if ( question.answerType == 'multiplechoicemultiple' || ( question.answerType =='dropdown' && question.allowMultiple ) && ( sectionQuestion[0].Multianswer == null || sectionQuestion[0].Multianswer == '' || !sectionQuestion[0].Multianswer.length ) ) {
667
+ if ( ( question.answerType == 'multiplechoicemultiple' || ( question.answerType =='dropdown' && question.allowMultiple ) ) && ( sectionQuestion[0].Multianswer == null || sectionQuestion[0].Multianswer == '' || !sectionQuestion[0].Multianswer.length ) ) {
668
668
  validationCount++;
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 == '' ) ) ) ) {
@@ -1444,6 +1444,9 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1444
1444
  if ( qaAnswers[j].answerType == 'date' ) {
1445
1445
  ansstructure.dateRangeType = requestSection[i].dateRangeType || false;
1446
1446
  }
1447
+ if ( qaAnswers[j].answerType == 'linearscale' ) {
1448
+ ansstructure.linearType = qaAnswers[j]?.answers[0]?.linearType;
1449
+ }
1447
1450
  des.push( ansstructure );
1448
1451
  }
1449
1452
  let structure = {};
@@ -4577,7 +4580,6 @@ export async function downloadChecklist( req, res ) {
4577
4580
  file_path: `${bucketpath}/${clientDetails?.profileDetails?.logo}`,
4578
4581
  };
4579
4582
  let brandImage = await signedUrl( params );
4580
- // let brandImage = await convertUrltoBase64( url );
4581
4583
  if ( brandImage ) {
4582
4584
  checklistDetails['brandLogo'] = brandImage;
4583
4585
  }
@@ -4605,18 +4607,55 @@ export async function downloadChecklist( req, res ) {
4605
4607
  const templateHtml = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/template.hbs', 'utf8' );
4606
4608
  const template = handlebars.compile( templateHtml );
4607
4609
  const html = template( { data: checklistDetails } );
4608
- pdf.create( html ).toStream( ( err, stream ) => {
4609
- if ( err ) {
4610
- return res.status( 500 ).send( 'Error generating PDF' );
4611
- }
4612
4610
 
4613
- res.setHeader( 'Content-Type', 'application/pdf' );
4614
- res.setHeader( 'Content-Disposition', 'attachment; filename=checkListDetails.pdf' );
4611
+ // Generate PDF using puppeteer instead of deprecated html-pdf
4612
+ const browser = await puppeteer.launch( {
4613
+ headless: 'new',
4614
+ args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ],
4615
+ } );
4616
+
4617
+ const page = await browser.newPage();
4618
+
4619
+ await page.setContent( html, {
4620
+ waitUntil: 'domcontentloaded',
4621
+ } );
4622
+
4623
+ /* -------- WAIT FOR ALL IMAGES TO LOAD -------- */
4624
+
4625
+ await page.evaluate( async () => {
4626
+ const images = Array.from( document.images );
4627
+
4628
+ await Promise.all(
4629
+ images.map( ( img ) => {
4630
+ if ( img.complete ) return;
4631
+
4632
+ return new Promise( ( resolve ) => {
4633
+ img.onload = img.onerror = resolve;
4634
+ } );
4635
+ } ),
4636
+ );
4637
+ } );
4638
+
4639
+ /* ---------------- GENERATE PDF ---------------- */
4615
4640
 
4616
- stream.pipe( res );
4641
+ const pdfBuffer = await page.pdf( {
4642
+ format: 'A4',
4643
+ printBackground: true,
4617
4644
  } );
4645
+
4646
+ await browser.close();
4647
+
4648
+ /* ---------------- RESPONSE ---------------- */
4649
+
4650
+ res.setHeader( 'Content-Type', 'application/pdf' );
4651
+ res.setHeader(
4652
+ 'Content-Disposition',
4653
+ 'attachment; filename=checkListDetails.pdf',
4654
+ );
4655
+
4656
+ return res.end( pdfBuffer );
4618
4657
  } catch ( e ) {
4619
- console.log( 'getChecklistQuestionAnswers =>', e );
4620
- return false;
4658
+ logger.error( { functionName: 'getChecklistQuestionAnswers', error: e } );
4659
+ return e;
4621
4660
  }
4622
4661
  }
@@ -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 };
@@ -290,8 +312,13 @@ export const checklistPerformance = async ( req, res ) => {
290
312
  { client_id: requestData.clientId },
291
313
  // { store_id: { $in: requestData.storeId } },
292
314
  { $or: [ { store_id: { $in: requestData.storeId } }, { store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } } ] },
315
+
293
316
  );
294
317
 
318
+ if ( requestData?.sortColumnName == 'questionCompliance' ) {
319
+ findAndQuery.push( { sourceCheckList_id: { $in: checklistIdList } } );
320
+ }
321
+
295
322
  findQuery.push( { $match: { $and: findAndQuery } } );
296
323
 
297
324
  if ( requestData.searchValue && requestData.searchValue != '' ) {
@@ -409,9 +436,6 @@ export const checklistPerformance = async ( req, res ) => {
409
436
  findQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
410
437
  }
411
438
 
412
- let limit = parseInt( requestData?.limit ) || 10;
413
- let skip = limit * ( requestData?.offset ) || 0;
414
-
415
439
  findQuery.push( {
416
440
  $facet: {
417
441
  data: [
@@ -427,6 +451,11 @@ export const checklistPerformance = async ( req, res ) => {
427
451
  return res.sendError( 'no data found', 204 );
428
452
  }
429
453
 
454
+ getChecklistPerformanceData.forEach( ( ele ) => {
455
+ let findCompliance = complianceData?.find( ( data ) => data.checklistId == ele?.sourceCheckList_id );
456
+ ele['questionComplianceRate'] = findCompliance?.compliance ?? 0;
457
+ } );
458
+
430
459
  if ( requestData.export ) {
431
460
  const exportdata = [];
432
461
  getChecklistPerformanceData[0].data.forEach( ( element ) => {
@@ -4303,3 +4332,27 @@ function escapeRegex( text ) {
4303
4332
  // return [ ];
4304
4333
  // }
4305
4334
  // }
4335
+
4336
+ async function LamdaServiceCall( url, data ) {
4337
+ try {
4338
+ const requestOptions = {
4339
+ method: 'POST',
4340
+ headers: {
4341
+ 'Content-Type': 'application/json',
4342
+ },
4343
+ body: JSON.stringify( data ),
4344
+ };
4345
+ console.log( data );
4346
+ const response = await fetch( url, requestOptions );
4347
+ if ( !response.ok ) {
4348
+ throw new Error( `Response status: ${response.status}` );
4349
+ return false;
4350
+ }
4351
+ const json = await response.json();
4352
+ return json;
4353
+ } catch ( error ) {
4354
+ console.log( error );
4355
+ logger.error( { error: error, message: data, function: 'LamdaServiceCall' } );
4356
+ return false;
4357
+ }
4358
+ }