tango-app-api-infra 3.9.5-vms.83 → 3.9.5-vms.85
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.
|
@@ -312,6 +312,33 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
312
312
|
|
|
313
313
|
record.mappingInfo = [ ...ticketData?.[0]?._source?.mappingInfo.slice( 0, -1 ),
|
|
314
314
|
...temp ];
|
|
315
|
+
|
|
316
|
+
if ( Array.isArray( record.mappingInfo ) ) {
|
|
317
|
+
record.mappingInfo = record.mappingInfo.map( ( item ) => {
|
|
318
|
+
return {
|
|
319
|
+
...item,
|
|
320
|
+
status: item.type === 'approve'? 'Tango Review Done':'Closed',
|
|
321
|
+
};
|
|
322
|
+
} );
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
record.mappingInfo.push(
|
|
326
|
+
{
|
|
327
|
+
type: 'finalRevision',
|
|
328
|
+
mode: inputData.mappingInfo?.mode,
|
|
329
|
+
revicedFootfall: revisedFootfall,
|
|
330
|
+
revicedPerc: inputData.mappingInfo?.revicedPerc,
|
|
331
|
+
count: inputData.mappingInfo?.count,
|
|
332
|
+
revisedDetail: inputData.mappingInfo?.revisedDetail,
|
|
333
|
+
status: 'Closed',
|
|
334
|
+
createdByEmail: req?.user?.email,
|
|
335
|
+
createdByUserName: req?.user?.userName,
|
|
336
|
+
createdByRole: req?.user?.role,
|
|
337
|
+
createdAt: new Date(),
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
);
|
|
315
342
|
}
|
|
316
343
|
} else {
|
|
317
344
|
if ( Array.isArray( record.mappingInfo ) ) {
|
|
@@ -392,7 +419,7 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
392
419
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
393
420
|
|
|
394
421
|
if ( insertResult && ( insertResult.statusCode === 201 || insertResult.statusCode === 200 ) ) {
|
|
395
|
-
if ( record.status
|
|
422
|
+
if ( ( record.status === 'Closed' || record.status === 'Open - Accuracy Issue' ) && inputData.ticketType !== 'internal' ) {
|
|
396
423
|
const query = {
|
|
397
424
|
storeId: inputData?.storeId,
|
|
398
425
|
isVideoStream: true,
|
|
@@ -532,7 +559,7 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
532
559
|
},
|
|
533
560
|
},
|
|
534
561
|
};
|
|
535
|
-
if ( Ticket[0]?._source?.type
|
|
562
|
+
if ( Ticket[0]?._source?.type !== 'internal' ) {
|
|
536
563
|
getTicket.query.bool.must.push(
|
|
537
564
|
{
|
|
538
565
|
nested: {
|
|
@@ -576,22 +603,24 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
576
603
|
.filter( ( item ) => item.type === 'tangoreview' )
|
|
577
604
|
.map( ( item ) => ( {
|
|
578
605
|
...item,
|
|
579
|
-
status: 'Closed',
|
|
606
|
+
status: 'Closed - Accuracy Issue',
|
|
580
607
|
createdByEmail: req?.user?.email,
|
|
581
608
|
createdByUserName: req?.user?.userName,
|
|
582
609
|
createdByRole: req?.user?.role,
|
|
610
|
+
comments: inputData?.comments || '',
|
|
611
|
+
subComments: inputData?.subComments ||'',
|
|
583
612
|
} ) );
|
|
584
613
|
|
|
585
614
|
record.mappingInfo = [ ...ticketData?.[0]?._source?.mappingInfo.slice( 0, -1 ),
|
|
586
615
|
...temp ];
|
|
587
|
-
if ( Array.isArray( record.mappingInfo ) ) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
616
|
+
// if ( Array.isArray( record.mappingInfo ) ) {
|
|
617
|
+
// record.mappingInfo = record.mappingInfo.map( ( item ) => {
|
|
618
|
+
// return {
|
|
619
|
+
// ...item,
|
|
620
|
+
// status: 'Closed',
|
|
621
|
+
// };
|
|
622
|
+
// } );
|
|
623
|
+
// }
|
|
595
624
|
|
|
596
625
|
record.mappingInfo.push(
|
|
597
626
|
{
|
|
@@ -606,6 +635,8 @@ export async function tangoReviewAccuracyClosedTicket( req, res ) {
|
|
|
606
635
|
createdByUserName: req?.user?.userName,
|
|
607
636
|
createdByRole: req?.user?.role,
|
|
608
637
|
createdAt: new Date(),
|
|
638
|
+
comments: inputData?.comments || '',
|
|
639
|
+
subComments: inputData?.subComments || '',
|
|
609
640
|
},
|
|
610
641
|
);
|
|
611
642
|
}
|
|
@@ -871,9 +902,13 @@ export async function ticketSummary( req, res ) {
|
|
|
871
902
|
const userInfo = req.user;
|
|
872
903
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
873
904
|
const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
874
|
-
|
|
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( ',' );
|
|
875
910
|
// const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
876
|
-
if ( req?.user?.userType
|
|
911
|
+
if ( req?.user?.userType !== 'tango' ) {
|
|
877
912
|
switch ( inputData?.tangoType ) {
|
|
878
913
|
case 'store':
|
|
879
914
|
const storeQuery = {
|
|
@@ -890,6 +925,24 @@ export async function ticketSummary( req, res ) {
|
|
|
890
925
|
},
|
|
891
926
|
},
|
|
892
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
|
+
},
|
|
893
946
|
{
|
|
894
947
|
nested: {
|
|
895
948
|
path: 'mappingInfo',
|
|
@@ -952,20 +1005,7 @@ export async function ticketSummary( req, res ) {
|
|
|
952
1005
|
size: 0,
|
|
953
1006
|
aggs: {
|
|
954
1007
|
avg_value: {
|
|
955
|
-
avg:
|
|
956
|
-
script: {
|
|
957
|
-
lang: 'painless',
|
|
958
|
-
source: `
|
|
959
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
960
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
961
|
-
try {
|
|
962
|
-
return Double.parseDouble(v);
|
|
963
|
-
} catch (Exception e) {
|
|
964
|
-
return null;
|
|
965
|
-
}
|
|
966
|
-
`,
|
|
967
|
-
},
|
|
968
|
-
},
|
|
1008
|
+
avg: 'reviced',
|
|
969
1009
|
},
|
|
970
1010
|
},
|
|
971
1011
|
};
|
|
@@ -998,11 +1038,10 @@ export async function ticketSummary( req, res ) {
|
|
|
998
1038
|
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
999
1039
|
let openInfraIssues = 0;
|
|
1000
1040
|
|
|
1001
|
-
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1041
|
+
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open - Accuracy Issue' );
|
|
1002
1042
|
oiQ.size = 0;
|
|
1003
1043
|
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1004
1044
|
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1005
|
-
|
|
1006
1045
|
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1007
1046
|
let inprogress = 0;
|
|
1008
1047
|
|
|
@@ -1032,14 +1071,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1032
1071
|
// For this, add a filter on revicedPerc >= 85
|
|
1033
1072
|
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1034
1073
|
{
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
source: `
|
|
1039
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1040
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1041
|
-
`,
|
|
1042
|
-
params: { num: 85 },
|
|
1074
|
+
range: {
|
|
1075
|
+
reviced: {
|
|
1076
|
+
gte: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1043
1077
|
},
|
|
1044
1078
|
},
|
|
1045
1079
|
},
|
|
@@ -1054,14 +1088,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1054
1088
|
|
|
1055
1089
|
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1056
1090
|
{
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
source: `
|
|
1061
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1062
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1063
|
-
`,
|
|
1064
|
-
params: { num: 85 },
|
|
1091
|
+
range: {
|
|
1092
|
+
reviced: {
|
|
1093
|
+
lt: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1065
1094
|
},
|
|
1066
1095
|
},
|
|
1067
1096
|
},
|
|
@@ -1097,23 +1126,48 @@ export async function ticketSummary( req, res ) {
|
|
|
1097
1126
|
},
|
|
1098
1127
|
},
|
|
1099
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
|
+
};
|
|
1100
1142
|
|
|
1143
|
+
const internalOpen = {
|
|
1144
|
+
size: 0,
|
|
1145
|
+
query: {
|
|
1146
|
+
bool: {
|
|
1147
|
+
must: [
|
|
1101
1148
|
{
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
{
|
|
1108
|
-
terms: {
|
|
1109
|
-
'mappingInfo.type': [ 'tagging', 'review', 'approve', 'tangoreview' ],
|
|
1110
|
-
},
|
|
1111
|
-
},
|
|
1112
|
-
],
|
|
1113
|
-
},
|
|
1149
|
+
'range': {
|
|
1150
|
+
'dateString': {
|
|
1151
|
+
'gte': inputData?.fromDate,
|
|
1152
|
+
'lte': inputData?.toDate,
|
|
1153
|
+
'format': 'yyyy-MM-dd',
|
|
1114
1154
|
},
|
|
1115
1155
|
},
|
|
1116
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
|
+
},
|
|
1117
1171
|
|
|
1118
1172
|
],
|
|
1119
1173
|
},
|
|
@@ -1123,20 +1177,32 @@ export async function ticketSummary( req, res ) {
|
|
|
1123
1177
|
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1124
1178
|
function buildInternalQueryWithStatus( baseQuery, statusValue ) {
|
|
1125
1179
|
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1126
|
-
//
|
|
1180
|
+
// Check if nested query exists, if not create it
|
|
1127
1181
|
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1128
|
-
if ( nested ) {
|
|
1129
|
-
//
|
|
1130
|
-
nested
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1182
|
+
if ( !nested ) {
|
|
1183
|
+
// Create nested query structure
|
|
1184
|
+
nested = {
|
|
1185
|
+
nested: {
|
|
1186
|
+
path: 'mappingInfo',
|
|
1187
|
+
query: {
|
|
1188
|
+
bool: {
|
|
1189
|
+
must: [],
|
|
1190
|
+
},
|
|
1191
|
+
},
|
|
1137
1192
|
},
|
|
1138
|
-
}
|
|
1193
|
+
};
|
|
1194
|
+
q.query.bool.must.push( nested );
|
|
1139
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
|
+
} );
|
|
1140
1206
|
return q;
|
|
1141
1207
|
}
|
|
1142
1208
|
|
|
@@ -1152,7 +1218,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1152
1218
|
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1153
1219
|
|
|
1154
1220
|
// add new filters
|
|
1155
|
-
|
|
1221
|
+
q.query.bool.must.push( ...filters );
|
|
1156
1222
|
}
|
|
1157
1223
|
|
|
1158
1224
|
return {
|
|
@@ -1161,18 +1227,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1161
1227
|
aggs: {
|
|
1162
1228
|
avg_value: {
|
|
1163
1229
|
avg: {
|
|
1164
|
-
|
|
1165
|
-
lang: 'painless',
|
|
1166
|
-
source: `
|
|
1167
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1168
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1169
|
-
try {
|
|
1170
|
-
return Double.parseDouble(v);
|
|
1171
|
-
} catch (Exception e) {
|
|
1172
|
-
return null;
|
|
1173
|
-
}
|
|
1174
|
-
`,
|
|
1175
|
-
},
|
|
1230
|
+
field: 'reviced',
|
|
1176
1231
|
},
|
|
1177
1232
|
},
|
|
1178
1233
|
},
|
|
@@ -1193,13 +1248,14 @@ export async function ticketSummary( req, res ) {
|
|
|
1193
1248
|
allInternalQuery.size = 0;
|
|
1194
1249
|
const totalInternalResp = await getOpenSearchData( openSearch.footfallDirectory, allInternalQuery );
|
|
1195
1250
|
totalInternalTickets = totalInternalResp?.body?.hits?.total?.value || 0;
|
|
1251
|
+
logger.info( { totalInternalResp } );
|
|
1196
1252
|
|
|
1197
1253
|
// openTickets: mappingInfo.status: 'Open'
|
|
1198
1254
|
let openInternalTickets = 0;
|
|
1199
1255
|
|
|
1200
|
-
let otQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open' );
|
|
1201
|
-
otQInternal.size = 0;
|
|
1202
|
-
const openInternalResp = await getOpenSearchData( openSearch.footfallDirectory,
|
|
1256
|
+
// let otQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open' );
|
|
1257
|
+
// otQInternal.size = 0;
|
|
1258
|
+
const openInternalResp = await getOpenSearchData( openSearch.footfallDirectory, internalOpen );
|
|
1203
1259
|
openInternalTickets = openInternalResp?.body?.hits?.total?.value || 0;
|
|
1204
1260
|
// logger.info( { msd: '..............2', openResp } );
|
|
1205
1261
|
|
|
@@ -1207,11 +1263,12 @@ export async function ticketSummary( req, res ) {
|
|
|
1207
1263
|
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1208
1264
|
let openInternalInfraIssues = 0;
|
|
1209
1265
|
|
|
1210
|
-
let oiQinternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open Accuracy Issue' );
|
|
1266
|
+
let oiQinternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open - Accuracy Issue' );
|
|
1211
1267
|
oiQinternal.size = 0;
|
|
1212
1268
|
const infraInternalResp = await getOpenSearchData( openSearch.footfallDirectory, oiQinternal );
|
|
1213
1269
|
openInternalInfraIssues = infraInternalResp?.body?.hits?.total?.value || 0;
|
|
1214
1270
|
|
|
1271
|
+
|
|
1215
1272
|
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1216
1273
|
let inprogressIntrenal = 0;
|
|
1217
1274
|
|
|
@@ -1241,14 +1298,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1241
1298
|
// For this, add a filter on revicedPerc >= 85
|
|
1242
1299
|
let aboveQinternal = buildAggInternalQuery( baseInternalQuery, [
|
|
1243
1300
|
{
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
source: `
|
|
1248
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1249
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1250
|
-
`,
|
|
1251
|
-
params: { num: 85 },
|
|
1301
|
+
range: {
|
|
1302
|
+
reviced: {
|
|
1303
|
+
gte: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1252
1304
|
},
|
|
1253
1305
|
},
|
|
1254
1306
|
},
|
|
@@ -1263,14 +1315,9 @@ export async function ticketSummary( req, res ) {
|
|
|
1263
1315
|
|
|
1264
1316
|
let belowQIneranl = buildAggInternalQuery( baseInternalQuery, [
|
|
1265
1317
|
{
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
source: `
|
|
1270
|
-
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1271
|
-
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1272
|
-
`,
|
|
1273
|
-
params: { num: 85 },
|
|
1318
|
+
range: {
|
|
1319
|
+
reviced: {
|
|
1320
|
+
lt: parseInt( getConfig?.footfallDirectoryConfigs?.tangoReview ),
|
|
1274
1321
|
},
|
|
1275
1322
|
},
|
|
1276
1323
|
},
|
|
@@ -1293,8 +1340,10 @@ export async function ticketSummary( req, res ) {
|
|
|
1293
1340
|
break;
|
|
1294
1341
|
default: '';
|
|
1295
1342
|
}
|
|
1296
|
-
} else if ( req?.user?.userType === '
|
|
1343
|
+
} else if ( req?.user?.userType === 'tango' ) {
|
|
1344
|
+
logger.info( { msg: '.........1', ticketsFeature, ticketsApproveFeature } );
|
|
1297
1345
|
if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1346
|
+
logger.info( '.........3' );
|
|
1298
1347
|
const storeQuery = {
|
|
1299
1348
|
size: 0,
|
|
1300
1349
|
query: {
|
|
@@ -1309,6 +1358,14 @@ export async function ticketSummary( req, res ) {
|
|
|
1309
1358
|
},
|
|
1310
1359
|
},
|
|
1311
1360
|
},
|
|
1361
|
+
{
|
|
1362
|
+
terms: {
|
|
1363
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1364
|
+
inputData.clientId :
|
|
1365
|
+
[ inputData.clientId ],
|
|
1366
|
+
},
|
|
1367
|
+
|
|
1368
|
+
},
|
|
1312
1369
|
{
|
|
1313
1370
|
nested: {
|
|
1314
1371
|
path: 'mappingInfo',
|
|
@@ -1371,20 +1428,7 @@ export async function ticketSummary( req, res ) {
|
|
|
1371
1428
|
size: 0,
|
|
1372
1429
|
aggs: {
|
|
1373
1430
|
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
|
-
},
|
|
1431
|
+
avg: 'mappingInfo.reviced',
|
|
1388
1432
|
},
|
|
1389
1433
|
},
|
|
1390
1434
|
};
|
|
@@ -1459,48 +1503,44 @@ try {
|
|
|
1459
1503
|
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1460
1504
|
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1461
1505
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1506
|
+
// Calculate average ticket percentage: avg((reviced/footfallCount)*100) filtered by baseStoreQuery
|
|
1507
|
+
|
|
1508
|
+
// Build aggregation query for ticket percentage
|
|
1509
|
+
let ticketPercentageAvg = 0;
|
|
1510
|
+
|
|
1511
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1512
|
+
avgTicketPercentageQuery.size = 0;
|
|
1513
|
+
avgTicketPercentageQuery.aggs = {
|
|
1514
|
+
avg_ticket_percentage: {
|
|
1515
|
+
avg: {
|
|
1467
1516
|
script: {
|
|
1468
|
-
lang: 'painless',
|
|
1469
1517
|
source: `
|
|
1470
|
-
doc['
|
|
1471
|
-
|
|
1518
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1519
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1520
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1521
|
+
} else {
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1472
1524
|
`,
|
|
1473
|
-
|
|
1525
|
+
lang: 'painless',
|
|
1474
1526
|
},
|
|
1475
1527
|
},
|
|
1476
1528
|
},
|
|
1529
|
+
};
|
|
1477
1530
|
|
|
1531
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1478
1532
|
|
|
1479
|
-
|
|
1480
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1481
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1533
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1482
1534
|
|
|
1535
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1483
1536
|
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1484
|
-
let
|
|
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';
|
|
1537
|
+
let ticketAccuracy = 0;
|
|
1503
1538
|
|
|
1539
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1540
|
+
logger.info( { belowQ } );
|
|
1541
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1542
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1543
|
+
logger.info( { accuracyResp } );
|
|
1504
1544
|
// Final result object
|
|
1505
1545
|
result = {
|
|
1506
1546
|
totalTickets,
|
|
@@ -1509,465 +1549,435 @@ try {
|
|
|
1509
1549
|
closedTickets,
|
|
1510
1550
|
dueToday: dueToday,
|
|
1511
1551
|
Expired: expiredTickets,
|
|
1512
|
-
avgTicket:
|
|
1513
|
-
avgAccuracy:
|
|
1552
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1553
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1514
1554
|
};
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1555
|
+
} else if ( ticketsFeature && ticketsApproveFeature ) {
|
|
1556
|
+
logger.info( '.........2' );
|
|
1557
|
+
if ( inputData?.permissionType === 'review' ) {
|
|
1558
|
+
const storeQuery = {
|
|
1559
|
+
size: 0,
|
|
1560
|
+
query: {
|
|
1561
|
+
bool: {
|
|
1562
|
+
must: [
|
|
1563
|
+
{
|
|
1564
|
+
'range': {
|
|
1565
|
+
'dateString': {
|
|
1566
|
+
'gte': inputData?.fromDate,
|
|
1567
|
+
'lte': inputData?.toDate,
|
|
1568
|
+
'format': 'yyyy-MM-dd',
|
|
1569
|
+
},
|
|
1529
1570
|
},
|
|
1530
1571
|
},
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1572
|
+
{
|
|
1573
|
+
terms: {
|
|
1574
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1575
|
+
inputData.clientId :
|
|
1576
|
+
[ inputData.clientId ],
|
|
1577
|
+
},
|
|
1578
|
+
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
nested: {
|
|
1582
|
+
path: 'mappingInfo',
|
|
1583
|
+
query: {
|
|
1584
|
+
bool: {
|
|
1585
|
+
must: [
|
|
1586
|
+
{
|
|
1587
|
+
term: {
|
|
1588
|
+
'mappingInfo.type': 'review',
|
|
1589
|
+
},
|
|
1541
1590
|
},
|
|
1542
|
-
|
|
1543
|
-
|
|
1591
|
+
],
|
|
1592
|
+
},
|
|
1544
1593
|
},
|
|
1545
1594
|
},
|
|
1546
1595
|
},
|
|
1547
|
-
},
|
|
1548
|
-
|
|
1549
|
-
],
|
|
1550
|
-
},
|
|
1551
|
-
},
|
|
1552
|
-
};
|
|
1553
1596
|
|
|
1554
|
-
|
|
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,
|
|
1597
|
+
],
|
|
1568
1598
|
},
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
return q;
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1575
|
-
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1599
|
+
},
|
|
1600
|
+
};
|
|
1576
1601
|
|
|
1577
|
-
//
|
|
1578
|
-
|
|
1602
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1603
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1604
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1605
|
+
// Remove any previous mappingInfo.status term
|
|
1606
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1607
|
+
if ( nested ) {
|
|
1608
|
+
// filter out all mappingInfo.status
|
|
1609
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1610
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1611
|
+
} );
|
|
1612
|
+
// add desired status
|
|
1613
|
+
nested.nested.query.bool.must.push( {
|
|
1614
|
+
term: {
|
|
1615
|
+
'mappingInfo.status': statusValue,
|
|
1616
|
+
},
|
|
1617
|
+
} );
|
|
1618
|
+
}
|
|
1619
|
+
return q;
|
|
1620
|
+
}
|
|
1579
1621
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
nested.nested.query.bool.must =
|
|
1583
|
-
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1622
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1623
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1584
1624
|
|
|
1585
|
-
//
|
|
1586
|
-
nested.
|
|
1587
|
-
}
|
|
1625
|
+
// locate nested section
|
|
1626
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1588
1627
|
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
}
|
|
1605
|
-
`,
|
|
1606
|
-
},
|
|
1628
|
+
if ( nested ) {
|
|
1629
|
+
// remove old status filters
|
|
1630
|
+
nested.nested.query.bool.must =
|
|
1631
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1632
|
+
|
|
1633
|
+
// add new filters
|
|
1634
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
return {
|
|
1638
|
+
...q,
|
|
1639
|
+
size: 0,
|
|
1640
|
+
aggs: {
|
|
1641
|
+
avg_value: {
|
|
1642
|
+
avg: 'mappingInfo.reviced',
|
|
1607
1643
|
},
|
|
1608
1644
|
},
|
|
1609
|
-
}
|
|
1645
|
+
};
|
|
1610
1646
|
};
|
|
1611
|
-
};
|
|
1612
|
-
|
|
1613
1647
|
|
|
1614
|
-
// Get OpenSearch connection
|
|
1615
1648
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1619
|
-
let totalTickets = 0;
|
|
1649
|
+
// Get OpenSearch connection
|
|
1620
1650
|
|
|
1621
|
-
|
|
1651
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1622
1652
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1653
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1654
|
+
let totalTickets = 0;
|
|
1626
1655
|
|
|
1627
|
-
|
|
1628
|
-
let openTickets = 0;
|
|
1656
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1629
1657
|
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1634
|
-
// logger.info( { msd: '..............2', openResp } );
|
|
1658
|
+
allQuery.size = 0;
|
|
1659
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1660
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1635
1661
|
|
|
1662
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1663
|
+
let openTickets = 0;
|
|
1636
1664
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1665
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1666
|
+
otQ.size = 0;
|
|
1667
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1668
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1669
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1639
1670
|
|
|
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
1671
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1672
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1673
|
+
let inprogress = 0;
|
|
1647
1674
|
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
// Average revisedPerc (for all tangoreview)
|
|
1675
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1676
|
+
ipQ.size = 0;
|
|
1677
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1678
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1653
1679
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1680
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1681
|
+
let closedTickets = 0;
|
|
1657
1682
|
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
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;
|
|
1683
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1684
|
+
clQ.size = 0;
|
|
1685
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1686
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1675
1687
|
|
|
1688
|
+
let dueToday = 0;
|
|
1689
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1690
|
+
|
|
1691
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1692
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1693
|
+
// Locate nested mappingInfo query
|
|
1694
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1695
|
+
if ( nestedDue ) {
|
|
1696
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1697
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1698
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1699
|
+
);
|
|
1700
|
+
// Add new dueDate filter
|
|
1701
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1702
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1703
|
+
} );
|
|
1704
|
+
}
|
|
1705
|
+
dueTodayQuery.size = 0;
|
|
1706
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1707
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1676
1708
|
|
|
1677
|
-
|
|
1678
|
-
|
|
1709
|
+
// filter expired Tickets
|
|
1710
|
+
let expiredTickets = 0;
|
|
1679
1711
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1712
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1713
|
+
eQ.size = 0;
|
|
1714
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1715
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1684
1716
|
|
|
1685
|
-
|
|
1686
|
-
let ticketAccuracyAbove = 0;
|
|
1717
|
+
// Calculate average ticket percentage: avg((reviced/footfallCount)*100) filtered by baseStoreQuery
|
|
1687
1718
|
|
|
1719
|
+
// Build aggregation query for ticket percentage
|
|
1720
|
+
let ticketPercentageAvg = 0;
|
|
1688
1721
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
{
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1722
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1723
|
+
avgTicketPercentageQuery.size = 0;
|
|
1724
|
+
avgTicketPercentageQuery.aggs = {
|
|
1725
|
+
avg_ticket_percentage: {
|
|
1726
|
+
avg: {
|
|
1727
|
+
script: {
|
|
1728
|
+
source: `
|
|
1729
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1730
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1731
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1732
|
+
} else {
|
|
1733
|
+
return null;
|
|
1734
|
+
}
|
|
1735
|
+
`,
|
|
1736
|
+
lang: 'painless',
|
|
1737
|
+
},
|
|
1700
1738
|
},
|
|
1701
1739
|
},
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
] );
|
|
1706
|
-
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1707
|
-
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1740
|
+
};
|
|
1708
1741
|
|
|
1709
|
-
|
|
1710
|
-
let ticketAccuracyBelow = 0;
|
|
1742
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1711
1743
|
|
|
1712
|
-
|
|
1713
|
-
{
|
|
1714
|
-
script: {
|
|
1715
|
-
script: {
|
|
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 },
|
|
1722
|
-
},
|
|
1723
|
-
},
|
|
1724
|
-
},
|
|
1744
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1725
1745
|
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1746
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1747
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1748
|
+
let ticketAccuracy = 0;
|
|
1729
1749
|
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1750
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1751
|
+
logger.info( { belowQ } );
|
|
1752
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1753
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1754
|
+
logger.info( { accuracyResp } );
|
|
1755
|
+
// Final result object
|
|
1756
|
+
result = {
|
|
1757
|
+
totalTickets,
|
|
1758
|
+
openTickets,
|
|
1759
|
+
inprogress,
|
|
1760
|
+
closedTickets,
|
|
1761
|
+
dueToday: dueToday,
|
|
1762
|
+
Expired: expiredTickets,
|
|
1763
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1764
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1765
|
+
};
|
|
1766
|
+
} else {
|
|
1767
|
+
const storeQuery = {
|
|
1768
|
+
size: 0,
|
|
1769
|
+
query: {
|
|
1770
|
+
bool: {
|
|
1771
|
+
must: [
|
|
1772
|
+
{
|
|
1773
|
+
'range': {
|
|
1774
|
+
'dateString': {
|
|
1775
|
+
'gte': inputData?.fromDate,
|
|
1776
|
+
'lte': inputData?.toDate,
|
|
1777
|
+
'format': 'yyyy-MM-dd',
|
|
1778
|
+
},
|
|
1753
1779
|
},
|
|
1754
1780
|
},
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1781
|
+
{
|
|
1782
|
+
terms: {
|
|
1783
|
+
'clientId.keyword': Array.isArray( inputData.clientId ) ?
|
|
1784
|
+
inputData.clientId :
|
|
1785
|
+
[ inputData.clientId ],
|
|
1786
|
+
},
|
|
1787
|
+
|
|
1788
|
+
},
|
|
1789
|
+
{
|
|
1790
|
+
nested: {
|
|
1791
|
+
path: 'mappingInfo',
|
|
1792
|
+
query: {
|
|
1793
|
+
bool: {
|
|
1794
|
+
must: [
|
|
1795
|
+
{
|
|
1796
|
+
term: {
|
|
1797
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1798
|
+
},
|
|
1765
1799
|
},
|
|
1766
|
-
|
|
1767
|
-
|
|
1800
|
+
],
|
|
1801
|
+
},
|
|
1768
1802
|
},
|
|
1769
1803
|
},
|
|
1770
1804
|
},
|
|
1771
|
-
},
|
|
1772
1805
|
|
|
1773
|
-
|
|
1806
|
+
],
|
|
1807
|
+
},
|
|
1774
1808
|
},
|
|
1775
|
-
}
|
|
1776
|
-
};
|
|
1809
|
+
};
|
|
1777
1810
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1811
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1812
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1813
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1814
|
+
// Remove any previous mappingInfo.status term
|
|
1815
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1816
|
+
if ( nested ) {
|
|
1817
|
+
// filter out all mappingInfo.status
|
|
1818
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1819
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1820
|
+
} );
|
|
1821
|
+
// add desired status
|
|
1822
|
+
nested.nested.query.bool.must.push( {
|
|
1823
|
+
term: {
|
|
1824
|
+
'mappingInfo.status': statusValue,
|
|
1825
|
+
},
|
|
1826
|
+
} );
|
|
1827
|
+
}
|
|
1828
|
+
return q;
|
|
1794
1829
|
}
|
|
1795
|
-
return q;
|
|
1796
|
-
}
|
|
1797
1830
|
|
|
1798
|
-
|
|
1799
|
-
|
|
1831
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1832
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1800
1833
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1834
|
+
// locate nested section
|
|
1835
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1803
1836
|
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1837
|
+
if ( nested ) {
|
|
1838
|
+
// remove old status filters
|
|
1839
|
+
nested.nested.query.bool.must =
|
|
1840
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1808
1841
|
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1842
|
+
// add new filters
|
|
1843
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1844
|
+
}
|
|
1812
1845
|
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
script: {
|
|
1820
|
-
lang: 'painless',
|
|
1821
|
-
source: `
|
|
1822
|
-
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1823
|
-
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1824
|
-
try {
|
|
1825
|
-
return Double.parseDouble(v);
|
|
1826
|
-
} catch (Exception e) {
|
|
1827
|
-
return null;
|
|
1828
|
-
}
|
|
1829
|
-
`,
|
|
1830
|
-
},
|
|
1846
|
+
return {
|
|
1847
|
+
...q,
|
|
1848
|
+
size: 0,
|
|
1849
|
+
aggs: {
|
|
1850
|
+
avg_value: {
|
|
1851
|
+
avg: 'mappingInfp.reviced',
|
|
1831
1852
|
},
|
|
1832
1853
|
},
|
|
1833
|
-
}
|
|
1854
|
+
};
|
|
1834
1855
|
};
|
|
1835
|
-
};
|
|
1836
1856
|
|
|
1837
1857
|
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1858
|
+
// Get OpenSearch connection
|
|
1841
1859
|
|
|
1842
|
-
|
|
1843
|
-
let totalTickets = 0;
|
|
1860
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1844
1861
|
|
|
1845
|
-
|
|
1862
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1863
|
+
let totalTickets = 0;
|
|
1846
1864
|
|
|
1847
|
-
|
|
1848
|
-
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1849
|
-
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1865
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1850
1866
|
|
|
1851
|
-
|
|
1852
|
-
|
|
1867
|
+
allQuery.size = 0;
|
|
1868
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1869
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1853
1870
|
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1857
|
-
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1858
|
-
// logger.info( { msd: '..............2', openResp } );
|
|
1871
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1872
|
+
let openTickets = 0;
|
|
1859
1873
|
|
|
1874
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1875
|
+
otQ.size = 0;
|
|
1876
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1877
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1878
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1860
1879
|
|
|
1861
|
-
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1862
|
-
let inprogress = 0;
|
|
1863
1880
|
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1867
|
-
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1881
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1882
|
+
let inprogress = 0;
|
|
1868
1883
|
|
|
1869
|
-
|
|
1870
|
-
|
|
1884
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1885
|
+
ipQ.size = 0;
|
|
1886
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1887
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1871
1888
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1875
|
-
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1876
|
-
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1877
|
-
let dueToday = 0;
|
|
1878
|
-
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1889
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1890
|
+
let closedTickets = 0;
|
|
1879
1891
|
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1892
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1893
|
+
clQ.size = 0;
|
|
1894
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1895
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1896
|
+
// dueToday: Tickets whose dueDate is today (format 'yyyy-MM-dd')
|
|
1897
|
+
let dueToday = 0;
|
|
1898
|
+
let todayDateString = new Date().toISOString().slice( 0, 10 );
|
|
1899
|
+
|
|
1900
|
+
// Build a query for tickets with mappingInfo.dueDate == todayDateString
|
|
1901
|
+
let dueTodayQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1902
|
+
// Locate nested mappingInfo query
|
|
1903
|
+
let nestedDue = dueTodayQuery.query.bool.must.find( ( m ) => m.nested );
|
|
1904
|
+
if ( nestedDue ) {
|
|
1905
|
+
// Remove any previous mappingInfo.dueDate term
|
|
1906
|
+
nestedDue.nested.query.bool.must = nestedDue.nested.query.bool.must.filter(
|
|
1907
|
+
( mustItem ) => !( mustItem.term && mustItem.term['mappingInfo.dueDate'] ),
|
|
1908
|
+
);
|
|
1909
|
+
// Add new dueDate filter
|
|
1910
|
+
nestedDue.nested.query.bool.must.push( {
|
|
1911
|
+
term: { 'mappingInfo.dueDate': todayDateString },
|
|
1912
|
+
} );
|
|
1913
|
+
}
|
|
1914
|
+
dueTodayQuery.size = 0;
|
|
1915
|
+
const dueTodayResp = await getOpenSearchData( openSearch.footfallDirectory, dueTodayQuery );
|
|
1916
|
+
dueToday = dueTodayResp?.body?.hits?.total?.value || 0;
|
|
1897
1917
|
|
|
1898
1918
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1919
|
+
// filter expired Tickets
|
|
1920
|
+
let expiredTickets = 0;
|
|
1901
1921
|
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1922
|
+
let eQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1923
|
+
eQ.size = 0;
|
|
1924
|
+
const eResp = await getOpenSearchData( openSearch.footfallDirectory, eQ );
|
|
1925
|
+
expiredTickets = eResp?.body?.hits?.total?.value || 0;
|
|
1906
1926
|
|
|
1907
|
-
|
|
1927
|
+
// filter under tango review
|
|
1908
1928
|
|
|
1909
|
-
|
|
1929
|
+
let undertangoTickets = 0;
|
|
1910
1930
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1931
|
+
let utrQ = buildStoreQueryWithStatus( baseStoreQuery, 'Under Tango Review' );
|
|
1932
|
+
utrQ.size = 0;
|
|
1933
|
+
const utrResp = await getOpenSearchData( openSearch.footfallDirectory, utrQ );
|
|
1934
|
+
undertangoTickets = utrResp?.body?.hits?.total?.value || 0;
|
|
1915
1935
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
{
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1936
|
+
let ticketPercentageAvg =0;
|
|
1937
|
+
let avgTicketPercentageQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1938
|
+
avgTicketPercentageQuery.size = 0;
|
|
1939
|
+
avgTicketPercentageQuery.aggs = {
|
|
1940
|
+
avg_ticket_percentage: {
|
|
1941
|
+
avg: {
|
|
1942
|
+
script: {
|
|
1943
|
+
source: `
|
|
1944
|
+
if (doc.containsKey('reviced') && doc['reviced'].size()!=0 &&
|
|
1945
|
+
doc.containsKey('footfallCount') && doc['footfallCount'].size()!=0 && doc['footfallCount'].value != 0) {
|
|
1946
|
+
return (doc['reviced'].value / doc['footfallCount'].value) * 100;
|
|
1947
|
+
} else {
|
|
1948
|
+
return null;
|
|
1949
|
+
}
|
|
1950
|
+
`,
|
|
1951
|
+
lang: 'painless',
|
|
1952
|
+
},
|
|
1928
1953
|
},
|
|
1929
1954
|
},
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1955
|
+
};
|
|
1932
1956
|
|
|
1933
|
-
|
|
1957
|
+
const avgTicketPercentageResp = await getOpenSearchData( openSearch.footfallDirectory, avgTicketPercentageQuery );
|
|
1934
1958
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1959
|
+
ticketPercentageAvg = avgTicketPercentageResp?.body?.aggregations?.avg_ticket_percentage?.value?.toFixed( 2 ) || '0';
|
|
1960
|
+
logger.info( { avgTicketPercentageResp } );
|
|
1961
|
+
let ticketAccuracy = 0;
|
|
1937
1962
|
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
{
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1957
|
-
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1958
|
-
|
|
1959
|
-
// Final result object
|
|
1960
|
-
result = {
|
|
1961
|
-
totalTickets,
|
|
1962
|
-
openTickets,
|
|
1963
|
-
inprogress,
|
|
1964
|
-
closedTickets,
|
|
1965
|
-
dueToday: dueToday,
|
|
1966
|
-
Expired: expiredTickets,
|
|
1967
|
-
underTangoReview: undertangoTickets,
|
|
1968
|
-
avgTicket: ticketAccuracyAbove+'%',
|
|
1969
|
-
avgAccuracy: ticketAccuracyBelow+'%',
|
|
1970
|
-
};
|
|
1963
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery );
|
|
1964
|
+
logger.info( { belowQ } );
|
|
1965
|
+
const accuracyResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1966
|
+
ticketAccuracy = accuracyResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1967
|
+
logger.info( { accuracyResp } );
|
|
1968
|
+
// Final result object
|
|
1969
|
+
result = {
|
|
1970
|
+
totalTickets,
|
|
1971
|
+
openTickets,
|
|
1972
|
+
inprogress,
|
|
1973
|
+
closedTickets,
|
|
1974
|
+
dueToday: dueToday,
|
|
1975
|
+
Expired: expiredTickets,
|
|
1976
|
+
underTangoReview: undertangoTickets,
|
|
1977
|
+
avgTicket: ticketPercentageAvg+'%',
|
|
1978
|
+
avgAccuracy: ticketAccuracy+'%',
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1971
1981
|
}
|
|
1972
1982
|
}
|
|
1973
1983
|
|
|
@@ -2209,7 +2219,6 @@ export async function ticketList( req, res ) {
|
|
|
2209
2219
|
const offset = inputData.offset == 0 ? 0 : ( inputData.offset - 1 ) * limit || 0;
|
|
2210
2220
|
inputData.clientId = inputData?.clientId?.split( ',' ); // convert strig to array
|
|
2211
2221
|
|
|
2212
|
-
|
|
2213
2222
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
2214
2223
|
|
|
2215
2224
|
const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
@@ -3034,6 +3043,8 @@ export async function ticketList( req, res ) {
|
|
|
3034
3043
|
'Approver (%)': item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3035
3044
|
'Tango (%)': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3036
3045
|
'Status': item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3046
|
+
'Comments': item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.comments || '--',
|
|
3047
|
+
'Sub Comments': item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.subComments || '--',
|
|
3037
3048
|
|
|
3038
3049
|
} );
|
|
3039
3050
|
}
|
|
@@ -3054,6 +3065,8 @@ export async function ticketList( req, res ) {
|
|
|
3054
3065
|
approverRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'approve' )?.revicedPerc || '--',
|
|
3055
3066
|
tangoRevisedAccuracy: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.revicedPerc || '--',
|
|
3056
3067
|
status: item?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.status || '--',
|
|
3068
|
+
comments: item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.comments || '--',
|
|
3069
|
+
subComments: item?.mappingInfo?.find( ( f ) => f.type === 'finalRevision' )?.subComments || '--',
|
|
3057
3070
|
|
|
3058
3071
|
} );
|
|
3059
3072
|
}
|
|
@@ -4891,7 +4904,7 @@ export async function updateUserTicketStatus( req, res ) {
|
|
|
4891
4904
|
|
|
4892
4905
|
const updatePayload = {
|
|
4893
4906
|
doc: {
|
|
4894
|
-
status: 'In
|
|
4907
|
+
status: lastEntry?.type == 'review'? 'Reviewer In progress':lastEntry?.type == 'approve'? 'Approver In progress':ticketSource?.status,
|
|
4895
4908
|
mappingInfo: updatedMappingInfo,
|
|
4896
4909
|
updatedAt: currentTime,
|
|
4897
4910
|
},
|