tango-app-api-infra 3.9.5-vms.90 → 3.9.5-vms.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -151,6 +151,7 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
151
151
|
query: {
|
|
152
152
|
bool: {
|
|
153
153
|
must: [
|
|
154
|
+
|
|
154
155
|
{
|
|
155
156
|
term: {
|
|
156
157
|
'storeId.keyword': inputData.storeId,
|
|
@@ -177,6 +178,11 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
177
178
|
query: {
|
|
178
179
|
bool: {
|
|
179
180
|
must: [
|
|
181
|
+
{
|
|
182
|
+
term: {
|
|
183
|
+
'type.keyword': 'store',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
180
186
|
{
|
|
181
187
|
term: {
|
|
182
188
|
'storeId.keyword': inputData.storeId,
|
|
@@ -505,6 +511,12 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
505
511
|
query: {
|
|
506
512
|
bool: {
|
|
507
513
|
must: [
|
|
514
|
+
{
|
|
515
|
+
term: {
|
|
516
|
+
'type.keyword': 'store',
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
|
|
508
520
|
{
|
|
509
521
|
term: {
|
|
510
522
|
'storeId.keyword': inputData.storeId,
|
|
@@ -572,36 +584,17 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
572
584
|
subComments: inputData?.subComments ||'',
|
|
573
585
|
} ) );
|
|
574
586
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
// return {
|
|
580
|
-
// ...item,
|
|
581
|
-
// status: 'Closed',
|
|
582
|
-
// };
|
|
583
|
-
// } );
|
|
584
|
-
// }
|
|
585
|
-
|
|
586
|
-
record.mappingInfo.push(
|
|
587
|
-
{
|
|
588
|
-
type: 'finalRevision',
|
|
589
|
-
mode: 'web',
|
|
590
|
-
revicedFootfall: temp?.[0]?.revicedFootfall,
|
|
591
|
-
revicedPerc: temp?.[0].revicedPerc,
|
|
592
|
-
count: temp?.[0].count,
|
|
593
|
-
revisedDetail: temp?.[0]?.revisedDetail,
|
|
594
|
-
status: 'Closed',
|
|
595
|
-
createdByEmail: req?.user?.email,
|
|
596
|
-
createdByUserName: req?.user?.userName,
|
|
597
|
-
createdByRole: req?.user?.role,
|
|
598
|
-
createdAt: new Date(),
|
|
587
|
+
const temp2 = record.mappingInfo
|
|
588
|
+
.filter( ( item ) => item.type === 'finalRevision' )
|
|
589
|
+
.map( ( item ) => ( {
|
|
590
|
+
...item,
|
|
599
591
|
comments: inputData?.comments || '',
|
|
600
|
-
subComments: inputData?.subComments ||
|
|
601
|
-
}
|
|
602
|
-
);
|
|
603
|
-
}
|
|
592
|
+
subComments: inputData?.subComments ||'',
|
|
593
|
+
} ) );
|
|
604
594
|
|
|
595
|
+
record.mappingInfo = [ ...ticketData?.[0]?._source?.mappingInfo.slice( 0, -2 ),
|
|
596
|
+
...temp, ...temp2 ];
|
|
597
|
+
}
|
|
605
598
|
|
|
606
599
|
// return;
|
|
607
600
|
|
|
@@ -610,84 +603,6 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
610
603
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
611
604
|
|
|
612
605
|
if ( insertResult && ( insertResult.statusCode === 201 || insertResult.statusCode === 200 ) ) {
|
|
613
|
-
const query = {
|
|
614
|
-
storeId: inputData?.storeId,
|
|
615
|
-
isVideoStream: true,
|
|
616
|
-
};
|
|
617
|
-
const getStoreType = await countDocumnetsCamera( query );
|
|
618
|
-
const revopInfoQuery = {
|
|
619
|
-
size: 10000,
|
|
620
|
-
query: {
|
|
621
|
-
bool: {
|
|
622
|
-
must: [
|
|
623
|
-
{
|
|
624
|
-
term: {
|
|
625
|
-
'storeId.keyword': inputData.storeId,
|
|
626
|
-
},
|
|
627
|
-
},
|
|
628
|
-
{
|
|
629
|
-
term: {
|
|
630
|
-
'dateString': inputData.dateString,
|
|
631
|
-
},
|
|
632
|
-
},
|
|
633
|
-
{
|
|
634
|
-
term: {
|
|
635
|
-
'isParent': false,
|
|
636
|
-
},
|
|
637
|
-
},
|
|
638
|
-
{
|
|
639
|
-
term: {
|
|
640
|
-
isChecked: true,
|
|
641
|
-
},
|
|
642
|
-
},
|
|
643
|
-
],
|
|
644
|
-
},
|
|
645
|
-
},
|
|
646
|
-
_source: [ 'tempId' ],
|
|
647
|
-
|
|
648
|
-
};
|
|
649
|
-
const revopInfo = await getOpenSearchData( openSearch.revop, revopInfoQuery );
|
|
650
|
-
// Get all tempIds from revopInfo response
|
|
651
|
-
const tempIds = revopInfo?.body?.hits?.hits?.map( ( hit ) => hit?._source?.tempId ).filter( Boolean ) || [];
|
|
652
|
-
// Prepare management eyeZone query based on storeId and dateString
|
|
653
|
-
const managerEyeZoneQuery = {
|
|
654
|
-
size: 1,
|
|
655
|
-
query: {
|
|
656
|
-
bool: {
|
|
657
|
-
must: [
|
|
658
|
-
{
|
|
659
|
-
term: {
|
|
660
|
-
'storeId.keyword': inputData.storeId,
|
|
661
|
-
},
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
term: {
|
|
665
|
-
'storeDate': inputData.dateString,
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
],
|
|
669
|
-
},
|
|
670
|
-
},
|
|
671
|
-
_source: [ 'originalToTrackerCustomerMapping' ],
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
// Query the managerEyeZone index for the matching document
|
|
675
|
-
const managerEyeZoneResp = await getOpenSearchData( openSearch.managerEyeZone, managerEyeZoneQuery );
|
|
676
|
-
const managerEyeZoneHit = managerEyeZoneResp?.body?.hits?.hits?.[0]?._source;
|
|
677
|
-
// Extract originalToTrackerCustomerMapping if it exists
|
|
678
|
-
const mapping =
|
|
679
|
-
managerEyeZoneHit && managerEyeZoneHit.originalToTrackerCustomerMapping ?
|
|
680
|
-
managerEyeZoneHit.originalToTrackerCustomerMapping :
|
|
681
|
-
{};
|
|
682
|
-
|
|
683
|
-
// Find tempIds that exist in both revopInfo results and manager mapping
|
|
684
|
-
const temp = [];
|
|
685
|
-
tempIds.filter( ( tid ) => mapping[tid] !== null ? temp.push( { tempId: mapping[tid] } ) :'' );
|
|
686
|
-
const isSendMessge = await sendSqsMessage( inputData, temp, getStoreType, inputData.storeId );
|
|
687
|
-
if ( isSendMessge == true ) {
|
|
688
|
-
logger.info( '....1' );
|
|
689
|
-
}
|
|
690
|
-
|
|
691
606
|
return res.sendSuccess( 'Ticket closed successfully' );
|
|
692
607
|
} else {
|
|
693
608
|
return res.sendError( 'Internal Server Error', 500 );
|
|
@@ -1511,6 +1426,220 @@ export async function ticketSummary( req, res ) {
|
|
|
1511
1426
|
avgTicket: ticketPercentageAvg+'%',
|
|
1512
1427
|
avgAccuracy: ticketAccuracy+'%',
|
|
1513
1428
|
};
|
|
1429
|
+
} else if ( !ticketsFeature && ticketsApproveFeature ) {
|
|
1430
|
+
const storeQuery = {
|
|
1431
|
+
size: 0,
|
|
1432
|
+
query: {
|
|
1433
|
+
bool: {
|
|
1434
|
+
must: [
|
|
1435
|
+
{
|
|
1436
|
+
'range': {
|
|
1437
|
+
'dateString': {
|
|
1438
|
+
'gte': inputData?.fromDate,
|
|
1439
|
+
'lte': inputData?.toDate,
|
|
1440
|
+
'format': 'yyyy-MM-dd',
|
|
1441
|
+
},
|
|
1442
|
+
},
|
|
1443
|
+
},
|
|
1444
|
+
{
|
|
1445
|
+
terms: {
|
|
1446
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1447
|
+
inputData.clientId :
|
|
1448
|
+
[ inputData.clientId ],
|
|
1449
|
+
},
|
|
1450
|
+
|
|
1451
|
+
},
|
|
1452
|
+
{
|
|
1453
|
+
nested: {
|
|
1454
|
+
path: 'mappingInfo',
|
|
1455
|
+
query: {
|
|
1456
|
+
bool: {
|
|
1457
|
+
must: [
|
|
1458
|
+
{
|
|
1459
|
+
term: {
|
|
1460
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1461
|
+
},
|
|
1462
|
+
},
|
|
1463
|
+
],
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
},
|
|
1468
|
+
|
|
1469
|
+
],
|
|
1470
|
+
},
|
|
1471
|
+
},
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1475
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1476
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1477
|
+
// Remove any previous mappingInfo.status term
|
|
1478
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1479
|
+
if ( nested ) {
|
|
1480
|
+
// filter out all mappingInfo.status
|
|
1481
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1482
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1483
|
+
} );
|
|
1484
|
+
// add desired status
|
|
1485
|
+
nested.nested.query.bool.must.push( {
|
|
1486
|
+
term: {
|
|
1487
|
+
'mappingInfo.status': statusValue,
|
|
1488
|
+
},
|
|
1489
|
+
} );
|
|
1490
|
+
}
|
|
1491
|
+
return q;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1495
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1496
|
+
|
|
1497
|
+
// locate nested section
|
|
1498
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1499
|
+
|
|
1500
|
+
if ( nested ) {
|
|
1501
|
+
// remove old status filters
|
|
1502
|
+
nested.nested.query.bool.must =
|
|
1503
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1504
|
+
|
|
1505
|
+
// add new filters
|
|
1506
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
return {
|
|
1510
|
+
...q,
|
|
1511
|
+
size: 0,
|
|
1512
|
+
aggs: {
|
|
1513
|
+
avg_value: {
|
|
1514
|
+
avg: 'mappingInfp.reviced',
|
|
1515
|
+
},
|
|
1516
|
+
},
|
|
1517
|
+
};
|
|
1518
|
+
};
|
|
1519
|
+
|
|
1520
|
+
|
|
1521
|
+
// Get OpenSearch connection
|
|
1522
|
+
|
|
1523
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1524
|
+
|
|
1525
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1526
|
+
let totalTickets = 0;
|
|
1527
|
+
|
|
1528
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1529
|
+
|
|
1530
|
+
allQuery.size = 0;
|
|
1531
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1532
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1533
|
+
|
|
1534
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1535
|
+
let openTickets = 0;
|
|
1536
|
+
|
|
1537
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1538
|
+
otQ.size = 0;
|
|
1539
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1540
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1541
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1542
|
+
|
|
1543
|
+
|
|
1544
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1545
|
+
let inprogress = 0;
|
|
1546
|
+
|
|
1547
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1548
|
+
ipQ.size = 0;
|
|
1549
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1550
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1551
|
+
|
|
1552
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1553
|
+
let closedTickets = 0;
|
|
1554
|
+
|
|
1555
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1556
|
+
clQ.size = 0;
|
|
1557
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1558
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1559
|
+
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1560
|
+
let dueToday = 0;
|
|
1561
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1562
|
+
|
|
1563
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1564
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1565
|
+
// Locate nested mappingInfo query
|
|
1566
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1567
|
+
if ( nestedDue ) {
|
|
1568
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1569
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1570
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1571
|
+
);
|
|
1572
|
+
// Add new dueDate filter
|
|
1573
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1574
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1575
|
+
} );
|
|
1576
|
+
}
|
|
1577
|
+
dueTodayQuery.size = 0;
|
|
1578
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1579
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1580
|
+
|
|
1581
|
+
|
|
1582
|
+
// filter expired Tickets
|
|
1583
|
+
let expiredTickets = 0;
|
|
1584
|
+
|
|
1585
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1586
|
+
eQ.size = 0;
|
|
1587
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1588
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1589
|
+
|
|
1590
|
+
// filter under tango review
|
|
1591
|
+
|
|
1592
|
+
let undertangoTickets = 0;
|
|
1593
|
+
|
|
1594
|
+
let utrQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1595
|
+
utrQ.size = 0;
|
|
1596
|
+
const utrResp = await getOpenSearchData( openSearch.footfallDirectory, utrQ );
|
|
1597
|
+
undertangoTickets = utrResp?.body?.hits?.total?.value || 0;
|
|
1598
|
+
|
|
1599
|
+
let ticketPercentageAvg =0;
|
|
1600
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1601
|
+
avgTicketPercentageQuery.size = 0;
|
|
1602
|
+
avgTicketPercentageQuery.aggs = {
|
|
1603
|
+
avg_ticket_percentage: {
|
|
1604
|
+
avg: {
|
|
1605
|
+
script: {
|
|
1606
|
+
source: `
|
|
1607
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1608
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1609
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1610
|
+
} else {
|
|
1611
|
+
return null;
|
|
1612
|
+
}
|
|
1613
|
+
`,
|
|
1614
|
+
lang: 'painless',
|
|
1615
|
+
},
|
|
1616
|
+
},
|
|
1617
|
+
},
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1621
|
+
|
|
1622
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1623
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1624
|
+
let ticketAccuracy = 0;
|
|
1625
|
+
|
|
1626
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1627
|
+
logger.info( { belowQ } );
|
|
1628
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1629
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1630
|
+
logger.info( { accuracyResp } );
|
|
1631
|
+
// Final result object
|
|
1632
|
+
result = {
|
|
1633
|
+
totalTickets,
|
|
1634
|
+
openTickets,
|
|
1635
|
+
inprogress,
|
|
1636
|
+
closedTickets,
|
|
1637
|
+
dueToday: dueToday,
|
|
1638
|
+
Expired: expiredTickets,
|
|
1639
|
+
underTangoReview: undertangoTickets,
|
|
1640
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1641
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1642
|
+
};
|
|
1514
1643
|
} else if ( ticketsFeature && ticketsApproveFeature ) {
|
|
1515
1644
|
if ( inputData?.permissionType === 'review' ) {
|
|
1516
1645
|
const storeQuery = {
|
|
@@ -2212,6 +2341,20 @@ export async function ticketList( req, res ) {
|
|
|
2212
2341
|
},
|
|
2213
2342
|
};
|
|
2214
2343
|
|
|
2344
|
+
if ( req?.user?.userType !== 'tango', req?.user?.role !== 'superadmin' ) {
|
|
2345
|
+
if ( req?.body?.assignedStores?.length > 0 ) {
|
|
2346
|
+
searchQuery.query.bool.must.push( {
|
|
2347
|
+
terms: {
|
|
2348
|
+
'storeId.keyword': Array.isArray( req?.body?.assignedStores ) ?
|
|
2349
|
+
req?.body?.assignedStores :
|
|
2350
|
+
[ req?.body?.assignedStores ],
|
|
2351
|
+
},
|
|
2352
|
+
} );
|
|
2353
|
+
} else {
|
|
2354
|
+
return res.sendError( 'no data', 204 );
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2215
2358
|
if ( inputData.sortBy ) {
|
|
2216
2359
|
let sortOrder = inputData.sortOrder === 1 ? 'asc' : 'desc';
|
|
2217
2360
|
|
|
@@ -2423,6 +2566,28 @@ export async function ticketList( req, res ) {
|
|
|
2423
2566
|
},
|
|
2424
2567
|
},
|
|
2425
2568
|
} );
|
|
2569
|
+
} else if ( !ticketsFeature && ticketsApproveFeature ) {
|
|
2570
|
+
searchQuery.query.bool.must.push( {
|
|
2571
|
+
nested: {
|
|
2572
|
+
path: 'mappingInfo',
|
|
2573
|
+
query: {
|
|
2574
|
+
bool: {
|
|
2575
|
+
must: [
|
|
2576
|
+
{
|
|
2577
|
+
term: {
|
|
2578
|
+
'mappingInfo.type': 'approve',
|
|
2579
|
+
},
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
terms: {
|
|
2583
|
+
'mappingInfo.status': inputData?.filterByStatus,
|
|
2584
|
+
},
|
|
2585
|
+
},
|
|
2586
|
+
],
|
|
2587
|
+
},
|
|
2588
|
+
},
|
|
2589
|
+
},
|
|
2590
|
+
} );
|
|
2426
2591
|
} else if ( ticketsFeature && ticketsApproveFeature ) {
|
|
2427
2592
|
switch ( inputData.permisisionType ) {
|
|
2428
2593
|
case 'review':
|
|
@@ -2992,9 +3157,18 @@ export async function ticketList( req, res ) {
|
|
|
2992
3157
|
'Ticket ID': item?.ticketId,
|
|
2993
3158
|
'store Name': item?.storeName,
|
|
2994
3159
|
'store ID': item?.storeId,
|
|
2995
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt,
|
|
2996
|
-
'Issue Date': item?.dateString,
|
|
2997
|
-
'Due Date':
|
|
3160
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3161
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3162
|
+
'Due Date': ( () => {
|
|
3163
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate;
|
|
3164
|
+
if ( dueDate ) {
|
|
3165
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3166
|
+
return 'Due Today';
|
|
3167
|
+
}
|
|
3168
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3169
|
+
}
|
|
3170
|
+
return '';
|
|
3171
|
+
} )(),
|
|
2998
3172
|
'Actual FF': item?.footfallCount,
|
|
2999
3173
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3000
3174
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
@@ -3011,20 +3185,29 @@ export async function ticketList( req, res ) {
|
|
|
3011
3185
|
for ( let item of ticketListData ) {
|
|
3012
3186
|
temp.push( {
|
|
3013
3187
|
|
|
3014
|
-
ticketId: item?.ticketId,
|
|
3015
|
-
storeId: item?.storeId,
|
|
3016
|
-
storeName: item?.storeName,
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3188
|
+
'ticketId': item?.ticketId,
|
|
3189
|
+
'storeId': item?.storeId,
|
|
3190
|
+
'storeName': item?.storeName,
|
|
3191
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3192
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3193
|
+
'Due Date': ( () => {
|
|
3194
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate;
|
|
3195
|
+
if ( dueDate ) {
|
|
3196
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3197
|
+
return 'Due Today';
|
|
3198
|
+
}
|
|
3199
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3200
|
+
}
|
|
3201
|
+
return '';
|
|
3202
|
+
} )(),
|
|
3203
|
+
'footfall': item?.footfallCount,
|
|
3204
|
+
'storeRevisedAccuracy': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3205
|
+
'reviewerRevisedAccuracy': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3206
|
+
'approverRevisedAccuracy': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3207
|
+
'tangoRevisedAccuracy': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3208
|
+
'status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3209
|
+
'comments': item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.comments || '--',
|
|
3210
|
+
'subComments': item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.subComments || '--',
|
|
3028
3211
|
|
|
3029
3212
|
} );
|
|
3030
3213
|
}
|
|
@@ -3033,29 +3216,50 @@ export async function ticketList( req, res ) {
|
|
|
3033
3216
|
if ( inputData?.isExport ) {
|
|
3034
3217
|
const exportData = [];
|
|
3035
3218
|
for ( let item of ticketListData ) {
|
|
3219
|
+
console.log( item );
|
|
3036
3220
|
exportData.push( {
|
|
3037
3221
|
|
|
3038
3222
|
'Ticket ID': item?.ticketId,
|
|
3039
3223
|
'Store Name': item?.storeName,
|
|
3040
3224
|
'Store ID': item?.storeId,
|
|
3041
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.createdAt,
|
|
3042
|
-
'Issue Date': item?.dateString,
|
|
3225
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3226
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3043
3227
|
'Ticket Type': item?.type,
|
|
3044
3228
|
'Actual FF': item?.footfallCount,
|
|
3045
|
-
// Use the dueDate from the last mappingInfo item whose type is NOT '
|
|
3229
|
+
// Use the dueDate from the last mappingInfo item whose type is NOT 'finalRevison'
|
|
3230
|
+
|
|
3046
3231
|
'Due Date': ( () => {
|
|
3047
3232
|
if ( Array.isArray( item?.mappingInfo ) ) {
|
|
3048
|
-
const filtered = item.mappingInfo.filter( ( f ) => f.dueDate && f.type !== '
|
|
3233
|
+
const filtered = item.mappingInfo.filter( ( f ) => f.dueDate && f.type !== 'finalRevison' );
|
|
3049
3234
|
return filtered.length > 0 ? filtered[filtered.length - 1].dueDate : '';
|
|
3050
3235
|
}
|
|
3051
3236
|
return '';
|
|
3052
3237
|
} )(),
|
|
3238
|
+
'Due Date (Formatted)': ( () => {
|
|
3239
|
+
if ( Array.isArray( item?.mappingInfo ) ) {
|
|
3240
|
+
// Find last mappingInfo whose type is NOT 'finalRevison'
|
|
3241
|
+
const filtered = item.mappingInfo.filter(
|
|
3242
|
+
( f ) => f.dueDate && f.type !== 'finalRevison',
|
|
3243
|
+
);
|
|
3244
|
+
if ( filtered.length > 0 ) {
|
|
3245
|
+
const lastDueDate = filtered[filtered.length - 1].dueDate;
|
|
3246
|
+
if ( lastDueDate ) {
|
|
3247
|
+
if ( dayjs( lastDueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3248
|
+
return 'Due Today';
|
|
3249
|
+
}
|
|
3250
|
+
return dayjs( lastDueDate ).format( 'DD MMM, YYYY' );
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
return '';
|
|
3255
|
+
} )(),
|
|
3256
|
+
|
|
3053
3257
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3054
3258
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3055
3259
|
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3056
3260
|
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3057
|
-
'Ticket Status': item?.status,
|
|
3058
|
-
'Tango Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3261
|
+
'Ticket Status': item?.type === 'store'? item?.status : '',
|
|
3262
|
+
'Tango Status': item?.type === 'store'? item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--' : item.status,
|
|
3059
3263
|
|
|
3060
3264
|
} );
|
|
3061
3265
|
}
|
|
@@ -3067,12 +3271,12 @@ export async function ticketList( req, res ) {
|
|
|
3067
3271
|
ticketId: item?.ticketId,
|
|
3068
3272
|
storeId: item?.storeId,
|
|
3069
3273
|
storeName: item?.storeName,
|
|
3070
|
-
ticketRaised: item?.mappingInfo?.find( ( f ) => f
|
|
3274
|
+
ticketRaised: item?.mappingInfo?.find( ( f ) => f?.type === 'tagging' )?.createdAt,
|
|
3071
3275
|
issueDate: item?.dateString,
|
|
3072
3276
|
footfall: item?.footfallCount,
|
|
3073
3277
|
dueDate: ( () => {
|
|
3074
3278
|
if ( Array.isArray( item?.mappingInfo ) ) {
|
|
3075
|
-
const filtered = item.mappingInfo.filter( ( f ) => f
|
|
3279
|
+
const filtered = item.mappingInfo.filter( ( f ) => f?.dueDate && f?.type !== 'finalRevisoon' );
|
|
3076
3280
|
return filtered.length > 0 ? filtered[filtered.length - 1].dueDate : '';
|
|
3077
3281
|
}
|
|
3078
3282
|
return '';
|
|
@@ -3099,9 +3303,18 @@ export async function ticketList( req, res ) {
|
|
|
3099
3303
|
'Ticket ID': item?.ticketId,
|
|
3100
3304
|
'Store Name': item?.storeName,
|
|
3101
3305
|
'Store ID': item?.storeId,
|
|
3102
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3103
|
-
'Issue Date': item?.dateString,
|
|
3104
|
-
'Due Date':
|
|
3306
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3307
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3308
|
+
'Due Date': ( () => {
|
|
3309
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate;
|
|
3310
|
+
if ( dueDate ) {
|
|
3311
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3312
|
+
return 'Due Today';
|
|
3313
|
+
}
|
|
3314
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3315
|
+
}
|
|
3316
|
+
return '';
|
|
3317
|
+
} )(),
|
|
3105
3318
|
'Actual FF': item?.footfallCount,
|
|
3106
3319
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3107
3320
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
@@ -3146,10 +3359,19 @@ export async function ticketList( req, res ) {
|
|
|
3146
3359
|
'Ticket ID': item?.ticketId,
|
|
3147
3360
|
'Store Name': item?.storeName,
|
|
3148
3361
|
'Store ID': item?.storeId,
|
|
3149
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3150
|
-
'Issue Date': item?.dateString,
|
|
3362
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3363
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3364
|
+
'Due Date': ( () => {
|
|
3365
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate;
|
|
3366
|
+
if ( dueDate ) {
|
|
3367
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3368
|
+
return 'Due Today';
|
|
3369
|
+
}
|
|
3370
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3371
|
+
}
|
|
3372
|
+
return '';
|
|
3373
|
+
} )(),
|
|
3151
3374
|
'Actual FF': item?.footfallCount,
|
|
3152
|
-
'Due Date': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate,
|
|
3153
3375
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3154
3376
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3155
3377
|
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
@@ -3189,10 +3411,20 @@ export async function ticketList( req, res ) {
|
|
|
3189
3411
|
'Ticket ID': item?.ticketId,
|
|
3190
3412
|
'Store ID': item?.storeId,
|
|
3191
3413
|
'Store Name': item?.storeName,
|
|
3192
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt,
|
|
3193
|
-
'Issue Date': item?.dateString,
|
|
3414
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3415
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3416
|
+
'Due Date': ( () => {
|
|
3417
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.dueDate;
|
|
3418
|
+
if ( dueDate ) {
|
|
3419
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3420
|
+
return 'Due Today';
|
|
3421
|
+
}
|
|
3422
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3423
|
+
}
|
|
3424
|
+
return '';
|
|
3425
|
+
} )(),
|
|
3194
3426
|
'Actual FF': item?.footfallCount,
|
|
3195
|
-
|
|
3427
|
+
|
|
3196
3428
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3197
3429
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
3198
3430
|
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.status || '--',
|
|
@@ -3230,9 +3462,18 @@ export async function ticketList( req, res ) {
|
|
|
3230
3462
|
'Ticket ID': item?.ticketId,
|
|
3231
3463
|
'Store Name': item?.storeName,
|
|
3232
3464
|
'Store ID': item?.storeId,
|
|
3233
|
-
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt,
|
|
3234
|
-
'Issue Date': item?.dateString,
|
|
3235
|
-
'Due Date':
|
|
3465
|
+
'Ticket Raised': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt? dayjs( item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.createdAt ).format( 'DD MMM, YYYY' ) : '',
|
|
3466
|
+
'Issue Date': item?.dateString ? dayjs( item.dateString ).format( 'DD MMM, YYYY' ) : '',
|
|
3467
|
+
'Due Date': ( () => {
|
|
3468
|
+
const dueDate = item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.dueDate;
|
|
3469
|
+
if ( dueDate ) {
|
|
3470
|
+
if ( dayjs( dueDate ).isSame( dayjs(), 'day' ) ) {
|
|
3471
|
+
return 'Due Today';
|
|
3472
|
+
}
|
|
3473
|
+
return dayjs( dueDate ).format( 'DD MMM, YYYY' );
|
|
3474
|
+
}
|
|
3475
|
+
return '';
|
|
3476
|
+
} )(),
|
|
3236
3477
|
'Actual FF': item?.footfallCount,
|
|
3237
3478
|
'Store (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tagging' )?.revicedPerc || '--',
|
|
3238
3479
|
'Reviewer (%)': item?.mappingInfo?.find( ( f ) => f.type === 'review' )?.revicedPerc || '--',
|
|
@@ -3287,7 +3528,7 @@ export async function getTickets( req, res ) {
|
|
|
3287
3528
|
const inputData = req.query;
|
|
3288
3529
|
|
|
3289
3530
|
|
|
3290
|
-
let source = [ 'storeId', 'type', 'dateString', 'ticketName', 'revicedFootfall', 'revicedPerc', 'mappingInfo', 'footfallCount', 'employeeCount', 'houseKeepingCount', 'duplicateCount', 'junkCount', 'junkACCount', 'comments', 'employee', 'houseKeeping', 'junk', 'duplicateImages', 'ticketId', 'clientId', 'storeName', 'createdAt', 'updatedAt', 'userName', 'email', 'role', 'status', 'employeeStatus', 'houseKeepingStatus', 'duplicateStatus', 'junkStatus', 'houseKeepingACCount', 'houseKeepingCount', 'employeeCount', 'employeeACCount', 'duplicateCount', 'duplicateACCount', 'approverRole', 'approverUserName', 'approverEmail', 'type' ];
|
|
3531
|
+
let source = [ 'storeId', 'createdByEmail', 'type', 'dateString', 'ticketName', 'revicedFootfall', 'revicedPerc', 'mappingInfo', 'footfallCount', 'employeeCount', 'houseKeepingCount', 'duplicateCount', 'junkCount', 'junkACCount', 'comments', 'employee', 'houseKeeping', 'junk', 'duplicateImages', 'ticketId', 'clientId', 'storeName', 'createdAt', 'updatedAt', 'userName', 'email', 'role', 'status', 'employeeStatus', 'houseKeepingStatus', 'duplicateStatus', 'junkStatus', 'houseKeepingACCount', 'houseKeepingCount', 'employeeCount', 'employeeACCount', 'duplicateCount', 'duplicateACCount', 'approverRole', 'approverUserName', 'approverEmail', 'type' ];
|
|
3291
3532
|
let filter = [
|
|
3292
3533
|
|
|
3293
3534
|
{
|
|
@@ -3334,6 +3575,7 @@ export async function getTickets( req, res ) {
|
|
|
3334
3575
|
response.map( ( hit ) => {
|
|
3335
3576
|
const defaultData = {
|
|
3336
3577
|
storeId: hit._source.storeId,
|
|
3578
|
+
createdByEmail: hit?._source?.createdByEmail,
|
|
3337
3579
|
dateString: hit?._source?.dateString,
|
|
3338
3580
|
ticketName: hit?._source?.ticketName,
|
|
3339
3581
|
status: hit?._source?.status?.revicedFootfall,
|
|
@@ -4457,6 +4699,14 @@ async function extractTempIds( document ) {
|
|
|
4457
4699
|
export async function reviewerList( req, res ) {
|
|
4458
4700
|
try {
|
|
4459
4701
|
const inputData = req.query;
|
|
4702
|
+
|
|
4703
|
+
console.log( '🚀 ~ reviewerList ~ inputData.tangotype:', inputData.tangotype );
|
|
4704
|
+
if ( inputData.tangotype!=''&&inputData.tangotype==='internal' ) {
|
|
4705
|
+
const getUserlist = await findUser( { userType: 'tango' }, { userName: 1, email: 1, role: 1 } );
|
|
4706
|
+
return res.sendSuccess( getUserlist || [] );
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
|
|
4460
4710
|
// Build the query for users who have rolespermission with featureName "FootfallDirectory",
|
|
4461
4711
|
// and a module "Reviewer" where isAdd or isEdit is true.
|
|
4462
4712
|
const reviewerRoleQuery = {
|
|
@@ -515,6 +515,7 @@ export const downloadTicketsValid = {
|
|
|
515
515
|
|
|
516
516
|
export const reviewerListSchema = Joi.object().keys( {
|
|
517
517
|
clientId: Joi.string().required(),
|
|
518
|
+
tangotype: Joi.string().optional(),
|
|
518
519
|
type: Joi.string().required().allow( 'approve', 'review' ),
|
|
519
520
|
} );
|
|
520
521
|
|
|
@@ -15,7 +15,7 @@ footfallDirectoryRouter.post( '/tango-review-accuracy-ticket', isAllowedSessionH
|
|
|
15
15
|
|
|
16
16
|
footfallDirectoryRouter.get( '/ticket-summary', isAllowedSessionHandler, bulkValidate( ticketSummaryValid ), ticketSummary );
|
|
17
17
|
|
|
18
|
-
footfallDirectoryRouter.get( '/ticket-list', isAllowedSessionHandler, bulkValidate( ticketListValid ), ticketList );
|
|
18
|
+
footfallDirectoryRouter.get( '/ticket-list', isAllowedSessionHandler, bulkValidate( ticketListValid ), getAssinedStore, ticketList );
|
|
19
19
|
footfallDirectoryRouter.get( '/get-tickets', isAllowedSessionHandler, bulkValidate( getTicketsValid ), getTickets );
|
|
20
20
|
footfallDirectoryRouter.get( '/get-tagged-stores', isAllowedSessionHandler, bulkValidate( getTaggedStoresValid ), getAssinedStore, getClusters, getTaggedStores );
|
|
21
21
|
footfallDirectoryRouter.put( '/update-status', isAllowedSessionHandler, bulkValidate( updateStatusValid ), updateStatus );
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bulkUpdate, getOpenSearchCount, getOpenSearchData, insertWithId, logger, sendMessageToFIFOQueue, updateOpenSearchData } from 'tango-app-api-middleware';
|
|
1
|
+
import { bulkUpdate, getOpenSearchCount, getOpenSearchData, insertWithId, logger, sendMessageToFIFOQueue, updateOpenSearchData, getOpenSearchById } from 'tango-app-api-middleware';
|
|
2
2
|
import { aggregateCluster } from '../services/cluster.service.js';
|
|
3
3
|
import { findOneRevopDownload } from '../services/revopDownload.service.js';
|
|
4
4
|
import { findOneStore } from '../services/store.service.js';
|
|
@@ -957,13 +957,14 @@ export async function ticketReview( req, res, next ) {
|
|
|
957
957
|
// check the createtion permission from the user permission
|
|
958
958
|
const userInfo = req?.user;
|
|
959
959
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
960
|
+
logger.info( { ticketsFeature, userInfo } );
|
|
960
961
|
if ( !ticketsFeature ) {
|
|
961
962
|
return res.sendError( 'Forbidden to Reiew this Ticket', 403 );
|
|
962
963
|
}
|
|
963
964
|
|
|
964
965
|
// get store info by the storeId into mongo db
|
|
965
966
|
const getstoreName = await findOneStore( { storeId: inputData.storeId, status: 'active' }, { storeId: 1, storeName: 1, clientId: 1 } );
|
|
966
|
-
|
|
967
|
+
logger.info( { getstoreName } );
|
|
967
968
|
if ( !getstoreName || getstoreName == null ) {
|
|
968
969
|
return res.sendError( 'The store ID is either inActive or not found', 400 );
|
|
969
970
|
}
|
|
@@ -1074,6 +1075,8 @@ export async function ticketReview( req, res, next ) {
|
|
|
1074
1075
|
return res.sendError( 'The Client ID is either not configured or not found', 400 );
|
|
1075
1076
|
}
|
|
1076
1077
|
|
|
1078
|
+
logger.info( { config } );
|
|
1079
|
+
|
|
1077
1080
|
// Get taggingLimitation from config (check both possible paths)
|
|
1078
1081
|
const taggingLimitation = getConfig?.effectiveLimitation?.values;
|
|
1079
1082
|
// Initialize count object from taggingLimitation
|
|
@@ -1148,7 +1151,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1148
1151
|
|
|
1149
1152
|
const revopData = await getOpenSearchData( openSearch.revop, revopQuery );
|
|
1150
1153
|
const buckets = revopData?.body?.aggregations?.type_counts?.buckets || [];
|
|
1151
|
-
|
|
1154
|
+
logger.info( { revopData } );
|
|
1152
1155
|
// Map OpenSearch revopsType values to count object keys
|
|
1153
1156
|
buckets.forEach( ( bucket ) => {
|
|
1154
1157
|
const revopsType = bucket.key;
|
|
@@ -1181,6 +1184,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1181
1184
|
if ( footfallCount - revisedFootfall == 0 ) {
|
|
1182
1185
|
return res.sendError( 'Cannot review a ticket because footfall hasn’t changed', 400 );
|
|
1183
1186
|
}
|
|
1187
|
+
logger.info( { footfallCount, revisedFootfall } );
|
|
1184
1188
|
const taggingData = {
|
|
1185
1189
|
size: 10000,
|
|
1186
1190
|
query: {
|
|
@@ -1213,6 +1217,16 @@ export async function ticketReview( req, res, next ) {
|
|
|
1213
1217
|
query: {
|
|
1214
1218
|
bool: {
|
|
1215
1219
|
must: [
|
|
1220
|
+
{
|
|
1221
|
+
term: {
|
|
1222
|
+
'type.keyword': 'store',
|
|
1223
|
+
},
|
|
1224
|
+
},
|
|
1225
|
+
{
|
|
1226
|
+
term: {
|
|
1227
|
+
'type.keyword': 'store',
|
|
1228
|
+
},
|
|
1229
|
+
},
|
|
1216
1230
|
{
|
|
1217
1231
|
term: {
|
|
1218
1232
|
'storeId.keyword': inputData.storeId,
|
|
@@ -1233,6 +1247,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1233
1247
|
if ( !ticketData || ticketData?.length == 0 ) {
|
|
1234
1248
|
return res.sendError( 'You don’t have any tagged images right now', 400 );
|
|
1235
1249
|
}
|
|
1250
|
+
logger.info( { ticketData, mappingInfo: ticketData?.[0]?._source?.mappingInfo } );
|
|
1236
1251
|
const record = {
|
|
1237
1252
|
|
|
1238
1253
|
status: 'Reviewer-Closed',
|
|
@@ -1245,7 +1260,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1245
1260
|
// createdByRole: req?.user?.role,
|
|
1246
1261
|
|
|
1247
1262
|
};
|
|
1248
|
-
|
|
1263
|
+
logger.info( { record } );
|
|
1249
1264
|
if ( Array.isArray( record.mappingInfo ) ) {
|
|
1250
1265
|
const temp = record.mappingInfo
|
|
1251
1266
|
.filter( ( item ) => item.type === 'review' )
|
|
@@ -1287,7 +1302,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1287
1302
|
// Retrieve client footfallDirectoryConfigs revision
|
|
1288
1303
|
let isAutoCloseEnable = getConfig?.footfallDirectoryConfigs?.isAutoCloseEnable; ;
|
|
1289
1304
|
let autoCloseAccuracy = getConfig?.footfallDirectoryConfigs?.autoCloseAccuracy;
|
|
1290
|
-
|
|
1305
|
+
logger.info( { isAutoCloseEnable, autoCloseAccuracy } );
|
|
1291
1306
|
|
|
1292
1307
|
const getNumber = autoCloseAccuracy.split( '%' )[0];
|
|
1293
1308
|
let autoCloseAccuracyValue = parseFloat( ( autoCloseAccuracy || getNumber ).replace( '%', '' ) );
|
|
@@ -1366,13 +1381,14 @@ export async function ticketReview( req, res, next ) {
|
|
|
1366
1381
|
createdAt: new Date(),
|
|
1367
1382
|
},
|
|
1368
1383
|
);
|
|
1384
|
+
logger.info( { revisedPercentage } );
|
|
1369
1385
|
} else {
|
|
1370
1386
|
// If ticket is closed, do not proceed with revision mapping
|
|
1371
1387
|
let revisionArray = [];
|
|
1372
1388
|
|
|
1373
1389
|
|
|
1374
1390
|
revisionArray = getConfig?.footfallDirectoryConfigs?.revision || [];
|
|
1375
|
-
|
|
1391
|
+
logger.info( { revisionArray } );
|
|
1376
1392
|
|
|
1377
1393
|
// Default fallbacks
|
|
1378
1394
|
let revisionMapping = null;
|
|
@@ -1405,7 +1421,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1405
1421
|
}
|
|
1406
1422
|
}
|
|
1407
1423
|
}
|
|
1408
|
-
|
|
1424
|
+
logger.info( { record } );
|
|
1409
1425
|
// Insert appropriate mappingInfo blocks
|
|
1410
1426
|
if ( revisionMapping ) {
|
|
1411
1427
|
// If reviewer and checked
|
|
@@ -1422,7 +1438,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1422
1438
|
let checkreview = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'reviewer' && data.isChecked === true );
|
|
1423
1439
|
|
|
1424
1440
|
|
|
1425
|
-
if ( checkreview.length > 0 ) {
|
|
1441
|
+
if ( checkreview.length > 0&&record.status!='Reviewer-Closed' ) {
|
|
1426
1442
|
let userQuery = [
|
|
1427
1443
|
{
|
|
1428
1444
|
$match: {
|
|
@@ -1441,6 +1457,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1441
1457
|
let createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
1442
1458
|
let description = `Created on ${createdOn}`;
|
|
1443
1459
|
|
|
1460
|
+
|
|
1444
1461
|
let Data = {
|
|
1445
1462
|
'title': title,
|
|
1446
1463
|
'body': description,
|
|
@@ -1463,6 +1480,36 @@ export async function ticketReview( req, res, next ) {
|
|
|
1463
1480
|
}
|
|
1464
1481
|
|
|
1465
1482
|
const id = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
|
|
1483
|
+
console.log( '-----', record.status );
|
|
1484
|
+
if ( record.status==='Reviewer-Closed' ) {
|
|
1485
|
+
console.log( '🚀 ~ ticketReview ~ id:', id );
|
|
1486
|
+
let Ticket = await getOpenSearchById( openSearch.footfallDirectory, id );
|
|
1487
|
+
console.log( '🚀 ~ ticketReview ~ Ticket:', Ticket.body );
|
|
1488
|
+
if ( Ticket?.body?._source?.type==='store' ) {
|
|
1489
|
+
let findTagging = Ticket?.body?._source?.mappingInfo.filter( ( data ) => data.type==='tagging' );
|
|
1490
|
+
if ( findTagging?.length>0&&findTagging[0].createdByEmail!='' ) {
|
|
1491
|
+
let userData = await findOneUser( { email: findTagging[0]?.createdByEmail } );
|
|
1492
|
+
console.log( '🚀 ~ ticketReview ~ findTagging[0]?.createdByEmail:', findTagging[0]?.createdByEmail );
|
|
1493
|
+
let title = `Received response for the Footfall ticket raised.`;
|
|
1494
|
+
let createdOn = dayjs( Ticket?.body?._source?.dateString ).format( 'DD MMM YYYY' );
|
|
1495
|
+
let description = `Raised on ${createdOn}`;
|
|
1496
|
+
|
|
1497
|
+
let Data = {
|
|
1498
|
+
'title': title,
|
|
1499
|
+
'body': description,
|
|
1500
|
+
'type': 'closed',
|
|
1501
|
+
'date': Ticket?.body?._source?.dateString,
|
|
1502
|
+
'storeId': Ticket?.body?._source?.storeId,
|
|
1503
|
+
'clientId': Ticket?.body?._source?.clientId,
|
|
1504
|
+
'ticketId': Ticket?.body?._source?.ticketId,
|
|
1505
|
+
};
|
|
1506
|
+
if ( userData && userData.fcmToken ) {
|
|
1507
|
+
const fcmToken = userData.fcmToken;
|
|
1508
|
+
await sendPushNotification( title, description, fcmToken, Data );
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1466
1513
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
1467
1514
|
|
|
1468
1515
|
if ( insertResult && insertResult.statusCode === 201 || insertResult.statusCode === 200 ) {
|
|
@@ -1552,7 +1599,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1552
1599
|
} catch ( error ) {
|
|
1553
1600
|
const err = error.message || 'Internal Server Error';
|
|
1554
1601
|
logger.error( { error: err, funtion: 'ticketreview' } );
|
|
1555
|
-
return res.sendError(
|
|
1602
|
+
return res.sendError( error, 500 );
|
|
1556
1603
|
}
|
|
1557
1604
|
}
|
|
1558
1605
|
|
|
@@ -1834,6 +1881,11 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1834
1881
|
query: {
|
|
1835
1882
|
bool: {
|
|
1836
1883
|
must: [
|
|
1884
|
+
{
|
|
1885
|
+
term: {
|
|
1886
|
+
'type.keyword': 'store',
|
|
1887
|
+
},
|
|
1888
|
+
},
|
|
1837
1889
|
{
|
|
1838
1890
|
term: {
|
|
1839
1891
|
'storeId.keyword': inputData.storeId,
|
|
@@ -2136,6 +2188,37 @@ export async function ticketApprove( req, res, next ) {
|
|
|
2136
2188
|
}
|
|
2137
2189
|
|
|
2138
2190
|
const id = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
|
|
2191
|
+
console.log( '🚀 ~ ticketReview ~ id:', id );
|
|
2192
|
+
console.log( '🚀 ~ ticketReview ~ id:', id );
|
|
2193
|
+
console.log( '🚀 ~ ticketReview ~ id:', id );
|
|
2194
|
+
if ( record.status==='Approver-Closed' ) {
|
|
2195
|
+
let Ticket = await getOpenSearchById( openSearch.footfallDirectory, id );
|
|
2196
|
+
console.log( '🚀 ~ ticketApprove ~ Ticket:', Ticket?.body );
|
|
2197
|
+
if ( Ticket?.body?._source?.type==='store' ) {
|
|
2198
|
+
let findTagging = Ticket?.body?._source?.mappingInfo.filter( ( data ) => data.type==='tagging' );
|
|
2199
|
+
console.log( '🚀 ~ ticketApprove ~ findTagging[0].createdByEmail:', findTagging[0].createdByEmail );
|
|
2200
|
+
if ( findTagging?.length>0&&findTagging[0].createdByEmail!='' ) {
|
|
2201
|
+
let userData = await findOneUser( { email: findTagging[0]?.createdByEmail } );
|
|
2202
|
+
let title = `Received response for the Footfall ticket raised.`;
|
|
2203
|
+
let createdOn = dayjs( Ticket?.body?._source?.dateString ).format( 'DD MMM YYYY' );
|
|
2204
|
+
let description = `Raised on ${createdOn}`;
|
|
2205
|
+
|
|
2206
|
+
let Data = {
|
|
2207
|
+
'title': title,
|
|
2208
|
+
'body': description,
|
|
2209
|
+
'type': 'closed',
|
|
2210
|
+
'date': Ticket?.body?._source?.dateString,
|
|
2211
|
+
'storeId': Ticket?.body?._source?.storeId,
|
|
2212
|
+
'clientId': Ticket?.body?._source?.clientId,
|
|
2213
|
+
'ticketId': Ticket?.body?._source?.ticketId,
|
|
2214
|
+
};
|
|
2215
|
+
if ( userData && userData.fcmToken ) {
|
|
2216
|
+
const fcmToken = userData.fcmToken;
|
|
2217
|
+
await sendPushNotification( title, description, fcmToken, Data );
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2139
2222
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
2140
2223
|
|
|
2141
2224
|
|