tango-app-api-store-builder 1.0.47 → 1.0.49

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-store-builder",
3
- "version": "1.0.47",
3
+ "version": "1.0.49",
4
4
  "description": "storeBuilder",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "path": "^0.12.7",
34
34
  "selenium-webdriver": "^4.31.0",
35
35
  "sharp": "^0.34.1",
36
- "tango-api-schema": "^2.5.34",
36
+ "tango-api-schema": "^2.5.35",
37
37
  "tango-app-api-middleware": "3.1.48",
38
38
  "url": "^0.11.4",
39
39
  "winston": "^3.17.0",
@@ -2475,6 +2475,7 @@ export async function createPlanoFromCAD( req, res ) {
2475
2475
  floorName: `Floor ${floorNumber}`,
2476
2476
  isEdited: false,
2477
2477
  cadLayout: true,
2478
+ isPlanoApproved: false,
2478
2479
  };
2479
2480
 
2480
2481
  let floorData = await floorService.findOne( { planoId: planoData._id, floorNumber }, { _id: 1, clientId: 1, storeName: 1, storeId: 1, planoId: 1 } );
@@ -2556,14 +2557,14 @@ export async function createPlanoFromCAD( req, res ) {
2556
2557
  } );
2557
2558
  }
2558
2559
 
2559
- return res.sendSuccess( meta );
2560
- } catch ( error ) {
2561
- logger.error( {
2560
+ return res.sendSuccess(meta);
2561
+ } catch (error) {
2562
+ logger.error({
2562
2563
  functionName: 'createPlanoFromCAD',
2563
2564
  error,
2564
- } );
2565
+ });
2565
2566
 
2566
- return res.sendError( { errMsg: 'Failed to create planogram.' }, 500 );
2567
+ return res.sendError({ errMsg: 'Failed to create planogram.', errInfo: error }, 500);
2567
2568
  }
2568
2569
  }
2569
2570
 
@@ -2779,3 +2780,22 @@ async function processFixtureTemplates( data ) {
2779
2780
 
2780
2781
  return updateStoreFixtures;
2781
2782
  }
2783
+
2784
+
2785
+ export async function approvePlanoLayout(req, res) {
2786
+ try {
2787
+
2788
+ const { floorId } = req.body;
2789
+
2790
+ await floorService.updateOne(
2791
+ { _id: new mongoose.Types.ObjectId(floorId) },
2792
+ {
2793
+ isPlanoApproved: true,
2794
+ },
2795
+ );
2796
+ res.sendSuccess(true);
2797
+ } catch (error) {
2798
+ logger.error({ functionName: 'approvePlanoLayout', error: e });
2799
+ res.sendError('Failed to approve planogram', 500);
2800
+ }
2801
+ }
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable quotes */
2
2
  // import { writeFileSync } from 'fs';
3
3
  import xlsx from 'xlsx';
4
- import { logger, fileUpload, download, insertOpenSearchData, getOpenSearchData } from 'tango-app-api-middleware';
4
+ import { logger, fileUpload, download } from 'tango-app-api-middleware';
5
5
  import * as storeBuilderService from '../service/storeBuilder.service.js';
6
6
  import * as storeService from '../service/store.service.js';
7
7
  import * as planoService from '../service/planogram.service.js';
@@ -20,6 +20,9 @@ import * as fixtureConfigService from '../service/fixtureConfig.service.js';
20
20
  import * as fixtureLibraryService from '../service/planoLibrary.service.js';
21
21
  import * as userService from '../service/user.service.js';
22
22
  import * as staticService from '../service/planoStaticData.service.js';
23
+ import * as planoRevisionService from '../service/planoRevision.service.js';
24
+
25
+
23
26
  import mongoose from 'mongoose';
24
27
  import JSZip from 'jszip';
25
28
  import { signedUrl } from 'tango-app-api-middleware';
@@ -27,6 +30,8 @@ import fs from 'fs';
27
30
  import os from 'os';
28
31
  import { fileURLToPath } from 'url';
29
32
  import path from 'path';
33
+ import FormData from 'form-data';
34
+
30
35
  const ObjectId=mongoose.Types.ObjectId;
31
36
 
32
37
  const __filename = fileURLToPath( import.meta.url );
@@ -15779,14 +15784,11 @@ export async function insertAntennaMappingData( req, res ) {
15779
15784
  shelfNumber: shelfNumber,
15780
15785
  } );
15781
15786
 
15782
- console.log( shelf );
15783
-
15784
15787
  if ( shelf ) {
15785
- let data = await fixtureShelfService.updateOne(
15788
+ await fixtureShelfService.updateOne(
15786
15789
  { _id: shelf._id },
15787
15790
  { antennaNo: antennaNo },
15788
15791
  );
15789
- console.log( data );
15790
15792
  console.log( `Updated fixture ${fixtureNumber}, shelf ${shelfNumber} with antennaNo:`, antennaNo );
15791
15793
  } else {
15792
15794
  const errorMsg = `Shelf not found for fixture ${fixtureNumber}, shelfNumber: ${shelfNumber}`;
@@ -15869,68 +15871,169 @@ export async function get4487FixtureDetails( req, res ) {
15869
15871
  }
15870
15872
  }
15871
15873
 
15872
- export async function getstoreMBQFixtureExcel( req, res ) {
15874
+ export async function getstoreMBQFixtureExcel(req, res) {
15873
15875
  try {
15874
- if ( !req.body?.storeName ) {
15875
- return res.sendError( 'storeName is required', 400 );
15876
- }
15877
- let getStoreDetails = await storeService.find( { storeName: { $in: req.body.storeName }, status: 'active', clientId: '11' }, { storeProfile: 1, storeName: 1 } );
15878
- if ( !getStoreDetails.length ) {
15879
- return res.sendError( 'No data found', 204 );
15880
- }
15876
+ const fromDate = new Date(dayjs().subtract(1, 'day').format('YYYY-MM-DD'));
15877
+ let toDate = new Date(dayjs().subtract(1, 'day').format('YYYY-MM-DD'));
15878
+ const userTimezoneOffset = toDate.getTimezoneOffset() * 60000;
15879
+ toDate = new Date(toDate.getTime() - userTimezoneOffset);
15880
+ toDate.setUTCHours(23, 59, 59, 59);
15881
+
15882
+ let query = [
15883
+ {
15884
+ $match: {
15885
+ createdAt: { $gte: fromDate, $lte: toDate },
15886
+ },
15887
+ },
15888
+ {
15889
+ $sort: {
15890
+ createdAt: -1,
15891
+ },
15892
+ },
15893
+ {
15894
+ $group: {
15895
+ _id: { store: '$storeName', floorId: '$floorId' },
15896
+ data: { $first: '$$ROOT' },
15897
+ },
15898
+ },
15899
+ ];
15900
+
15901
+ let planorevisions = await planoRevisionService.aggregate(query);
15881
15902
  let data = [];
15882
- let sortOrder = [ 5, 1, 2, 3, 4 ];
15883
- await Promise.all( getStoreDetails.map( async ( store ) => {
15884
- let storeFixturesList = await storeFixtureService.findAndSort( { storeName: store.storeName }, {}, { fixtureNumber: 1, associatedElementNumber: 1, associatedElementFixtureNumber: 1 } );
15885
- storeFixturesList.sort( ( a, b ) => {
15886
- const floorDiff = b.floorId.toString().localeCompare( a.floorId.toString() );
15887
- if ( floorDiff !== 0 ) return floorDiff;
15903
+ let sortOrder = [5, 1, 2, 3, 4];
15888
15904
 
15889
- if ( a.fixtureType !== b.fixtureType ) {
15905
+ await Promise.all(planorevisions.map(async (revision) => {
15906
+ let wallFixtures = revision?.data?.floorData?.layoutPolygon.flatMap((ele) => ele.fixtures);
15907
+ let centerFixtures = revision?.data?.floorData?.centerFixture;
15908
+ let storeFixturesList = [...wallFixtures, ...centerFixtures];
15909
+
15910
+ storeFixturesList.sort((a, b) => {
15911
+ const floorDiff = b.floorId.toString().localeCompare(a.floorId.toString());
15912
+ if (floorDiff !== 0) return floorDiff;
15913
+
15914
+ if (a.fixtureType !== b.fixtureType) {
15890
15915
  return a.fixtureType === "wall" ? -1 : 1;
15891
15916
  }
15892
15917
 
15893
- if ( a.fixtureType === "wall" ) {
15918
+ if (a.fixtureType === "wall") {
15894
15919
  const orderDiff =
15895
- sortOrder.indexOf( a.associatedElementNumber ) -
15896
- sortOrder.indexOf( b.associatedElementNumber );
15920
+ sortOrder.indexOf(a.associatedElementNumber) -
15921
+ sortOrder.indexOf(b.associatedElementNumber);
15897
15922
 
15898
- if ( orderDiff !== 0 ) return orderDiff;
15923
+ if (orderDiff !== 0) return orderDiff;
15899
15924
 
15900
15925
  return (
15901
- ( a.associatedElementFixtureNumber || 0 ) -
15902
- ( b.associatedElementFixtureNumber || 0 )
15926
+ (a.associatedElementFixtureNumber || 0) -
15927
+ (b.associatedElementFixtureNumber || 0)
15903
15928
  );
15904
15929
  }
15905
15930
 
15906
15931
  return 0;
15907
- } );
15932
+ });
15908
15933
 
15909
15934
 
15910
15935
  let storeFixtureDetails = [];
15911
- for ( let ele of storeFixturesList ) {
15912
- let shelfDetails = await fixtureShelfService.findAndSort( { fixtureId: ele._id }, {}, { shelfNumber: 1 } );
15936
+ for (let ele of storeFixturesList) {
15937
+ let shelfDetails = await fixtureShelfService.findAndSort({ fixtureId: ele._id }, {}, { shelfNumber: 1 });
15913
15938
 
15914
- storeFixtureDetails.push( {
15939
+ storeFixtureDetails.push({
15915
15940
  "Store Code": ele.storeName,
15916
15941
  "Wall": ele?.associatedElementNumber ?? 'floor',
15917
15942
  "Unique Fixture Number": 'FX - ' + ele.fixtureNumber,
15918
15943
  "Brand-Category": ele.header?.label,
15919
15944
  "Fixture Type": ele.fixtureCategory,
15920
- "Fixture Size": ele.fixtureWidth.value +' '+ ele.fixtureWidth.unit,
15945
+ "Fixture Size": ele.fixtureWidth.value + ' ' + ele.fixtureWidth.unit,
15921
15946
  "Shelves/ Rods/ Space per Fixture": shelfDetails.length,
15922
15947
  'Display per Shelf/ Rod/ Space': shelfDetails?.[0]?.productPerShelf,
15923
15948
  'Fixture Capacity': ele?.fixtureCapacity,
15924
15949
  },
15925
15950
  );
15926
15951
  }
15927
- data.push( ...storeFixtureDetails );
15928
- } ) );
15929
- // for ( let store of getStoreDetails ) {
15930
- // }
15931
- await download( data, res );
15932
- } catch ( e ) {
15933
- console.log( e );
15934
- return res.sendError( e, 500 );
15952
+ data.push(...storeFixtureDetails);
15953
+ }));
15954
+
15955
+
15956
+ // ------------------------------------------------
15957
+ const originalSend = res.send.bind(res);
15958
+
15959
+ res.send = async (buffer) => {
15960
+ const uploadDate = dayjs().format('DD-MM-YYYY');
15961
+ const uploadTime = dayjs().format('HH-mm-ss');
15962
+ const fileName = `mbq_${uploadTime}.xlsx`;
15963
+
15964
+ const tempFilePath = path.join(os.tmpdir(), fileName);
15965
+
15966
+ try {
15967
+ // 1️⃣ Write buffer to temp file
15968
+ fs.writeFileSync(tempFilePath, buffer);
15969
+
15970
+ // 2️⃣ Create multipart form with REAL FILE
15971
+ const formData = new FormData();
15972
+ formData.append(
15973
+ 'file',
15974
+ fs.createReadStream(tempFilePath),
15975
+ fileName
15976
+ );
15977
+
15978
+ // 3️⃣ Upload using node-fetch
15979
+ const response = await fetch(
15980
+ `${JSON.parse(process.env.LAMBDAURL).mbqFileUpload}` +
15981
+ `?date=${uploadDate}&filename=${encodeURIComponent(fileName)}`,
15982
+ {
15983
+ method: 'POST',
15984
+ body: formData,
15985
+ headers: formData.getHeaders()
15986
+ }
15987
+ );
15988
+
15989
+ const resultText = await response.text();
15990
+
15991
+ if (response.ok) {
15992
+ logger.info({
15993
+ functionName: 'MBQUploadSuccess',
15994
+ fileName,
15995
+ uploadDate,
15996
+ result: resultText
15997
+ });
15998
+ } else {
15999
+ logger.error({
16000
+ functionName: 'MBQUploadFailed',
16001
+ status: response.status,
16002
+ fileName,
16003
+ uploadDate,
16004
+ result: resultText
16005
+ });
16006
+ }
16007
+
16008
+ } catch (err) {
16009
+ logger.error({
16010
+ functionName: 'MBQUploadError',
16011
+ fileName,
16012
+ uploadDate,
16013
+ error: err
16014
+ });
16015
+ } finally {
16016
+ // 4️⃣ Cleanup temp file
16017
+ if (fs.existsSync(tempFilePath)) {
16018
+ fs.unlinkSync(tempFilePath);
16019
+ }
16020
+ }
16021
+
16022
+ // 5️⃣ Continue normal download
16023
+ return originalSend(buffer);
16024
+ };
16025
+
16026
+
16027
+ // ------------------------------------------------
16028
+
16029
+ if (!data.length) {
16030
+ return res.sendError('No data available for export', 204);
16031
+ }
16032
+
16033
+ await download(data, res);
16034
+ } catch (e) {
16035
+ logger.error({ functionName: "getstoreMBQFixtureExcel", error: e });
16036
+ return res.sendError(e, 500);
15935
16037
  }
15936
16038
  }
16039
+
@@ -27,8 +27,8 @@ import * as fixtureConfigDuplicateService from '../service/fixtureConfigDuplicat
27
27
  import * as planoVmDuplicateService from '../service/planoVmDuplicate.service.js';
28
28
  import advancedFormat from 'dayjs/plugin/advancedFormat.js';
29
29
  import * as planoRevisionService from '../service/planoRevision.service.js';
30
- import xlsx from 'xlsx';
31
- import fs from 'fs';
30
+ // import xlsx from 'xlsx';
31
+ // import fs from 'fs';
32
32
 
33
33
  dayjs.extend( advancedFormat );
34
34
  dayjs.extend( utc );
@@ -2794,7 +2794,7 @@ export async function storeFixturesv2( req, res ) {
2794
2794
  planograms.map( async ( planogram ) => {
2795
2795
  const floors = await storeBuilderService.find(
2796
2796
  { planoId: planogram._id, ...( req.body?.floorId && { _id: req.body.floorId } ) },
2797
- { floorName: 1, layoutPolygon: 1, planoId: 1, isEdited: 1, planoProgress: 1, updatedAt: 1, verificationStatus: 1, merchRolloutStatus: 1, vmRolloutStatus: 1, cadLayout: 1 },
2797
+ { floorName: 1, layoutPolygon: 1, planoId: 1, isEdited: 1, planoProgress: 1, updatedAt: 1, verificationStatus: 1, merchRolloutStatus: 1, vmRolloutStatus: 1, cadLayout: 1,isPlanoApproved:1 },
2798
2798
  );
2799
2799
 
2800
2800
  const floorsWithFixtures = await Promise.all(
@@ -5732,6 +5732,7 @@ export async function planoList( req, res ) {
5732
5732
  planoTask: { $ifNull: [ '$planoTask', [] ] },
5733
5733
  layoutCount: 1,
5734
5734
  layoutStatus: 1,
5735
+ planoStrategy: 1,
5735
5736
  taskDetails: {
5736
5737
  $let: {
5737
5738
  vars: {
@@ -6132,6 +6133,7 @@ export async function planoList( req, res ) {
6132
6133
  'Store Capacity': ele?.fixtureCapacity ?? 0,
6133
6134
  'Last update': ele?.lastUpdate ? dayjs( ele.lastUpdate ).format( 'MMM DD, YYYY' ) : '--',
6134
6135
  'Planogram Status': ( ele?.taskDetails.fixtureStatus == 'complete' && ele?.taskDetails.layoutStatus == 'complete' && ele.layoutStatus.includes( false ) ) ? 'Yet to Publish' : !ele.layoutStatus.includes( false ) ? 'Published' : fixtureStatus,
6136
+ 'Store Type': ele?.planoStrategy,
6135
6137
  } );
6136
6138
  } );
6137
6139
  return await download( exportData, res );
@@ -13,8 +13,6 @@ import mongoose from 'mongoose';
13
13
  const ObjectId = mongoose.Types.ObjectId;
14
14
  import * as floorService from '../service/storeBuilder.service.js';
15
15
  import * as planoStaticService from '../service/planoStaticData.service.js';
16
- import * as assignService from '../service/assignService.service.js';
17
- import * as taskAssignService from '../service/assignService.service.js';
18
16
  import * as storeBuilderService from '../service/storeBuilder.service.js';
19
17
  import * as storeFixtureService from '../service/storeFixture.service.js';
20
18
  import * as fixtureShelfService from '../service/fixtureShelf.service.js';
@@ -179,7 +177,7 @@ export async function createTask( req, res ) {
179
177
  endDate = dayjs().add( days, 'day' ).format( 'YYYY-MM-DD' );
180
178
  endDate = `${endDate} ${scheduleEndTime}`;
181
179
  if ( !req.body?.stores?.length ) {
182
- let assignQuery = [
180
+ let storeQuery = [
183
181
  {
184
182
  $addFields: {
185
183
  store: { $toLower: '$storeName' },
@@ -187,53 +185,26 @@ export async function createTask( req, res ) {
187
185
  },
188
186
  {
189
187
  $match: {
190
- client_id: req.body.clientId,
188
+ clientId: req.body.clientId,
191
189
  store: req.body.store.toLowerCase(),
192
190
  },
193
191
  },
194
192
  {
195
- $sort: {
196
- _id: -1,
193
+ $project: {
194
+ spocDetails: 1,
197
195
  },
198
196
  },
199
- {
200
- $limit: 1,
201
- },
202
197
  ];
203
- let getUserDetails = await assignService.aggregate( assignQuery );
204
- if ( !getUserDetails.length ) {
205
- getUserDetails = await taskAssignService.taskAggregate( assignQuery );
206
- if ( !getUserDetails.length ) {
207
- let storeQuery = [
208
- {
209
- $addFields: {
210
- store: { $toLower: '$storeName' },
211
- },
212
- },
213
- {
214
- $match: {
215
- clientId: req.body.clientId,
216
- store: req.body.store.toLowerCase(),
217
- },
218
- },
219
- {
220
- $project: {
221
- spocDetails: 1,
222
- },
223
- },
224
- ];
225
- let getEmail = await storeService.aggregate( storeQuery );
226
- if ( getEmail.length ) {
227
- getUserDetails = [ { storeName: req.body.store, userEmail: getEmail?.[0]?.spocDetails?.[0]?.email } ];
228
- }
229
- }
198
+ let getEmail = await storeService.aggregate( storeQuery );
199
+ if ( getEmail.length ) {
200
+ let getUserDetails = [ { storeName: req.body.store, userEmail: getEmail?.[0]?.spocDetails?.[0]?.email } ];
201
+ req.body.stores = [
202
+ {
203
+ store: getUserDetails[0].storeName,
204
+ email: req.body?.email ? req.body.email : getUserDetails[0].userEmail,
205
+ },
206
+ ];
230
207
  }
231
- req.body.stores = [
232
- {
233
- store: getUserDetails[0].storeName,
234
- email: req.body?.email ? req.body.email : getUserDetails[0].userEmail,
235
- },
236
- ];
237
208
  }
238
209
  storeList = req.body.stores.map( ( ele ) => ele.store.toLowerCase() );
239
210
  let userEmailList = [ ...new Set( req.body.stores.map( ( ele ) => ele.email ) ) ];
@@ -28,4 +28,5 @@ managePlanoRouter
28
28
  .post('/getRolloutFeedbackv2', isAllowedSessionHandler, managePlanoController.getRolloutFeedbackv2)
29
29
  .post('/updateRolloutStatus', isAllowedSessionHandler, managePlanoController.updateRolloutStatus)
30
30
  .post('/getPlanoStoreVideoParams', isAllowedSessionHandler, managePlanoController.getPlanoStoreVideoPageParams)
31
+ .post('/approvePlanoLayout', isAllowedSessionHandler, managePlanoController.approvePlanoLayout)
31
32
  .post('/createPlanoFromCAD', isAllowedSessionHandler, managePlanoController.createPlanoFromCAD);
package/items.xlsx DELETED
Binary file