tango-app-api-infra 3.9.5-vms.5 → 3.9.5-vms.7
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
|
@@ -497,7 +497,7 @@ export async function ticketList( req, res ) {
|
|
|
497
497
|
const ticketsFeature = userInfo?.rolespermission?.some( ( f ) => f.featureName === 'FootfallDirectory' && ( f.modules.find( ( m ) => m.name =='reviewer' && ( m.isAdd==true || m.isEdit==true ) ) ) );
|
|
498
498
|
|
|
499
499
|
if ( req.user.userType =='tango' ) {
|
|
500
|
-
result =inputData.
|
|
500
|
+
result =inputData.tangotype == 'store'?
|
|
501
501
|
|
|
502
502
|
|
|
503
503
|
[
|
|
@@ -519,7 +519,7 @@ export async function ticketList( req, res ) {
|
|
|
519
519
|
ticketId: 'TE_FDT_1763860421803',
|
|
520
520
|
storeId: '11-1716',
|
|
521
521
|
storeName: 'LKST1916',
|
|
522
|
-
ticketRaised: '2025-11-
|
|
522
|
+
ticketRaised: '2025-11-21',
|
|
523
523
|
issueDate: '2025-11-20',
|
|
524
524
|
dueDate: '2025-11-26',
|
|
525
525
|
footfall: 94,
|
|
@@ -716,18 +716,18 @@ export async function ticketList( req, res ) {
|
|
|
716
716
|
[
|
|
717
717
|
|
|
718
718
|
{
|
|
719
|
-
ticketId: '
|
|
719
|
+
ticketId: 'TE_FDT_1763860421803',
|
|
720
720
|
storeId: '11-1716',
|
|
721
721
|
storeName: 'LKST1916',
|
|
722
|
-
ticketRaised: '2025-11-
|
|
723
|
-
issueDate: '2025-11-
|
|
724
|
-
footfall:
|
|
725
|
-
type: '
|
|
726
|
-
storeRevisedAccuracy: '
|
|
727
|
-
reviewerRevisedAccuracy: '
|
|
728
|
-
approverRevisedAccuracy: '
|
|
729
|
-
tangoRevisedAccuracy: '
|
|
730
|
-
status: '
|
|
722
|
+
ticketRaised: '2025-11-21',
|
|
723
|
+
issueDate: '2025-11-20',
|
|
724
|
+
footfall: 94,
|
|
725
|
+
type: 'store',
|
|
726
|
+
storeRevisedAccuracy: '95%',
|
|
727
|
+
reviewerRevisedAccuracy: '--',
|
|
728
|
+
approverRevisedAccuracy: '--',
|
|
729
|
+
tangoRevisedAccuracy: '--',
|
|
730
|
+
status: 'Open',
|
|
731
731
|
tangoStatus: 'Open',
|
|
732
732
|
},
|
|
733
733
|
{
|
|
@@ -899,13 +899,13 @@ export async function ticketList( req, res ) {
|
|
|
899
899
|
approvedBy: 'mu_mu@yopmail.com',
|
|
900
900
|
},
|
|
901
901
|
{
|
|
902
|
-
ticketId: '
|
|
902
|
+
ticketId: 'TE_FDT_1763860421803',
|
|
903
903
|
storeId: '11-1716',
|
|
904
904
|
storeName: 'LKST1916',
|
|
905
|
-
ticketRaised: '2025-11-
|
|
906
|
-
issueDate: '2025-11-
|
|
907
|
-
dueDate: '2025-11-
|
|
908
|
-
footfall:
|
|
905
|
+
ticketRaised: '2025-11-21',
|
|
906
|
+
issueDate: '2025-11-20',
|
|
907
|
+
dueDate: '2025-11-26',
|
|
908
|
+
footfall: 94,
|
|
909
909
|
storeRevisedAccuracy: '90%',
|
|
910
910
|
reviewerRevisedAccuracy: '90%',
|
|
911
911
|
approverRevisedAccuracy: '90%',
|
|
@@ -914,18 +914,18 @@ export async function ticketList( req, res ) {
|
|
|
914
914
|
approvedBy: 'mu_mu@yopmail.com',
|
|
915
915
|
},
|
|
916
916
|
{
|
|
917
|
-
ticketId: '
|
|
917
|
+
ticketId: 'TE_FDT_1763711403163',
|
|
918
918
|
storeId: '11-1716',
|
|
919
919
|
storeName: 'LKST1916',
|
|
920
|
-
ticketRaised: '2025-11-
|
|
921
|
-
issueDate: '2025-11-
|
|
922
|
-
dueDate: '
|
|
923
|
-
footfall:
|
|
924
|
-
storeRevisedAccuracy: '
|
|
920
|
+
ticketRaised: '2025-11-20',
|
|
921
|
+
issueDate: '2025-11-19',
|
|
922
|
+
dueDate: 'Due Today',
|
|
923
|
+
footfall: 94,
|
|
924
|
+
storeRevisedAccuracy: '95%',
|
|
925
925
|
reviewerRevisedAccuracy: '--',
|
|
926
926
|
approverRevisedAccuracy: '--',
|
|
927
927
|
tangoRevisedAccuracy: '--',
|
|
928
|
-
status: 'In-
|
|
928
|
+
status: 'In-Progress',
|
|
929
929
|
approvedBy: 'mu_mu@yopmail.com',
|
|
930
930
|
},
|
|
931
931
|
{
|
|
@@ -1023,13 +1023,13 @@ req.user.role === 'user'? 'NA':
|
|
|
1023
1023
|
ticketsFeature?
|
|
1024
1024
|
[
|
|
1025
1025
|
{
|
|
1026
|
-
ticketId: '
|
|
1026
|
+
ticketId: 'TE_FDT_1763860421803',
|
|
1027
1027
|
storeId: '11-1716',
|
|
1028
1028
|
storeName: 'LKST1916',
|
|
1029
|
-
ticketRaised: '2025-11-
|
|
1030
|
-
issueDate: '2025-11-
|
|
1029
|
+
ticketRaised: '2025-11-21',
|
|
1030
|
+
issueDate: '2025-11-20',
|
|
1031
1031
|
dueDate: 'Due Today',
|
|
1032
|
-
footfall:
|
|
1032
|
+
footfall: 90,
|
|
1033
1033
|
storeRevisedAccuracy: '90%',
|
|
1034
1034
|
reviewerRevisedAccuracy: '0%',
|
|
1035
1035
|
status: 'Open',
|
|
@@ -1039,13 +1039,13 @@ ticketsFeature?
|
|
|
1039
1039
|
ticketId: 'TE_FDT_1763539990346',
|
|
1040
1040
|
storeId: '11-2000',
|
|
1041
1041
|
storeName: 'LKST2368',
|
|
1042
|
-
ticketRaised: '2025-11-
|
|
1043
|
-
issueDate: '2025-11-
|
|
1044
|
-
dueDate: '2025-11-
|
|
1042
|
+
ticketRaised: '2025-11-21',
|
|
1043
|
+
issueDate: '2025-11-20',
|
|
1044
|
+
dueDate: '2025-11-26',
|
|
1045
1045
|
footfall: 90,
|
|
1046
1046
|
storeRevisedAccuracy: '90%',
|
|
1047
1047
|
reviewerRevisedAccuracy: '--',
|
|
1048
|
-
status: '
|
|
1048
|
+
status: 'In-Progress',
|
|
1049
1049
|
ReviewedBy: 'mu_mu@yopmail.com',
|
|
1050
1050
|
},
|
|
1051
1051
|
{
|
|
@@ -2310,7 +2310,7 @@ export async function openTicketList( req, res ) {
|
|
|
2310
2310
|
}
|
|
2311
2311
|
}
|
|
2312
2312
|
|
|
2313
|
-
export async function
|
|
2313
|
+
export async function assignTicket( req, res ) {
|
|
2314
2314
|
try {
|
|
2315
2315
|
const inputData = req.body;
|
|
2316
2316
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
@@ -2384,7 +2384,154 @@ export async function updateiTcket( req, res ) {
|
|
|
2384
2384
|
return res.sendSuccess( { updated: response?.body?.updated ?? 0 } );
|
|
2385
2385
|
} catch ( error ) {
|
|
2386
2386
|
const err = error.message || 'Internal Server Error';
|
|
2387
|
-
logger.error( { error: error, function: '
|
|
2387
|
+
logger.error( { error: error, function: 'assignTicket' } );
|
|
2388
|
+
return res.sendError( err, 500 );
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
export async function updateTempStatus( req, res ) {
|
|
2393
|
+
try {
|
|
2394
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
2395
|
+
const { id, status } = req.body;
|
|
2396
|
+
|
|
2397
|
+
// Use bulk update API via bucketing (batch update) -- fetch docs, then bulk-update
|
|
2398
|
+
// 1. Search for all documents matching the ticket IDs
|
|
2399
|
+
const searchBody = {
|
|
2400
|
+
query: {
|
|
2401
|
+
bool: {
|
|
2402
|
+
must: [
|
|
2403
|
+
{
|
|
2404
|
+
terms: {
|
|
2405
|
+
'id.keyword': id,
|
|
2406
|
+
},
|
|
2407
|
+
},
|
|
2408
|
+
],
|
|
2409
|
+
},
|
|
2410
|
+
},
|
|
2411
|
+
_source: [ '_id' ], // Only bring _id for efficiency
|
|
2412
|
+
};
|
|
2413
|
+
|
|
2414
|
+
const searchResp = await getOpenSearchData(
|
|
2415
|
+
openSearch.revop,
|
|
2416
|
+
searchBody,
|
|
2417
|
+
);
|
|
2418
|
+
logger.info( { searchResp: searchResp } );
|
|
2419
|
+
// Extract bulk IDs to update
|
|
2420
|
+
const hits = searchResp?.body?.hits?.hits ?? [];
|
|
2421
|
+
logger.info( { hits: hits } );
|
|
2422
|
+
if ( !hits.length ) {
|
|
2423
|
+
return res.sendError( 'no data', 204 );
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// 2. Build bulk update commands
|
|
2427
|
+
// Each doc: { update: { _id: ..., _index: ... } }, { doc: { status: status } }
|
|
2428
|
+
|
|
2429
|
+
// 1. Get all IDs from hits
|
|
2430
|
+
const docIdToIndex = {};
|
|
2431
|
+
hits.forEach( ( doc ) => {
|
|
2432
|
+
docIdToIndex[doc._id] = doc._index;
|
|
2433
|
+
} );
|
|
2434
|
+
const docIds = hits.map( ( doc ) => doc._id );
|
|
2435
|
+
logger.info( { docIds } );
|
|
2436
|
+
// 2. Fetch all docs by ID to get 'actions' (in chunks if large)
|
|
2437
|
+
const getBody = [];
|
|
2438
|
+
for ( const doc of hits ) {
|
|
2439
|
+
getBody.push( { _index: doc._index, _id: doc._id } );
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
let mgetResp;
|
|
2443
|
+
try {
|
|
2444
|
+
mgetResp = await getOpenSearchData(
|
|
2445
|
+
openSearch.revop,
|
|
2446
|
+
{
|
|
2447
|
+
query: {
|
|
2448
|
+
ids: {
|
|
2449
|
+
values: docIds,
|
|
2450
|
+
},
|
|
2451
|
+
},
|
|
2452
|
+
_source: true,
|
|
2453
|
+
},
|
|
2454
|
+
);
|
|
2455
|
+
} catch ( err ) {
|
|
2456
|
+
logger.error( { error: err } );
|
|
2457
|
+
mgetResp = undefined;
|
|
2458
|
+
}
|
|
2459
|
+
logger.info( { mgetResp } );
|
|
2460
|
+
// (If you have a utility for multi-get, you may want to use that. Else, you might need to fetch each by ID.)
|
|
2461
|
+
// For fallback, fetch all source fields via another search
|
|
2462
|
+
let fullDocs = [];
|
|
2463
|
+
if ( mgetResp && mgetResp.body && mgetResp.body.docs && Array.isArray( mgetResp.body.docs ) ) {
|
|
2464
|
+
fullDocs = mgetResp.body.docs;
|
|
2465
|
+
} else if ( searchResp.body && searchResp.body.hits && searchResp.body.hits.hits ) {
|
|
2466
|
+
// fallback: use searchResp docs (request _source above)
|
|
2467
|
+
fullDocs = searchResp.body.hits.hits;
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
// 3. Prepare the new actions array for each doc, and set up bulk update payloads
|
|
2471
|
+
const reviewActions = [ 'approved', 'rejected' ];
|
|
2472
|
+
const docsToUpdate = [];
|
|
2473
|
+
logger.info( { fullDocs: fullDocs } );
|
|
2474
|
+
for ( const doc of fullDocs ) {
|
|
2475
|
+
const source = doc._source || doc.fields || {}; // support mget and search hits
|
|
2476
|
+
let actions = Array.isArray( source.actions ) ? [ ...source.actions ] : [];
|
|
2477
|
+
if ( reviewActions.includes( status ) ) {
|
|
2478
|
+
// for review: update or push 'review'
|
|
2479
|
+
let found = false;
|
|
2480
|
+
actions = actions.map( ( item ) => {
|
|
2481
|
+
if ( item.actionType === 'review' ) {
|
|
2482
|
+
found = true;
|
|
2483
|
+
return { ...item, action: status };
|
|
2484
|
+
}
|
|
2485
|
+
return item;
|
|
2486
|
+
} );
|
|
2487
|
+
if ( !found ) {
|
|
2488
|
+
actions.push( { actionType: 'review', action: status } );
|
|
2489
|
+
}
|
|
2490
|
+
} else {
|
|
2491
|
+
// tagging: update or push 'tagging'
|
|
2492
|
+
let found = false;
|
|
2493
|
+
actions = actions.map( ( item ) => {
|
|
2494
|
+
if ( item.actionType === 'tagging' ) {
|
|
2495
|
+
found = true;
|
|
2496
|
+
return { ...item, action: 'submitted' };
|
|
2497
|
+
}
|
|
2498
|
+
return item;
|
|
2499
|
+
} );
|
|
2500
|
+
if ( !found ) {
|
|
2501
|
+
actions.push( { actionType: 'tagging', action: 'submitted' } );
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
docsToUpdate.push( {
|
|
2505
|
+
_index: doc._index || docIdToIndex[doc._id],
|
|
2506
|
+
_id: doc._id,
|
|
2507
|
+
actions,
|
|
2508
|
+
} );
|
|
2509
|
+
}
|
|
2510
|
+
const bulkPayload = [];
|
|
2511
|
+
// 4. Build bulk update payload
|
|
2512
|
+
for ( const doc of docsToUpdate ) {
|
|
2513
|
+
bulkPayload.push( {
|
|
2514
|
+
update: { _index: doc._index, _id: doc._id },
|
|
2515
|
+
} );
|
|
2516
|
+
bulkPayload.push( {
|
|
2517
|
+
doc: { actions: doc.actions },
|
|
2518
|
+
} );
|
|
2519
|
+
}
|
|
2520
|
+
logger.info( { bulkPayload: bulkPayload } );
|
|
2521
|
+
|
|
2522
|
+
|
|
2523
|
+
// 3. Execute bulk update
|
|
2524
|
+
const bulkResp = await bulkUpdate( bulkPayload );
|
|
2525
|
+
|
|
2526
|
+
// Count successes
|
|
2527
|
+
const updatedCount = bulkResp?.body?.items?.filter( ( item ) => item?.update?.result === 'updated' || item?.update?.result === 'noop' ).length ?? 0;
|
|
2528
|
+
|
|
2529
|
+
logger.info( { updated: updatedCount, by: 'updateTempStatus', ids: id } );
|
|
2530
|
+
|
|
2531
|
+
return res.sendSuccess( { updated: updatedCount } );
|
|
2532
|
+
} catch ( error ) {
|
|
2533
|
+
const err = error.message;
|
|
2534
|
+
logger.info( { error: err, function: 'updateTempStatus' } );
|
|
2388
2535
|
return res.sendError( err, 500 );
|
|
2389
2536
|
}
|
|
2390
2537
|
}
|
|
@@ -463,7 +463,7 @@ export const openTicketListValid = {
|
|
|
463
463
|
};
|
|
464
464
|
|
|
465
465
|
|
|
466
|
-
export const
|
|
466
|
+
export const assignTicketSchema = Joi.object().keys( {
|
|
467
467
|
email: Joi.string().required(),
|
|
468
468
|
userName: Joi.string().optional(),
|
|
469
469
|
role: Joi.string().optional(),
|
|
@@ -473,6 +473,18 @@ export const updateTicketListSchema = Joi.object().keys( {
|
|
|
473
473
|
|
|
474
474
|
} );
|
|
475
475
|
|
|
476
|
-
export const
|
|
477
|
-
body:
|
|
476
|
+
export const assignTicketValid = {
|
|
477
|
+
body: assignTicketSchema,
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
export const updateTempStatusSchema = Joi.object().keys( {
|
|
481
|
+
id: Joi.array().items( Joi.string().required() ).required(),
|
|
482
|
+
status: Joi.string().required(),
|
|
483
|
+
type: Joi.string().required(),
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
} );
|
|
487
|
+
|
|
488
|
+
export const updateTempStatusValid = {
|
|
489
|
+
body: updateTempStatusSchema,
|
|
478
490
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { getClusters, getConfig, isGrantedUsers, isTicketExists, ticketCreation } from '../validations/footfallDirectory.validation.js';
|
|
3
|
-
import { createTicket, downloadTickets, getTaggedStores, getTickets, openTicketList, reviewerList, ticketList, ticketSummary,
|
|
4
|
-
import { createTicketValid, downloadTicketsValid, getTaggedStoresValid, getTicketsValid, openTicketListValid, reviewerListValid, ticketListValid, ticketSummaryValid, updateStatusValid,
|
|
3
|
+
import { assignTicket, createTicket, downloadTickets, getTaggedStores, getTickets, openTicketList, reviewerList, ticketList, ticketSummary, updateStatus, updateTempStatus } from '../controllers/footfallDirectory.controllers.js';
|
|
4
|
+
import { createTicketValid, downloadTicketsValid, getTaggedStoresValid, getTicketsValid, openTicketListValid, reviewerListValid, ticketListValid, ticketSummaryValid, updateStatusValid, assignTicketValid, updateTempStatusValid } from '../dtos/footfallDirectory.dtos.js';
|
|
5
5
|
import { bulkValidate, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
6
6
|
|
|
7
7
|
export const footfallDirectoryRouter = express.Router();
|
|
@@ -17,6 +17,7 @@ footfallDirectoryRouter.put( '/update-status', isAllowedSessionHandler, bulkVali
|
|
|
17
17
|
footfallDirectoryRouter.get( '/download-tickets', isAllowedSessionHandler, bulkValidate( downloadTicketsValid ), isTicketExists, downloadTickets );
|
|
18
18
|
footfallDirectoryRouter.get( '/reviewer-list', isAllowedSessionHandler, bulkValidate( reviewerListValid ), reviewerList );
|
|
19
19
|
footfallDirectoryRouter.post( '/open-ticket-list', isAllowedSessionHandler, bulkValidate( openTicketListValid ), openTicketList );
|
|
20
|
-
footfallDirectoryRouter.post( '/
|
|
20
|
+
footfallDirectoryRouter.post( '/assign-ticket', isAllowedSessionHandler, bulkValidate( assignTicketValid ), assignTicket );
|
|
21
|
+
footfallDirectoryRouter.post( '/update-temp-status', isAllowedSessionHandler, bulkValidate( updateTempStatusValid ), updateTempStatus );
|
|
21
22
|
|
|
22
23
|
|