tango-app-api-infra 3.9.5-vms.60 → 3.9.5-vms.62
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
|
@@ -6,9 +6,9 @@ import { findOneRevopDownload, upsertRevopDownload } from '../services/revopDown
|
|
|
6
6
|
import dayjs from 'dayjs';
|
|
7
7
|
import utc from 'dayjs/plugin/utc.js';
|
|
8
8
|
import timezone from 'dayjs/plugin/timezone.js';
|
|
9
|
-
import { findUser } from '../services/user.service.js';
|
|
10
9
|
import { findOneClient } from '../services/client.service.js';
|
|
11
|
-
|
|
10
|
+
import { findUser, findOneUser } from '../services/user.service.js';
|
|
11
|
+
import { sendPushNotification } from 'tango-app-api-middleware';
|
|
12
12
|
dayjs.extend( utc );
|
|
13
13
|
dayjs.extend( timezone );
|
|
14
14
|
|
|
@@ -157,6 +157,7 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
157
157
|
};
|
|
158
158
|
let findTicket = await getOpenSearchData( openSearch.footfallDirectory, findQuery );
|
|
159
159
|
let Ticket = findTicket.body?.hits?.hits;
|
|
160
|
+
console.log( '🚀 ~ tangoReviewTicket ~ Ticket:', Ticket );
|
|
160
161
|
if ( Ticket.length === 0 ) {
|
|
161
162
|
return res.sendError( 'Ticket not found', 400 );
|
|
162
163
|
}
|
|
@@ -391,6 +392,28 @@ export async function tangoReviewTicket( req, res ) {
|
|
|
391
392
|
);
|
|
392
393
|
}
|
|
393
394
|
|
|
395
|
+
if ( Ticket[0]?._source?.type==='store' ) {
|
|
396
|
+
let userData = await findOneUser( { email: Ticket[0]?._source?.createdByEmail } );
|
|
397
|
+
let title = `Received response for the Footfall ticket raised.`;
|
|
398
|
+
let createdOn = dayjs( Ticket[0]?._source?.dateString ).format( 'DD MMM YYYY' );
|
|
399
|
+
let description = `Raised on ${createdOn}`;
|
|
400
|
+
console.log( '🚀 ~ ticketCreation ~ userData.role:', userData.email );
|
|
401
|
+
let Data = {
|
|
402
|
+
'title': title,
|
|
403
|
+
'body': description,
|
|
404
|
+
'type': 'closed',
|
|
405
|
+
'date': Ticket[0]?._source?.dateString,
|
|
406
|
+
'storeId': Ticket[0]?._source?.storeId,
|
|
407
|
+
'clientId': Ticket[0]?._source?.clientId,
|
|
408
|
+
'ticketId': Ticket[0]?._source?.ticketId,
|
|
409
|
+
};
|
|
410
|
+
if ( userData && userData.fcmToken ) {
|
|
411
|
+
const fcmToken = userData.fcmToken;
|
|
412
|
+
await sendPushNotification( title, description, fcmToken, Data );
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// return;
|
|
416
|
+
|
|
394
417
|
let id = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
|
|
395
418
|
if ( inputData.ticketType === 'internal' ) {
|
|
396
419
|
id = `${inputData.storeId}_${inputData.dateString}_internal_footfall-directory-tagging`;
|
|
@@ -883,14 +906,14 @@ export async function ticketList( req, res ) {
|
|
|
883
906
|
};
|
|
884
907
|
|
|
885
908
|
if ( inputData.sortBy ) {
|
|
886
|
-
let sortOrder = inputData.sortOrder === 1? 'asc': 'desc';
|
|
909
|
+
let sortOrder = inputData.sortOrder === 1 ? 'asc' : 'desc';
|
|
887
910
|
|
|
888
911
|
// Remove default sort so we don't duplicate/conflict
|
|
889
912
|
// INSERT_YOUR_CODE
|
|
890
913
|
// If sortBy is present, check if the field needs ".keyword" (for string fields like storeName, storeId, ticketId)
|
|
891
914
|
// This avoids OpenSearch errors about sorting on text fields.
|
|
892
915
|
const stringKeywordFields = [ 'storeName', 'storeId', 'ticketId', 'status', 'type', 'clientId' ];
|
|
893
|
-
let sortField = inputData.sortBy == 'footfall'? 'footfallCount' :inputData.sortBy == 'issueDate'?'dateString':inputData.sortBy;
|
|
916
|
+
let sortField = inputData.sortBy == 'footfall' ? 'footfallCount' : inputData.sortBy == 'issueDate' ? 'dateString' : inputData.sortBy;
|
|
894
917
|
if ( stringKeywordFields.includes( sortField ) ) {
|
|
895
918
|
sortField = `${sortField}.keyword`;
|
|
896
919
|
}
|
|
@@ -930,7 +953,7 @@ export async function ticketList( req, res ) {
|
|
|
930
953
|
searchQuery.query.bool.must.push( {
|
|
931
954
|
term: {
|
|
932
955
|
'mappingInfo.type': ticketsFeature ? 'review' : ticketsApproveFeature ?
|
|
933
|
-
'approve' :'tagging',
|
|
956
|
+
'approve' : 'tagging',
|
|
934
957
|
},
|
|
935
958
|
},
|
|
936
959
|
{
|
|
@@ -944,14 +967,14 @@ export async function ticketList( req, res ) {
|
|
|
944
967
|
searchQuery.query.bool.must.push( {
|
|
945
968
|
term: {
|
|
946
969
|
'mappingInfo.type': inputData?.permissionType == 'review' ? 'review' :
|
|
947
|
-
|
|
970
|
+
'approve',
|
|
948
971
|
},
|
|
949
972
|
} );
|
|
950
973
|
}
|
|
951
974
|
|
|
952
975
|
if ( inputData.searchValue && inputData.searchValue !== '' ) {
|
|
953
|
-
searchQuery.query.bool['should'] =[];
|
|
954
|
-
searchQuery.query.bool.should=[
|
|
976
|
+
searchQuery.query.bool['should'] = [];
|
|
977
|
+
searchQuery.query.bool.should = [
|
|
955
978
|
|
|
956
979
|
{
|
|
957
980
|
'wildcard': {
|
|
@@ -1034,7 +1057,7 @@ export async function ticketList( req, res ) {
|
|
|
1034
1057
|
}
|
|
1035
1058
|
}
|
|
1036
1059
|
} else {
|
|
1037
|
-
if ( inputData?.permissionType ==='approve' ) {
|
|
1060
|
+
if ( inputData?.permissionType === 'approve' ) {
|
|
1038
1061
|
for ( let item of ticketListData ) {
|
|
1039
1062
|
temp.push( {
|
|
1040
1063
|
|
|
@@ -1058,7 +1081,7 @@ export async function ticketList( req, res ) {
|
|
|
1058
1081
|
|
|
1059
1082
|
} );
|
|
1060
1083
|
}
|
|
1061
|
-
} else if ( inputData?.permissionType ==='review' ) {
|
|
1084
|
+
} else if ( inputData?.permissionType === 'review' ) {
|
|
1062
1085
|
for ( let item of ticketListData ) {
|
|
1063
1086
|
temp.push( {
|
|
1064
1087
|
|
|
@@ -2365,7 +2388,7 @@ export async function openTicketList( req, res ) {
|
|
|
2365
2388
|
// INSERT_YOUR_CODE
|
|
2366
2389
|
// Add sorting by revicedPerc descending (highest revised accuracy first)
|
|
2367
2390
|
openSearchQuery.sort = [
|
|
2368
|
-
{ 'revicedPerc.keyword': { order: inputData?.sortOrder === 1? 'asc':'desc' } },
|
|
2391
|
+
{ 'revicedPerc.keyword': { order: inputData?.sortOrder === 1 ? 'asc' : 'desc' } },
|
|
2369
2392
|
];
|
|
2370
2393
|
|
|
2371
2394
|
|
|
@@ -2587,7 +2610,7 @@ export async function updateTempStatus( req, res ) {
|
|
|
2587
2610
|
);
|
|
2588
2611
|
|
|
2589
2612
|
|
|
2590
|
-
const taggedImages = getSearchResp?.body?.hits?.hits?.length > 0? getSearchResp?.body?.hits?.hits : [];
|
|
2613
|
+
const taggedImages = getSearchResp?.body?.hits?.hits?.length > 0 ? getSearchResp?.body?.hits?.hits : [];
|
|
2591
2614
|
const logs = {
|
|
2592
2615
|
type: inputData.type,
|
|
2593
2616
|
storeId: taggedImages?.[0]?._source?.storeId,
|
|
@@ -9,6 +9,8 @@ import { findteams } from '../services/teams.service.js';
|
|
|
9
9
|
import { findcluster } from '../services/cluster.service.js';
|
|
10
10
|
import { sendPushNotification } from 'tango-app-api-middleware';
|
|
11
11
|
import dayjs from 'dayjs';
|
|
12
|
+
import { sendSqsMessage } from '../controllers/footfallDirectory.controllers.js';
|
|
13
|
+
import { countDocumnetsCamera } from '../services/camera.service.js';
|
|
12
14
|
// import utc from 'dayjs/plugin/utc.js';
|
|
13
15
|
// import timezone from 'dayjs/plugin/timezone.js';
|
|
14
16
|
|
|
@@ -232,6 +234,7 @@ export async function ticketCreation( req, res, next ) {
|
|
|
232
234
|
try {
|
|
233
235
|
const inputData = req.body;
|
|
234
236
|
const sqs = JSON.parse( process.env.SQS );
|
|
237
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
235
238
|
if ( inputData?.type !== 'create' ) {
|
|
236
239
|
return next();
|
|
237
240
|
}
|
|
@@ -250,7 +253,6 @@ export async function ticketCreation( req, res, next ) {
|
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
// get the footfall count from opensearch
|
|
253
|
-
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
254
256
|
const dateString = `${inputData.storeId}_${inputData.dateString}`;
|
|
255
257
|
const getQuery = {
|
|
256
258
|
query: {
|
|
@@ -547,11 +549,17 @@ export async function ticketCreation( req, res, next ) {
|
|
|
547
549
|
}
|
|
548
550
|
}
|
|
549
551
|
|
|
550
|
-
|
|
551
|
-
let checkapprove = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'approver' && data.isChecked === true );
|
|
552
|
+
const revision = getConfig.footfallDirectoryConfigs?.revision ?? [];
|
|
552
553
|
|
|
553
|
-
|
|
554
|
-
|
|
554
|
+
const hasReviewer = revision.some(
|
|
555
|
+
( data ) => data.actionType === 'reviewer' && data.isChecked === true,
|
|
556
|
+
);
|
|
557
|
+
const hasApprover = revision.some(
|
|
558
|
+
( data ) => data.actionType === 'approver' && data.isChecked === true,
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
if ( hasReviewer || hasApprover ) {
|
|
562
|
+
const userQuery = [
|
|
555
563
|
{
|
|
556
564
|
$match: {
|
|
557
565
|
clientId: getstoreName.clientId,
|
|
@@ -559,40 +567,49 @@ export async function ticketCreation( req, res, next ) {
|
|
|
559
567
|
},
|
|
560
568
|
},
|
|
561
569
|
];
|
|
562
|
-
let finduserList = await aggregateUser( userQuery );
|
|
563
570
|
|
|
571
|
+
const finduserList = await aggregateUser( userQuery );
|
|
564
572
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
let description = `Created on ${createdOn}`;
|
|
569
|
-
let Data = {
|
|
570
|
-
'title': title,
|
|
571
|
-
'body': description,
|
|
572
|
-
'type': 'create',
|
|
573
|
-
'date': record.dateString,
|
|
574
|
-
'storeId': record.storeId,
|
|
575
|
-
'clientId': record.clientId,
|
|
576
|
-
'ticketId': record.ticketId,
|
|
577
|
-
};
|
|
573
|
+
const createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
574
|
+
const title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
|
|
575
|
+
const description = `Created on ${createdOn}`;
|
|
578
576
|
|
|
579
|
-
|
|
577
|
+
const Data = {
|
|
578
|
+
title,
|
|
579
|
+
body: description,
|
|
580
|
+
type: 'create',
|
|
581
|
+
date: record.dateString,
|
|
582
|
+
storeId: record.storeId,
|
|
583
|
+
clientId: record.clientId,
|
|
584
|
+
ticketId: record.ticketId,
|
|
585
|
+
};
|
|
580
586
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
587
|
+
await Promise.all(
|
|
588
|
+
( finduserList || [] ).map( async ( userData ) => {
|
|
589
|
+
const ticketsFeature = userData?.rolespermission?.some(
|
|
590
|
+
( f ) =>
|
|
591
|
+
f.featureName === 'FootfallDirectory' &&
|
|
592
|
+
f.modules?.some(
|
|
593
|
+
( m ) =>
|
|
594
|
+
m.name === 'reviewer' && ( m.isAdd === true || m.isEdit === true ),
|
|
595
|
+
),
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
if ( !ticketsFeature ) return;
|
|
599
|
+
|
|
600
|
+
const notifyUser = await getAssinedStore( userData, req.body.storeId );
|
|
601
|
+
if ( !notifyUser || !userData?.fcmToken ) return;
|
|
602
|
+
|
|
603
|
+
await sendPushNotification( title, description, userData.fcmToken, Data );
|
|
604
|
+
} ),
|
|
605
|
+
);
|
|
589
606
|
}
|
|
590
607
|
|
|
591
608
|
|
|
592
609
|
const id = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
|
|
593
610
|
const insertResult = await insertWithId( openSearch.footfallDirectory, id, record );
|
|
594
611
|
if ( insertResult && insertResult.statusCode === 201 ) {
|
|
595
|
-
|
|
612
|
+
// After successful ticket creation, update status to "submitted" in revop index for the relevant records
|
|
596
613
|
|
|
597
614
|
|
|
598
615
|
const bulkUpdateBody = taggingImages.map( ( img ) => [
|
|
@@ -604,7 +621,93 @@ export async function ticketCreation( req, res, next ) {
|
|
|
604
621
|
await bulkUpdate( bulkUpdateBody ); // Optionally use a dedicated bulk helper if available
|
|
605
622
|
}
|
|
606
623
|
|
|
624
|
+
if ( record.status = 'Closed' ) {
|
|
625
|
+
const query = {
|
|
626
|
+
storeId: inputData?.storeId,
|
|
627
|
+
isVideoStream: true,
|
|
628
|
+
};
|
|
629
|
+
const getStoreType = await countDocumnetsCamera( query );
|
|
630
|
+
const revopInfoQuery = {
|
|
631
|
+
size: 10000,
|
|
632
|
+
query: {
|
|
633
|
+
bool: {
|
|
634
|
+
must: [
|
|
635
|
+
{
|
|
636
|
+
term: {
|
|
637
|
+
'storeId.keyword': inputData.storeId,
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
term: {
|
|
642
|
+
'dateString': inputData.dateString,
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
term: {
|
|
647
|
+
'isParent': false,
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
term: {
|
|
652
|
+
isChecked: true,
|
|
653
|
+
},
|
|
654
|
+
},
|
|
655
|
+
],
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
_source: [ 'tempId' ],
|
|
659
|
+
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const revopInfo = await getOpenSearchData( openSearch.revop, revopInfoQuery );
|
|
607
663
|
|
|
664
|
+
// Get all tempIds from revopInfo response
|
|
665
|
+
const tempIds =
|
|
666
|
+
revopInfo?.body?.hits?.hits?.map( ( hit ) => hit?._source?.tempId ).filter( Boolean ) || [];
|
|
667
|
+
// Prepare management eyeZone query based on storeId and dateString
|
|
668
|
+
const managerEyeZoneQuery = {
|
|
669
|
+
size: 1,
|
|
670
|
+
query: {
|
|
671
|
+
bool: {
|
|
672
|
+
must: [
|
|
673
|
+
{
|
|
674
|
+
term: {
|
|
675
|
+
'storeId.keyword': inputData.storeId,
|
|
676
|
+
},
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
term: {
|
|
680
|
+
'storeDate': inputData.dateString,
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
_source: [ 'originalToTrackerCustomerMapping' ],
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// Query the managerEyeZone index for the matching document
|
|
690
|
+
const managerEyeZoneResp = await getOpenSearchData( openSearch.managerEyeZone, managerEyeZoneQuery );
|
|
691
|
+
const managerEyeZoneHit = managerEyeZoneResp?.body?.hits?.hits?.[0]?._source;
|
|
692
|
+
// Extract originalToTrackerCustomerMapping if it exists
|
|
693
|
+
const mapping =
|
|
694
|
+
managerEyeZoneHit && managerEyeZoneHit.originalToTrackerCustomerMapping ?
|
|
695
|
+
managerEyeZoneHit.originalToTrackerCustomerMapping :
|
|
696
|
+
{};
|
|
697
|
+
|
|
698
|
+
// If you want to compare or find matching tempIds in the mapping
|
|
699
|
+
// The mapping is { "1": tempId1, ... }, so get values as array of tempIds
|
|
700
|
+
// const managerMappedTempIds = Object.values( mapping );
|
|
701
|
+
|
|
702
|
+
// Find tempIds that exist in both revopInfo results and manager mapping
|
|
703
|
+
const temp = [];
|
|
704
|
+
tempIds.filter( ( tid ) => mapping[tid] !== null ? temp.push( { tempId: mapping[tid] } ) :'' );
|
|
705
|
+
const isSendMessge = await sendSqsMessage( inputData, temp, getStoreType, inputData.storeId );
|
|
706
|
+
if ( isSendMessge == true ) {
|
|
707
|
+
logger.info( '....1' );
|
|
708
|
+
// return true; // res.sendSuccess( 'Ticket has been updated successfully' );
|
|
709
|
+
} // Example: log or use these tempIds for further logic
|
|
710
|
+
}
|
|
608
711
|
// Check if ticketCount exceeds breach limit within config months and revised footfall percentage > config accuracy
|
|
609
712
|
|
|
610
713
|
if ( req.accuracyBreach && req.accuracyBreach.ticketCount && req.accuracyBreach.days && req.accuracyBreach.accuracy ) {
|
|
@@ -630,14 +733,14 @@ export async function ticketCreation( req, res, next ) {
|
|
|
630
733
|
const startDateObj = new Date( currentDateObj );
|
|
631
734
|
|
|
632
735
|
if ( breachDays === 30 ) {
|
|
633
|
-
|
|
736
|
+
// Consider within this month
|
|
634
737
|
startDateObj.setDate( 1 ); // First day of current month
|
|
635
738
|
} else if ( breachDays === 60 ) {
|
|
636
|
-
|
|
739
|
+
// Consider this month and last month
|
|
637
740
|
startDateObj.setMonth( startDateObj.getMonth() - 1 );
|
|
638
741
|
startDateObj.setDate( 1 ); // First day of last month
|
|
639
742
|
} else {
|
|
640
|
-
|
|
743
|
+
// For other values, calculate months from days
|
|
641
744
|
const breachMonths = Math.ceil( breachDays / 30 );
|
|
642
745
|
startDateObj.setMonth( startDateObj.getMonth() - breachMonths + 1 );
|
|
643
746
|
startDateObj.setDate( 1 );
|
|
@@ -685,21 +788,21 @@ export async function ticketCreation( req, res, next ) {
|
|
|
685
788
|
}
|
|
686
789
|
|
|
687
790
|
if ( breachTicketsCount >= breachCount ) {
|
|
688
|
-
|
|
791
|
+
// Calculate remaining future days in the config period
|
|
689
792
|
const futureDates = [];
|
|
690
793
|
|
|
691
794
|
// Calculate end date of config period
|
|
692
795
|
const configEndDateObj = new Date( currentDateObj );
|
|
693
796
|
if ( breachDays === 30 ) {
|
|
694
|
-
|
|
797
|
+
// End of current month
|
|
695
798
|
configEndDateObj.setMonth( configEndDateObj.getMonth() + 1 );
|
|
696
799
|
configEndDateObj.setDate( 0 ); // Last day of current month
|
|
697
800
|
} else if ( breachDays === 60 ) {
|
|
698
|
-
|
|
801
|
+
// End of next month
|
|
699
802
|
configEndDateObj.setMonth( configEndDateObj.getMonth() + 2 );
|
|
700
803
|
configEndDateObj.setDate( 0 ); // Last day of next month
|
|
701
804
|
} else {
|
|
702
|
-
|
|
805
|
+
// For other values, add the remaining days
|
|
703
806
|
const remainingDays = breachDays - ( Math.floor( ( currentDateObj - startDateObj ) / ( 1000 * 60 * 60 * 24 ) ) );
|
|
704
807
|
configEndDateObj.setDate( configEndDateObj.getDate() + remainingDays );
|
|
705
808
|
}
|
|
@@ -754,7 +857,7 @@ export async function ticketCreation( req, res, next ) {
|
|
|
754
857
|
}
|
|
755
858
|
} catch ( error ) {
|
|
756
859
|
const err = error.message || 'Internal Server Error';
|
|
757
|
-
logger.error( { error:
|
|
860
|
+
logger.error( { error: error, funtion: 'ticketCreation' } );
|
|
758
861
|
return res.sendError( err, 500 );
|
|
759
862
|
}
|
|
760
863
|
}
|