tango-app-api-trax 3.8.28 → 3.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.8.28",
3
+ "version": "3.8.30",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "nodemon": "^3.1.4",
30
30
  "path": "^0.12.7",
31
31
  "puppeteer": "^24.39.1",
32
- "tango-api-schema": "^2.5.88",
32
+ "tango-api-schema": "^2.5.92",
33
33
  "tango-app-api-middleware": "^3.5.2",
34
34
  "url": "^0.11.4",
35
35
  "winston": "^3.13.1",
@@ -451,37 +451,83 @@ export async function redoChecklist( req, res ) {
451
451
  let findQuestion = question[sectionIndex].questions.findIndex( ( ele ) => ele.qno == req.body.payload.qno );
452
452
 
453
453
  let data = { ...question[sectionIndex].questions[findQuestion], redo: true, redoComment: req.body.payload?.checklistDescription || '' };
454
- // if ( checklistDetails.client_id == '458' ) {
455
- data.answers.forEach( ( item ) => {
456
- if ( item.showLinked ) {
457
- item.nestedQuestion.forEach( ( ele ) => {
458
- let eleIndex = question[sectionIndex].questions.findIndex( ( qn ) => qn.qno == parseInt( ele ) );
459
- let element = { ...question[sectionIndex].questions[eleIndex], redo: true, redoComment: '', linkquestionenabled: false };
460
- question[sectionIndex].questions[eleIndex] = element;
461
- question[sectionIndex].questions[eleIndex].userAnswer = [];
462
- question[sectionIndex].questions[eleIndex].remarks = '';
454
+ let answerIndex = req.body.payload?.answerIndex;
455
+ let isSingleAnswerRedo = answerIndex != null;
456
+
457
+ if ( !isSingleAnswerRedo ) {
458
+ // if ( checklistDetails.client_id == '458' ) {
459
+ data.answers.forEach( ( item ) => {
460
+ if ( item.showLinked ) {
461
+ item.nestedQuestion.forEach( ( ele ) => {
462
+ let eleIndex = question[sectionIndex].questions.findIndex( ( qn ) => qn.qno == parseInt( ele ) );
463
+ let element = { ...question[sectionIndex].questions[eleIndex], redo: true, redoComment: '', linkquestionenabled: false };
464
+ question[sectionIndex].questions[eleIndex] = element;
465
+ question[sectionIndex].questions[eleIndex].userAnswer = [];
466
+ question[sectionIndex].questions[eleIndex].remarks = '';
467
+ } );
468
+ }
469
+ } );
470
+ // data.answers.forEach( ( item ) => {
471
+ // if ( item.showLinked ) {
472
+ // item.nestedQuestion = [];
473
+ // item.showLinked = false;
474
+ // item.linkedQuestion = 0;
475
+ // }
476
+ // } );
477
+ // }
478
+ }
479
+ let userAnswer = Array.isArray( data.userAnswer ) ? [ ...data.userAnswer ] : [];
480
+
481
+ question[sectionIndex].questions[findQuestion] = data;
482
+ if ( isSingleAnswerRedo ) {
483
+ let targetQuestion = question[sectionIndex].questions[findQuestion];
484
+ let targetUserAnswerIndex = targetQuestion.userAnswer?.findIndex( ( ele ) => ele.answer == req.body.payload.answerName );
485
+ let targetUserAnswer = targetQuestion.userAnswer[targetUserAnswerIndex];
486
+ if ( targetUserAnswer && Array.isArray( targetQuestion.answers ) ) {
487
+ let matchedAnsIdx = targetQuestion.answers.findIndex( ( ans ) => {
488
+ // if ( targetUserAnswer.no !== undefined && ans.index === targetUserAnswer.no ) return true;
489
+ // if ( targetUserAnswer.index !== undefined && ans.index === targetUserAnswer.index ) return true;
490
+ // if ( targetUserAnswer.answeroptionNumber !== undefined && ans.answeroptionNumber === targetUserAnswer.answeroptionNumber ) return true;
491
+ return ans.answer === targetUserAnswer.answer;
463
492
  } );
493
+ if ( matchedAnsIdx !== -1 ) {
494
+ targetQuestion.answers[matchedAnsIdx].redo = true;
495
+ targetQuestion.answers[matchedAnsIdx].validationAnswer = '';
496
+ targetQuestion.remarks = '';
497
+ }
498
+ targetQuestion.userAnswer.splice( targetUserAnswerIndex, 1 );
464
499
  }
465
- } );
466
- // data.answers.forEach( ( item ) => {
467
- // if ( item.showLinked ) {
468
- // item.nestedQuestion = [];
469
- // item.showLinked = false;
470
- // item.linkedQuestion = 0;
471
- // }
472
- // } );
473
- // }
474
- let userAnswer = data.userAnswer;
475
500
 
476
- question[sectionIndex].questions[findQuestion] = data;
477
- question[sectionIndex].questions[findQuestion].userAnswer = [];
478
- question[sectionIndex].questions[findQuestion].remarks = '';
501
+ let currentQno = req.body.payload.qno;
502
+ let parentQIndex = -1;
503
+ // let parentAnsIndex = -1;
504
+ for ( let i = 0; i < question[sectionIndex].questions.length; i++ ) {
505
+ let parentAnswers = question[sectionIndex].questions[i].answers || [];
506
+ let foundAnsIdx = parentAnswers.findIndex( ( ans ) => Array.isArray( ans?.nestedQuestion ) && ans.nestedQuestion.some( ( ele ) => parseInt( ele ) == currentQno ) );
507
+ if ( foundAnsIdx !== -1 ) {
508
+ parentQIndex = i;
509
+ // parentAnsIndex = foundAnsIdx;
510
+ break;
511
+ }
512
+ }
513
+ if ( parentQIndex !== -1 ) {
514
+ let parentQno = question[sectionIndex].questions[parentQIndex].qno;
515
+ question[sectionIndex].questions[findQuestion].parentQno = parentQno;
516
+ // question[sectionIndex].questions[findQuestion].remarks = '';
517
+ // question[sectionIndex].questions[parentQIndex].answers[parentAnsIndex].redo = true;
518
+ // question[sectionIndex].questions[parentQIndex].answers[parentAnsIndex].validationAnswer = '';
519
+ }
520
+ } else {
521
+ question[sectionIndex].questions[findQuestion].userAnswer = [];
522
+ question[sectionIndex].questions[findQuestion].remarks = '';
523
+ }
479
524
  checklistDetails.questionAnswers = question;
480
525
  let updateData = {
481
- checklistStatus: 'open',
526
+ checklistStatus: checklistDetails.checklistStatus != 'submit' ? checklistDetails.checklistStatus : 'open',
482
527
  redoStatus: true,
483
528
  reinitiateStatus: true,
484
529
  questionAnswers: question,
530
+ ...( checklistDetails.checklistStatus != 'submit' && checklistDetails.redoStatus ) ? { redoEdit: true } : {},
485
531
  };
486
532
 
487
533
  let response = await processedChecklist.updateOne( { _id: req.body.payload._id }, updateData );
@@ -4533,8 +4533,8 @@ export async function recurringFlagAlert( req, res ) {
4533
4533
  } );
4534
4534
  }
4535
4535
  const g = groupMap.get( k );
4536
- g.questionCount += 1;
4537
- g.runAICount += ( i.runAICount || 0 );
4536
+ if ( i.sopFired ) g.questionCount += 1;
4537
+ if ( i.runAIFired ) g.runAICount += 1;
4538
4538
  if ( parseSubmissionDate( i.lastSubmissionDate ) > parseSubmissionDate( g.lastSubmissionDate ) ) {
4539
4539
  g.lastSubmissionDate = i.lastSubmissionDate;
4540
4540
  g.lastSubmittedBy = i.lastSubmittedBy;
@@ -4573,6 +4573,7 @@ export async function recurringFlagAlert( req, res ) {
4573
4573
  isMultiStore,
4574
4574
  isMultiChecklist,
4575
4575
  isMultiStoreSingleChecklist,
4576
+ isUserCoverage: isAllUser,
4576
4577
  showTable: isMultiStore || isMultiChecklist,
4577
4578
  hasAttachment,
4578
4579
  domain: flagDomain,
@@ -4699,7 +4700,7 @@ function computeWow( current, previous ) {
4699
4700
 
4700
4701
  async function aggregateWeeklyFlagsByStore( weekStart, weekEnd ) {
4701
4702
  const rows = await processedchecklist.aggregate( [
4702
- { $match: { date_string: { $gte: weekStart, $lte: weekEnd }, isdeleted: { $ne: true } } },
4703
+ { $match: { date_string: { $gte: weekStart, $lte: weekEnd }, checkListType: 'custom' } },
4703
4704
  { $group: {
4704
4705
  _id: { client_id: '$client_id', store_id: '$store_id' },
4705
4706
  storeName: { $last: '$storeName' },
@@ -4982,7 +4983,7 @@ export async function weeklyWrapAlert( req, res ) {
4982
4983
  // resolveUserAssignedStores — superadmin / tango users see everything, regular admins see only
4983
4984
  // stores they own (assignedStores + clusters they lead + teams they're in/lead).
4984
4985
  const adminUsers = await userService.find(
4985
- { clientId: String( clientId ), email: { $in: [ 'gopisjkg@gmail.com', 'sh9628hs@gmail.com' ] }, role: { $in: [ 'admin', 'superadmin' ] } },
4986
+ { clientId: String( clientId ), role: { $in: [ 'admin', 'superadmin' ] } },
4986
4987
  { email: 1, assignedStores: 1, userName: 1, userType: 1, role: 1, clientId: 1 },
4987
4988
  );
4988
4989
  console.log( adminUsers );
@@ -1082,12 +1082,15 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1082
1082
  try {
1083
1083
  let requestData = req.body;
1084
1084
  requestData.questionAnswers = typeof requestData.questionAnswers == 'string' ? JSON.parse( requestData.questionAnswers ) : requestData.questionAnswers;
1085
- let getChecklistQA = await processedchecklist.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1 } );
1085
+ let getChecklistQA = await processedchecklist.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1, redoEdit: 1 } );
1086
1086
  let reqAnswers = requestData.questionAnswers;
1087
1087
  logger.error( { functionName: 'updatedPayload', message: reqAnswers } );
1088
1088
  let CLQAnswers = getChecklistQA.questionAnswers;
1089
1089
 
1090
1090
  if ( requestData.submittype == 'submit' ) {
1091
+ if ( getChecklistQA?.redoEdit ) {
1092
+ requestData.submittype = 'draft';
1093
+ }
1091
1094
  reqAnswers.forEach( ( reqA ) => {
1092
1095
  if ( ![ 'multiplechoicemultiple', 'multipleImage', 'image/video' ].includes( reqA?.answerType ) && ( reqA.answerType == 'dropDown' && !reqA.allowMultiple ) ) {
1093
1096
  if ( ( !reqA.linkType && ( reqA.answer == null || reqA.answer == '' ) ) || ( reqA.linkType && reqA.linkquestionenabled && ( reqA.answer == null || reqA.answer == '' ) ) ) {
@@ -1307,27 +1310,35 @@ export async function sopMobilechecklistMultiSectionFormatterv1( req, res, next
1307
1310
  for ( let k = 0; k < qaans.length; k++ ) {
1308
1311
  let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
1309
1312
  for ( let s = 0; s < separatedArray.length; s++ ) {
1310
- if ( separatedArray[s].answer == qaans[k].answer ) {
1311
- if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
1312
- if ( separatedArray[s].validationAnswer ) {
1313
- let validationAnswer = decodeURIComponent( separatedArray[s].validationAnswer.split( '?' )[0] );
1314
- if ( validationAnswer.length ) {
1315
- let splitImgUrl = validationAnswer.split( '/' );
1316
- if ( splitImgUrl.length > 1 ) {
1317
- splitImgUrl.splice( 0, 3 );
1318
- qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
1313
+ if ( ( separatedArray[s].answer == qaans[k].answer ) ) {
1314
+ if ( ( getChecklistQA?.redoEdit && qaans[k].redo == separatedArray[s].redo ) || !getChecklistQA?.redoEdit ) {
1315
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
1316
+ if ( separatedArray[s].validationAnswer ) {
1317
+ let validationAnswer = decodeURIComponent( separatedArray[s].validationAnswer.split( '?' )[0] );
1318
+ if ( validationAnswer.length ) {
1319
+ let splitImgUrl = validationAnswer.split( '/' );
1320
+ if ( splitImgUrl.length > 1 ) {
1321
+ splitImgUrl.splice( 0, 3 );
1322
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
1323
+ }
1319
1324
  }
1320
1325
  }
1321
- }
1322
- } else {
1326
+ } else {
1323
1327
  // qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
1324
- qaans[k].validationAnswer = separatedArray[s].validationAnswer || '';
1328
+ qaans[k].validationAnswer = separatedArray[s].validationAnswer || '';
1329
+ }
1325
1330
  }
1326
1331
 
1327
1332
  mcmo.push( qaans[k] );
1328
1333
  }
1329
1334
  }
1330
1335
  }
1336
+ qaAnswers[j].answers.forEach( ( ele ) => {
1337
+ if ( typeof ele?.redo === 'boolean' && requestData.submittype === 'submit' ) {
1338
+ ele.redo = false;
1339
+ }
1340
+ } );
1341
+
1331
1342
  let structure = {};
1332
1343
  structure.qno = qaAnswers[j].qno;
1333
1344
  structure.uniqueqno = qaAnswers[j].uniqueqno;
@@ -2113,8 +2124,12 @@ async function updateRecurringFlagTracker( processedChecklist, questionAnswers,
2113
2124
  } );
2114
2125
  } );
2115
2126
  if ( ops.length ) {
2116
- let data = await recurringFlagTracker.bulkWrite( ops );
2117
- console.log( data );
2127
+ try {
2128
+ let data = await recurringFlagTracker.bulkWrite( ops, { ordered: false } );
2129
+ console.log( 'recurringFlagTracker bulkWrite result', data );
2130
+ } catch ( bulkErr ) {
2131
+ logger.error( { function: 'updateRecurringFlagTracker.bulkWrite', code: bulkErr?.code, message: bulkErr?.message, writeErrors: bulkErr?.writeErrors } );
2132
+ }
2118
2133
  }
2119
2134
  } catch ( error ) {
2120
2135
  logger.error( { function: 'updateRecurringFlagTracker', error } );
@@ -2168,6 +2183,7 @@ export async function submitChecklist( req, res ) {
2168
2183
  let flagCount = QuestionFlag( req, res );
2169
2184
  updateData.questionFlag = flagCount;
2170
2185
  updateData.submitTime_string = currentDateTime.format( 'hh:mm A, DD MMM YYYY' );
2186
+ updateData.redoEdit = false;
2171
2187
  if ( requestData.deviceDetails && requestData.deviceDetails != '' ) {
2172
2188
  updateData.deviceDetails =JSON.parse( requestData.deviceDetails );
2173
2189
  }
@@ -2440,7 +2456,8 @@ export async function submitTask( req, res ) {
2440
2456
  'storeResponseTime': currentDateTime.format( 'HH:mm:ss - MMM DD, YYYY' ),
2441
2457
  'message_mode': 'retriggered',
2442
2458
  };
2443
- sendMessageToQueue( `${JSON.parse( process.env.SQS ).url}${JSON.parse( process.env.SQS ).storeHygiene}`, JSON.stringify( sqsData ) );
2459
+ let sqsResponse = await sendMessageToQueue( `${JSON.parse( process.env.SQS ).url}${JSON.parse( process.env.SQS ).storeHygiene}`, JSON.stringify( sqsData ) );
2460
+ console.log( sqsResponse );
2444
2461
  }
2445
2462
  if ( !excludedChecklists.includes( checklist.checkListName ) ) {
2446
2463
  const query1 = [
@@ -3616,7 +3633,7 @@ export async function questionList( req, res ) {
3616
3633
  checkvalidation = answer.validationAnswer;
3617
3634
  }
3618
3635
  }
3619
- Multianswer.push( { 'answer': answer.answer, 'no': ansIndex, 'validationAnswer': checkvalidation } );
3636
+ Multianswer.push( { 'answer': answer.answer, 'no': ansIndex, 'validationAnswer': checkvalidation, ...( answer.redo && { redo: answer.redo } ) } );
3620
3637
  getchecklist[0].questionAnswers[secIndex].questions[questionIndex].answers[ansIndex].index = ansIndex;
3621
3638
  }
3622
3639
 
@@ -162,7 +162,7 @@
162
162
  <table class="rfTable">
163
163
  <thead>
164
164
  <tr>
165
- {{#if data.isMultiStore}}<th>{{data.subjectLabel}} Name</th>{{/if}}
165
+ {{#if data.isMultiStore}}{{#unless data.isUserCoverage}}<th>{{data.subjectLabel}} Name</th>{{/unless}}{{/if}}
166
166
  {{#unless data.isMultiStoreSingleChecklist}}<th>Checklist Name</th>{{/unless}}
167
167
  <th>Last Submitted By</th>
168
168
  <th>Last Submission Date</th>
@@ -172,7 +172,7 @@
172
172
  <tbody>
173
173
  {{#each data.rows}}
174
174
  <tr>
175
- {{#if ../data.isMultiStore}}<td>{{this.subjectName}}</td>{{/if}}
175
+ {{#if ../data.isMultiStore}}{{#unless ../data.isUserCoverage}}<td>{{this.subjectName}}</td>{{/unless}}{{/if}}
176
176
  {{#unless ../data.isMultiStoreSingleChecklist}}<td>{{this.checklistName}}</td>{{/unless}}
177
177
  <td>{{this.lastSubmittedBy}}</td>
178
178
  <td>{{this.lastSubmissionDate}}</td>
@@ -136,6 +136,10 @@
136
136
  .headertitle.submittedText {
137
137
  width:116px !important;
138
138
  }
139
+
140
+ .flagged {
141
+ color:red
142
+ }
139
143
  </style>
140
144
  </head>
141
145
 
@@ -224,7 +228,7 @@
224
228
  <div class="px-4 answer">
225
229
  {{#if (includes ../../../data.validateType ../answerType)}}
226
230
  {{#eq sopFlag true }}
227
- <span id="agreed" style="color:red">{{answer}}</span><br>
231
+ <span id="agreed flagged">{{answer}}</span><br>
228
232
  {{/eq}}
229
233
  {{#eq sopFlag false }}
230
234
  <span id="agreed">{{answer}}</span><br>
@@ -255,7 +259,7 @@
255
259
  <a href="{{validationAnswer}}" target="_blank" style="text-decoration: underline;color:#0085D2" id="agreed">{{validationAnswer}}</a><br>
256
260
  {{/eq}}
257
261
  {{#eq validationType 'Descriptive Answer'}}
258
- {{validationAnswer}}
262
+ <span class="{{#if this.sopFlag}}flagged{{/if}}">Validation Answer: {{validationAnswer}}</span>
259
263
  {{/eq}}
260
264
  {{#eq validationType 'Capture Multiple Image with description'}}
261
265
  <div class="Reference"><span>Uploaded Image</span><br>
@@ -215,6 +215,17 @@
215
215
  </div>
216
216
  {{/if}}
217
217
  {{/eq}}
218
+ {{#eq this.validationDisplayType 'text'}}
219
+ {{#if this.validationAnswer}}
220
+ <div class="q-answer-text {{#if this.sopFlag}}flagged{{/if}}">validation Answer: {{this.validationAnswer}}</div>
221
+ {{/if}}
222
+ {{/eq}}
223
+ {{#eq this.validationDisplayType 'video'}}
224
+ {{#if this.validationAnswer}}
225
+ <div class="q-answer-caption">Validation Video</div>
226
+ <a class="q-answer-link" href="{{this.validationAnswer}}" target="_blank">{{this.validationAnswer}}</a>
227
+ {{/if}}
228
+ {{/eq}}
218
229
 
219
230
  <table style="width:100%;margin-top:8px;table-layout:fixed"><tr>
220
231
  <td style="width:50%;vertical-align:top;padding-right:8px">
@@ -233,16 +244,54 @@
233
244
  <div class="q-answer-caption">Reference Image</div>
234
245
  <img src="{{this.referenceImage}}" alt="Reference Image" />
235
246
  </div>
247
+ {{else}}
248
+ {{#eq this.answerType 'image'}}
249
+ {{#if this.answer}}
250
+ <div class="q-answer-media">
251
+ <div class="q-answer-caption">Uploaded Image</div>
252
+ <img src="{{this.answer}}" alt="Uploaded Image" />
253
+ </div>
254
+ {{/if}}
255
+ {{/eq}}
236
256
  {{/if}}
237
257
  {{/if}}
258
+ {{else}}
259
+ {{#eq this.answerType 'image'}}
260
+ {{#if this.answer}}
261
+ <div class="q-answer-media">
262
+ <div class="q-answer-caption">Uploaded Image</div>
263
+ <img src="{{this.answer}}" alt="Uploaded Image" />
264
+ </div>
265
+ {{/if}}
266
+ {{/eq}}
238
267
  {{/neq}}
268
+ {{else}}
269
+ {{#eq this.answerType 'image'}}
270
+ {{#if this.answer}}
271
+ <div class="q-answer-media">
272
+ <div class="q-answer-caption">Uploaded Image</div>
273
+ <img src="{{this.answer}}" alt="Uploaded Image" />
274
+ </div>
275
+ {{/if}}
276
+ {{/eq}}
239
277
  {{/neq}}
240
278
  </td>
241
279
  <td style="width:50%;vertical-align:top;padding-left:8px">
242
280
  {{#eq this.answerType 'image'}}
243
281
  {{#if this.answer}}
244
- <div class="q-answer-caption">Uploaded Image</div>
245
- <img src="{{this.answer}}" alt="Uploaded Image" />
282
+ {{#neq ../answerType 'image/video'}}
283
+ {{#neq ../answerType 'multipleImage'}}
284
+ {{#if this.multiReferenceImage.length}}
285
+ <div class="q-answer-caption">Uploaded Image</div>
286
+ <img src="{{this.answer}}" alt="Uploaded Image" />
287
+ {{else}}
288
+ {{#if this.referenceImage}}
289
+ <div class="q-answer-caption">Uploaded Image</div>
290
+ <img src="{{this.answer}}" alt="Uploaded Image" />
291
+ {{/if}}
292
+ {{/if}}
293
+ {{/neq}}
294
+ {{/neq}}
246
295
  {{/if}}
247
296
  {{/eq}}
248
297
  {{#if this.validation}}
@@ -251,18 +300,7 @@
251
300
  <div class="q-answer-caption">Validation Image</div>
252
301
  <img src="{{this.validationAnswer}}" alt="Validation Image" />
253
302
  {{/if}}
254
- {{/eq}}
255
- {{#eq this.validationDisplayType 'video'}}
256
- {{#if this.validationAnswer}}
257
- <div class="q-answer-caption">Validation Video</div>
258
- <a class="q-answer-link" href="{{this.validationAnswer}}" target="_blank">{{this.validationAnswer}}</a>
259
- {{/if}}
260
- {{/eq}}
261
- {{#eq this.validationDisplayType 'text'}}
262
- {{#if this.validationAnswer}}
263
- <div class="q-answer-text">{{this.validationAnswer}}</div>
264
- {{/if}}
265
- {{/eq}}
303
+ {{/eq}}
266
304
  {{#eq this.validationDisplayType 'multiImage'}}
267
305
  {{#if this.validationImage.length}}
268
306
  <div class="q-answer-caption">Validation Image</div>