tango-app-api-infra 3.9.5-vms.54 → 3.9.5-vms.55

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.54",
3
+ "version": "3.9.5-vms.55",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -856,6 +856,7 @@ export async function ticketList( req, res ) {
856
856
  size: limit, // or use parseInt(req.query.limit) for dynamic
857
857
  from: offset, // or use parseInt(req.query.offset) for dynamic
858
858
  sort: [ { 'createdAt': { order: 'desc' } } ],
859
+
859
860
  query: {
860
861
  bool: {
861
862
  must: [
@@ -881,7 +882,24 @@ export async function ticketList( req, res ) {
881
882
  },
882
883
  };
883
884
 
885
+ if ( inputData.sortBy ) {
886
+ let sortOrder = inputData.sortOrder === 1? 'asc': 'desc';
887
+
888
+ // Remove default sort so we don't duplicate/conflict
889
+ // INSERT_YOUR_CODE
890
+ // If sortBy is present, check if the field needs ".keyword" (for string fields like storeName, storeId, ticketId)
891
+ // This avoids OpenSearch errors about sorting on text fields.
892
+ const stringKeywordFields = [ 'storeName', 'storeId', 'ticketId', 'status', 'type', 'clientId' ];
893
+ let sortField = inputData.sortBy == 'footfall'? 'footfallCount' :inputData.sortBy == 'issueDate'?'dateString':inputData.sortBy;
894
+ if ( stringKeywordFields.includes( sortField ) ) {
895
+ sortField = `${sortField}.keyword`;
896
+ }
884
897
 
898
+ // Remove default sort so we don't duplicate/conflict
899
+ searchQuery.sort = [
900
+ { [sortField]: { order: sortOrder } },
901
+ ];
902
+ }
885
903
  // Example: Filtering by storeId if present in the query
886
904
  if ( inputData.storeId ) {
887
905
  inputData.storeId = inputData?.storeId?.split( ',' );
@@ -963,7 +981,7 @@ export async function ticketList( req, res ) {
963
981
  }
964
982
  // You can add more filters as needed
965
983
  const searchResult = await getOpenSearchData( openSearch.footfallDirectory, searchQuery );
966
-
984
+ logger.info( { searchResult } );
967
985
  const count = searchResult?.body?.hits?.total?.value || 0;
968
986
 
969
987
  if ( count === 0 ) {
@@ -1318,10 +1336,153 @@ export async function getTickets( req, res ) {
1318
1336
 
1319
1337
  ) {
1320
1338
  item._source.mappingInfo.revisedDetail = processedRevopSources;
1339
+ const vmsCommentsLogIndex = openSearch.vmsCommentsLog || 'vms-comments-log-dev';
1340
+ let commentsResponse = [];
1341
+ const commentsFilter = [
1342
+ { term: { 'storeId.keyword': item?._source?.storeId } },
1343
+ { term: { dateString: item?._source?.dateString } },
1344
+
1345
+ ];
1346
+
1347
+ const commentsQuery = {
1348
+ size: 10000,
1349
+ sort: [
1350
+ { createdAt: { order: 'desc' } }, // Sort descending by createdAt
1351
+ ],
1352
+ query: {
1353
+ bool: {
1354
+ filter: commentsFilter,
1355
+ },
1356
+ },
1357
+ };
1358
+
1359
+ const commentsRes = await getOpenSearchData( vmsCommentsLogIndex, commentsQuery );
1321
1360
  // If mappingInfo is an array, update revisedDetail for each mappingInfo object
1322
1361
  if ( Array.isArray( item._source.mappingInfo ) ) {
1323
1362
  item._source.mappingInfo.forEach( ( mappingObj ) => {
1324
- if ( Object.prototype.hasOwnProperty.call( mappingObj, 'revisedDetail' ) && mappingObj.type !== 'tangoreview' ) {
1363
+ if ( mappingObj.status == 'In-Progress' ) {
1364
+ commentsResponse = commentsRes?.body?.hits?.hits?.map( ( hit ) => hit._source ) || [];
1365
+
1366
+ // Check if duplicate condition exists in commentsResponse
1367
+ const isDuplicate = Array.isArray( commentsResponse ) &&
1368
+ commentsResponse.some( ( c ) => c.category === 'duplicate' );
1369
+
1370
+ // Structure comments output
1371
+ let commentsDetails = [];
1372
+ if ( isDuplicate ) {
1373
+ // Duplicate case - check from commentsResponse
1374
+ // Collect for each type (tagging, review, approve)
1375
+ const types = [ 'tagging', 'review', 'approve' ];
1376
+ commentsDetails = types.map( ( typeValue ) => {
1377
+ // parent value from original comment structure
1378
+ let parent = null;
1379
+ // Get all comments of this type (no filter by category)
1380
+ let comms = commentsResponse
1381
+ .filter( ( c ) => c.type === typeValue )
1382
+ .map( ( c ) => {
1383
+ if ( typeValue === 'tagging' ) {
1384
+ parent = c.parent;
1385
+ return {
1386
+ createdByEmail: c.createdByEmail,
1387
+ createdByUserName: c.createdByUserName,
1388
+ createdByRole: c.createdByRole,
1389
+ message: c.message,
1390
+ };
1391
+ }
1392
+ if ( typeValue === 'review' || typeValue === 'approve' ) {
1393
+ return {
1394
+ parent: c.parent,
1395
+ category: c.category,
1396
+ taggedImages: Array.isArray( c.taggedImages ) ?
1397
+ c.taggedImages.map( ( img ) => ( {
1398
+ id: img?._source?.id,
1399
+ tempId: img?._source?.tempId,
1400
+ timeRange: img?._source?.timeRange,
1401
+ entryTime: img?._source?.entryTime,
1402
+ exitTime: img?._source?.exitTime,
1403
+ filePath: img?._source?.filePath,
1404
+ isChecked: img?._source?.isChecked,
1405
+ } ) ) :
1406
+ [],
1407
+ createdByEmail: c.createdByEmail,
1408
+ createdByUserName: c.createdByUserName,
1409
+ createdByRole: c.createdByRole,
1410
+ status: c.status,
1411
+ message: c.message,
1412
+ };
1413
+ }
1414
+ return {};
1415
+ } );
1416
+ return {
1417
+ ...( typeValue === 'tagging' ? { category: 'duplicate' } : {} ),
1418
+ type: typeValue,
1419
+ ...( typeValue === 'tagging' ? { parent } : {} ),
1420
+ comments: comms,
1421
+ };
1422
+ } );
1423
+ } else {
1424
+ // For non-duplicate categories
1425
+ // Collect by type/tag (tagging/review/approve) and build similar structure
1426
+ const types = [ 'tagging', 'review', 'approve' ];
1427
+ commentsDetails = types.map( ( typeValue ) => {
1428
+ // parent for these non-duplicate is always null
1429
+ let comms = commentsResponse
1430
+ .filter( ( c ) => c.type === typeValue )
1431
+ .map( ( c ) => {
1432
+ if ( typeValue === 'tagging' ) {
1433
+ return {
1434
+ id: c.id,
1435
+ tempId: c.tempId,
1436
+ timeRange: c.timeRange,
1437
+ entryTime: c.entryTime,
1438
+ exitTime: c.exitTime,
1439
+ filePath: c.filePath,
1440
+ isChecked: c.isChecked,
1441
+ createdAt: c.createdAt,
1442
+ message: c.message,
1443
+ createdByEmail: c.createdByEmail,
1444
+ createdByUserName: c.createdByUserName,
1445
+ createdByRole: c.createdByRole,
1446
+ };
1447
+ }
1448
+ if ( typeValue === 'review' || typeValue === 'approve' ) {
1449
+ return {
1450
+ category: c.category,
1451
+ taggedImages: Array.isArray( c.taggedImages ) ?
1452
+ c.taggedImages.map( ( img ) => ( {
1453
+ id: img?._source?.id,
1454
+ tempId: img?._source?.tempId,
1455
+ timeRange: img?._source?.timeRange,
1456
+ entryTime: img?._source?.entryTime,
1457
+ exitTime: img?._source?.exitTime,
1458
+ filePath: img?._source?.filePath,
1459
+ isChecked: img?._source?.isChecked,
1460
+ } ) ) :
1461
+ [],
1462
+ createdByEmail: c.createdByEmail,
1463
+ createdByUserName: c.createdByUserName,
1464
+ createdByRole: c.createdByRole,
1465
+ status: c.status,
1466
+ message: c.message,
1467
+ };
1468
+ }
1469
+ return {};
1470
+ } );
1471
+ return {
1472
+ ...( typeValue === 'tagging' ? { category: 'duplicate' } : {} ),
1473
+ parent: null,
1474
+ type: typeValue,
1475
+ comments: comms,
1476
+ };
1477
+ } );
1478
+ }
1479
+
1480
+ item._source.commentsDetails = commentsDetails;
1481
+ }
1482
+ if (
1483
+ Object.prototype.hasOwnProperty.call( mappingObj, 'revisedDetail' ) &&
1484
+ mappingObj.type !== 'tangoreview'
1485
+ ) {
1325
1486
  mappingObj.revisedDetail = processedRevopSources;
1326
1487
  }
1327
1488
  } );
@@ -2171,6 +2332,16 @@ export async function openTicketList( req, res ) {
2171
2332
  clientId: Array.isArray( clientId ) ? clientId : [ clientId ],
2172
2333
  },
2173
2334
  },
2335
+ {
2336
+ term: {
2337
+ 'mappingInfo.type': inputData.type,
2338
+ },
2339
+ },
2340
+ {
2341
+ term: {
2342
+ 'mappingInfo.status.keyword': 'Open',
2343
+ },
2344
+ },
2174
2345
  {
2175
2346
  range: {
2176
2347
  dateString: {
@@ -2195,6 +2366,7 @@ export async function openTicketList( req, res ) {
2195
2366
 
2196
2367
  // Assuming getOpenSearchData and openSearch.footfallDirectoryTagging are available
2197
2368
  const result = await getOpenSearchData( openSearch.footfallDirectory, openSearchQuery );
2369
+ logger.info( { result } );
2198
2370
  const getUserlist = result?.body?.hits?.hits?.map( ( hit ) => hit._source ) || [];
2199
2371
  return res.sendSuccess( getUserlist || [] );
2200
2372
  } catch ( error ) {
@@ -509,6 +509,7 @@ export const openTicketListSchema = Joi.object().keys( {
509
509
  clientId: Joi.array().items(
510
510
  Joi.string().required(),
511
511
  ).required(),
512
+ type: Joi.string().required().allow( 'review', 'approve' ),
512
513
 
513
514
 
514
515
  } );