tango-app-api-trax 3.9.68 → 3.9.69
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
|
@@ -69,12 +69,45 @@ export async function viewchecklist( req, res ) {
|
|
|
69
69
|
try {
|
|
70
70
|
let url = JSON.parse( process.env.LAMBDAURL );
|
|
71
71
|
let resultData = await LamdaServiceCall( url.checklistAnswer, req.body );
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// Guard before touching resultData — LamdaServiceCall returns false on failure.
|
|
73
|
+
if ( !resultData ) {
|
|
74
|
+
return res.sendError( 'No Content', 204 );
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const answers = resultData.checklistAnswers || [];
|
|
78
|
+
// Enrich each answer with its store's SPOC email. Batch every store lookup
|
|
79
|
+
// into a single $in query (one round-trip instead of one per answer), indexed
|
|
80
|
+
// by storeId for an in-memory lookup below.
|
|
81
|
+
const storeIds = [ ...new Set(
|
|
82
|
+
answers
|
|
83
|
+
.filter( ( ele ) => ele?.storeProfile?.storeName && ele?.storeProfile?.store_id )
|
|
84
|
+
.map( ( ele ) => ele?.storeProfile?.store_id ),
|
|
85
|
+
) ];
|
|
86
|
+
const spocEmailByStoreId = {};
|
|
87
|
+
if ( storeIds.length ) {
|
|
88
|
+
const storeDetails = await storeService.find(
|
|
89
|
+
{ storeId: { $in: storeIds } },
|
|
90
|
+
{ storeId: 1, spocDetails: 1 },
|
|
91
|
+
);
|
|
92
|
+
storeDetails?.forEach( ( store ) => {
|
|
93
|
+
if ( store.spocDetails?.[0]?.email ) {
|
|
94
|
+
spocEmailByStoreId[store.storeId] = { email: store.spocDetails?.[0]?.email, name: store.spocDetails?.[0]?.name };
|
|
95
|
+
}
|
|
96
|
+
} );
|
|
97
|
+
}
|
|
98
|
+
// Keep every answer; only attach the SPOC email when we found one.
|
|
99
|
+
resultData.checklistAnswers = answers.map( ( ele ) => {
|
|
100
|
+
ele.storeProfile.userList = [ { name: ele.storeProfile.userName, email: ele.storeProfile.userEmail } ];
|
|
101
|
+
if ( ele?.storeProfile?.storeName && spocEmailByStoreId[ele?.storeProfile?.store_id] ) {
|
|
102
|
+
if ( !ele.storeProfile.userList.find( ( list ) => list.email == spocEmailByStoreId[ele?.storeProfile?.store_id]?.email ) ) {
|
|
103
|
+
ele.storeProfile.userList.push( { name: spocEmailByStoreId[ele?.storeProfile?.store_id]?.name, email: spocEmailByStoreId[ele?.storeProfile?.store_id]?.email } );
|
|
104
|
+
}
|
|
77
105
|
}
|
|
106
|
+
return ele;
|
|
107
|
+
} );
|
|
108
|
+
|
|
109
|
+
if ( resultData.status_code == '200' ) {
|
|
110
|
+
return res.sendSuccess( resultData );
|
|
78
111
|
} else {
|
|
79
112
|
return res.sendError( 'No Content', 204 );
|
|
80
113
|
}
|
|
@@ -451,7 +484,7 @@ export async function redoChecklist( req, res ) {
|
|
|
451
484
|
|
|
452
485
|
let findQuestion = question[sectionIndex].questions.findIndex( ( ele ) => ele.qno == req.body.payload.qno );
|
|
453
486
|
|
|
454
|
-
let data = { ...question[sectionIndex].questions[findQuestion], redo: true,
|
|
487
|
+
let data = { ...question[sectionIndex].questions[findQuestion], redo: true, ...( !req.body.payload?.answerIndex && { redoComment: req.body.payload?.checklistDescription || '' } ) };
|
|
455
488
|
let answerIndex = req.body.payload?.answerIndex;
|
|
456
489
|
let isSingleAnswerRedo = answerIndex != null;
|
|
457
490
|
|
|
@@ -575,7 +608,7 @@ export async function redoChecklist( req, res ) {
|
|
|
575
608
|
type: checklistDetails.checkListType,
|
|
576
609
|
userAnswer: userAnswer,
|
|
577
610
|
initiatedBy: req.user.userName,
|
|
578
|
-
initiatedTime: dayjs().format(),
|
|
611
|
+
initiatedTime: dayjs.utc( ).format(),
|
|
579
612
|
answerType: question[sectionIndex].questions[findQuestion].answerType,
|
|
580
613
|
submitedBy: checklistDetails.userName,
|
|
581
614
|
submitTime: dayjs.utc( checklistDetails.submitTime ).format(),
|
|
@@ -667,7 +700,7 @@ export async function redomultiChecklist( req, res ) {
|
|
|
667
700
|
|
|
668
701
|
let findQuestion = question[sectionIndex].questions.findIndex( ( ele ) => ele.qno == req.body.payload.qno );
|
|
669
702
|
|
|
670
|
-
let data = { ...question[sectionIndex].questions[findQuestion], redo: true,
|
|
703
|
+
let data = { ...question[sectionIndex].questions[findQuestion], redo: true, redoComment: req.body.payload?.showcomment ? req.body.payload?.checklistDescription : findcomment?.Comments };
|
|
671
704
|
// if ( checklistDetails.client_id == '458' ) {
|
|
672
705
|
data.answers.forEach( ( item ) => {
|
|
673
706
|
if ( item.showLinked ) {
|
|
@@ -2669,12 +2669,7 @@ function QuestionFlag( req, res ) {
|
|
|
2669
2669
|
let answervalidate = question.userAnswer.filter( ( answer ) => {
|
|
2670
2670
|
return answer.sopFlag == true;
|
|
2671
2671
|
} );
|
|
2672
|
-
|
|
2673
|
-
if ( answervalidate?.length ) {
|
|
2674
|
-
answerCount = 1;
|
|
2675
|
-
}
|
|
2676
|
-
// flagCount = flagCount + answervalidate.length;
|
|
2677
|
-
flagCount = flagCount + answerCount;
|
|
2672
|
+
flagCount = flagCount + answervalidate.length;
|
|
2678
2673
|
}
|
|
2679
2674
|
} );
|
|
2680
2675
|
} );
|
|
@@ -444,47 +444,13 @@ export const flagCardsV1 = async ( req, res ) => {
|
|
|
444
444
|
},
|
|
445
445
|
];
|
|
446
446
|
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
// cards on the client once it resolves.
|
|
450
|
-
const getOverallChecklistData = await processedchecklistService.aggregate( findQuery );
|
|
451
|
-
|
|
452
|
-
if ( !getOverallChecklistData.length ) {
|
|
453
|
-
return res.sendSuccess( { flagCards } );
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const [ data ] = getOverallChecklistData;
|
|
457
|
-
if ( data.questionFlag ) flagCards.questionFlag.count = data.questionFlag;
|
|
458
|
-
if ( data.delayInSubmission ) flagCards.delayInSubmission.count = data.delayInSubmission;
|
|
459
|
-
flagCards.totalFlag = flagCards.questionFlag.count + flagCards.delayInSubmission.count;
|
|
460
|
-
|
|
461
|
-
return res.sendSuccess( { flagCards } );
|
|
462
|
-
} catch ( error ) {
|
|
463
|
-
console.error( 'Error in flagCardsV1:', error );
|
|
464
|
-
logger.error( { error, function: 'flagCardsV1' } );
|
|
465
|
-
return res.sendError( error, 500 );
|
|
466
|
-
}
|
|
467
|
-
};
|
|
468
|
-
|
|
469
|
-
// Detection-only companion for flagCardsV1. Runs the published-checklist lookup
|
|
470
|
-
// + the detection Lambda (the slow part) and returns just the detection
|
|
471
|
-
// contribution, so the UI can merge it into the cards returned by flagCardsV1:
|
|
472
|
-
// flagCards.detectionFlag = res.flagCards.detectionFlag;
|
|
473
|
-
// flagCards.runAIFlag = res.flagCards.runAIFlag; // when present
|
|
474
|
-
// flagCards.totalFlag += res.flagCards.detectionTotalFlag;
|
|
475
|
-
export const flagCardsDetectionV1 = async ( req, res ) => {
|
|
476
|
-
try {
|
|
477
|
-
const { clientId, storeId, fromDate, toDate } = req.body;
|
|
478
|
-
|
|
479
|
-
const flagCards = {
|
|
480
|
-
detectionFlag: { count: 0 },
|
|
481
|
-
detectionTotalFlag: 0,
|
|
482
|
-
};
|
|
483
|
-
|
|
447
|
+
// These three lookups are independent of one another, so run them concurrently
|
|
448
|
+
// instead of sequentially (Mongo aggregation + config find + detection Lambda).
|
|
484
449
|
const detectionPayload = { fromDate, toDate, storeId, clientId };
|
|
485
450
|
const lambdaURL = 'https://f65azvtljclaxp6l7rnx65cdmm0lcgvp.lambda-url.ap-south-1.on.aws/';
|
|
486
451
|
|
|
487
|
-
const [ publishedAiChecklists, resultData ] = await Promise.all( [
|
|
452
|
+
const [ getOverallChecklistData, publishedAiChecklists, resultData ] = await Promise.all( [
|
|
453
|
+
processedchecklistService.aggregate( findQuery ),
|
|
488
454
|
checklistconfigService.find(
|
|
489
455
|
{
|
|
490
456
|
client_id: clientId,
|
|
@@ -496,6 +462,15 @@ export const flagCardsDetectionV1 = async ( req, res ) => {
|
|
|
496
462
|
LamdaServiceCall( lambdaURL, detectionPayload ),
|
|
497
463
|
] );
|
|
498
464
|
|
|
465
|
+
if ( !getOverallChecklistData.length ) {
|
|
466
|
+
return res.sendSuccess( { flagCards } );
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const [ data ] = getOverallChecklistData;
|
|
470
|
+
if ( data.questionFlag ) flagCards.questionFlag.count = data.questionFlag;
|
|
471
|
+
if ( data.delayInSubmission ) flagCards.delayInSubmission.count = data.delayInSubmission;
|
|
472
|
+
flagCards.totalFlag = flagCards.questionFlag.count + flagCards.delayInSubmission.count;
|
|
473
|
+
|
|
499
474
|
const published = publishedAiChecklists.map( ( val ) => val?.checkListType );
|
|
500
475
|
if ( resultData && resultData.status_code === '200' ) {
|
|
501
476
|
published.forEach( ( item ) => {
|
|
@@ -503,18 +478,18 @@ export const flagCardsDetectionV1 = async ( req, res ) => {
|
|
|
503
478
|
flagCards.detectionFlag.count += resultData[item];
|
|
504
479
|
}
|
|
505
480
|
} );
|
|
506
|
-
flagCards.
|
|
481
|
+
flagCards.totalFlag += flagCards.detectionFlag.count;
|
|
507
482
|
if ( resultData?.runAI ) {
|
|
508
483
|
resultData.runAI.flagCount = resultData.runaiflags;
|
|
509
484
|
flagCards.runAIFlag = resultData?.runAI;
|
|
510
|
-
flagCards.
|
|
485
|
+
flagCards.totalFlag += resultData.runaiflags;
|
|
511
486
|
}
|
|
512
487
|
}
|
|
513
488
|
|
|
514
489
|
return res.sendSuccess( { flagCards } );
|
|
515
490
|
} catch ( error ) {
|
|
516
|
-
console.error( 'Error in
|
|
517
|
-
logger.error( { error, function: '
|
|
491
|
+
console.error( 'Error in flagCardsV1:', error );
|
|
492
|
+
logger.error( { error, function: 'flagCardsV1' } );
|
|
518
493
|
return res.sendError( error, 500 );
|
|
519
494
|
}
|
|
520
495
|
};
|
|
@@ -2021,151 +1996,6 @@ export const flagComparisonCardsV2 = async ( req, res ) => {
|
|
|
2021
1996
|
return { comparisonData, ComparisonFlag };
|
|
2022
1997
|
};
|
|
2023
1998
|
|
|
2024
|
-
// Fast path: only the Mongo aggregations + client flag. The detection Lambda
|
|
2025
|
-
// (slow) is fetched separately via flagComparisonCardsDetectionV2, which
|
|
2026
|
-
// returns the total/detection/runAI comparisons for the UI to overwrite.
|
|
2027
|
-
const [ rangeOneData, rangeTwoData, traxMonthlyComparisonData ] = await Promise.all( [
|
|
2028
|
-
processedchecklistService.aggregate( createFindQuery( rangeOneFromDate, rangeOneToDate ) ),
|
|
2029
|
-
processedchecklistService.aggregate( createFindQuery( rangeTwoFromDate, rangeTwoToDate ) ),
|
|
2030
|
-
clientService.findOne( { clientId: requestData.clientId }, { traxMonthlyComparison: 1 } ),
|
|
2031
|
-
] );
|
|
2032
|
-
|
|
2033
|
-
// console.log( 'rangeOneFromDate =>', rangeOneFromDate );
|
|
2034
|
-
// console.log( 'rangeOneToDate =>', rangeOneToDate );
|
|
2035
|
-
// console.log( 'rangeOneData =>', rangeOneData );
|
|
2036
|
-
|
|
2037
|
-
// console.log( 'rangeTwoFromDate =>', rangeTwoFromDate );
|
|
2038
|
-
// console.log( 'rangeTwoToDate =>', rangeTwoToDate );
|
|
2039
|
-
// console.log( 'rangeTwoData =>', rangeTwoData );
|
|
2040
|
-
|
|
2041
|
-
const flagComparisonCards = {
|
|
2042
|
-
totalComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2043
|
-
questionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2044
|
-
delayInSubmissionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2045
|
-
detectionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2046
|
-
runAIComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2047
|
-
};
|
|
2048
|
-
|
|
2049
|
-
if ( rangeOneData.length && rangeTwoData.length ) {
|
|
2050
|
-
// Mongo-only total (question + delay). flagComparisonCardsDetectionV2 returns
|
|
2051
|
-
// the detection-inclusive total plus the detection/runAI comparisons, which
|
|
2052
|
-
// the UI overwrites onto these cards once the Lambda resolves.
|
|
2053
|
-
flagComparisonCards.totalComparisonFlag = calculateComparison( rangeOneData[0].totalFlag, rangeTwoData[0].totalFlag );
|
|
2054
|
-
flagComparisonCards.questionComparisonFlag = calculateComparison( rangeOneData[0].questionFlag, rangeTwoData[0].questionFlag );
|
|
2055
|
-
flagComparisonCards.delayInSubmissionComparisonFlag = calculateComparison( rangeOneData[0].delayInSubmission, rangeTwoData[0].delayInSubmission );
|
|
2056
|
-
}
|
|
2057
|
-
flagComparisonCards.traxMonthlyComparison = false;
|
|
2058
|
-
if ( traxMonthlyComparisonData && traxMonthlyComparisonData.traxMonthlyComparison ) {
|
|
2059
|
-
flagComparisonCards.traxMonthlyComparison = traxMonthlyComparisonData.traxMonthlyComparison;
|
|
2060
|
-
}
|
|
2061
|
-
return res.sendSuccess( { flagComparisonCards } );
|
|
2062
|
-
} catch ( error ) {
|
|
2063
|
-
console.log( 'error =>', error );
|
|
2064
|
-
logger.error( { error, function: 'flagComparisonCardsV2' } );
|
|
2065
|
-
return res.sendError( error, 500 );
|
|
2066
|
-
}
|
|
2067
|
-
};
|
|
2068
|
-
|
|
2069
|
-
// Detection-only companion for flagComparisonCardsV2. Re-runs the (cheap) range
|
|
2070
|
-
// aggregations alongside the two detection Lambda calls, and returns only the
|
|
2071
|
-
// comparisons that depend on detection data. The UI overwrites these three keys
|
|
2072
|
-
// onto the cards from flagComparisonCardsV2 once this resolves:
|
|
2073
|
-
// totalComparisonFlag, detectionComparisonFlag, runAIComparisonFlag.
|
|
2074
|
-
// NOTE: the date-range / createFindQuery logic below mirrors flagComparisonCardsV2 —
|
|
2075
|
-
// keep the two in sync if that logic changes.
|
|
2076
|
-
export const flagComparisonCardsDetectionV2 = async ( req, res ) => {
|
|
2077
|
-
try {
|
|
2078
|
-
let requestData = req.body;
|
|
2079
|
-
let toDate = new Date( requestData.toDate );
|
|
2080
|
-
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
2081
|
-
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
2082
|
-
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
2083
|
-
|
|
2084
|
-
let rangeOneFromDate;
|
|
2085
|
-
let rangeOneToDate;
|
|
2086
|
-
let rangeTwoFromDate;
|
|
2087
|
-
let rangeTwoToDate;
|
|
2088
|
-
if ( requestData.dateType == 'weekly' ) {
|
|
2089
|
-
rangeOneFromDate = new Date( requestData.toDate );
|
|
2090
|
-
rangeOneFromDate.setDate( rangeOneFromDate.getDate() - 6 );
|
|
2091
|
-
rangeOneToDate = new Date( requestData.toDate );
|
|
2092
|
-
rangeOneToDate = new Date( rangeOneToDate.getTime() - userTimezoneOffset );
|
|
2093
|
-
rangeOneToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2094
|
-
rangeTwoToDate = new Date( requestData.toDate );
|
|
2095
|
-
rangeTwoToDate.setDate( rangeTwoToDate.getDate() - 7 );
|
|
2096
|
-
rangeTwoFromDate = new Date( rangeTwoToDate );
|
|
2097
|
-
rangeTwoFromDate.setDate( rangeTwoFromDate.getDate() - 6 );
|
|
2098
|
-
rangeTwoToDate = new Date( rangeTwoToDate.getTime() - userTimezoneOffset );
|
|
2099
|
-
rangeTwoToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2100
|
-
} else if ( requestData.dateType == 'monthly' ) {
|
|
2101
|
-
rangeOneFromDate = new Date( requestData.toDate );
|
|
2102
|
-
rangeOneFromDate.setDate( rangeOneFromDate.getDate() - 29 );
|
|
2103
|
-
rangeOneToDate = new Date( requestData.toDate );
|
|
2104
|
-
rangeOneToDate = new Date( rangeOneToDate.getTime() - userTimezoneOffset );
|
|
2105
|
-
rangeOneToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2106
|
-
rangeTwoToDate = new Date( requestData.toDate );
|
|
2107
|
-
rangeTwoToDate.setDate( rangeTwoToDate.getDate() - 30 );
|
|
2108
|
-
rangeTwoFromDate = new Date( rangeTwoToDate );
|
|
2109
|
-
rangeTwoFromDate.setDate( rangeTwoFromDate.getDate() - 29 );
|
|
2110
|
-
rangeTwoToDate = new Date( rangeTwoToDate.getTime() - userTimezoneOffset );
|
|
2111
|
-
rangeTwoToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2112
|
-
} else {
|
|
2113
|
-
rangeOneFromDate = new Date( requestData.toDate );
|
|
2114
|
-
rangeOneFromDate.setDate( rangeOneFromDate.getDate() - 0 );
|
|
2115
|
-
rangeOneToDate = new Date( requestData.toDate );
|
|
2116
|
-
rangeOneToDate = new Date( rangeOneToDate.getTime() - userTimezoneOffset );
|
|
2117
|
-
rangeOneToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2118
|
-
rangeTwoToDate = new Date( requestData.toDate );
|
|
2119
|
-
rangeTwoToDate.setDate( rangeTwoToDate.getDate() - 1 );
|
|
2120
|
-
rangeTwoFromDate = new Date( rangeTwoToDate );
|
|
2121
|
-
rangeTwoFromDate.setDate( rangeTwoFromDate.getDate() - 0 );
|
|
2122
|
-
rangeTwoToDate = new Date( rangeTwoToDate.getTime() - userTimezoneOffset );
|
|
2123
|
-
rangeTwoToDate.setUTCHours( 23, 59, 59, 59 );
|
|
2124
|
-
}
|
|
2125
|
-
|
|
2126
|
-
const createFindQuery = ( fromDate, toDate ) => [
|
|
2127
|
-
{ $match: { client_id: requestData.clientId,
|
|
2128
|
-
date_iso: { $gte: fromDate, $lte: toDate },
|
|
2129
|
-
$or: requestData.clientId === '11' ?
|
|
2130
|
-
[
|
|
2131
|
-
{ store_id: { $in: requestData.storeId } },
|
|
2132
|
-
{ store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } },
|
|
2133
|
-
] :
|
|
2134
|
-
[
|
|
2135
|
-
{ store_id: { $in: requestData.storeId } },
|
|
2136
|
-
{ store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } },
|
|
2137
|
-
{ aiStoreList: { $in: requestData.storeId } },
|
|
2138
|
-
],
|
|
2139
|
-
} },
|
|
2140
|
-
{
|
|
2141
|
-
$project: {
|
|
2142
|
-
timeFlag: 1,
|
|
2143
|
-
questionFlag: 1,
|
|
2144
|
-
},
|
|
2145
|
-
},
|
|
2146
|
-
{
|
|
2147
|
-
$group: {
|
|
2148
|
-
_id: '',
|
|
2149
|
-
totalFlag: { $sum: { $add: [ '$questionFlag', '$timeFlag' ] } },
|
|
2150
|
-
questionFlag: { $sum: '$questionFlag' },
|
|
2151
|
-
delayInSubmission: { $sum: '$timeFlag' },
|
|
2152
|
-
},
|
|
2153
|
-
},
|
|
2154
|
-
];
|
|
2155
|
-
|
|
2156
|
-
const calculateComparison = ( rangeOneVal, rangeTwoVal ) => {
|
|
2157
|
-
if ( rangeOneVal === 0 ) {
|
|
2158
|
-
return { comparisonData: 0, ComparisonFlag: false };
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
|
-
let comparisonData = Math.abs( ( ( rangeOneVal - rangeTwoVal ) / rangeTwoVal ) * 100 );
|
|
2162
|
-
if ( comparisonData === Infinity ) comparisonData = 0;
|
|
2163
|
-
comparisonData = comparisonData % 1 === 0 ? comparisonData.toFixed( 0 ) : comparisonData.toFixed( 1 );
|
|
2164
|
-
comparisonData = parseInt( comparisonData );
|
|
2165
|
-
const ComparisonFlag = rangeOneVal > rangeTwoVal;
|
|
2166
|
-
return { comparisonData, ComparisonFlag };
|
|
2167
|
-
};
|
|
2168
|
-
|
|
2169
1999
|
const getDetectionCount = async ( fromDate, toDate ) => {
|
|
2170
2000
|
const detectionPayload = {
|
|
2171
2001
|
fromDate: dayjs( fromDate ).format( 'YYYY-MM-DD' ),
|
|
@@ -2174,6 +2004,7 @@ export const flagComparisonCardsDetectionV2 = async ( req, res ) => {
|
|
|
2174
2004
|
clientId: requestData.clientId,
|
|
2175
2005
|
};
|
|
2176
2006
|
|
|
2007
|
+
// The config lookup and the detection Lambda are independent — run them together.
|
|
2177
2008
|
const LamdaURL = 'https://f65azvtljclaxp6l7rnx65cdmm0lcgvp.lambda-url.ap-south-1.on.aws/';
|
|
2178
2009
|
const [ publishedAiChecklists, resultData ] = await Promise.all( [
|
|
2179
2010
|
checklistconfigService.find(
|
|
@@ -2186,6 +2017,9 @@ export const flagComparisonCardsDetectionV2 = async ( req, res ) => {
|
|
|
2186
2017
|
),
|
|
2187
2018
|
LamdaServiceCall( LamdaURL, detectionPayload ),
|
|
2188
2019
|
] );
|
|
2020
|
+
// if ( !publishedAiChecklists?.length ) {
|
|
2021
|
+
// return 0;
|
|
2022
|
+
// }
|
|
2189
2023
|
const published = publishedAiChecklists.map( ( val ) => val?.checkListType );
|
|
2190
2024
|
if ( resultData?.status_code === '200' ) {
|
|
2191
2025
|
let result = 0;
|
|
@@ -2203,268 +2037,51 @@ export const flagComparisonCardsDetectionV2 = async ( req, res ) => {
|
|
|
2203
2037
|
return 0;
|
|
2204
2038
|
};
|
|
2205
2039
|
|
|
2206
|
-
const [ rangeOneData, rangeTwoData, rangeOneDetectionCount, rangeTwoDetectionCount ] = await Promise.all( [
|
|
2040
|
+
const [ rangeOneData, rangeTwoData, rangeOneDetectionCount, rangeTwoDetectionCount, traxMonthlyComparisonData ] = await Promise.all( [
|
|
2207
2041
|
processedchecklistService.aggregate( createFindQuery( rangeOneFromDate, rangeOneToDate ) ),
|
|
2208
2042
|
processedchecklistService.aggregate( createFindQuery( rangeTwoFromDate, rangeTwoToDate ) ),
|
|
2209
2043
|
getDetectionCount( rangeOneFromDate, rangeOneToDate ),
|
|
2210
2044
|
getDetectionCount( rangeTwoFromDate, rangeTwoToDate ),
|
|
2045
|
+
clientService.findOne( { clientId: requestData.clientId }, { traxMonthlyComparison: 1 } ),
|
|
2211
2046
|
] );
|
|
2212
2047
|
|
|
2048
|
+
// console.log( 'rangeOneFromDate =>', rangeOneFromDate );
|
|
2049
|
+
// console.log( 'rangeOneToDate =>', rangeOneToDate );
|
|
2050
|
+
// console.log( 'rangeOneData =>', rangeOneData );
|
|
2051
|
+
|
|
2052
|
+
// console.log( 'rangeTwoFromDate =>', rangeTwoFromDate );
|
|
2053
|
+
// console.log( 'rangeTwoToDate =>', rangeTwoToDate );
|
|
2054
|
+
// console.log( 'rangeTwoData =>', rangeTwoData );
|
|
2055
|
+
|
|
2213
2056
|
const flagComparisonCards = {
|
|
2214
2057
|
totalComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2058
|
+
questionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2059
|
+
delayInSubmissionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2215
2060
|
detectionComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2216
2061
|
runAIComparisonFlag: { comparisonData: 0, ComparisonFlag: false },
|
|
2217
2062
|
};
|
|
2218
2063
|
|
|
2219
2064
|
if ( rangeOneData.length && rangeTwoData.length ) {
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
const rangeTwoDetection = ( rangeTwoDetectionCount && rangeTwoDetectionCount.result ) || 0;
|
|
2223
|
-
const rangeOneAi = ( rangeOneDetectionCount && rangeOneDetectionCount.ai ) || 0;
|
|
2224
|
-
const rangeTwoAi = ( rangeTwoDetectionCount && rangeTwoDetectionCount.ai ) || 0;
|
|
2225
|
-
|
|
2226
|
-
const rangeOneTotalFlag = rangeOneData[0].totalFlag + rangeOneDetection;
|
|
2227
|
-
const rangeTwoTotalFlag = rangeTwoData[0].totalFlag + rangeTwoDetection;
|
|
2065
|
+
let rangeOneTotalFlag = rangeOneData[0].totalFlag + rangeOneDetectionCount.result || 0;
|
|
2066
|
+
let rangeTwoTotalFlag = rangeTwoData[0].totalFlag + rangeTwoDetectionCount.result || 0;
|
|
2228
2067
|
flagComparisonCards.totalComparisonFlag = calculateComparison( rangeOneTotalFlag, rangeTwoTotalFlag );
|
|
2229
|
-
flagComparisonCards.
|
|
2230
|
-
flagComparisonCards.
|
|
2068
|
+
flagComparisonCards.questionComparisonFlag = calculateComparison( rangeOneData[0].questionFlag, rangeTwoData[0].questionFlag );
|
|
2069
|
+
flagComparisonCards.delayInSubmissionComparisonFlag = calculateComparison( rangeOneData[0].delayInSubmission, rangeTwoData[0].delayInSubmission );
|
|
2070
|
+
flagComparisonCards.detectionComparisonFlag = calculateComparison( rangeOneDetectionCount.result, rangeTwoDetectionCount.result );
|
|
2071
|
+
flagComparisonCards.runAIComparisonFlag = calculateComparison( rangeOneDetectionCount.ai, rangeTwoDetectionCount.ai );
|
|
2072
|
+
}
|
|
2073
|
+
flagComparisonCards.traxMonthlyComparison = false;
|
|
2074
|
+
if ( traxMonthlyComparisonData && traxMonthlyComparisonData.traxMonthlyComparison ) {
|
|
2075
|
+
flagComparisonCards.traxMonthlyComparison = traxMonthlyComparisonData.traxMonthlyComparison;
|
|
2231
2076
|
}
|
|
2232
|
-
|
|
2233
2077
|
return res.sendSuccess( { flagComparisonCards } );
|
|
2234
2078
|
} catch ( error ) {
|
|
2235
2079
|
console.log( 'error =>', error );
|
|
2236
|
-
logger.error( { error, function: '
|
|
2080
|
+
logger.error( { error, function: 'flagComparisonCardsV1' } );
|
|
2237
2081
|
return res.sendError( error, 500 );
|
|
2238
2082
|
}
|
|
2239
2083
|
};
|
|
2240
2084
|
|
|
2241
|
-
// Builds the per-checklist aggregation pipeline for the flag table. Used by the
|
|
2242
|
-
// detection endpoint (flagTablesDetectionV2) and mirrored by flagTablesV2's own
|
|
2243
|
-
// inline build — the two MUST produce an identical pipeline so the detection map
|
|
2244
|
-
// keys line up with the rows the client already rendered from flagTablesV2.
|
|
2245
|
-
function buildFlagTablesFindQuery( requestData ) {
|
|
2246
|
-
let fromDate = new Date( requestData.fromDate );
|
|
2247
|
-
let toDate = new Date( requestData.toDate );
|
|
2248
|
-
let userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
|
|
2249
|
-
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
2250
|
-
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
2251
|
-
|
|
2252
|
-
const findQuery = [];
|
|
2253
|
-
const findAndQuery = [];
|
|
2254
|
-
findAndQuery.push(
|
|
2255
|
-
{ client_id: requestData.clientId },
|
|
2256
|
-
{ date_iso: { $gte: fromDate, $lte: toDate } },
|
|
2257
|
-
{ $or: [ { store_id: { $in: requestData.storeId } }, { store_id: { $eq: '' }, userEmail: { $in: requestData.userEmailes } }, { aiStoreList: { $in: requestData.storeId } } ] },
|
|
2258
|
-
);
|
|
2259
|
-
|
|
2260
|
-
if ( requestData?.filter === 'all' ) {
|
|
2261
|
-
findAndQuery.push( { $or: [ { checkListType: { $in: [ 'custom', 'customerunattended', 'mobileusagedetection', 'staffleftinthemiddle', 'storeopenandclose', 'uniformdetection', 'cleaning', 'scrum', 'outsidebusinesshoursqueuetracking', 'halfshutter', 'tvcompliance', 'cameratampering', 'queuealert', 'staffgrouping', 'boxalert', 'employeeCount', 'storehygienemonitoring', 'unattendeddetection', 'vehicle_check_in', 'employeemonitoring', 'activitymonitoring' ] } } ] } );
|
|
2262
|
-
} else if ( requestData?.filter === 'question' ) {
|
|
2263
|
-
findAndQuery.push( { checkListType: 'custom' } );
|
|
2264
|
-
findAndQuery.push( { questionFlag: { $gte: 1 } } );
|
|
2265
|
-
} else if ( requestData?.filter === 'time' ) {
|
|
2266
|
-
findAndQuery.push( { checkListType: 'custom' } );
|
|
2267
|
-
findAndQuery.push( { timeFlag: { $gte: 1 } } );
|
|
2268
|
-
} else if ( requestData?.filter === 'detection' ) {
|
|
2269
|
-
findAndQuery.push( { checkListType: { $ne: 'custom' } } );
|
|
2270
|
-
} else if ( requestData?.filter === 'runAI' ) {
|
|
2271
|
-
if ( requestData.runAIChecklistName ) {
|
|
2272
|
-
findAndQuery.push( { checkListName: { $in: requestData.runAIChecklistName } } );
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
findQuery.push( { $match: { $and: findAndQuery } } );
|
|
2277
|
-
|
|
2278
|
-
if ( requestData.searchValue && requestData.searchValue != '' ) {
|
|
2279
|
-
findQuery.push( { $match: { $or: [ { checkListName: { $regex: requestData.searchValue, $options: 'i' } } ] } } );
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
findQuery.push( {
|
|
2283
|
-
$project: {
|
|
2284
|
-
sourceCheckList_id: 1,
|
|
2285
|
-
checkListId: 1,
|
|
2286
|
-
checkListName: 1,
|
|
2287
|
-
coverage: 1,
|
|
2288
|
-
storeCount: 1,
|
|
2289
|
-
createdBy: 1,
|
|
2290
|
-
createdByName: 1,
|
|
2291
|
-
checklistStatus: 1,
|
|
2292
|
-
timeFlag: 1,
|
|
2293
|
-
questionFlag: 1,
|
|
2294
|
-
questionCount: 1,
|
|
2295
|
-
mobileDetectionFlag: 1,
|
|
2296
|
-
storeOpenCloseFlag: 1,
|
|
2297
|
-
uniformDetectionFlag: 1,
|
|
2298
|
-
checkListType: 1,
|
|
2299
|
-
scheduleRepeatedType: 1,
|
|
2300
|
-
store_id: 1,
|
|
2301
|
-
aiStoreList: 1,
|
|
2302
|
-
runAIQuestionCount: 1,
|
|
2303
|
-
},
|
|
2304
|
-
} );
|
|
2305
|
-
|
|
2306
|
-
findQuery.push( {
|
|
2307
|
-
$group: {
|
|
2308
|
-
_id: '$sourceCheckList_id',
|
|
2309
|
-
checkListName: { $last: '$checkListName' },
|
|
2310
|
-
checkListChar: { $last: { $substr: [ '$checkListName', 0, 2 ] } },
|
|
2311
|
-
coverage: { $last: '$coverage' },
|
|
2312
|
-
sourceCheckList_id: { $last: '$sourceCheckList_id' },
|
|
2313
|
-
checkListType: { $last: '$checkListType' },
|
|
2314
|
-
storeCount: { $sum: 1 },
|
|
2315
|
-
storeCountAi: { $max: '$storeCount' },
|
|
2316
|
-
flaggedStores: { $sum: { $cond: [
|
|
2317
|
-
{
|
|
2318
|
-
$or: [
|
|
2319
|
-
{ '$gt': [ '$timeFlag', 0 ] },
|
|
2320
|
-
{ '$gt': [ '$questionFlag', 0 ] },
|
|
2321
|
-
{ '$gt': [ '$mobileDetectionFlag', 0 ] },
|
|
2322
|
-
{ '$gt': [ '$storeOpenCloseFlag', 0 ] },
|
|
2323
|
-
{ '$gt': [ '$uniformDetectionFlag', 0 ] },
|
|
2324
|
-
{ '$gt': [ '$customerUnattended', 0 ] },
|
|
2325
|
-
{ '$gt': [ '$staffLeftInTheMiddle', 0 ] },
|
|
2326
|
-
{ '$gt': [ '$cleaning', 0 ] },
|
|
2327
|
-
{ '$gt': [ '$scrum', 0 ] },
|
|
2328
|
-
{ '$gt': [ '$employeeCount', 0 ] },
|
|
2329
|
-
{ '$gt': [ '$employeemonitoring', 0 ] },
|
|
2330
|
-
{ '$gt': [ '$activitymonitoring', 0 ] },
|
|
2331
|
-
],
|
|
2332
|
-
},
|
|
2333
|
-
1,
|
|
2334
|
-
0,
|
|
2335
|
-
] } },
|
|
2336
|
-
flagCount: {
|
|
2337
|
-
$sum: {
|
|
2338
|
-
$add: [ '$questionFlag', '$timeFlag' ],
|
|
2339
|
-
},
|
|
2340
|
-
},
|
|
2341
|
-
submittedChecklist: {
|
|
2342
|
-
$sum: {
|
|
2343
|
-
$cond: [ { $eq: [ '$checklistStatus', 'submit' ] }, 1, 0 ],
|
|
2344
|
-
},
|
|
2345
|
-
},
|
|
2346
|
-
questionFlag: { $sum: '$questionFlag' },
|
|
2347
|
-
timeFlag: { $sum: '$timeFlag' },
|
|
2348
|
-
questionCount: { $sum: '$questionCount' },
|
|
2349
|
-
aiStoreList: { $max: '$aiStoreList' },
|
|
2350
|
-
aiStoreListNew: { $sum: { $size: '$aiStoreList' } },
|
|
2351
|
-
submittedQuestionCount: { $sum: { $cond: [ { $eq: [ '$checklistStatus', 'submit' ] }, '$questionCount', 0 ] } },
|
|
2352
|
-
runAIQuestionCount: { $last: '$runAIQuestionCount' },
|
|
2353
|
-
},
|
|
2354
|
-
} );
|
|
2355
|
-
|
|
2356
|
-
findQuery.push( {
|
|
2357
|
-
$project: {
|
|
2358
|
-
assignedStores: '$storeCount',
|
|
2359
|
-
assignedStoresAi: '$aiStoreListNew',
|
|
2360
|
-
checkListName: 1,
|
|
2361
|
-
coverage: 1,
|
|
2362
|
-
checkListChar: 1,
|
|
2363
|
-
sourceCheckList_id: 1,
|
|
2364
|
-
checkListType: 1,
|
|
2365
|
-
flagType: 1,
|
|
2366
|
-
uniqueFlaggedStores: 1,
|
|
2367
|
-
flaggedStores: '$flaggedStores',
|
|
2368
|
-
flagCount: 1,
|
|
2369
|
-
questionCount: 1,
|
|
2370
|
-
correctAnswers: { $subtract: [ '$submittedQuestionCount', '$questionFlag' ] },
|
|
2371
|
-
customQuestionFlagCount: '$questionFlag',
|
|
2372
|
-
customTimeFlagCount: '$timeFlag',
|
|
2373
|
-
submittedChecklist: 1,
|
|
2374
|
-
aiStoreList: 1,
|
|
2375
|
-
runAIQuestionCount: 1,
|
|
2376
|
-
},
|
|
2377
|
-
} );
|
|
2378
|
-
|
|
2379
|
-
findQuery.push( {
|
|
2380
|
-
$project: {
|
|
2381
|
-
checkListName: 1,
|
|
2382
|
-
checkListChar: 1,
|
|
2383
|
-
coverage: {
|
|
2384
|
-
$concat: [
|
|
2385
|
-
{ $toUpper: { $substr: [ { $ifNull: [ '$coverage', '' ] }, 0, 1 ] } },
|
|
2386
|
-
{ $substr: [ { $ifNull: [ '$coverage', '' ] }, 1, { $strLenCP: { $ifNull: [ '$coverage', '' ] } } ] },
|
|
2387
|
-
],
|
|
2388
|
-
},
|
|
2389
|
-
sourceCheckList_id: 1,
|
|
2390
|
-
checkListType: 1,
|
|
2391
|
-
flagType: 1,
|
|
2392
|
-
assignedStores: 1,
|
|
2393
|
-
assignedStoresAi: 1,
|
|
2394
|
-
flaggedStores: 1,
|
|
2395
|
-
flagCount: 1,
|
|
2396
|
-
uniqueFlaggedStores: 1,
|
|
2397
|
-
complianceRate: {
|
|
2398
|
-
$cond: {
|
|
2399
|
-
if: { $eq: [ '$questionCount', 0 ] },
|
|
2400
|
-
then: 0,
|
|
2401
|
-
else: {
|
|
2402
|
-
$round: [ { $multiply: [ { $divide: [ '$correctAnswers', '$questionCount' ] }, 100 ] }, 2 ],
|
|
2403
|
-
},
|
|
2404
|
-
},
|
|
2405
|
-
},
|
|
2406
|
-
customQuestionFlagCount: 1,
|
|
2407
|
-
customTimeFlagCount: 1,
|
|
2408
|
-
submittedChecklist: 1,
|
|
2409
|
-
aiStoreList: 1,
|
|
2410
|
-
runAIQuestionCount: 1,
|
|
2411
|
-
},
|
|
2412
|
-
} );
|
|
2413
|
-
|
|
2414
|
-
findQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
|
|
2415
|
-
return findQuery;
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// Merges detection / runAI / all flag values from the Lambda into the aggregated
|
|
2419
|
-
// rows (mutates in place). Single source of truth shared by flagTablesV2's export
|
|
2420
|
-
// path and flagTablesDetectionV2 — the detection-column values (flaggedStores,
|
|
2421
|
-
// flagCount, complianceRate, assignedStores) and their edge cases live here only.
|
|
2422
|
-
function mergeDetectionIntoRows( getChecklistPerformanceData, lambdaResultData, requestData ) {
|
|
2423
|
-
if ( !getChecklistPerformanceData?.length ) return;
|
|
2424
|
-
const detectionChecklists = getChecklistPerformanceData?.filter( ( val ) => val?.checkListType !== 'custom' );
|
|
2425
|
-
if ( !( detectionChecklists?.length || [ 'runAI', 'all' ].includes( requestData?.filter ) ) ) return;
|
|
2426
|
-
const resultData = lambdaResultData;
|
|
2427
|
-
if ( !resultData || resultData.status_code != '200' ) return;
|
|
2428
|
-
|
|
2429
|
-
for ( let index = 0; index < getChecklistPerformanceData.length; index++ ) {
|
|
2430
|
-
if ( [ 'runAI', 'all' ].includes( requestData?.filter ) ) {
|
|
2431
|
-
let findCheckList = resultData?.runAI?.list?.find( ( ele ) => ele.checkListName == getChecklistPerformanceData[index].checkListName );
|
|
2432
|
-
if ( findCheckList ) {
|
|
2433
|
-
if ( requestData?.filter == 'all' ) {
|
|
2434
|
-
getChecklistPerformanceData[index].runAIFlag = findCheckList.flagCount;
|
|
2435
|
-
getChecklistPerformanceData[index].flaggedStores = getChecklistPerformanceData[index].flaggedStores + findCheckList.flagCount;
|
|
2436
|
-
} else {
|
|
2437
|
-
getChecklistPerformanceData[index].flagCount = findCheckList.flagCount;
|
|
2438
|
-
getChecklistPerformanceData[index].flaggedStores = findCheckList.flagStoreCount;
|
|
2439
|
-
}
|
|
2440
|
-
} else {
|
|
2441
|
-
if ( getChecklistPerformanceData[index].checkListType !== 'custom' ) {
|
|
2442
|
-
if ( requestData?.filter == 'all' ) {
|
|
2443
|
-
getChecklistPerformanceData[index].runAIFlag = 0;
|
|
2444
|
-
getChecklistPerformanceData[index].flagCount = resultData?.[getChecklistPerformanceData[index]?.checkListType] || 0;
|
|
2445
|
-
getChecklistPerformanceData[index].flaggedStores = resultData?.[`${getChecklistPerformanceData[index]?.checkListType}_flaggedstores`] || 0;
|
|
2446
|
-
} else {
|
|
2447
|
-
getChecklistPerformanceData[index].flagCount = 0;
|
|
2448
|
-
getChecklistPerformanceData[index].flaggedStores = 0;
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
getChecklistPerformanceData[index].complianceRate = ( 100- ( getChecklistPerformanceData[index].flaggedStores / getChecklistPerformanceData[index].assignedStores ) * 100 );
|
|
2453
|
-
getChecklistPerformanceData[index].complianceRate = Math.min( 100, Math.max( 0, getChecklistPerformanceData[index].complianceRate ) );
|
|
2454
|
-
getChecklistPerformanceData[index].complianceRate = ( getChecklistPerformanceData[index].complianceRate % 1 === 0 ) ? getChecklistPerformanceData[index].complianceRate.toFixed( 0 ) : getChecklistPerformanceData[index].complianceRate.toFixed( 2 );
|
|
2455
|
-
} else {
|
|
2456
|
-
if ( getChecklistPerformanceData[index].checkListType !== 'custom' ) {
|
|
2457
|
-
getChecklistPerformanceData[index].flagCount = resultData?.[getChecklistPerformanceData[index]?.checkListType] || 0;
|
|
2458
|
-
getChecklistPerformanceData[index].flaggedStores = resultData?.[`${getChecklistPerformanceData[index]?.checkListType}_flaggedstores`] || 0;
|
|
2459
|
-
getChecklistPerformanceData[index].assignedStores = getChecklistPerformanceData[index]?.aiStoreList?.filter( ( element ) => requestData.storeId.includes( element ) )?.length || 0;
|
|
2460
|
-
getChecklistPerformanceData[index].complianceRate = ( 100- ( getChecklistPerformanceData[index].flaggedStores / getChecklistPerformanceData[index].assignedStores ) * 100 );
|
|
2461
|
-
getChecklistPerformanceData[index].complianceRate = Math.min( 100, Math.max( 0, getChecklistPerformanceData[index].complianceRate ) );
|
|
2462
|
-
getChecklistPerformanceData[index].complianceRate = ( getChecklistPerformanceData[index].complianceRate % 1 === 0 ) ? getChecklistPerformanceData[index].complianceRate.toFixed( 0 ) : getChecklistPerformanceData[index].complianceRate.toFixed( 2 );
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
|
|
2468
2085
|
export const flagTablesV2 = async ( req, res ) => {
|
|
2469
2086
|
try {
|
|
2470
2087
|
let requestData = req.body;
|
|
@@ -2474,6 +2091,8 @@ export const flagTablesV2 = async ( req, res ) => {
|
|
|
2474
2091
|
toDate = new Date( toDate.getTime() - userTimezoneOffset );
|
|
2475
2092
|
toDate.setUTCHours( 23, 59, 59, 59 );
|
|
2476
2093
|
let result = {};
|
|
2094
|
+
let limit = parseInt( requestData?.limit ) || 10;
|
|
2095
|
+
let skip = limit * ( requestData?.offset ) || 0;
|
|
2477
2096
|
|
|
2478
2097
|
const lamdaUrl = JSON.parse( process.env.LAMBDAURL );
|
|
2479
2098
|
|
|
@@ -2662,11 +2281,10 @@ export const flagTablesV2 = async ( req, res ) => {
|
|
|
2662
2281
|
// fixes. One row per checklist keeps the in-memory set small.
|
|
2663
2282
|
findQuery.push( { $sort: { ['submittedChecklist']: -1 } } );
|
|
2664
2283
|
|
|
2665
|
-
//
|
|
2666
|
-
//
|
|
2667
|
-
// Lambda entirely and hydrates detection values via flagTablesDetectionV2.
|
|
2284
|
+
// The detection Lambda only needs request params (not the aggregation result),
|
|
2285
|
+
// so fire it concurrently with the Mongo aggregation instead of after it.
|
|
2668
2286
|
// 'question'/'time' filters are custom-only, so the Lambda is never needed there.
|
|
2669
|
-
const mayNeedLambda =
|
|
2287
|
+
const mayNeedLambda = ![ 'question', 'time' ].includes( requestData?.filter );
|
|
2670
2288
|
const detectionPayload = {
|
|
2671
2289
|
'fromDate': requestData.fromDate,
|
|
2672
2290
|
'toDate': requestData.toDate,
|
|
@@ -2689,10 +2307,54 @@ export const flagTablesV2 = async ( req, res ) => {
|
|
|
2689
2307
|
}
|
|
2690
2308
|
|
|
2691
2309
|
let getTotalCount = getChecklistPerformanceData.length;
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2310
|
+
if ( getChecklistPerformanceData.length ) {
|
|
2311
|
+
const detectionChecklists = getChecklistPerformanceData?.filter( ( val ) => val?.checkListType !== 'custom' );
|
|
2312
|
+
|
|
2313
|
+
if ( detectionChecklists?.length || [ 'runAI', 'all' ].includes( requestData?.filter ) ) {
|
|
2314
|
+
let resultData = lambdaResultData;
|
|
2315
|
+
if ( resultData ) {
|
|
2316
|
+
if ( resultData.status_code == '200' ) {
|
|
2317
|
+
for ( let index = 0; index < getChecklistPerformanceData.length; index++ ) {
|
|
2318
|
+
if ( [ 'runAI', 'all' ].includes( requestData?.filter ) ) {
|
|
2319
|
+
let findCheckList = resultData?.runAI?.list?.find( ( ele ) => ele.checkListName == getChecklistPerformanceData[index].checkListName );
|
|
2320
|
+
if ( findCheckList ) {
|
|
2321
|
+
if ( requestData?.filter == 'all' ) {
|
|
2322
|
+
getChecklistPerformanceData[index].runAIFlag = findCheckList.flagCount;
|
|
2323
|
+
getChecklistPerformanceData[index].flaggedStores = getChecklistPerformanceData[index].flaggedStores + findCheckList.flagCount;
|
|
2324
|
+
} else {
|
|
2325
|
+
getChecklistPerformanceData[index].flagCount = findCheckList.flagCount;
|
|
2326
|
+
getChecklistPerformanceData[index].flaggedStores = findCheckList.flagStoreCount;
|
|
2327
|
+
}
|
|
2328
|
+
} else {
|
|
2329
|
+
if ( getChecklistPerformanceData[index].checkListType !== 'custom' ) {
|
|
2330
|
+
if ( requestData?.filter == 'all' ) {
|
|
2331
|
+
getChecklistPerformanceData[index].runAIFlag = 0;
|
|
2332
|
+
getChecklistPerformanceData[index].flagCount = resultData?.[getChecklistPerformanceData[index]?.checkListType] || 0;
|
|
2333
|
+
getChecklistPerformanceData[index].flaggedStores = resultData?.[`${getChecklistPerformanceData[index]?.checkListType}_flaggedstores`] || 0;
|
|
2334
|
+
} else {
|
|
2335
|
+
getChecklistPerformanceData[index].flagCount = 0;
|
|
2336
|
+
getChecklistPerformanceData[index].flaggedStores = 0;
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
getChecklistPerformanceData[index].complianceRate = ( 100- ( getChecklistPerformanceData[index].flaggedStores / getChecklistPerformanceData[index].assignedStores ) * 100 );
|
|
2341
|
+
getChecklistPerformanceData[index].complianceRate = Math.min( 100, Math.max( 0, getChecklistPerformanceData[index].complianceRate ) );
|
|
2342
|
+
getChecklistPerformanceData[index].complianceRate = ( getChecklistPerformanceData[index].complianceRate % 1 === 0 ) ? getChecklistPerformanceData[index].complianceRate.toFixed( 0 ) : getChecklistPerformanceData[index].complianceRate.toFixed( 2 );
|
|
2343
|
+
} else {
|
|
2344
|
+
if ( getChecklistPerformanceData[index].checkListType !== 'custom' ) {
|
|
2345
|
+
getChecklistPerformanceData[index].flagCount = resultData?.[getChecklistPerformanceData[index]?.checkListType] || 0;
|
|
2346
|
+
getChecklistPerformanceData[index].flaggedStores = resultData?.[`${getChecklistPerformanceData[index]?.checkListType}_flaggedstores`] || 0;
|
|
2347
|
+
getChecklistPerformanceData[index].assignedStores = getChecklistPerformanceData[index]?.aiStoreList?.filter( ( element ) => requestData.storeId.includes( element ) )?.length || 0;
|
|
2348
|
+
getChecklistPerformanceData[index].complianceRate = ( 100- ( getChecklistPerformanceData[index].flaggedStores / getChecklistPerformanceData[index].assignedStores ) * 100 );
|
|
2349
|
+
getChecklistPerformanceData[index].complianceRate = Math.min( 100, Math.max( 0, getChecklistPerformanceData[index].complianceRate ) );
|
|
2350
|
+
getChecklistPerformanceData[index].complianceRate = ( getChecklistPerformanceData[index].complianceRate % 1 === 0 ) ? getChecklistPerformanceData[index].complianceRate.toFixed( 0 ) : getChecklistPerformanceData[index].complianceRate.toFixed( 2 );
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2696
2358
|
|
|
2697
2359
|
// Sort in JS AFTER the Lambda merge so detection / runAI / all rows order by
|
|
2698
2360
|
// their real (merged) flaggedStores / flagCount / complianceRate / assignedStores
|
|
@@ -2784,10 +2446,8 @@ export const flagTablesV2 = async ( req, res ) => {
|
|
|
2784
2446
|
}
|
|
2785
2447
|
|
|
2786
2448
|
result.totalCount = getTotalCount;
|
|
2787
|
-
//
|
|
2788
|
-
|
|
2789
|
-
// flagTablesDetectionV2. Export returns earlier via download() above.
|
|
2790
|
-
result.checklistPerformance = getChecklistPerformanceData;
|
|
2449
|
+
// Paginate in JS now that the full set is sorted by the merged values.
|
|
2450
|
+
result.checklistPerformance = getChecklistPerformanceData.slice( skip, skip + limit );
|
|
2791
2451
|
return res.sendSuccess( result );
|
|
2792
2452
|
} catch ( error ) {
|
|
2793
2453
|
console.log( 'error =>', error );
|
|
@@ -2796,71 +2456,6 @@ export const flagTablesV2 = async ( req, res ) => {
|
|
|
2796
2456
|
}
|
|
2797
2457
|
};
|
|
2798
2458
|
|
|
2799
|
-
// Detection-only companion for flagTablesV2. Re-runs the SAME (cheap) aggregation
|
|
2800
|
-
// alongside the detection Lambda (the slow part), merges the detection values, and
|
|
2801
|
-
// returns them keyed by sourceCheckList_id. The client patches these onto the rows
|
|
2802
|
-
// it already rendered from flagTablesV2, then re-sorts / re-paginates:
|
|
2803
|
-
// for ( const row of rows ) {
|
|
2804
|
-
// const d = res.detection[ row.sourceCheckList_id ];
|
|
2805
|
-
// if ( d ) Object.assign( row, d );
|
|
2806
|
-
// }
|
|
2807
|
-
// The aggregation is re-run (not passed in) so the two endpoints stay independent
|
|
2808
|
-
// and the Lambda still runs concurrently with Mongo; the aggregation is cheap
|
|
2809
|
-
// relative to the ~8s Lambda that dominates this call's latency.
|
|
2810
|
-
export const flagTablesDetectionV2 = async ( req, res ) => {
|
|
2811
|
-
try {
|
|
2812
|
-
const requestData = req.body;
|
|
2813
|
-
|
|
2814
|
-
// 'question'/'time' filters are custom-only — no detection data to fetch.
|
|
2815
|
-
const mayNeedLambda = ![ 'question', 'time' ].includes( requestData?.filter );
|
|
2816
|
-
if ( !mayNeedLambda ) {
|
|
2817
|
-
return res.sendSuccess( { detection: {} } );
|
|
2818
|
-
}
|
|
2819
|
-
|
|
2820
|
-
const findQuery = buildFlagTablesFindQuery( requestData );
|
|
2821
|
-
|
|
2822
|
-
const lamdaUrl = JSON.parse( process.env.LAMBDAURL );
|
|
2823
|
-
const LamdaURL = lamdaUrl.flagTablesV2;
|
|
2824
|
-
const detectionPayload = {
|
|
2825
|
-
'fromDate': requestData.fromDate,
|
|
2826
|
-
'toDate': requestData.toDate,
|
|
2827
|
-
'storeId': requestData.storeId,
|
|
2828
|
-
'clientId': requestData.clientId,
|
|
2829
|
-
};
|
|
2830
|
-
|
|
2831
|
-
const [ getChecklistPerformanceData, lambdaResultData ] = await Promise.all( [
|
|
2832
|
-
processedchecklistService.aggregate( findQuery ),
|
|
2833
|
-
LamdaServiceCall( LamdaURL, detectionPayload ),
|
|
2834
|
-
] );
|
|
2835
|
-
|
|
2836
|
-
if ( !getChecklistPerformanceData?.length ) {
|
|
2837
|
-
return res.sendSuccess( { detection: {} } );
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
mergeDetectionIntoRows( getChecklistPerformanceData, lambdaResultData, requestData );
|
|
2841
|
-
|
|
2842
|
-
// Return only the detection-affected fields, keyed by sourceCheckList_id, so the
|
|
2843
|
-
// client can patch them onto its already-rendered rows.
|
|
2844
|
-
const detection = {};
|
|
2845
|
-
getChecklistPerformanceData.forEach( ( row ) => {
|
|
2846
|
-
const key = String( row.sourceCheckList_id ?? row._id );
|
|
2847
|
-
detection[key] = {
|
|
2848
|
-
flagCount: row.flagCount,
|
|
2849
|
-
flaggedStores: row.flaggedStores,
|
|
2850
|
-
complianceRate: row.complianceRate,
|
|
2851
|
-
assignedStores: row.assignedStores,
|
|
2852
|
-
...( row.runAIFlag !== undefined ? { runAIFlag: row.runAIFlag } : {} ),
|
|
2853
|
-
};
|
|
2854
|
-
} );
|
|
2855
|
-
|
|
2856
|
-
return res.sendSuccess( { detection } );
|
|
2857
|
-
} catch ( error ) {
|
|
2858
|
-
console.log( 'error =>', error );
|
|
2859
|
-
logger.error( { error: error, message: req.query, function: 'flagTablesDetectionV2' } );
|
|
2860
|
-
return res.sendError( { error: error }, 500 );
|
|
2861
|
-
}
|
|
2862
|
-
};
|
|
2863
|
-
|
|
2864
2459
|
export const checklistCountByType = async ( req, res ) => {
|
|
2865
2460
|
try {
|
|
2866
2461
|
let { clientId, fromDate, toDate } = req.body;
|
|
@@ -9,14 +9,11 @@ import {
|
|
|
9
9
|
flagChecklistTableV1,
|
|
10
10
|
overallFlagMetrics,
|
|
11
11
|
flagCardsV1,
|
|
12
|
-
flagCardsDetectionV1,
|
|
13
12
|
flagComparisonCardsV1,
|
|
14
13
|
flagTablesV1,
|
|
15
14
|
checklistDropdownV1,
|
|
16
15
|
flagTablesV2,
|
|
17
|
-
flagTablesDetectionV2,
|
|
18
16
|
flagComparisonCardsV2,
|
|
19
|
-
flagComparisonCardsDetectionV2,
|
|
20
17
|
checklistCountByType,
|
|
21
18
|
} from '../controllers/teaxFlag.controller.js';
|
|
22
19
|
import { isAllowedSessionHandler } from 'tango-app-api-middleware';
|
|
@@ -45,9 +42,6 @@ traxFlagRouter
|
|
|
45
42
|
.post( '/flagCardsV1', isAllowedSessionHandler,
|
|
46
43
|
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
47
44
|
flagCardsV1 )
|
|
48
|
-
.post( '/flagCardsDetectionV1', isAllowedSessionHandler,
|
|
49
|
-
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
50
|
-
flagCardsDetectionV1 )
|
|
51
45
|
.post( '/flagComparisonCardsV1', isAllowedSessionHandler,
|
|
52
46
|
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
53
47
|
flagComparisonCardsV1 )
|
|
@@ -57,15 +51,9 @@ traxFlagRouter
|
|
|
57
51
|
.post( '/flagComparisonCardsV2', isAllowedSessionHandler,
|
|
58
52
|
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
59
53
|
flagComparisonCardsV2 )
|
|
60
|
-
.post( '/flagComparisonCardsDetectionV2', isAllowedSessionHandler,
|
|
61
|
-
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
62
|
-
flagComparisonCardsDetectionV2 )
|
|
63
54
|
.post( '/flagTablesV2', isAllowedSessionHandler,
|
|
64
55
|
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
65
56
|
flagTablesV2 )
|
|
66
|
-
.post( '/flagTablesDetectionV2', isAllowedSessionHandler,
|
|
67
|
-
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
68
|
-
flagTablesDetectionV2 )
|
|
69
57
|
.post( '/checklistCountByType', isAllowedSessionHandler,
|
|
70
58
|
accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoTrax', name: 'checklist', permissions: [] } ] } ),
|
|
71
59
|
checklistCountByType );
|