tango-app-api-infra 3.9.5-vms.78 → 3.9.5-vms.79
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.
|
@@ -392,6 +392,85 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
392
392
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
393
393
|
|
|
394
394
|
if ( insertResult && ( insertResult.statusCode === 201 || insertResult.statusCode === 200 ) ) {
|
|
395
|
+
if ( record.status = 'Closed' && inputData.ticketType !== 'internal' ) {
|
|
396
|
+
const query = {
|
|
397
|
+
storeId: inputData?.storeId,
|
|
398
|
+
isVideoStream: true,
|
|
399
|
+
};
|
|
400
|
+
const getStoreType = await countDocumnetsCamera( query );
|
|
401
|
+
const revopInfoQuery = {
|
|
402
|
+
size: 10000,
|
|
403
|
+
query: {
|
|
404
|
+
bool: {
|
|
405
|
+
must: [
|
|
406
|
+
{
|
|
407
|
+
term: {
|
|
408
|
+
'storeId.keyword': inputData.storeId,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
term: {
|
|
413
|
+
'dateString': inputData.dateString,
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
term: {
|
|
418
|
+
'isParent': false,
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
term: {
|
|
423
|
+
isChecked: true,
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
_source: [ 'tempId' ],
|
|
430
|
+
|
|
431
|
+
};
|
|
432
|
+
const revopInfo = await getOpenSearchData( openSearch.revop, revopInfoQuery );
|
|
433
|
+
// Get all tempIds from revopInfo response
|
|
434
|
+
const tempIds = revopInfo?.body?.hits?.hits?.map( ( hit ) => hit?._source?.tempId ).filter( Boolean ) || [];
|
|
435
|
+
// Prepare management eyeZone query based on storeId and dateString
|
|
436
|
+
const managerEyeZoneQuery = {
|
|
437
|
+
size: 1,
|
|
438
|
+
query: {
|
|
439
|
+
bool: {
|
|
440
|
+
must: [
|
|
441
|
+
{
|
|
442
|
+
term: {
|
|
443
|
+
'storeId.keyword': inputData.storeId,
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
term: {
|
|
448
|
+
'storeDate': inputData.dateString,
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
],
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
_source: [ 'originalToTrackerCustomerMapping' ],
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// Query the managerEyeZone index for the matching document
|
|
458
|
+
const managerEyeZoneResp = await getOpenSearchData( openSearch.managerEyeZone, managerEyeZoneQuery );
|
|
459
|
+
const managerEyeZoneHit = managerEyeZoneResp?.body?.hits?.hits?.[0]?._source;
|
|
460
|
+
// Extract originalToTrackerCustomerMapping if it exists
|
|
461
|
+
const mapping =
|
|
462
|
+
managerEyeZoneHit && managerEyeZoneHit.originalToTrackerCustomerMapping ?
|
|
463
|
+
managerEyeZoneHit.originalToTrackerCustomerMapping :
|
|
464
|
+
{};
|
|
465
|
+
|
|
466
|
+
// Find tempIds that exist in both revopInfo results and manager mapping
|
|
467
|
+
const temp = [];
|
|
468
|
+
tempIds.filter( ( tid ) => mapping[tid] !== null ? temp.push( { tempId: mapping[tid] } ) :'' );
|
|
469
|
+
const isSendMessge = await sendSqsMessage( inputData, temp, getStoreType, inputData.storeId );
|
|
470
|
+
if ( isSendMessge == true ) {
|
|
471
|
+
logger.info( '....1' );
|
|
472
|
+
}
|
|
473
|
+
}
|
|
395
474
|
return res.sendSuccess( 'Ticket closed successfully' );
|
|
396
475
|
} else {
|
|
397
476
|
return res.sendError( 'Internal Server Error', 500 );
|
|
@@ -514,22 +593,6 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
514
593
|
} );
|
|
515
594
|
}
|
|
516
595
|
|
|
517
|
-
|
|
518
|
-
// If no review mapping existed, push a new one
|
|
519
|
-
// if ( record.mappingInfo.length === 0 ) {
|
|
520
|
-
// record.mappingInfo.push( {
|
|
521
|
-
// type: 'tangoreview',
|
|
522
|
-
// mode: inputData.mappingInfo?.mode,
|
|
523
|
-
// revicedFootfall: temp?.mappingInfo?.revicedFootfall,
|
|
524
|
-
// revicedPerc: temp?.mappingInfo?.revicedPerc,
|
|
525
|
-
// count: temp?.mappingInfo?.count,
|
|
526
|
-
// revisedDetail: temp?.mappingInfo?.revisedDetail,
|
|
527
|
-
// status: 'Closed',
|
|
528
|
-
// createdByEmail: req?.user?.email,
|
|
529
|
-
// createdByUserName: req?.user?.userName,
|
|
530
|
-
// createdByRole: req?.user?.role,
|
|
531
|
-
// } );
|
|
532
|
-
// }
|
|
533
596
|
record.mappingInfo.push(
|
|
534
597
|
{
|
|
535
598
|
type: 'finalRevision',
|
|
@@ -555,6 +618,84 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
555
618
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
556
619
|
|
|
557
620
|
if ( insertResult && ( insertResult.statusCode === 201 || insertResult.statusCode === 200 ) ) {
|
|
621
|
+
const query = {
|
|
622
|
+
storeId: inputData?.storeId,
|
|
623
|
+
isVideoStream: true,
|
|
624
|
+
};
|
|
625
|
+
const getStoreType = await countDocumnetsCamera( query );
|
|
626
|
+
const revopInfoQuery = {
|
|
627
|
+
size: 10000,
|
|
628
|
+
query: {
|
|
629
|
+
bool: {
|
|
630
|
+
must: [
|
|
631
|
+
{
|
|
632
|
+
term: {
|
|
633
|
+
'storeId.keyword': inputData.storeId,
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
term: {
|
|
638
|
+
'dateString': inputData.dateString,
|
|
639
|
+
},
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
term: {
|
|
643
|
+
'isParent': false,
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
term: {
|
|
648
|
+
isChecked: true,
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
_source: [ 'tempId' ],
|
|
655
|
+
|
|
656
|
+
};
|
|
657
|
+
const revopInfo = await getOpenSearchData( openSearch.revop, revopInfoQuery );
|
|
658
|
+
// Get all tempIds from revopInfo response
|
|
659
|
+
const tempIds = revopInfo?.body?.hits?.hits?.map( ( hit ) => hit?._source?.tempId ).filter( Boolean ) || [];
|
|
660
|
+
// Prepare management eyeZone query based on storeId and dateString
|
|
661
|
+
const managerEyeZoneQuery = {
|
|
662
|
+
size: 1,
|
|
663
|
+
query: {
|
|
664
|
+
bool: {
|
|
665
|
+
must: [
|
|
666
|
+
{
|
|
667
|
+
term: {
|
|
668
|
+
'storeId.keyword': inputData.storeId,
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
term: {
|
|
673
|
+
'storeDate': inputData.dateString,
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
],
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
_source: [ 'originalToTrackerCustomerMapping' ],
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// Query the managerEyeZone index for the matching document
|
|
683
|
+
const managerEyeZoneResp = await getOpenSearchData( openSearch.managerEyeZone, managerEyeZoneQuery );
|
|
684
|
+
const managerEyeZoneHit = managerEyeZoneResp?.body?.hits?.hits?.[0]?._source;
|
|
685
|
+
// Extract originalToTrackerCustomerMapping if it exists
|
|
686
|
+
const mapping =
|
|
687
|
+
managerEyeZoneHit && managerEyeZoneHit.originalToTrackerCustomerMapping ?
|
|
688
|
+
managerEyeZoneHit.originalToTrackerCustomerMapping :
|
|
689
|
+
{};
|
|
690
|
+
|
|
691
|
+
// Find tempIds that exist in both revopInfo results and manager mapping
|
|
692
|
+
const temp = [];
|
|
693
|
+
tempIds.filter( ( tid ) => mapping[tid] !== null ? temp.push( { tempId: mapping[tid] } ) :'' );
|
|
694
|
+
const isSendMessge = await sendSqsMessage( inputData, temp, getStoreType, inputData.storeId );
|
|
695
|
+
if ( isSendMessge == true ) {
|
|
696
|
+
logger.info( '....1' );
|
|
697
|
+
}
|
|
698
|
+
|
|
558
699
|
return res.sendSuccess( 'Ticket closed successfully' );
|
|
559
700
|
} else {
|
|
560
701
|
return res.sendError( 'Internal Server Error', 500 );
|
|
@@ -1101,69 +1242,503 @@ export async function ticketSummary( req, res ) {
|
|
|
1101
1242
|
let aboveQinternal = buildAggInternalQuery( baseInternalQuery, [
|
|
1102
1243
|
{
|
|
1103
1244
|
script: {
|
|
1104
|
-
script: {
|
|
1105
|
-
lang: 'painless',
|
|
1106
|
-
source: `
|
|
1107
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1108
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1109
|
-
`,
|
|
1110
|
-
params: { num: 85 },
|
|
1111
|
-
},
|
|
1245
|
+
script: {
|
|
1246
|
+
lang: 'painless',
|
|
1247
|
+
source: `
|
|
1248
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1249
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1250
|
+
`,
|
|
1251
|
+
params: { num: 85 },
|
|
1252
|
+
},
|
|
1253
|
+
},
|
|
1254
|
+
},
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
] );
|
|
1258
|
+
const aboveRespInternal = await getOpenSearchData( openSearch.footfallDirectory, aboveQinternal );
|
|
1259
|
+
internalTicketAccuracyAbove = aboveRespInternal?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1260
|
+
|
|
1261
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1262
|
+
let internalTicketAccuracyBelow = 0;
|
|
1263
|
+
|
|
1264
|
+
let belowQIneranl = buildAggInternalQuery( baseInternalQuery, [
|
|
1265
|
+
{
|
|
1266
|
+
script: {
|
|
1267
|
+
script: {
|
|
1268
|
+
lang: 'painless',
|
|
1269
|
+
source: `
|
|
1270
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1271
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1272
|
+
`,
|
|
1273
|
+
params: { num: 85 },
|
|
1274
|
+
},
|
|
1275
|
+
},
|
|
1276
|
+
},
|
|
1277
|
+
|
|
1278
|
+
] );
|
|
1279
|
+
const belowRespInternal = await getOpenSearchData( openSearch.footfallDirectory, belowQIneranl );
|
|
1280
|
+
internalTicketAccuracyBelow = belowRespInternal?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1281
|
+
|
|
1282
|
+
// Final result object
|
|
1283
|
+
result = {
|
|
1284
|
+
totalTickets: totalInternalTickets,
|
|
1285
|
+
averageAccuracyOverAll: internalAverageAccuracyOverAll+'%',
|
|
1286
|
+
openTickets: openInternalTickets,
|
|
1287
|
+
openInfraIssues: openInternalInfraIssues,
|
|
1288
|
+
inprogress: inprogressIntrenal,
|
|
1289
|
+
closedTickets: closedInternalTickets,
|
|
1290
|
+
ticketAccuracyAbove: internalTicketAccuracyAbove+'%',
|
|
1291
|
+
ticketAccuracyBelow: internalTicketAccuracyBelow+'%',
|
|
1292
|
+
};
|
|
1293
|
+
break;
|
|
1294
|
+
default: '';
|
|
1295
|
+
}
|
|
1296
|
+
} else if ( req?.user?.userType === 'client' ) {
|
|
1297
|
+
if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1298
|
+
const storeQuery = {
|
|
1299
|
+
size: 0,
|
|
1300
|
+
query: {
|
|
1301
|
+
bool: {
|
|
1302
|
+
must: [
|
|
1303
|
+
{
|
|
1304
|
+
'range': {
|
|
1305
|
+
'dateString': {
|
|
1306
|
+
'gte': inputData?.fromDate,
|
|
1307
|
+
'lte': inputData?.toDate,
|
|
1308
|
+
'format': 'yyyy-MM-dd',
|
|
1309
|
+
},
|
|
1310
|
+
},
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
nested: {
|
|
1314
|
+
path: 'mappingInfo',
|
|
1315
|
+
query: {
|
|
1316
|
+
bool: {
|
|
1317
|
+
must: [
|
|
1318
|
+
{
|
|
1319
|
+
term: {
|
|
1320
|
+
'mappingInfo.type': 'review',
|
|
1321
|
+
},
|
|
1322
|
+
},
|
|
1323
|
+
],
|
|
1324
|
+
},
|
|
1325
|
+
},
|
|
1326
|
+
},
|
|
1327
|
+
},
|
|
1328
|
+
|
|
1329
|
+
],
|
|
1330
|
+
},
|
|
1331
|
+
},
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1334
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1335
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1336
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1337
|
+
// Remove any previous mappingInfo.status term
|
|
1338
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1339
|
+
if ( nested ) {
|
|
1340
|
+
// filter out all mappingInfo.status
|
|
1341
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1342
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1343
|
+
} );
|
|
1344
|
+
// add desired status
|
|
1345
|
+
nested.nested.query.bool.must.push( {
|
|
1346
|
+
term: {
|
|
1347
|
+
'mappingInfo.status': statusValue,
|
|
1348
|
+
},
|
|
1349
|
+
} );
|
|
1350
|
+
}
|
|
1351
|
+
return q;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1355
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1356
|
+
|
|
1357
|
+
// locate nested section
|
|
1358
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1359
|
+
|
|
1360
|
+
if ( nested ) {
|
|
1361
|
+
// remove old status filters
|
|
1362
|
+
nested.nested.query.bool.must =
|
|
1363
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1364
|
+
|
|
1365
|
+
// add new filters
|
|
1366
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return {
|
|
1370
|
+
...q,
|
|
1371
|
+
size: 0,
|
|
1372
|
+
aggs: {
|
|
1373
|
+
avg_value: {
|
|
1374
|
+
avg: {
|
|
1375
|
+
script: {
|
|
1376
|
+
lang: 'painless',
|
|
1377
|
+
source: `
|
|
1378
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1379
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1380
|
+
try {
|
|
1381
|
+
return Double.parseDouble(v);
|
|
1382
|
+
} catch (Exception e) {
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
`,
|
|
1386
|
+
},
|
|
1387
|
+
},
|
|
1388
|
+
},
|
|
1389
|
+
},
|
|
1390
|
+
};
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
// Get OpenSearch connection
|
|
1395
|
+
|
|
1396
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1397
|
+
|
|
1398
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1399
|
+
let totalTickets = 0;
|
|
1400
|
+
|
|
1401
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1402
|
+
|
|
1403
|
+
allQuery.size = 0;
|
|
1404
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1405
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1406
|
+
|
|
1407
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1408
|
+
let openTickets = 0;
|
|
1409
|
+
|
|
1410
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1411
|
+
otQ.size = 0;
|
|
1412
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1413
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1414
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1418
|
+
let inprogress = 0;
|
|
1419
|
+
|
|
1420
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1421
|
+
ipQ.size = 0;
|
|
1422
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1423
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1424
|
+
|
|
1425
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1426
|
+
let closedTickets = 0;
|
|
1427
|
+
|
|
1428
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1429
|
+
clQ.size = 0;
|
|
1430
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1431
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1432
|
+
|
|
1433
|
+
let dueToday = 0;
|
|
1434
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1435
|
+
|
|
1436
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1437
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1438
|
+
// Locate nested mappingInfo query
|
|
1439
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1440
|
+
if ( nestedDue ) {
|
|
1441
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1442
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1443
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1444
|
+
);
|
|
1445
|
+
// Add new dueDate filter
|
|
1446
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1447
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1448
|
+
} );
|
|
1449
|
+
}
|
|
1450
|
+
dueTodayQuery.size = 0;
|
|
1451
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1452
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1453
|
+
|
|
1454
|
+
// filter expired Tickets
|
|
1455
|
+
let expiredTickets = 0;
|
|
1456
|
+
|
|
1457
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1458
|
+
eQ.size = 0;
|
|
1459
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1460
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1461
|
+
|
|
1462
|
+
let ticketAccuracyAbove = 0;
|
|
1463
|
+
// For this, add a filter on revicedPerc >= 85
|
|
1464
|
+
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1465
|
+
{
|
|
1466
|
+
script: {
|
|
1467
|
+
script: {
|
|
1468
|
+
lang: 'painless',
|
|
1469
|
+
source: `
|
|
1470
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1471
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1472
|
+
`,
|
|
1473
|
+
params: { num: 85 },
|
|
1474
|
+
},
|
|
1475
|
+
},
|
|
1476
|
+
},
|
|
1477
|
+
|
|
1478
|
+
|
|
1479
|
+
] );
|
|
1480
|
+
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1481
|
+
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1482
|
+
|
|
1483
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1484
|
+
let ticketAccuracyBelow = 0;
|
|
1485
|
+
|
|
1486
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1487
|
+
{
|
|
1488
|
+
script: {
|
|
1489
|
+
script: {
|
|
1490
|
+
lang: 'painless',
|
|
1491
|
+
source: `
|
|
1492
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1493
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1494
|
+
`,
|
|
1495
|
+
params: { num: 85 },
|
|
1496
|
+
},
|
|
1497
|
+
},
|
|
1498
|
+
},
|
|
1499
|
+
|
|
1500
|
+
] );
|
|
1501
|
+
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1502
|
+
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1503
|
+
|
|
1504
|
+
// Final result object
|
|
1505
|
+
result = {
|
|
1506
|
+
totalTickets,
|
|
1507
|
+
openTickets,
|
|
1508
|
+
inprogress,
|
|
1509
|
+
closedTickets,
|
|
1510
|
+
dueToday: dueToday,
|
|
1511
|
+
Expired: expiredTickets,
|
|
1512
|
+
avgTicket: ticketAccuracyAbove+'%',
|
|
1513
|
+
avgAccuracy: ticketAccuracyBelow+'%',
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
} else if ( ticketsFeature && ticketsApproveFeature ) {
|
|
1517
|
+
if ( inputData?.permissionType === 'review' ) {
|
|
1518
|
+
const storeQuery = {
|
|
1519
|
+
size: 0,
|
|
1520
|
+
query: {
|
|
1521
|
+
bool: {
|
|
1522
|
+
must: [
|
|
1523
|
+
{
|
|
1524
|
+
'range': {
|
|
1525
|
+
'dateString': {
|
|
1526
|
+
'gte': inputData?.fromDate,
|
|
1527
|
+
'lte': inputData?.toDate,
|
|
1528
|
+
'format': 'yyyy-MM-dd',
|
|
1529
|
+
},
|
|
1530
|
+
},
|
|
1531
|
+
},
|
|
1532
|
+
{
|
|
1533
|
+
nested: {
|
|
1534
|
+
path: 'mappingInfo',
|
|
1535
|
+
query: {
|
|
1536
|
+
bool: {
|
|
1537
|
+
must: [
|
|
1538
|
+
{
|
|
1539
|
+
term: {
|
|
1540
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1541
|
+
},
|
|
1542
|
+
},
|
|
1543
|
+
],
|
|
1544
|
+
},
|
|
1545
|
+
},
|
|
1546
|
+
},
|
|
1547
|
+
},
|
|
1548
|
+
|
|
1549
|
+
],
|
|
1550
|
+
},
|
|
1551
|
+
},
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1555
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1556
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1557
|
+
// Remove any previous mappingInfo.status term
|
|
1558
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1559
|
+
if ( nested ) {
|
|
1560
|
+
// filter out all mappingInfo.status
|
|
1561
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1562
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1563
|
+
} );
|
|
1564
|
+
// add desired status
|
|
1565
|
+
nested.nested.query.bool.must.push( {
|
|
1566
|
+
term: {
|
|
1567
|
+
'mappingInfo.status': statusValue,
|
|
1568
|
+
},
|
|
1569
|
+
} );
|
|
1570
|
+
}
|
|
1571
|
+
return q;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1575
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1576
|
+
|
|
1577
|
+
// locate nested section
|
|
1578
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1579
|
+
|
|
1580
|
+
if ( nested ) {
|
|
1581
|
+
// remove old status filters
|
|
1582
|
+
nested.nested.query.bool.must =
|
|
1583
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1584
|
+
|
|
1585
|
+
// add new filters
|
|
1586
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
return {
|
|
1590
|
+
...q,
|
|
1591
|
+
size: 0,
|
|
1592
|
+
aggs: {
|
|
1593
|
+
avg_value: {
|
|
1594
|
+
avg: {
|
|
1595
|
+
script: {
|
|
1596
|
+
lang: 'painless',
|
|
1597
|
+
source: `
|
|
1598
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1599
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1600
|
+
try {
|
|
1601
|
+
return Double.parseDouble(v);
|
|
1602
|
+
} catch (Exception e) {
|
|
1603
|
+
return null;
|
|
1604
|
+
}
|
|
1605
|
+
`,
|
|
1606
|
+
},
|
|
1607
|
+
},
|
|
1608
|
+
},
|
|
1609
|
+
},
|
|
1610
|
+
};
|
|
1611
|
+
};
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
// Get OpenSearch connection
|
|
1615
|
+
|
|
1616
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1617
|
+
|
|
1618
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1619
|
+
let totalTickets = 0;
|
|
1620
|
+
|
|
1621
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1622
|
+
|
|
1623
|
+
allQuery.size = 0;
|
|
1624
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1625
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1626
|
+
|
|
1627
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1628
|
+
let openTickets = 0;
|
|
1629
|
+
|
|
1630
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1631
|
+
otQ.size = 0;
|
|
1632
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1633
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1634
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1638
|
+
let inprogress = 0;
|
|
1639
|
+
|
|
1640
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1641
|
+
ipQ.size = 0;
|
|
1642
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1643
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1644
|
+
|
|
1645
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1646
|
+
let closedTickets = 0;
|
|
1647
|
+
|
|
1648
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1649
|
+
clQ.size = 0;
|
|
1650
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1651
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1652
|
+
// Average revisedPerc (for all tangoreview)
|
|
1653
|
+
|
|
1654
|
+
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1655
|
+
let dueToday = 0;
|
|
1656
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1657
|
+
|
|
1658
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1659
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1660
|
+
// Locate nested mappingInfo query
|
|
1661
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1662
|
+
if ( nestedDue ) {
|
|
1663
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1664
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1665
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1666
|
+
);
|
|
1667
|
+
// Add new dueDate filter
|
|
1668
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1669
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1670
|
+
} );
|
|
1671
|
+
}
|
|
1672
|
+
dueTodayQuery.size = 0;
|
|
1673
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1674
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
// filter expired Tickets
|
|
1678
|
+
let expiredTickets = 0;
|
|
1679
|
+
|
|
1680
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1681
|
+
eQ.size = 0;
|
|
1682
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1683
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1684
|
+
|
|
1685
|
+
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
1686
|
+
let ticketAccuracyAbove = 0;
|
|
1687
|
+
|
|
1688
|
+
|
|
1689
|
+
// For this, add a filter on revicedPerc >= 85
|
|
1690
|
+
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1691
|
+
{
|
|
1692
|
+
script: {
|
|
1693
|
+
script: {
|
|
1694
|
+
lang: 'painless',
|
|
1695
|
+
source: `
|
|
1696
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1697
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1698
|
+
`,
|
|
1699
|
+
params: { num: 85 },
|
|
1112
1700
|
},
|
|
1113
1701
|
},
|
|
1702
|
+
},
|
|
1114
1703
|
|
|
1115
1704
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1705
|
+
] );
|
|
1706
|
+
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1707
|
+
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1119
1708
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1709
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1710
|
+
let ticketAccuracyBelow = 0;
|
|
1122
1711
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1712
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1713
|
+
{
|
|
1714
|
+
script: {
|
|
1125
1715
|
script: {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
params: { num: 85 },
|
|
1133
|
-
},
|
|
1716
|
+
lang: 'painless',
|
|
1717
|
+
source: `
|
|
1718
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1719
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1720
|
+
`,
|
|
1721
|
+
params: { num: 85 },
|
|
1134
1722
|
},
|
|
1135
1723
|
},
|
|
1724
|
+
},
|
|
1136
1725
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1726
|
+
] );
|
|
1727
|
+
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1728
|
+
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1140
1729
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
default: '';
|
|
1154
|
-
}
|
|
1155
|
-
// result = {
|
|
1156
|
-
// totalTickets: 0,
|
|
1157
|
-
// averageAccuracyOverAll: 0,
|
|
1158
|
-
// openTickets: 0,
|
|
1159
|
-
// openInfraIssues: 0,
|
|
1160
|
-
// inprogress: 0,
|
|
1161
|
-
// closedTickets: 0,
|
|
1162
|
-
// ticketAccuracyAbove: '0%',
|
|
1163
|
-
// ticketAccuracyBelow: '0%',
|
|
1164
|
-
// };
|
|
1165
|
-
} else if ( req?.user?.userType === 'client' ) {
|
|
1166
|
-
if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1730
|
+
// Final result object
|
|
1731
|
+
result = {
|
|
1732
|
+
totalTickets,
|
|
1733
|
+
openTickets,
|
|
1734
|
+
inprogress,
|
|
1735
|
+
closedTickets,
|
|
1736
|
+
dueToday: dueToday,
|
|
1737
|
+
Expired: expiredTickets,
|
|
1738
|
+
avgTicket: ticketAccuracyAbove+'%',
|
|
1739
|
+
avgAccuracy: ticketAccuracyBelow+'%',
|
|
1740
|
+
};
|
|
1741
|
+
} else {
|
|
1167
1742
|
const storeQuery = {
|
|
1168
1743
|
size: 0,
|
|
1169
1744
|
query: {
|
|
@@ -1186,7 +1761,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1186
1761
|
must: [
|
|
1187
1762
|
{
|
|
1188
1763
|
term: {
|
|
1189
|
-
'mappingInfo.type': 'review',
|
|
1764
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1190
1765
|
},
|
|
1191
1766
|
},
|
|
1192
1767
|
],
|
|
@@ -1245,12 +1820,12 @@ export async function ticketSummary( req, res ) {
|
|
|
1245
1820
|
lang: 'painless',
|
|
1246
1821
|
source: `
|
|
1247
1822
|
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1248
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1249
|
-
try {
|
|
1823
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1824
|
+
try {
|
|
1250
1825
|
return Double.parseDouble(v);
|
|
1251
|
-
} catch (Exception e) {
|
|
1826
|
+
} catch (Exception e) {
|
|
1252
1827
|
return null;
|
|
1253
|
-
}
|
|
1828
|
+
}
|
|
1254
1829
|
`,
|
|
1255
1830
|
},
|
|
1256
1831
|
},
|
|
@@ -1283,14 +1858,6 @@ try {
|
|
|
1283
1858
|
// logger.info( { msd: '..............2', openResp } );
|
|
1284
1859
|
|
|
1285
1860
|
|
|
1286
|
-
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1287
|
-
let openInfraIssues = 0;
|
|
1288
|
-
|
|
1289
|
-
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1290
|
-
oiQ.size = 0;
|
|
1291
|
-
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1292
|
-
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1293
|
-
|
|
1294
1861
|
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1295
1862
|
let inprogress = 0;
|
|
1296
1863
|
|
|
@@ -1306,18 +1873,48 @@ try {
|
|
|
1306
1873
|
clQ.size = 0;
|
|
1307
1874
|
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1308
1875
|
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1309
|
-
//
|
|
1310
|
-
let
|
|
1876
|
+
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1877
|
+
let dueToday = 0;
|
|
1878
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1879
|
+
|
|
1880
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1881
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1882
|
+
// Locate nested mappingInfo query
|
|
1883
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1884
|
+
if ( nestedDue ) {
|
|
1885
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1886
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1887
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1888
|
+
);
|
|
1889
|
+
// Add new dueDate filter
|
|
1890
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1891
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1892
|
+
} );
|
|
1893
|
+
}
|
|
1894
|
+
dueTodayQuery.size = 0;
|
|
1895
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1896
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1311
1897
|
|
|
1312
|
-
let avgQ = buildAggStoreQuery( baseStoreQuery );
|
|
1313
|
-
const avgResp = await getOpenSearchData( openSearch.footfallDirectory, avgQ );
|
|
1314
|
-
averageAccuracyOverAll = avgResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1315
1898
|
|
|
1316
|
-
//
|
|
1317
|
-
let
|
|
1899
|
+
// filter expired Tickets
|
|
1900
|
+
let expiredTickets = 0;
|
|
1318
1901
|
|
|
1902
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1903
|
+
eQ.size = 0;
|
|
1904
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1905
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1906
|
+
|
|
1907
|
+
// filter under tango review
|
|
1908
|
+
|
|
1909
|
+
let undertangoTickets = 0;
|
|
1910
|
+
|
|
1911
|
+
let utrQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1912
|
+
utrQ.size = 0;
|
|
1913
|
+
const utrResp = await getOpenSearchData( openSearch.footfallDirectory, utrQ );
|
|
1914
|
+
undertangoTickets = utrResp?.body?.hits?.total?.value || 0;
|
|
1319
1915
|
|
|
1320
1916
|
// For this, add a filter on revicedPerc >= 85
|
|
1917
|
+
let ticketAccuracyAbove = 0;
|
|
1321
1918
|
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1322
1919
|
{
|
|
1323
1920
|
script: {
|
|
@@ -1334,6 +1931,7 @@ try {
|
|
|
1334
1931
|
|
|
1335
1932
|
|
|
1336
1933
|
] );
|
|
1934
|
+
|
|
1337
1935
|
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1338
1936
|
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1339
1937
|
|
|
@@ -1361,246 +1959,16 @@ try {
|
|
|
1361
1959
|
// Final result object
|
|
1362
1960
|
result = {
|
|
1363
1961
|
totalTickets,
|
|
1364
|
-
averageAccuracyOverAll: averageAccuracyOverAll+'%',
|
|
1365
1962
|
openTickets,
|
|
1366
|
-
openInfraIssues,
|
|
1367
1963
|
inprogress,
|
|
1368
1964
|
closedTickets,
|
|
1369
|
-
|
|
1370
|
-
|
|
1965
|
+
dueToday: dueToday,
|
|
1966
|
+
Expired: expiredTickets,
|
|
1967
|
+
underTangoReview: undertangoTickets,
|
|
1968
|
+
avgTicket: ticketAccuracyAbove+'%',
|
|
1969
|
+
avgAccuracy: ticketAccuracyBelow+'%',
|
|
1371
1970
|
};
|
|
1372
1971
|
}
|
|
1373
|
-
} else if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1374
|
-
const storeQuery = {
|
|
1375
|
-
size: 0,
|
|
1376
|
-
query: {
|
|
1377
|
-
bool: {
|
|
1378
|
-
must: [
|
|
1379
|
-
{
|
|
1380
|
-
'range': {
|
|
1381
|
-
'dateString': {
|
|
1382
|
-
'gte': inputData?.fromDate,
|
|
1383
|
-
'lte': inputData?.toDate,
|
|
1384
|
-
'format': 'yyyy-MM-dd',
|
|
1385
|
-
},
|
|
1386
|
-
},
|
|
1387
|
-
},
|
|
1388
|
-
{
|
|
1389
|
-
nested: {
|
|
1390
|
-
path: 'mappingInfo',
|
|
1391
|
-
query: {
|
|
1392
|
-
bool: {
|
|
1393
|
-
must: [
|
|
1394
|
-
{
|
|
1395
|
-
term: {
|
|
1396
|
-
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1397
|
-
},
|
|
1398
|
-
},
|
|
1399
|
-
],
|
|
1400
|
-
},
|
|
1401
|
-
},
|
|
1402
|
-
},
|
|
1403
|
-
},
|
|
1404
|
-
|
|
1405
|
-
],
|
|
1406
|
-
},
|
|
1407
|
-
},
|
|
1408
|
-
};
|
|
1409
|
-
|
|
1410
|
-
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1411
|
-
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1412
|
-
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1413
|
-
// Remove any previous mappingInfo.status term
|
|
1414
|
-
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1415
|
-
if ( nested ) {
|
|
1416
|
-
// filter out all mappingInfo.status
|
|
1417
|
-
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1418
|
-
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1419
|
-
} );
|
|
1420
|
-
// add desired status
|
|
1421
|
-
nested.nested.query.bool.must.push( {
|
|
1422
|
-
term: {
|
|
1423
|
-
'mappingInfo.status': statusValue,
|
|
1424
|
-
},
|
|
1425
|
-
} );
|
|
1426
|
-
}
|
|
1427
|
-
return q;
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1431
|
-
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1432
|
-
|
|
1433
|
-
// locate nested section
|
|
1434
|
-
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1435
|
-
|
|
1436
|
-
if ( nested ) {
|
|
1437
|
-
// remove old status filters
|
|
1438
|
-
nested.nested.query.bool.must =
|
|
1439
|
-
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1440
|
-
|
|
1441
|
-
// add new filters
|
|
1442
|
-
nested.nested.query.bool.must.push( ...filters );
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
return {
|
|
1446
|
-
...q,
|
|
1447
|
-
size: 0,
|
|
1448
|
-
aggs: {
|
|
1449
|
-
avg_value: {
|
|
1450
|
-
avg: {
|
|
1451
|
-
script: {
|
|
1452
|
-
lang: 'painless',
|
|
1453
|
-
source: `
|
|
1454
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1455
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1456
|
-
try {
|
|
1457
|
-
return Double.parseDouble(v);
|
|
1458
|
-
} catch (Exception e) {
|
|
1459
|
-
return null;
|
|
1460
|
-
}
|
|
1461
|
-
`,
|
|
1462
|
-
},
|
|
1463
|
-
},
|
|
1464
|
-
},
|
|
1465
|
-
},
|
|
1466
|
-
};
|
|
1467
|
-
};
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
// Get OpenSearch connection
|
|
1471
|
-
|
|
1472
|
-
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1473
|
-
|
|
1474
|
-
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1475
|
-
let totalTickets = 0;
|
|
1476
|
-
|
|
1477
|
-
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1478
|
-
|
|
1479
|
-
allQuery.size = 0;
|
|
1480
|
-
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1481
|
-
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1482
|
-
|
|
1483
|
-
// openTickets: mappingInfo.status: 'Open'
|
|
1484
|
-
let openTickets = 0;
|
|
1485
|
-
|
|
1486
|
-
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1487
|
-
otQ.size = 0;
|
|
1488
|
-
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1489
|
-
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1490
|
-
// logger.info( { msd: '..............2', openResp } );
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1494
|
-
let openInfraIssues = 0;
|
|
1495
|
-
|
|
1496
|
-
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1497
|
-
oiQ.size = 0;
|
|
1498
|
-
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1499
|
-
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1500
|
-
|
|
1501
|
-
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1502
|
-
let inprogress = 0;
|
|
1503
|
-
|
|
1504
|
-
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1505
|
-
ipQ.size = 0;
|
|
1506
|
-
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1507
|
-
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1508
|
-
|
|
1509
|
-
// closedTickets: mappingInfo.status: 'closed'
|
|
1510
|
-
let closedTickets = 0;
|
|
1511
|
-
|
|
1512
|
-
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1513
|
-
clQ.size = 0;
|
|
1514
|
-
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1515
|
-
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1516
|
-
// Average revisedPerc (for all tangoreview)
|
|
1517
|
-
let averageAccuracyOverAll = 0;
|
|
1518
|
-
|
|
1519
|
-
let avgQ = buildAggStoreQuery( baseStoreQuery );
|
|
1520
|
-
const avgResp = await getOpenSearchData( openSearch.footfallDirectory, avgQ );
|
|
1521
|
-
averageAccuracyOverAll = avgResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1522
|
-
|
|
1523
|
-
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
1524
|
-
let ticketAccuracyAbove = 0;
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
// For this, add a filter on revicedPerc >= 85
|
|
1528
|
-
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1529
|
-
{
|
|
1530
|
-
script: {
|
|
1531
|
-
script: {
|
|
1532
|
-
lang: 'painless',
|
|
1533
|
-
source: `
|
|
1534
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1535
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1536
|
-
`,
|
|
1537
|
-
params: { num: 85 },
|
|
1538
|
-
},
|
|
1539
|
-
},
|
|
1540
|
-
},
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
] );
|
|
1544
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1545
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1546
|
-
|
|
1547
|
-
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1548
|
-
let ticketAccuracyBelow = 0;
|
|
1549
|
-
|
|
1550
|
-
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1551
|
-
{
|
|
1552
|
-
script: {
|
|
1553
|
-
script: {
|
|
1554
|
-
lang: 'painless',
|
|
1555
|
-
source: `
|
|
1556
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1557
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1558
|
-
`,
|
|
1559
|
-
params: { num: 85 },
|
|
1560
|
-
},
|
|
1561
|
-
},
|
|
1562
|
-
},
|
|
1563
|
-
|
|
1564
|
-
] );
|
|
1565
|
-
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1566
|
-
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1567
|
-
|
|
1568
|
-
// Final result object
|
|
1569
|
-
result = {
|
|
1570
|
-
totalTickets,
|
|
1571
|
-
averageAccuracyOverAll: averageAccuracyOverAll+'%',
|
|
1572
|
-
openTickets,
|
|
1573
|
-
openInfraIssues,
|
|
1574
|
-
inprogress,
|
|
1575
|
-
closedTickets,
|
|
1576
|
-
ticketAccuracyAbove: ticketAccuracyAbove+'%',
|
|
1577
|
-
ticketAccuracyBelow: ticketAccuracyBelow+'%',
|
|
1578
|
-
};
|
|
1579
|
-
} else {
|
|
1580
|
-
result = req.user.role === 'superadmin' ?
|
|
1581
|
-
{
|
|
1582
|
-
totalTickets: 0,
|
|
1583
|
-
openTickets: 0,
|
|
1584
|
-
inprogress: 0,
|
|
1585
|
-
closedTickets: 0,
|
|
1586
|
-
dueToday: 0,
|
|
1587
|
-
Expired: 0,
|
|
1588
|
-
underTangoReview: 0,
|
|
1589
|
-
avgTicket: '0%',
|
|
1590
|
-
avgAccuracy: '0%',
|
|
1591
|
-
} :
|
|
1592
|
-
req.user.role === 'user' ? 'NA' :
|
|
1593
|
-
ticketsFeature ?
|
|
1594
|
-
{
|
|
1595
|
-
totalTickets: 0,
|
|
1596
|
-
openTickets: 0,
|
|
1597
|
-
inprogress: 0,
|
|
1598
|
-
closedTickets: 0,
|
|
1599
|
-
dueToday: 0,
|
|
1600
|
-
Expired: 0,
|
|
1601
|
-
avgTicket: '0%',
|
|
1602
|
-
avgAccuracy: '0%',
|
|
1603
|
-
} : 'NA';
|
|
1604
1972
|
}
|
|
1605
1973
|
|
|
1606
1974
|
return res.sendSuccess( { result: result } );
|
|
@@ -1615,7 +1983,7 @@ export async function ticketList1( req, res ) {
|
|
|
1615
1983
|
try {
|
|
1616
1984
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
1617
1985
|
const inputData = req.query;
|
|
1618
|
-
const limit = inputData.limit || 10;
|
|
1986
|
+
const limit =inputData?.isExport ? 10000: inputData.limit || 10;
|
|
1619
1987
|
const offset = inputData.offset == 0 ? 0 : ( inputData.offset - 1 ) * limit || 0;
|
|
1620
1988
|
const order = inputData?.sortOrder || -1;
|
|
1621
1989
|
|
|
@@ -1837,7 +2205,7 @@ export async function ticketList( req, res ) {
|
|
|
1837
2205
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
1838
2206
|
const inputData = req.query;
|
|
1839
2207
|
const userInfo = req.user;
|
|
1840
|
-
const limit = inputData?.limit || 10;
|
|
2208
|
+
const limit =inputData?.isExport? 10000: inputData?.limit || 10;
|
|
1841
2209
|
const offset = inputData.offset == 0 ? 0 : ( inputData.offset - 1 ) * limit || 0;
|
|
1842
2210
|
inputData.clientId = inputData?.clientId?.split( ',' ); // convert strig to array
|
|
1843
2211
|
|
|
@@ -2642,137 +3010,285 @@ export async function ticketList( req, res ) {
|
|
|
2642
3010
|
let temp = [];
|
|
2643
3011
|
if ( req.user.userType === 'tango' ) {
|
|
2644
3012
|
if ( inputData.tangoType === 'store' ) {
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
3013
|
+
if ( inputData?.isExport ) {
|
|
3014
|
+
const exportData = [];
|
|
3015
|
+
for ( let item of ticketListData ) {
|
|
3016
|
+
exportData.push( {
|
|
3017
|
+
|
|
3018
|
+
'Ticket ID': item?.ticketId,
|
|
3019
|
+
'store Name': item?.storeName,
|
|
3020
|
+
'store ID': item?.storeId,
|
|
3021
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt,
|
|
3022
|
+
'Issue Date': item?.dateString,
|
|
3023
|
+
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate,
|
|
3024
|
+
'Actual FF': item?.footfallCount,
|
|
3025
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3026
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3027
|
+
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3028
|
+
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3029
|
+
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
2660
3030
|
|
|
2661
|
-
|
|
3031
|
+
} );
|
|
3032
|
+
}
|
|
3033
|
+
return await download( exportData, res );
|
|
3034
|
+
} else {
|
|
3035
|
+
for ( let item of ticketListData ) {
|
|
3036
|
+
temp.push( {
|
|
3037
|
+
|
|
3038
|
+
ticketId: item?.ticketId,
|
|
3039
|
+
storeId: item?.storeId,
|
|
3040
|
+
storeName: item?.storeName,
|
|
3041
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt,
|
|
3042
|
+
issueDate: item?.dateString,
|
|
3043
|
+
dueDate: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate,
|
|
3044
|
+
footfall: item?.footfallCount,
|
|
3045
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3046
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3047
|
+
approverRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3048
|
+
tangoRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3049
|
+
status: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3050
|
+
|
|
3051
|
+
} );
|
|
3052
|
+
}
|
|
2662
3053
|
}
|
|
2663
3054
|
} else {
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
3055
|
+
if ( inputData?.isExport ) {
|
|
3056
|
+
const exportData = [];
|
|
3057
|
+
for ( let item of ticketListData ) {
|
|
3058
|
+
exportData.push( {
|
|
3059
|
+
|
|
3060
|
+
'Ticket ID': item?.ticketId,
|
|
3061
|
+
'Store Name': item?.storeName,
|
|
3062
|
+
'Store ID': item?.storeId,
|
|
3063
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.createdAt,
|
|
3064
|
+
'Issue Date': item?.dateString,
|
|
3065
|
+
'Ticket Type': item?.type,
|
|
3066
|
+
'Actual FF': item?.footfallCount,
|
|
3067
|
+
// Use the dueDate from the last mappingInfo item whose type is NOT 'finalRevisoon'
|
|
3068
|
+
'Due Date': ( () => {
|
|
3069
|
+
if ( Array.isArray( item?.mappingInfo ) ) {
|
|
3070
|
+
const filtered = item.mappingInfo.filter( ( f ) => f.dueDate && f.type !== 'finalRevisoon' );
|
|
3071
|
+
return filtered.length > 0 ? filtered[filtered.length - 1].dueDate : '';
|
|
3072
|
+
}
|
|
3073
|
+
return '';
|
|
3074
|
+
} )(),
|
|
3075
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3076
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3077
|
+
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3078
|
+
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3079
|
+
'Ticket Status': item?.status,
|
|
3080
|
+
'Tango Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
2682
3081
|
|
|
2683
|
-
|
|
3082
|
+
} );
|
|
3083
|
+
}
|
|
3084
|
+
return await download( exportData, res );
|
|
3085
|
+
} else {
|
|
3086
|
+
for ( let item of ticketListData ) {
|
|
3087
|
+
temp.push( {
|
|
3088
|
+
|
|
3089
|
+
ticketId: item?.ticketId,
|
|
3090
|
+
storeId: item?.storeId,
|
|
3091
|
+
storeName: item?.storeName,
|
|
3092
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.createdAt,
|
|
3093
|
+
issueDate: item?.dateString,
|
|
3094
|
+
footfall: item?.footfallCount,
|
|
3095
|
+
dueDate: ( () => {
|
|
3096
|
+
if ( Array.isArray( item?.mappingInfo ) ) {
|
|
3097
|
+
const filtered = item.mappingInfo.filter( ( f ) => f.dueDate && f.type !== 'finalRevisoon' );
|
|
3098
|
+
return filtered.length > 0 ? filtered[filtered.length - 1].dueDate : '';
|
|
3099
|
+
}
|
|
3100
|
+
return '';
|
|
3101
|
+
} )(),
|
|
3102
|
+
type: item?.type || 'store',
|
|
3103
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3104
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3105
|
+
approverRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3106
|
+
tangoRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3107
|
+
status: item?.status,
|
|
3108
|
+
tangoStatus: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3109
|
+
|
|
3110
|
+
} );
|
|
3111
|
+
}
|
|
2684
3112
|
}
|
|
2685
3113
|
}
|
|
2686
3114
|
} else {
|
|
2687
3115
|
if ( inputData?.permissionType === 'approve' ) {
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
approvedBy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
3116
|
+
if ( inputData.exportData ) {
|
|
3117
|
+
const exportData = [];
|
|
3118
|
+
for ( let item of ticketListData ) {
|
|
3119
|
+
exportData.push( {
|
|
3120
|
+
|
|
3121
|
+
'Ticket ID': item?.ticketId,
|
|
3122
|
+
'Store Name': item?.storeName,
|
|
3123
|
+
'Store ID': item?.storeId,
|
|
3124
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3125
|
+
'Issue Date': item?.dateString,
|
|
3126
|
+
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate,
|
|
3127
|
+
'Actual FF': item?.footfallCount,
|
|
3128
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3129
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3130
|
+
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3131
|
+
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3132
|
+
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.status || '--',
|
|
3133
|
+
'Tango Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3134
|
+
'Approved by': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
2708
3135
|
|
|
2709
|
-
|
|
3136
|
+
} );
|
|
3137
|
+
}
|
|
3138
|
+
return await download( exportData, res );
|
|
3139
|
+
} else {
|
|
3140
|
+
for ( let item of ticketListData ) {
|
|
3141
|
+
temp.push( {
|
|
3142
|
+
|
|
3143
|
+
ticketId: item?.ticketId,
|
|
3144
|
+
storeId: item?.storeId,
|
|
3145
|
+
storeName: item?.storeName,
|
|
3146
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3147
|
+
issueDate: item?.dateString,
|
|
3148
|
+
dueDate: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate,
|
|
3149
|
+
footfall: item?.footfallCount,
|
|
3150
|
+
type: item.type || 'store',
|
|
3151
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3152
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3153
|
+
approverRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3154
|
+
tangoRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3155
|
+
status: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.status || '--',
|
|
3156
|
+
tangoStatus: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3157
|
+
approvedBy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
3158
|
+
|
|
3159
|
+
} );
|
|
3160
|
+
}
|
|
2710
3161
|
}
|
|
2711
3162
|
} else if ( inputData?.permissionType === 'review' ) {
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
3163
|
+
if ( inputData?.isExport ) {
|
|
3164
|
+
const exportData = [];
|
|
3165
|
+
for ( let item of ticketListData ) {
|
|
3166
|
+
exportData.push( {
|
|
3167
|
+
|
|
3168
|
+
'Ticket ID': item?.ticketId,
|
|
3169
|
+
'Store Name': item?.storeName,
|
|
3170
|
+
'Store ID': item?.storeId,
|
|
3171
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3172
|
+
'Issue Date': item?.dateString,
|
|
3173
|
+
'Actual FF': item?.footfallCount,
|
|
3174
|
+
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate,
|
|
3175
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3176
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3177
|
+
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
3178
|
+
'Reviewed by': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdByEmail || '--',
|
|
2728
3179
|
|
|
2729
|
-
|
|
3180
|
+
} );
|
|
3181
|
+
}
|
|
3182
|
+
return await download( exportData, res );
|
|
3183
|
+
} else {
|
|
3184
|
+
for ( let item of ticketListData ) {
|
|
3185
|
+
temp.push( {
|
|
3186
|
+
|
|
3187
|
+
ticketId: item?.ticketId,
|
|
3188
|
+
storeId: item?.storeId,
|
|
3189
|
+
storeName: item?.storeName,
|
|
3190
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3191
|
+
issueDate: item?.dateString,
|
|
3192
|
+
footfall: item?.footfallCount,
|
|
3193
|
+
dueDate: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate,
|
|
3194
|
+
type: item.type || 'store',
|
|
3195
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3196
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3197
|
+
status: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
3198
|
+
ReviewedBy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdByEmail || '--',
|
|
3199
|
+
|
|
3200
|
+
} );
|
|
3201
|
+
}
|
|
2730
3202
|
}
|
|
2731
3203
|
} else if ( req.user.role === 'user' ) {
|
|
2732
3204
|
temp = [];
|
|
2733
3205
|
} else if ( ticketsFeature ) {
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
3206
|
+
if ( inputData?.isExport ) {
|
|
3207
|
+
const exportData = [];
|
|
3208
|
+
for ( let item of ticketListData ) {
|
|
3209
|
+
exportData.push( {
|
|
3210
|
+
|
|
3211
|
+
'Ticket ID': item?.ticketId,
|
|
3212
|
+
'Store ID': item?.storeId,
|
|
3213
|
+
'Store Name': item?.storeName,
|
|
3214
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3215
|
+
'Issue Date': item?.dateString,
|
|
3216
|
+
'Actual FF': item?.footfallCount,
|
|
3217
|
+
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate,
|
|
3218
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3219
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3220
|
+
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
3221
|
+
'Reviewed by': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdByEmail || '--',
|
|
2750
3222
|
|
|
2751
|
-
|
|
3223
|
+
} );
|
|
3224
|
+
}
|
|
3225
|
+
return await download( exportData, res );
|
|
3226
|
+
} else {
|
|
3227
|
+
for ( let item of ticketListData ) {
|
|
3228
|
+
temp.push( {
|
|
3229
|
+
|
|
3230
|
+
ticketId: item?.ticketId,
|
|
3231
|
+
storeId: item?.storeId,
|
|
3232
|
+
storeName: item?.storeName,
|
|
3233
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3234
|
+
issueDate: item?.dateString,
|
|
3235
|
+
footfall: item?.footfallCount,
|
|
3236
|
+
dueDate: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate,
|
|
3237
|
+
type: item.type || 'store',
|
|
3238
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3239
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3240
|
+
status: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
3241
|
+
ReviewedBy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdByEmail || '--',
|
|
3242
|
+
|
|
3243
|
+
} );
|
|
3244
|
+
}
|
|
2752
3245
|
}
|
|
2753
3246
|
} else if ( ticketsApproveFeature ) {
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
approvedBy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
3247
|
+
if ( inputData.isExport ) {
|
|
3248
|
+
const exportData = [];
|
|
3249
|
+
for ( let item of ticketListData ) {
|
|
3250
|
+
exportData.push( {
|
|
3251
|
+
|
|
3252
|
+
'Ticket ID': item?.ticketId,
|
|
3253
|
+
'Store Name': item?.storeName,
|
|
3254
|
+
'Store ID': item?.storeId,
|
|
3255
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3256
|
+
'Issue Date': item?.dateString,
|
|
3257
|
+
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate,
|
|
3258
|
+
'Actual FF': item?.footfallCount,
|
|
3259
|
+
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3260
|
+
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3261
|
+
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3262
|
+
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3263
|
+
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.status || '--',
|
|
3264
|
+
'Tango Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3265
|
+
'Approved by': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
2774
3266
|
|
|
2775
|
-
|
|
3267
|
+
} );
|
|
3268
|
+
}
|
|
3269
|
+
return await download( exportData, res );
|
|
3270
|
+
} else {
|
|
3271
|
+
for ( let item of ticketListData ) {
|
|
3272
|
+
temp.push( {
|
|
3273
|
+
|
|
3274
|
+
ticketId: item?.ticketId,
|
|
3275
|
+
storeId: item?.storeId,
|
|
3276
|
+
storeName: item?.storeName,
|
|
3277
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3278
|
+
issueDate: item?.dateString,
|
|
3279
|
+
dueDate: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate,
|
|
3280
|
+
footfall: item?.footfallCount,
|
|
3281
|
+
type: item.type || 'store',
|
|
3282
|
+
storeRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3283
|
+
reviewerRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3284
|
+
approverRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3285
|
+
tangoRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3286
|
+
status: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.status || '--',
|
|
3287
|
+
tangoStatus: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3288
|
+
approvedBy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdByEmail || '--',
|
|
3289
|
+
|
|
3290
|
+
} );
|
|
3291
|
+
}
|
|
2776
3292
|
}
|
|
2777
3293
|
} else {
|
|
2778
3294
|
temp = [];
|
|
@@ -4038,6 +4554,7 @@ export async function openTicketList( req, res ) {
|
|
|
4038
4554
|
},
|
|
4039
4555
|
];
|
|
4040
4556
|
|
|
4557
|
+
|
|
4041
4558
|
const openSearchQuery = {
|
|
4042
4559
|
size: 10000,
|
|
4043
4560
|
query: {
|
|
@@ -4047,6 +4564,31 @@ export async function openTicketList( req, res ) {
|
|
|
4047
4564
|
},
|
|
4048
4565
|
_source: [ 'ticketId', 'storeName', 'storeId', 'dateString', 'revicedFootfall', 'footfallCount', 'revicedPerc', 'type' ],
|
|
4049
4566
|
};
|
|
4567
|
+
|
|
4568
|
+
if ( inputData.searchValue && inputData.searchValue !== '' ) {
|
|
4569
|
+
openSearchQuery.query.bool['should'] = [];
|
|
4570
|
+
openSearchQuery.query.bool.should = [
|
|
4571
|
+
|
|
4572
|
+
{
|
|
4573
|
+
'wildcard': {
|
|
4574
|
+
'storeName.keyword': {
|
|
4575
|
+
'value': `*${inputData.searchValue}*`,
|
|
4576
|
+
},
|
|
4577
|
+
},
|
|
4578
|
+
},
|
|
4579
|
+
{
|
|
4580
|
+
'wildcard': {
|
|
4581
|
+
'ticketId.keyword': {
|
|
4582
|
+
'value': `*${inputData.searchValue}*`,
|
|
4583
|
+
},
|
|
4584
|
+
},
|
|
4585
|
+
},
|
|
4586
|
+
|
|
4587
|
+
|
|
4588
|
+
];
|
|
4589
|
+
openSearchQuery.query.bool['minimum_should_match'] = 1;
|
|
4590
|
+
}
|
|
4591
|
+
|
|
4050
4592
|
// INSERT_YOUR_CODE
|
|
4051
4593
|
// Add sorting by revicedPerc descending (highest revised accuracy first)
|
|
4052
4594
|
openSearchQuery.sort = [
|