tango-app-api-infra 3.9.5-vms.53 → 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
|
@@ -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 (
|
|
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 ) {
|
|
@@ -546,7 +546,7 @@ export async function ticketCreation( req, res, next ) {
|
|
|
546
546
|
record.mappingInfo.push( tangoReviewMapping );
|
|
547
547
|
}
|
|
548
548
|
}
|
|
549
|
-
|
|
549
|
+
|
|
550
550
|
let checkreview = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'reviewer' && data.isChecked === true );
|
|
551
551
|
let checkapprove = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'approver' && data.isChecked === true );
|
|
552
552
|
|
|
@@ -566,14 +566,13 @@ export async function ticketCreation( req, res, next ) {
|
|
|
566
566
|
let title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
|
|
567
567
|
let createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
568
568
|
let description = `Created on ${createdOn}`;
|
|
569
|
-
console.log( '🚀 ~ ticketCreation ~ userData.role:', userData.email );
|
|
570
569
|
let Data = {
|
|
571
570
|
storeId: getstoreName.storeId,
|
|
572
571
|
issueDate: inputData.dateString,
|
|
573
572
|
};
|
|
574
573
|
|
|
575
574
|
const ticketsFeature = userData?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
576
|
-
|
|
575
|
+
|
|
577
576
|
if ( ticketsFeature ) {
|
|
578
577
|
let notifyuser = await getAssinedStore( userData, req.body.storeId, Data );
|
|
579
578
|
if ( userData && userData.fcmToken && notifyuser ) {
|
|
@@ -1143,7 +1142,7 @@ export async function ticketReview( req, res, next ) {
|
|
|
1143
1142
|
record.mappingInfo.push( tangoReviewMapping );
|
|
1144
1143
|
}
|
|
1145
1144
|
}
|
|
1146
|
-
|
|
1145
|
+
|
|
1147
1146
|
let checkreview = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'reviewer' && data.isChecked === true );
|
|
1148
1147
|
let checkapprove = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'approver' && data.isChecked === true );
|
|
1149
1148
|
|
|
@@ -1163,13 +1162,13 @@ export async function ticketReview( req, res, next ) {
|
|
|
1163
1162
|
let title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
|
|
1164
1163
|
let createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
1165
1164
|
let description = `Created on ${createdOn}`;
|
|
1166
|
-
|
|
1165
|
+
|
|
1167
1166
|
let Data = {
|
|
1168
1167
|
storeId: getstoreName.storeId,
|
|
1169
1168
|
issueDate: inputData.dateString,
|
|
1170
1169
|
};
|
|
1171
1170
|
const ticketsFeature = userData?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'reviewer' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
1172
|
-
|
|
1171
|
+
|
|
1173
1172
|
if ( ticketsFeature ) {
|
|
1174
1173
|
let notifyuser = await getAssinedStore( userData, req.body.storeId, Data );
|
|
1175
1174
|
if ( userData && userData.fcmToken && notifyuser ) {
|
|
@@ -1636,23 +1635,40 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1636
1635
|
},
|
|
1637
1636
|
);
|
|
1638
1637
|
}
|
|
1639
|
-
for ( let userData of finduserList ) {
|
|
1640
|
-
let title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
|
|
1641
|
-
let createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
1642
|
-
let description = `Created on ${createdOn}`;
|
|
1643
|
-
console.log( '🚀 ~ ticketCreation ~ userData.role:', userData.email );
|
|
1644
|
-
let Data = {
|
|
1645
|
-
storeId: getstoreName.storeId,
|
|
1646
|
-
issueDate: inputData.dateString,
|
|
1647
|
-
};
|
|
1648
1638
|
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1639
|
+
|
|
1640
|
+
let checkreview = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'reviewer' && data.isChecked === true );
|
|
1641
|
+
let checkapprove = getConfig.footfallDirectoryConfigs.revision.filter( ( data ) => data.actionType === 'approver' && data.isChecked === true );
|
|
1642
|
+
|
|
1643
|
+
if ( checkreview.length > 0 || checkapprove.length > 0 ) {
|
|
1644
|
+
let userQuery = [
|
|
1645
|
+
{
|
|
1646
|
+
$match: {
|
|
1647
|
+
clientId: getstoreName.clientId,
|
|
1648
|
+
role: 'admin',
|
|
1649
|
+
},
|
|
1650
|
+
},
|
|
1651
|
+
];
|
|
1652
|
+
let finduserList = await aggregateUser( userQuery );
|
|
1653
|
+
|
|
1654
|
+
// return;
|
|
1655
|
+
for ( let userData of finduserList ) {
|
|
1656
|
+
let title = `${getstoreName?.storeName} Have raised a ticket for a Footfall Mismatch`;
|
|
1657
|
+
let createdOn = dayjs().format( 'DD MMM YYYY' );
|
|
1658
|
+
let description = `Created on ${createdOn}`;
|
|
1659
|
+
|
|
1660
|
+
let Data = {
|
|
1661
|
+
storeId: getstoreName.storeId,
|
|
1662
|
+
issueDate: inputData.dateString,
|
|
1663
|
+
};
|
|
1664
|
+
const ticketsFeature = userData?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name == 'approver' && ( m.isAdd == true || m.isEdit == true ) ) ) );
|
|
1665
|
+
|
|
1666
|
+
if ( ticketsFeature ) {
|
|
1667
|
+
let notifyuser = await getAssinedStore( userData, req.body.storeId, Data );
|
|
1668
|
+
if ( userData && userData.fcmToken && notifyuser ) {
|
|
1669
|
+
const fcmToken = userData.fcmToken;
|
|
1670
|
+
await sendPushNotification( title, description, fcmToken );
|
|
1671
|
+
}
|
|
1656
1672
|
}
|
|
1657
1673
|
}
|
|
1658
1674
|
}
|
|
@@ -1735,7 +1751,6 @@ export async function getAssinedStore( user, storeId ) {
|
|
|
1735
1751
|
// Convert Set back to Array if needed
|
|
1736
1752
|
let assignedStores = Array.from( storeIds );
|
|
1737
1753
|
if ( assignedStores.includes( storeId ) ) {
|
|
1738
|
-
console.log( '🚀 ~ getAssinedStore ~ req.body.assignedStores:', assignedStores );
|
|
1739
1754
|
return true;
|
|
1740
1755
|
} else {
|
|
1741
1756
|
return true;
|