tango-app-api-trax 1.0.0-alpha-task.130

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 (49) hide show
  1. package/.eslintrc.cjs +41 -0
  2. package/README.md +29 -0
  3. package/fir-51e77-firebase-adminsdk-x3sdp-fd902b74ae.json +14 -0
  4. package/index.js +12 -0
  5. package/package.json +43 -0
  6. package/src/controllers/download.controller.js +544 -0
  7. package/src/controllers/gallery.controller.js +457 -0
  8. package/src/controllers/internalTrax.controller.js +989 -0
  9. package/src/controllers/locus.controller.js +214 -0
  10. package/src/controllers/mobileTrax.controller.js +2327 -0
  11. package/src/controllers/teaxFlag.controller.js +2699 -0
  12. package/src/controllers/trax.controller.js +2214 -0
  13. package/src/controllers/traxDashboard.controllers.js +3523 -0
  14. package/src/dtos/dashboardValidation.dtos.js +143 -0
  15. package/src/dtos/downloadValidation.dtos.js +44 -0
  16. package/src/dtos/validation.dtos.js +138 -0
  17. package/src/hbs/login-otp.hbs +944 -0
  18. package/src/routes/download.router.js +23 -0
  19. package/src/routes/gallery.routes.js +28 -0
  20. package/src/routes/internalTraxApi.router.js +19 -0
  21. package/src/routes/locus.router.js +16 -0
  22. package/src/routes/mobileTrax.routes.js +25 -0
  23. package/src/routes/trax.routes.js +24 -0
  24. package/src/routes/traxDashboard.routes.js +59 -0
  25. package/src/routes/traxFlag.router.js +74 -0
  26. package/src/services/app.service.js +10 -0
  27. package/src/services/approver.service.js +20 -0
  28. package/src/services/authentication.service.js +6 -0
  29. package/src/services/checklist.service.js +31 -0
  30. package/src/services/checklistAssign.service.js +31 -0
  31. package/src/services/checklistQuestion.service.js +31 -0
  32. package/src/services/checklistlog.service.js +35 -0
  33. package/src/services/clientRequest.service.js +5 -0
  34. package/src/services/clients.services.js +23 -0
  35. package/src/services/domain.service.js +28 -0
  36. package/src/services/download.services.js +38 -0
  37. package/src/services/group.service.js +22 -0
  38. package/src/services/lenskartEmployeeMapping.service.js +15 -0
  39. package/src/services/locus.service.js +34 -0
  40. package/src/services/otp.service.js +14 -0
  41. package/src/services/processedTaskConfig.service.js +32 -0
  42. package/src/services/processedTaskList.service.js +30 -0
  43. package/src/services/processedchecklist.services.js +36 -0
  44. package/src/services/processedchecklistconfig.services.js +35 -0
  45. package/src/services/store.service.js +31 -0
  46. package/src/services/tagging.service.js +5 -0
  47. package/src/services/ticket.service.js +15 -0
  48. package/src/services/user.service.js +25 -0
  49. package/src/services/userAssignedstores.service.js +10 -0
@@ -0,0 +1,2327 @@
1
+ import { logger, signedUrl, fileUpload, getOtp, sendEmailWithSES, getUuid } from 'tango-app-api-middleware';
2
+ import * as processedchecklist from '../services/processedchecklist.services.js';
3
+ import * as processedtask from '../services/processedTaskList.service.js';
4
+ import * as PCLconfig from '../services/processedchecklistconfig.services.js';
5
+ import * as processedTaskConfigService from '../services/processedTaskConfig.service.js';
6
+ import * as storeService from '../services/store.service.js';
7
+ import * as checklistService from '../services/checklist.service.js';
8
+ import * as processedTask from '../services/processedTaskList.service.js';
9
+ import * as checklistLogs from '../services/checklistlog.service.js';
10
+ import { insertSingleProcessData } from './trax.controller.js';
11
+ import * as userService from '../services/user.service.js';
12
+ import dayjs from 'dayjs';
13
+ import mongoose from 'mongoose';
14
+ import * as appService from '../services/app.service.js';
15
+ const ObjectId = mongoose.Types.ObjectId;
16
+ import customParseFormat from 'dayjs/plugin/customParseFormat.js';
17
+ import timeZone from 'dayjs/plugin/timezone.js';
18
+ import { findOTP, updateOneOTP } from '../services/otp.service.js';
19
+ import * as clientService from '../services/clients.services.js';
20
+ import { create } from '../services/authentication.service.js';
21
+ import { readFileSync } from 'fs';
22
+ import { join } from 'path';
23
+ import handlebars from 'handlebars';
24
+ dayjs.extend( customParseFormat );
25
+ dayjs.extend( timeZone );
26
+
27
+ export async function storeList( req, res ) {
28
+ try {
29
+ if ( !req.query?.date ) {
30
+ return res.sendError( 'date is required', 400 );
31
+ }
32
+ let userChecklist = await processedchecklist.find( { userId: req.user._id, userEmail: req.user.email, client_id: req.user.clientId, date_string: dayjs( req.query.date ).format( 'YYYY-MM-DD' ) }, { store_id: 1, storeName: 1 } );
33
+ if ( !userChecklist.length ) {
34
+ return res.sendSuccess( [] );
35
+ }
36
+
37
+ userChecklist = Array.from(
38
+ new Map( userChecklist.map( ( item ) => [ item.store_id, item ] ) ).values(),
39
+ );
40
+
41
+ let storeIdList = userChecklist.map( ( item ) => item.store_id );
42
+ let storeStatus = await storeService.find( { storeId: { $in: storeIdList }, status: 'active', clientId: req.user.clientId }, { storeId: 1, storeName: 1 } );
43
+ if ( storeStatus.length ) {
44
+ storeStatus = storeStatus.map( ( item ) => {
45
+ return { store_id: item.storeId, storeName: item.storeName };
46
+ } );
47
+ }
48
+
49
+ return res.sendSuccess( storeStatus );
50
+ } catch ( e ) {
51
+ logger.error( { function: storeList, error: e } );
52
+ return res.sendError( e, 500 );
53
+ }
54
+ }
55
+
56
+ export async function storeListv1( req, res ) {
57
+ try {
58
+ if ( !req.query?.date ) {
59
+ return res.sendError( 'date is required', 400 );
60
+ }
61
+ let userChecklist = await processedchecklist.find( { userId: req.user._id, userEmail: req.user.email, date_string: dayjs( req.query.date ).format( 'YYYY-MM-DD' ) }, { store_id: 1, storeName: 1 } );
62
+
63
+ let userTask = await processedTask.find( { userId: req.user._id, userEmail: req.user.email, date_string: dayjs( req.query.date ).format( 'YYYY-MM-DD' ) }, { store_id: 1, storeName: 1 } );
64
+
65
+ if ( !userChecklist.length && !userTask.length ) {
66
+ return res.sendSuccess( [] );
67
+ }
68
+
69
+ let allStores = [ ...userChecklist, ...userTask ];
70
+
71
+ allStores = Array.from(
72
+ new Map( allStores.map( ( item ) => [ item.store_id, item ] ) ).values(),
73
+ );
74
+
75
+ let storeIdList = allStores.map( ( item ) => item.store_id );
76
+ let storeStatus = await storeService.find( { storeId: { $in: storeIdList }, status: 'active' }, { storeId: 1, storeName: 1 } );
77
+ if ( storeStatus.length ) {
78
+ storeStatus = storeStatus.map( ( item ) => {
79
+ return { store_id: item.storeId, storeName: item.storeName };
80
+ } );
81
+ }
82
+
83
+ return res.sendSuccess( storeStatus );
84
+ } catch ( e ) {
85
+ logger.error( { function: 'storeListv1', error: e } );
86
+ return res.sendError( e, 500 );
87
+ }
88
+ }
89
+
90
+ export async function startChecklist( req, res ) {
91
+ try {
92
+ let requestData = req.body;
93
+ let findQuery = [];
94
+ findQuery.push( {
95
+ $match: {
96
+ $and: [
97
+ { _id: new ObjectId( requestData.processedcheckListId ) },
98
+ { userId: req.user._id },
99
+ { date_string: requestData.date },
100
+ ],
101
+ },
102
+ } );
103
+
104
+ let getBeforeChecklist = await processedchecklist.aggregate( findQuery );
105
+ if ( !getBeforeChecklist.length ) {
106
+ return res.sendError( 'Check List Got Edited Please Fill Again', 422 );
107
+ }
108
+
109
+ if ( getBeforeChecklist[0].checklistStatus != 'open' ) {
110
+ return res.sendError( 'already check list started', 400 );
111
+ }
112
+
113
+ logger.info( `v5 => Checklist Started => store Name: ${getBeforeChecklist[0].storeName}, User Email: ${getBeforeChecklist[0].userEmail}, Checklist Name: ${getBeforeChecklist[0].checkListName}` );
114
+ let PCLQusestion = await PCLconfig.findOne( { _id: new ObjectId( getBeforeChecklist[0].checkListId ) } );
115
+ let updateQuery = {};
116
+ updateQuery._id = new ObjectId( requestData.processedcheckListId );
117
+ updateQuery.userId = req.user._id;
118
+ updateQuery.date_string = requestData.date;
119
+
120
+ if ( PCLQusestion && PCLQusestion?.questionAnswers && PCLQusestion?.questionAnswers.length > 0 ) {
121
+ await PCLQusestion.questionAnswers.forEach( ( section ) => {
122
+ section.questions.forEach( ( question ) => {
123
+ if ( question.answerType == 'multiplechoicemultiple' ) {
124
+ let Multianswer = [];
125
+ if ( question.answers.length > 0 ) {
126
+ question.answers.forEach( ( answer, ansIndex ) => {
127
+ Multianswer.push( { 'answer': null, 'no': ansIndex, 'validationAnswer': null } );
128
+ answer.index = ansIndex;
129
+ } );
130
+ question.Multianswer = Multianswer;
131
+ }
132
+ } else if ( question.answerType == 'multipleImage' ) {
133
+ let Multianswer = [];
134
+ if ( question.answers.length > 0 ) {
135
+ question.answers.forEach( ( answer, ansIndex ) => {
136
+ Multianswer.push( { 'answer': null, 'no': ansIndex, 'validationAnswer': null } );
137
+ answer.index = ansIndex;
138
+ } );
139
+ question.Multianswer = Multianswer;
140
+ }
141
+ } else {
142
+ question.Multianswer = [];
143
+ }
144
+ } );
145
+ } );
146
+ }
147
+
148
+ let updateData = {};
149
+ let storeTimeZone = await storeService.findOne( { storeName: getBeforeChecklist[0].storeName }, { 'storeProfile.timeZone': 1 } );
150
+ let currentDateTime;
151
+ if ( storeTimeZone?.storeProfile?.timeZone ) {
152
+ currentDateTime = dayjs().tz( storeTimeZone?.storeProfile?.timeZone );
153
+ } else {
154
+ currentDateTime = dayjs();
155
+ }
156
+ updateData.checklistStatus = 'inprogress';
157
+ updateData.startMobileTime = requestData?.currentTime;
158
+ updateData.questionAnswers = getBeforeChecklist[0]?.redoStatus ? getBeforeChecklist[0].questionAnswers : PCLQusestion.questionAnswers;
159
+ // const newDateTime = currentDateTime.add(5, 'hours').add(30, 'minutes');
160
+ // updateData.startTime_string = newDateTime.format('hh:mm A, DD MMM');
161
+ updateData.startTime_string = currentDateTime.format( 'hh:mm A, DD MMM YYYY' );
162
+ updateData.startTime = dayjs.utc( updateData.startTime_string, 'hh:mm A, DD MMM YYYY' ).format();
163
+
164
+ let updatechecklist = await processedchecklist.updateOne( updateQuery, updateData );
165
+ PCLQusestion.startTime = dayjs.utc( updateData.startTime_string, 'hh:mm A, DD MMM YYYY' ).format();
166
+ PCLQusestion.save();
167
+ if ( updatechecklist.modifiedCount > 0 ) {
168
+ findQuery.push( {
169
+ $project: {
170
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
171
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
172
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
173
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
174
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
175
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
176
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
177
+ startTime: { $ifNull: [ '$startTime', '' ] },
178
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
179
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
180
+ allowedStoreLocation: { $ifNull: [ '$checallowedStoreLocationkListName', false ] },
181
+ questionAnswers: { $ifNull: [ '$questionAnswers', '' ] },
182
+ redoStatus: { $ifNull: [ '$redoStatus', '' ] },
183
+ },
184
+ } );
185
+ let getupdatedchecklist = await processedchecklist.aggregate( findQuery );
186
+ let bucket = JSON.parse( process.env.BUCKET );
187
+ getupdatedchecklist[0].questionAnswers.forEach( ( section ) => {
188
+ section.questions.forEach( async ( question ) => {
189
+ if ( question.questionReferenceImage && question.questionReferenceImage!='' ) {
190
+ question.questionReferenceImage = await signedUrl( { Bucket: bucket.sop, file_path: decodeURIComponent( question.questionReferenceImage ) } );
191
+ }
192
+ question.answers.forEach( async ( answer ) => {
193
+ if ( answer.referenceImage != '' ) {
194
+ answer.referenceImage = await signedUrl( { Bucket: bucket.sop, file_path: decodeURIComponent( answer.referenceImage ) } );
195
+ }
196
+ } );
197
+ } );
198
+ } );
199
+ let logInsertData = {
200
+ store_id: getBeforeChecklist[0].store_id,
201
+ storeName: getBeforeChecklist[0].storeName,
202
+ action: 'started',
203
+ checklistId: getBeforeChecklist[0].checkListId,
204
+ checkListName: getBeforeChecklist[0].checkListName,
205
+ checkListType: getBeforeChecklist[0].checkListType,
206
+ client_id: req.user.clientId,
207
+ };
208
+ await checklistLogs.create( logInsertData );
209
+
210
+ let getchecklist = getupdatedchecklist;
211
+ let questions = [];
212
+ function processQuestion( question, section, questions, nested=false ) {
213
+ let findExists = questions.find( ( item ) => item?.qno && item.qno == question.qno );
214
+ if ( findExists && nested ) {
215
+ let findIndex = questions.findIndex( ( item ) => item?.qno && item.qno == question.qno );
216
+ questions.splice( findIndex, 1 );
217
+ questions.push( question );
218
+ }
219
+ if ( !findExists ) {
220
+ questions.push( question );
221
+ for ( let answer of question.answers ) {
222
+ if ( answer.showLinked && answer?.linkedQuestion != '' ) {
223
+ let linkedQuestion = section.questions.find( ( item ) => item.qno == answer.linkedQuestion );
224
+ if ( linkedQuestion ) {
225
+ processQuestion( linkedQuestion, section, questions, true );
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+ for ( let [ index, data ] of getchecklist.entries() ) {
232
+ for ( let [ secIndex, section ] of data.questionAnswers.entries() ) {
233
+ questions = [];
234
+ for ( let question of section.questions ) {
235
+ processQuestion( question, section, questions );
236
+ }
237
+ getchecklist[index].questionAnswers[secIndex].questions = questions;
238
+ }
239
+ }
240
+ return res.sendSuccess( getchecklist );
241
+ } else {
242
+ return res.sendError( 'something went wrong please try again', 500 );
243
+ }
244
+ } catch ( e ) {
245
+ logger.error( { function: 'startChecklist', error: e } );
246
+ return res.sendError( e, 500 );
247
+ }
248
+ }
249
+
250
+ export async function startTask( req, res ) {
251
+ try {
252
+ const { body: requestData, user } = req;
253
+
254
+ const findQuery = [
255
+ {
256
+ $match: {
257
+ $and: [
258
+ { _id: new ObjectId( requestData.processedcheckListId ) },
259
+ { userId: user._id },
260
+ { date_string: requestData.date },
261
+ ],
262
+ },
263
+ },
264
+ ];
265
+
266
+ const getBeforeTask = await processedTask.aggregate( findQuery );
267
+ if ( !getBeforeTask.length ) {
268
+ return res.sendError( 'Task edited. Please fill again.', 422 );
269
+ }
270
+
271
+ const task = getBeforeTask[0];
272
+ if ( task.checklistStatus !== 'open' ) {
273
+ return res.sendError( 'Task already started', 400 );
274
+ }
275
+
276
+ logger.info(
277
+ `v5 => Checklist Started => store Name: ${task.storeName}, User Email: ${task.userEmail}, Checklist Name: ${task.checkListName}`,
278
+ );
279
+
280
+ const processedTaskConfig = await processedTaskConfigService.findOne( { _id: new ObjectId( task.checkListId ) } );
281
+
282
+ if ( processedTaskConfig?.questionAnswers?.length > 0 ) {
283
+ for ( const section of processedTaskConfig.questionAnswers ) {
284
+ for ( const question of section.questions ) {
285
+ if ( [ 'multiplechoicemultiple', 'multipleImage' ].includes( question.answerType ) ) {
286
+ question.Multianswer = question.answers.map( ( _, index ) => ( {
287
+ answer: null,
288
+ no: index,
289
+ validationAnswer: null,
290
+ } ) );
291
+ } else {
292
+ question.Multianswer = [];
293
+ }
294
+ }
295
+ }
296
+ }
297
+
298
+ const storeTimeZone = await storeService.findOne(
299
+ { storeName: task.storeName },
300
+ { 'storeProfile.timeZone': 1 },
301
+ );
302
+ const currentDateTime = storeTimeZone?.storeProfile?.timeZone ?
303
+ dayjs().tz( storeTimeZone.storeProfile.timeZone ) :
304
+ dayjs();
305
+
306
+ const updateData = {
307
+ checklistStatus: 'inprogress',
308
+ startMobileTime: requestData?.currentTime,
309
+ questionAnswers: task.redoStatus ? task.questionAnswers : processedTaskConfig.questionAnswers,
310
+ startTime_string: currentDateTime.format( 'hh:mm A, DD MMM YYYY' ),
311
+ startTime: dayjs
312
+ .utc( currentDateTime.format( 'hh:mm A, DD MMM YYYY' ), 'hh:mm A, DD MMM YYYY' )
313
+ .format(),
314
+ };
315
+
316
+ const updateQuery = {
317
+ _id: new ObjectId( requestData.processedcheckListId ),
318
+ userId: user._id,
319
+ date_string: requestData.date,
320
+ };
321
+
322
+ const updateTaskResult = await processedTask.updateOne( updateQuery, updateData );
323
+
324
+ if ( !updateTaskResult?.matchedCount ) {
325
+ return res.sendError( 'Something went wrong, please try again', 500 );
326
+ }
327
+
328
+ processedTaskConfig.startTime = updateData.startTime;
329
+ await processedTaskConfig.save();
330
+
331
+ findQuery.push( {
332
+ $project: {
333
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
334
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
335
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
336
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
337
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
338
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
339
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
340
+ startTime: { $ifNull: [ '$startTime', '' ] },
341
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
342
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
343
+ allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', false ] },
344
+ questionAnswers: { $ifNull: [ '$questionAnswers', '' ] },
345
+ redoStatus: { $ifNull: [ '$redoStatus', '' ] },
346
+ },
347
+ } );
348
+ const getUpdatedTask = await processedTask.aggregate( findQuery );
349
+
350
+
351
+ const bucket = JSON.parse( process.env.BUCKET );
352
+ await Promise.all(
353
+ getUpdatedTask[0].questionAnswers.map( ( section ) =>
354
+ section.questions.map( async ( question ) => {
355
+ if ( question.questionReferenceImage ) {
356
+ question.questionReferenceImage = await signedUrl( {
357
+ Bucket: bucket.sop,
358
+ file_path: decodeURIComponent( question.questionReferenceImage ),
359
+ } );
360
+ }
361
+ await Promise.all(
362
+ question.answers.map( async ( answer ) => {
363
+ if ( answer.referenceImage ) {
364
+ answer.referenceImage = await signedUrl( {
365
+ Bucket: bucket.sop,
366
+ file_path: decodeURIComponent( answer.referenceImage ),
367
+ } );
368
+ }
369
+ } ),
370
+ );
371
+ } ),
372
+ ).flat(),
373
+ );
374
+
375
+
376
+ const logData = {
377
+ store_id: task.store_id,
378
+ storeName: task.storeName,
379
+ action: 'started',
380
+ checklistId: task.checkListId,
381
+ checkListName: task.checkListName,
382
+ checkListType: task.checkListType,
383
+ client_id: user.clientId,
384
+ };
385
+ await checklistLogs.create( logData );
386
+
387
+ return res.sendSuccess( getUpdatedTask );
388
+ } catch ( error ) {
389
+ logger.error( { function: 'startTask', error } );
390
+ return res.sendError( error, 500 );
391
+ }
392
+ }
393
+
394
+ export async function sopMobilechecklistValidater( req, res, next ) {
395
+ try {
396
+ let requestData = req.body;
397
+ let validateError = '';
398
+ if (
399
+ !requestData.hasOwnProperty( 'date' ) ||
400
+ requestData.date === undefined ||
401
+ requestData.date === null ||
402
+ requestData.date == ''
403
+ ) {
404
+ validateError = validateError + 'Date, ';
405
+ }
406
+
407
+ if ( !requestData.hasOwnProperty( 'processedcheckListId' ) ||
408
+ requestData.processedcheckListId === undefined ||
409
+ requestData.processedcheckListId === null ||
410
+ requestData.processedcheckListId == ''
411
+ ) {
412
+ validateError = validateError + 'ProcessedcheckListId, ';
413
+ }
414
+
415
+ if ( !requestData.hasOwnProperty( 'questionAnswers' ) || requestData.questionAnswerslength == 0 ) {
416
+ validateError = validateError + 'questionAnswers ';
417
+ }
418
+
419
+ if ( validateError.length > 0 ) {
420
+ return res.sendError( validateError + 'Is Reqired', 400 );
421
+ } else {
422
+ next();
423
+ }
424
+ } catch ( error ) {
425
+ logger.error( { function: 'sopMobilechecklistValidater', error: error } );
426
+ return res.sendError( error );
427
+ }
428
+ };
429
+
430
+ export async function sopMobilechecklistQuestionValidator( req, res, next ) {
431
+ try {
432
+ let requestData = req.body;
433
+ requestData.questionAnswers = typeof requestData.questionAnswers == 'string' ? JSON.parse( requestData.questionAnswers ) : requestData.questionAnswers;
434
+ let getChecklistQA = await processedchecklist.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1 } );
435
+ if ( !getChecklistQA ) {
436
+ return res.sendError( 'Check List Got Edited Please Fill Again', 422 );
437
+ }
438
+ if ( requestData.submittype == 'submit' ) {
439
+ let reqAnswers = requestData.questionAnswers;
440
+ let CLQAnswers = getChecklistQA.questionAnswers;
441
+ let validationCount= 0;
442
+ CLQAnswers.forEach( ( section ) => {
443
+ let requestSection = reqAnswers.filter( ( reqSection ) => reqSection.section_id == section.section_id );
444
+ section.questions.forEach( ( question ) => {
445
+ question.answers.forEach( ( answer ) => {
446
+ let sectionQuestion = requestSection.filter( ( secQuestion ) => secQuestion.qno == question.qno );
447
+ if ( question.answerType == 'multiplechoicemultiple' && ( sectionQuestion[0].Multianswer == null || sectionQuestion[0].Multianswer == '' || !sectionQuestion[0].Multianswer.length ) ) {
448
+ validationCount++;
449
+ } else {
450
+ if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( question.answerType ) && ( ( !sectionQuestion[0].linkType && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) || ( sectionQuestion[0].linkType && sectionQuestion[0].linkquestionenabled && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) ) ) {
451
+ validationCount++;
452
+ }
453
+ }
454
+ } );
455
+ } );
456
+ } );
457
+ if ( validationCount ) {
458
+ return res.sendError( 'Please Fill all Required Fields', 400 );
459
+ } else {
460
+ next();
461
+ }
462
+ } else {
463
+ next();
464
+ }
465
+ } catch ( e ) {
466
+ logger.error( { function: 'sopMobilechecklistQuestionValidator', error: e } );
467
+ return res.sendError( e, 500 );
468
+ }
469
+ };
470
+
471
+ export async function sopMobileTaskQuestionValidator( req, res, next ) {
472
+ try {
473
+ let requestData = req.body;
474
+ requestData.questionAnswers = typeof requestData.questionAnswers == 'string' ? JSON.parse( requestData.questionAnswers ) : requestData.questionAnswers;
475
+ let getChecklistQA = await processedtask.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1 } );
476
+ if ( !getChecklistQA ) {
477
+ return res.sendError( 'Check List Got Edited Please Fill Again', 422 );
478
+ }
479
+ if ( requestData.submittype == 'submit' ) {
480
+ let reqAnswers = requestData.questionAnswers;
481
+ let CLQAnswers = getChecklistQA.questionAnswers;
482
+ let validationCount= 0;
483
+ CLQAnswers.forEach( ( section ) => {
484
+ let requestSection = reqAnswers.filter( ( reqSection ) => reqSection.section_id == section.section_id );
485
+ section.questions.forEach( ( question ) => {
486
+ question.answers.forEach( ( answer ) => {
487
+ let sectionQuestion = requestSection.filter( ( secQuestion ) => secQuestion.qno == question.qno );
488
+ if ( question.answerType == 'multiplechoicemultiple' && ( sectionQuestion[0].Multianswer == null || sectionQuestion[0].Multianswer == '' || !sectionQuestion[0].Multianswer.length ) ) {
489
+ validationCount++;
490
+ } else {
491
+ if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( question.answerType ) && ( ( !sectionQuestion[0].linkType && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) || ( sectionQuestion[0].linkType && sectionQuestion[0].linkquestionenabled && ( sectionQuestion[0].answer == null || sectionQuestion[0].answer == '' ) ) ) ) {
492
+ validationCount++;
493
+ }
494
+ }
495
+ } );
496
+ } );
497
+ } );
498
+ if ( validationCount ) {
499
+ return res.sendError( 'Please Fill all Required Fields', 400 );
500
+ } else {
501
+ next();
502
+ }
503
+ } else {
504
+ next();
505
+ }
506
+ } catch ( e ) {
507
+ logger.error( { function: 'sopMobileTaskQuestionValidator', error: e } );
508
+ return res.sendError( e, 500 );
509
+ }
510
+ };
511
+
512
+ export async function sopMobilechecklistMultiSectionFormatter( req, res, next ) {
513
+ try {
514
+ let requestData = req.body;
515
+ requestData.questionAnswers = typeof requestData.questionAnswers == 'string' ? JSON.parse( requestData.questionAnswers ) : requestData.questionAnswers;
516
+ let getChecklistQA = await processedchecklist.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1 } );
517
+ let reqAnswers = requestData.questionAnswers;
518
+ let CLQAnswers = getChecklistQA.questionAnswers;
519
+
520
+ if ( requestData.submittype == 'submit' ) {
521
+ reqAnswers.forEach( ( reqA ) => {
522
+ if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( reqA?.answerType ) ) {
523
+ if ( ( !reqA.linkType && ( reqA.answer == null || reqA.answer == '' ) ) || ( reqA.linkType && reqA.linkquestionenabled && ( reqA.answer == null || reqA.answer == '' ) ) ) {
524
+ return res.sendError( 'Please Fill All Fields', 400 );
525
+ }
526
+ }
527
+ } );
528
+ }
529
+
530
+ let sectionFormat = [];
531
+ let uniqueSections = {};
532
+ reqAnswers.forEach( ( item ) => {
533
+ const key = `${item.section_id}-${item.sectionName}`;
534
+ if ( !uniqueSections[key] ) {
535
+ uniqueSections[key] = { id: item.section_id, name: item.sectionName };
536
+ }
537
+ } );
538
+ const uniqueArray = Object.values( uniqueSections );
539
+ for ( let section of uniqueArray ) {
540
+ let CLQSection = CLQAnswers.find( ( item ) => item.section_id == section.id );
541
+ if ( CLQSection ) {
542
+ let newArray = [];
543
+ let qaAnswers = CLQSection.questions;
544
+ let requestSection = reqAnswers.filter( ( item ) => item.section_id == section.id );
545
+ for ( let i = 0; i < requestSection.length; i++ ) {
546
+ for ( let j = 0; j < qaAnswers.length; j++ ) {
547
+ if ( requestSection[i].qno == qaAnswers[j].qno ) {
548
+ if ( qaAnswers[j].answerType == 'yes/no' ) {
549
+ let qaans = qaAnswers[j].answers;
550
+ let yn = [];
551
+ for ( let k = 0; k < qaans.length; k++ ) {
552
+ if ( requestSection[i].answer == qaans[k].answer ) {
553
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
554
+ if ( requestSection[i].validationAnswer ) {
555
+ let validateAns = decodeURIComponent( requestSection[i].validationAnswer.split( '?' )[0] );
556
+ if ( validateAns.length ) {
557
+ let splitImgUrl = validateAns.split( '/' );
558
+ if ( splitImgUrl.length > 1 ) {
559
+ splitImgUrl.splice( 0, 3 );
560
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
561
+ }
562
+ }
563
+ }
564
+ } else {
565
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
566
+ qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
567
+ }
568
+ yn.push( qaans[k] );
569
+ }
570
+ }
571
+ let structure = {};
572
+ structure.qno = qaAnswers[j].qno;
573
+ structure.qname = qaAnswers[j].qname;
574
+ structure.answerType = qaAnswers[j].answerType;
575
+ structure.runAI = qaAnswers[j].runAI;
576
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
577
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
578
+ structure.remarks = requestSection[i].remarks;
579
+ structure.answers = qaAnswers[j].answers;
580
+ structure.userAnswer = yn;
581
+ structure.linkType = qaAnswers[j].linkType;
582
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled;
583
+ structure.parentanswer = requestSection[i].parentanswer;
584
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage;
585
+ structure.descriptivetype = qaAnswers[j].descriptivetype;
586
+ if ( qaAnswers[j]?.redo ) {
587
+ structure.redo = false;
588
+ }
589
+ newArray.push( structure );
590
+ } else if ( qaAnswers[j].answerType == 'multiplechoicesingle' ) {
591
+ let qaans = qaAnswers[j].answers;
592
+ let ms = [];
593
+ for ( let k = 0; k < qaans.length; k++ ) {
594
+ if ( requestSection[i].answer == qaans[k].answer ) {
595
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
596
+ if ( requestSection[i].validationAnswer ) {
597
+ let validationAnswer = decodeURIComponent( requestSection[i].validationAnswer.split( '?' )[0] );
598
+ if ( validationAnswer.length ) {
599
+ let splitImgUrl = validationAnswer.split( '/' );
600
+ if ( splitImgUrl.length > 1 ) {
601
+ splitImgUrl.splice( 0, 3 );
602
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
603
+ }
604
+ }
605
+ }
606
+ } else {
607
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
608
+ qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
609
+ }
610
+ ms.push( qaans[k] );
611
+ }
612
+ }
613
+ let structure = {};
614
+ structure.qno = qaAnswers[j].qno;
615
+ structure.qname = qaAnswers[j].qname;
616
+ structure.answerType = qaAnswers[j].answerType;
617
+ structure.runAI = qaAnswers[j].runAI;
618
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
619
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
620
+ structure.remarks = requestSection[i].remarks;
621
+ structure.answers = qaAnswers[j].answers;
622
+ structure.userAnswer = ms;
623
+ structure.linkType = qaAnswers[j].linkType;
624
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled;
625
+ structure.parentanswer = requestSection[i].parentanswer;
626
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage;
627
+ structure.descriptivetype = qaAnswers[j].descriptivetype;
628
+ if ( qaAnswers[j]?.redo ) {
629
+ structure.redo = false;
630
+ }
631
+ newArray.push( structure );
632
+ } else if ( qaAnswers[j].answerType == 'multiplechoicemultiple' ) {
633
+ let qaans = qaAnswers[j].answers;
634
+ let mcmo = [];
635
+ for ( let k = 0; k < qaans.length; k++ ) {
636
+ let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
637
+ for ( let s = 0; s < separatedArray.length; s++ ) {
638
+ if ( separatedArray[s].answer == qaans[k].answer ) {
639
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
640
+ if ( separatedArray[s].validationAnswer ) {
641
+ let validationAnswer = decodeURIComponent( separatedArray[s].validationAnswer.split( '?' )[0] );
642
+ if ( validationAnswer.length ) {
643
+ let splitImgUrl = validationAnswer.split( '/' );
644
+ if ( splitImgUrl.length > 1 ) {
645
+ splitImgUrl.splice( 0, 3 );
646
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
647
+ }
648
+ }
649
+ }
650
+ } else {
651
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
652
+ qaans[k].validationAnswer = separatedArray[s].validationAnswer || '';
653
+ }
654
+
655
+ mcmo.push( qaans[k] );
656
+ }
657
+ }
658
+ }
659
+ let structure = {};
660
+ structure.qno = qaAnswers[j].qno;
661
+ structure.qname = qaAnswers[j].qname;
662
+ structure.answerType = qaAnswers[j].answerType;
663
+ structure.runAI = qaAnswers[j].runAI;
664
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
665
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
666
+ structure.remarks = requestSection[i].remarks;
667
+ structure.answers = qaAnswers[j].answers;
668
+ structure.userAnswer = mcmo;
669
+ structure.linkType = qaAnswers[j].linkType;
670
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled;
671
+ structure.parentanswer = requestSection[i].parentanswer;
672
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage;
673
+ structure.descriptivetype = qaAnswers[j].descriptivetype;
674
+ if ( qaAnswers[j]?.redo ) {
675
+ structure.redo = false;
676
+ }
677
+ newArray.push( structure );
678
+ } else if ( qaAnswers[j].answerType == 'multipleImage' ) {
679
+ let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
680
+ let mcmi = [];
681
+ // for (let k = 0; k < qaans.length; k++) {
682
+ for ( let s = 0; s < separatedArray.length; s++ ) {
683
+ if ( separatedArray[s].answer && separatedArray[s].answer !='' ) {
684
+ let newAnswer = {};
685
+ let validationAnswer = decodeURIComponent( separatedArray[s].answer.split( '?' )[0] );
686
+ if ( validationAnswer.length ) {
687
+ let splitImgUrl = validationAnswer.split( '/' );
688
+ if ( splitImgUrl.length > 1 ) {
689
+ splitImgUrl.splice( 0, 3 );
690
+ newAnswer.answer = splitImgUrl.join( '/' ) || '';
691
+ }
692
+ }
693
+
694
+ newAnswer.answeroptionNumber = 0;
695
+ newAnswer.sopFlag = false;
696
+ newAnswer.validation = false;
697
+ newAnswer.validationType = '';
698
+ newAnswer.referenceImage = '';
699
+ newAnswer.allowUploadfromGallery = false;
700
+ newAnswer.runAI = false;
701
+ newAnswer.descriptivetype = '';
702
+ newAnswer.showLinked = false;
703
+ newAnswer.linkedQuestion = 0;
704
+ newAnswer.nestedQuestion = [];
705
+ newAnswer.index = s;
706
+ mcmi.push( newAnswer );
707
+ }
708
+ }
709
+ // }
710
+ let structure = {};
711
+ structure.qno = qaAnswers[j].qno;
712
+ structure.qname = qaAnswers[j].qname;
713
+ structure.answerType = qaAnswers[j].answerType;
714
+ structure.runAI = qaAnswers[j].runAI;
715
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
716
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
717
+ structure.remarks = requestSection[i].remarks;
718
+ structure.answers = qaAnswers[j].answers;
719
+ structure.userAnswer = mcmi;
720
+ structure.linkType = qaAnswers[j].linkType;
721
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled;
722
+ structure.parentanswer = requestSection[i].parentanswer;
723
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage;
724
+ structure.descriptivetype = qaAnswers[j].descriptivetype;
725
+ if ( qaAnswers[j]?.redo ) {
726
+ structure.redo = false;
727
+ }
728
+ newArray.push( structure );
729
+ } else {
730
+ let des = [];
731
+ if ( requestSection[i].answer != 'null' && requestSection[i].answer != '' && requestSection[i].answer != null ) {
732
+ let validationAnswer = decodeURIComponent( requestSection[i].answer.split( '?' )[0] );
733
+ if ( validationAnswer.length ) {
734
+ let splitImgUrl = validationAnswer.split( '/' );
735
+ if ( splitImgUrl.length > 1 ) {
736
+ splitImgUrl.splice( 0, 3 );
737
+ requestSection[i].answer = splitImgUrl.join( '/' );
738
+ }
739
+ }
740
+ let ansstructure = {
741
+ answer: requestSection[i].answer,
742
+ answeroptionNumber: 1,
743
+ sopFlag: false,
744
+ validation: false,
745
+ validationType: '',
746
+ validationAnswer: '',
747
+ referenceImage: qaAnswers[j].answers[0].referenceImage,
748
+ showLinked: qaAnswers[j].answers[0].showLinked,
749
+ linkedQuestion: qaAnswers[j].answers[0].linkedQuestion,
750
+ };
751
+ if ( qaAnswers[j].answerType == 'date' ) {
752
+ ansstructure.dateRangeType = requestSection[i].dateRangeType || false;
753
+ }
754
+ des.push( ansstructure );
755
+ }
756
+ let structure = {};
757
+ structure.qno = qaAnswers[j].qno;
758
+ structure.qname = qaAnswers[j].qname;
759
+ structure.answerType = qaAnswers[j].answerType;
760
+ structure.runAI = qaAnswers[j].runAI;
761
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
762
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
763
+ structure.remarks = requestSection[i].remarks;
764
+ structure.answers = qaAnswers[j].answers;
765
+ structure.userAnswer = des;
766
+ structure.linkType = qaAnswers[j].linkType;
767
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled;
768
+ structure.parentanswer = requestSection[i].parentanswer;
769
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage;
770
+ structure.descriptivetype = qaAnswers[j].descriptivetype;
771
+ if ( qaAnswers[j]?.redo ) {
772
+ structure.redo = false;
773
+ }
774
+ newArray.push( structure );
775
+ }
776
+ }
777
+ }
778
+ }
779
+ let sectionData = {
780
+ 'section_id': section.id,
781
+ 'sectionName': section.name,
782
+ 'questions': newArray,
783
+ };
784
+ sectionFormat.push( sectionData );
785
+ }
786
+ }
787
+
788
+
789
+ requestData.questionAnswers = sectionFormat;
790
+ next();
791
+ } catch ( error ) {
792
+ logger.error( { function: 'sopMobileValidater error =>', error: error } );
793
+ return res.sendError( error, 500 );
794
+ }
795
+ };
796
+
797
+ export async function sopMobileTaskMultiSectionFormatter( req, res, next ) {
798
+ try {
799
+ let requestData = req.body;
800
+ requestData.questionAnswers = typeof requestData.questionAnswers == 'string' ? JSON.parse( requestData.questionAnswers ) : requestData.questionAnswers;
801
+ let getChecklistQA = await processedTask.findOne( { _id: new ObjectId( requestData.processedcheckListId ) }, { questionAnswers: 1 } );
802
+ let reqAnswers = requestData.questionAnswers;
803
+ let CLQAnswers = getChecklistQA.questionAnswers;
804
+
805
+ if ( requestData.submittype == 'submit' ) {
806
+ reqAnswers.forEach( ( reqA ) => {
807
+ if ( ![ 'multiplechoicemultiple', 'multipleImage' ].includes( reqA?.answerType ) ) {
808
+ if ( ( !reqA.linkType && ( reqA.answer == null || reqA.answer == '' ) ) || ( reqA.linkType && reqA.linkquestionenabled && ( reqA.answer == null || reqA.answer == '' ) ) ) {
809
+ return res.sendError( 'Please Fill All Fields', 400 );
810
+ }
811
+ }
812
+ } );
813
+ }
814
+
815
+ let sectionFormat = [];
816
+ let uniqueSections = {};
817
+ reqAnswers.forEach( ( item ) => {
818
+ const key = `${item.section_id}-${item.sectionName}`;
819
+ if ( !uniqueSections[key] ) {
820
+ uniqueSections[key] = { id: item.section_id, name: item.sectionName };
821
+ }
822
+ } );
823
+ const uniqueArray = Object.values( uniqueSections );
824
+ for ( let section of uniqueArray ) {
825
+ let CLQSection = CLQAnswers.find( ( item ) => item.section_id == section.id );
826
+ if ( CLQSection ) {
827
+ let newArray = [];
828
+ let qaAnswers = CLQSection.questions;
829
+ let requestSection = reqAnswers.filter( ( item ) => item.section_id == section.id );
830
+ for ( let i = 0; i < requestSection.length; i++ ) {
831
+ for ( let j = 0; j < qaAnswers.length; j++ ) {
832
+ if ( requestSection[i].qno == qaAnswers[j].qno ) {
833
+ if ( qaAnswers[j].answerType == 'yes/no' ) {
834
+ let qaans = qaAnswers[j].answers;
835
+ let yn = [];
836
+ for ( let k = 0; k < qaans.length; k++ ) {
837
+ if ( requestSection[i].answer == qaans[k].answer ) {
838
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
839
+ if ( requestSection[i].validationAnswer ) {
840
+ let validateAns = decodeURIComponent( requestSection[i].validationAnswer.split( '?' )[0] );
841
+ if ( validateAns.length ) {
842
+ let splitImgUrl = validateAns.split( '/' );
843
+ if ( splitImgUrl.length > 1 ) {
844
+ splitImgUrl.splice( 0, 3 );
845
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
846
+ }
847
+ }
848
+ }
849
+ } else {
850
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
851
+ qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
852
+ }
853
+ yn.push( qaans[k] );
854
+ }
855
+ }
856
+ let structure = {};
857
+ structure.qno = qaAnswers[j].qno;
858
+ structure.qname = qaAnswers[j].qname;
859
+ structure.answerType = qaAnswers[j].answerType;
860
+ structure.runAI = qaAnswers[j].runAI;
861
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
862
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
863
+ structure.remarks = requestSection[i].remarks;
864
+ structure.answers = qaAnswers[j].answers;
865
+ structure.userAnswer = yn;
866
+ structure.linkType = qaAnswers[j].linkType,
867
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled,
868
+ structure.parentanswer = requestSection[i].parentanswer,
869
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage,
870
+ structure.descriptivetype = qaAnswers[j].descriptivetype,
871
+ structure.redo = qaAnswers[j]?.redo,
872
+ newArray.push( structure );
873
+ } else if ( qaAnswers[j].answerType == 'multiplechoicesingle' ) {
874
+ let qaans = qaAnswers[j].answers;
875
+ let ms = [];
876
+ for ( let k = 0; k < qaans.length; k++ ) {
877
+ if ( requestSection[i].answer == qaans[k].answer ) {
878
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
879
+ if ( requestSection[i].validationAnswer ) {
880
+ let validationAnswer = decodeURIComponent( requestSection[i].validationAnswer.split( '?' )[0] );
881
+ if ( validationAnswer.length ) {
882
+ let splitImgUrl = validationAnswer.split( '/' );
883
+ if ( splitImgUrl.length > 1 ) {
884
+ splitImgUrl.splice( 0, 3 );
885
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
886
+ }
887
+ }
888
+ }
889
+ } else {
890
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
891
+ qaans[k].validationAnswer = requestSection[i].validationAnswer || '';
892
+ }
893
+ ms.push( qaans[k] );
894
+ }
895
+ }
896
+ let structure = {};
897
+ structure.qno = qaAnswers[j].qno;
898
+ structure.qname = qaAnswers[j].qname;
899
+ structure.answerType = qaAnswers[j].answerType;
900
+ structure.runAI = qaAnswers[j].runAI;
901
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
902
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
903
+ structure.remarks = requestSection[i].remarks;
904
+ structure.answers = qaAnswers[j].answers;
905
+ structure.userAnswer = ms;
906
+ structure.linkType = qaAnswers[j].linkType,
907
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled,
908
+ structure.parentanswer = requestSection[i].parentanswer,
909
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage,
910
+ structure.descriptivetype = qaAnswers[j].descriptivetype,
911
+ structure.redo = qaAnswers[j]?.redo,
912
+ newArray.push( structure );
913
+ } else if ( qaAnswers[j].answerType == 'multiplechoicemultiple' ) {
914
+ let qaans = qaAnswers[j].answers;
915
+ let mcmo = [];
916
+ for ( let k = 0; k < qaans.length; k++ ) {
917
+ let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
918
+ for ( let s = 0; s < separatedArray.length; s++ ) {
919
+ if ( separatedArray[s].answer == qaans[k].answer ) {
920
+ if ( qaans[k].validationType == 'Capture Image' || qaans[k].validationType == 'Capture Video' ) {
921
+ if ( separatedArray[s].validationAnswer ) {
922
+ let validationAnswer = decodeURIComponent( separatedArray[s].validationAnswer.split( '?' )[0] );
923
+ if ( validationAnswer.length ) {
924
+ let splitImgUrl = validationAnswer.split( '/' );
925
+ if ( splitImgUrl.length > 1 ) {
926
+ splitImgUrl.splice( 0, 3 );
927
+ qaans[k].validationAnswer = splitImgUrl.join( '/' ) || '';
928
+ }
929
+ }
930
+ }
931
+ } else {
932
+ qaans[k].descriptivetype = qaAnswers[j].descriptivetype || '';
933
+ qaans[k].validationAnswer = separatedArray[s].validationAnswer || '';
934
+ }
935
+
936
+ mcmo.push( qaans[k] );
937
+ }
938
+ }
939
+ }
940
+ let structure = {};
941
+ structure.qno = qaAnswers[j].qno;
942
+ structure.qname = qaAnswers[j].qname;
943
+ structure.answerType = qaAnswers[j].answerType;
944
+ structure.runAI = qaAnswers[j].runAI;
945
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
946
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
947
+ structure.remarks = requestSection[i].remarks;
948
+ structure.answers = qaAnswers[j].answers;
949
+ structure.userAnswer = mcmo;
950
+ structure.linkType = qaAnswers[j].linkType,
951
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled,
952
+ structure.parentanswer = requestSection[i].parentanswer,
953
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage,
954
+ structure.descriptivetype = qaAnswers[j].descriptivetype,
955
+ structure.redo = qaAnswers[j]?.redo,
956
+ newArray.push( structure );
957
+ } else if ( qaAnswers[j].answerType == 'multipleImage' ) {
958
+ let separatedArray = typeof requestSection[i].Multianswer == 'string' ? JSON.parse( requestSection[i].Multianswer ) : requestSection[i].Multianswer;
959
+ let mcmi = [];
960
+ // for (let k = 0; k < qaans.length; k++) {
961
+ for ( let s = 0; s < separatedArray.length; s++ ) {
962
+ if ( separatedArray[s].answer && separatedArray[s].answer !='' ) {
963
+ let newAnswer = {};
964
+ let validationAnswer = decodeURIComponent( separatedArray[s].answer.split( '?' )[0] );
965
+ if ( validationAnswer.length ) {
966
+ let splitImgUrl = validationAnswer.split( '/' );
967
+ if ( splitImgUrl.length > 1 ) {
968
+ splitImgUrl.splice( 0, 3 );
969
+ newAnswer.answer = splitImgUrl.join( '/' ) || '';
970
+ }
971
+ }
972
+
973
+ newAnswer.answeroptionNumber = 0;
974
+ newAnswer.sopFlag = false;
975
+ newAnswer.validation = false;
976
+ newAnswer.validationType = '';
977
+ newAnswer.referenceImage = '';
978
+ newAnswer.allowUploadfromGallery = false;
979
+ newAnswer.runAI = false;
980
+ newAnswer.descriptivetype = '';
981
+ newAnswer.showLinked = false;
982
+ newAnswer.linkedQuestion = 0;
983
+ newAnswer.nestedQuestion = [];
984
+ newAnswer.index = s;
985
+ mcmi.push( newAnswer );
986
+ }
987
+ }
988
+ // }
989
+ let structure = {};
990
+ structure.qno = qaAnswers[j].qno;
991
+ structure.qname = qaAnswers[j].qname;
992
+ structure.answerType = qaAnswers[j].answerType;
993
+ structure.runAI = qaAnswers[j].runAI;
994
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
995
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
996
+ structure.remarks = requestSection[i].remarks;
997
+ structure.answers = qaAnswers[j].answers;
998
+ structure.userAnswer = mcmi;
999
+ structure.linkType = qaAnswers[j].linkType,
1000
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled,
1001
+ structure.parentanswer = requestSection[i].parentanswer,
1002
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage,
1003
+ structure.descriptivetype = qaAnswers[j].descriptivetype,
1004
+ structure.redo = qaAnswers[j]?.redo,
1005
+ newArray.push( structure );
1006
+ } else {
1007
+ let des = [];
1008
+ if ( requestSection[i].answer != 'null' && requestSection[i].answer != '' && requestSection[i].answer != null ) {
1009
+ let validationAnswer = decodeURIComponent( requestSection[i].answer.split( '?' )[0] );
1010
+ if ( validationAnswer.length ) {
1011
+ let splitImgUrl = validationAnswer.split( '/' );
1012
+ if ( splitImgUrl.length > 1 ) {
1013
+ splitImgUrl.splice( 0, 3 );
1014
+ requestSection[i].answer = splitImgUrl.join( '/' );
1015
+ }
1016
+ }
1017
+ let ansstructure = {
1018
+ answer: requestSection[i].answer,
1019
+ answeroptionNumber: 1,
1020
+ sopFlag: false,
1021
+ validation: false,
1022
+ validationType: '',
1023
+ validationAnswer: '',
1024
+ referenceImage: qaAnswers[j].answers[0]?.referenceImage,
1025
+ showLinked: qaAnswers[j].answers[0]?.showLinked,
1026
+ linkedQuestion: qaAnswers[j].answers[0]?.linkedQuestion,
1027
+ };
1028
+ if ( qaAnswers[j].answerType == 'date' ) {
1029
+ ansstructure.dateRangeType = requestSection[i].dateRangeType || false;
1030
+ }
1031
+ des.push( ansstructure );
1032
+ }
1033
+ let structure = {};
1034
+ structure.qno = qaAnswers[j].qno;
1035
+ structure.qname = qaAnswers[j].qname;
1036
+ structure.answerType = qaAnswers[j].answerType;
1037
+ structure.runAI = qaAnswers[j].runAI;
1038
+ structure.runAIDescription = qaAnswers[j].runAIDescription;
1039
+ structure.allowUploadfromGallery = qaAnswers[j].allowUploadfromGallery;
1040
+ structure.remarks = requestSection[i].remarks;
1041
+ structure.answers = qaAnswers[j].answers;
1042
+ structure.userAnswer = des;
1043
+ structure.linkType = qaAnswers[j].linkType,
1044
+ structure.linkquestionenabled = requestSection[i].linkquestionenabled,
1045
+ structure.parentanswer = requestSection[i].parentanswer,
1046
+ structure.questionReferenceImage = qaAnswers[j].questionReferenceImage,
1047
+ structure.descriptivetype = qaAnswers[j].descriptivetype,
1048
+ structure.redo = qaAnswers[j]?.redo,
1049
+ newArray.push( structure );
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ let sectionData = {
1055
+ 'section_id': section.id,
1056
+ 'sectionName': section.name,
1057
+ 'questions': newArray,
1058
+ };
1059
+ sectionFormat.push( sectionData );
1060
+ }
1061
+ }
1062
+
1063
+
1064
+ requestData.questionAnswers = sectionFormat;
1065
+ next();
1066
+ } catch ( error ) {
1067
+ logger.error( { function: 'sopMobileValidater error =>', error: error, message: req.body } );
1068
+ return res.sendError( error, 500 );
1069
+ }
1070
+ };
1071
+
1072
+ function QuestionFlag( req, res ) {
1073
+ try {
1074
+ let flagCount = 0;
1075
+ let inputData = req.body;
1076
+ inputData.questionAnswers.forEach( ( sections ) => {
1077
+ sections.questions.forEach( ( question ) => {
1078
+ if ( question.userAnswer && question.userAnswer.length>0 ) {
1079
+ let answervalidate = question.userAnswer.filter( ( answer ) => {
1080
+ return answer.sopFlag == true;
1081
+ } );
1082
+ flagCount = flagCount + answervalidate.length;
1083
+ }
1084
+ } );
1085
+ } );
1086
+ return flagCount;
1087
+ } catch ( error ) {
1088
+ logger.error( { function: 'QuestionFlag error=>', error: error } );
1089
+ let msg = error.error ? error.error : error;
1090
+ return res.sendError( msg, 500 );
1091
+ }
1092
+ }
1093
+
1094
+ export async function submitChecklist( req, res ) {
1095
+ try {
1096
+ let requestData = req.body;
1097
+ let findQuery = [];
1098
+ findQuery.push( {
1099
+ $match: {
1100
+ $and: [
1101
+ { _id: new ObjectId( requestData.processedcheckListId ) },
1102
+ { userId: req.user._id },
1103
+ { date_string: requestData.date },
1104
+ ],
1105
+ },
1106
+ } );
1107
+
1108
+ let getchecklist = await processedchecklist.aggregate( findQuery );
1109
+ if ( !getchecklist.length ) {
1110
+ return res.sendError( 'Checklist Got Edited Please Fill Again', 422 );
1111
+ }
1112
+
1113
+ let checklistDetails = await checklistService.findOne( { _id: getchecklist[0].sourceCheckList_id } );
1114
+
1115
+ if ( getchecklist[0].checklistStatus == 'open' ) {
1116
+ return res.sendError( 'checklist in open status need to start', 400 );
1117
+ } else if ( getchecklist[0].checklistStatus == 'submit' ) {
1118
+ return res.sendError( 'checklist Already Submitted', 400 );
1119
+ } else {
1120
+ let updateQuery = {};
1121
+ updateQuery._id = new ObjectId( requestData.processedcheckListId );
1122
+ updateQuery.userId = req.user._id;
1123
+ updateQuery.date_string = requestData.date;
1124
+ let storeTimeZone = await storeService.findOne( { storeName: getchecklist[0].storeName }, { 'storeProfile.timeZone': 1 } );
1125
+ let currentDateTime;
1126
+ if ( storeTimeZone?.storeProfile?.timeZone ) {
1127
+ currentDateTime = dayjs().tz( storeTimeZone?.storeProfile?.timeZone );
1128
+ } else {
1129
+ currentDateTime = dayjs();
1130
+ }
1131
+ let updateData = {};
1132
+ let flagCount = QuestionFlag( req, res );
1133
+ updateData.questionFlag = flagCount;
1134
+ updateData.submitTime_string = currentDateTime.format( 'hh:mm A, DD MMM YYYY' );
1135
+ if ( requestData.submittype == 'draft' ) {
1136
+ logger.info( `v5 => Checklist Save => store Name: ${getchecklist[0].storeName}, User Email: ${getchecklist[0].userEmail}, Checklist Name: ${getchecklist[0].checkListName}` );
1137
+ updateData.questionAnswers = requestData.questionAnswers;
1138
+ updateData.updatedAt = dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format();
1139
+ } else {
1140
+ logger.info( `v5 => Checklist Submit => store Name: ${getchecklist[0].storeName}, User Email: ${getchecklist[0].userEmail}, Checklist Name: ${getchecklist[0].checkListName}` );
1141
+ updateData.questionAnswers = requestData.questionAnswers;
1142
+ updateData.submitTime = dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format();
1143
+ updateData.checklistStatus = 'submit';
1144
+ updateData.updatedAt = dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format();
1145
+ updateData.submitMobileTime = requestData?.currentTime;
1146
+ }
1147
+ updateData.questionAnswers.forEach( ( section ) => {
1148
+ section.questions.forEach( ( question ) => {
1149
+ if ( question.redo === true ) {
1150
+ question.redo = false;
1151
+ }
1152
+ } );
1153
+ } );
1154
+ let updatechecklist = await processedchecklist.updateOne( updateQuery, updateData );
1155
+ if ( updatechecklist?.modifiedCount > 0 ) {
1156
+ if ( checklistDetails && checklistDetails.allowedMultiSubmit && requestData.submittype == 'submit' ) {
1157
+ let currentTime;
1158
+ let date = getchecklist[0].date_string +' '+ getchecklist[0].scheduleEndTime;
1159
+ let scheduleTime;
1160
+ if ( storeTimeZone?.storeProfile?.timeZone ) {
1161
+ currentTime = dayjs().tz( storeTimeZone?.storeProfile?.timeZone );
1162
+ scheduleTime = dayjs( date, 'YYYY-MM-DD hh:mm A' ).tz( storeTimeZone?.storeProfile?.timeZone );
1163
+ } else {
1164
+ currentTime = dayjs();
1165
+ scheduleTime = dayjs( date, 'YYYY-MM-DD hh:mm A' );
1166
+ }
1167
+ if ( currentTime < scheduleTime ) {
1168
+ await insertSingleProcessData( getchecklist[0].sourceCheckList_id, requestData.processedcheckListId );
1169
+ }
1170
+ }
1171
+
1172
+ let logInsertData = {
1173
+ store_id: getchecklist[0].store_id,
1174
+ storeName: getchecklist[0].storeName,
1175
+ action: requestData?.submittype === 'draft' ? 'saved' : 'submitted',
1176
+ checklistId: getchecklist[0].sourceCheckList_id,
1177
+ processedChecklistId: getchecklist[0]._id,
1178
+ checkListName: getchecklist[0].checkListName,
1179
+ checkListType: getchecklist[0].checkListType,
1180
+ client_id: req.user.clientId,
1181
+ };
1182
+
1183
+ await checklistLogs.create( logInsertData );
1184
+ // let time = dayjs().format( 'HH:mm:ss' );
1185
+ // let [ hours, minutes ] = time.split( ':' ).map( Number );
1186
+ // let nearestMultipleOf10Minutes = Math.floor( minutes / 10 ) * 10;
1187
+ // let roundedHours = hours + Math.floor( ( minutes - nearestMultipleOf10Minutes ) / 60 );
1188
+ // let roundedMinutes = nearestMultipleOf10Minutes;
1189
+ // let roundedSeconds = 0;
1190
+ // let roundedTime = `${String( roundedHours ).padStart( 2, '0' )}:${String( roundedMinutes ).padStart( 2, '0' )}:${String( roundedSeconds ).padStart( 2, '0' )}`;
1191
+ // let createdAtDate;
1192
+ // if ( storeTimeZone?.timezone ) {
1193
+ // createdAtDate = dayjs( `${getchecklist[0].date_string} ${time}`, 'YYYY-MM-DD hh:mm:ss' ).tz( storeTimeZone?.timezone ).utc( '+00:00' );
1194
+ // } else {
1195
+ // createdAtDate = dayjs( `${getchecklist[0].date_string} ${time}`, 'YYYY-MM-DD hh:mm:ss' ).utc( '+00:00' );
1196
+ // }
1197
+ // let detectionData = {
1198
+ // client_id: req.user.clientId,
1199
+ // store_id: getchecklist[0].store_id,
1200
+ // userName: req.user.name,
1201
+ // userId: req.user._id,
1202
+ // time: time,
1203
+ // type: 'positive',
1204
+ // checklistName: getchecklist[0].checkListName,
1205
+ // checklistId: getchecklist[0].checkListId,
1206
+ // sourceChecklist_id: getchecklist[0].sourceCheckList_id,
1207
+ // category: 'custom',
1208
+ // scheduleTime: getchecklist[0].scheduleEndTime_iso,
1209
+ // startRange: roundedTime,
1210
+ // date_iso: getchecklist[0].date_iso,
1211
+ // date_string: getchecklist[0].date_string,
1212
+ // createdAt: createdAtDate,
1213
+ // };
1214
+ // await detectionService.create( detectionData );
1215
+ updateOpenSearch( req.user, requestData );
1216
+
1217
+ return res.sendSuccess( 'Checklist Updated Successfully' );
1218
+ } else {
1219
+ return res.sendError( 'something went wrong please try again', 500 );
1220
+ }
1221
+ }
1222
+ } catch ( e ) {
1223
+ logger.error( { function: 'submitChecklist', error: e } );
1224
+ return res.sendError( e, 500 );
1225
+ }
1226
+ }
1227
+
1228
+ export async function submitTask( req, res ) {
1229
+ try {
1230
+ const { body: requestData, user } = req;
1231
+ const { processedcheckListId, date, submittype, currentTime, questionAnswers } = requestData;
1232
+
1233
+
1234
+ const findQuery = [
1235
+ {
1236
+ $match: {
1237
+ _id: new ObjectId( processedcheckListId ),
1238
+ userId: user._id,
1239
+ date_string: date,
1240
+ },
1241
+ },
1242
+ ];
1243
+
1244
+ const [ checklist ] = await processedTask.aggregate( findQuery );
1245
+
1246
+ if ( !checklist ) {
1247
+ return res.sendError( 'Task edited. Please fill again', 422 );
1248
+ }
1249
+
1250
+ // eslint-disable-next-line camelcase
1251
+ const { checklistStatus, storeName, userEmail, checkListName, store_id } = checklist;
1252
+
1253
+ if ( checklistStatus === 'open' ) {
1254
+ return res.sendError( 'Checklist is in open status. Please start.', 400 );
1255
+ }
1256
+
1257
+ if ( checklistStatus === 'submit' ) {
1258
+ return res.sendError( 'Checklist already submitted', 400 );
1259
+ }
1260
+
1261
+ const storeTimeZone = await storeService.findOne( { storeName }, { 'storeProfile.timeZone': 1 } );
1262
+ const currentDateTime = storeTimeZone?.storeProfile?.timeZone ?
1263
+ dayjs().tz( storeTimeZone.storeProfile.timeZone ) :
1264
+ dayjs();
1265
+
1266
+ const updateQuery = {
1267
+ _id: new ObjectId( processedcheckListId ),
1268
+ userId: user._id,
1269
+ date_string: date,
1270
+ };
1271
+
1272
+ questionAnswers.forEach( ( section ) => {
1273
+ section.questions.forEach( ( question ) => {
1274
+ if ( question.redo === true ) {
1275
+ question.redo = false;
1276
+ }
1277
+ } );
1278
+ } );
1279
+
1280
+ const updateData = {
1281
+ questionAnswers,
1282
+ updatedAt: dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format(),
1283
+ questionFlag: QuestionFlag( req, res ),
1284
+ };
1285
+
1286
+ if ( submittype === 'draft' ) {
1287
+ logger.info(
1288
+ `v5 => Checklist Save => store Name: ${storeName}, User Email: ${userEmail}, Checklist Name: ${checkListName}`,
1289
+ );
1290
+ updateData.submitTime_string = currentDateTime.format( 'hh:mm A, DD MMM YYYY' );
1291
+ } else {
1292
+ logger.info(
1293
+ `v5 => Checklist Submit => store Name: ${storeName}, User Email: ${userEmail}, Checklist Name: ${checkListName}`,
1294
+ );
1295
+ Object.assign( updateData, {
1296
+ submitTime: dayjs.utc( currentDateTime.format( 'hh:mm:ss A, DD MMM YYYY' ), 'hh:mm:ss A, DD MMM YYYY' ).format(),
1297
+ checklistStatus: 'submit',
1298
+ submitMobileTime: currentTime,
1299
+ submitTime_string: currentDateTime.format( 'hh:mm A, DD MMM YYYY' ),
1300
+ } );
1301
+ }
1302
+
1303
+ const updateResult = await processedTask.updateOne( updateQuery, updateData );
1304
+
1305
+ if ( updateResult.modifiedCount > 0 ) {
1306
+ const logInsertData = {
1307
+ // eslint-disable-next-line camelcase
1308
+ store_id,
1309
+ storeName,
1310
+ action: submittype === 'draft' ? 'saved' : 'submitted',
1311
+ checklistId: checklist.sourceCheckList_id,
1312
+ processedChecklistId: checklist._id,
1313
+ checkListType: checklist.checkListType,
1314
+ checkListName,
1315
+ client_id: user.clientId,
1316
+ };
1317
+ await checklistLogs.create( logInsertData );
1318
+
1319
+ updateOpenSearchTask( user, requestData );
1320
+
1321
+ return res.sendSuccess( 'Task Updated Successfully' );
1322
+ } else {
1323
+ return res.sendError( 'Something went wrong. Please try again', 500 );
1324
+ }
1325
+ } catch ( error ) {
1326
+ logger.error( { function: 'submitTask', error } );
1327
+ return res.sendError( error.message || 'Internal Server Error', 500 );
1328
+ }
1329
+ }
1330
+
1331
+
1332
+ async function updateOpenSearch( user, data ) {
1333
+ let findQuery = [ {
1334
+ $match: {
1335
+ $and: [
1336
+ { _id: new ObjectId( data.processedcheckListId ) },
1337
+ { userId: user._id },
1338
+ { date_string: data.date },
1339
+ ],
1340
+ },
1341
+ } ];
1342
+
1343
+ let getchecklist = await processedchecklist.aggregate( findQuery );
1344
+ if ( getchecklist.length ) {
1345
+ let logInsertData = {
1346
+ store_id: getchecklist[0].store_id,
1347
+ storeName: getchecklist[0].storeName,
1348
+ action: 'OpenSearch insert Triggered',
1349
+ checklistId: getchecklist[0].checkListId,
1350
+ checkListName: getchecklist[0].checkListName,
1351
+ checkListType: getchecklist[0].checkListType,
1352
+ client_id: user.clientId,
1353
+ };
1354
+ await checklistLogs.create( logInsertData );
1355
+ const requestOptions = {
1356
+ method: 'POST',
1357
+ headers: {
1358
+ 'Content-Type': 'application/json',
1359
+ },
1360
+ body: JSON.stringify( { doc: { ...getchecklist[0] } } ),
1361
+ };
1362
+ let url = JSON.parse( process.env.LAMBDAURL );
1363
+ let searchResponse = await fetch( url.submitChecklist, requestOptions );
1364
+ if ( searchResponse.ok ) {
1365
+ let logInsertData = {
1366
+ store_id: getchecklist[0].store_id,
1367
+ storeName: getchecklist[0].storeName,
1368
+ action: 'OpenSearch inserted Successfully',
1369
+ checklistId: getchecklist[0].checkListId,
1370
+ checkListName: getchecklist[0].checkListName,
1371
+ checkListType: getchecklist[0].checkListType,
1372
+ client_id: user.clientId,
1373
+ };
1374
+ await checklistLogs.create( logInsertData );
1375
+ }
1376
+ }
1377
+ }
1378
+
1379
+ async function updateOpenSearchTask( user, data ) {
1380
+ let findQuery = [ {
1381
+ $match: {
1382
+ $and: [
1383
+ { _id: new ObjectId( data.processedcheckListId ) },
1384
+ { userId: user._id },
1385
+ { date_string: data.date },
1386
+ ],
1387
+ },
1388
+ } ];
1389
+
1390
+ let getchecklist = await processedTask.aggregate( findQuery );
1391
+ if ( getchecklist.length ) {
1392
+ let logInsertData = {
1393
+ store_id: getchecklist[0].store_id,
1394
+ storeName: getchecklist[0].storeName,
1395
+ action: 'OpenSearch insert Triggered',
1396
+ checklistId: getchecklist[0].checkListId,
1397
+ checkListName: getchecklist[0].checkListName,
1398
+ checkListType: getchecklist[0].checkListType,
1399
+ client_id: user.clientId,
1400
+ };
1401
+ await checklistLogs.create( logInsertData );
1402
+ const requestOptions = {
1403
+ method: 'POST',
1404
+ headers: {
1405
+ 'Content-Type': 'application/json',
1406
+ },
1407
+ body: JSON.stringify( { doc: { ...getchecklist[0] } } ),
1408
+ };
1409
+ let url = JSON.parse( process.env.LAMBDAURL );
1410
+ let searchResponse = await fetch( url.submitTask, requestOptions );
1411
+ if ( searchResponse.ok ) {
1412
+ let logInsertData = {
1413
+ store_id: getchecklist[0].store_id,
1414
+ storeName: getchecklist[0].storeName,
1415
+ action: 'OpenSearch inserted Successfully',
1416
+ checklistId: getchecklist[0].checkListId,
1417
+ checkListName: getchecklist[0].checkListName,
1418
+ checkListType: getchecklist[0].checkListType,
1419
+ client_id: user.clientId,
1420
+ };
1421
+ await checklistLogs.create( logInsertData );
1422
+ }
1423
+ }
1424
+ }
1425
+
1426
+ export async function dashboard( req, res ) {
1427
+ try {
1428
+ let requestData = req.query;
1429
+ let query = [];
1430
+ query.push(
1431
+ {
1432
+ $match: {
1433
+ $and: [
1434
+ { store_id: requestData.store_id },
1435
+ { userId: req.user._id },
1436
+ { date_string: requestData.date },
1437
+ { checkListType: 'custom' },
1438
+ { timeFlagStatus: true },
1439
+ ],
1440
+ },
1441
+ },
1442
+ );
1443
+
1444
+ query.push(
1445
+ {
1446
+ $facet: {
1447
+ total: [
1448
+ { $count: 'total' },
1449
+ ],
1450
+ toDo: [
1451
+ {
1452
+ $match: {
1453
+ checklistStatus: 'open',
1454
+ },
1455
+ },
1456
+ {
1457
+ $group: {
1458
+ _id: '',
1459
+ count: { $sum: 1 },
1460
+ },
1461
+ },
1462
+ ],
1463
+ inprogress: [
1464
+ {
1465
+ $match: {
1466
+ checklistStatus: 'inprogress',
1467
+ },
1468
+ },
1469
+ {
1470
+ $group: {
1471
+ _id: '',
1472
+ count: { $sum: 1 },
1473
+ },
1474
+ },
1475
+ ],
1476
+ submit: [
1477
+ {
1478
+ $match: {
1479
+ checklistStatus: 'submit',
1480
+ },
1481
+ },
1482
+ {
1483
+ $group: {
1484
+ _id: '',
1485
+ count: { $sum: 1 },
1486
+ },
1487
+ },
1488
+ ],
1489
+ },
1490
+ },
1491
+ );
1492
+
1493
+ let resultData = await processedchecklist.aggregate( query );
1494
+
1495
+ resultData = {
1496
+ totalchecklist: resultData[0]?.total.length ? resultData[0]?.total[0]?.total : 0,
1497
+ todo: resultData[0]?.toDo.length ? resultData[0]?.toDo[0]?.count : 0,
1498
+ inprogress: resultData[0]?.inprogress.length ? resultData[0]?.inprogress[0]?.count : 0,
1499
+ done: resultData[0]?.submit.length ? resultData[0]?.submit[0]?.count : 0,
1500
+ };
1501
+
1502
+ return res.sendSuccess( resultData );
1503
+ } catch ( e ) {
1504
+ logger.error( { function: 'dahboard', error: e } );
1505
+ return res.sendError( e, 500 );
1506
+ }
1507
+ }
1508
+
1509
+ export async function dashboardv1( req, res ) {
1510
+ try {
1511
+ // eslint-disable-next-line camelcase
1512
+ const { store_id, date } = req.query;
1513
+ const userId = req.user._id;
1514
+
1515
+ const baseMatch = {
1516
+ // eslint-disable-next-line camelcase
1517
+ store_id,
1518
+ userId,
1519
+ date_string: date,
1520
+ timeFlagStatus: true,
1521
+ };
1522
+
1523
+ const buildPipeline = ( matchExtraConditions = {} ) => [
1524
+ { $match: { ...baseMatch, ...matchExtraConditions } },
1525
+ {
1526
+ $facet: {
1527
+ total: [ { $count: 'total' } ],
1528
+ toDo: [
1529
+ { $match: { checklistStatus: 'open' } },
1530
+ { $group: { _id: '', count: { $sum: 1 } } },
1531
+ ],
1532
+ inprogress: [
1533
+ { $match: { checklistStatus: 'inprogress' } },
1534
+ { $group: { _id: '', count: { $sum: 1 } } },
1535
+ ],
1536
+ submit: [
1537
+ { $match: { checklistStatus: 'submit' } },
1538
+ { $group: { _id: '', count: { $sum: 1 } } },
1539
+ ],
1540
+ },
1541
+ },
1542
+ ];
1543
+
1544
+ const processResult = ( result ) => ( {
1545
+ totalchecklist: result[0]?.total[0]?.total || 0,
1546
+ todo: result[0]?.toDo[0]?.count || 0,
1547
+ inprogress: result[0]?.inprogress[0]?.count || 0,
1548
+ done: result[0]?.submit[0]?.count || 0,
1549
+ } );
1550
+
1551
+ const checklistQuery = buildPipeline( { checkListType: 'custom' } );
1552
+ const taskQuery = buildPipeline();
1553
+
1554
+ const [ checklistResult, taskResult ] = await Promise.allSettled( [
1555
+ processedchecklist.aggregate( checklistQuery ),
1556
+ processedTask.aggregate( taskQuery ),
1557
+ ] );
1558
+
1559
+ const checklistResultData =
1560
+ checklistResult.status === 'fulfilled' ?
1561
+ processResult( checklistResult.value ) :
1562
+ { totalchecklist: 0, todo: 0, inprogress: 0, done: 0 };
1563
+
1564
+ const taskResultData =
1565
+ taskResult.status === 'fulfilled' ?
1566
+ processResult( taskResult.value ) :
1567
+ { totalchecklist: 0, todo: 0, inprogress: 0, done: 0 };
1568
+
1569
+ const totalResult = {
1570
+ totalchecklist: checklistResultData.totalchecklist + taskResultData.totalchecklist,
1571
+ todo: checklistResultData.todo + taskResultData.todo,
1572
+ inprogress: checklistResultData.inprogress + taskResultData.inprogress,
1573
+ done: checklistResultData.done + taskResultData.done,
1574
+ };
1575
+
1576
+ return res.sendSuccess( totalResult );
1577
+ } catch ( e ) {
1578
+ logger.error( { function: 'dashboardv1', error: e } );
1579
+ return res.sendError( e, 500 );
1580
+ }
1581
+ }
1582
+
1583
+ export async function checklist( req, res ) {
1584
+ try {
1585
+ let requestData = req.query;
1586
+ let findQuery = [];
1587
+ let findAndQuery = [];
1588
+ let limit;
1589
+ let skip;
1590
+ let sortColumnName;
1591
+ let sortBy;
1592
+ switch ( requestData.checklistStatus ) {
1593
+ case 'open':
1594
+ sortColumnName = 'timeDifference';
1595
+ sortBy = 1;
1596
+ break;
1597
+ case 'inprogress':
1598
+ sortColumnName = 'timeDifference';
1599
+ sortBy = 1;
1600
+ break;
1601
+ case 'submit':
1602
+ sortColumnName = 'submitTime';
1603
+ sortBy = -1;
1604
+ break;
1605
+ default:
1606
+ sortColumnName = 'timeDifference';
1607
+ sortBy = 1;
1608
+ break;
1609
+ }
1610
+
1611
+ findAndQuery.push(
1612
+ { store_id: requestData.store_id },
1613
+ { userId: req.user._id },
1614
+ { date_string: requestData.date },
1615
+ { checkListType: 'custom' },
1616
+ { timeFlagStatus: true },
1617
+ );
1618
+
1619
+ if ( requestData.checklistStatus ) {
1620
+ findAndQuery.push( { checklistStatus: requestData.checklistStatus } );
1621
+ }
1622
+
1623
+ findQuery.push( { $match: { $and: findAndQuery } } );
1624
+
1625
+ if ( requestData.searchValue && requestData.searchValue != '' ) {
1626
+ findQuery.push( { $match: { $or: [ { checkListName: { $regex: requestData.searchValue, $options: 'i' } } ] } } );
1627
+ }
1628
+
1629
+ findQuery.push( {
1630
+ $project: {
1631
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
1632
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
1633
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
1634
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
1635
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
1636
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
1637
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
1638
+ startTime: { $ifNull: [ '$startTime', '' ] },
1639
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
1640
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
1641
+ allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
1642
+ reinitiateStatus: { $ifNull: [ '$reinitiateStatus', '' ] },
1643
+ startTime_string: { $ifNull: [ '$startTime_string', '' ] },
1644
+ submitTime_string: { $ifNull: [ '$submitTime_string', '' ] },
1645
+ timeFlag: { $ifNull: [ '$timeFlag', '' ] },
1646
+ scheduleRepeatedType: { $ifNull: [ '$scheduleRepeatedType', '' ] },
1647
+ timeDifference: { $subtract: [ '$scheduleEndTime_iso', '$date_iso' ] },
1648
+ },
1649
+ } );
1650
+
1651
+ if ( requestData.limit && requestData.offset ) {
1652
+ limit = parseInt( requestData.limit ) || 10;
1653
+ skip = limit * ( requestData.offset ) || 0;
1654
+ findQuery.push( { $skip: skip }, { $limit: limit } );
1655
+ }
1656
+
1657
+ findQuery.push( { $sort: { [sortColumnName]: sortBy } } );
1658
+
1659
+ let totalchecklist = await processedchecklist.aggregate( findQuery );
1660
+
1661
+ return res.sendSuccess( { count: totalchecklist.length, data: totalchecklist } );
1662
+ } catch ( e ) {
1663
+ logger.error( { function: 'checklist', error: e } );
1664
+ return res.sendError( e, 500 );
1665
+ }
1666
+ }
1667
+
1668
+ export async function checklistv1( req, res ) {
1669
+ try {
1670
+ // eslint-disable-next-line camelcase
1671
+ const { store_id, date, checklistStatus, searchValue } = req.query;
1672
+ const userId = req.user._id;
1673
+
1674
+ const buildPipeline = ( matchExtraConditions = [], type ) => {
1675
+ const matchConditions = [
1676
+ // eslint-disable-next-line camelcase
1677
+ { store_id },
1678
+ { userId },
1679
+ { date_string: date },
1680
+ { timeFlagStatus: true },
1681
+ ...matchExtraConditions,
1682
+ ];
1683
+
1684
+ if ( checklistStatus ) {
1685
+ matchConditions.push( { checklistStatus } );
1686
+ }
1687
+
1688
+ const pipeline = [
1689
+ { $match: { $and: matchConditions } },
1690
+ ...( searchValue ?
1691
+ [ { $match: { $or: [ { checkListName: { $regex: searchValue, $options: 'i' } } ] } } ] :
1692
+ [] ),
1693
+ {
1694
+ $project: {
1695
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
1696
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
1697
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
1698
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
1699
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
1700
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
1701
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
1702
+ startTime: { $ifNull: [ '$startTime', '' ] },
1703
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
1704
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
1705
+ allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
1706
+ reinitiateStatus: { $ifNull: [ '$reinitiateStatus', '' ] },
1707
+ startTime_string: { $ifNull: [ '$startTime_string', '' ] },
1708
+ submitTime_string: { $ifNull: [ '$submitTime_string', '' ] },
1709
+ timeFlag: { $ifNull: [ '$timeFlag', '' ] },
1710
+ scheduleRepeatedType: { $ifNull: [ '$scheduleRepeatedType', '' ] },
1711
+ timeDifference: { $subtract: [ '$scheduleEndTime_iso', '$date_iso' ] },
1712
+ redoStatus: { $ifNull: [ '$redoStatus', false ] },
1713
+ type: { $ifNull: [ '$checkListType', '' ] },
1714
+ },
1715
+ },
1716
+ ];
1717
+
1718
+ return pipeline;
1719
+ };
1720
+
1721
+ const [ checklistResult, taskResult ] = await Promise.allSettled( [
1722
+ processedchecklist.aggregate( buildPipeline( [ { checkListType: 'custom' } ], 'checklist' ) ),
1723
+ processedTask.aggregate( buildPipeline( [], 'task' ) ),
1724
+ ] );
1725
+
1726
+ const checklistData = checklistResult.status === 'fulfilled' ? checklistResult.value : [];
1727
+ const taskData = taskResult.status === 'fulfilled' ? taskResult.value : [];
1728
+
1729
+ const totalData = [ ...checklistData, ...taskData ];
1730
+
1731
+ if ( !totalData.length ) {
1732
+ return res.sendError( { error: 'No Data Found' }, 204 );
1733
+ }
1734
+
1735
+ const getSortingParams = ( status ) => {
1736
+ switch ( status ) {
1737
+ case 'submit':
1738
+ return { column: 'submitTime', order: -1 };
1739
+ case 'open':
1740
+ case 'inprogress':
1741
+ default:
1742
+ return { column: 'timeDifference', order: 1 };
1743
+ }
1744
+ };
1745
+
1746
+ const { column: sortColumnName, order: sortBy } = getSortingParams( checklistStatus );
1747
+
1748
+ totalData.sort( ( a, b ) => {
1749
+ if ( sortBy === 1 ) {
1750
+ return ( a[sortColumnName] || 0 ) - ( b[sortColumnName] || 0 );
1751
+ } else {
1752
+ return ( b[sortColumnName] || 0 ) - ( a[sortColumnName] || 0 );
1753
+ }
1754
+ } );
1755
+
1756
+ return res.sendSuccess( { count: totalData.length, data: totalData } );
1757
+ } catch ( e ) {
1758
+ logger.error( { function: 'checklistv1', error: e } );
1759
+ return res.sendError( e, 500 );
1760
+ }
1761
+ }
1762
+
1763
+ export async function questionList( req, res ) {
1764
+ try {
1765
+ let requestData = req.query;
1766
+ if ( !requestData.processedcheckListId ) {
1767
+ res.sendError( 'processedcheckListId is Required', 400 );
1768
+ }
1769
+
1770
+ let findQuery = [];
1771
+ let findAndQuery = [];
1772
+ findAndQuery.push( { _id: new ObjectId( requestData.processedcheckListId ) } );
1773
+ findQuery.push( { $match: { $and: findAndQuery } } );
1774
+
1775
+ findQuery.push( {
1776
+ $project: {
1777
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
1778
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
1779
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
1780
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
1781
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
1782
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
1783
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
1784
+ startTime: { $ifNull: [ '$startTime', '' ] },
1785
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
1786
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
1787
+ allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
1788
+ reinitiateStatus: { $ifNull: [ '$reinitiateStatus', '' ] },
1789
+ questionAnswers: { $ifNull: [ '$questionAnswers', '' ] },
1790
+ getchecklist: { $ifNull: [ '$getchecklist', '' ] },
1791
+ userEmail: { $ifNull: [ '$userEmail', '' ] },
1792
+ storeName: { $ifNull: [ '$storeName', '' ] },
1793
+ redoStatus: { $ifNull: [ '$redoStatus', false ] },
1794
+ },
1795
+ } );
1796
+
1797
+ let getchecklist = await processedchecklist.aggregate( findQuery );
1798
+ if ( !getchecklist.length ) {
1799
+ return res.sendError( 'Check List Got Edited Please Fill Again', 422 );
1800
+ } else {
1801
+ logger.info( `v5 => Checklist Continue => store Name: ${getchecklist[0].storeName}, User Email: ${getchecklist[0].userEmail}, Checklist Name: ${getchecklist[0].checkListName}` );
1802
+ let bucket = JSON.parse( process.env.BUCKET );
1803
+ for ( let [ secIndex, section ] of getchecklist[0].questionAnswers.entries() ) {
1804
+ for ( let [ questionIndex, question ] of section.questions.entries() ) {
1805
+ let Multianswer = [];
1806
+ if ( getchecklist[0].questionAnswers[secIndex].questions[questionIndex].questionReferenceImage && getchecklist[0].questionAnswers[secIndex].questions[questionIndex].questionReferenceImage !='' ) {
1807
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].questionReferenceImage = await signedUrl( { file_path: decodeURIComponent( getchecklist[0].questionAnswers[secIndex].questions[questionIndex].questionReferenceImage ), Bucket: bucket.sop } );
1808
+ }
1809
+ for ( let [ ansIndex, answer ] of question.answers.entries() ) {
1810
+ if ( question.answerType == 'multiplechoicemultiple' ) {
1811
+ let checkvalidation = null;
1812
+ if ( answer.validationAnswer && answer.validationAnswer !='' ) {
1813
+ checkvalidation = await signedUrl( { file_path: decodeURIComponent( answer.validationAnswer ), Bucket: bucket.sop } );
1814
+ }
1815
+ Multianswer.push( { 'answer': answer.answer, 'no': ansIndex, 'validationAnswer': checkvalidation } );
1816
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].answers[ansIndex].index = ansIndex;
1817
+ }
1818
+ if ( answer.referenceImage != '' ) {
1819
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].answers[ansIndex].referenceImage = await signedUrl( { file_path: decodeURIComponent( answer.referenceImage ), Bucket: bucket.sop } );
1820
+ }
1821
+ if ( ( answer.validationType == 'Capture Image' || answer.validationType == 'Capture Video' ) && answer.validationAnswer && answer.validationAnswer != '' ) {
1822
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].answers[ansIndex].validationAnswer = await signedUrl( { file_path: decodeURIComponent( answer.validationAnswer ), Bucket: bucket.sop } );
1823
+ }
1824
+ }
1825
+ if ( question?.userAnswer ) {
1826
+ for ( let [ userAnsIndex, userAns ] of question.userAnswer.entries() ) {
1827
+ if ( ( userAns.validationType == 'Capture Image' || userAns.validationType == 'Capture Video' ) && userAns.validationAnswer && userAns.validationAnswer != '' ) {
1828
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].validationAnswer = await signedUrl( { file_path: decodeURIComponent( userAns.validationAnswer ), Bucket: bucket.sop } );
1829
+ }
1830
+ if ( [ 'image', 'descriptiveImage', 'video' ].includes( question.answerType ) && userAns.answer != '' ) {
1831
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].answer = await signedUrl( { file_path: decodeURIComponent( userAns.answer ), Bucket: bucket.sop } );
1832
+ }
1833
+ if ( userAns.referenceImage != '' ) {
1834
+ getchecklist[0].questionAnswers[secIndex].questions[questionIndex].userAnswer[userAnsIndex].referenceImage = await signedUrl( { file_path: decodeURIComponent( userAns.referenceImage ), Bucket: bucket.sop } );
1835
+ }
1836
+ if ( question.answerType == 'multiplechoicemultiple' ) {
1837
+ let ansIndex = Multianswer.findIndex( ( item ) => item.answer == userAns.answer );
1838
+ if ( ansIndex ) {
1839
+ Multianswer[ansIndex].validationAnswer = userAns.validationAnswer;
1840
+ }
1841
+ }
1842
+ if ( question.answerType == 'multipleImage' ) {
1843
+ if ( userAns && userAns.answer && userAns.answer !='' ) {
1844
+ let manswer = await signedUrl( { file_path: decodeURIComponent( userAns.answer ), Bucket: bucket.sop } );
1845
+ Multianswer.push( { 'answer': manswer, 'no': userAnsIndex, 'validationAnswer': '' } );
1846
+ } else {
1847
+
1848
+ }
1849
+ }
1850
+ }
1851
+ }
1852
+ if ( question.answerType == 'multiplechoicemultiple' ) {
1853
+ Multianswer.forEach( ( item ) => {
1854
+ if ( item.validationAnswer == null ) {
1855
+ item.answer = null;
1856
+ }
1857
+ } );
1858
+ if ( Multianswer.length ) {
1859
+ question.Multianswer = Multianswer;
1860
+ } else {
1861
+ question.Multianswer = Multianswer;
1862
+ }
1863
+ }
1864
+ if ( question.answerType == 'multipleImage' ) {
1865
+ if ( Multianswer.length ) {
1866
+ question.Multianswer = Multianswer;
1867
+ } else {
1868
+ Multianswer.push( { 'answer': null, 'no': 0, 'validationAnswer': null } );
1869
+ question.Multianswer = Multianswer;
1870
+ }
1871
+ }
1872
+ }
1873
+ }
1874
+
1875
+ let questions = [];
1876
+ function processQuestion( question, section, questions, nested=false ) {
1877
+ let findExists = questions.find( ( item ) => item?.qno && item.qno == question.qno );
1878
+ if ( findExists && nested ) {
1879
+ let findIndex = questions.findIndex( ( item ) => item?.qno && item.qno == question.qno );
1880
+ questions.splice( findIndex, 1 );
1881
+ questions.push( question );
1882
+ for ( let answer of question.answers ) {
1883
+ if ( answer.showLinked && answer?.linkedQuestion != '' ) {
1884
+ let linkedQuestion = section.questions.find( ( item ) => item.qno == answer.linkedQuestion );
1885
+ if ( linkedQuestion ) {
1886
+ processQuestion( linkedQuestion, section, questions, true );
1887
+ }
1888
+ }
1889
+ }
1890
+ }
1891
+ if ( !findExists ) {
1892
+ questions.push( question );
1893
+ for ( let answer of question.answers ) {
1894
+ if ( answer.showLinked && answer?.linkedQuestion != '' ) {
1895
+ let linkedQuestion = section.questions.find( ( item ) => item.qno == answer.linkedQuestion );
1896
+ if ( linkedQuestion ) {
1897
+ processQuestion( linkedQuestion, section, questions, true );
1898
+ }
1899
+ }
1900
+ }
1901
+ }
1902
+ }
1903
+ for ( let [ index, data ] of getchecklist.entries() ) {
1904
+ for ( let [ secIndex, section ] of data.questionAnswers.entries() ) {
1905
+ questions = [];
1906
+ for ( let question of section.questions ) {
1907
+ processQuestion( question, section, questions );
1908
+ }
1909
+ getchecklist[index].questionAnswers[secIndex].questions = questions;
1910
+ }
1911
+ }
1912
+
1913
+ return res.sendSuccess( getchecklist );
1914
+ }
1915
+ } catch ( e ) {
1916
+ logger.error( { function: 'questionList', error: e } );
1917
+ return res.sendError( e, 500 );
1918
+ }
1919
+ }
1920
+
1921
+ export async function taskQuestionList( req, res ) {
1922
+ try {
1923
+ const { processedcheckListId } = req.query;
1924
+
1925
+ if ( !processedcheckListId ) {
1926
+ return res.sendError( 'processedcheckListId is required', 400 );
1927
+ }
1928
+
1929
+ const findQuery = [
1930
+ {
1931
+ $match: {
1932
+ _id: new ObjectId( processedcheckListId ),
1933
+ },
1934
+ },
1935
+ {
1936
+ $project: {
1937
+ checkListName: { $ifNull: [ '$checkListName', '' ] },
1938
+ scheduleStartTime: { $ifNull: [ '$scheduleStartTime', '' ] },
1939
+ scheduleStartTime_iso: { $ifNull: [ '$scheduleStartTime_iso', '' ] },
1940
+ scheduleEndTime: { $ifNull: [ '$scheduleEndTime', '' ] },
1941
+ scheduleEndTime_iso: { $ifNull: [ '$scheduleEndTime_iso', '' ] },
1942
+ checklistStatus: { $ifNull: [ '$checklistStatus', '' ] },
1943
+ checkListId: { $ifNull: [ '$checkListId', '' ] },
1944
+ startTime: { $ifNull: [ '$startTime', '' ] },
1945
+ submitTime: { $ifNull: [ '$submitTime', '' ] },
1946
+ allowedOverTime: { $ifNull: [ '$allowedOverTime', '' ] },
1947
+ allowedStoreLocation: { $ifNull: [ '$allowedStoreLocation', '' ] },
1948
+ reinitiateStatus: { $ifNull: [ '$reinitiateStatus', '' ] },
1949
+ questionAnswers: { $ifNull: [ '$questionAnswers', '' ] },
1950
+ userEmail: { $ifNull: [ '$userEmail', '' ] },
1951
+ storeName: { $ifNull: [ '$storeName', '' ] },
1952
+ },
1953
+ },
1954
+ ];
1955
+
1956
+ const [ checklist ] = await processedTask.aggregate( findQuery );
1957
+
1958
+ if ( !checklist ) {
1959
+ return res.sendError( 'Task got edited, please fill again', 422 );
1960
+ }
1961
+
1962
+ logger.info(
1963
+ `v5 => Checklist Continue => store Name: ${checklist.storeName}, User Email: ${checklist.userEmail}, Checklist Name: ${checklist.checkListName}`,
1964
+ );
1965
+
1966
+ const bucket = JSON.parse( process.env.BUCKET );
1967
+ const sopBucket = bucket.sop;
1968
+
1969
+ const getSignedUrl = async ( filePath ) =>
1970
+ filePath && filePath !== '' ?
1971
+ await signedUrl( { file_path: decodeURIComponent( filePath ), Bucket: sopBucket } ) :
1972
+ '';
1973
+
1974
+ for ( const section of checklist.questionAnswers || [] ) {
1975
+ for ( const question of section.questions || [] ) {
1976
+ const { answerType, answers = [], userAnswer = [] } = question;
1977
+ const multiAnswer = [];
1978
+
1979
+ if ( typeof question.questionReferenceImage == 'string' && question.questionReferenceImage ) {
1980
+ question.questionReferenceImage = await getSignedUrl( question.questionReferenceImage );
1981
+ } else {
1982
+ if ( question.questionReferenceImage.length ) {
1983
+ let image = [];
1984
+ for ( let img of question.questionReferenceImage ) {
1985
+ image.push( await getSignedUrl( img ) );
1986
+ }
1987
+ question.questionReferenceImage = image;
1988
+ }
1989
+ }
1990
+
1991
+ for ( const [ ansIndex, answer ] of answers.entries() ) {
1992
+ answer.index = ansIndex;
1993
+
1994
+ answer.referenceImage = answer?.referenceImage ? await getSignedUrl( answer.referenceImage ) : '';
1995
+
1996
+ if ( [ 'Capture Image', 'Capture Video' ].includes( answer.validationType ) && answer.validationAnswer ) {
1997
+ answer.validationAnswer = await getSignedUrl( answer.validationAnswer );
1998
+ }
1999
+
2000
+ if ( answerType === 'multiplechoicemultiple'&& answer.validationAnswer ) {
2001
+ const validationAnswer = await getSignedUrl( answer.validationAnswer );
2002
+ multiAnswer.push( { answer: answer.answer, no: ansIndex, validationAnswer } );
2003
+ }
2004
+ }
2005
+
2006
+ for ( const [ userAnsIndex, userAns ] of userAnswer.entries() ) {
2007
+ if ( [ 'Capture Image', 'Capture Video' ].includes( userAns.validationType ) && userAns.validationAnswer ) {
2008
+ userAns.validationAnswer = await getSignedUrl( userAns.validationAnswer );
2009
+ }
2010
+
2011
+ if ( [ 'image', 'descriptiveImage', 'video' ].includes( answerType ) && userAns.answer ) {
2012
+ userAns.answer = await getSignedUrl( userAns.answer );
2013
+ }
2014
+
2015
+ userAns.referenceImage = userAns.referenceImage ? await getSignedUrl( userAns.referenceImage ) : '';
2016
+
2017
+ if ( answerType === 'multiplechoicemultiple' ) {
2018
+ const ansIndex = multiAnswer.findIndex( ( item ) => item.answer === userAns.answer );
2019
+ if ( ansIndex >= 0 ) {
2020
+ multiAnswer[ansIndex].validationAnswer = userAns.validationAnswer;
2021
+ }
2022
+ }
2023
+
2024
+ if ( answerType === 'multipleImage' && userAns.answer ) {
2025
+ const manswer = await getSignedUrl( userAns.answer );
2026
+ multiAnswer.push( { answer: manswer, no: userAnsIndex, validationAnswer: '' } );
2027
+ }
2028
+ }
2029
+
2030
+ if ( [ 'multiplechoicemultiple', 'multipleImage' ].includes( answerType ) ) {
2031
+ question.Multianswer = multiAnswer.length ?
2032
+ multiAnswer.map( ( item ) => ( { ...item, answer: item.validationAnswer ? item.answer : null } ) ) :
2033
+ [ { answer: null, no: 0, validationAnswer: null } ];
2034
+ }
2035
+ }
2036
+ }
2037
+
2038
+ return res.sendSuccess( [ checklist ] );
2039
+ } catch ( error ) {
2040
+ logger.error( { function: 'taskQuestionList', error } );
2041
+ return res.sendError( error.message || 'Internal Server Error', 500 );
2042
+ }
2043
+ }
2044
+
2045
+
2046
+ export async function uploadAnswerImage( req, res ) {
2047
+ try {
2048
+ let input = req.body;
2049
+ let bucket = JSON.parse( process.env.BUCKET );
2050
+ if ( !input.checklistId ) {
2051
+ return res.sensError( 'Invalid Request: Please include checklistId!', 400 );
2052
+ }
2053
+
2054
+ if ( !input.sectionName ) {
2055
+ return res.sensError( 'Invalid Request: Please include sectionName!', 400 );
2056
+ }
2057
+
2058
+ if ( ( !input.questionNo && input.questionNo != 0 ) ) {
2059
+ return res.sensError( 'Invalid Request: Please include questionNo!', 400 );
2060
+ }
2061
+
2062
+ let date = dayjs().format( 'YYYY-MM-DD' );
2063
+ let folder;
2064
+
2065
+ if ( input.type == 'custom' ) {
2066
+ folder = 'checklist-answers';
2067
+ } else {
2068
+ folder = 'task-answers';
2069
+ }
2070
+
2071
+ if ( req.files && req.files.answerImage ) {
2072
+ let imageUrl;
2073
+ let filePath = `${folder}/${req.user.clientId}/${date}/${input.checklistId}/${input.sectionName.replace( ' ', '' )}/${input.questionNo}/`;
2074
+ let params = {
2075
+ fileName: `${Date.now()}-${Math.floor( 1000 + Math.random() * 9000 )}.${req.files.answerImage.name.split( '.' )[1]}`,
2076
+ Key: filePath,
2077
+ Bucket: bucket.sop,
2078
+ body: req.files.answerImage.data,
2079
+ ContentType: req.files.answerImage.mimetype,
2080
+ };
2081
+
2082
+ imageUrl = await fileUpload( params );
2083
+ if ( imageUrl.errors && imageUrl.errors.length ) {
2084
+ return res.sendError( imageUrl.errors[0].message, '400' );
2085
+ }
2086
+
2087
+ if ( imageUrl != '' ) {
2088
+ imageUrl = await signedUrl( { file_path: imageUrl.Key, Bucket: bucket.sop } );
2089
+
2090
+ return res.sendSuccess( {
2091
+ bucketName: bucket.sop,
2092
+ imageUrl: imageUrl,
2093
+ message: 'Image uploaded successfully!',
2094
+ } );
2095
+ }
2096
+ } else {
2097
+ return res.sendError( 'Please upload an image with key answerImage!', 400 );
2098
+ }
2099
+ } catch ( e ) {
2100
+ logger.error( { function: 'uploadAnswerImage', error: e } );
2101
+ return res.sendError( e, 500 );
2102
+ }
2103
+ }
2104
+
2105
+ export async function appVersion( req, res ) {
2106
+ try {
2107
+ let reqquery = req.query;
2108
+ let query = [];
2109
+ let limit = req.query.limit || 10;
2110
+ let skip = req.query.limit * req.query.offset || 0;
2111
+ let appNameIds = [];
2112
+
2113
+ if ( reqquery.appName && reqquery.appName !='' ) {
2114
+ let storedata = reqquery.appName.split( ',' );
2115
+ storedata.forEach( ( element ) => {
2116
+ appNameIds.push( element );
2117
+ } );
2118
+ }
2119
+
2120
+ if ( reqquery.appName && reqquery.appName !='' ) {
2121
+ query.push( { $match: { appName: { $in: appNameIds } } } );
2122
+ }
2123
+
2124
+ query.push( {
2125
+ $facet: {
2126
+ data: [
2127
+ { $skip: skip }, { $limit: limit },
2128
+ ],
2129
+ count: [
2130
+ { $count: 'count' },
2131
+ ],
2132
+ },
2133
+ } );
2134
+
2135
+ let response = await appService.aggregate( query );
2136
+ return res.sendSuccess( { count: response[0].count.length ? response[0].count[0].count : 0, data: response[0].data } );
2137
+ } catch ( e ) {
2138
+ logger.error( { function: 'appVersion', error: e } );
2139
+ return res.sendError( e, 500 );
2140
+ }
2141
+ }
2142
+
2143
+
2144
+ export async function updateappVersion( req, res ) {
2145
+ try {
2146
+ let reqData = req.body;
2147
+ if ( !reqData.appName ) {
2148
+ return res.sendError( 'appName Required', 400 );
2149
+ }
2150
+
2151
+ if ( !reqData.appVersion ) {
2152
+ return res.sendError( 'appVersion Required', 400 );
2153
+ }
2154
+
2155
+ let checkQuery = {};
2156
+ checkQuery.appName = reqData.appName;
2157
+
2158
+ let insertData = await appService.updateOne( checkQuery, reqData );
2159
+ if ( insertData ) {
2160
+ return res.sendSuccess( 'App Version Update Done' );
2161
+ } else {
2162
+ return res.sendError( 'Something went wrong please try again', 500 );
2163
+ }
2164
+ } catch ( error ) {
2165
+ logger.error( { function: 'appVersionupdate', error: error } );
2166
+ if ( error.name === 'ValidationError' ) return res.sendError( error, 400 );
2167
+ else return res.sendError( error, 500 );
2168
+ }
2169
+ };
2170
+
2171
+ export async function login( req, res ) {
2172
+ try {
2173
+ let inputData = req.body;
2174
+ const query = {
2175
+ email: { $regex: new RegExp( `^${inputData.email}$`, 'i' ) },
2176
+ };
2177
+ const result = await userService.findOne( query );
2178
+ if ( !result ) {
2179
+ return res.sendError( `User mail not Exists`, 401 );
2180
+ }
2181
+ if ( !result.isActive ) {
2182
+ return res.sendError( 'The user has been unauthorized to login', 401 );
2183
+ }
2184
+ if ( inputData.otp ) {
2185
+ const otpMatching = await findOTP( { email: inputData.email, type: 'login', otp: inputData.otp } );
2186
+ if ( !otpMatching?.length ) {
2187
+ return res.sendError( `Invalid OTP`, 401 );
2188
+ }
2189
+ } else {
2190
+ const otp = getOtp();
2191
+ await updateOneOTP( { email: inputData.email, type: 'login' }, { email: inputData.email, otp: otp, type: 'login' } );
2192
+ const emailVars = {
2193
+ email: inputData.email,
2194
+ otp: otp,
2195
+ name: result.userName,
2196
+ };
2197
+ await sendSignInOtpEmail( emailVars );
2198
+ return res.sendSuccess( { result: 'VERIFY-OTP' } );
2199
+ }
2200
+ const token = {
2201
+ authenticationToken: await getUuid(),
2202
+ refreshToken: await getUuid(),
2203
+ };
2204
+ const record = {
2205
+ user: result?._id,
2206
+ token: token?.authenticationToken,
2207
+ refreshToken: token?.refreshToken,
2208
+ type: 'retail',
2209
+ };
2210
+
2211
+ let userDetails = await userService.findOne( { fcmToken: inputData.fcmToken } );
2212
+
2213
+ if ( userDetails ) {
2214
+ await userService.updateOne( { _id: userDetails?._id }, { fcmToken: '' } );
2215
+ }
2216
+
2217
+ const auth = await create( record );
2218
+ await userService.updateOne( { _id: result?._id }, { refreshToken: token?.refreshToken, fcmToken: inputData.fcmToken } );
2219
+
2220
+ if ( auth ) {
2221
+ return res.sendSuccess( { result: token } );
2222
+ }
2223
+ } catch ( e ) {
2224
+ logger.error( { function: 'login', error: e } );
2225
+ return res.sendError( e, 500 );
2226
+ }
2227
+ }
2228
+
2229
+ export const sendSignInOtpEmail = async ( emailVars ) => {
2230
+ try {
2231
+ const ses = JSON.parse( process.env.SES );
2232
+ const url = JSON.parse( process.env.URL );
2233
+ const attachments = null;
2234
+ const subject = 'Fwd: Tango Eye | Verify OTP';
2235
+ const fileContent = readFileSync( join() + '/src/hbs/login-otp.hbs', 'utf8' );
2236
+ const htmlContent = handlebars.compile( fileContent );
2237
+ const html = htmlContent( { ...emailVars, domain: url.apiDomain } );
2238
+ const result = await sendEmailWithSES( emailVars.email, subject, html, attachments, ses.adminEmail );
2239
+ return result;
2240
+ } catch ( error ) {
2241
+ logger.error( { error: error, function: 'sendSignInOtpEmail' } );
2242
+ return error;
2243
+ }
2244
+ };
2245
+
2246
+
2247
+ export async function location( req, res ) {
2248
+ try {
2249
+ let input = req.body;
2250
+ if ( input.latitude && input.longitude ) {
2251
+ let storeLatitude = req.sop_assigned_store.latitude;
2252
+ let storeLongitude = req.sop_assigned_store.longitude;
2253
+
2254
+ function degreesToRadians( degrees ) {
2255
+ let radians = ( degrees * Math.PI ) / 180;
2256
+ return radians;
2257
+ }
2258
+
2259
+ function calcDistance( startingCoords, destinationCoords ) {
2260
+ let startingLat = degreesToRadians( startingCoords.latitude );
2261
+ let startingLong = degreesToRadians( startingCoords.longitude );
2262
+ let destinationLat = degreesToRadians( destinationCoords.latitude );
2263
+ let destinationLong = degreesToRadians( destinationCoords.longitude );
2264
+
2265
+ // Radius of the Earth in kilometers
2266
+ let radius = 6571;
2267
+
2268
+ // Haversine equation
2269
+ let distanceInKilometers =
2270
+ Math.acos( Math.sin( startingLat ) * Math.sin( destinationLat ) +
2271
+ Math.cos( startingLat ) * Math.cos( destinationLat ) *
2272
+ Math.cos( startingLong - destinationLong ) ) * radius;
2273
+ return distanceInKilometers*1000; // to metres
2274
+ }
2275
+
2276
+ let sCoords = {
2277
+ latitude: storeLatitude,
2278
+ longitude: storeLongitude,
2279
+ };
2280
+
2281
+ let dCoords = {
2282
+ latitude: input.latitude,
2283
+ longitude: input.longitude,
2284
+ };
2285
+
2286
+ let distance = calcDistance( sCoords, dCoords );
2287
+
2288
+ let brand = await clientService.findOne( { clientId: req.user.clientId } );
2289
+
2290
+ let radiusConfigured = brand ? ( brand.storeRadiusConfig ? brand.storeRadiusConfig : 500 ) : 500;
2291
+ let actualDistance = ( ( distance/1000.0 ) || 0 ).toFixed( 2 );
2292
+ let actualDistanceMSG = 'You are '+actualDistance+' KM far from the store location';
2293
+
2294
+ if ( distance<=radiusConfigured ) {
2295
+ return res.sendSuccess( { locationRadiusCheck: true, distance: distance, unit: 'metre', message: actualDistanceMSG } );
2296
+ } else {
2297
+ return res.sendSuccess( { locationRadiusCheck: false, distance: distance, unit: 'metre', message: actualDistanceMSG } );
2298
+ }
2299
+ } else {
2300
+ return res.sendError( 'Please include latitude and longitude!', 400 );
2301
+ }
2302
+ } catch ( e ) {
2303
+ logger.error( { error: e, function: 'location' } );
2304
+ return sendError( error, 500 );
2305
+ }
2306
+ }
2307
+
2308
+ export async function getStoreLocation( req, res, next ) {
2309
+ try {
2310
+ let input = req.body;
2311
+ if ( input.store_id ) {
2312
+ let storeDetails = await storeService.findOne( { storeId: input.store_id }, { storeProfile: 1 } );
2313
+ if ( storeDetails ) {
2314
+ req.sop_assigned_store = storeDetails.storeProfile;
2315
+ next();
2316
+ } else {
2317
+ return res.sendError( 'Invalid store_id provided!', 400 );
2318
+ }
2319
+ } else {
2320
+ return res.sendError( 'No store/Checklist assigned to the user!', 400 );
2321
+ }
2322
+ } catch ( error ) {
2323
+ logger.error( { function: 'SOP Mobile store check middleware error', error: error } );
2324
+ let msg = error.error ? error.error : error;
2325
+ return res.sendError( msg, 500 );
2326
+ }
2327
+ };