tango-app-api-store-builder 1.1.6 → 1.1.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/data/failure_cases.json +1 -10
- package/data/ivmLogic.json +3 -24
- package/package.json +2 -2
- package/src/controllers/collectionUpdates.controller.js +2 -578
- package/src/controllers/planoAI.controller.js +77 -1582
- package/src/controllers/script.controller.js +2 -72
- package/src/controllers/storeBuilder.controller.js +4 -11
- package/src/routes/planoAI.routes.js +1 -12
- package/data/Lenskart Offline New launches VM Placement.xlsx +0 -0
- package/data/UpdatedURF-520 antenna_floor.xlsx +0 -0
- package/data/UpdatedURF-520 antenna_wall.xlsx +0 -0
- package/data/customSort_changed_stores.json +0 -10754
- package/data/kpop_nunn_update_fails.json +0 -752
- package/src/service/cluster.service.js +0 -21
- package/src/service/findReplaceAiModel.service.js +0 -45
package/data/failure_cases.json
CHANGED
package/data/ivmLogic.json
CHANGED
|
@@ -2248,7 +2248,7 @@
|
|
|
2248
2248
|
{
|
|
2249
2249
|
"Header": "Work Essentials",
|
|
2250
2250
|
"Top": "VC/Studio Non Metals",
|
|
2251
|
-
"Mid": "Air PIDs",
|
|
2251
|
+
"Mid": "Air PIDs + Air Pids PIDs",
|
|
2252
2252
|
"Bottom": "VC/Studio Full Rim Metals & HR &RL"
|
|
2253
2253
|
}
|
|
2254
2254
|
]
|
|
@@ -2265,7 +2265,7 @@
|
|
|
2265
2265
|
},
|
|
2266
2266
|
{
|
|
2267
2267
|
"Header": "Work Essentials",
|
|
2268
|
-
"Top": "Air PIDs",
|
|
2268
|
+
"Top": "Air PIDs + Air Pids PIDs",
|
|
2269
2269
|
"Mid": "VC Eye Full Rim Metals",
|
|
2270
2270
|
"Bottom": "HR & RL"
|
|
2271
2271
|
}
|
|
@@ -2284,7 +2284,7 @@
|
|
|
2284
2284
|
{
|
|
2285
2285
|
"Header": "Work Essentials",
|
|
2286
2286
|
"Top": "VC Eye Acetate",
|
|
2287
|
-
"Mid": "Air PIDs",
|
|
2287
|
+
"Mid": "Air PIDs + Air Pids PIDs",
|
|
2288
2288
|
"Bottom": "Air PIDs"
|
|
2289
2289
|
},
|
|
2290
2290
|
{
|
|
@@ -5850,13 +5850,6 @@
|
|
|
5850
5850
|
"Top panel": "Make every look extraordinary",
|
|
5851
5851
|
"1X3 talker": "Bold acetate"
|
|
5852
5852
|
},
|
|
5853
|
-
{
|
|
5854
|
-
"Header": "Trending",
|
|
5855
|
-
"Fixture": "Trending 3",
|
|
5856
|
-
"PID Allocation": "Studio eye + sun",
|
|
5857
|
-
"Top panel": "Dark Knight",
|
|
5858
|
-
"1X3 talker": "Dark Knight"
|
|
5859
|
-
},
|
|
5860
5853
|
{
|
|
5861
5854
|
"Header": "Work essentials",
|
|
5862
5855
|
"Fixture": "Air 1",
|
|
@@ -5899,20 +5892,6 @@
|
|
|
5899
5892
|
"Top panel": "Barely there perfectly present",
|
|
5900
5893
|
"1X3 talker": "Half rim and rimless 2"
|
|
5901
5894
|
},
|
|
5902
|
-
{
|
|
5903
|
-
"Header": "Work essentials",
|
|
5904
|
-
"Fixture": "Work essentials 1",
|
|
5905
|
-
"PID Allocation": "LK AIR Switch",
|
|
5906
|
-
"Top panel": "Specs to sunnies. Sunnies to specs",
|
|
5907
|
-
"1X3 talker": "Switch"
|
|
5908
|
-
},
|
|
5909
|
-
{
|
|
5910
|
-
"Header": "Work essentials",
|
|
5911
|
-
"Fixture": "Work essentials 1",
|
|
5912
|
-
"PID Allocation": "LK air switch",
|
|
5913
|
-
"Top panel": "Specs to sunnies. Sunnies to specs",
|
|
5914
|
-
"1X3 talker": "Switch"
|
|
5915
|
-
},
|
|
5916
5895
|
{
|
|
5917
5896
|
"Header": "Innovation",
|
|
5918
5897
|
"Fixture": "Innovation",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-store-builder",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
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.
|
|
36
|
+
"tango-api-schema": "^2.5.41",
|
|
37
37
|
"tango-app-api-middleware": "3.1.48",
|
|
38
38
|
"url": "^0.11.4",
|
|
39
39
|
"winston": "^3.17.0",
|
|
@@ -4229,13 +4229,13 @@ export async function updateTemplateGroup() {
|
|
|
4229
4229
|
);
|
|
4230
4230
|
|
|
4231
4231
|
|
|
4232
|
-
const fixture = storeFixtures.find( ( fixture ) => fixture.
|
|
4232
|
+
const fixture = storeFixtures.find( ( fixture ) => fixture.header.label === 'JJ Sun' );
|
|
4233
4233
|
|
|
4234
4234
|
if ( !fixture ) {
|
|
4235
4235
|
continue;
|
|
4236
4236
|
}
|
|
4237
4237
|
|
|
4238
|
-
fixture.
|
|
4238
|
+
fixture.header.label = 'Meller';
|
|
4239
4239
|
|
|
4240
4240
|
await updateFixtures( [ fixture ] );
|
|
4241
4241
|
console.log( `Updated store: ${store} ${fixture.fixtureType}` );
|
|
@@ -4243,579 +4243,3 @@ export async function updateTemplateGroup() {
|
|
|
4243
4243
|
}
|
|
4244
4244
|
|
|
4245
4245
|
// updateTemplateGroup();
|
|
4246
|
-
|
|
4247
|
-
async function updateKpopNunNCollection() {
|
|
4248
|
-
const workbook = xlsx.readFile( './data/Lenskart Offline New launches VM Placement.xlsx' );
|
|
4249
|
-
|
|
4250
|
-
const sheetName = 'KPOP (NunN)';
|
|
4251
|
-
const sheet = workbook.Sheets[sheetName];
|
|
4252
|
-
|
|
4253
|
-
if ( !sheet ) {
|
|
4254
|
-
console.error( `Sheet "${sheetName}" not found in workbook` );
|
|
4255
|
-
return;
|
|
4256
|
-
}
|
|
4257
|
-
|
|
4258
|
-
const JsonData = xlsx.utils.sheet_to_json( sheet );
|
|
4259
|
-
const data = JSON.parse( JSON.stringify( JsonData, null, 2 ) );
|
|
4260
|
-
|
|
4261
|
-
const sortFunc = ( groupFixtures ) => {
|
|
4262
|
-
const sortRules = {
|
|
4263
|
-
5: 'desc',
|
|
4264
|
-
1: 'asc',
|
|
4265
|
-
2: 'asc',
|
|
4266
|
-
3: 'asc',
|
|
4267
|
-
4: 'desc',
|
|
4268
|
-
floor: 'asc',
|
|
4269
|
-
};
|
|
4270
|
-
|
|
4271
|
-
const staticOrder = [ '5', '1', '2', '4', '3', 'floor' ];
|
|
4272
|
-
|
|
4273
|
-
return groupFixtures.sort( ( a, b ) => {
|
|
4274
|
-
const wallA = a.associatedElementNumber !== undefined ? String( a.associatedElementNumber ) : 'floor';
|
|
4275
|
-
const wallB = b.associatedElementNumber !== undefined ? String( b.associatedElementNumber ) : 'floor';
|
|
4276
|
-
|
|
4277
|
-
// Step 1: enforce static wall order
|
|
4278
|
-
if ( wallA !== wallB ) {
|
|
4279
|
-
return staticOrder.indexOf( wallA ) - staticOrder.indexOf( wallB );
|
|
4280
|
-
}
|
|
4281
|
-
|
|
4282
|
-
// Step 2: same wall/floor → apply rule
|
|
4283
|
-
const rule = sortRules[wallA];
|
|
4284
|
-
const fixtureA = a.associatedElementFixtureNumber;
|
|
4285
|
-
const fixtureB = b.associatedElementFixtureNumber;
|
|
4286
|
-
|
|
4287
|
-
return rule === 'asc' ?
|
|
4288
|
-
fixtureA - fixtureB :
|
|
4289
|
-
fixtureB - fixtureA;
|
|
4290
|
-
} );
|
|
4291
|
-
};
|
|
4292
|
-
|
|
4293
|
-
async function getFixtures( query ) {
|
|
4294
|
-
let fixtures = await storeFixtureService.find( query );
|
|
4295
|
-
|
|
4296
|
-
fixtures = fixtures.map( ( fixture ) => fixture.toObject() );
|
|
4297
|
-
|
|
4298
|
-
const fixturesWithShelvesAndVms = await Promise.all(
|
|
4299
|
-
fixtures.map( async ( fixture ) => {
|
|
4300
|
-
const shelves = await fixtureShelfService.findAndSort( { fixtureId: fixture._id }, { }, { shelfNumber: 1 } );
|
|
4301
|
-
|
|
4302
|
-
const shelfDetails = await Promise.all(
|
|
4303
|
-
shelves.map( async ( shelf ) => {
|
|
4304
|
-
return shelf.toObject();
|
|
4305
|
-
} ),
|
|
4306
|
-
);
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
const vmDetails = await Promise.all( fixture?.vmConfig?.map( async ( vm ) => {
|
|
4310
|
-
const vmInfo = await planoVmService.findOne( { _id: vm.vmId } );
|
|
4311
|
-
return {
|
|
4312
|
-
...vm,
|
|
4313
|
-
...vmInfo?.toObject(),
|
|
4314
|
-
};
|
|
4315
|
-
} ) );
|
|
4316
|
-
|
|
4317
|
-
return {
|
|
4318
|
-
...fixture,
|
|
4319
|
-
shelfConfig: shelfDetails,
|
|
4320
|
-
vmConfig: vmDetails,
|
|
4321
|
-
};
|
|
4322
|
-
} ),
|
|
4323
|
-
);
|
|
4324
|
-
|
|
4325
|
-
return fixturesWithShelvesAndVms;
|
|
4326
|
-
};
|
|
4327
|
-
|
|
4328
|
-
async function updateFixtures( fixtures = [] ) {
|
|
4329
|
-
for ( let i = 0; i < fixtures.length; i++ ) {
|
|
4330
|
-
const fixture = fixtures[i];
|
|
4331
|
-
if ( !fixture ) {
|
|
4332
|
-
continue;
|
|
4333
|
-
}
|
|
4334
|
-
|
|
4335
|
-
const fixtureId = fixture._id;
|
|
4336
|
-
delete fixture._id;
|
|
4337
|
-
|
|
4338
|
-
const fixtureBrands = new Set();
|
|
4339
|
-
|
|
4340
|
-
await Promise.all( fixture.shelfConfig.map( async ( shelf ) => {
|
|
4341
|
-
const shelfId = shelf._id;
|
|
4342
|
-
delete shelf._id;
|
|
4343
|
-
shelf.productBrandName.forEach( ( brand ) => fixtureBrands.add( brand ) );
|
|
4344
|
-
return await fixtureShelfService.updateOne( { _id: shelfId }, shelf );
|
|
4345
|
-
} ) );
|
|
4346
|
-
|
|
4347
|
-
fixture.productBrandName = [ ...fixtureBrands ];
|
|
4348
|
-
|
|
4349
|
-
const vmConfig = await Promise.all( fixture.vmConfig.map( async ( vm ) => {
|
|
4350
|
-
let isVmExist = await planoVmService.findOne( { vmName: vm.vmName } );
|
|
4351
|
-
|
|
4352
|
-
if ( !isVmExist ) {
|
|
4353
|
-
const updateData = {
|
|
4354
|
-
'vmName': vm.vmName,
|
|
4355
|
-
'clientId': '11',
|
|
4356
|
-
'status': 'complete',
|
|
4357
|
-
'vmHeight': {
|
|
4358
|
-
'value': 100,
|
|
4359
|
-
'unit': 'mm',
|
|
4360
|
-
},
|
|
4361
|
-
'vmType': 'LKVM',
|
|
4362
|
-
'vmWidth': {
|
|
4363
|
-
'value': 230,
|
|
4364
|
-
'unit': 'mm',
|
|
4365
|
-
},
|
|
4366
|
-
};
|
|
4367
|
-
|
|
4368
|
-
isVmExist = await planoVmService.create( updateData );
|
|
4369
|
-
}
|
|
4370
|
-
|
|
4371
|
-
return { vmId: isVmExist._id, ...vm };
|
|
4372
|
-
} ) );
|
|
4373
|
-
|
|
4374
|
-
fixture.vmConfig = vmConfig;
|
|
4375
|
-
delete fixture.shelfConfig;
|
|
4376
|
-
|
|
4377
|
-
await storeFixtureService.updateOne( { _id: fixtureId }, fixture );
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4381
|
-
const checkVmExistInFixtures = ( fixtures, vmName ) => {
|
|
4382
|
-
if ( !vmName || !Array.isArray( fixtures ) ) return false;
|
|
4383
|
-
|
|
4384
|
-
const normalizedName = vmName.replace( /\s+/g, '' ).toLowerCase();
|
|
4385
|
-
|
|
4386
|
-
return fixtures.some( ( fixture ) =>
|
|
4387
|
-
Array.isArray( fixture?.vmConfig ) &&
|
|
4388
|
-
fixture.vmConfig.some( ( vm ) => {
|
|
4389
|
-
if ( !vm.vmName ) return false;
|
|
4390
|
-
const normalizedFixtureVm = vm.vmName.replace( /\s+/g, '' ).toLowerCase();
|
|
4391
|
-
return normalizedFixtureVm.includes( normalizedName );
|
|
4392
|
-
} ),
|
|
4393
|
-
);
|
|
4394
|
-
};
|
|
4395
|
-
|
|
4396
|
-
const checkBrandExistInShelves = ( fixtures, brandName ) => {
|
|
4397
|
-
if ( !brandName || !Array.isArray( fixtures ) ) return false;
|
|
4398
|
-
|
|
4399
|
-
const normalizedBrand = brandName.replace( /\s+/g, '' ).toLowerCase();
|
|
4400
|
-
|
|
4401
|
-
return fixtures.some( ( fixture ) =>
|
|
4402
|
-
Array.isArray( fixture.shelfConfig ) &&
|
|
4403
|
-
fixture.shelfConfig.some( ( shelf ) =>
|
|
4404
|
-
Array.isArray( shelf.productBrandName ) &&
|
|
4405
|
-
shelf.productBrandName.some( ( name ) =>
|
|
4406
|
-
name.replace( /\s+/g, '' ).toLowerCase().includes( normalizedBrand ),
|
|
4407
|
-
),
|
|
4408
|
-
),
|
|
4409
|
-
);
|
|
4410
|
-
};
|
|
4411
|
-
|
|
4412
|
-
const writeLog = ( logData, path ) => {
|
|
4413
|
-
let logs = [];
|
|
4414
|
-
|
|
4415
|
-
try {
|
|
4416
|
-
const fileContent = fs.readFileSync( path, "utf8" );
|
|
4417
|
-
logs = JSON.parse( fileContent );
|
|
4418
|
-
|
|
4419
|
-
if ( !Array.isArray( logs ) ) {
|
|
4420
|
-
logs = [];
|
|
4421
|
-
}
|
|
4422
|
-
} catch ( err ) {
|
|
4423
|
-
logs = [];
|
|
4424
|
-
}
|
|
4425
|
-
|
|
4426
|
-
logs.push( logData );
|
|
4427
|
-
|
|
4428
|
-
fs.writeFileSync( path, JSON.stringify( logs, null, 2 ) );
|
|
4429
|
-
};
|
|
4430
|
-
|
|
4431
|
-
// Handle Tentpole Euro Centers: Replace Hip Hop with KPOP (NuuN), If Hip Hop not found then Replace Bidri, If both not found, then replace existing VM on first Tentpole Euro Centers
|
|
4432
|
-
async function handleTentpoleEuroCenters( fixtures, store ) {
|
|
4433
|
-
// Filter fixtures that match "Tentpole" OR "VC Eye / LK Air"
|
|
4434
|
-
let matchingFixtures = fixtures.filter( ( fixture ) => {
|
|
4435
|
-
const rawLabel = fixture.header?.label;
|
|
4436
|
-
const label = rawLabel ? rawLabel.replace( /\s+/g, " " ).trim() : "";
|
|
4437
|
-
|
|
4438
|
-
const rawDescription = fixture.description;
|
|
4439
|
-
const description = rawDescription ? rawDescription.replace( /\s+/g, " " ).trim() : "";
|
|
4440
|
-
|
|
4441
|
-
// Check label match
|
|
4442
|
-
const labelMatch =
|
|
4443
|
-
label === "Tentpole" ||
|
|
4444
|
-
label === "VC Eye / LK Air" ||
|
|
4445
|
-
label.toLowerCase().includes( "tentpole" ) ||
|
|
4446
|
-
label.toLowerCase().includes( "vc eye" ) ||
|
|
4447
|
-
label.toLowerCase().includes( "lk air" );
|
|
4448
|
-
|
|
4449
|
-
// Check description only if label does NOT exist
|
|
4450
|
-
const descriptionMatch =
|
|
4451
|
-
( !label || label.length === 0 ) &&
|
|
4452
|
-
( description === "Tentpole" ||
|
|
4453
|
-
description === "VC Eye / LK Air" ||
|
|
4454
|
-
description.toLowerCase().includes( "tentpole" ) ||
|
|
4455
|
-
description.toLowerCase().includes( "vc eye" ) ||
|
|
4456
|
-
description.toLowerCase().includes( "lk air" ) );
|
|
4457
|
-
|
|
4458
|
-
return labelMatch || descriptionMatch;
|
|
4459
|
-
} );
|
|
4460
|
-
|
|
4461
|
-
if ( matchingFixtures.length === 0 ) {
|
|
4462
|
-
const logData = {
|
|
4463
|
-
store: store?.['Store Code'],
|
|
4464
|
-
condition: store?.['Placement'],
|
|
4465
|
-
exception: store?.['Exceptions'],
|
|
4466
|
-
};
|
|
4467
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4468
|
-
return;
|
|
4469
|
-
}
|
|
4470
|
-
|
|
4471
|
-
// Check for VM exceptions on all filtered fixtures
|
|
4472
|
-
// Priority: 1. Tentpole fixture (if found, use it regardless of Hip Hop or Bidri), 2. Hip Hop, 3. Bidri, 4. Any other fixture
|
|
4473
|
-
let tentpoleFixture = matchingFixtures.find( ( fixture ) => {
|
|
4474
|
-
const rawLabel = fixture.header?.label;
|
|
4475
|
-
const label = rawLabel ? rawLabel.replace( /\s+/g, " " ).trim() : "";
|
|
4476
|
-
const rawDescription = fixture.description;
|
|
4477
|
-
const description = rawDescription ? rawDescription.replace( /\s+/g, " " ).trim() : "";
|
|
4478
|
-
|
|
4479
|
-
// Check if it's a Tentpole fixture (label or description)
|
|
4480
|
-
const isTentpole = label === "Tentpole" ||
|
|
4481
|
-
label.toLowerCase().includes( "tentpole" ) ||
|
|
4482
|
-
( ( !label || label.length === 0 ) &&
|
|
4483
|
-
( description === "Tentpole" || description.toLowerCase().includes( "tentpole" ) ) );
|
|
4484
|
-
|
|
4485
|
-
return isTentpole;
|
|
4486
|
-
} );
|
|
4487
|
-
|
|
4488
|
-
if ( !tentpoleFixture ) {
|
|
4489
|
-
// If no Tentpole found, look for Hip Hop
|
|
4490
|
-
tentpoleFixture = matchingFixtures.find( ( fixture ) => {
|
|
4491
|
-
return checkVmExistInFixtures( [ fixture ], 'Hip Hop' ) || checkVmExistInFixtures( [ fixture ], 'Hiphop' );
|
|
4492
|
-
} );
|
|
4493
|
-
}
|
|
4494
|
-
|
|
4495
|
-
if ( !tentpoleFixture ) {
|
|
4496
|
-
// If no Hip Hop found, look for Bidri
|
|
4497
|
-
tentpoleFixture = matchingFixtures.find( ( fixture ) => {
|
|
4498
|
-
return checkVmExistInFixtures( [ fixture ], 'Bidri' );
|
|
4499
|
-
} );
|
|
4500
|
-
}
|
|
4501
|
-
|
|
4502
|
-
if ( !tentpoleFixture ) {
|
|
4503
|
-
// If none of the above found, use the first matching fixture
|
|
4504
|
-
tentpoleFixture = matchingFixtures[0];
|
|
4505
|
-
}
|
|
4506
|
-
|
|
4507
|
-
// Check if Hip Hop exists on the selected fixture
|
|
4508
|
-
const hasHipHop = checkVmExistInFixtures( [ tentpoleFixture ], 'Hip Hop' ) || checkVmExistInFixtures( [ tentpoleFixture ], 'Hiphop' );
|
|
4509
|
-
// Check if Bidri exists on the selected fixture
|
|
4510
|
-
const hasBidri = checkVmExistInFixtures( [ tentpoleFixture ], 'Bidri' );
|
|
4511
|
-
|
|
4512
|
-
// Calculate shelf count for L-shaped VM configuration
|
|
4513
|
-
const shelfCount = tentpoleFixture.shelfConfig?.length || 4;
|
|
4514
|
-
const verticalEndPosition = Math.max( 1, shelfCount - 1 ); // Vertical part covers shelves 1 to (shelfCount - 1)
|
|
4515
|
-
const horizontalPosition = shelfCount; // Horizontal part covers the last shelf
|
|
4516
|
-
|
|
4517
|
-
// Create KPOP (NuuN) VM data in L-shape: two VMs
|
|
4518
|
-
const kpopVmConfig = [
|
|
4519
|
-
{
|
|
4520
|
-
vmName: 'KPOP (NuuN) - 1',
|
|
4521
|
-
startYPosition: 1,
|
|
4522
|
-
endYPosition: verticalEndPosition,
|
|
4523
|
-
xZone: 'left',
|
|
4524
|
-
yZone: 'stretch',
|
|
4525
|
-
},
|
|
4526
|
-
{
|
|
4527
|
-
vmName: 'KPOP (NuuN) - 2',
|
|
4528
|
-
startYPosition: horizontalPosition,
|
|
4529
|
-
endYPosition: horizontalPosition,
|
|
4530
|
-
xZone: 'stretch',
|
|
4531
|
-
yZone: 'stretch',
|
|
4532
|
-
},
|
|
4533
|
-
];
|
|
4534
|
-
|
|
4535
|
-
if ( hasHipHop ) {
|
|
4536
|
-
// Replace Hip Hop VM
|
|
4537
|
-
tentpoleFixture.vmConfig = tentpoleFixture.vmConfig.filter( ( vm ) => {
|
|
4538
|
-
const normalizedVm = vm.vmName?.replace( /\s+/g, '' ).toLowerCase() || '';
|
|
4539
|
-
return !normalizedVm.includes( 'hiphop' ) && !normalizedVm.includes( 'hip hop' );
|
|
4540
|
-
} );
|
|
4541
|
-
tentpoleFixture.vmConfig.push( ...kpopVmConfig );
|
|
4542
|
-
} else if ( hasBidri ) {
|
|
4543
|
-
// Replace Bidri VM
|
|
4544
|
-
tentpoleFixture.vmConfig = tentpoleFixture.vmConfig.filter( ( vm ) => {
|
|
4545
|
-
const normalizedVm = vm.vmName?.replace( /\s+/g, '' ).toLowerCase() || '';
|
|
4546
|
-
return !normalizedVm.includes( 'bidri' );
|
|
4547
|
-
} );
|
|
4548
|
-
tentpoleFixture.vmConfig.push( ...kpopVmConfig );
|
|
4549
|
-
} else {
|
|
4550
|
-
// Replace existing VM on first Tentpole Euro Centers
|
|
4551
|
-
tentpoleFixture.vmConfig = kpopVmConfig;
|
|
4552
|
-
}
|
|
4553
|
-
|
|
4554
|
-
// Update productBrandName for all shelves to "KPOP (NunN)"
|
|
4555
|
-
tentpoleFixture.shelfConfig.forEach( ( shelf ) => {
|
|
4556
|
-
shelf.productBrandName = [ 'KPOP (NunN)' ];
|
|
4557
|
-
} );
|
|
4558
|
-
|
|
4559
|
-
await updateFixtures( [ tentpoleFixture ] );
|
|
4560
|
-
}
|
|
4561
|
-
|
|
4562
|
-
// Handle Non IVM Wall Talker: First VC Eye+LK Air Eye Fixtures-Mid Zone
|
|
4563
|
-
// Exception: If First Fixture is Sale/Almost Gone Fixture/Mid Zone is allocated Hustlr VM/Phonic Full VM then move to Second fixture
|
|
4564
|
-
async function handleNonIvmWallTalker( fixtures, store ) {
|
|
4565
|
-
let vcLkFixtures = fixtures.filter( ( fixture ) =>
|
|
4566
|
-
fixture.header?.label === 'VC Eye / LK Air' || fixture.header?.label?.toLowerCase().includes( 'vc eye' ) || fixture.header?.label?.toLowerCase().includes( 'lk air' ),
|
|
4567
|
-
);
|
|
4568
|
-
|
|
4569
|
-
if ( vcLkFixtures.length === 0 ) {
|
|
4570
|
-
const logData = {
|
|
4571
|
-
store: store?.['Store Code'],
|
|
4572
|
-
condition: store?.['Placement'],
|
|
4573
|
-
exception: store?.['Exceptions'],
|
|
4574
|
-
};
|
|
4575
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4576
|
-
return;
|
|
4577
|
-
}
|
|
4578
|
-
|
|
4579
|
-
let targetFixture = vcLkFixtures[0];
|
|
4580
|
-
|
|
4581
|
-
// Check if first fixture should be skipped
|
|
4582
|
-
const hasSaleOrAlmostGone =
|
|
4583
|
-
checkVmExistInFixtures( [ targetFixture ], 'All Styles at Rs 800' ) ||
|
|
4584
|
-
checkVmExistInFixtures( [ targetFixture ], 'Almost Gone' ) ||
|
|
4585
|
-
checkBrandExistInShelves( [ targetFixture ], 'discounted' );
|
|
4586
|
-
|
|
4587
|
-
// Check if Mid Zone is allocated to Hustlr VM or Phonic Full VM
|
|
4588
|
-
const firstFixtureMidShelves = targetFixture.shelfConfig?.filter( ( shelf ) => shelf.zone === 'Mid' ) || [];
|
|
4589
|
-
const firstFixtureMidShelfNumbers = new Set( firstFixtureMidShelves.map( ( shelf ) => shelf.shelfNumber ) );
|
|
4590
|
-
const midZoneVms = targetFixture.vmConfig?.filter( ( vm ) => firstFixtureMidShelfNumbers.has( vm.startYPosition ) ) || [];
|
|
4591
|
-
const hasHustlrOrPhonicInMid = midZoneVms.some( ( vm ) => {
|
|
4592
|
-
const normalizedVm = vm.vmName?.replace( /\s+/g, '' ).toLowerCase() || '';
|
|
4593
|
-
return normalizedVm.includes( 'hustlr' ) || normalizedVm.includes( 'phonic' );
|
|
4594
|
-
} );
|
|
4595
|
-
|
|
4596
|
-
const shouldSkipFirst = hasSaleOrAlmostGone || hasHustlrOrPhonicInMid ||
|
|
4597
|
-
checkVmExistInFixtures( [ targetFixture ], 'Hustlr' ) ||
|
|
4598
|
-
checkVmExistInFixtures( [ targetFixture ], 'Phonic' ) ||
|
|
4599
|
-
checkVmExistInFixtures( [ targetFixture ], 'Phonic Full VM' );
|
|
4600
|
-
|
|
4601
|
-
if ( shouldSkipFirst && vcLkFixtures.length > 1 ) {
|
|
4602
|
-
targetFixture = vcLkFixtures[1];
|
|
4603
|
-
}
|
|
4604
|
-
|
|
4605
|
-
if ( !targetFixture ) {
|
|
4606
|
-
const logData = {
|
|
4607
|
-
store: store?.['Store Code'],
|
|
4608
|
-
condition: store?.['Placement'],
|
|
4609
|
-
exception: store?.['Exceptions'],
|
|
4610
|
-
};
|
|
4611
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4612
|
-
return;
|
|
4613
|
-
}
|
|
4614
|
-
|
|
4615
|
-
// Recalculate midShelves for the selected fixture (might be second fixture)
|
|
4616
|
-
const midShelves = targetFixture.shelfConfig?.filter( ( shelf ) => shelf.zone === 'Mid' ).sort( ( a, b ) => a.shelfNumber - b.shelfNumber );
|
|
4617
|
-
|
|
4618
|
-
if ( !midShelves || midShelves.length === 0 ) {
|
|
4619
|
-
const logData = {
|
|
4620
|
-
store: store?.['Store Code'],
|
|
4621
|
-
condition: store?.['Placement'],
|
|
4622
|
-
exception: store?.['Exceptions'],
|
|
4623
|
-
};
|
|
4624
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4625
|
-
return;
|
|
4626
|
-
}
|
|
4627
|
-
|
|
4628
|
-
const midShelfNumbers = new Set( midShelves.map( ( shelf ) => shelf.shelfNumber ) );
|
|
4629
|
-
const existingVms = targetFixture.vmConfig?.filter( ( vm ) => !midShelfNumbers.has( vm.startYPosition ) ) || [];
|
|
4630
|
-
|
|
4631
|
-
// Calculate middle shelf of mid shelves
|
|
4632
|
-
let midShelfNumber;
|
|
4633
|
-
if ( midShelves.length % 2 !== 0 ) {
|
|
4634
|
-
// Odd number of mid shelves: use the middle one
|
|
4635
|
-
midShelfNumber = midShelves[Math.floor( midShelves.length / 2 )].shelfNumber;
|
|
4636
|
-
} else {
|
|
4637
|
-
// Even number of mid shelves: use the lower middle one
|
|
4638
|
-
midShelfNumber = midShelves[midShelves.length / 2 - 1].shelfNumber;
|
|
4639
|
-
}
|
|
4640
|
-
|
|
4641
|
-
const kpopVmData = {
|
|
4642
|
-
vmName: 'KPOP (NuuN)',
|
|
4643
|
-
startYPosition: midShelfNumber,
|
|
4644
|
-
endYPosition: midShelfNumber,
|
|
4645
|
-
xZone: 'left',
|
|
4646
|
-
yZone: 'stretch',
|
|
4647
|
-
};
|
|
4648
|
-
|
|
4649
|
-
existingVms.push( kpopVmData );
|
|
4650
|
-
targetFixture.vmConfig = existingVms;
|
|
4651
|
-
|
|
4652
|
-
// Update productBrandName for mid zone shelves to "KPOP (NunN)"
|
|
4653
|
-
targetFixture.shelfConfig.forEach( ( shelf ) => {
|
|
4654
|
-
if ( shelf.zone === 'Mid' ) {
|
|
4655
|
-
shelf.productBrandName = [ 'KPOP (NunN)' ];
|
|
4656
|
-
}
|
|
4657
|
-
} );
|
|
4658
|
-
|
|
4659
|
-
await updateFixtures( [ targetFixture ] );
|
|
4660
|
-
}
|
|
4661
|
-
|
|
4662
|
-
// Handle IVM Top Masking: First Trending Fixtures
|
|
4663
|
-
// Exception: If first Fixture is Sale/Almost Gone then move to Second fixture
|
|
4664
|
-
async function handleIvmTopMasking( fixtures, store ) {
|
|
4665
|
-
let trendingFixtures = fixtures.filter( ( fixture ) =>
|
|
4666
|
-
fixture.header?.label === 'Trending' ||
|
|
4667
|
-
fixture.header?.label === 'Trending 1' ||
|
|
4668
|
-
fixture.header?.label === 'Trending 2' ||
|
|
4669
|
-
fixture.header?.label === 'Trending 3' ||
|
|
4670
|
-
fixture.header?.label === 'Trending 4' );
|
|
4671
|
-
|
|
4672
|
-
if ( trendingFixtures.length === 0 ) {
|
|
4673
|
-
const logData = {
|
|
4674
|
-
store: store?.['Store Code'],
|
|
4675
|
-
condition: store?.['Placement'],
|
|
4676
|
-
exception: store?.['Exceptions'],
|
|
4677
|
-
};
|
|
4678
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4679
|
-
return;
|
|
4680
|
-
}
|
|
4681
|
-
|
|
4682
|
-
let targetFixture = trendingFixtures[0];
|
|
4683
|
-
|
|
4684
|
-
// Check if first fixture should be skipped
|
|
4685
|
-
const shouldSkipFirst =
|
|
4686
|
-
checkVmExistInFixtures( [ targetFixture ], 'All Styles at Rs 800' ) ||
|
|
4687
|
-
checkVmExistInFixtures( [ targetFixture ], 'Almost Gone' ) ||
|
|
4688
|
-
checkBrandExistInShelves( [ targetFixture ], 'discounted' );
|
|
4689
|
-
|
|
4690
|
-
if ( shouldSkipFirst && trendingFixtures.length > 1 ) {
|
|
4691
|
-
targetFixture = trendingFixtures[1];
|
|
4692
|
-
}
|
|
4693
|
-
|
|
4694
|
-
if ( !targetFixture ) {
|
|
4695
|
-
const logData = {
|
|
4696
|
-
store: store?.['Store Code'],
|
|
4697
|
-
condition: store?.['Placement'],
|
|
4698
|
-
exception: store?.['Exceptions'],
|
|
4699
|
-
};
|
|
4700
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4701
|
-
return;
|
|
4702
|
-
}
|
|
4703
|
-
|
|
4704
|
-
const topShelves = targetFixture.shelfConfig?.filter( ( shelf ) => shelf.zone === 'Top' ).sort( ( a, b ) => a.shelfNumber - b.shelfNumber );
|
|
4705
|
-
|
|
4706
|
-
if ( !topShelves || topShelves.length === 0 ) {
|
|
4707
|
-
const logData = {
|
|
4708
|
-
store: store?.['Store Code'],
|
|
4709
|
-
condition: store?.['Placement'],
|
|
4710
|
-
exception: store?.['Exceptions'],
|
|
4711
|
-
};
|
|
4712
|
-
writeLog( logData, './data/kpop_nunn_update_fails.json' );
|
|
4713
|
-
return;
|
|
4714
|
-
}
|
|
4715
|
-
|
|
4716
|
-
const topShelfNumbers = new Set( topShelves.map( ( shelf ) => shelf.shelfNumber ) );
|
|
4717
|
-
const existingVms = targetFixture.vmConfig?.filter( ( vm ) => !topShelfNumbers.has( vm.startYPosition ) ) || [];
|
|
4718
|
-
|
|
4719
|
-
const topShelfNumber = topShelves[0].shelfNumber;
|
|
4720
|
-
const kpopVmData = {
|
|
4721
|
-
vmName: 'KPOP (NuuN)',
|
|
4722
|
-
startYPosition: topShelfNumber,
|
|
4723
|
-
endYPosition: topShelfNumber,
|
|
4724
|
-
xZone: 'stretch',
|
|
4725
|
-
yZone: 'stretch',
|
|
4726
|
-
};
|
|
4727
|
-
|
|
4728
|
-
existingVms.push( kpopVmData );
|
|
4729
|
-
targetFixture.vmConfig = existingVms;
|
|
4730
|
-
|
|
4731
|
-
// Update productBrandName for top zone shelves to "KPOP (NunN)"
|
|
4732
|
-
targetFixture.shelfConfig.forEach( ( shelf ) => {
|
|
4733
|
-
if ( shelf.zone === 'Top' ) {
|
|
4734
|
-
shelf.productBrandName = [ 'KPOP (NunN)' ];
|
|
4735
|
-
}
|
|
4736
|
-
} );
|
|
4737
|
-
|
|
4738
|
-
await updateFixtures( [ targetFixture ] );
|
|
4739
|
-
}
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
// Main processing loop
|
|
4743
|
-
for ( let i = 0; i < data.length; i++ ) {
|
|
4744
|
-
const store = data[i];
|
|
4745
|
-
if ( ![
|
|
4746
|
-
"LKST1414",
|
|
4747
|
-
"LKST986",
|
|
4748
|
-
"LKST1540",
|
|
4749
|
-
"LKST1060",
|
|
4750
|
-
"LKST1599",
|
|
4751
|
-
"LKST1454",
|
|
4752
|
-
"LKST1424",
|
|
4753
|
-
"LKST154",
|
|
4754
|
-
"LKST1025",
|
|
4755
|
-
"LKST1086",
|
|
4756
|
-
"LKST162",
|
|
4757
|
-
"LKST1043",
|
|
4758
|
-
"LKST1969",
|
|
4759
|
-
"LKST647",
|
|
4760
|
-
"LKST1384",
|
|
4761
|
-
"LKST788",
|
|
4762
|
-
"LKST994",
|
|
4763
|
-
"LKST1416",
|
|
4764
|
-
"LKST1161",
|
|
4765
|
-
"LKST214",
|
|
4766
|
-
"LKST246",
|
|
4767
|
-
"LKST1535",
|
|
4768
|
-
"ST200",
|
|
4769
|
-
"LKST127",
|
|
4770
|
-
"LKST782",
|
|
4771
|
-
"LKST110",
|
|
4772
|
-
"LKST1122",
|
|
4773
|
-
"LKST191",
|
|
4774
|
-
"LKST1084",
|
|
4775
|
-
"LKST993",
|
|
4776
|
-
"LKST739",
|
|
4777
|
-
"LKST1115",
|
|
4778
|
-
"LKST953",
|
|
4779
|
-
].includes( store?.['Store Code'] ) ) continue;
|
|
4780
|
-
const storePlano = await planoService.findOne( { storeName: store?.['Store Code'] } );
|
|
4781
|
-
|
|
4782
|
-
if ( !storePlano ) {
|
|
4783
|
-
console.log( `Planogram not found for store: ${store?.['Store Code']}` );
|
|
4784
|
-
continue;
|
|
4785
|
-
}
|
|
4786
|
-
|
|
4787
|
-
let storeFixtures = await getFixtures( { planoId: storePlano._id } );
|
|
4788
|
-
storeFixtures = sortFunc( storeFixtures );
|
|
4789
|
-
|
|
4790
|
-
const wallFixtures = storeFixtures.filter(
|
|
4791
|
-
( f ) => f.associatedElementType !== undefined && f.associatedElementNumber !== undefined,
|
|
4792
|
-
);
|
|
4793
|
-
|
|
4794
|
-
const floorFixtures = storeFixtures.filter(
|
|
4795
|
-
( f ) => f.associatedElementType === undefined && f.associatedElementNumber === undefined,
|
|
4796
|
-
);
|
|
4797
|
-
|
|
4798
|
-
const placement = store?.['Placement'];
|
|
4799
|
-
|
|
4800
|
-
// Use only Placement column to determine handler
|
|
4801
|
-
if ( placement === 'First Tentpole Euro Centers' ) {
|
|
4802
|
-
await handleTentpoleEuroCenters( floorFixtures, store );
|
|
4803
|
-
} else if ( placement === 'First VC Eye+LK Air Eye Fixtures-Mid Zone' ) {
|
|
4804
|
-
// This placement is used for both Non IVM Wall Talker and Wynk Store
|
|
4805
|
-
// Both have similar logic, using handleNonIvmWallTalker
|
|
4806
|
-
await handleNonIvmWallTalker( wallFixtures, store );
|
|
4807
|
-
} else if ( placement === 'First Trending Fixtures' ) {
|
|
4808
|
-
// This placement is used for both IVM Top Masking and Mega Store
|
|
4809
|
-
// Both have similar logic, using handleIvmTopMasking
|
|
4810
|
-
await handleIvmTopMasking( wallFixtures, store );
|
|
4811
|
-
}
|
|
4812
|
-
|
|
4813
|
-
console.log( `Processed store: ${store?.['Store Code']}` );
|
|
4814
|
-
}
|
|
4815
|
-
|
|
4816
|
-
console.log( 'KPOP (NunN) collection update completed' );
|
|
4817
|
-
}
|
|
4818
|
-
|
|
4819
|
-
// updateKpopNunNCollection();
|
|
4820
|
-
|
|
4821
|
-
|