tango-app-api-trax 3.7.75 → 3.7.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -2
- package/src/controllers/handlebar-helper.js +31 -0
- package/src/controllers/internalTrax.controller.js +210 -3
- package/src/controllers/mobileTrax.controller.js +388 -43
- package/src/controllers/trax.controller.js +80 -1
- package/src/controllers/traxDashboard.controllers.js +58 -3
- package/src/hbs/flag.hbs +249 -0
- package/src/hbs/login-otp.hbs +943 -943
- package/src/hbs/template.hbs +337 -0
- package/src/routes/internalTraxApi.router.js +1 -0
- package/src/routes/mobileTrax.routes.js +3 -1
- package/src/routes/trax.routes.js +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-trax",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.77",
|
|
4
4
|
"description": "Trax",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,11 +23,13 @@
|
|
|
23
23
|
"firebase-admin": "^13.0.0",
|
|
24
24
|
"fs": "^0.0.1-security",
|
|
25
25
|
"handlebars": "^4.7.8",
|
|
26
|
+
"html-pdf": "^3.0.1",
|
|
26
27
|
"lodash": "^4.17.21",
|
|
27
28
|
"mongodb": "^6.8.0",
|
|
28
29
|
"nodemon": "^3.1.4",
|
|
29
30
|
"path": "^0.12.7",
|
|
30
|
-
"
|
|
31
|
+
"puppeteer": "^24.39.1",
|
|
32
|
+
"tango-api-schema": "^2.5.67",
|
|
31
33
|
"tango-app-api-middleware": "^3.5.2",
|
|
32
34
|
"url": "^0.11.4",
|
|
33
35
|
"winston": "^3.13.1",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Handlebars from 'handlebars';
|
|
2
|
+
|
|
3
|
+
Handlebars.registerHelper( 'eq', function( arg1, arg2, options ) {
|
|
4
|
+
return ( arg1 == arg2 ) ? options.fn( this ) : options.inverse( this );
|
|
5
|
+
} );
|
|
6
|
+
|
|
7
|
+
Handlebars.registerHelper( 'neq', function( a, b, options ) {
|
|
8
|
+
return a !== b ? options.fn( this ) : options.inverse( this );
|
|
9
|
+
} );
|
|
10
|
+
|
|
11
|
+
Handlebars.registerHelper( 'includes', function( array, value ) {
|
|
12
|
+
if ( !Array.isArray( array ) ) return false;
|
|
13
|
+
return array.includes( value );
|
|
14
|
+
} );
|
|
15
|
+
|
|
16
|
+
Handlebars.registerHelper( 'gte', function( a, b, options ) {
|
|
17
|
+
if ( options && options.fn ) {
|
|
18
|
+
return ( a >= b ) ? options.fn( this ) : options.inverse( this );
|
|
19
|
+
}
|
|
20
|
+
return a >= b;
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
Handlebars.registerHelper( 'mult', function( a, b ) {
|
|
24
|
+
return Math.round( ( a || 0 ) * ( b || 1 ) );
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
Handlebars.registerHelper( 'add', function( a, b ) {
|
|
28
|
+
return ( a || 0 ) + ( b || 0 );
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
export default Handlebars;
|
|
@@ -595,6 +595,7 @@ export async function PCLconfigCreation( req, res ) {
|
|
|
595
595
|
element4.remainder = getCLconfig?.remainder || [];
|
|
596
596
|
element4.country = element4?.store?.[0]?.country || '';
|
|
597
597
|
element4.state = element4?.store?.[0]?.state || '';
|
|
598
|
+
element4.complianceCount = getCLconfig?.complianceCount || 0;
|
|
598
599
|
|
|
599
600
|
// if ( getCLconfig?.isPlano ) {
|
|
600
601
|
// let planoDetails = await planoService.findOne( { storeId: element4.store_id, clientId: getCLconfig.client_id }, { _id: 1 } );
|
|
@@ -1362,6 +1363,42 @@ export async function insertTimeDelayFlags( req, res ) {
|
|
|
1362
1363
|
|
|
1363
1364
|
let updatedDetails = await processedchecklist.updateMany( { _id: { $in: checklistId } }, { timeFlag: 1 } );
|
|
1364
1365
|
|
|
1366
|
+
|
|
1367
|
+
let notifyStores = await processedchecklist.find( { _id: { $in: checklistId }, notify: { $exists: false } } );
|
|
1368
|
+
|
|
1369
|
+
if ( notifyStores.length ) {
|
|
1370
|
+
Promise.all( notifyStores.map( async ( store ) => {
|
|
1371
|
+
let checklistDetails = await checklistService.findOne( { _id: store.sourceCheckList_id }, { notifyFlags: 1, approver: 1 } );
|
|
1372
|
+
if ( checklistDetails?.notifyFlags?.notifyType?.length ) {
|
|
1373
|
+
let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
|
|
1374
|
+
emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
|
|
1375
|
+
let data = {
|
|
1376
|
+
storeName: store.storeName,
|
|
1377
|
+
flagCount: 1,
|
|
1378
|
+
checklistName: store.checkListName?.trim(),
|
|
1379
|
+
submittedBy: '--',
|
|
1380
|
+
time: '--',
|
|
1381
|
+
domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags`,
|
|
1382
|
+
type: 'delay',
|
|
1383
|
+
};
|
|
1384
|
+
const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
|
|
1385
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
1386
|
+
const html = htmlContent( { data: data } );
|
|
1387
|
+
emailList.forEach( ( email ) => {
|
|
1388
|
+
let params = {
|
|
1389
|
+
toEmail: email,
|
|
1390
|
+
mailSubject: 'TangoEye | Checklist Flag',
|
|
1391
|
+
htmlBody: html,
|
|
1392
|
+
attachment: '',
|
|
1393
|
+
sourceEmail: JSON.parse( process.env.SES ).adminEmail,
|
|
1394
|
+
};
|
|
1395
|
+
sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
|
|
1396
|
+
} );
|
|
1397
|
+
}
|
|
1398
|
+
await processedchecklist.updateOne( { _id: store._id }, { notify: true } );
|
|
1399
|
+
} ) );
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1365
1402
|
if ( updatedDetails ) {
|
|
1366
1403
|
return res.sendSuccess( { message: 'Time Delay Updated Successfully' } );
|
|
1367
1404
|
}
|
|
@@ -2715,8 +2752,13 @@ export async function updateChecklistConfig( req, res ) {
|
|
|
2715
2752
|
|
|
2716
2753
|
export async function submittedList( req, res ) {
|
|
2717
2754
|
try {
|
|
2755
|
+
let fromDate = new Date( dayjs().format( 'YYYY-MM-DD' ) );
|
|
2756
|
+
let toDate = new Date( dayjs().format( 'YYYY-MM-DD' ) );
|
|
2757
|
+
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
2758
|
+
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
2759
|
+
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
2718
2760
|
let getSubmitChecklist = await processedchecklist.find( { checklistStatus: 'submit', date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ) }, { _id: 1 } );
|
|
2719
|
-
let getSubmitTask = await processedTaskService.find( { checklistStatus: 'submit', date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ), isPlano: { $exists: false } }, { _id: 1 } );
|
|
2761
|
+
let getSubmitTask = await processedTaskService.find( { checklistStatus: 'submit', $or: [ { date_iso: new Date( dayjs().format( 'YYYY-MM-DD' ) ) }, { scheduleEndTime_iso: { $gte: fromDate, $lte: toDate } } ], isPlano: { $exists: false } }, { _id: 1 } );
|
|
2720
2762
|
|
|
2721
2763
|
let result = [ ...getSubmitChecklist?.map( ( ele ) => ele?._id ), ...getSubmitTask?.map( ( ele ) => ele?._id ) ];
|
|
2722
2764
|
return res.sendSuccess( result );
|
|
@@ -3203,9 +3245,37 @@ export async function checklistTaskSubmissionDetails( req, res ) {
|
|
|
3203
3245
|
}
|
|
3204
3246
|
let details = [];
|
|
3205
3247
|
if ( req.body.type == 'checklist' ) {
|
|
3206
|
-
details = await processedchecklist.find( { sourceCheckList_id: req.body.checklistId, date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
|
|
3248
|
+
details = await processedchecklist.find( { sourceCheckList_id: req.body.checklistId, checklistStatus: 'submit', date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
|
|
3249
|
+
date_string: 1,
|
|
3250
|
+
checkListName: 1,
|
|
3251
|
+
createdByName: 1,
|
|
3252
|
+
store_id: 1,
|
|
3253
|
+
storeName: 1,
|
|
3254
|
+
submmitedBy: '$userName',
|
|
3255
|
+
submmitedByEmail: '$userEmail',
|
|
3256
|
+
checklistStatus: 1,
|
|
3257
|
+
submitTime: 1,
|
|
3258
|
+
approvalTime: 1,
|
|
3259
|
+
approvalTime_string: 1,
|
|
3260
|
+
approvalByName: 1,
|
|
3261
|
+
approvalByEmail: 1,
|
|
3262
|
+
} );
|
|
3207
3263
|
} else {
|
|
3208
|
-
details = await processedTaskService.find( { sourceCheckList_id: req.body.checklistId, date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
|
|
3264
|
+
details = await processedTaskService.find( { sourceCheckList_id: req.body.checklistId, checklistStatus: 'submit', date_iso: new Date( dayjs( req.body.date ).format( 'YYYY-MM-DD' ) ) }, {
|
|
3265
|
+
date_string: 1,
|
|
3266
|
+
checkListName: 1,
|
|
3267
|
+
createdByName: 1,
|
|
3268
|
+
store_id: 1,
|
|
3269
|
+
storeName: 1,
|
|
3270
|
+
submmitedBy: '$userName',
|
|
3271
|
+
submmitedByEmail: '$userEmail',
|
|
3272
|
+
checklistStatus: 1,
|
|
3273
|
+
submitTime: 1,
|
|
3274
|
+
approvalTime: 1,
|
|
3275
|
+
approvalTime_string: 1,
|
|
3276
|
+
approvalByName: 1,
|
|
3277
|
+
approvalByEmail: 1,
|
|
3278
|
+
} );
|
|
3209
3279
|
}
|
|
3210
3280
|
return res.sendSuccess( details );
|
|
3211
3281
|
} catch ( e ) {
|
|
@@ -3213,3 +3283,140 @@ export async function checklistTaskSubmissionDetails( req, res ) {
|
|
|
3213
3283
|
return res.sendError( e, 500 );
|
|
3214
3284
|
}
|
|
3215
3285
|
}
|
|
3286
|
+
|
|
3287
|
+
export async function getStoreTaskDetails( req, res ) {
|
|
3288
|
+
try {
|
|
3289
|
+
const checklistQuery = [
|
|
3290
|
+
{
|
|
3291
|
+
$match: {
|
|
3292
|
+
storeName: req.body.storeName,
|
|
3293
|
+
checkListName: { $regex: 'Store Tour', $options: 'i' },
|
|
3294
|
+
},
|
|
3295
|
+
},
|
|
3296
|
+
{
|
|
3297
|
+
$group: {
|
|
3298
|
+
_id: '$storeName',
|
|
3299
|
+
checklistStatus: { $last: '$checklistStatus' },
|
|
3300
|
+
checkListName: { $last: '$checkListName' },
|
|
3301
|
+
scheduleEndTime_iso: { $last: '$scheduleEndTime_iso' },
|
|
3302
|
+
},
|
|
3303
|
+
},
|
|
3304
|
+
];
|
|
3305
|
+
const checkListDetails = await processedchecklist.aggregate( checklistQuery );
|
|
3306
|
+
const taskQuery = [
|
|
3307
|
+
{
|
|
3308
|
+
$match: {
|
|
3309
|
+
storeName: req.body.storeName,
|
|
3310
|
+
isPlano: true,
|
|
3311
|
+
planoType: { $in: [ 'fixture', 'merchRollout', 'vmRollout' ] },
|
|
3312
|
+
},
|
|
3313
|
+
},
|
|
3314
|
+
{
|
|
3315
|
+
$group: {
|
|
3316
|
+
_id: { store: '$storeName', type: '$planoType' },
|
|
3317
|
+
checklistStatus: { $last: '$checklistStatus' },
|
|
3318
|
+
checkListName: { $last: '$checkListName' },
|
|
3319
|
+
scheduleEndTime_iso: { $last: '$scheduleEndTime_iso' },
|
|
3320
|
+
},
|
|
3321
|
+
},
|
|
3322
|
+
{
|
|
3323
|
+
$project: {
|
|
3324
|
+
store: '$_id.store',
|
|
3325
|
+
type: '$_id.type',
|
|
3326
|
+
checklistStatus: 1,
|
|
3327
|
+
checkListName: 1,
|
|
3328
|
+
scheduleEndTime_iso: 1,
|
|
3329
|
+
},
|
|
3330
|
+
},
|
|
3331
|
+
];
|
|
3332
|
+
|
|
3333
|
+
|
|
3334
|
+
const taskDetails = await processedTaskService.aggregate( taskQuery );
|
|
3335
|
+
console.log( taskDetails );
|
|
3336
|
+
let info = [ ...checkListDetails, ...taskDetails ];
|
|
3337
|
+
// const details = {
|
|
3338
|
+
// storeTourVideoChecklist: ( !checkListDetails.length || checkListDetails?.[0]?.checklistStatus == 'submit' ) ? true : false,
|
|
3339
|
+
// FixtureVerification: ( !taskDetails.length || !taskDetails?.some( ( ele ) => ele?.type == 'fixture' ) || taskDetails?.some( ( ele ) => ele?.type == 'fixture' && ele?.checklistStatus == 'submit' ) ) ? true : false,
|
|
3340
|
+
// MerchRollout: ( !taskDetails.length || !taskDetails?.some( ( ele ) => ele?.type == 'merchRollout' ) || taskDetails?.some( ( ele ) => ele?.type == 'merchRollout' && ele?.checklistStatus == 'submit' ) ) ? true : false,
|
|
3341
|
+
// VmRollout: ( !taskDetails.length || !taskDetails?.some( ( ele ) => ele?.type == 'vmRollout' ) || taskDetails?.some( ( ele ) => ele?.type == 'vmRollout' && ele?.checklistStatus == 'submit' ) ) ? true : false,
|
|
3342
|
+
// };
|
|
3343
|
+
|
|
3344
|
+
let result = {
|
|
3345
|
+
storeId: req.body.storeName,
|
|
3346
|
+
tangoPosBlocks: info.filter( ( ele ) => ele.checklistStatus != 'submit' && dayjs( ele?.scheduleEndTime_iso ).format( 'YYYY-MM-DD' ) < dayjs().format( 'YYYY-MM-DD' ) ).map( ( ele ) => {
|
|
3347
|
+
return {
|
|
3348
|
+
blockName: ele?.checkListName,
|
|
3349
|
+
blockEnabled: true,
|
|
3350
|
+
blockReason: `${ele?.checkListName} is completed`,
|
|
3351
|
+
};
|
|
3352
|
+
} ),
|
|
3353
|
+
upcomingTangoPosBlocks: info.filter( ( ele ) => ele.checklistStatus !== 'submit' ).map( ( ele ) => {
|
|
3354
|
+
return {
|
|
3355
|
+
blockName: ele?.checkListName,
|
|
3356
|
+
blockReason: `Compelete ${ele?.checkListName} before ${dayjs( ele?.scheduleEndTime_iso ).format( 'YYYY-MM-DD' )} to avoid ABC block`,
|
|
3357
|
+
dueDate: dayjs( ele?.scheduleEndTime_iso ).format( 'YYYY-MM-DD' ),
|
|
3358
|
+
};
|
|
3359
|
+
} ),
|
|
3360
|
+
};
|
|
3361
|
+
|
|
3362
|
+
|
|
3363
|
+
return res.sendSuccess( result );
|
|
3364
|
+
} catch ( error ) {
|
|
3365
|
+
const err = error.message || 'Internal Server Error';
|
|
3366
|
+
logger.error( { error: error, message: req.body, function: 'getStoretaskDetails' } );
|
|
3367
|
+
return res.sendError( err, 500 );
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
export async function runAIFlag( req, res ) {
|
|
3372
|
+
try {
|
|
3373
|
+
let checklistDetails = await CLconfig.find( { publish: true, $expr: { $ne: [ { $size: '$notifyFlags.notifyType' }, 0 ] }, runAIQuestionCount: { $ne: 0 } }, { _id: 1 } );
|
|
3374
|
+
if ( checklistDetails.length ) {
|
|
3375
|
+
await Promise.all( checklistDetails.map( async ( ele ) => {
|
|
3376
|
+
let submitDetails = await processedchecklist.find( { sourceCheckList_id: ele._id, checklistStatus: 'submit' }, { storeName: 1, checkListName: 1, questionAnswers: 1 } );
|
|
3377
|
+
await Promise.all( submitDetails.map( ( store ) => {
|
|
3378
|
+
if ( questionAnswers.length ) {
|
|
3379
|
+
let runAIFlag = 0;
|
|
3380
|
+
questionAnswers.forEach( ( section ) => {
|
|
3381
|
+
section.questions.forEach( ( question ) => {
|
|
3382
|
+
if ( question.answerType == 'image' && ( question?.userAnswer?.[0]?.runAIDate.value == 'false' || !question?.userAnswer?.[0]?.runAIDate.value ) ) {
|
|
3383
|
+
runAIFlag++;
|
|
3384
|
+
}
|
|
3385
|
+
} );
|
|
3386
|
+
} );
|
|
3387
|
+
|
|
3388
|
+
if ( runAIFlag ) {
|
|
3389
|
+
let emailList = checklistDetails?.notifyFlags?.notifyType.includes( 'approver' ) ? checklistDetails.approver.map( ( ele ) => ele?.value ): [];
|
|
3390
|
+
emailList = [ ...emailList, ...checklistDetails?.notifyFlags?.users?.map( ( ele ) => ele?.value ) ];
|
|
3391
|
+
let data = {
|
|
3392
|
+
storeName: store.storeName,
|
|
3393
|
+
flagCount: 1,
|
|
3394
|
+
checklistName: store.checkListName?.trim(),
|
|
3395
|
+
submittedBy: '--',
|
|
3396
|
+
time: '--',
|
|
3397
|
+
domain: `${JSON.parse( process.env.URL ).domain}/manage/trax/flags`,
|
|
3398
|
+
type: 'delay',
|
|
3399
|
+
};
|
|
3400
|
+
const fileContent = fs.readFileSync( path.resolve( path.dirname( '' ) ) + '/src/hbs/flag.hbs', 'utf8' );
|
|
3401
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
3402
|
+
const html = htmlContent( { data: data } );
|
|
3403
|
+
emailList.forEach( ( email ) => {
|
|
3404
|
+
let params = {
|
|
3405
|
+
toEmail: email,
|
|
3406
|
+
mailSubject: 'TangoEye | Checklist Flag',
|
|
3407
|
+
htmlBody: html,
|
|
3408
|
+
attachment: '',
|
|
3409
|
+
sourceEmail: JSON.parse( process.env.SES ).adminEmail,
|
|
3410
|
+
};
|
|
3411
|
+
sendEmailWithSES( params.toEmail, params.mailSubject, params.htmlBody, params.attachment, params.sourceEmail );
|
|
3412
|
+
} );
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
} ) );
|
|
3416
|
+
} ) );
|
|
3417
|
+
}
|
|
3418
|
+
} catch ( e ) {
|
|
3419
|
+
logger.error( { functionName: 'runAIFlag', error: e } );
|
|
3420
|
+
return res.sendError( e, 500 );
|
|
3421
|
+
}
|
|
3422
|
+
}
|