tango-app-api-infra 3.9.5-vms.6 → 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-infra",
3
- "version": "3.9.5-vms.6",
3
+ "version": "3.9.5-vms.7",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -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.tangotyep == 'store'?
500
+ result =inputData.tangotype == 'store'?
501
501
 
502
502
 
503
503
  [
@@ -716,18 +716,18 @@ export async function ticketList( req, res ) {
716
716
  [
717
717
 
718
718
  {
719
- ticketId: 'TE_FDT_1763539990306',
719
+ ticketId: 'TE_FDT_1763860421803',
720
720
  storeId: '11-1716',
721
721
  storeName: 'LKST1916',
722
- ticketRaised: '2025-11-16',
723
- issueDate: '2025-11-16',
724
- footfall: 200,
725
- type: 'internal',
726
- storeRevisedAccuracy: '98%',
727
- reviewerRevisedAccuracy: '97%',
728
- approverRevisedAccuracy: '98%',
729
- tangoRevisedAccuracy: '98%',
730
- status: 'Closed',
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
  {
@@ -1023,13 +1023,13 @@ req.user.role === 'user'? 'NA':
1023
1023
  ticketsFeature?
1024
1024
  [
1025
1025
  {
1026
- ticketId: 'TE_FDT_17635399903490',
1026
+ ticketId: 'TE_FDT_1763860421803',
1027
1027
  storeId: '11-1716',
1028
1028
  storeName: 'LKST1916',
1029
- ticketRaised: '2025-11-16',
1030
- issueDate: '2025-11-15',
1029
+ ticketRaised: '2025-11-21',
1030
+ issueDate: '2025-11-20',
1031
1031
  dueDate: 'Due Today',
1032
- footfall: 213,
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-16',
1043
- issueDate: '2025-11-14',
1044
- dueDate: '2025-11-18',
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: 'Expired',
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 updateiTcket( req, res ) {
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: 'updateticket' } );
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 updateTicketListSchema = Joi.object().keys( {
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 updateTicketListValid = {
477
- body: updateTicketListSchema,
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, updateiTcket, updateStatus } from '../controllers/footfallDirectory.controllers.js';
4
- import { createTicketValid, downloadTicketsValid, getTaggedStoresValid, getTicketsValid, openTicketListValid, reviewerListValid, ticketListValid, ticketSummaryValid, updateStatusValid, updateTicketListValid } from '../dtos/footfallDirectory.dtos.js';
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( '/update-ticket-user', isAllowedSessionHandler, bulkValidate( updateTicketListValid ), updateiTcket );
20
+ footfallDirectoryRouter.post( '/assign-ticket', isAllowedSessionHandler, bulkValidate( assignTicketValid ), assignTicket );
21
+ footfallDirectoryRouter.post( '/update-temp-status', isAllowedSessionHandler, bulkValidate( updateTempStatusValid ), updateTempStatus );
21
22
 
22
23