@blackcode_sa/metaestetics-api 1.12.40 → 1.12.42

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.
@@ -1193,7 +1193,14 @@ var TECHNOLOGIES_COLLECTION = "technologies";
1193
1193
  // src/backoffice/services/product.service.ts
1194
1194
  var ProductService = class extends BaseService {
1195
1195
  /**
1196
- * Gets reference to products collection under a technology
1196
+ * Gets reference to top-level products collection (source of truth)
1197
+ * @returns Firestore collection reference
1198
+ */
1199
+ getTopLevelProductsRef() {
1200
+ return (0, import_firestore8.collection)(this.db, PRODUCTS_COLLECTION);
1201
+ }
1202
+ /**
1203
+ * Gets reference to products collection under a technology (backward compatibility)
1197
1204
  * @param technologyId - ID of the technology
1198
1205
  * @returns Firestore collection reference
1199
1206
  */
@@ -1209,6 +1216,7 @@ var ProductService = class extends BaseService {
1209
1216
  ...product,
1210
1217
  brandId,
1211
1218
  technologyId,
1219
+ // Required for old subcollection structure
1212
1220
  createdAt: now,
1213
1221
  updatedAt: now,
1214
1222
  isActive: true
@@ -1268,30 +1276,26 @@ var ProductService = class extends BaseService {
1268
1276
  }
1269
1277
  /**
1270
1278
  * Gets counts of active products grouped by category, subcategory, and technology.
1271
- * This uses a single collectionGroup query for efficiency.
1279
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1272
1280
  */
1273
1281
  async getProductCounts() {
1274
- const q = (0, import_firestore8.query)((0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore8.where)("isActive", "==", true));
1275
- const snapshot = await (0, import_firestore8.getDocs)(q);
1276
1282
  const counts = {
1277
1283
  byCategory: {},
1278
1284
  bySubcategory: {},
1279
1285
  byTechnology: {}
1280
1286
  };
1281
- if (snapshot.empty) {
1282
- return counts;
1283
- }
1287
+ const q = (0, import_firestore8.query)((0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore8.where)("isActive", "==", true));
1288
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1284
1289
  snapshot.docs.forEach((doc11) => {
1285
1290
  const product = doc11.data();
1286
- const { categoryId, subcategoryId, technologyId } = product;
1287
- if (categoryId) {
1288
- counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
1291
+ if (product.categoryId) {
1292
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
1289
1293
  }
1290
- if (subcategoryId) {
1291
- counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
1294
+ if (product.subcategoryId) {
1295
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
1292
1296
  }
1293
- if (technologyId) {
1294
- counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
1297
+ if (product.technologyId) {
1298
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
1295
1299
  }
1296
1300
  });
1297
1301
  return counts;
@@ -1370,6 +1374,160 @@ var ProductService = class extends BaseService {
1370
1374
  ...docSnap.data()
1371
1375
  };
1372
1376
  }
1377
+ // ==========================================
1378
+ // NEW METHODS: Top-level collection (preferred)
1379
+ // ==========================================
1380
+ /**
1381
+ * Creates a new product in the top-level collection
1382
+ */
1383
+ async createTopLevel(brandId, product, technologyIds = []) {
1384
+ const now = /* @__PURE__ */ new Date();
1385
+ const newProduct = {
1386
+ ...product,
1387
+ brandId,
1388
+ assignedTechnologyIds: technologyIds,
1389
+ createdAt: now,
1390
+ updatedAt: now,
1391
+ isActive: true
1392
+ };
1393
+ const productRef = await (0, import_firestore8.addDoc)(this.getTopLevelProductsRef(), newProduct);
1394
+ return { id: productRef.id, ...newProduct };
1395
+ }
1396
+ /**
1397
+ * Gets all products from the top-level collection
1398
+ */
1399
+ async getAllTopLevel(options) {
1400
+ const { rowsPerPage, lastVisible, brandId } = options;
1401
+ const constraints = [(0, import_firestore8.where)("isActive", "==", true), (0, import_firestore8.orderBy)("name")];
1402
+ if (brandId) {
1403
+ constraints.push((0, import_firestore8.where)("brandId", "==", brandId));
1404
+ }
1405
+ if (lastVisible) {
1406
+ constraints.push((0, import_firestore8.startAfter)(lastVisible));
1407
+ }
1408
+ constraints.push((0, import_firestore8.limit)(rowsPerPage));
1409
+ const q = (0, import_firestore8.query)(this.getTopLevelProductsRef(), ...constraints);
1410
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1411
+ const products = snapshot.docs.map(
1412
+ (doc11) => ({
1413
+ id: doc11.id,
1414
+ ...doc11.data()
1415
+ })
1416
+ );
1417
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
1418
+ return { products, lastVisible: newLastVisible };
1419
+ }
1420
+ /**
1421
+ * Gets a product by ID from the top-level collection
1422
+ */
1423
+ async getByIdTopLevel(productId) {
1424
+ const docRef = (0, import_firestore8.doc)(this.getTopLevelProductsRef(), productId);
1425
+ const docSnap = await (0, import_firestore8.getDoc)(docRef);
1426
+ if (!docSnap.exists()) return null;
1427
+ return {
1428
+ id: docSnap.id,
1429
+ ...docSnap.data()
1430
+ };
1431
+ }
1432
+ /**
1433
+ * Updates a product in the top-level collection
1434
+ */
1435
+ async updateTopLevel(productId, product) {
1436
+ const updateData = {
1437
+ ...product,
1438
+ updatedAt: /* @__PURE__ */ new Date()
1439
+ };
1440
+ const docRef = (0, import_firestore8.doc)(this.getTopLevelProductsRef(), productId);
1441
+ await (0, import_firestore8.updateDoc)(docRef, updateData);
1442
+ return this.getByIdTopLevel(productId);
1443
+ }
1444
+ /**
1445
+ * Deletes a product from the top-level collection (soft delete)
1446
+ */
1447
+ async deleteTopLevel(productId) {
1448
+ await this.updateTopLevel(productId, {
1449
+ isActive: false
1450
+ });
1451
+ }
1452
+ /**
1453
+ * Assigns a product to a technology
1454
+ */
1455
+ async assignToTechnology(productId, technologyId) {
1456
+ const docRef = (0, import_firestore8.doc)(this.getTopLevelProductsRef(), productId);
1457
+ await (0, import_firestore8.updateDoc)(docRef, {
1458
+ assignedTechnologyIds: (0, import_firestore8.arrayUnion)(technologyId),
1459
+ updatedAt: /* @__PURE__ */ new Date()
1460
+ });
1461
+ }
1462
+ /**
1463
+ * Unassigns a product from a technology
1464
+ */
1465
+ async unassignFromTechnology(productId, technologyId) {
1466
+ const docRef = (0, import_firestore8.doc)(this.getTopLevelProductsRef(), productId);
1467
+ await (0, import_firestore8.updateDoc)(docRef, {
1468
+ assignedTechnologyIds: (0, import_firestore8.arrayRemove)(technologyId),
1469
+ updatedAt: /* @__PURE__ */ new Date()
1470
+ });
1471
+ }
1472
+ /**
1473
+ * Gets products assigned to a specific technology
1474
+ */
1475
+ async getAssignedProducts(technologyId) {
1476
+ const q = (0, import_firestore8.query)(
1477
+ this.getTopLevelProductsRef(),
1478
+ (0, import_firestore8.where)("assignedTechnologyIds", "array-contains", technologyId),
1479
+ (0, import_firestore8.where)("isActive", "==", true),
1480
+ (0, import_firestore8.orderBy)("name")
1481
+ );
1482
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1483
+ return snapshot.docs.map(
1484
+ (doc11) => ({
1485
+ id: doc11.id,
1486
+ ...doc11.data()
1487
+ })
1488
+ );
1489
+ }
1490
+ /**
1491
+ * Gets products NOT assigned to a specific technology
1492
+ */
1493
+ async getUnassignedProducts(technologyId) {
1494
+ const q = (0, import_firestore8.query)(
1495
+ this.getTopLevelProductsRef(),
1496
+ (0, import_firestore8.where)("isActive", "==", true),
1497
+ (0, import_firestore8.orderBy)("name")
1498
+ );
1499
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1500
+ const allProducts = snapshot.docs.map(
1501
+ (doc11) => ({
1502
+ id: doc11.id,
1503
+ ...doc11.data()
1504
+ })
1505
+ );
1506
+ return allProducts.filter(
1507
+ (product) => {
1508
+ var _a;
1509
+ return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
1510
+ }
1511
+ );
1512
+ }
1513
+ /**
1514
+ * Gets all products for a brand (from top-level collection)
1515
+ */
1516
+ async getByBrand(brandId) {
1517
+ const q = (0, import_firestore8.query)(
1518
+ this.getTopLevelProductsRef(),
1519
+ (0, import_firestore8.where)("brandId", "==", brandId),
1520
+ (0, import_firestore8.where)("isActive", "==", true),
1521
+ (0, import_firestore8.orderBy)("name")
1522
+ );
1523
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1524
+ return snapshot.docs.map(
1525
+ (doc11) => ({
1526
+ id: doc11.id,
1527
+ ...doc11.data()
1528
+ })
1529
+ );
1530
+ }
1373
1531
  };
1374
1532
 
1375
1533
  // src/backoffice/services/requirement.service.ts
@@ -1911,7 +2069,18 @@ var TechnologyService = class extends BaseService {
1911
2069
  });
1912
2070
  updateData.updatedAt = /* @__PURE__ */ new Date();
1913
2071
  const docRef = (0, import_firestore11.doc)(this.technologiesRef, id);
2072
+ const beforeTech = await this.getById(id);
1914
2073
  await (0, import_firestore11.updateDoc)(docRef, updateData);
2074
+ const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
2075
+ const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
2076
+ const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
2077
+ if (categoryChanged || subcategoryChanged || nameChanged) {
2078
+ await this.updateProductsInSubcollection(id, {
2079
+ categoryId: updateData.categoryId,
2080
+ subcategoryId: updateData.subcategoryId,
2081
+ technologyName: updateData.name
2082
+ });
2083
+ }
1915
2084
  return this.getById(id);
1916
2085
  }
1917
2086
  /**
@@ -2347,6 +2516,125 @@ var TechnologyService = class extends BaseService {
2347
2516
  })
2348
2517
  );
2349
2518
  }
2519
+ // ==========================================
2520
+ // NEW METHODS: Product assignment management
2521
+ // ==========================================
2522
+ /**
2523
+ * Assigns multiple products to a technology
2524
+ * Updates each product's assignedTechnologyIds array
2525
+ */
2526
+ async assignProducts(technologyId, productIds) {
2527
+ const batch = (0, import_firestore11.writeBatch)(this.db);
2528
+ for (const productId of productIds) {
2529
+ const productRef = (0, import_firestore11.doc)(this.db, PRODUCTS_COLLECTION, productId);
2530
+ batch.update(productRef, {
2531
+ assignedTechnologyIds: (0, import_firestore11.arrayUnion)(technologyId),
2532
+ updatedAt: /* @__PURE__ */ new Date()
2533
+ });
2534
+ }
2535
+ await batch.commit();
2536
+ }
2537
+ /**
2538
+ * Unassigns multiple products from a technology
2539
+ * Updates each product's assignedTechnologyIds array
2540
+ */
2541
+ async unassignProducts(technologyId, productIds) {
2542
+ const batch = (0, import_firestore11.writeBatch)(this.db);
2543
+ for (const productId of productIds) {
2544
+ const productRef = (0, import_firestore11.doc)(this.db, PRODUCTS_COLLECTION, productId);
2545
+ batch.update(productRef, {
2546
+ assignedTechnologyIds: (0, import_firestore11.arrayRemove)(technologyId),
2547
+ updatedAt: /* @__PURE__ */ new Date()
2548
+ });
2549
+ }
2550
+ await batch.commit();
2551
+ }
2552
+ /**
2553
+ * Gets products assigned to a specific technology
2554
+ * Reads from top-level collection for immediate consistency (Cloud Functions may lag)
2555
+ */
2556
+ async getAssignedProducts(technologyId) {
2557
+ const q = (0, import_firestore11.query)(
2558
+ (0, import_firestore11.collection)(this.db, PRODUCTS_COLLECTION),
2559
+ (0, import_firestore11.where)("assignedTechnologyIds", "array-contains", technologyId),
2560
+ (0, import_firestore11.where)("isActive", "==", true),
2561
+ (0, import_firestore11.orderBy)("name")
2562
+ );
2563
+ const snapshot = await (0, import_firestore11.getDocs)(q);
2564
+ return snapshot.docs.map(
2565
+ (doc11) => ({
2566
+ id: doc11.id,
2567
+ ...doc11.data()
2568
+ })
2569
+ );
2570
+ }
2571
+ /**
2572
+ * Gets products NOT assigned to a specific technology
2573
+ */
2574
+ async getUnassignedProducts(technologyId) {
2575
+ const q = (0, import_firestore11.query)(
2576
+ (0, import_firestore11.collection)(this.db, PRODUCTS_COLLECTION),
2577
+ (0, import_firestore11.where)("isActive", "==", true),
2578
+ (0, import_firestore11.orderBy)("name")
2579
+ );
2580
+ const snapshot = await (0, import_firestore11.getDocs)(q);
2581
+ const allProducts = snapshot.docs.map(
2582
+ (doc11) => ({
2583
+ id: doc11.id,
2584
+ ...doc11.data()
2585
+ })
2586
+ );
2587
+ return allProducts.filter(
2588
+ (product) => {
2589
+ var _a;
2590
+ return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
2591
+ }
2592
+ );
2593
+ }
2594
+ /**
2595
+ * Gets product assignment statistics for a technology
2596
+ */
2597
+ async getProductStats(technologyId) {
2598
+ const products = await this.getAssignedProducts(technologyId);
2599
+ const byBrand = {};
2600
+ products.forEach((product) => {
2601
+ byBrand[product.brandName] = (byBrand[product.brandName] || 0) + 1;
2602
+ });
2603
+ return {
2604
+ totalAssigned: products.length,
2605
+ byBrand
2606
+ };
2607
+ }
2608
+ /**
2609
+ * Updates products in technology subcollection when technology metadata changes
2610
+ * @param technologyId - ID of the technology
2611
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2612
+ */
2613
+ async updateProductsInSubcollection(technologyId, updates) {
2614
+ const productsRef = (0, import_firestore11.collection)(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
2615
+ const productsSnapshot = await (0, import_firestore11.getDocs)(productsRef);
2616
+ if (productsSnapshot.empty) {
2617
+ return;
2618
+ }
2619
+ const batch = (0, import_firestore11.writeBatch)(this.db);
2620
+ for (const productDoc of productsSnapshot.docs) {
2621
+ const productRef = productDoc.ref;
2622
+ const updateFields = {};
2623
+ if (updates.categoryId !== void 0) {
2624
+ updateFields.categoryId = updates.categoryId;
2625
+ }
2626
+ if (updates.subcategoryId !== void 0) {
2627
+ updateFields.subcategoryId = updates.subcategoryId;
2628
+ }
2629
+ if (updates.technologyName !== void 0) {
2630
+ updateFields.technologyName = updates.technologyName;
2631
+ }
2632
+ if (Object.keys(updateFields).length > 0) {
2633
+ batch.update(productRef, updateFields);
2634
+ }
2635
+ }
2636
+ await batch.commit();
2637
+ }
2350
2638
  };
2351
2639
 
2352
2640
  // src/backoffice/services/constants.service.ts