tango-app-api-infra 3.9.5-vms.84 → 3.9.5-vms.86
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
|
@@ -902,7 +902,11 @@ export async function ticketSummary( req, res ) {
|
|
|
902
902
|
const userInfo = req.user;
|
|
903
903
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
904
904
|
const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
905
|
-
|
|
905
|
+
const getConfig = await findOneClient( { clientId: inputData?.clientId }, { footfallDirectoryConfigs: 1 } );
|
|
906
|
+
if ( !getConfig || getConfig ==null ) {
|
|
907
|
+
return res.sendError( 'this client not configured against footfall directory', 400 );
|
|
908
|
+
}
|
|
909
|
+
inputData.clientId = inputData?.clientId?.split( ',' );
|
|
906
910
|
// const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
907
911
|
if ( req?.user?.userType === 'tango' ) {
|
|
908
912
|
switch ( inputData?.tangoType ) {
|
|
@@ -921,6 +925,24 @@ export async function ticketSummary( req, res ) {
|
|
|
921
925
|
},
|
|
922
926
|
},
|
|
923
927
|
},
|
|
928
|
+
|
|
929
|
+
{
|
|
930
|
+
terms: {
|
|
931
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
932
|
+
inputData.clientId :
|
|
933
|
+
[ inputData.clientId ],
|
|
934
|
+
},
|
|
935
|
+
|
|
936
|
+
},
|
|
937
|
+
|
|
938
|
+
{
|
|
939
|
+
range: {
|
|
940
|
+
reviced: {
|
|
941
|
+
lt: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
942
|
+
}
|
|
943
|
+
,
|
|
944
|
+
},
|
|
945
|
+
},
|
|
924
946
|
{
|
|
925
947
|
nested: {
|
|
926
948
|
path: 'mappingInfo',
|
|
@@ -983,20 +1005,7 @@ export async function ticketSummary( req, res ) {
|
|
|
983
1005
|
size: 0,
|
|
984
1006
|
aggs: {
|
|
985
1007
|
avg_value: {
|
|
986
|
-
avg:
|
|
987
|
-
script: {
|
|
988
|
-
lang: 'painless',
|
|
989
|
-
source: `
|
|
990
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
991
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
992
|
-
try {
|
|
993
|
-
return Double.parseDouble(v);
|
|
994
|
-
} catch (Exception e) {
|
|
995
|
-
return null;
|
|
996
|
-
}
|
|
997
|
-
`,
|
|
998
|
-
},
|
|
999
|
-
},
|
|
1008
|
+
avg: 'reviced',
|
|
1000
1009
|
},
|
|
1001
1010
|
},
|
|
1002
1011
|
};
|
|
@@ -1029,11 +1038,10 @@ export async function ticketSummary( req, res ) {
|
|
|
1029
1038
|
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1030
1039
|
let openInfraIssues = 0;
|
|
1031
1040
|
|
|
1032
|
-
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1041
|
+
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open - Accuracy Issue' );
|
|
1033
1042
|
oiQ.size = 0;
|
|
1034
1043
|
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1035
1044
|
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1036
|
-
|
|
1037
1045
|
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1038
1046
|
let inprogress = 0;
|
|
1039
1047
|
|
|
@@ -1063,14 +1071,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1063
1071
|
// For this, add a filter on revicedPerc >= 85
|
|
1064
1072
|
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1065
1073
|
{
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
source: `
|
|
1070
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1071
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1072
|
-
`,
|
|
1073
|
-
params: { num: 85 },
|
|
1074
|
+
range: {
|
|
1075
|
+
reviced: {
|
|
1076
|
+
gte: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1074
1077
|
},
|
|
1075
1078
|
},
|
|
1076
1079
|
},
|
|
@@ -1085,14 +1088,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1085
1088
|
|
|
1086
1089
|
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1087
1090
|
{
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
source: `
|
|
1092
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1093
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1094
|
-
`,
|
|
1095
|
-
params: { num: 85 },
|
|
1091
|
+
range: {
|
|
1092
|
+
reviced: {
|
|
1093
|
+
lt: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1096
1094
|
},
|
|
1097
1095
|
},
|
|
1098
1096
|
},
|
|
@@ -1128,23 +1126,48 @@ export async function ticketSummary( req, res ) {
|
|
|
1128
1126
|
},
|
|
1129
1127
|
},
|
|
1130
1128
|
},
|
|
1129
|
+
{
|
|
1130
|
+
terms: {
|
|
1131
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1132
|
+
inputData.clientId :
|
|
1133
|
+
[ inputData.clientId ],
|
|
1134
|
+
},
|
|
1135
|
+
|
|
1136
|
+
},
|
|
1137
|
+
|
|
1138
|
+
],
|
|
1139
|
+
},
|
|
1140
|
+
},
|
|
1141
|
+
};
|
|
1131
1142
|
|
|
1143
|
+
const internalOpen = {
|
|
1144
|
+
size: 0,
|
|
1145
|
+
query: {
|
|
1146
|
+
bool: {
|
|
1147
|
+
must: [
|
|
1132
1148
|
{
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
{
|
|
1139
|
-
terms: {
|
|
1140
|
-
'mappingInfo.type': [ 'tagging', 'review', 'approve', 'tangoreview' ],
|
|
1141
|
-
},
|
|
1142
|
-
},
|
|
1143
|
-
],
|
|
1144
|
-
},
|
|
1149
|
+
'range': {
|
|
1150
|
+
'dateString': {
|
|
1151
|
+
'gte': inputData?.fromDate,
|
|
1152
|
+
'lte': inputData?.toDate,
|
|
1153
|
+
'format': 'yyyy-MM-dd',
|
|
1145
1154
|
},
|
|
1146
1155
|
},
|
|
1147
1156
|
},
|
|
1157
|
+
{
|
|
1158
|
+
terms: {
|
|
1159
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1160
|
+
inputData.clientId :
|
|
1161
|
+
[ inputData.clientId ],
|
|
1162
|
+
},
|
|
1163
|
+
|
|
1164
|
+
},
|
|
1165
|
+
{
|
|
1166
|
+
terms: {
|
|
1167
|
+
'status.keyword': [ 'Open', 'Raised' ],
|
|
1168
|
+
},
|
|
1169
|
+
|
|
1170
|
+
},
|
|
1148
1171
|
|
|
1149
1172
|
],
|
|
1150
1173
|
},
|
|
@@ -1154,20 +1177,32 @@ export async function ticketSummary( req, res ) {
|
|
|
1154
1177
|
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1155
1178
|
function buildInternalQueryWithStatus( baseQuery, statusValue ) {
|
|
1156
1179
|
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1157
|
-
//
|
|
1180
|
+
// Check if nested query exists, if not create it
|
|
1158
1181
|
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1159
|
-
if ( nested ) {
|
|
1160
|
-
//
|
|
1161
|
-
nested
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1182
|
+
if ( !nested ) {
|
|
1183
|
+
// Create nested query structure
|
|
1184
|
+
nested = {
|
|
1185
|
+
nested: {
|
|
1186
|
+
path: 'mappingInfo',
|
|
1187
|
+
query: {
|
|
1188
|
+
bool: {
|
|
1189
|
+
must: [],
|
|
1190
|
+
},
|
|
1191
|
+
},
|
|
1168
1192
|
},
|
|
1169
|
-
}
|
|
1193
|
+
};
|
|
1194
|
+
q.query.bool.must.push( nested );
|
|
1170
1195
|
}
|
|
1196
|
+
// filter out all mappingInfo.status
|
|
1197
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1198
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1199
|
+
} );
|
|
1200
|
+
// add desired status
|
|
1201
|
+
nested.nested.query.bool.must.push( {
|
|
1202
|
+
term: {
|
|
1203
|
+
'mappingInfo.status': statusValue,
|
|
1204
|
+
},
|
|
1205
|
+
} );
|
|
1171
1206
|
return q;
|
|
1172
1207
|
}
|
|
1173
1208
|
|
|
@@ -1183,7 +1218,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1183
1218
|
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1184
1219
|
|
|
1185
1220
|
// add new filters
|
|
1186
|
-
|
|
1221
|
+
q.query.bool.must.push( ...filters );
|
|
1187
1222
|
}
|
|
1188
1223
|
|
|
1189
1224
|
return {
|
|
@@ -1192,18 +1227,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1192
1227
|
aggs: {
|
|
1193
1228
|
avg_value: {
|
|
1194
1229
|
avg: {
|
|
1195
|
-
|
|
1196
|
-
lang: 'painless',
|
|
1197
|
-
source: `
|
|
1198
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1199
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1200
|
-
try {
|
|
1201
|
-
return Double.parseDouble(v);
|
|
1202
|
-
} catch (Exception e) {
|
|
1203
|
-
return null;
|
|
1204
|
-
}
|
|
1205
|
-
`,
|
|
1206
|
-
},
|
|
1230
|
+
field: 'reviced',
|
|
1207
1231
|
},
|
|
1208
1232
|
},
|
|
1209
1233
|
},
|
|
@@ -1224,13 +1248,14 @@ export async function ticketSummary( req, res ) {
|
|
|
1224
1248
|
allInternalQuery.size = 0;
|
|
1225
1249
|
const totalInternalResp = await getOpenSearchData( openSearch.footfallDirectory, allInternalQuery );
|
|
1226
1250
|
totalInternalTickets = totalInternalResp?.body?.hits?.total?.value || 0;
|
|
1251
|
+
logger.info( { totalInternalResp } );
|
|
1227
1252
|
|
|
1228
1253
|
// openTickets: mappingInfo.status: 'Open'
|
|
1229
1254
|
let openInternalTickets = 0;
|
|
1230
1255
|
|
|
1231
|
-
let otQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open' );
|
|
1232
|
-
otQInternal.size = 0;
|
|
1233
|
-
const openInternalResp = await getOpenSearchData( openSearch.footfallDirectory,
|
|
1256
|
+
// let otQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open' );
|
|
1257
|
+
// otQInternal.size = 0;
|
|
1258
|
+
const openInternalResp = await getOpenSearchData( openSearch.footfallDirectory, internalOpen );
|
|
1234
1259
|
openInternalTickets = openInternalResp?.body?.hits?.total?.value || 0;
|
|
1235
1260
|
// logger.info( { msd: '..............2', openResp } );
|
|
1236
1261
|
|
|
@@ -1238,11 +1263,12 @@ export async function ticketSummary( req, res ) {
|
|
|
1238
1263
|
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1239
1264
|
let openInternalInfraIssues = 0;
|
|
1240
1265
|
|
|
1241
|
-
let oiQinternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open Accuracy Issue' );
|
|
1266
|
+
let oiQinternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open - Accuracy Issue' );
|
|
1242
1267
|
oiQinternal.size = 0;
|
|
1243
1268
|
const infraInternalResp = await getOpenSearchData( openSearch.footfallDirectory, oiQinternal );
|
|
1244
1269
|
openInternalInfraIssues = infraInternalResp?.body?.hits?.total?.value || 0;
|
|
1245
1270
|
|
|
1271
|
+
|
|
1246
1272
|
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1247
1273
|
let inprogressIntrenal = 0;
|
|
1248
1274
|
|
|
@@ -1272,14 +1298,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1272
1298
|
// For this, add a filter on revicedPerc >= 85
|
|
1273
1299
|
let aboveQinternal = buildAggInternalQuery( baseInternalQuery, [
|
|
1274
1300
|
{
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
source: `
|
|
1279
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1280
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1281
|
-
`,
|
|
1282
|
-
params: { num: 85 },
|
|
1301
|
+
range: {
|
|
1302
|
+
reviced: {
|
|
1303
|
+
gte: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1283
1304
|
},
|
|
1284
1305
|
},
|
|
1285
1306
|
},
|
|
@@ -1294,14 +1315,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1294
1315
|
|
|
1295
1316
|
let belowQIneranl = buildAggInternalQuery( baseInternalQuery, [
|
|
1296
1317
|
{
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
source: `
|
|
1301
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1302
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1303
|
-
`,
|
|
1304
|
-
params: { num: 85 },
|
|
1318
|
+
range: {
|
|
1319
|
+
reviced: {
|
|
1320
|
+
lt: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1305
1321
|
},
|
|
1306
1322
|
},
|
|
1307
1323
|
},
|
|
@@ -1324,7 +1340,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1324
1340
|
break;
|
|
1325
1341
|
default: '';
|
|
1326
1342
|
}
|
|
1327
|
-
} else if ( req?.user?.userType
|
|
1343
|
+
} else if ( req?.user?.userType !== 'tango' ) {
|
|
1328
1344
|
if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1329
1345
|
const storeQuery = {
|
|
1330
1346
|
size: 0,
|
|
@@ -1340,6 +1356,14 @@ export async function ticketSummary( req, res ) {
|
|
|
1340
1356
|
},
|
|
1341
1357
|
},
|
|
1342
1358
|
},
|
|
1359
|
+
{
|
|
1360
|
+
terms: {
|
|
1361
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1362
|
+
inputData.clientId :
|
|
1363
|
+
[ inputData.clientId ],
|
|
1364
|
+
},
|
|
1365
|
+
|
|
1366
|
+
},
|
|
1343
1367
|
{
|
|
1344
1368
|
nested: {
|
|
1345
1369
|
path: 'mappingInfo',
|
|
@@ -1402,20 +1426,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1402
1426
|
size: 0,
|
|
1403
1427
|
aggs: {
|
|
1404
1428
|
avg_value: {
|
|
1405
|
-
avg:
|
|
1406
|
-
script: {
|
|
1407
|
-
lang: 'painless',
|
|
1408
|
-
source: `
|
|
1409
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1410
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1411
|
-
try {
|
|
1412
|
-
return Double.parseDouble(v);
|
|
1413
|
-
} catch (Exception e) {
|
|
1414
|
-
return null;
|
|
1415
|
-
}
|
|
1416
|
-
`,
|
|
1417
|
-
},
|
|
1418
|
-
},
|
|
1429
|
+
avg: 'mappingInfo.reviced',
|
|
1419
1430
|
},
|
|
1420
1431
|
},
|
|
1421
1432
|
};
|
|
@@ -1490,48 +1501,44 @@ try {
|
|
|
1490
1501
|
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1491
1502
|
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1492
1503
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1504
|
+
// Calculate average ticket percentage: avg((reviced/footfallCount)*100) filtered by baseStoreQuery
|
|
1505
|
+
|
|
1506
|
+
// Build aggregation query for ticket percentage
|
|
1507
|
+
let ticketPercentageAvg = 0;
|
|
1508
|
+
|
|
1509
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1510
|
+
avgTicketPercentageQuery.size = 0;
|
|
1511
|
+
avgTicketPercentageQuery.aggs = {
|
|
1512
|
+
avg_ticket_percentage: {
|
|
1513
|
+
avg: {
|
|
1498
1514
|
script: {
|
|
1499
|
-
lang: 'painless',
|
|
1500
1515
|
source: `
|
|
1501
|
-
doc['
|
|
1502
|
-
|
|
1516
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1517
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1518
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1519
|
+
} else {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1503
1522
|
`,
|
|
1504
|
-
|
|
1523
|
+
lang: 'painless',
|
|
1505
1524
|
},
|
|
1506
1525
|
},
|
|
1507
1526
|
},
|
|
1527
|
+
};
|
|
1508
1528
|
|
|
1529
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1509
1530
|
|
|
1510
|
-
|
|
1511
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1512
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1531
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1513
1532
|
|
|
1533
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1514
1534
|
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1515
|
-
let
|
|
1516
|
-
|
|
1517
|
-
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1518
|
-
{
|
|
1519
|
-
script: {
|
|
1520
|
-
script: {
|
|
1521
|
-
lang: 'painless',
|
|
1522
|
-
source: `
|
|
1523
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1524
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1525
|
-
`,
|
|
1526
|
-
params: { num: 85 },
|
|
1527
|
-
},
|
|
1528
|
-
},
|
|
1529
|
-
},
|
|
1530
|
-
|
|
1531
|
-
] );
|
|
1532
|
-
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1533
|
-
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1535
|
+
let ticketAccuracy = 0;
|
|
1534
1536
|
|
|
1537
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1538
|
+
logger.info( { belowQ } );
|
|
1539
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1540
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1541
|
+
logger.info( { accuracyResp } );
|
|
1535
1542
|
// Final result object
|
|
1536
1543
|
result = {
|
|
1537
1544
|
totalTickets,
|
|
@@ -1540,465 +1547,434 @@ try {
|
|
|
1540
1547
|
closedTickets,
|
|
1541
1548
|
dueToday: dueToday,
|
|
1542
1549
|
Expired: expiredTickets,
|
|
1543
|
-
avgTicket:
|
|
1544
|
-
avgAccuracy:
|
|
1550
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1551
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1545
1552
|
};
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1553
|
+
} else if ( ticketsFeature && ticketsApproveFeature ) {
|
|
1554
|
+
if ( inputData?.permissionType === 'review' ) {
|
|
1555
|
+
const storeQuery = {
|
|
1556
|
+
size: 0,
|
|
1557
|
+
query: {
|
|
1558
|
+
bool: {
|
|
1559
|
+
must: [
|
|
1560
|
+
{
|
|
1561
|
+
'range': {
|
|
1562
|
+
'dateString': {
|
|
1563
|
+
'gte': inputData?.fromDate,
|
|
1564
|
+
'lte': inputData?.toDate,
|
|
1565
|
+
'format': 'yyyy-MM-dd',
|
|
1566
|
+
},
|
|
1560
1567
|
},
|
|
1561
1568
|
},
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1569
|
+
{
|
|
1570
|
+
terms: {
|
|
1571
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1572
|
+
inputData.clientId :
|
|
1573
|
+
[ inputData.clientId ],
|
|
1574
|
+
},
|
|
1575
|
+
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
nested: {
|
|
1579
|
+
path: 'mappingInfo',
|
|
1580
|
+
query: {
|
|
1581
|
+
bool: {
|
|
1582
|
+
must: [
|
|
1583
|
+
{
|
|
1584
|
+
term: {
|
|
1585
|
+
'mappingInfo.type': 'review',
|
|
1586
|
+
},
|
|
1572
1587
|
},
|
|
1573
|
-
|
|
1574
|
-
|
|
1588
|
+
],
|
|
1589
|
+
},
|
|
1575
1590
|
},
|
|
1576
1591
|
},
|
|
1577
1592
|
},
|
|
1578
|
-
},
|
|
1579
1593
|
|
|
1580
|
-
|
|
1594
|
+
],
|
|
1595
|
+
},
|
|
1581
1596
|
},
|
|
1582
|
-
}
|
|
1583
|
-
};
|
|
1597
|
+
};
|
|
1584
1598
|
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1599
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1600
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1601
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1602
|
+
// Remove any previous mappingInfo.status term
|
|
1603
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1604
|
+
if ( nested ) {
|
|
1605
|
+
// filter out all mappingInfo.status
|
|
1606
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1607
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1608
|
+
} );
|
|
1609
|
+
// add desired status
|
|
1610
|
+
nested.nested.query.bool.must.push( {
|
|
1611
|
+
term: {
|
|
1612
|
+
'mappingInfo.status': statusValue,
|
|
1613
|
+
},
|
|
1614
|
+
} );
|
|
1615
|
+
}
|
|
1616
|
+
return q;
|
|
1601
1617
|
}
|
|
1602
|
-
return q;
|
|
1603
|
-
}
|
|
1604
1618
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1619
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1620
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1607
1621
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1622
|
+
// locate nested section
|
|
1623
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1610
1624
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1625
|
+
if ( nested ) {
|
|
1626
|
+
// remove old status filters
|
|
1627
|
+
nested.nested.query.bool.must =
|
|
1628
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1615
1629
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1630
|
+
// add new filters
|
|
1631
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1632
|
+
}
|
|
1619
1633
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
script: {
|
|
1627
|
-
lang: 'painless',
|
|
1628
|
-
source: `
|
|
1629
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1630
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1631
|
-
try {
|
|
1632
|
-
return Double.parseDouble(v);
|
|
1633
|
-
} catch (Exception e) {
|
|
1634
|
-
return null;
|
|
1635
|
-
}
|
|
1636
|
-
`,
|
|
1637
|
-
},
|
|
1634
|
+
return {
|
|
1635
|
+
...q,
|
|
1636
|
+
size: 0,
|
|
1637
|
+
aggs: {
|
|
1638
|
+
avg_value: {
|
|
1639
|
+
avg: 'mappingInfo.reviced',
|
|
1638
1640
|
},
|
|
1639
1641
|
},
|
|
1640
|
-
}
|
|
1642
|
+
};
|
|
1641
1643
|
};
|
|
1642
|
-
};
|
|
1643
1644
|
|
|
1644
1645
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1648
|
-
|
|
1649
|
-
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1650
|
-
let totalTickets = 0;
|
|
1646
|
+
// Get OpenSearch connection
|
|
1651
1647
|
|
|
1652
|
-
|
|
1648
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1653
1649
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1650
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1651
|
+
let totalTickets = 0;
|
|
1657
1652
|
|
|
1658
|
-
|
|
1659
|
-
let openTickets = 0;
|
|
1653
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1660
1654
|
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1665
|
-
// logger.info( { msd: '..............2', openResp } );
|
|
1655
|
+
allQuery.size = 0;
|
|
1656
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1657
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1666
1658
|
|
|
1659
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1660
|
+
let openTickets = 0;
|
|
1667
1661
|
|
|
1668
|
-
|
|
1669
|
-
|
|
1662
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1663
|
+
otQ.size = 0;
|
|
1664
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1665
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1666
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1670
1667
|
|
|
1671
|
-
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1672
|
-
ipQ.size = 0;
|
|
1673
|
-
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1674
|
-
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1675
1668
|
|
|
1676
|
-
|
|
1677
|
-
|
|
1669
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1670
|
+
let inprogress = 0;
|
|
1678
1671
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
// Average revisedPerc (for all tangoreview)
|
|
1672
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1673
|
+
ipQ.size = 0;
|
|
1674
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1675
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1684
1676
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1677
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1678
|
+
let closedTickets = 0;
|
|
1688
1679
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
if ( nestedDue ) {
|
|
1694
|
-
// Remove any previous mappingInfo.dueDate term
|
|
1695
|
-
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1696
|
-
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1697
|
-
);
|
|
1698
|
-
// Add new dueDate filter
|
|
1699
|
-
nestedDue.nested.query.bool.must.push( {
|
|
1700
|
-
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1701
|
-
} );
|
|
1702
|
-
}
|
|
1703
|
-
dueTodayQuery.size = 0;
|
|
1704
|
-
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1705
|
-
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1680
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1681
|
+
clQ.size = 0;
|
|
1682
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1683
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1706
1684
|
|
|
1685
|
+
let dueToday = 0;
|
|
1686
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1687
|
+
|
|
1688
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1689
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1690
|
+
// Locate nested mappingInfo query
|
|
1691
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1692
|
+
if ( nestedDue ) {
|
|
1693
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1694
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1695
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1696
|
+
);
|
|
1697
|
+
// Add new dueDate filter
|
|
1698
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1699
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1700
|
+
} );
|
|
1701
|
+
}
|
|
1702
|
+
dueTodayQuery.size = 0;
|
|
1703
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1704
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1707
1705
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1706
|
+
// filter expired Tickets
|
|
1707
|
+
let expiredTickets = 0;
|
|
1710
1708
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1709
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1710
|
+
eQ.size = 0;
|
|
1711
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1712
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1715
1713
|
|
|
1716
|
-
|
|
1717
|
-
let ticketAccuracyAbove = 0;
|
|
1714
|
+
// Calculate average ticket percentage: avg((reviced/footfallCount)*100) filtered by baseStoreQuery
|
|
1718
1715
|
|
|
1716
|
+
// Build aggregation query for ticket percentage
|
|
1717
|
+
let ticketPercentageAvg = 0;
|
|
1719
1718
|
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
{
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1719
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1720
|
+
avgTicketPercentageQuery.size = 0;
|
|
1721
|
+
avgTicketPercentageQuery.aggs = {
|
|
1722
|
+
avg_ticket_percentage: {
|
|
1723
|
+
avg: {
|
|
1724
|
+
script: {
|
|
1725
|
+
source: `
|
|
1726
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1727
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1728
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1729
|
+
} else {
|
|
1730
|
+
return null;
|
|
1731
|
+
}
|
|
1732
|
+
`,
|
|
1733
|
+
lang: 'painless',
|
|
1734
|
+
},
|
|
1731
1735
|
},
|
|
1732
1736
|
},
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
] );
|
|
1737
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1738
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1737
|
+
};
|
|
1739
1738
|
|
|
1740
|
-
|
|
1741
|
-
let ticketAccuracyBelow = 0;
|
|
1739
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1742
1740
|
|
|
1743
|
-
|
|
1744
|
-
{
|
|
1745
|
-
script: {
|
|
1746
|
-
script: {
|
|
1747
|
-
lang: 'painless',
|
|
1748
|
-
source: `
|
|
1749
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1750
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1751
|
-
`,
|
|
1752
|
-
params: { num: 85 },
|
|
1753
|
-
},
|
|
1754
|
-
},
|
|
1755
|
-
},
|
|
1741
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1756
1742
|
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1743
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1744
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1745
|
+
let ticketAccuracy = 0;
|
|
1760
1746
|
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1747
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1748
|
+
logger.info( { belowQ } );
|
|
1749
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1750
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1751
|
+
logger.info( { accuracyResp } );
|
|
1752
|
+
// Final result object
|
|
1753
|
+
result = {
|
|
1754
|
+
totalTickets,
|
|
1755
|
+
openTickets,
|
|
1756
|
+
inprogress,
|
|
1757
|
+
closedTickets,
|
|
1758
|
+
dueToday: dueToday,
|
|
1759
|
+
Expired: expiredTickets,
|
|
1760
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1761
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1762
|
+
};
|
|
1763
|
+
} else {
|
|
1764
|
+
const storeQuery = {
|
|
1765
|
+
size: 0,
|
|
1766
|
+
query: {
|
|
1767
|
+
bool: {
|
|
1768
|
+
must: [
|
|
1769
|
+
{
|
|
1770
|
+
'range': {
|
|
1771
|
+
'dateString': {
|
|
1772
|
+
'gte': inputData?.fromDate,
|
|
1773
|
+
'lte': inputData?.toDate,
|
|
1774
|
+
'format': 'yyyy-MM-dd',
|
|
1775
|
+
},
|
|
1784
1776
|
},
|
|
1785
1777
|
},
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1778
|
+
{
|
|
1779
|
+
terms: {
|
|
1780
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1781
|
+
inputData.clientId :
|
|
1782
|
+
[ inputData.clientId ],
|
|
1783
|
+
},
|
|
1784
|
+
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
nested: {
|
|
1788
|
+
path: 'mappingInfo',
|
|
1789
|
+
query: {
|
|
1790
|
+
bool: {
|
|
1791
|
+
must: [
|
|
1792
|
+
{
|
|
1793
|
+
term: {
|
|
1794
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1795
|
+
},
|
|
1796
1796
|
},
|
|
1797
|
-
|
|
1798
|
-
|
|
1797
|
+
],
|
|
1798
|
+
},
|
|
1799
1799
|
},
|
|
1800
1800
|
},
|
|
1801
1801
|
},
|
|
1802
|
-
},
|
|
1803
1802
|
|
|
1804
|
-
|
|
1803
|
+
],
|
|
1804
|
+
},
|
|
1805
1805
|
},
|
|
1806
|
-
}
|
|
1807
|
-
};
|
|
1806
|
+
};
|
|
1808
1807
|
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1808
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1809
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1810
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1811
|
+
// Remove any previous mappingInfo.status term
|
|
1812
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1813
|
+
if ( nested ) {
|
|
1814
|
+
// filter out all mappingInfo.status
|
|
1815
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1816
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1817
|
+
} );
|
|
1818
|
+
// add desired status
|
|
1819
|
+
nested.nested.query.bool.must.push( {
|
|
1820
|
+
term: {
|
|
1821
|
+
'mappingInfo.status': statusValue,
|
|
1822
|
+
},
|
|
1823
|
+
} );
|
|
1824
|
+
}
|
|
1825
|
+
return q;
|
|
1825
1826
|
}
|
|
1826
|
-
return q;
|
|
1827
|
-
}
|
|
1828
1827
|
|
|
1829
|
-
|
|
1830
|
-
|
|
1828
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1829
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1831
1830
|
|
|
1832
|
-
|
|
1833
|
-
|
|
1831
|
+
// locate nested section
|
|
1832
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1834
1833
|
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1834
|
+
if ( nested ) {
|
|
1835
|
+
// remove old status filters
|
|
1836
|
+
nested.nested.query.bool.must =
|
|
1837
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1839
1838
|
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1839
|
+
// add new filters
|
|
1840
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1841
|
+
}
|
|
1843
1842
|
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
script: {
|
|
1851
|
-
lang: 'painless',
|
|
1852
|
-
source: `
|
|
1853
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1854
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1855
|
-
try {
|
|
1856
|
-
return Double.parseDouble(v);
|
|
1857
|
-
} catch (Exception e) {
|
|
1858
|
-
return null;
|
|
1859
|
-
}
|
|
1860
|
-
`,
|
|
1861
|
-
},
|
|
1843
|
+
return {
|
|
1844
|
+
...q,
|
|
1845
|
+
size: 0,
|
|
1846
|
+
aggs: {
|
|
1847
|
+
avg_value: {
|
|
1848
|
+
avg: 'mappingInfp.reviced',
|
|
1862
1849
|
},
|
|
1863
1850
|
},
|
|
1864
|
-
}
|
|
1851
|
+
};
|
|
1865
1852
|
};
|
|
1866
|
-
};
|
|
1867
|
-
|
|
1868
1853
|
|
|
1869
|
-
// Get OpenSearch connection
|
|
1870
1854
|
|
|
1871
|
-
|
|
1855
|
+
// Get OpenSearch connection
|
|
1872
1856
|
|
|
1873
|
-
|
|
1874
|
-
let totalTickets = 0;
|
|
1857
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1875
1858
|
|
|
1876
|
-
|
|
1859
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1860
|
+
let totalTickets = 0;
|
|
1877
1861
|
|
|
1878
|
-
|
|
1879
|
-
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1880
|
-
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1862
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1881
1863
|
|
|
1882
|
-
|
|
1883
|
-
|
|
1864
|
+
allQuery.size = 0;
|
|
1865
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1866
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1884
1867
|
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1888
|
-
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1889
|
-
// logger.info( { msd: '..............2', openResp } );
|
|
1868
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1869
|
+
let openTickets = 0;
|
|
1890
1870
|
|
|
1871
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1872
|
+
otQ.size = 0;
|
|
1873
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1874
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1875
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1891
1876
|
|
|
1892
|
-
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1893
|
-
let inprogress = 0;
|
|
1894
1877
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1898
|
-
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1878
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1879
|
+
let inprogress = 0;
|
|
1899
1880
|
|
|
1900
|
-
|
|
1901
|
-
|
|
1881
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1882
|
+
ipQ.size = 0;
|
|
1883
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1884
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1902
1885
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1906
|
-
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1907
|
-
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1908
|
-
let dueToday = 0;
|
|
1909
|
-
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1886
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1887
|
+
let closedTickets = 0;
|
|
1910
1888
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1889
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1890
|
+
clQ.size = 0;
|
|
1891
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1892
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1893
|
+
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1894
|
+
let dueToday = 0;
|
|
1895
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1896
|
+
|
|
1897
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1898
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1899
|
+
// Locate nested mappingInfo query
|
|
1900
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1901
|
+
if ( nestedDue ) {
|
|
1902
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1903
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1904
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1905
|
+
);
|
|
1906
|
+
// Add new dueDate filter
|
|
1907
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1908
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1909
|
+
} );
|
|
1910
|
+
}
|
|
1911
|
+
dueTodayQuery.size = 0;
|
|
1912
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1913
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1928
1914
|
|
|
1929
1915
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1916
|
+
// filter expired Tickets
|
|
1917
|
+
let expiredTickets = 0;
|
|
1932
1918
|
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1919
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1920
|
+
eQ.size = 0;
|
|
1921
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1922
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1937
1923
|
|
|
1938
|
-
|
|
1924
|
+
// filter under tango review
|
|
1939
1925
|
|
|
1940
|
-
|
|
1926
|
+
let undertangoTickets = 0;
|
|
1941
1927
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1928
|
+
let utrQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1929
|
+
utrQ.size = 0;
|
|
1930
|
+
const utrResp = await getOpenSearchData( openSearch.footfallDirectory, utrQ );
|
|
1931
|
+
undertangoTickets = utrResp?.body?.hits?.total?.value || 0;
|
|
1946
1932
|
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
{
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1933
|
+
let ticketPercentageAvg =0;
|
|
1934
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1935
|
+
avgTicketPercentageQuery.size = 0;
|
|
1936
|
+
avgTicketPercentageQuery.aggs = {
|
|
1937
|
+
avg_ticket_percentage: {
|
|
1938
|
+
avg: {
|
|
1939
|
+
script: {
|
|
1940
|
+
source: `
|
|
1941
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1942
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1943
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1944
|
+
} else {
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
`,
|
|
1948
|
+
lang: 'painless',
|
|
1949
|
+
},
|
|
1959
1950
|
},
|
|
1960
1951
|
},
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
] );
|
|
1965
|
-
|
|
1966
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1967
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1968
|
-
|
|
1969
|
-
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1970
|
-
let ticketAccuracyBelow = 0;
|
|
1952
|
+
};
|
|
1971
1953
|
|
|
1972
|
-
|
|
1973
|
-
{
|
|
1974
|
-
script: {
|
|
1975
|
-
script: {
|
|
1976
|
-
lang: 'painless',
|
|
1977
|
-
source: `
|
|
1978
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1979
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1980
|
-
`,
|
|
1981
|
-
params: { num: 85 },
|
|
1982
|
-
},
|
|
1983
|
-
},
|
|
1984
|
-
},
|
|
1954
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1985
1955
|
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1956
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1957
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1958
|
+
let ticketAccuracy = 0;
|
|
1989
1959
|
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
1960
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1961
|
+
logger.info( { belowQ } );
|
|
1962
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1963
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1964
|
+
logger.info( { accuracyResp } );
|
|
1965
|
+
// Final result object
|
|
1966
|
+
result = {
|
|
1967
|
+
totalTickets,
|
|
1968
|
+
openTickets,
|
|
1969
|
+
inprogress,
|
|
1970
|
+
closedTickets,
|
|
1971
|
+
dueToday: dueToday,
|
|
1972
|
+
Expired: expiredTickets,
|
|
1973
|
+
underTangoReview: undertangoTickets,
|
|
1974
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1975
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
2002
1978
|
}
|
|
2003
1979
|
}
|
|
2004
1980
|
|
|
@@ -4925,7 +4901,7 @@ export async function updateUserTicketStatus( req, res ) {
|
|
|
4925
4901
|
|
|
4926
4902
|
const updatePayload = {
|
|
4927
4903
|
doc: {
|
|
4928
|
-
status: 'In
|
|
4904
|
+
status: lastEntry?.type == 'review'? 'Reviewer In progress':lastEntry?.type == 'approve'? 'Approver In progress':ticketSource?.status,
|
|
4929
4905
|
mappingInfo: updatedMappingInfo,
|
|
4930
4906
|
updatedAt: currentTime,
|
|
4931
4907
|
},
|