tango-app-api-store-builder 1.0.30 → 1.0.32

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.30",
3
+ "version": "1.0.32",
4
4
  "description": "storeBuilder",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  "path": "^0.12.7",
33
33
  "selenium-webdriver": "^4.31.0",
34
34
  "sharp": "^0.34.1",
35
- "tango-api-schema": "^2.5.17",
35
+ "tango-api-schema": "^2.5.23",
36
36
  "tango-app-api-middleware": "3.1.48",
37
37
  "url": "^0.11.4",
38
38
  "winston": "^3.17.0",
@@ -1,6 +1,6 @@
1
1
  import * as floorService from '../service/storeBuilder.service.js';
2
- import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData, getOpenSearchById } from 'tango-app-api-middleware';
3
- // import * as storeService from '../service/store.service.js';
2
+ import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData, getOpenSearchById, fileUpload } from 'tango-app-api-middleware';
3
+ import * as storeService from '../service/store.service.js';
4
4
  import * as planoService from '../service/planogram.service.js';
5
5
  import * as storeFixtureService from '../service/storeFixture.service.js';
6
6
  import * as fixtureShelfService from '../service/fixtureShelf.service.js';
@@ -1372,7 +1372,7 @@ export async function updateStoreFixture( req, res ) {
1372
1372
  };
1373
1373
  vmDetails = await planoVmService.create( planovmData );
1374
1374
  }
1375
- vmConfig.push( { ...vm, vmId: vmDetails._id, vmName: vmDetails.vmName, vmImage: vmDetails.vmImageUrl } );
1375
+ vmConfig.push({ ...vm, vmId: vmDetails._id, vmName: vmDetails.vmName, vmImage: vmDetails.vmImageUrl });
1376
1376
  }
1377
1377
  data.vmConfig = vmConfig;
1378
1378
  let groupName = {
@@ -2363,3 +2363,261 @@ export async function getPlanoStoreVideoPageParams( req, res ) {
2363
2363
  res.sendError( 'Failed to fetch plano store video page params', 500 );
2364
2364
  }
2365
2365
  }
2366
+
2367
+ export async function createPlanoFromCAD(req, res) {
2368
+ try {
2369
+ const user = req.user;
2370
+ const file = req.files.file;
2371
+ const { storeId, floorNumber } = req.body;
2372
+
2373
+ if (!req?.files?.file) return res.sendError('File is required', 400);
2374
+
2375
+ if (!storeId || !floorNumber) return res.sendError('storeId and floorNumber are required', 400);
2376
+
2377
+ if (!file.name.endsWith('.dxf')) return res.sendError('Only DXF files are allowed', 400);
2378
+
2379
+
2380
+ // if (file.size > 20 * 1024 * 1024) {
2381
+ // return res.sendError('File size exceeds 20MB limit', 400);
2382
+ // }
2383
+
2384
+ // File Upload
2385
+ const fileUploadPayload = {
2386
+ Bucket: JSON.parse(process.env.BUCKET).storeBuilder,
2387
+ Key: `planoCad/`,
2388
+ fileName: Date.now() + '.' + file.name?.split('.')?.slice(-1)?.[0],
2389
+ ContentType: file.mimetype,
2390
+ body: file.data,
2391
+ };
2392
+
2393
+ const fileRes = await fileUpload(fileUploadPayload);
2394
+
2395
+ if (!fileRes?.Key) return res.sendError('Failed to upload file to storage', 502);
2396
+
2397
+ // CAD Extraction
2398
+ const dataExtractPayload = {
2399
+ s3Bucket: fileUploadPayload.Bucket,
2400
+ filePath: fileRes.Key,
2401
+ };
2402
+
2403
+ const cadRes = await fetch(
2404
+ JSON.parse(process.env.LAMBDAURL).extractCADDetails,
2405
+ {
2406
+ method: 'POST',
2407
+ headers: { 'Content-Type': 'application/json' },
2408
+ body: JSON.stringify(dataExtractPayload),
2409
+ }
2410
+ );
2411
+
2412
+ if (!cadRes.ok) {
2413
+ const errorText = await cadRes.text();
2414
+ logger.error({ cadLambdaError: errorText });
2415
+ return res.sendError('CAD extraction service failed', 502);
2416
+ }
2417
+
2418
+ const cadData = await cadRes.json();
2419
+
2420
+ if (
2421
+ cadData?.status !== 'success' ||
2422
+ !cadData?.data?.layoutPolygon
2423
+ ) {
2424
+ return res.sendError('Invalid CAD layout data', 502);
2425
+ }
2426
+
2427
+ const userMeta = {
2428
+ createdBy: user._id,
2429
+ createdByEmail: user.email,
2430
+ createdByName: user.userName,
2431
+ }
2432
+
2433
+ // PLANOGRAM
2434
+ let planoData = await planoService.findOne({ storeId }, { _id: 1, clientId: 1, storeName: 1, });
2435
+
2436
+ if (!planoData) {
2437
+ const storeData = await storeService.findOne({ storeId }, { clientId: 1, storeName: 1 });
2438
+ if (!storeData) return res.sendError('Unable to find the store to create planogram', 400);
2439
+
2440
+ const newPlano = {
2441
+ clientId: storeData.clientId,
2442
+ storeName: storeData.storeName,
2443
+ storeId,
2444
+ layoutName: `${storeData.storeName} - Layout`,
2445
+ attachments: [],
2446
+ status: 'completed',
2447
+ productResolutionLevel: 'L2',
2448
+ scanType: 'qr',
2449
+ planoStrategy: "nonIvm",
2450
+ ...userMeta
2451
+ };
2452
+
2453
+ planoData = await planoService.create(newPlano);
2454
+ if (!planoData) return res.sendError('Failed to create new planogram', 400);
2455
+ }
2456
+
2457
+ const floorPayload = {
2458
+ layoutPolygon: processWallData(cadData.data.layoutPolygon),
2459
+ planoProgress: 25,
2460
+ floorName: `Floor ${floorNumber}`,
2461
+ isEdited: false,
2462
+ cadLayout: true
2463
+ };
2464
+
2465
+ let floorData = await floorService.findOne({ planoId: planoData._id, floorNumber }, { _id: 1, clientId: 1, storeName: 1, storeId: 1, planoId: 1 });
2466
+ if (floorData) {
2467
+ await floorService.updateOne({ _id: floorData._id }, { ...floorPayload, updatedBy: user._id });
2468
+ } else {
2469
+ const newFloor = {
2470
+ clientId: planoData.clientId,
2471
+ planoId: planoData._id,
2472
+ layoutName: `${planoData.storeName} - Layout`,
2473
+ status: 'completed',
2474
+ storeName: planoData.storeName,
2475
+ floorNumber,
2476
+ storeId,
2477
+ ...floorPayload,
2478
+ ...userMeta,
2479
+ };
2480
+
2481
+ floorData = await floorService.create(newFloor);
2482
+ if (!floorData) return res.sendError('Failed to create new floor layout', 400);
2483
+ }
2484
+
2485
+ const meta = {
2486
+ clientId: floorData.clientId,
2487
+ storeName: floorData.storeName,
2488
+ storeId: floorData.storeId,
2489
+ planoId: floorData.planoId,
2490
+ floorId: floorData._id,
2491
+ }
2492
+
2493
+ logger.info({
2494
+ functionName: 'CAD DATA: ',
2495
+ body: cadData.data,
2496
+ });
2497
+
2498
+ // Create Fixtures
2499
+ const processedFixtures = createStoreFixtures(cadData.data, meta);
2500
+
2501
+ try {
2502
+ await storeFixtureService.deleteMany({ floorId: meta.floorId });
2503
+ await fixtureShelfService.deleteMany({ floorId: meta.floorId });
2504
+ for (let i = 0; i < processedFixtures.length; i++) {
2505
+ const fix = processedFixtures[i];
2506
+ await storeFixtureService.create(fix);
2507
+ }
2508
+ } catch (e) {
2509
+ logger.error({
2510
+ functionName: 'createPlanoFromCAD [Create Fixtures]',
2511
+ error: e,
2512
+ });
2513
+ }
2514
+
2515
+ return res.sendSuccess(meta);
2516
+
2517
+ } catch (error) {
2518
+ logger.error({
2519
+ functionName: 'createPlanoFromCAD',
2520
+ error,
2521
+ });
2522
+
2523
+ return res.sendError('Failed to create planogram.', 500);
2524
+ }
2525
+ }
2526
+
2527
+ function processWallData(cadRes) {
2528
+ return cadRes.map((w) => {
2529
+ return {
2530
+ "elementType": w?.elementType ?? 'wall',
2531
+ "distance": w?.distance ?? 16,
2532
+ "elementNumber": w?.elementNumber ?? 0,
2533
+ "unit": w?.unit ?? "ft",
2534
+ "direction": w?.direction ?? "right",
2535
+ "angle": w?.angle ?? 0,
2536
+ "relativePosition": w?.relativePosition,
2537
+ }
2538
+ });
2539
+ }
2540
+
2541
+ function createStoreFixtures(data, meta) {
2542
+
2543
+ let fixtures = [];
2544
+ const walls = data?.layoutPolygon ?? [];
2545
+ for (let i = 1; i <= walls.length; i++) {
2546
+ const w = walls[i - 1];
2547
+ const wFixtures = w?.fixtures ?? [];
2548
+
2549
+ for (let j = 1; j <= wFixtures.length; j++) {
2550
+ const f = wFixtures[j - 1];
2551
+
2552
+ const fixtureInfo = {
2553
+ f: f,
2554
+ meta: meta,
2555
+ wallNumber: w.elementNumber,
2556
+ fixtureNumber: j,
2557
+ }
2558
+
2559
+ fixtures.push(processFixtureData(fixtureInfo));
2560
+ }
2561
+ }
2562
+
2563
+ const centerFixtures = data?.centerFixture ?? [];
2564
+ for (let i = 1; i <= centerFixtures.length; i++) {
2565
+ const f = centerFixtures[i - 1];
2566
+
2567
+ const fixtureInfo = {
2568
+ f: f,
2569
+ meta: meta,
2570
+ wallNumber: undefined,
2571
+ fixtureNumber: i,
2572
+ }
2573
+
2574
+ fixtures.push(processFixtureData(fixtureInfo));
2575
+ }
2576
+
2577
+ return fixtures;
2578
+ }
2579
+
2580
+ function processFixtureData(data) {
2581
+ const f = data.f;
2582
+
2583
+ function normalizeCadText(value) {
2584
+ if (typeof value !== 'string') return value;
2585
+ return value.replace(/^\\[^;]+;/, '').trim();
2586
+ }
2587
+
2588
+ return {
2589
+ ...data.meta,
2590
+ fixtureName: normalizeCadText(f?.header?.label ?? ''),
2591
+ relativePosition: f?.relativePosition,
2592
+ fixtureType: f?.associatedElementType,
2593
+ header: {
2594
+ ...f?.header,
2595
+ label: normalizeCadText(f?.header?.label ?? '')
2596
+ },
2597
+ footer: f?.footer,
2598
+ fixtureWidth: f?.fixtureWidth,
2599
+ fixtureLength: f?.fixtureLength,
2600
+ fixtureNumber: f?.fixtureNumber,
2601
+ associatedElementNumber: data?.wallNumber,
2602
+ associatedElementFixtureNumber: data.fixtureNumber,
2603
+ associatedElementType: f?.associatedElementType === 'wall' ? 'wall' : undefined,
2604
+ productBrandName: Array.isArray(f?.productBrandName) ? f?.productBrandName?.map(normalizeCadText) : normalizeCadText(f?.productBrandName),
2605
+
2606
+ fixtureHeight: {
2607
+ value: 0,
2608
+ unit: 'mm',
2609
+ },
2610
+ fixtureStaticLength: {
2611
+ value: 1524,
2612
+ unit: 'mm',
2613
+ },
2614
+ fixtureStaticWidth: {
2615
+ value: 1220,
2616
+ unit: 'mm',
2617
+ },
2618
+ productResolutionLevel: 'L2',
2619
+ isBodyEnabled: true,
2620
+ isMerchEdited: false,
2621
+ isVmEdited: false,
2622
+ };
2623
+ }
@@ -9573,8 +9573,8 @@ export async function productMappings( req, res ) {
9573
9573
 
9574
9574
  const { fixtureId, Top, Mid, Bottom } = payload;
9575
9575
 
9576
- const storeName = 'LKST2681';
9577
- const storeId = '11-2362';
9576
+ const storeName = 'LKST11';
9577
+ const storeId = '11-259';
9578
9578
  const clientId = '11';
9579
9579
 
9580
9580
  if ( !fixtureId ) {
@@ -2792,7 +2792,7 @@ export async function storeFixturesv2( req, res ) {
2792
2792
  planograms.map( async ( planogram ) => {
2793
2793
  const floors = await storeBuilderService.find(
2794
2794
  { planoId: planogram._id, ...( req.body?.floorId && { _id: req.body.floorId } ) },
2795
- { floorName: 1, layoutPolygon: 1, planoId: 1, isEdited: 1, planoProgress: 1, updatedAt: 1, verificationStatus: 1, merchRolloutStatus: 1, vmRolloutStatus: 1 },
2795
+ { floorName: 1, layoutPolygon: 1, planoId: 1, isEdited: 1, planoProgress: 1, updatedAt: 1, verificationStatus: 1, merchRolloutStatus: 1, vmRolloutStatus: 1,cadLayout:1 },
2796
2796
  );
2797
2797
 
2798
2798
  const floorsWithFixtures = await Promise.all(
@@ -5154,8 +5154,8 @@ export async function planoList( req, res ) {
5154
5154
  clientId: inputData.clientId,
5155
5155
  status: 'active',
5156
5156
  ...( inputData?.stores?.length && { storeId: { $in: inputData.stores } } ),
5157
- ...( req.body.filter?.country?.length && { 'storeProfile.country': { $in: req.body.filter.country } } ),
5158
- ...( req.body.filter?.city?.length && { 'storeProfile.city': { $in: req.body.filter.city } } ),
5157
+ ...( req.body.filter.country.length && { 'storeProfile.country': { $in: req.body.filter.country } } ),
5158
+ ...( req.body.filter.city.length && { 'storeProfile.city': { $in: req.body.filter.city } } ),
5159
5159
  ...( req.body?.assignedStores?.length && { storeId: { $in: req.body?.assignedStores } } ) }, { storeId: 1, storeProfile: 1 } );
5160
5160
 
5161
5161
  let storeDetails = storeList.map( ( ele ) => ele.storeId );
@@ -6095,16 +6095,9 @@ export async function planoList( req, res ) {
6095
6095
  if ( req.body.export ) {
6096
6096
  let exportData = [];
6097
6097
  planoDetails[0].data.forEach( ( ele ) => {
6098
- let findStore = storeList.find( ( store ) => ele.storeId == store.storeId );
6099
- if ( findStore ) {
6100
- ele['country'] = findStore.storeProfile.country;
6101
- ele['city'] = findStore.storeProfile.city;
6102
- }
6103
6098
  exportData.push( {
6104
6099
  'Store Name': ele?.storeName ?? '--',
6105
6100
  'Layout Name': ele?.layoutName ?? '--',
6106
- 'Country': ele?.country ?? '--',
6107
- 'City': ele?.City ?? '--',
6108
6101
  'Plano Completion %': ele?.taskDetails.layoutStatus == 'complete' && ele?.taskDetails.fixtureStatus == 'complete' ? 100 : ele?.taskDetails.layoutStatus == 'complete' ? 50 : 25,
6109
6102
  'Layout': ele?.layoutCount ?? 0,
6110
6103
  'Layout Status': ele?.taskDetails.layoutStatus == 'complete' ? 'Completed' : 'Yet to assign',
@@ -6813,8 +6806,8 @@ export async function getRolloutDetails( req, res ) {
6813
6806
  clientId: req.body.clientId,
6814
6807
  status: 'active',
6815
6808
  ...( req.body?.stores?.length && { storeId: { $in: req.body.stores } } ),
6816
- ...( req.body.filter?.country?.length && { 'storeProfile.country': { $in: req.body.filter.country } } ),
6817
- ...( req.body.filter?.city?.length && { 'storeProfile.city': { $in: req.body.filter.city } } ),
6809
+ ...( req.body.filter.country.length && { 'storeProfile.country': { $in: req.body.filter.country } } ),
6810
+ ...( req.body.filter.city.length && { 'storeProfile.city': { $in: req.body.filter.city } } ),
6818
6811
  ...( req.body?.assignedStores?.length && { storeId: { $in: req.body?.assignedStores } } ) }, { storeId: 1, storeProfile: 1 } );
6819
6812
 
6820
6813
  let storeDetails = storeList.map( ( ele ) => ele.storeId );
@@ -7673,8 +7666,6 @@ export async function getRolloutDetails( req, res ) {
7673
7666
  exportData.push( {
7674
7667
  'Store Name': ele?.storeName ?? '--',
7675
7668
  'Plano Name': ele?.layoutName ?? '--',
7676
- 'Country': ele?.country ?? '--',
7677
- 'city': ele?.city ?? '--',
7678
7669
  'Merch Fixtures': ele?.fixtureCount ?? 0,
7679
7670
  'Merch Status': ele?.taskDetails.fixtureStatus == 'complete' ? 'Completed' : ele?.taskDetails.fixtureStatus == 'pending' ? 'Review Pending' : 'Yet to Assign',
7680
7671
  'Visual Merch': ele?.vmCount ?? 0,
@@ -8464,7 +8455,7 @@ export async function getPlanogramListOld( req, res ) {
8464
8455
 
8465
8456
  return res.sendSuccess( { data, count: total } );
8466
8457
  } catch ( err ) {
8467
- logger.error( { functionName: 'getPlanogramListOld', error: err } );
8458
+ logger.error( { functionName: 'getLayoutList', error: err } );
8468
8459
  return res.sendError( err, 500 );
8469
8460
  }
8470
8461
  }
@@ -8591,16 +8582,15 @@ export async function getPlanogramList( req, res ) {
8591
8582
  merchCompliance: {
8592
8583
  $floor: [
8593
8584
  {
8594
- $cond: {
8595
- if: { $gt: [ { $ifNull: [ '$productCount', 0 ] }, 0 ] },
8596
- then: {
8585
+ $multiply: [
8586
+ {
8597
8587
  $divide: [
8598
8588
  { $ifNull: [ { $arrayElemAt: [ '$complianceCount.count', 0 ] }, 0 ] },
8599
- '$productCount',
8589
+ { $ifNull: [ '$productCount', 1 ] },
8600
8590
  ],
8601
8591
  },
8602
- else: 0,
8603
- },
8592
+ 100,
8593
+ ],
8604
8594
  },
8605
8595
  ],
8606
8596
  },
@@ -8693,372 +8683,81 @@ export async function getPlanogramList( req, res ) {
8693
8683
 
8694
8684
  return res.sendSuccess( { data, count: total } );
8695
8685
  } catch ( err ) {
8696
- logger.error( { functionName: 'getPlanogramList', error: err } );
8686
+ logger.error( { functionName: 'getLayoutList', error: err } );
8697
8687
  return res.sendError( err, 500 );
8698
8688
  }
8699
8689
  }
8700
8690
 
8701
-
8702
- export async function revisionData( req, res ) {
8703
- try {
8704
- let storeList = req.body.store;
8705
- await Promise.all( storeList.map( async ( ele ) => {
8706
- console.log( ele );
8707
- req.body = { id: [ ele ] };
8708
- await convertFixtureStructure( req, res );
8709
- } ) );
8710
- return res.sendSuccess( 'Updated Successfully' );
8711
- } catch ( e ) {
8712
- logger.error( { functionName: 'revisionData', error: e } );
8713
- return res.sendError( e, 500 );
8714
- }
8715
- }
8716
-
8717
- async function convertFixtureStructure( req ) {
8691
+ export async function getStoreFloorsList(req, res) {
8718
8692
  try {
8719
- const planoIds = req.body.id
8720
- .filter( ( id ) => mongoose.Types.ObjectId.isValid( id ) )
8721
- .map( ( id ) => new mongoose.Types.ObjectId( id ) );
8722
-
8723
- const planograms = await planoService.find(
8724
- {
8725
- $or: [
8726
- { _id: { $in: planoIds } },
8727
- { storeId: { $in: req.body.id } },
8728
- ],
8729
- },
8730
- { storeId: 1, storeName: 1, planoId: '$_id', productResolutionLevel: 1, scanType: 1, clientId: 1, validateShelfSections: 1, layoutName: 1 },
8731
- );
8732
-
8733
- if ( !planograms?.length ) return false;
8734
-
8735
- const currentDate = new Date( dayjs().format( 'YYYY-MM-DD' ) );
8736
-
8737
- await Promise.all(
8738
- planograms.map( async ( planogram ) => {
8739
- const floors = await storeBuilderService.find(
8740
- { planoId: planogram._id, ...( req.body?.floorId && { _id: req.body.floorId } ) },
8741
- { floorName: 1, layoutPolygon: 1, planoId: 1, isEdited: 1, planoProgress: 1, updatedAt: 1, verificationStatus: 1, merchRolloutStatus: 1, vmRolloutStatus: 1 },
8742
- );
8743
-
8744
- await Promise.all(
8745
- floors.map( async ( floor, index ) => {
8746
- let fixtureCount = 0;
8747
- let totalVmCount = 0;
8748
- let productCapacity = 0;
8749
- const masterTemplateIds = new Set();
8750
- const layoutPolygonWithFixtures = await Promise.all(
8751
- floor.layoutPolygon.map( async ( element ) => {
8752
- const fixtures = await storeFixtureService.findAndSort( {
8753
- floorId: floor._id,
8754
- associatedElementType: element.elementType,
8755
- associatedElementNumber: element.elementNumber,
8756
- fixtureType: { $ne: 'other' },
8757
- }, { shelfcount: 0 }, { associatedElementFixtureNumber: 1 } );
8758
-
8759
- const fixturesWithStatus = await Promise.all(
8760
- fixtures.map( async ( fixture ) => {
8761
- if ( fixture?.masterTemplateId && mongoose.Types.ObjectId.isValid( fixture?.masterTemplateId ) ) {
8762
- masterTemplateIds.add( fixture?.masterTemplateId );
8763
- }
8764
- if ( fixture?.imageUrl ) {
8765
- let params = {
8766
- Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
8767
- file_path: fixture.imageUrl,
8768
- };
8769
- fixture.imageUrl = await signedUrl( params );
8770
- } else {
8771
- fixture.imageUrl = '';
8772
- }
8773
- productCapacity += fixture.toObject().fixtureCapacity;
8774
- fixtureCount += 1;
8775
- const productCount = await planoMappingService.count( { fixtureId: fixture._id, type: 'product' } );
8776
-
8777
- const vmCount = await planoMappingService.count( { fixtureId: fixture._id, type: 'vm' } );
8778
-
8779
- const complianceCount = await planoComplianceService.count( {
8780
- fixtureId: fixture._id,
8781
- compliance: 'proper',
8782
- date: currentDate,
8783
- } );
8784
-
8785
- const shelves = await fixtureShelfService.findAndSort( { fixtureId: fixture._id }, { }, { shelfNumber: 1 } );
8786
-
8787
- const shelfDetails = await Promise.all(
8788
- shelves.map( async ( shelf ) => {
8789
- const productDetails = await planoMappingService.find( { fixtureId: fixture._id, shelfId: shelf._id, type: 'product' }, { _id: 1 } );
8790
- let productIdList = productDetails.map( ( ele ) => ele._id );
8791
- let complianceQuery = [
8792
- {
8793
- $match: {
8794
- fixtureId: fixture._id,
8795
- shelfId: shelf._id,
8796
- date: currentDate,
8797
- planoMappingId: { $in: productIdList },
8798
- },
8799
- },
8800
- {
8801
- $group: {
8802
- _id: '$createdAt',
8803
- status: { $push: '$compliance' },
8804
- },
8805
- },
8806
- {
8807
- $sort: { _id: -1 },
8808
- },
8809
- {
8810
- $limit: 1,
8811
- },
8812
- ];
8813
- let complianceStatus = await planoComplianceService.aggregate( complianceQuery );
8814
- const compliance = complianceStatus?.[0]?.status?.length ? ( ( complianceStatus?.[0]?.status?.length != shelf.productPerShelf ) || complianceStatus?.[0]?.status.includes( 'misplaced' ) ) ? 'improper' : 'proper' : 'improper';
8815
-
8816
- const vmCount = await planoMappingService.count( { fixtureId: fixture._id, shelfId: shelf._id, type: 'vm' } );
8817
-
8818
- return {
8819
- ...shelf.toObject(),
8820
- productCount: productDetails.length,
8821
- vmCount: vmCount,
8822
- compliance,
8823
- };
8824
- } ),
8825
- );
8826
-
8827
- let fixtureStatus;
8828
-
8829
- const cvProcessStatus = await planoQrConversionRequestService.count( { fixtureId: fixture._id, date: currentDate, status: 'initiated' } );
8830
-
8831
- if ( cvProcessStatus ) {
8832
- fixtureStatus = 'inprogress';
8833
- } else {
8834
- const missingCount = await planoComplianceService.count( {
8835
- fixtureId: fixture._id,
8836
- compliance: 'missing',
8837
- date: currentDate,
8838
- } );
8839
- fixtureStatus = complianceCount === 0 && !missingCount ? '' : complianceCount === productCount ? 'complete' : 'incomplete';
8840
- }
8841
-
8842
-
8843
- const vmDetails = await Promise.all( fixture.toObject()?.vmConfig?.map( async ( vm ) => {
8844
- totalVmCount += 1;
8845
- const vmInfo = await planoVmService.findOne( { _id: vm.vmId } );
8846
- return {
8847
- ...vm,
8848
- ...vmInfo?.toObject(),
8849
- };
8850
- } ) );
8851
-
8852
- return {
8853
- ...fixture.toObject(),
8854
- status: fixtureStatus,
8855
- shelfCount: shelves.length,
8856
- productCount: productCount,
8857
- vmCount: vmCount,
8858
- shelfConfig: shelfDetails,
8859
- vmConfig: vmDetails,
8860
- };
8861
- } ),
8862
- );
8863
-
8864
- const otherElements = await storeFixtureService.find( {
8865
- floorId: floor._id,
8866
- associatedElementType: element.elementType,
8867
- associatedElementNumber: element.elementNumber,
8868
- fixtureType: 'other',
8869
- } );
8870
-
8871
- return {
8872
- ...element,
8873
- fixtures: fixturesWithStatus,
8874
- otherElements: otherElements,
8875
- };
8876
- } ),
8877
- );
8878
-
8879
- const centerFixtures = await storeFixtureService.findAndSort( {
8880
- floorId: floor._id,
8881
- $and: [
8882
- { associatedElementType: { $exists: false } },
8883
- { associatedElementNumber: { $exists: false } },
8884
- { fixtureType: { $ne: 'other' } },
8885
- ],
8886
- }, { shelfcount: 0 }, { associatedElementFixtureNumber: 1 } );
8887
-
8888
-
8889
- const centerFixturesWithStatus = await Promise.all(
8890
- centerFixtures.map( async ( fixture ) => {
8891
- if ( fixture?.masterTemplateId && mongoose.Types.ObjectId.isValid( fixture?.masterTemplateId ) ) {
8892
- masterTemplateIds.add( fixture?.masterTemplateId );
8893
- }
8894
- if ( fixture?.imageUrl ) {
8895
- let params = {
8896
- Bucket: JSON.parse( process.env.BUCKET ).storeBuilder,
8897
- file_path: fixture.imageUrl,
8898
- };
8899
- fixture.imageUrl = await signedUrl( params );
8900
- } else {
8901
- fixture.imageUrl = '';
8902
- }
8903
- productCapacity += fixture.toObject().fixtureCapacity;
8904
- fixtureCount += 1;
8905
- const productCount = await planoMappingService.count( { fixtureId: fixture._id, type: 'product' } );
8906
-
8907
- const vmCount = await planoMappingService.count( { fixtureId: fixture._id, type: 'vm' } );
8908
-
8909
- const complianceCount = await planoComplianceService.count( {
8910
- fixtureId: fixture._id,
8911
- compliance: 'proper',
8912
- date: currentDate,
8913
- } );
8914
-
8915
- const shelves = await fixtureShelfService.findAndSort( { fixtureId: fixture._id }, { }, { shelfNumber: 1 } );
8916
-
8917
- const shelfDetails = await Promise.all(
8918
- shelves.map( async ( shelf ) => {
8919
- const productDetails = await planoMappingService.find( { fixtureId: fixture._id, shelfId: shelf._id, type: 'product' }, { _id: 1 } );
8920
- let productIdList = productDetails.map( ( ele ) => ele._id );
8921
- let complianceQuery = [
8922
- {
8923
- $match: {
8924
- fixtureId: fixture._id,
8925
- shelfId: shelf._id,
8926
- date: currentDate,
8927
- planoMappingId: { $in: productIdList },
8928
- },
8929
- },
8930
- {
8931
- $group: {
8932
- _id: '$createdAt',
8933
- status: { $push: '$compliance' },
8934
- },
8935
- },
8936
- {
8937
- $sort: { _id: -1 },
8938
- },
8939
- {
8940
- $limit: 1,
8941
- },
8942
- ];
8943
- let complianceStatus = await planoComplianceService.aggregate( complianceQuery );
8944
- const compliance = complianceStatus?.[0]?.status.length ? ( ( complianceStatus?.[0]?.status?.length != shelf.productPerShelf ) || complianceStatus?.[0]?.status?.includes( 'misplaced' ) ) ? 'improper' : 'proper' : 'improper';
8945
-
8946
-
8947
- const vmCount = await planoMappingService.count( { fixtureId: fixture._id, shelfId: shelf._id, type: 'vm' } );
8948
-
8949
- return {
8950
- ...shelf.toObject(),
8951
- productCount: productDetails.length,
8952
- vmCount: vmCount,
8953
- compliance,
8954
- };
8955
- } ),
8956
- );
8957
-
8958
- let fixtureStatus;
8959
-
8960
- const cvProcessStatus = await planoQrConversionRequestService.count( { fixtureId: fixture._id, date: currentDate, status: 'initiated' } );
8961
-
8962
- if ( cvProcessStatus ) {
8963
- fixtureStatus = 'inprogress';
8964
- } else {
8965
- const missingCount = await planoComplianceService.count( {
8966
- fixtureId: fixture._id,
8967
- compliance: 'missing',
8968
- date: currentDate,
8969
- } );
8970
- fixtureStatus = complianceCount === 0 && !missingCount ? '' : complianceCount === productCount ? 'complete' : 'incomplete';
8971
- }
8972
-
8973
-
8974
- const vmDetails = await Promise.all( fixture.toObject().vmConfig.map( async ( vm ) => {
8975
- totalVmCount += 1;
8976
- const vmInfo = await planoVmService.findOne( { _id: vm.vmId } );
8977
8693
 
8978
- return {
8979
- ...vm,
8980
- ...vmInfo?.toObject(),
8981
- };
8982
- } ) );
8983
-
8984
- return {
8985
- ...fixture.toObject(),
8986
- status: fixtureStatus,
8987
- shelfCount: shelves.length,
8988
- productCount: productCount,
8989
- vmCount: vmCount,
8990
- shelfConfig: shelfDetails,
8991
- vmConfig: vmDetails,
8992
- };
8993
- } ),
8994
- );
8694
+ const { storeId } = req.query;
8995
8695
 
8696
+ if (!storeId) {
8697
+ return res.sendError('storeId is required');
8698
+ }
8996
8699
 
8997
- const otherElements = await storeFixtureService.find( {
8998
- floorId: floor._id,
8999
- associatedElementType: { $exists: false },
9000
- associatedElementNumber: { $exists: false },
9001
- fixtureType: 'other',
9002
- } );
8700
+ const query = [
8701
+ {
8702
+ $match: {
8703
+ storeId: storeId
8704
+ }
8705
+ },
8706
+ {
8707
+ $lookup: {
8708
+ from: "storelayouts",
8709
+ let: { planoId: "$_id" },
8710
+ pipeline: [
8711
+ {
8712
+ $match: {
8713
+ $expr: { $eq: ["$planoId", "$$planoId"] }
8714
+ }
8715
+ },
8716
+ {
8717
+ $project: {
8718
+ _id: 1,
8719
+ floorNumber: 1,
8720
+ floorName: 1
8721
+ }
8722
+ }
8723
+ ],
8724
+ as: "floors"
8725
+ }
8726
+ },
8727
+ {
8728
+ $project: {
8729
+ _id: 0,
8730
+ floors: 1
8731
+ }
8732
+ }
8733
+ ]
9003
8734
 
9004
8735
 
9005
- let masterTempArr = [ ...masterTemplateIds ];
8736
+ const floorsRes = await planoService.aggregate(query);
9006
8737
 
8738
+ return res.sendSuccess(floorsRes?.[0]?.floors ?? []);
9007
8739
 
9008
- if ( masterTempArr?.length && req.body?.treeView ) {
9009
- masterTempArr = await fixtureConfigService.find( { _id: { $in: [ ...masterTemplateIds ] } } );
9010
- }
8740
+ } catch (e) {
8741
+ logger.error({ functionName: 'getStoreFloorsList', error: e });
8742
+ return res.sendError(e, 500);
8743
+ }
8744
+ }
9011
8745
 
9012
- let floorData = {
9013
- ...floor.toObject(),
9014
- updatedAt: dayjs( floor?.updatedAt ).format( 'Do MMM YYYY' ),
9015
- fixtureCount: fixtureCount,
9016
- vmCount: totalVmCount,
9017
- layoutPolygon: layoutPolygonWithFixtures,
9018
- centerFixture: centerFixturesWithStatus,
9019
- otherElements: otherElements,
9020
- lastUpdate: dayjs( floor?.updatedAt ).format( 'Do MMMM YYYY hh:mm A' ),
9021
- ...( floors.length > 1 ) ? { floorNum: `Floor ${index + 1}/${floors.length}` } : { floorNum: 'Floor 1' },
9022
- };
8746
+ export async function getAllStores(req, res) {
8747
+ try {
9023
8748
 
9024
- let planoProductCount = 0;
9025
- layoutPolygonWithFixtures.forEach( ( poly ) => {
9026
- poly.fixtures.forEach( ( fixt ) => {
9027
- planoProductCount += fixt.fixtureCapacity;
9028
- } );
9029
- } );
8749
+ const { clientId } = req.query;
9030
8750
 
9031
- centerFixturesWithStatus.forEach( ( fixt ) => {
9032
- planoProductCount += fixt.fixtureCapacity;
9033
- } );
8751
+ if (!clientId) {
8752
+ return res.sendError('clientId is required', 400);
8753
+ }
9034
8754
 
9035
- floorData = { ...floorData, planoProductCount };
9036
-
9037
- const data = {
9038
- storeName: planogram.storeName,
9039
- storeId: planogram.storeId,
9040
- clientId: planogram.clientId,
9041
- planoId: planogram._id,
9042
- productResolutionLevel: planogram.productResolutionLevel,
9043
- scanType: planogram.scanType,
9044
- createdByName: 'Bejan',
9045
- createdByEmail: 'Bejan@tangotech.co.in',
9046
- createdBy: new mongoose.Types.ObjectId( '66a78cd82734f4f857cd6db6' ),
9047
- layoutName: planogram.layoutName,
9048
- floorId: floorData._id,
9049
- floorData: floorData,
9050
- };
8755
+ const storeRes = await storeService.find({ clientId: clientId, status: 'active' }, { storeId: 1, storeName: 1, _id: 0 })
9051
8756
 
9052
- console.log( data, 'data' );
8757
+ return res.sendSuccess(storeRes);
9053
8758
 
9054
- await planoRevisionService.create( data );
9055
- } ),
9056
- );
9057
- } ),
9058
- );
9059
- } catch ( e ) {
9060
- console.log( e );
9061
- logger.error( { functionName: 'storeFixturesv2', error: e, message: req.body } );
9062
- return e;
8759
+ } catch (e) {
8760
+ logger.error({ functionName: 'getAllStores', error: e });
8761
+ return res.sendError(e, 500);
9063
8762
  }
9064
8763
  }
@@ -6,25 +6,26 @@ import { isAllowedSessionHandler } from 'tango-app-api-middleware';
6
6
  export const managePlanoRouter = express.Router();
7
7
 
8
8
  managePlanoRouter
9
- .post( '/updateStorePlano', isAllowedSessionHandler, managePlanoController.updateStorePlano )
10
- .post( '/getplanoFeedback', isAllowedSessionHandler, managePlanoController.getplanoFeedback )
11
- .post( '/getplanoFeedbackv1', isAllowedSessionHandler, managePlanoController.getplanoFeedbackv1 )
12
- .post( '/getStoreFixturesfeedback', isAllowedSessionHandler, managePlanoController.getStoreFixturesfeedback )
13
- .get( '/fixtureList', isAllowedSessionHandler, managePlanoController.fixtureList )
14
- .get( '/templateList', isAllowedSessionHandler, managePlanoController.templateList )
15
- .get( '/fixtureBrandsList', isAllowedSessionHandler, managePlanoController.fixtureBrandsList )
16
- .get( '/fixtureVMList', isAllowedSessionHandler, managePlanoController.fixtureVMList )
17
- .get( '/fixtureVMListv1', isAllowedSessionHandler, managePlanoController.fixtureVMListv1 )
18
- .post( '/updateFixtureStatus', isAllowedSessionHandler, managePlanoController.updateFixtureStatus )
19
- .post( '/updateApprovalStatus', isAllowedSessionHandler, managePlanoController.updateApprovalStatus )
20
- .post( '/updateStoreFixture', isAllowedSessionHandler, managePlanoController.updateStoreFixture )
21
- .post( '/updateredostatus', isAllowedSessionHandler, managePlanoController.updateredostatus )
22
- .post( '/updateGlobalComment', isAllowedSessionHandler, managePlanoController.updateGlobalComment )
23
- .post( '/getGlobalComment', isAllowedSessionHandler, managePlanoController.getGlobalComment )
24
- .post( '/createRevision', isAllowedSessionHandler, managePlanoController.createPlanoRevision )
25
- .post( '/getRevisions', isAllowedSessionHandler, managePlanoController.getAllPlanoRevisions )
26
- .post( '/getRevisionData', isAllowedSessionHandler, managePlanoController.getPlanoRevisionById )
27
- .post( '/getRolloutFeedback', isAllowedSessionHandler, managePlanoController.getRolloutFeedback )
28
- .post( '/getRolloutFeedbackv2', isAllowedSessionHandler, managePlanoController.getRolloutFeedbackv2 )
29
- .post( '/updateRolloutStatus', isAllowedSessionHandler, managePlanoController.updateRolloutStatus )
30
- .post( '/getPlanoStoreVideoParams', isAllowedSessionHandler, managePlanoController.getPlanoStoreVideoPageParams );
9
+ .post('/updateStorePlano', isAllowedSessionHandler, managePlanoController.updateStorePlano)
10
+ .post('/getplanoFeedback', isAllowedSessionHandler, managePlanoController.getplanoFeedback)
11
+ .post('/getplanoFeedbackv1', isAllowedSessionHandler, managePlanoController.getplanoFeedbackv1)
12
+ .post('/getStoreFixturesfeedback', isAllowedSessionHandler, managePlanoController.getStoreFixturesfeedback)
13
+ .get('/fixtureList', isAllowedSessionHandler, managePlanoController.fixtureList)
14
+ .get('/templateList', isAllowedSessionHandler, managePlanoController.templateList)
15
+ .get('/fixtureBrandsList', isAllowedSessionHandler, managePlanoController.fixtureBrandsList)
16
+ .get('/fixtureVMList', isAllowedSessionHandler, managePlanoController.fixtureVMList)
17
+ .get('/fixtureVMListv1', isAllowedSessionHandler, managePlanoController.fixtureVMListv1)
18
+ .post('/updateFixtureStatus', isAllowedSessionHandler, managePlanoController.updateFixtureStatus)
19
+ .post('/updateApprovalStatus', isAllowedSessionHandler, managePlanoController.updateApprovalStatus)
20
+ .post('/updateStoreFixture', isAllowedSessionHandler, managePlanoController.updateStoreFixture)
21
+ .post('/updateredostatus', isAllowedSessionHandler, managePlanoController.updateredostatus)
22
+ .post('/updateGlobalComment', isAllowedSessionHandler, managePlanoController.updateGlobalComment)
23
+ .post('/getGlobalComment', isAllowedSessionHandler, managePlanoController.getGlobalComment)
24
+ .post('/createRevision', isAllowedSessionHandler, managePlanoController.createPlanoRevision)
25
+ .post('/getRevisions', isAllowedSessionHandler, managePlanoController.getAllPlanoRevisions)
26
+ .post('/getRevisionData', isAllowedSessionHandler, managePlanoController.getPlanoRevisionById)
27
+ .post('/getRolloutFeedback', isAllowedSessionHandler, managePlanoController.getRolloutFeedback)
28
+ .post('/getRolloutFeedbackv2', isAllowedSessionHandler, managePlanoController.getRolloutFeedbackv2)
29
+ .post('/updateRolloutStatus', isAllowedSessionHandler, managePlanoController.updateRolloutStatus)
30
+ .post('/getPlanoStoreVideoParams', isAllowedSessionHandler, managePlanoController.getPlanoStoreVideoPageParams)
31
+ .post('/createPlanoFromCAD', isAllowedSessionHandler, managePlanoController.createPlanoFromCAD);
@@ -69,5 +69,6 @@ storeBuilderRouter
69
69
  .post( '/updateProductMapping', storeBuilderController.updateProductMapping )
70
70
  .post( '/calculateCompliance', isAllowedSessionHandler, storeBuilderController.calculateCompliance )
71
71
  .post( '/getPlanogramList', isAllowedSessionHandler, storeBuilderController.getPlanogramList )
72
- .post( '/revisionUpdate', storeBuilderController.revisionData )
72
+ .get('/getAllStores', isAllowedSessionHandler, storeBuilderController.getAllStores)
73
+ .get('/getStoreFloorsList', isAllowedSessionHandler, storeBuilderController.getStoreFloorsList)
73
74
  ;