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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-infra",
3
- "version": "3.9.5-vms.60",
3
+ "version": "3.9.5-vms.62",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -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
- 'approve',
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
- let checkreview = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'reviewer' && data.isChecked === true );
551
- let checkapprove = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'approver' && data.isChecked === true );
552
+ const revision = getConfig.footfallDirectoryConfigs?.revision ?? [];
552
553
 
553
- if ( checkreview.length > 0 || checkapprove.length > 0 ) {
554
- let userQuery = [
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
- for ( let userData of finduserList ) {
566
- let title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
567
- let createdOn = dayjs().format( 'DD MMM YYYY' );
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
- const ticketsFeature = userData?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
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
- if ( ticketsFeature ) {
582
- let notifyuser = await getAssinedStore( userData, req.body.storeId );
583
- if ( userData && userData.fcmToken && notifyuser ) {
584
- const fcmToken = userData.fcmToken;
585
- await sendPushNotification( title, description, fcmToken, Data );
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
- // After successful ticket creation, update status to "submitted" in revop index for the relevant records
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
- // Consider within this month
736
+ // Consider within this month
634
737
  startDateObj.setDate( 1 ); // First day of current month
635
738
  } else if ( breachDays === 60 ) {
636
- // Consider this month and last month
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
- // For other values, calculate months from days
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
- // Calculate remaining future days in the config period
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
- // End of current month
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
- // End of next month
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
- // For other values, add the remaining days
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: err, funtion: 'ticketCreation' } );
860
+ logger.error( { error: error, funtion: 'ticketCreation' } );
758
861
  return res.sendError( err, 500 );
759
862
  }
760
863
  }