tango-app-api-infra 3.9.25 → 3.9.27

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.25",
3
+ "version": "3.9.27",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -147,7 +147,7 @@ export async function tangoReviewTicket( req, res ) {
147
147
  const getFootfallCount = await getOpenSearchData( openSearch.footfall, getQuery );
148
148
  const hits = getFootfallCount?.body?.hits?.hits || [];
149
149
  if ( hits?.[0]?._source?.footfall_count <= 0 ) {
150
- return res.sendError( 'You can’t create a ticket because this store has 0 footfall data' );
150
+ return res.sendError( 'You can’t create a ticket because this store has 0 footfall data', 400 );
151
151
  }
152
152
  // get category details from the client level configuration
153
153
  const getConfig = await findOneClient( { clientId: getstoreName.clientId }, { footfallDirectoryConfigs: 1 } );
@@ -234,19 +234,11 @@ export async function tangoReviewTicket( req, res ) {
234
234
  return res.sendError( 'You don’t have any tagged images right now', 400 );
235
235
  }
236
236
 
237
-
238
- if ( inputData?.ticketType != 'internal' ) {
239
- const approveDueDate = ticketData?.[0]?._source?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate;
240
-
241
- if ( dayjs().isAfter( dayjs( approveDueDate ), 'day' ) ) {
242
- res.sendError( 'Ticket approval is not allowed beyond the due date.' );
243
- }
244
- }
245
237
  const tangoDueDate = ticketData?.[0]?._source?.mappingInfo?.find( ( f ) => f.type === 'tangoreview' )?.dueDate;
246
238
  // const tangoAllowDueDate = getConfig?.footfallDirectoryConfigs?.allowTangoReview || 0;
247
239
 
248
240
  if ( dayjs().isAfter( dayjs( tangoDueDate ), 'day' ) && inputData?.ticketType !== 'internal' ) {
249
- return res.sendError( `Tango review is not allowed beyond the due date.` );
241
+ return res.sendError( `Tango review is not allowed beyond the due date.`, 400 );
250
242
  }
251
243
 
252
244
  if ( inputData.ticketType === 'internal' ) {
@@ -7498,4 +7490,107 @@ export async function getBadTicket( req, res ) {
7498
7490
  }
7499
7491
  }
7500
7492
 
7493
+ // Returns footfall-directory-tagging records whose audit-input-images S3 folder
7494
+ // (v4rnd-vms-audit-input-images/${storeId}/${dateString}/) is empty or missing.
7495
+ // Query params: fromDate, toDate (YYYY-MM-DD). Defaults to Jan 1 - Apr 30 of the current year.
7496
+ // export async function getUnmatchedAuditFolders( req, res ) {
7497
+ // try {
7498
+ // const openSearch = JSON.parse( process.env.OPENSEARCH );
7499
+ // const bucketConfig = JSON.parse( process.env.BUCKET );
7500
+ // // Audit input images bucket; folder layout is ${storeId}/${dateString}/ with dateString as DD-MM-YYYY.
7501
+ // const auditInputBucket = bucketConfig.tangoReviewInput || 'v4rnd-vms-audit-input-images';
7502
+
7503
+ // // dateString is stored as YYYY-MM-DD. Default window: Jan 1 - Apr 30 of the current year.
7504
+ // const currentYear = new Date().getFullYear();
7505
+ // const fromDate = req.query.fromDate || `${currentYear}-02-02`;
7506
+ // const toDate = req.query.toDate || `${currentYear}-03-01`;
7507
+
7508
+ // // 1. Pull every record in the date range (scroll to get past the 10k window).
7509
+ // const scrollQuery = {
7510
+ // size: 1000,
7511
+ // _source: [ 'storeId', 'dateString' ],
7512
+ // query: {
7513
+ // range: { dateString: { gte: fromDate, lte: toDate } },
7514
+ // },
7515
+ // };
7516
+
7517
+ // let scrollResult = await searchOpenSearchData( openSearch.footfallDirectory, scrollQuery );
7518
+ // const totalCount = scrollResult?.body?.hits?.total?.value || 0;
7519
+ // if ( totalCount === 0 ) {
7520
+ // return res.sendError( 'No footfall-directory-tagging records found for the selected dates', 204 );
7521
+ // }
7522
+
7523
+ // let scrollId = scrollResult?.body?._scroll_id;
7524
+ // let hits = scrollResult?.body?.hits?.hits || [];
7525
+ // let allHits = [ ...hits ];
7526
+ // while ( hits.length > 0 ) {
7527
+ // const scrollResp = await scrollResponse( scrollId );
7528
+ // hits = scrollResp?.body?.hits?.hits || [];
7529
+ // scrollId = scrollResp?.body?._scroll_id;
7530
+ // allHits = [ ...allHits, ...hits ];
7531
+ // }
7532
+ // await clearScroll( scrollId );
7533
+
7534
+ // // 2. Keep only the main tagging docs (exclude *_internal_* records) and dedupe by storeId+dateString.
7535
+ // const uniqueRecords = new Map();
7536
+ // for ( const hit of allHits ) {
7537
+ // const docId = hit?._id || '';
7538
+ // if ( !docId.endsWith( '_footfall-directory-tagging' ) || docId.includes( '_internal_' ) ) {
7539
+ // continue;
7540
+ // }
7541
+ // const storeId = hit?._source?.storeId;
7542
+ // const dateString = hit?._source?.dateString;
7543
+ // if ( !storeId || !dateString ) {
7544
+ // continue;
7545
+ // }
7546
+ // uniqueRecords.set( `${storeId}_${dateString}`, { storeId, dateString } );
7547
+ // }
7548
+
7549
+ // const records = [ ...uniqueRecords.values() ];
7550
+ // logger.info( { records } );
7551
+ // // 3. For each record, check whether its audit-input-images folder exists.
7552
+ // // Images live in nested subfolders under ${storeId}/${dateString}/, so we use a recursive
7553
+ // // prefix check (checkFileExist has no delimiter) instead of listing direct children only.
7554
+ // // dateString (YYYY-MM-DD) -> folder (DD-MM-YYYY).
7555
+ // const unmatched = [];
7556
+ // const errored = [];
7557
+ // const batches = await chunkArray( records, 25 );
7558
+ // logger.info( { batches } );
7559
+ // for ( const batch of batches ) {
7560
+ // await Promise.all(
7561
+ // batch.map( async ( record ) => {
7562
+ // const folderDate = dayjs( record.dateString ).format( 'DD-MM-YYYY' );
7563
+ // const folderPath = `/${record.storeId}/${folderDate}/`;
7564
+ // const exists = await checkFileExist( {
7565
+ // Bucket: auditInputBucket,
7566
+ // Key: folderPath,
7567
+ // } );
7568
+ // logger.info( { exists, auditInputBucket, folderPath } );
7569
+ // // checkFileExist returns true/false on success, or the error object on failure.
7570
+ // if ( exists === false ) {
7571
+ // unmatched.push( { ...record, folderPath } );
7572
+ // } else if ( exists !== true ) {
7573
+ // errored.push( { ...record, folderPath } );
7574
+ // }
7575
+ // } ),
7576
+ // );
7577
+ // }
7578
+
7579
+ // return res.sendSuccess( {
7580
+ // fromDate,
7581
+ // toDate,
7582
+ // bucket: auditInputBucket,
7583
+ // totalRecords: records.length,
7584
+ // unmatchedCount: unmatched.length,
7585
+ // unmatched,
7586
+ // erroredCount: errored.length,
7587
+ // errored,
7588
+ // } );
7589
+ // } catch ( error ) {
7590
+ // const err = error.message || 'Internal Server Error';
7591
+ // logger.error( { error: error, function: 'getUnmatchedAuditFolders' } );
7592
+ // return res.sendError( err, 500 );
7593
+ // }
7594
+ // }
7595
+
7501
7596
 
@@ -32,4 +32,6 @@ footfallDirectoryRouter.put( '/update-accuarcy-issues', isAllowedSessionHandler,
32
32
 
33
33
  footfallDirectoryRouter.get( '/get-bad-ticket', isAllowedSessionHandler, bulkValidate( getBadTicketValid ), getBadTicket );
34
34
 
35
+ // footfallDirectoryRouter.get( '/unmatched-audit-folders', getUnmatchedAuditFolders );
36
+
35
37