tango-app-api-infra 3.9.25-vmsbug.2 → 3.9.26

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.25-vmsbug.2",
3
+ "version": "3.9.26",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -452,11 +452,11 @@ export async function emailUserList( req, res ) {
452
452
  }
453
453
  }
454
454
  if ( getconfigs.ticketConfigs.infraReport.allowSpoc ) {
455
- let spocList=[];
455
+ let spocList = [];
456
456
  let storelist = await findStore( { 'clientId': req.query.clientId, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1, 'spocDetails': 1 } );
457
457
  for ( let store of storelist ) {
458
- if ( store.spocDetails&&store.spocDetails.length>0 ) {
459
- if ( store.spocDetails[0].email!='' ) {
458
+ if ( store.spocDetails && store.spocDetails.length > 0 ) {
459
+ if ( store.spocDetails[0].email != '' ) {
460
460
  spocList.push( {
461
461
  clientId: req.query.clientId,
462
462
  ticketConfigs: getconfigs.ticketConfigs,
@@ -481,7 +481,7 @@ export async function emailUserList( req, res ) {
481
481
  userName: user.name,
482
482
  storeList: [],
483
483
  };
484
- if ( user.stores&&user.stores.length>0 ) {
484
+ if ( user.stores && user.stores.length > 0 ) {
485
485
  let storelist = await findStore( { 'storeId': { $in: user.stores }, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
486
486
  obj.storeList = storelist;
487
487
  }
@@ -510,7 +510,7 @@ export async function emailUserList( req, res ) {
510
510
  user.storeList = [];
511
511
  for ( let group of user.assignedValue ) {
512
512
  let groupdata = await findOneGroup( { '_id': group, 'clientId': user.clientId } );
513
- if ( groupdata&&groupdata.storeList ) {
513
+ if ( groupdata && groupdata.storeList ) {
514
514
  let storelist = await findStore( { 'storeId': { $in: groupdata.storeList }, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
515
515
  user.storeList = [ ...user.storeList, ...storelist ];
516
516
  }
@@ -529,7 +529,7 @@ export async function emailUserList( req, res ) {
529
529
  }
530
530
  }
531
531
  } else if ( user.ticketConfigs.infraReport.type && user.ticketConfigs.infraReport.type === 'defined' ) {
532
- let times =await generateTimeIntervals( user.ticketConfigs.infraReport.startTime, user.ticketConfigs.infraReport.endTime, user.ticketConfigs.infraReport.interval );
532
+ let times = await generateTimeIntervals( user.ticketConfigs.infraReport.startTime, user.ticketConfigs.infraReport.endTime, user.ticketConfigs.infraReport.interval );
533
533
  for ( let store of user.storeList ) {
534
534
  const result = await checkStoreTimezoneMatchesInterval( times, store.storeProfile.timeZone );
535
535
  if ( result ) {
@@ -653,11 +653,11 @@ export async function emailUserListv2( req, res ) {
653
653
  }
654
654
  }
655
655
  if ( getconfigs.ticketConfigs.infraReport.allowSpoc ) {
656
- let spocList=[];
656
+ let spocList = [];
657
657
  let storelist = await findStore( { 'clientId': req.query.clientId, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1, 'spocDetails': 1 } );
658
658
  for ( let store of storelist ) {
659
- if ( store.spocDetails&&store.spocDetails.length>0 ) {
660
- if ( store.spocDetails[0].email!='' ) {
659
+ if ( store.spocDetails && store.spocDetails.length > 0 ) {
660
+ if ( store.spocDetails[0].email != '' ) {
661
661
  spocList.push( {
662
662
  clientId: req.query.clientId,
663
663
  ticketConfigs: getconfigs.ticketConfigs,
@@ -682,14 +682,14 @@ export async function emailUserListv2( req, res ) {
682
682
  userName: user.name,
683
683
  storeList: [],
684
684
  };
685
- if ( user.stores&&user.stores.length>0 ) {
685
+ if ( user.stores && user.stores.length > 0 ) {
686
686
  let storelist = await findStore( { 'storeId': { $in: user.stores }, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
687
687
  obj.storeList = storelist;
688
688
  }
689
689
  for ( let cluster of user.clusters ) {
690
690
  let clusterdata = await findOneCluster( { '_id': cluster, 'clientId': req.query.clientId } );
691
691
 
692
- if ( clusterdata&&clusterdata.stores ) {
692
+ if ( clusterdata && clusterdata.stores ) {
693
693
  let stores = clusterdata.stores.map( ( data ) => data.storeId );
694
694
  let storelist = await findStore( { 'storeId': { $in: stores }, 'status': 'active', 'edge.firstFile': true }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
695
695
 
@@ -707,7 +707,7 @@ export async function emailUserListv2( req, res ) {
707
707
  for ( let user of clientList ) {
708
708
  if ( user.userType == 'client' ) {
709
709
  if ( user.role !== 'superadmin' ) {
710
- let storeIds =new Set();
710
+ let storeIds = new Set();
711
711
  if ( user.assignedStores ) {
712
712
  storeIds = new Set( user.assignedStores.map( ( store ) => store.storeId ) );
713
713
  }
@@ -745,7 +745,7 @@ export async function emailUserListv2( req, res ) {
745
745
  }
746
746
  }
747
747
  let TeamMember = await findteams( { clientId: user.clientId, users: { $elemMatch: { email: user.email } } } );
748
- if ( TeamMember&&TeamMember.length>0 ) {
748
+ if ( TeamMember && TeamMember.length > 0 ) {
749
749
  for ( let team of TeamMember ) {
750
750
  let clusterList = await findcluster( { clientId: user.clientId, teams: { $elemMatch: { name: team.teamName } } } );
751
751
  if ( clusterList.length > 0 ) {
@@ -756,7 +756,7 @@ export async function emailUserListv2( req, res ) {
756
756
  }
757
757
  }
758
758
  let TeamLeader = await findteams( { clientId: user.clientId, Teamlead: { $elemMatch: { email: user.email } } } );
759
- if ( TeamLeader&&TeamLeader.length>0 ) {
759
+ if ( TeamLeader && TeamLeader.length > 0 ) {
760
760
  for ( let team of TeamLeader ) {
761
761
  let clusterList = await findcluster( { clientId: user.clientId, teams: { $elemMatch: { name: team.teamName } } } );
762
762
  if ( clusterList.length > 0 ) {
@@ -790,7 +790,7 @@ export async function emailUserListv2( req, res ) {
790
790
  }
791
791
  }
792
792
  } else if ( user.ticketConfigs.infraReport.type && user.ticketConfigs.infraReport.type === 'defined' ) {
793
- let times =await generateTimeIntervals( user.ticketConfigs.infraReport.startTime, user.ticketConfigs.infraReport.endTime, user.ticketConfigs.infraReport.interval );
793
+ let times = await generateTimeIntervals( user.ticketConfigs.infraReport.startTime, user.ticketConfigs.infraReport.endTime, user.ticketConfigs.infraReport.interval );
794
794
  for ( let store of user.storeList ) {
795
795
  const result = await checkStoreTimezoneMatchesInterval( times, store.storeProfile.timeZone );
796
796
  if ( result ) {
@@ -941,7 +941,7 @@ export async function infraReportSent( req, res ) {
941
941
 
942
942
  let ticketList = await aggregateTangoTicket( query );
943
943
  const exportdata = [];
944
- if ( ticketList&&ticketList.length>0 ) {
944
+ if ( ticketList && ticketList.length > 0 ) {
945
945
  for ( let element of ticketList ) {
946
946
  let clientuser = await findOneUser( { _id: element.ticketDetails.addressingClient } );
947
947
  let tangouser = await findOneUser( { _id: element.ticketDetails.addressingUser } );
@@ -953,7 +953,7 @@ export async function infraReportSent( req, res ) {
953
953
  'BrandName': element.basicDetails.clientName,
954
954
  'TicketCreatedDate & Time': dayjs( element.createdAt ).tz( 'Asia/Kolkata' ).format( 'YYYY-MM-DD HH:mm A' ),
955
955
  'StoreID': element.basicDetails.storeId,
956
- 'StoreCode': findstore.storeProfile&&findstore.storeProfile.storeCode?findstore.storeProfile.storeCode:'-',
956
+ 'StoreCode': findstore.storeProfile && findstore.storeProfile.storeCode ? findstore.storeProfile.storeCode : '-',
957
957
  'StoreName': element.basicDetails.storeName,
958
958
  'PrimaryIssue ': element.primaryIssue,
959
959
  'SecondaryIssue': element.secondaryIssue,
@@ -1113,6 +1113,7 @@ export async function camAngleChangeReport( req, res ) {
1113
1113
  'Store Name': findStore.storeName,
1114
1114
  'Store Code': findStore.storeId,
1115
1115
  'Date Changed': formattedPreviousDay,
1116
+ 'Reason': stream?.reason?stream?.reason:'-',
1116
1117
  'ImageURL': {
1117
1118
  url: Image,
1118
1119
  label: 'Angle changed Image',
@@ -1208,7 +1209,7 @@ export async function edgeApplogsCheck( req, res ) {
1208
1209
  const errorLogList = await getOpenSearchData( JSON.parse( process.env.OPENSEARCH ).edgeAppSystemLogs, errorLog );
1209
1210
  let internetSlowcount = [];
1210
1211
  let result = [];
1211
- let apploginCount=[];
1212
+ let apploginCount = [];
1212
1213
  function createLogCheck( error ) {
1213
1214
  return {
1214
1215
  code: error._source.log_code,
@@ -1243,7 +1244,7 @@ export async function edgeApplogsCheck( req, res ) {
1243
1244
  let newraray = apploginCount.reverse();
1244
1245
 
1245
1246
  let findissueEdgeApp = {};
1246
- if ( newraray.length>0 ) {
1247
+ if ( newraray.length > 0 ) {
1247
1248
  result = [ ...result, ...[ newraray[0] ] ];
1248
1249
  }
1249
1250
  if ( result.length > 0 ) {
@@ -1436,7 +1437,7 @@ export async function edgeApplogsCheck( req, res ) {
1436
1437
  item.ticketId === ticket.ticketId,
1437
1438
  );
1438
1439
  if ( !existsInArray ) {
1439
- if ( diffInMinutes>60 &&diffInMinutes<=180 ) {
1440
+ if ( diffInMinutes > 60 && diffInMinutes <= 180 ) {
1440
1441
  findissueEdgeApp = {
1441
1442
  ticketId: ticket.ticketId,
1442
1443
  edgelog: findissue,
@@ -1479,86 +1480,330 @@ export async function edgeApplogsCheck( req, res ) {
1479
1480
  res.sendError( error, 500 );
1480
1481
  }
1481
1482
  }
1483
+ async function processTicket( ticket, opensearch ) {
1484
+ const ticketResult = [];
1485
+ const ticketNotAddressed = [];
1486
+
1487
+ const date = dayjs( ticket.createdAt ).format( 'YYYY-MM-DD' );
1488
+ const istTimestamp = dayjs.utc( ticket.createdAt ).tz( 'Asia/Kolkata' ).format( 'HH:mm:ss' );
1489
+ const ticketTime = dayjs( `${date} ${istTimestamp}` );
1490
+
1491
+ const RELEVANT_CODES = new Set( [ 1000, 1003, 1004, 1007, 1011, 1013, 1014, 1016, 1022, 1024, 1025, 1026, 1044, 1050, 1051, 1053, 1055, 1056, 1057, 1058 ] );
1492
+
1493
+ // ── Fetch logs from OpenSearch ─────────────────────────────────────────
1494
+ const errorLogList = await getOpenSearchData( opensearch.edgeAppSystemLogs, {
1495
+ size: 5000,
1496
+ query: {
1497
+ bool: {
1498
+ must: [
1499
+ { range: { log_code: { gte: 1000 } } },
1500
+ { term: { 'store_date.keyword': dayjs( date ).format( 'DD-MM-YYYY' ) } },
1501
+ { term: { 'storeId.keyword': ticket.basicDetails.storeId } },
1502
+ ],
1503
+ },
1504
+ },
1505
+ sort: [ { timestamp: { order: 'asc' } } ],
1506
+ } );
1507
+
1508
+ // ── Classify logs into result and reference buckets ────────────────────
1509
+ const result = [];
1510
+ const resumeLogs = []; // 1010 — paired with 1011 (sleep mode)
1511
+ const internetConnectedLogs = []; // 1006 — paired with 1007/2007 (internet down)
1512
+ const loginLogs = []; // 1052/1054 — paired with 1058 and 1053
1513
+
1514
+ for ( const error of errorLogList.body.hits.hits ) {
1515
+ const logCode = Number( error._source.log_code );
1516
+ const log = { code: String( logCode ), edgelog: error._source.data };
1517
+
1518
+ if ( RELEVANT_CODES.has( logCode ) ) result.push( log );
1519
+ if ( logCode === 1010 ) resumeLogs.push( log );
1520
+ if ( logCode === 1006 ) internetConnectedLogs.push( log );
1521
+ if ( logCode === 1052 || logCode === 1054 ) loginLogs.push( log );
1522
+ if ( logCode > 2000 && logCode !== 2014 ) result.push( log );
1523
+ if ( logCode === 1005 ) {
1524
+ const megabytes = bytesToMB( error._source.data.upload_Speed.split( '.' )[0] );
1525
+ if ( megabytes < 2 ) result.push( log );
1526
+ }
1527
+ }
1528
+
1529
+ if ( !result.length ) return { ticketResult, ticketNotAddressed };
1530
+
1531
+ // ── Helpers scoped to this ticket ──────────────────────────────────────
1532
+ const codeSet = new Set( result.map( ( r ) => Number( r.code ) ) );
1533
+ const logTime = ( time ) => dayjs( `${date} ${time}` );
1534
+ const beforeTicket = ( time ) => logTime( time ).isBefore( ticketTime );
1535
+ const refLogBefore = ( refLogs, targetTime ) =>
1536
+ refLogs.find( ( l ) => logTime( l.edgelog.occuringTime ).isBefore( targetTime ) );
1537
+
1538
+ let storeData = null;
1539
+ const getStore = async () => {
1540
+ if ( !storeData ) storeData = await findOneStore( { storeId: ticket.basicDetails.storeId } );
1541
+ return storeData;
1542
+ };
1543
+
1544
+ const recordIssue = async ( primary, secondary, edgelog ) => {
1545
+ const issue = { ticketId: ticket.ticketId, storeId: ticket.basicDetails.storeId, primary, secondary, edgelog };
1546
+ const updateResult = await updateIssue( issue );
1547
+ if ( updateResult?.skipped ) {
1548
+ ticketNotAddressed.push( { ticketId: ticket.ticketId, storeId: ticket.basicDetails.storeId, storeName: ticket.basicDetails.storeName, reason: updateResult.reason } );
1549
+ } else {
1550
+ ticketResult.push( issue );
1551
+ }
1552
+ };
1553
+
1554
+ const appcrashcount = [];
1555
+ const appservercount = [];
1556
+ const logincount = [];
1557
+
1558
+ for ( const log of result ) {
1559
+ if ( ticketResult.length || ticketNotAddressed.length ) break;
1560
+
1561
+ const code = Number( log.code );
1562
+ const occursAt = log.edgelog?.occuringTime;
1563
+
1564
+ // ── System Issues ──────────────────────────────────────────────────
1565
+
1566
+ if ( code === 1003 && beforeTicket( occursAt ) ) {
1567
+ await recordIssue( 'System Issues', [ 'Antivirus blocking' ], log );
1568
+ }
1569
+
1570
+ if ( code === 1000 && beforeTicket( occursAt ) ) {
1571
+ // Antivirus blocking: >= 3 app crashes within a 1-hour window
1572
+ appcrashcount.push( logTime( occursAt ) );
1573
+ const oneHourAgo = logTime( occursAt ).subtract( 1, 'hour' );
1574
+ if ( appcrashcount.filter( ( t ) => t.isAfter( oneHourAgo ) ).length >= 3 ) {
1575
+ await recordIssue( 'System Issues', [ 'Antivirus blocking' ], log );
1576
+ }
1577
+ }
1578
+
1579
+ if ( code === 1011 && beforeTicket( occursAt ) ) {
1580
+ // Sleep mode: resume (1010) came more than 15 min after suspend (1011)
1581
+ const suspendTime = logTime( occursAt );
1582
+ const resumeLog = resumeLogs.find( ( r ) => logTime( r.edgelog.occuringTime ).isAfter( suspendTime ) );
1583
+ if ( resumeLog ) {
1584
+ const diffMin = logTime( resumeLog.edgelog.occuringTime ).diff( suspendTime, 'minute' );
1585
+ if ( diffMin > 15 ) await recordIssue( 'System Issues', [ 'System is in Sleep Mode' ], log );
1586
+ }
1587
+ }
1588
+
1589
+ if ( code === 1051 && beforeTicket( occursAt ) ) {
1590
+ // High utilization: any of CPU / memory / disk >= 90%
1591
+ const cpu = Number( log.edgelog.cpu_usage ) || 0;
1592
+ const memory = Number( log.edgelog.memory_usage ) || 0;
1593
+ const disk = Number( log.edgelog.disk_usage ) || 0;
1594
+ if ( cpu >= 90 || memory >= 90 || disk >= 90 ) {
1595
+ await recordIssue( 'System Issues', [ 'System utilization high - CPU or memory or Disk' ], log );
1596
+ }
1597
+ }
1598
+
1599
+ if ( code === 1014 && beforeTicket( occursAt ) ) {
1600
+ // Confirm mismatch occurred during store operating hours (in the store's registered timezone)
1601
+ const store = await getStore();
1602
+ const occurTimeInStoreZone = dayjs.tz( `${date} ${occursAt}`, 'Asia/Kolkata' ).tz( store.storeProfile.timeZone );
1603
+ const storeOpenInStoreZone = dayjs.tz( `${date} ${store.storeProfile.open}`, store.storeProfile.timeZone );
1604
+ const storeCloseInStoreZone = dayjs.tz( `${date} ${store.storeProfile.close}`, store.storeProfile.timeZone );
1605
+ if ( occurTimeInStoreZone.isAfter( storeOpenInStoreZone ) && occurTimeInStoreZone.isBefore( storeCloseInStoreZone ) ) {
1606
+ await recordIssue( 'System Issues', [ 'Date/Time Mismatch Issue' ], log );
1607
+ }
1608
+ }
1609
+
1610
+ // ── Camera Issues ──────────────────────────────────────────────────
1611
+
1612
+ if ( code === 2024 && beforeTicket( occursAt ) ) {
1613
+ await recordIssue( 'Camera Issues', [ 'Camera Not working due Network disconnect' ], log.edgelog );
1614
+ }
1615
+
1616
+ if ( code === 1024 && beforeTicket( log.edgelog?.data?.occuringTime ) ) {
1617
+ // 1024 + 1050 + 1055 → Network switched
1618
+ // 1024 + 1055 → Camera not working
1619
+ // 1024 + 1056 → RTSP / credential changed
1620
+ let secondary;
1621
+ if ( codeSet.has( 1050 ) && codeSet.has( 1055 ) ) secondary = 'Camera Not working because of Network switched';
1622
+ else if ( codeSet.has( 1055 ) ) secondary = 'Camera Not working';
1623
+ else if ( codeSet.has( 1056 ) ) secondary = 'RTSP URL not supported / Camera credential changed';
1624
+ if ( secondary ) await recordIssue( 'Camera Issues', [ secondary ], log.edgelog?.data );
1625
+ }
1626
+
1627
+ // ── Operational Issues ─────────────────────────────────────────────
1628
+
1629
+ if ( code === 1004 || code === 1013 ) {
1630
+ // System turned on lately: app/system start >= 20 min after store open
1631
+ const store = await getStore();
1632
+ const diffMin = logTime( occursAt ).diff( logTime( store.storeProfile.open ), 'minute' );
1633
+ if ( diffMin >= 20 ) await recordIssue( 'Store Operation Issues', [ 'System turned on lately' ], log );
1634
+ }
1635
+
1636
+ if ( code === 1058 && beforeTicket( occursAt ) ) {
1637
+ // User logged in lately: 1058 came > 5 min after last login event (1052/1054)
1638
+ const loginLog = refLogBefore( loginLogs, logTime( occursAt ) );
1639
+ if ( loginLog ) {
1640
+ const diffMin = logTime( occursAt ).diff( logTime( loginLog.edgelog.occuringTime ), 'minute' );
1641
+ if ( diffMin > 5 ) await recordIssue( 'Store Operation Issues', [ 'User logged in lately' ], log );
1642
+ }
1643
+ }
1644
+
1645
+ if ( code === 1053 && beforeTicket( occursAt ) ) {
1646
+ // System turned off: shutdown (1053) came > 15 min after last login event (1052/1054)
1647
+ const loginLog = refLogBefore( loginLogs, logTime( occursAt ) );
1648
+ if ( loginLog ) {
1649
+ const diffMin = logTime( occursAt ).diff( logTime( loginLog.edgelog.occuringTime ), 'minute' );
1650
+ if ( diffMin > 15 ) await recordIssue( 'Store Operation Issues', [ 'System turned off' ], log );
1651
+ }
1652
+ }
1653
+
1654
+ // ── App Issues ─────────────────────────────────────────────────────
1655
+
1656
+ if ( code === 1025 && beforeTicket( occursAt ) ) {
1657
+ await recordIssue( 'Application Issues', [ 'App Without Stream' ], log.edgelog );
1658
+ }
1659
+
1660
+ if ( code === 1057 && beforeTicket( occursAt ) ) {
1661
+ // App server issue: > 5 occurrences within a 1-hour window
1662
+ appservercount.push( logTime( occursAt ) );
1663
+ const oneHourAgo = logTime( occursAt ).subtract( 1, 'hour' );
1664
+ if ( appservercount.filter( ( t ) => t.isAfter( oneHourAgo ) ).length > 5 ) {
1665
+ await recordIssue( 'Application Issues', [ 'App server issue' ], log );
1666
+ }
1667
+ }
1668
+
1669
+ if ( code === 1016 && beforeTicket( occursAt ) ) {
1670
+ await recordIssue( 'Application Issues', [ 'App login issue' ], log );
1671
+ }
1672
+
1673
+ // ── Internet Issues ────────────────────────────────────────────────
1674
+
1675
+ if ( ( code === 1007 || code === 2007 ) && beforeTicket( occursAt ) ) {
1676
+ // Internet not working: disconnect (1007/2007) came > 10 min after last connect (1006)
1677
+ const connectedLog = refLogBefore( internetConnectedLogs, logTime( occursAt ) );
1678
+ if ( connectedLog ) {
1679
+ const diffMin = logTime( occursAt ).diff( logTime( connectedLog.edgelog.occuringTime ), 'minute' );
1680
+ if ( diffMin > 10 ) await recordIssue( 'Internet Issues', [ 'Internet not working' ], log );
1681
+ }
1682
+ }
1683
+
1684
+ if ( code === 2004 ) {
1685
+ // Internet not working (legacy): > 3 disconnects after store open and before ticket time
1686
+ const store = await getStore();
1687
+ const occurTime = logTime( occursAt );
1688
+ if ( occurTime.isBefore( ticketTime ) && occurTime.isAfter( logTime( store.storeProfile.open ) ) ) {
1689
+ logincount.push( occursAt );
1690
+ if ( logincount.length > 3 ) await recordIssue( 'Internet Issues', [ 'Internet not working' ], log );
1691
+ }
1692
+ }
1693
+
1694
+ if ( ( code === 1026 || code === 1044 ) && beforeTicket( occursAt ) ) {
1695
+ // Internet Slow: files pushed to cloud in 30 min <= 3
1696
+ if ( ( Number( log.edgelog.files_pushed ) || 0 ) <= 3 ) {
1697
+ await recordIssue( 'Internet Issues', [ 'Internet Slow' ], log );
1698
+ }
1699
+ }
1700
+ }
1701
+
1702
+ return { ticketResult, ticketNotAddressed };
1703
+ }
1704
+
1705
+ export async function edgeApplogsCheckv2( req, res ) {
1706
+ try {
1707
+ const opensearch = JSON.parse( process.env.OPENSEARCH );
1708
+ const finalresult = [];
1709
+ const notAddressed = [];
1710
+
1711
+ const ticketList = await findTangoTicket( {
1712
+ 'issueDate': new Date( req.body.issueDate ),
1713
+ 'status': { $ne: 'closed' },
1714
+ 'ticketDetails.issueStatus': 'notidentified',
1715
+ 'issueType': 'infra',
1716
+ } );
1717
+
1718
+ // Process tickets in parallel chunks to avoid sequential bottleneck
1719
+ const CHUNK_SIZE = 10;
1720
+ for ( let i = 0; i < ticketList.length; i += CHUNK_SIZE ) {
1721
+ const chunk = ticketList.slice( i, i + CHUNK_SIZE );
1722
+ const chunkResults = await Promise.all( chunk.map( ( ticket ) => processTicket( ticket, opensearch ) ) );
1723
+ for ( const { ticketResult, ticketNotAddressed } of chunkResults ) {
1724
+ finalresult.push( ...ticketResult );
1725
+ notAddressed.push( ...ticketNotAddressed );
1726
+ }
1727
+ }
1728
+
1729
+ res.sendSuccess( { count: finalresult.length, result: finalresult, notAddressedCount: notAddressed.length, notAddressed } );
1730
+ } catch ( error ) {
1731
+ logger.error( { error, function: 'edgeApplogsCheckv2' } );
1732
+ res.sendError( error, 500 );
1733
+ }
1734
+ }
1735
+
1482
1736
  function bytesToMB( bytes ) {
1483
1737
  return bytes / ( 1024 * 1024 );
1484
1738
  }
1485
1739
 
1486
1740
  export async function updateIssue( data ) {
1487
1741
  try {
1488
- let Ticket = await findOneTangoTicket(
1489
- {
1490
- ticketId: data.ticketId,
1491
- },
1492
- );
1493
- if ( Ticket ) {
1494
- data.issueType = Ticket.issueType;
1495
- data.basicDetails = Ticket.basicDetails;
1496
- data.ticketDetails = Ticket.ticketDetails;
1497
- data.ticketActivity = Ticket.ticketActivity;
1498
- if ( data.primary && data.secondary && data.secondary.length ) {
1499
- let primaryReason = await findOneinfraReason( { name: data.primary } );
1500
- if ( !primaryReason ) {
1501
- return res.sendError( 'Primary Reason Not exists in database', 500 );
1502
- }
1503
- const secondary = [];
1504
- const steptoReslove = [];
1505
- for ( let i = 0; i < data.secondary.length; i++ ) {
1506
- let secondaryReason = await findOneinfraReason( { name: data.secondary[i] } );
1507
- if ( !secondaryReason ) {
1508
- return res.sendError( `secondary Reason - ${data.secondary[i]} Not exists in database`, 500 );
1509
- }
1510
- secondary.push( {
1511
- name: secondaryReason.name,
1512
- } );
1513
- let resolveSteps = [];
1514
- for ( let i = 0; i < secondaryReason.stepstoResolve.length; i++ ) {
1515
- resolveSteps.push( {
1516
- name: secondaryReason.stepstoResolve[i].name,
1517
- } );
1518
- }
1519
- steptoReslove.push( {
1520
- primaryIssue: secondaryReason.name,
1521
- secondaryIsssue: [ ...resolveSteps ],
1522
- } );
1523
- }
1524
-
1525
- data.ticketActivity.push( {
1526
- actionType: 'issueUpdate',
1527
- actionBy: 'automated',
1528
- IdentifiedBy: 'Tango',
1529
- timeStamp: new Date(),
1530
- reasons: [ {
1531
- primaryIssue: primaryReason.name,
1532
- secondaryIssue: secondary,
1533
- } ],
1534
- },
1535
- );
1742
+ const Ticket = await findOneTangoTicket( { ticketId: data.ticketId } );
1743
+ if ( !Ticket ) return { success: true };
1744
+
1745
+ data.issueType = Ticket.issueType;
1746
+ data.basicDetails = Ticket.basicDetails;
1747
+ data.ticketDetails = Ticket.ticketDetails;
1748
+ data.ticketActivity = Ticket.ticketActivity;
1749
+
1750
+ if ( data.primary && data.secondary && data.secondary.length ) {
1751
+ const primaryReason = await findOneinfraReason( { name: data.primary } );
1752
+ if ( !primaryReason ) {
1753
+ logger.warn( { message: `Primary reason not found: ${data.primary}`, ticketId: data.ticketId } );
1754
+ return { skipped: true, ticketId: data.ticketId, storeId: data.storeId, reason: `Primary reason not found: ${data.primary}` };
1536
1755
  }
1537
- if ( data.issueType == 'infra' ) {
1538
- let client = await findOneClient( { clientId: data.basicDetails.clientId }, { ticketConfigs: 1 } );
1539
- let statusCheckAlertTime = dayjs().add( client.ticketConfigs.statusCheckAlert, 'hours' ).format( 'YYYY-MM-DD hh:mm' );
1540
- data.ticketActivity.push( {
1541
- actionType: 'statusCheck',
1542
- timeStamp: statusCheckAlertTime,
1543
- actionBy: 'Tango',
1544
- IdentifiedBy: 'Tango',
1545
- statusCheckAlertTime: statusCheckAlertTime,
1756
+
1757
+ const secondary = [];
1758
+ const steptoReslove = [];
1759
+ for ( const secondaryName of data.secondary ) {
1760
+ const secondaryReason = await findOneinfraReason( { name: secondaryName } );
1761
+ if ( !secondaryReason ) {
1762
+ logger.warn( { message: `Secondary reason not found: ${secondaryName}`, ticketId: data.ticketId } );
1763
+ return { skipped: true, ticketId: data.ticketId, storeId: data.storeId, reason: `Secondary reason not found: ${secondaryName}` };
1764
+ }
1765
+ secondary.push( { name: secondaryReason.name } );
1766
+ steptoReslove.push( {
1767
+ primaryIssue: secondaryReason.name,
1768
+ secondaryIsssue: secondaryReason.stepstoResolve.map( ( s ) => ( { name: s.name } ) ),
1546
1769
  } );
1547
1770
  }
1548
- let client = await findOneClient( { clientId: data.basicDetails.clientId } );
1549
- let refreshdate = dayjs().add( client.ticketConfigs.refreshAlert, 'days' );
1550
-
1551
- let query = {
1552
- 'ticketActivity': data.ticketActivity,
1553
- 'ticketDetails.issueIdentifiedDate': new Date(),
1554
- 'ticketDetails.issueStatus': 'identified',
1555
- 'status': 'inprogress',
1556
- 'ticketDetails.ticketRefreshTime': new Date( dayjs( refreshdate ).format( 'YYYY-MM-DD' ) ),
1557
- };
1558
- await updateOneTangoTicket( { ticketId: data.ticketId }, query );
1771
+
1772
+ data.ticketActivity.push( {
1773
+ actionType: 'issueUpdate',
1774
+ actionBy: 'automated',
1775
+ IdentifiedBy: 'Tango',
1776
+ timeStamp: new Date(),
1777
+ reasons: [ { primaryIssue: primaryReason.name, secondaryIssue: secondary } ],
1778
+ } );
1779
+ }
1780
+
1781
+ if ( data.issueType == 'infra' ) {
1782
+ const client = await findOneClient( { clientId: data.basicDetails.clientId }, { ticketConfigs: 1 } );
1783
+ const statusCheckAlertTime = dayjs().add( client.ticketConfigs.statusCheckAlert, 'hours' ).format( 'YYYY-MM-DD hh:mm' );
1784
+ data.ticketActivity.push( {
1785
+ actionType: 'statusCheck',
1786
+ timeStamp: statusCheckAlertTime,
1787
+ actionBy: 'Tango',
1788
+ IdentifiedBy: 'Tango',
1789
+ statusCheckAlertTime,
1790
+ } );
1559
1791
  }
1792
+
1793
+ const client = await findOneClient( { clientId: data.basicDetails.clientId } );
1794
+ const refreshdate = dayjs().add( client.ticketConfigs.refreshAlert, 'days' );
1795
+ await updateOneTangoTicket( { ticketId: data.ticketId }, {
1796
+ 'ticketActivity': data.ticketActivity,
1797
+ 'ticketDetails.issueIdentifiedDate': new Date(),
1798
+ 'ticketDetails.issueStatus': 'identified',
1799
+ 'status': 'inprogress',
1800
+ 'ticketDetails.ticketRefreshTime': new Date( dayjs( refreshdate ).format( 'YYYY-MM-DD' ) ),
1801
+ } );
1802
+
1803
+ return { success: true };
1560
1804
  } catch ( error ) {
1561
- logger.error( { error: error, function: 'updateAutomaticIssue' } );
1805
+ logger.error( { error, function: 'updateAutomaticIssue' } );
1806
+ return { success: true }; // don't block the caller on unexpected errors
1562
1807
  }
1563
1808
  }
1564
1809