tango-app-api-infra 3.9.5-vms.75 → 3.9.5-vms.76

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.75",
3
+ "version": "3.9.5-vms.76",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1065,7 +1065,7 @@ export async function ticketList( req, res ) {
1065
1065
  if ( req.user.userType === 'tango' ) {
1066
1066
  searchQuery.query.bool.must.push( {
1067
1067
  terms: {
1068
- 'status': Array.isArray( inputData?.status ) ?
1068
+ 'status.keyword': Array.isArray( inputData?.status ) ?
1069
1069
  inputData?.status :
1070
1070
  [ inputData?.status ],
1071
1071
  },
@@ -1162,7 +1162,9 @@ export async function ticketList( req, res ) {
1162
1162
  }
1163
1163
 
1164
1164
  if ( inputData.filterByStatus && inputData.filterByStatus!=='' ) {
1165
- if ( req?.user?.userType == 'tango' ) {
1165
+ inputData.filterByStatus = inputData?.filterByStatus?.split( ',' );
1166
+
1167
+ if ( req?.user?.userType === 'tango' ) {
1166
1168
  {
1167
1169
  switch ( inputData?.tangoType ) {
1168
1170
  case 'store':
@@ -1191,7 +1193,7 @@ export async function ticketList( req, res ) {
1191
1193
  case 'internal':
1192
1194
  searchQuery.query.bool.must.push( {
1193
1195
  'terms': {
1194
- 'status': Array.isArray( inputData?.filterByStatus ) ?
1196
+ 'status.keyword': Array.isArray( inputData?.filterByStatus ) ?
1195
1197
  inputData?.filterByStatus :
1196
1198
  [ inputData?.filterByStatus ],
1197
1199
  },
@@ -1315,6 +1317,285 @@ export async function ticketList( req, res ) {
1315
1317
  }
1316
1318
  }
1317
1319
 
1320
+ if ( inputData?.filterByReviewer && inputData?.filterByReviewer !== '' ) {
1321
+ let percQuery = null;
1322
+ const value = inputData.filterByReviewer;
1323
+
1324
+ // Helper function: remove trailing '%' and convert to number
1325
+ const percValue = ( val ) => {
1326
+ if ( typeof val === 'string' ) {
1327
+ return parseFloat( val.replace( '%', '' ).trim() );
1328
+ }
1329
+ return parseFloat( val );
1330
+ };
1331
+
1332
+ // Example filter values: "<90", "<=90", ">=90", "50 to 90"
1333
+ if ( /^<=?\d+$/.test( value ) ) {
1334
+ // "<90" or "<=90"
1335
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1336
+ const op = value.includes( '=' ) ? 'lte' : 'lt';
1337
+ percQuery = {
1338
+ script: {
1339
+ script: {
1340
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'lt' ? '<' : '<='} params.num`,
1341
+ params: { num },
1342
+ },
1343
+ },
1344
+ };
1345
+ } else if ( /^>=?\d+$/.test( value ) ) {
1346
+ // ">=90"
1347
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1348
+ const op = value.includes( '=' ) ? 'gte' : 'gt';
1349
+ percQuery = {
1350
+ script: {
1351
+ script: {
1352
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'gt' ? '>' : '>='} params.num`,
1353
+ params: { num },
1354
+ },
1355
+ },
1356
+ };
1357
+ } else if ( /^(\d+)\s*to\s*(\d+)$/.test( value ) ) {
1358
+ // "50 to 90"
1359
+ const match = value.match( /^(\d+)\s*to\s*(\d+)$/ );
1360
+ const from = percValue( match[1] );
1361
+ const to = percValue( match[2] );
1362
+ percQuery = {
1363
+ script: {
1364
+ script: {
1365
+ source:
1366
+ `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) >= params.from && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) <= params.to`,
1367
+ params: { from, to },
1368
+ },
1369
+ },
1370
+ };
1371
+ }
1372
+ // fallback: treat as exact match (e.g., "90")
1373
+ if ( !percQuery && /^\d+$/.test( value ) ) {
1374
+ percQuery = {
1375
+ script: {
1376
+ script: {
1377
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) == params.num`,
1378
+ params: { num: percValue( value ) },
1379
+ },
1380
+ },
1381
+ };
1382
+ }
1383
+
1384
+ if ( percQuery ) {
1385
+ searchQuery.query.bool.must.push( {
1386
+ nested: {
1387
+ path: 'mappingInfo',
1388
+ query: {
1389
+ bool: {
1390
+ must: [
1391
+ { term: { 'mappingInfo.type': 'review' } },
1392
+ percQuery,
1393
+ ],
1394
+ },
1395
+ },
1396
+ },
1397
+ } );
1398
+ }
1399
+ }
1400
+
1401
+ if ( inputData?.filterByApprover && inputData?.filterByApprover !== '' ) {
1402
+ let percQuery = null;
1403
+ const value = inputData.filterByApprover;
1404
+
1405
+ // Helper function: remove trailing '%' and convert to number
1406
+ const percValue = ( val ) => {
1407
+ if ( typeof val === 'string' ) {
1408
+ return parseFloat( val.replace( '%', '' ).trim() );
1409
+ }
1410
+ return parseFloat( val );
1411
+ };
1412
+
1413
+ // Example filter values: "<90", "<=90", ">=90", "50 to 90"
1414
+ if ( /^<=?\d+$/.test( value ) ) {
1415
+ // "<90" or "<=90"
1416
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1417
+ const op = value.includes( '=' ) ? 'lte' : 'lt';
1418
+ percQuery = {
1419
+ script: {
1420
+ script: {
1421
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'lt' ? '<' : '<='} params.num`,
1422
+ params: { num },
1423
+ },
1424
+ },
1425
+ };
1426
+ } else if ( /^>=?\d+$/.test( value ) ) {
1427
+ // ">=90"
1428
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1429
+ const op = value.includes( '=' ) ? 'gte' : 'gt';
1430
+ percQuery = {
1431
+ script: {
1432
+ script: {
1433
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'gt' ? '>' : '>='} params.num`,
1434
+ params: { num },
1435
+ },
1436
+ },
1437
+ };
1438
+ } else if ( /^(\d+)\s*to\s*(\d+)$/.test( value ) ) {
1439
+ // "50 to 90"
1440
+ const match = value.match( /^(\d+)\s*to\s*(\d+)$/ );
1441
+ const from = percValue( match[1] );
1442
+ const to = percValue( match[2] );
1443
+ percQuery = {
1444
+ script: {
1445
+ script: {
1446
+ source:
1447
+ `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) >= params.from && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) <= params.to`,
1448
+ params: { from, to },
1449
+ },
1450
+ },
1451
+ };
1452
+ }
1453
+ // fallback: treat as exact match (e.g., "90")
1454
+ if ( !percQuery && /^\d+$/.test( value ) ) {
1455
+ percQuery = {
1456
+ script: {
1457
+ script: {
1458
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) == params.num`,
1459
+ params: { num: percValue( value ) },
1460
+ },
1461
+ },
1462
+ };
1463
+ }
1464
+
1465
+ if ( percQuery ) {
1466
+ searchQuery.query.bool.must.push( {
1467
+ nested: {
1468
+ path: 'mappingInfo',
1469
+ query: {
1470
+ bool: {
1471
+ must: [
1472
+ { term: { 'mappingInfo.type': 'approve' } },
1473
+ percQuery,
1474
+ ],
1475
+ },
1476
+ },
1477
+ },
1478
+ } );
1479
+ }
1480
+ }
1481
+
1482
+ if ( inputData?.filterByTango && inputData?.filterByTango !== '' ) {
1483
+ let percQuery = null;
1484
+ const value = inputData.filterByTango;
1485
+
1486
+ // Helper function: remove trailing '%' and convert to number
1487
+ const percValue = ( val ) => {
1488
+ if ( typeof val === 'string' ) {
1489
+ return parseFloat( val.replace( '%', '' ).trim() );
1490
+ }
1491
+ return parseFloat( val );
1492
+ };
1493
+
1494
+ // Example filter values: "<90", "<=90", ">=90", "50 to 90"
1495
+ if ( /^<=?\d+$/.test( value ) ) {
1496
+ // "<90" or "<=90"
1497
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1498
+ const op = value.includes( '=' ) ? 'lte' : 'lt';
1499
+ percQuery = {
1500
+ script: {
1501
+ script: {
1502
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'lt' ? '<' : '<='} params.num`,
1503
+ params: { num },
1504
+ },
1505
+ },
1506
+ };
1507
+ } else if ( /^>=?\d+$/.test( value ) ) {
1508
+ // ">=90"
1509
+ const num = percValue( value.replace( /[^\d]/g, '' ) );
1510
+ const op = value.includes( '=' ) ? 'gte' : 'gt';
1511
+ percQuery = {
1512
+ script: {
1513
+ script: {
1514
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) ${op === 'gt' ? '>' : '>='} params.num`,
1515
+ params: { num },
1516
+ },
1517
+ },
1518
+ };
1519
+ } else if ( /^(\d+)\s*to\s*(\d+)$/.test( value ) ) {
1520
+ // "50 to 90"
1521
+ const match = value.match( /^(\d+)\s*to\s*(\d+)$/ );
1522
+ const from = percValue( match[1] );
1523
+ const to = percValue( match[2] );
1524
+ percQuery = {
1525
+ script: {
1526
+ script: {
1527
+ source:
1528
+ `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) >= params.from && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) <= params.to`,
1529
+ params: { from, to },
1530
+ },
1531
+ },
1532
+ };
1533
+ }
1534
+ // fallback: treat as exact match (e.g., "90")
1535
+ if ( !percQuery && /^\d+$/.test( value ) ) {
1536
+ percQuery = {
1537
+ script: {
1538
+ script: {
1539
+ source: `doc['mappingInfo.revicedPerc.keyword'].size()!=0 && Integer.parseInt(doc['mappingInfo.revicedPerc.keyword'].value.replace('%','')) == params.num`,
1540
+ params: { num: percValue( value ) },
1541
+ },
1542
+ },
1543
+ };
1544
+ }
1545
+
1546
+ if ( percQuery ) {
1547
+ searchQuery.query.bool.must.push( {
1548
+ nested: {
1549
+ path: 'mappingInfo',
1550
+ query: {
1551
+ bool: {
1552
+ must: [
1553
+ { term: { 'mappingInfo.type': 'tangoreview' } },
1554
+ percQuery,
1555
+ ],
1556
+ },
1557
+ },
1558
+ },
1559
+ } );
1560
+ }
1561
+ }
1562
+
1563
+ if ( inputData?.filterByReviewedBy && inputData?.filterByReviewedBy !== '' ) {
1564
+ inputData.filterByReviewedBy = inputData?.filterByReviewedBy?.split( ',' );
1565
+ searchQuery.query.bool.must.push( {
1566
+ nested: {
1567
+ path: 'mappingInfo',
1568
+ query: {
1569
+ bool: {
1570
+ must: [
1571
+ { term: { 'mappingInfo.type': 'review' } },
1572
+ { terms: { 'mappingInfo.createdByEmail': inputData?.filterByReviewedBy } },
1573
+
1574
+ ],
1575
+ },
1576
+ },
1577
+ },
1578
+ } );
1579
+ }
1580
+
1581
+ if ( inputData?.fileterByApprovedBy && inputData?.fileterByApprovedBy !== '' ) {
1582
+ inputData.fileterByApprovedBy = inputData?.fileterByApprovedBy?.split( ',' );
1583
+ searchQuery.query.bool.must.push( {
1584
+ nested: {
1585
+ path: 'mappingInfo',
1586
+ query: {
1587
+ bool: {
1588
+ must: [
1589
+ { term: { 'mappingInfo.type': 'approve' } },
1590
+ { terms: { 'mappingInfo.createdByEmail': inputData?.fileterByApprovedBy } },
1591
+
1592
+ ],
1593
+ },
1594
+ },
1595
+ },
1596
+ } );
1597
+ }
1598
+
1318
1599
  if ( req?.user?.userType === 'tango' && inputData.tangoType !== 'internal' ) {
1319
1600
  searchQuery.query.bool.must.push(
1320
1601
  {
@@ -1428,7 +1709,7 @@ export async function ticketList( req, res ) {
1428
1709
  // You can add more filters as needed
1429
1710
  const searchResult = await getOpenSearchData( openSearch.footfallDirectory, searchQuery );
1430
1711
  const count = searchResult?.body?.hits?.total?.value || 0;
1431
-
1712
+ logger.info( { searchResult } );
1432
1713
  if ( count === 0 ) {
1433
1714
  return res.sendError( 'no data found', 204 );
1434
1715
  }
@@ -158,12 +158,12 @@ export const ticketListSchema = Joi.object().keys( {
158
158
  sortOrder: Joi.number().valid( -1, 1 ).optional(),
159
159
  tangoType: Joi.string().valid( 'store', 'internal', '' ).optional(),
160
160
  permissionType: Joi.string().valid( 'review', 'approve' ).optional(),
161
- filterByStatus: Joi.array().items( Joi.string().required() ).optional(),
162
- filterByReviewer: Joi.string().optional(),
163
- filterByApprover: Joi.string().optional(),
164
- filterByTango: Joi.string().optional(),
165
- filterByReviewedBy: Joi.array().items( Joi.string().required() ).optional(),
166
- fileterByApprovedBy: Joi.array().items( Joi.string().required() ).optional(),
161
+ filterByStatus: Joi.string().optional().allow( '' ),
162
+ filterByReviewer: Joi.string().optional().allow( '' ),
163
+ filterByApprover: Joi.string().optional().allow( '' ),
164
+ filterByTango: Joi.string().optional().allow( '' ),
165
+ filterByReviewedBy: Joi.string().optional().allow( '' ),
166
+ fileterByApprovedBy: Joi.string().optional().allow( '' ),
167
167
  fromDate: Joi.string()
168
168
  .pattern( /^\d{4}-\d{2}-\d{2}$/, 'YYYY-MM-DD format' )
169
169
  .required()