tango-app-api-infra 3.9.5-vms.77 → 3.9.5-vms.78
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
|
@@ -385,14 +385,11 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
385
385
|
|
|
386
386
|
let id = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
|
|
387
387
|
let getExistingOne = await getOpenSearchById( openSearch.footfallDirectory, id );
|
|
388
|
-
|
|
389
|
-
if ( inputData.ticketType === 'internal'&&!getExistingOne?.body?._source ) {
|
|
388
|
+
if ( inputData.ticketType === 'internal' &&!getExistingOne?.body?._source ) {
|
|
390
389
|
id = `${inputData.storeId}_${inputData.dateString}_internal_footfall-directory-tagging`;
|
|
391
390
|
}
|
|
392
391
|
|
|
393
|
-
|
|
394
392
|
const insertResult = await updateOpenSearchData( openSearch.footfallDirectory, id, { doc: record } );
|
|
395
|
-
console.log( insertResult );
|
|
396
393
|
|
|
397
394
|
if ( insertResult && ( insertResult.statusCode === 201 || insertResult.statusCode === 200 ) ) {
|
|
398
395
|
return res.sendSuccess( 'Ticket closed successfully' );
|
|
@@ -400,7 +397,6 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
400
397
|
return res.sendError( 'Internal Server Error', 500 );
|
|
401
398
|
}
|
|
402
399
|
} catch ( error ) {
|
|
403
|
-
console.log( '🚀 ~ tangoReviewTicket ~ error:', error );
|
|
404
400
|
const err = error.message || 'Internal Server Error';
|
|
405
401
|
logger.error( { error: error, funtion: 'tangoReviewTicket' } );
|
|
406
402
|
return res.sendError( err, 500 );
|
|
@@ -727,20 +723,858 @@ export async function ticketSummary1( req, res ) {
|
|
|
727
723
|
|
|
728
724
|
export async function ticketSummary( req, res ) {
|
|
729
725
|
try {
|
|
726
|
+
const inputData = req.query;
|
|
727
|
+
|
|
730
728
|
let result = '';
|
|
729
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
731
730
|
const userInfo = req.user;
|
|
732
731
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
732
|
+
const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
733
|
+
|
|
733
734
|
// const ticketsApproveFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
734
|
-
if ( req
|
|
735
|
+
if ( req?.user?.userType === 'tango' ) {
|
|
736
|
+
switch ( inputData?.tangoType ) {
|
|
737
|
+
case 'store':
|
|
738
|
+
const storeQuery = {
|
|
739
|
+
size: 0,
|
|
740
|
+
query: {
|
|
741
|
+
bool: {
|
|
742
|
+
must: [
|
|
743
|
+
{
|
|
744
|
+
'range': {
|
|
745
|
+
'dateString': {
|
|
746
|
+
'gte': inputData?.fromDate,
|
|
747
|
+
'lte': inputData?.toDate,
|
|
748
|
+
'format': 'yyyy-MM-dd',
|
|
749
|
+
},
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
nested: {
|
|
754
|
+
path: 'mappingInfo',
|
|
755
|
+
query: {
|
|
756
|
+
bool: {
|
|
757
|
+
must: [
|
|
758
|
+
{
|
|
759
|
+
term: {
|
|
760
|
+
'mappingInfo.type': 'tangoreview',
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
],
|
|
764
|
+
},
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
|
|
769
|
+
],
|
|
770
|
+
},
|
|
771
|
+
},
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
775
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
776
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
777
|
+
// Remove any previous mappingInfo.status term
|
|
778
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
779
|
+
if ( nested ) {
|
|
780
|
+
// filter out all mappingInfo.status
|
|
781
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
782
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
783
|
+
} );
|
|
784
|
+
// add desired status
|
|
785
|
+
nested.nested.query.bool.must.push( {
|
|
786
|
+
term: {
|
|
787
|
+
'mappingInfo.status': statusValue,
|
|
788
|
+
},
|
|
789
|
+
} );
|
|
790
|
+
}
|
|
791
|
+
return q;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
795
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
796
|
+
|
|
797
|
+
// locate nested section
|
|
798
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
799
|
+
|
|
800
|
+
if ( nested ) {
|
|
801
|
+
// remove old status filters
|
|
802
|
+
nested.nested.query.bool.must =
|
|
803
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
804
|
+
|
|
805
|
+
// add new filters
|
|
806
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return {
|
|
810
|
+
...q,
|
|
811
|
+
size: 0,
|
|
812
|
+
aggs: {
|
|
813
|
+
avg_value: {
|
|
814
|
+
avg: {
|
|
815
|
+
script: {
|
|
816
|
+
lang: 'painless',
|
|
817
|
+
source: `
|
|
818
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
819
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
820
|
+
try {
|
|
821
|
+
return Double.parseDouble(v);
|
|
822
|
+
} catch (Exception e) {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
`,
|
|
826
|
+
},
|
|
827
|
+
},
|
|
828
|
+
},
|
|
829
|
+
},
|
|
830
|
+
};
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
// Get OpenSearch connection
|
|
835
|
+
|
|
836
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
837
|
+
|
|
838
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
839
|
+
let totalTickets = 0;
|
|
840
|
+
|
|
841
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
842
|
+
|
|
843
|
+
allQuery.size = 0;
|
|
844
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
845
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
846
|
+
|
|
847
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
848
|
+
let openTickets = 0;
|
|
849
|
+
|
|
850
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
851
|
+
otQ.size = 0;
|
|
852
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
853
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
854
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
858
|
+
let openInfraIssues = 0;
|
|
859
|
+
|
|
860
|
+
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
861
|
+
oiQ.size = 0;
|
|
862
|
+
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
863
|
+
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
864
|
+
|
|
865
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
866
|
+
let inprogress = 0;
|
|
867
|
+
|
|
868
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
869
|
+
ipQ.size = 0;
|
|
870
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
871
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
872
|
+
|
|
873
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
874
|
+
let closedTickets = 0;
|
|
875
|
+
|
|
876
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
877
|
+
clQ.size = 0;
|
|
878
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
879
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
880
|
+
// Average revisedPerc (for all tangoreview)
|
|
881
|
+
let averageAccuracyOverAll = 0;
|
|
882
|
+
|
|
883
|
+
let avgQ = buildAggStoreQuery( baseStoreQuery );
|
|
884
|
+
const avgResp = await getOpenSearchData( openSearch.footfallDirectory, avgQ );
|
|
885
|
+
averageAccuracyOverAll = avgResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
886
|
+
|
|
887
|
+
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
888
|
+
let ticketAccuracyAbove = 0;
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
// For this, add a filter on revicedPerc >= 85
|
|
892
|
+
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
893
|
+
{
|
|
894
|
+
script: {
|
|
895
|
+
script: {
|
|
896
|
+
lang: 'painless',
|
|
897
|
+
source: `
|
|
898
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
899
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
900
|
+
`,
|
|
901
|
+
params: { num: 85 },
|
|
902
|
+
},
|
|
903
|
+
},
|
|
904
|
+
},
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
] );
|
|
908
|
+
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
909
|
+
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
910
|
+
|
|
911
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
912
|
+
let ticketAccuracyBelow = 0;
|
|
913
|
+
|
|
914
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
915
|
+
{
|
|
916
|
+
script: {
|
|
917
|
+
script: {
|
|
918
|
+
lang: 'painless',
|
|
919
|
+
source: `
|
|
920
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
921
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
922
|
+
`,
|
|
923
|
+
params: { num: 85 },
|
|
924
|
+
},
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
|
|
928
|
+
] );
|
|
929
|
+
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
930
|
+
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
931
|
+
|
|
932
|
+
// Final result object
|
|
933
|
+
result = {
|
|
934
|
+
totalTickets,
|
|
935
|
+
averageAccuracyOverAll: averageAccuracyOverAll+'%',
|
|
936
|
+
openTickets,
|
|
937
|
+
openInfraIssues,
|
|
938
|
+
inprogress,
|
|
939
|
+
closedTickets,
|
|
940
|
+
ticketAccuracyAbove: ticketAccuracyAbove+'%',
|
|
941
|
+
ticketAccuracyBelow: ticketAccuracyBelow+'%',
|
|
942
|
+
};
|
|
943
|
+
break;
|
|
944
|
+
case 'internal':
|
|
945
|
+
const internalQuery = {
|
|
946
|
+
size: 0,
|
|
947
|
+
query: {
|
|
948
|
+
bool: {
|
|
949
|
+
must: [
|
|
950
|
+
{
|
|
951
|
+
'range': {
|
|
952
|
+
'dateString': {
|
|
953
|
+
'gte': inputData?.fromDate,
|
|
954
|
+
'lte': inputData?.toDate,
|
|
955
|
+
'format': 'yyyy-MM-dd',
|
|
956
|
+
},
|
|
957
|
+
},
|
|
958
|
+
},
|
|
959
|
+
|
|
960
|
+
{
|
|
961
|
+
nested: {
|
|
962
|
+
path: 'mappingInfo',
|
|
963
|
+
query: {
|
|
964
|
+
bool: {
|
|
965
|
+
must: [
|
|
966
|
+
{
|
|
967
|
+
terms: {
|
|
968
|
+
'mappingInfo.type': [ 'tagging', 'review', 'approve', 'tangoreview' ],
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
],
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
},
|
|
975
|
+
},
|
|
976
|
+
|
|
977
|
+
],
|
|
978
|
+
},
|
|
979
|
+
},
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
983
|
+
function buildInternalQueryWithStatus( baseQuery, statusValue ) {
|
|
984
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
985
|
+
// Remove any previous mappingInfo.status term
|
|
986
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
987
|
+
if ( nested ) {
|
|
988
|
+
// filter out all mappingInfo.status
|
|
989
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
990
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
991
|
+
} );
|
|
992
|
+
// add desired status
|
|
993
|
+
nested.nested.query.bool.must.push( {
|
|
994
|
+
term: {
|
|
995
|
+
'mappingInfo.status': statusValue,
|
|
996
|
+
},
|
|
997
|
+
} );
|
|
998
|
+
}
|
|
999
|
+
return q;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
const buildAggInternalQuery = ( baseQuery, filters = [] ) => {
|
|
1003
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1004
|
+
|
|
1005
|
+
// locate nested section
|
|
1006
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1007
|
+
|
|
1008
|
+
if ( nested ) {
|
|
1009
|
+
// remove old status filters
|
|
1010
|
+
nested.nested.query.bool.must =
|
|
1011
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1012
|
+
|
|
1013
|
+
// add new filters
|
|
1014
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
return {
|
|
1018
|
+
...q,
|
|
1019
|
+
size: 0,
|
|
1020
|
+
aggs: {
|
|
1021
|
+
avg_value: {
|
|
1022
|
+
avg: {
|
|
1023
|
+
script: {
|
|
1024
|
+
lang: 'painless',
|
|
1025
|
+
source: `
|
|
1026
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1027
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1028
|
+
try {
|
|
1029
|
+
return Double.parseDouble(v);
|
|
1030
|
+
} catch (Exception e) {
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
`,
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
},
|
|
1037
|
+
},
|
|
1038
|
+
};
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
// Get OpenSearch connection
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
const baseInternalQuery = JSON.parse( JSON.stringify( internalQuery ) );
|
|
1046
|
+
|
|
1047
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1048
|
+
let totalInternalTickets = 0;
|
|
1049
|
+
|
|
1050
|
+
let allInternalQuery = JSON.parse( JSON.stringify( baseInternalQuery ) );
|
|
1051
|
+
|
|
1052
|
+
allInternalQuery.size = 0;
|
|
1053
|
+
const totalInternalResp = await getOpenSearchData( openSearch.footfallDirectory, allInternalQuery );
|
|
1054
|
+
totalInternalTickets = totalInternalResp?.body?.hits?.total?.value || 0;
|
|
1055
|
+
|
|
1056
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1057
|
+
let openInternalTickets = 0;
|
|
1058
|
+
|
|
1059
|
+
let otQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open' );
|
|
1060
|
+
otQInternal.size = 0;
|
|
1061
|
+
const openInternalResp = await getOpenSearchData( openSearch.footfallDirectory, otQInternal );
|
|
1062
|
+
openInternalTickets = openInternalResp?.body?.hits?.total?.value || 0;
|
|
1063
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1067
|
+
let openInternalInfraIssues = 0;
|
|
1068
|
+
|
|
1069
|
+
let oiQinternal = buildInternalQueryWithStatus( baseInternalQuery, 'Open Accuracy Issue' );
|
|
1070
|
+
oiQinternal.size = 0;
|
|
1071
|
+
const infraInternalResp = await getOpenSearchData( openSearch.footfallDirectory, oiQinternal );
|
|
1072
|
+
openInternalInfraIssues = infraInternalResp?.body?.hits?.total?.value || 0;
|
|
1073
|
+
|
|
1074
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1075
|
+
let inprogressIntrenal = 0;
|
|
1076
|
+
|
|
1077
|
+
let ipQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'In-Progress' );
|
|
1078
|
+
ipQInternal.size = 0;
|
|
1079
|
+
const ipInternalResp = await getOpenSearchData( openSearch.footfallDirectory, ipQInternal );
|
|
1080
|
+
inprogressIntrenal = ipInternalResp?.body?.hits?.total?.value || 0;
|
|
1081
|
+
|
|
1082
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1083
|
+
let closedInternalTickets = 0;
|
|
1084
|
+
|
|
1085
|
+
let clQInternal = buildInternalQueryWithStatus( baseInternalQuery, 'Closed' );
|
|
1086
|
+
clQInternal.size = 0;
|
|
1087
|
+
const clInternalResp = await getOpenSearchData( openSearch.footfallDirectory, clQInternal );
|
|
1088
|
+
closedInternalTickets = clInternalResp?.body?.hits?.total?.value || 0;
|
|
1089
|
+
// Average revisedPerc (for all tangoreview)
|
|
1090
|
+
let internalAverageAccuracyOverAll = 0;
|
|
1091
|
+
|
|
1092
|
+
let avgQInternal = buildAggInternalQuery( baseInternalQuery );
|
|
1093
|
+
const avgInternalResp = await getOpenSearchData( openSearch.footfallDirectory, avgQInternal );
|
|
1094
|
+
internalAverageAccuracyOverAll = avgInternalResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1095
|
+
|
|
1096
|
+
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
1097
|
+
let internalTicketAccuracyAbove = 0;
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
// For this, add a filter on revicedPerc >= 85
|
|
1101
|
+
let aboveQinternal = buildAggInternalQuery( baseInternalQuery, [
|
|
1102
|
+
{
|
|
1103
|
+
script: {
|
|
1104
|
+
script: {
|
|
1105
|
+
lang: 'painless',
|
|
1106
|
+
source: `
|
|
1107
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1108
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1109
|
+
`,
|
|
1110
|
+
params: { num: 85 },
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
},
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
] );
|
|
1117
|
+
const aboveRespInternal = await getOpenSearchData( openSearch.footfallDirectory, aboveQinternal );
|
|
1118
|
+
internalTicketAccuracyAbove = aboveRespInternal?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1119
|
+
|
|
1120
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1121
|
+
let internalTicketAccuracyBelow = 0;
|
|
1122
|
+
|
|
1123
|
+
let belowQIneranl = buildAggInternalQuery( baseInternalQuery, [
|
|
1124
|
+
{
|
|
1125
|
+
script: {
|
|
1126
|
+
script: {
|
|
1127
|
+
lang: 'painless',
|
|
1128
|
+
source: `
|
|
1129
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1130
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1131
|
+
`,
|
|
1132
|
+
params: { num: 85 },
|
|
1133
|
+
},
|
|
1134
|
+
},
|
|
1135
|
+
},
|
|
1136
|
+
|
|
1137
|
+
] );
|
|
1138
|
+
const belowRespInternal = await getOpenSearchData( openSearch.footfallDirectory, belowQIneranl );
|
|
1139
|
+
internalTicketAccuracyBelow = belowRespInternal?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1140
|
+
|
|
1141
|
+
// Final result object
|
|
1142
|
+
result = {
|
|
1143
|
+
totalTickets: totalInternalTickets,
|
|
1144
|
+
averageAccuracyOverAll: internalAverageAccuracyOverAll+'%',
|
|
1145
|
+
openTickets: openInternalTickets,
|
|
1146
|
+
openInfraIssues: openInternalInfraIssues,
|
|
1147
|
+
inprogress: inprogressIntrenal,
|
|
1148
|
+
closedTickets: closedInternalTickets,
|
|
1149
|
+
ticketAccuracyAbove: internalTicketAccuracyAbove+'%',
|
|
1150
|
+
ticketAccuracyBelow: internalTicketAccuracyBelow+'%',
|
|
1151
|
+
};
|
|
1152
|
+
break;
|
|
1153
|
+
default: '';
|
|
1154
|
+
}
|
|
1155
|
+
// result = {
|
|
1156
|
+
// totalTickets: 0,
|
|
1157
|
+
// averageAccuracyOverAll: 0,
|
|
1158
|
+
// openTickets: 0,
|
|
1159
|
+
// openInfraIssues: 0,
|
|
1160
|
+
// inprogress: 0,
|
|
1161
|
+
// closedTickets: 0,
|
|
1162
|
+
// ticketAccuracyAbove: '0%',
|
|
1163
|
+
// ticketAccuracyBelow: '0%',
|
|
1164
|
+
// };
|
|
1165
|
+
} else if ( req?.user?.userType === 'client' ) {
|
|
1166
|
+
if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1167
|
+
const storeQuery = {
|
|
1168
|
+
size: 0,
|
|
1169
|
+
query: {
|
|
1170
|
+
bool: {
|
|
1171
|
+
must: [
|
|
1172
|
+
{
|
|
1173
|
+
'range': {
|
|
1174
|
+
'dateString': {
|
|
1175
|
+
'gte': inputData?.fromDate,
|
|
1176
|
+
'lte': inputData?.toDate,
|
|
1177
|
+
'format': 'yyyy-MM-dd',
|
|
1178
|
+
},
|
|
1179
|
+
},
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
nested: {
|
|
1183
|
+
path: 'mappingInfo',
|
|
1184
|
+
query: {
|
|
1185
|
+
bool: {
|
|
1186
|
+
must: [
|
|
1187
|
+
{
|
|
1188
|
+
term: {
|
|
1189
|
+
'mappingInfo.type': 'review',
|
|
1190
|
+
},
|
|
1191
|
+
},
|
|
1192
|
+
],
|
|
1193
|
+
},
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1197
|
+
|
|
1198
|
+
],
|
|
1199
|
+
},
|
|
1200
|
+
},
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1204
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1205
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1206
|
+
// Remove any previous mappingInfo.status term
|
|
1207
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1208
|
+
if ( nested ) {
|
|
1209
|
+
// filter out all mappingInfo.status
|
|
1210
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1211
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1212
|
+
} );
|
|
1213
|
+
// add desired status
|
|
1214
|
+
nested.nested.query.bool.must.push( {
|
|
1215
|
+
term: {
|
|
1216
|
+
'mappingInfo.status': statusValue,
|
|
1217
|
+
},
|
|
1218
|
+
} );
|
|
1219
|
+
}
|
|
1220
|
+
return q;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1224
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1225
|
+
|
|
1226
|
+
// locate nested section
|
|
1227
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1228
|
+
|
|
1229
|
+
if ( nested ) {
|
|
1230
|
+
// remove old status filters
|
|
1231
|
+
nested.nested.query.bool.must =
|
|
1232
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1233
|
+
|
|
1234
|
+
// add new filters
|
|
1235
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
return {
|
|
1239
|
+
...q,
|
|
1240
|
+
size: 0,
|
|
1241
|
+
aggs: {
|
|
1242
|
+
avg_value: {
|
|
1243
|
+
avg: {
|
|
1244
|
+
script: {
|
|
1245
|
+
lang: 'painless',
|
|
1246
|
+
source: `
|
|
1247
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1248
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1249
|
+
try {
|
|
1250
|
+
return Double.parseDouble(v);
|
|
1251
|
+
} catch (Exception e) {
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
`,
|
|
1255
|
+
},
|
|
1256
|
+
},
|
|
1257
|
+
},
|
|
1258
|
+
},
|
|
1259
|
+
};
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
// Get OpenSearch connection
|
|
1264
|
+
|
|
1265
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1266
|
+
|
|
1267
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1268
|
+
let totalTickets = 0;
|
|
1269
|
+
|
|
1270
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1271
|
+
|
|
1272
|
+
allQuery.size = 0;
|
|
1273
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1274
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1275
|
+
|
|
1276
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1277
|
+
let openTickets = 0;
|
|
1278
|
+
|
|
1279
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1280
|
+
otQ.size = 0;
|
|
1281
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1282
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1283
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1287
|
+
let openInfraIssues = 0;
|
|
1288
|
+
|
|
1289
|
+
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1290
|
+
oiQ.size = 0;
|
|
1291
|
+
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1292
|
+
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1293
|
+
|
|
1294
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1295
|
+
let inprogress = 0;
|
|
1296
|
+
|
|
1297
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1298
|
+
ipQ.size = 0;
|
|
1299
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1300
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1301
|
+
|
|
1302
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1303
|
+
let closedTickets = 0;
|
|
1304
|
+
|
|
1305
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1306
|
+
clQ.size = 0;
|
|
1307
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1308
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1309
|
+
// Average revisedPerc (for all tangoreview)
|
|
1310
|
+
let averageAccuracyOverAll = 0;
|
|
1311
|
+
|
|
1312
|
+
let avgQ = buildAggStoreQuery( baseStoreQuery );
|
|
1313
|
+
const avgResp = await getOpenSearchData( openSearch.footfallDirectory, avgQ );
|
|
1314
|
+
averageAccuracyOverAll = avgResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1315
|
+
|
|
1316
|
+
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
1317
|
+
let ticketAccuracyAbove = 0;
|
|
1318
|
+
|
|
1319
|
+
|
|
1320
|
+
// For this, add a filter on revicedPerc >= 85
|
|
1321
|
+
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1322
|
+
{
|
|
1323
|
+
script: {
|
|
1324
|
+
script: {
|
|
1325
|
+
lang: 'painless',
|
|
1326
|
+
source: `
|
|
1327
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1328
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1329
|
+
`,
|
|
1330
|
+
params: { num: 85 },
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
},
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
] );
|
|
1337
|
+
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1338
|
+
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1339
|
+
|
|
1340
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1341
|
+
let ticketAccuracyBelow = 0;
|
|
1342
|
+
|
|
1343
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1344
|
+
{
|
|
1345
|
+
script: {
|
|
1346
|
+
script: {
|
|
1347
|
+
lang: 'painless',
|
|
1348
|
+
source: `
|
|
1349
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1350
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1351
|
+
`,
|
|
1352
|
+
params: { num: 85 },
|
|
1353
|
+
},
|
|
1354
|
+
},
|
|
1355
|
+
},
|
|
1356
|
+
|
|
1357
|
+
] );
|
|
1358
|
+
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1359
|
+
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1360
|
+
|
|
1361
|
+
// Final result object
|
|
1362
|
+
result = {
|
|
1363
|
+
totalTickets,
|
|
1364
|
+
averageAccuracyOverAll: averageAccuracyOverAll+'%',
|
|
1365
|
+
openTickets,
|
|
1366
|
+
openInfraIssues,
|
|
1367
|
+
inprogress,
|
|
1368
|
+
closedTickets,
|
|
1369
|
+
ticketAccuracyAbove: ticketAccuracyAbove+'%',
|
|
1370
|
+
ticketAccuracyBelow: ticketAccuracyBelow+'%',
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
} else if ( ticketsFeature && !ticketsApproveFeature ) {
|
|
1374
|
+
const storeQuery = {
|
|
1375
|
+
size: 0,
|
|
1376
|
+
query: {
|
|
1377
|
+
bool: {
|
|
1378
|
+
must: [
|
|
1379
|
+
{
|
|
1380
|
+
'range': {
|
|
1381
|
+
'dateString': {
|
|
1382
|
+
'gte': inputData?.fromDate,
|
|
1383
|
+
'lte': inputData?.toDate,
|
|
1384
|
+
'format': 'yyyy-MM-dd',
|
|
1385
|
+
},
|
|
1386
|
+
},
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
nested: {
|
|
1390
|
+
path: 'mappingInfo',
|
|
1391
|
+
query: {
|
|
1392
|
+
bool: {
|
|
1393
|
+
must: [
|
|
1394
|
+
{
|
|
1395
|
+
term: {
|
|
1396
|
+
'mappingInfo.type': inputData.permissionType === 'review'? 'review':'approve',
|
|
1397
|
+
},
|
|
1398
|
+
},
|
|
1399
|
+
],
|
|
1400
|
+
},
|
|
1401
|
+
},
|
|
1402
|
+
},
|
|
1403
|
+
},
|
|
1404
|
+
|
|
1405
|
+
],
|
|
1406
|
+
},
|
|
1407
|
+
},
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
// Helper function to clone deep and replace mappingInfo.status for openTickets/closed/etc
|
|
1411
|
+
function buildStoreQueryWithStatus( baseQuery, statusValue ) {
|
|
1412
|
+
let q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1413
|
+
// Remove any previous mappingInfo.status term
|
|
1414
|
+
let nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1415
|
+
if ( nested ) {
|
|
1416
|
+
// filter out all mappingInfo.status
|
|
1417
|
+
nested.nested.query.bool.must = nested?.nested?.query?.bool?.must.filter( ( mustItem ) => {
|
|
1418
|
+
return !( mustItem.term && mustItem.term['mappingInfo.status'] );
|
|
1419
|
+
} );
|
|
1420
|
+
// add desired status
|
|
1421
|
+
nested.nested.query.bool.must.push( {
|
|
1422
|
+
term: {
|
|
1423
|
+
'mappingInfo.status': statusValue,
|
|
1424
|
+
},
|
|
1425
|
+
} );
|
|
1426
|
+
}
|
|
1427
|
+
return q;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
const buildAggStoreQuery = ( baseQuery, filters = [] ) => {
|
|
1431
|
+
const q = JSON.parse( JSON.stringify( baseQuery ) );
|
|
1432
|
+
|
|
1433
|
+
// locate nested section
|
|
1434
|
+
const nested = q.query.bool.must.find( ( m ) => m.nested );
|
|
1435
|
+
|
|
1436
|
+
if ( nested ) {
|
|
1437
|
+
// remove old status filters
|
|
1438
|
+
nested.nested.query.bool.must =
|
|
1439
|
+
nested.nested.query.bool.must.filter( ( m ) => !( m.term && m.term['mappingInfo.status'] ) );
|
|
1440
|
+
|
|
1441
|
+
// add new filters
|
|
1442
|
+
nested.nested.query.bool.must.push( ...filters );
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
return {
|
|
1446
|
+
...q,
|
|
1447
|
+
size: 0,
|
|
1448
|
+
aggs: {
|
|
1449
|
+
avg_value: {
|
|
1450
|
+
avg: {
|
|
1451
|
+
script: {
|
|
1452
|
+
lang: 'painless',
|
|
1453
|
+
source: `
|
|
1454
|
+
if (doc['revicedPerc.keyword'].size() == 0) return null;
|
|
1455
|
+
String v = doc['revicedPerc.keyword'].value.replace('%','');
|
|
1456
|
+
try {
|
|
1457
|
+
return Double.parseDouble(v);
|
|
1458
|
+
} catch (Exception e) {
|
|
1459
|
+
return null;
|
|
1460
|
+
}
|
|
1461
|
+
`,
|
|
1462
|
+
},
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
1467
|
+
};
|
|
1468
|
+
|
|
1469
|
+
|
|
1470
|
+
// Get OpenSearch connection
|
|
1471
|
+
|
|
1472
|
+
const baseStoreQuery = JSON.parse( JSON.stringify( storeQuery ) );
|
|
1473
|
+
|
|
1474
|
+
// Total Tickets (all tickets with mappingInfo.type == tangoreview)
|
|
1475
|
+
let totalTickets = 0;
|
|
1476
|
+
|
|
1477
|
+
let allQuery = JSON.parse( JSON.stringify( baseStoreQuery ) );
|
|
1478
|
+
|
|
1479
|
+
allQuery.size = 0;
|
|
1480
|
+
const totalResp = await getOpenSearchData( openSearch.footfallDirectory, allQuery );
|
|
1481
|
+
totalTickets = totalResp?.body?.hits?.total?.value || 0;
|
|
1482
|
+
|
|
1483
|
+
// openTickets: mappingInfo.status: 'Open'
|
|
1484
|
+
let openTickets = 0;
|
|
1485
|
+
|
|
1486
|
+
let otQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open' );
|
|
1487
|
+
otQ.size = 0;
|
|
1488
|
+
const openResp = await getOpenSearchData( openSearch.footfallDirectory, otQ );
|
|
1489
|
+
openTickets = openResp?.body?.hits?.total?.value || 0;
|
|
1490
|
+
// logger.info( { msd: '..............2', openResp } );
|
|
1491
|
+
|
|
1492
|
+
|
|
1493
|
+
// openInfraIssues: mappingInfo.status: 'Open Accuracy Issue'
|
|
1494
|
+
let openInfraIssues = 0;
|
|
1495
|
+
|
|
1496
|
+
let oiQ = buildStoreQueryWithStatus( baseStoreQuery, 'Open Accuracy Issue' );
|
|
1497
|
+
oiQ.size = 0;
|
|
1498
|
+
const infraResp = await getOpenSearchData( openSearch.footfallDirectory, oiQ );
|
|
1499
|
+
openInfraIssues = infraResp?.body?.hits?.total?.value || 0;
|
|
1500
|
+
|
|
1501
|
+
// inprogress: mappingInfo.status: 'in-Progress'
|
|
1502
|
+
let inprogress = 0;
|
|
1503
|
+
|
|
1504
|
+
let ipQ = buildStoreQueryWithStatus( baseStoreQuery, 'In-Progress' );
|
|
1505
|
+
ipQ.size = 0;
|
|
1506
|
+
const ipResp = await getOpenSearchData( openSearch.footfallDirectory, ipQ );
|
|
1507
|
+
inprogress = ipResp?.body?.hits?.total?.value || 0;
|
|
1508
|
+
|
|
1509
|
+
// closedTickets: mappingInfo.status: 'closed'
|
|
1510
|
+
let closedTickets = 0;
|
|
1511
|
+
|
|
1512
|
+
let clQ = buildStoreQueryWithStatus( baseStoreQuery, 'Closed' );
|
|
1513
|
+
clQ.size = 0;
|
|
1514
|
+
const clResp = await getOpenSearchData( openSearch.footfallDirectory, clQ );
|
|
1515
|
+
closedTickets = clResp?.body?.hits?.total?.value || 0;
|
|
1516
|
+
// Average revisedPerc (for all tangoreview)
|
|
1517
|
+
let averageAccuracyOverAll = 0;
|
|
1518
|
+
|
|
1519
|
+
let avgQ = buildAggStoreQuery( baseStoreQuery );
|
|
1520
|
+
const avgResp = await getOpenSearchData( openSearch.footfallDirectory, avgQ );
|
|
1521
|
+
averageAccuracyOverAll = avgResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1522
|
+
|
|
1523
|
+
// ticketAccuracyAbove: avg of revicedPerc > 85%
|
|
1524
|
+
let ticketAccuracyAbove = 0;
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
// For this, add a filter on revicedPerc >= 85
|
|
1528
|
+
let aboveQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1529
|
+
{
|
|
1530
|
+
script: {
|
|
1531
|
+
script: {
|
|
1532
|
+
lang: 'painless',
|
|
1533
|
+
source: `
|
|
1534
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1535
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) >= params.num
|
|
1536
|
+
`,
|
|
1537
|
+
params: { num: 85 },
|
|
1538
|
+
},
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
] );
|
|
1544
|
+
const aboveResp = await getOpenSearchData( openSearch.footfallDirectory, aboveQ );
|
|
1545
|
+
ticketAccuracyAbove = aboveResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1546
|
+
|
|
1547
|
+
// ticketAccuracyBelow: avg of revicedPerc < 85%
|
|
1548
|
+
let ticketAccuracyBelow = 0;
|
|
1549
|
+
|
|
1550
|
+
let belowQ = buildAggStoreQuery( baseStoreQuery, [
|
|
1551
|
+
{
|
|
1552
|
+
script: {
|
|
1553
|
+
script: {
|
|
1554
|
+
lang: 'painless',
|
|
1555
|
+
source: `
|
|
1556
|
+
doc['revicedPerc.keyword'].size()!=0 &&
|
|
1557
|
+
Integer.parseInt(doc['revicedPerc.keyword'].value.replace('%','')) < params.num
|
|
1558
|
+
`,
|
|
1559
|
+
params: { num: 85 },
|
|
1560
|
+
},
|
|
1561
|
+
},
|
|
1562
|
+
},
|
|
1563
|
+
|
|
1564
|
+
] );
|
|
1565
|
+
const belowResp = await getOpenSearchData( openSearch.footfallDirectory, belowQ );
|
|
1566
|
+
ticketAccuracyBelow = belowResp?.body?.aggregations?.avg_value?.value?.toFixed( 2 ) || '0';
|
|
1567
|
+
|
|
1568
|
+
// Final result object
|
|
735
1569
|
result = {
|
|
736
|
-
totalTickets
|
|
737
|
-
averageAccuracyOverAll:
|
|
738
|
-
openTickets
|
|
739
|
-
openInfraIssues
|
|
740
|
-
inprogress
|
|
741
|
-
closedTickets
|
|
742
|
-
ticketAccuracyAbove: '
|
|
743
|
-
ticketAccuracyBelow: '
|
|
1570
|
+
totalTickets,
|
|
1571
|
+
averageAccuracyOverAll: averageAccuracyOverAll+'%',
|
|
1572
|
+
openTickets,
|
|
1573
|
+
openInfraIssues,
|
|
1574
|
+
inprogress,
|
|
1575
|
+
closedTickets,
|
|
1576
|
+
ticketAccuracyAbove: ticketAccuracyAbove+'%',
|
|
1577
|
+
ticketAccuracyBelow: ticketAccuracyBelow+'%',
|
|
744
1578
|
};
|
|
745
1579
|
} else {
|
|
746
1580
|
result = req.user.role === 'superadmin' ?
|
|
@@ -1326,6 +2160,87 @@ export async function ticketList( req, res ) {
|
|
|
1326
2160
|
}
|
|
1327
2161
|
}
|
|
1328
2162
|
|
|
2163
|
+
if ( inputData?.filterByStore && inputData?.filterByStore !== '' ) {
|
|
2164
|
+
let percQuery = null;
|
|
2165
|
+
const value = inputData.filterByStore;
|
|
2166
|
+
|
|
2167
|
+
// Helper function: remove trailing '%' and convert to number
|
|
2168
|
+
const percValue = ( val ) => {
|
|
2169
|
+
if ( typeof val === 'string' ) {
|
|
2170
|
+
return parseFloat( val.replace( '%', '' ).trim() );
|
|
2171
|
+
}
|
|
2172
|
+
return parseFloat( val );
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
// Example filter values: "<90", "<=90", ">=90", "50 to 90"
|
|
2176
|
+
if ( /^<=?\d+$/.test( value ) ) {
|
|
2177
|
+
// "<90" or "<=90"
|
|
2178
|
+
const num = percValue( value.replace( /[^\d]/g, '' ) );
|
|
2179
|
+
const op = value.includes( '=' ) ? 'lte' : 'lt';
|
|
2180
|
+
percQuery = {
|
|
2181
|
+
script: {
|
|
2182
|
+
script: {
|
|
2183
|
+
source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'lt' ? '<' : '<='} params.num`,
|
|
2184
|
+
params: { num },
|
|
2185
|
+
},
|
|
2186
|
+
},
|
|
2187
|
+
};
|
|
2188
|
+
} else if ( /^>=?\d+$/.test( value ) ) {
|
|
2189
|
+
// ">=90"
|
|
2190
|
+
const num = percValue( value.replace( /[^\d]/g, '' ) );
|
|
2191
|
+
const op = value.includes( '=' ) ? 'gte' : 'gt';
|
|
2192
|
+
percQuery = {
|
|
2193
|
+
script: {
|
|
2194
|
+
script: {
|
|
2195
|
+
source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'gt' ? '>' : '>='} params.num`,
|
|
2196
|
+
params: { num },
|
|
2197
|
+
},
|
|
2198
|
+
},
|
|
2199
|
+
};
|
|
2200
|
+
} else if ( /^(\d+)\s*to\s*(\d+)$/.test( value ) ) {
|
|
2201
|
+
// "50 to 90"
|
|
2202
|
+
const match = value.match( /^(\d+)\s*to\s*(\d+)$/ );
|
|
2203
|
+
const from = percValue( match[1] );
|
|
2204
|
+
const to = percValue( match[2] );
|
|
2205
|
+
percQuery = {
|
|
2206
|
+
script: {
|
|
2207
|
+
script: {
|
|
2208
|
+
source:
|
|
2209
|
+
`doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) >= params.from && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) <= params.to`,
|
|
2210
|
+
params: { from, to },
|
|
2211
|
+
},
|
|
2212
|
+
},
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
// fallback: treat as exact match (e.g., "90")
|
|
2216
|
+
if ( !percQuery && /^\d+$/.test( value ) ) {
|
|
2217
|
+
percQuery = {
|
|
2218
|
+
script: {
|
|
2219
|
+
script: {
|
|
2220
|
+
source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) == params.num`,
|
|
2221
|
+
params: { num: percValue( value ) },
|
|
2222
|
+
},
|
|
2223
|
+
},
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
if ( percQuery ) {
|
|
2228
|
+
searchQuery.query.bool.must.push( {
|
|
2229
|
+
nested: {
|
|
2230
|
+
path: 'mappingInfo',
|
|
2231
|
+
query: {
|
|
2232
|
+
bool: {
|
|
2233
|
+
must: [
|
|
2234
|
+
{ term: { 'mappingInfo.type': 'tagging' } },
|
|
2235
|
+
percQuery,
|
|
2236
|
+
],
|
|
2237
|
+
},
|
|
2238
|
+
},
|
|
2239
|
+
},
|
|
2240
|
+
} );
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
1329
2244
|
if ( inputData?.filterByReviewer && inputData?.filterByReviewer !== '' ) {
|
|
1330
2245
|
let percQuery = null;
|
|
1331
2246
|
const value = inputData.filterByReviewer;
|
|
@@ -1633,7 +2548,7 @@ export async function ticketList( req, res ) {
|
|
|
1633
2548
|
|
|
1634
2549
|
|
|
1635
2550
|
);
|
|
1636
|
-
} else if ( req?.user?.userType === 'client'
|
|
2551
|
+
} else if ( req?.user?.userType === 'client' ) {
|
|
1637
2552
|
searchQuery.query.bool.must.push(
|
|
1638
2553
|
{
|
|
1639
2554
|
term: {
|
|
@@ -2666,7 +3581,7 @@ export async function getTaggedStores( req, res ) {
|
|
|
2666
3581
|
+ (doc.containsKey('employeeCount') && !doc['employeeCount'].empty ? doc['employeeCount'].value : 0)
|
|
2667
3582
|
+ (doc.containsKey('junkCount') && !doc['junkCount'].empty ? doc['junkCount'].value : 0);
|
|
2668
3583
|
`,
|
|
2669
|
-
lang: '
|
|
3584
|
+
lang: 'scripting',
|
|
2670
3585
|
},
|
|
2671
3586
|
},
|
|
2672
3587
|
},
|
|
@@ -3076,6 +3991,7 @@ export async function reviewerList( req, res ) {
|
|
|
3076
3991
|
export async function openTicketList( req, res ) {
|
|
3077
3992
|
try {
|
|
3078
3993
|
const inputData = req.body;
|
|
3994
|
+
logger.info( { inputData } );
|
|
3079
3995
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
3080
3996
|
|
|
3081
3997
|
// INSERT_YOUR_CODE
|
|
@@ -86,7 +86,8 @@ export const tangoReviewAccuracyClosedTicketValid = {
|
|
|
86
86
|
|
|
87
87
|
export const ticketSummarySchema = Joi.object().keys( {
|
|
88
88
|
clientId: Joi.string().required(),
|
|
89
|
-
|
|
89
|
+
tangoType: Joi.string().valid( 'store', 'internal' ).optional(),
|
|
90
|
+
permissionType: Joi.string().valid( 'approve', 'review' ).optional(),
|
|
90
91
|
fromDate: Joi.string()
|
|
91
92
|
.pattern( /^\d{4}-\d{2}-\d{2}$/, 'YYYY-MM-DD format' )
|
|
92
93
|
.required()
|
|
@@ -159,6 +160,7 @@ export const ticketListSchema = Joi.object().keys( {
|
|
|
159
160
|
tangoType: Joi.string().valid( 'store', 'internal', '' ).optional(),
|
|
160
161
|
permissionType: Joi.string().valid( 'review', 'approve' ).optional(),
|
|
161
162
|
filterByStatus: Joi.string().optional().allow( '' ),
|
|
163
|
+
filterByStore: Joi.string().optional().allow( '' ),
|
|
162
164
|
filterByReviewer: Joi.string().optional().allow( '' ),
|
|
163
165
|
filterByApprover: Joi.string().optional().allow( '' ),
|
|
164
166
|
filterByTango: Joi.string().optional().allow( '' ),
|