@blackcode_sa/metaestetics-api 1.12.41 → 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.
@@ -482,13 +482,13 @@ interface Product {
482
482
  composition?: string;
483
483
  indications?: string[];
484
484
  contraindications?: ContraindicationDynamic[];
485
- /** @deprecated Use assignedTechnologyIds instead */
485
+ /** Present only in subcollections - synced from technology metadata */
486
486
  technologyId?: string;
487
- /** @deprecated Will be removed in future version */
487
+ /** Present only in subcollections - synced from technology name */
488
488
  technologyName?: string;
489
- /** @deprecated Not needed in top-level collection */
489
+ /** Present only in subcollections - synced from technology categoryId */
490
490
  categoryId?: string;
491
- /** @deprecated Not needed in top-level collection */
491
+ /** Present only in subcollections - synced from technology subcategoryId */
492
492
  subcategoryId?: string;
493
493
  }
494
494
 
@@ -482,13 +482,13 @@ interface Product {
482
482
  composition?: string;
483
483
  indications?: string[];
484
484
  contraindications?: ContraindicationDynamic[];
485
- /** @deprecated Use assignedTechnologyIds instead */
485
+ /** Present only in subcollections - synced from technology metadata */
486
486
  technologyId?: string;
487
- /** @deprecated Will be removed in future version */
487
+ /** Present only in subcollections - synced from technology name */
488
488
  technologyName?: string;
489
- /** @deprecated Not needed in top-level collection */
489
+ /** Present only in subcollections - synced from technology categoryId */
490
490
  categoryId?: string;
491
- /** @deprecated Not needed in top-level collection */
491
+ /** Present only in subcollections - synced from technology subcategoryId */
492
492
  subcategoryId?: string;
493
493
  }
494
494
 
@@ -611,13 +611,13 @@ interface Product {
611
611
  composition?: string;
612
612
  indications?: string[];
613
613
  contraindications?: ContraindicationDynamic[];
614
- /** @deprecated Use assignedTechnologyIds instead */
614
+ /** Present only in subcollections - synced from technology metadata */
615
615
  technologyId?: string;
616
- /** @deprecated Will be removed in future version */
616
+ /** Present only in subcollections - synced from technology name */
617
617
  technologyName?: string;
618
- /** @deprecated Not needed in top-level collection */
618
+ /** Present only in subcollections - synced from technology categoryId */
619
619
  categoryId?: string;
620
- /** @deprecated Not needed in top-level collection */
620
+ /** Present only in subcollections - synced from technology subcategoryId */
621
621
  subcategoryId?: string;
622
622
  }
623
623
  /**
@@ -1585,9 +1585,8 @@ declare class ProductService extends BaseService implements IProductService {
1585
1585
  technologyId?: string;
1586
1586
  }): Promise<number>;
1587
1587
  /**
1588
- * Gets counts of active products grouped by technology.
1589
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1590
- * Categories/subcategories not available in top-level structure.
1588
+ * Gets counts of active products grouped by category, subcategory, and technology.
1589
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1591
1590
  */
1592
1591
  getProductCounts(): Promise<{
1593
1592
  byCategory: Record<string, number>;
@@ -2171,6 +2170,12 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
2171
2170
  totalAssigned: number;
2172
2171
  byBrand: Record<string, number>;
2173
2172
  }>;
2173
+ /**
2174
+ * Updates products in technology subcollection when technology metadata changes
2175
+ * @param technologyId - ID of the technology
2176
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2177
+ */
2178
+ private updateProductsInSubcollection;
2174
2179
  }
2175
2180
 
2176
2181
  /**
@@ -611,13 +611,13 @@ interface Product {
611
611
  composition?: string;
612
612
  indications?: string[];
613
613
  contraindications?: ContraindicationDynamic[];
614
- /** @deprecated Use assignedTechnologyIds instead */
614
+ /** Present only in subcollections - synced from technology metadata */
615
615
  technologyId?: string;
616
- /** @deprecated Will be removed in future version */
616
+ /** Present only in subcollections - synced from technology name */
617
617
  technologyName?: string;
618
- /** @deprecated Not needed in top-level collection */
618
+ /** Present only in subcollections - synced from technology categoryId */
619
619
  categoryId?: string;
620
- /** @deprecated Not needed in top-level collection */
620
+ /** Present only in subcollections - synced from technology subcategoryId */
621
621
  subcategoryId?: string;
622
622
  }
623
623
  /**
@@ -1585,9 +1585,8 @@ declare class ProductService extends BaseService implements IProductService {
1585
1585
  technologyId?: string;
1586
1586
  }): Promise<number>;
1587
1587
  /**
1588
- * Gets counts of active products grouped by technology.
1589
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1590
- * Categories/subcategories not available in top-level structure.
1588
+ * Gets counts of active products grouped by category, subcategory, and technology.
1589
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1591
1590
  */
1592
1591
  getProductCounts(): Promise<{
1593
1592
  byCategory: Record<string, number>;
@@ -2171,6 +2170,12 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
2171
2170
  totalAssigned: number;
2172
2171
  byBrand: Record<string, number>;
2173
2172
  }>;
2173
+ /**
2174
+ * Updates products in technology subcollection when technology metadata changes
2175
+ * @param technologyId - ID of the technology
2176
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2177
+ */
2178
+ private updateProductsInSubcollection;
2174
2179
  }
2175
2180
 
2176
2181
  /**
@@ -1275,9 +1275,8 @@ var ProductService = class extends BaseService {
1275
1275
  return snapshot.data().count;
1276
1276
  }
1277
1277
  /**
1278
- * Gets counts of active products grouped by technology.
1279
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1280
- * Categories/subcategories not available in top-level structure.
1278
+ * Gets counts of active products grouped by category, subcategory, and technology.
1279
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1281
1280
  */
1282
1281
  async getProductCounts() {
1283
1282
  const counts = {
@@ -1285,14 +1284,18 @@ var ProductService = class extends BaseService {
1285
1284
  bySubcategory: {},
1286
1285
  byTechnology: {}
1287
1286
  };
1288
- const q = (0, import_firestore8.query)(this.getTopLevelProductsRef(), (0, import_firestore8.where)("isActive", "==", true));
1287
+ const q = (0, import_firestore8.query)((0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore8.where)("isActive", "==", true));
1289
1288
  const snapshot = await (0, import_firestore8.getDocs)(q);
1290
1289
  snapshot.docs.forEach((doc11) => {
1291
1290
  const product = doc11.data();
1292
- if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
1293
- product.assignedTechnologyIds.forEach((techId) => {
1294
- counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
1295
- });
1291
+ if (product.categoryId) {
1292
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
1293
+ }
1294
+ if (product.subcategoryId) {
1295
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
1296
+ }
1297
+ if (product.technologyId) {
1298
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
1296
1299
  }
1297
1300
  });
1298
1301
  return counts;
@@ -2066,7 +2069,18 @@ var TechnologyService = class extends BaseService {
2066
2069
  });
2067
2070
  updateData.updatedAt = /* @__PURE__ */ new Date();
2068
2071
  const docRef = (0, import_firestore11.doc)(this.technologiesRef, id);
2072
+ const beforeTech = await this.getById(id);
2069
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
+ }
2070
2084
  return this.getById(id);
2071
2085
  }
2072
2086
  /**
@@ -2591,6 +2605,36 @@ var TechnologyService = class extends BaseService {
2591
2605
  byBrand
2592
2606
  };
2593
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
+ }
2594
2638
  };
2595
2639
 
2596
2640
  // src/backoffice/services/constants.service.ts
@@ -1254,9 +1254,8 @@ var ProductService = class extends BaseService {
1254
1254
  return snapshot.data().count;
1255
1255
  }
1256
1256
  /**
1257
- * Gets counts of active products grouped by technology.
1258
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1259
- * Categories/subcategories not available in top-level structure.
1257
+ * Gets counts of active products grouped by category, subcategory, and technology.
1258
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1260
1259
  */
1261
1260
  async getProductCounts() {
1262
1261
  const counts = {
@@ -1264,14 +1263,18 @@ var ProductService = class extends BaseService {
1264
1263
  bySubcategory: {},
1265
1264
  byTechnology: {}
1266
1265
  };
1267
- const q = query6(this.getTopLevelProductsRef(), where6("isActive", "==", true));
1266
+ const q = query6(collectionGroup(this.db, PRODUCTS_COLLECTION), where6("isActive", "==", true));
1268
1267
  const snapshot = await getDocs6(q);
1269
1268
  snapshot.docs.forEach((doc11) => {
1270
1269
  const product = doc11.data();
1271
- if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
1272
- product.assignedTechnologyIds.forEach((techId) => {
1273
- counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
1274
- });
1270
+ if (product.categoryId) {
1271
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
1272
+ }
1273
+ if (product.subcategoryId) {
1274
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
1275
+ }
1276
+ if (product.technologyId) {
1277
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
1275
1278
  }
1276
1279
  });
1277
1280
  return counts;
@@ -2085,7 +2088,18 @@ var TechnologyService = class extends BaseService {
2085
2088
  });
2086
2089
  updateData.updatedAt = /* @__PURE__ */ new Date();
2087
2090
  const docRef = doc9(this.technologiesRef, id);
2091
+ const beforeTech = await this.getById(id);
2088
2092
  await updateDoc9(docRef, updateData);
2093
+ const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
2094
+ const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
2095
+ const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
2096
+ if (categoryChanged || subcategoryChanged || nameChanged) {
2097
+ await this.updateProductsInSubcollection(id, {
2098
+ categoryId: updateData.categoryId,
2099
+ subcategoryId: updateData.subcategoryId,
2100
+ technologyName: updateData.name
2101
+ });
2102
+ }
2089
2103
  return this.getById(id);
2090
2104
  }
2091
2105
  /**
@@ -2610,6 +2624,36 @@ var TechnologyService = class extends BaseService {
2610
2624
  byBrand
2611
2625
  };
2612
2626
  }
2627
+ /**
2628
+ * Updates products in technology subcollection when technology metadata changes
2629
+ * @param technologyId - ID of the technology
2630
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2631
+ */
2632
+ async updateProductsInSubcollection(technologyId, updates) {
2633
+ const productsRef = collection9(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
2634
+ const productsSnapshot = await getDocs9(productsRef);
2635
+ if (productsSnapshot.empty) {
2636
+ return;
2637
+ }
2638
+ const batch = writeBatch(this.db);
2639
+ for (const productDoc of productsSnapshot.docs) {
2640
+ const productRef = productDoc.ref;
2641
+ const updateFields = {};
2642
+ if (updates.categoryId !== void 0) {
2643
+ updateFields.categoryId = updates.categoryId;
2644
+ }
2645
+ if (updates.subcategoryId !== void 0) {
2646
+ updateFields.subcategoryId = updates.subcategoryId;
2647
+ }
2648
+ if (updates.technologyName !== void 0) {
2649
+ updateFields.technologyName = updates.technologyName;
2650
+ }
2651
+ if (Object.keys(updateFields).length > 0) {
2652
+ batch.update(productRef, updateFields);
2653
+ }
2654
+ }
2655
+ await batch.commit();
2656
+ }
2613
2657
  };
2614
2658
 
2615
2659
  // src/backoffice/services/constants.service.ts
package/dist/index.d.mts CHANGED
@@ -595,13 +595,13 @@ interface Product {
595
595
  composition?: string;
596
596
  indications?: string[];
597
597
  contraindications?: ContraindicationDynamic[];
598
- /** @deprecated Use assignedTechnologyIds instead */
598
+ /** Present only in subcollections - synced from technology metadata */
599
599
  technologyId?: string;
600
- /** @deprecated Will be removed in future version */
600
+ /** Present only in subcollections - synced from technology name */
601
601
  technologyName?: string;
602
- /** @deprecated Not needed in top-level collection */
602
+ /** Present only in subcollections - synced from technology categoryId */
603
603
  categoryId?: string;
604
- /** @deprecated Not needed in top-level collection */
604
+ /** Present only in subcollections - synced from technology subcategoryId */
605
605
  subcategoryId?: string;
606
606
  }
607
607
  /**
@@ -1597,9 +1597,8 @@ declare class ProductService extends BaseService implements IProductService {
1597
1597
  technologyId?: string;
1598
1598
  }): Promise<number>;
1599
1599
  /**
1600
- * Gets counts of active products grouped by technology.
1601
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1602
- * Categories/subcategories not available in top-level structure.
1600
+ * Gets counts of active products grouped by category, subcategory, and technology.
1601
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1603
1602
  */
1604
1603
  getProductCounts(): Promise<{
1605
1604
  byCategory: Record<string, number>;
@@ -2404,6 +2403,12 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
2404
2403
  totalAssigned: number;
2405
2404
  byBrand: Record<string, number>;
2406
2405
  }>;
2406
+ /**
2407
+ * Updates products in technology subcollection when technology metadata changes
2408
+ * @param technologyId - ID of the technology
2409
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2410
+ */
2411
+ private updateProductsInSubcollection;
2407
2412
  }
2408
2413
 
2409
2414
  /**
package/dist/index.d.ts CHANGED
@@ -595,13 +595,13 @@ interface Product {
595
595
  composition?: string;
596
596
  indications?: string[];
597
597
  contraindications?: ContraindicationDynamic[];
598
- /** @deprecated Use assignedTechnologyIds instead */
598
+ /** Present only in subcollections - synced from technology metadata */
599
599
  technologyId?: string;
600
- /** @deprecated Will be removed in future version */
600
+ /** Present only in subcollections - synced from technology name */
601
601
  technologyName?: string;
602
- /** @deprecated Not needed in top-level collection */
602
+ /** Present only in subcollections - synced from technology categoryId */
603
603
  categoryId?: string;
604
- /** @deprecated Not needed in top-level collection */
604
+ /** Present only in subcollections - synced from technology subcategoryId */
605
605
  subcategoryId?: string;
606
606
  }
607
607
  /**
@@ -1597,9 +1597,8 @@ declare class ProductService extends BaseService implements IProductService {
1597
1597
  technologyId?: string;
1598
1598
  }): Promise<number>;
1599
1599
  /**
1600
- * Gets counts of active products grouped by technology.
1601
- * NOTE: Only counts top-level collection to avoid duplication during migration.
1602
- * Categories/subcategories not available in top-level structure.
1600
+ * Gets counts of active products grouped by category, subcategory, and technology.
1601
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1603
1602
  */
1604
1603
  getProductCounts(): Promise<{
1605
1604
  byCategory: Record<string, number>;
@@ -2404,6 +2403,12 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
2404
2403
  totalAssigned: number;
2405
2404
  byBrand: Record<string, number>;
2406
2405
  }>;
2406
+ /**
2407
+ * Updates products in technology subcollection when technology metadata changes
2408
+ * @param technologyId - ID of the technology
2409
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2410
+ */
2411
+ private updateProductsInSubcollection;
2407
2412
  }
2408
2413
 
2409
2414
  /**
package/dist/index.js CHANGED
@@ -18813,7 +18813,18 @@ var TechnologyService = class extends BaseService {
18813
18813
  });
18814
18814
  updateData.updatedAt = /* @__PURE__ */ new Date();
18815
18815
  const docRef = (0, import_firestore61.doc)(this.technologiesRef, id);
18816
+ const beforeTech = await this.getById(id);
18816
18817
  await (0, import_firestore61.updateDoc)(docRef, updateData);
18818
+ const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
18819
+ const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
18820
+ const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
18821
+ if (categoryChanged || subcategoryChanged || nameChanged) {
18822
+ await this.updateProductsInSubcollection(id, {
18823
+ categoryId: updateData.categoryId,
18824
+ subcategoryId: updateData.subcategoryId,
18825
+ technologyName: updateData.name
18826
+ });
18827
+ }
18817
18828
  return this.getById(id);
18818
18829
  }
18819
18830
  /**
@@ -19338,6 +19349,36 @@ var TechnologyService = class extends BaseService {
19338
19349
  byBrand
19339
19350
  };
19340
19351
  }
19352
+ /**
19353
+ * Updates products in technology subcollection when technology metadata changes
19354
+ * @param technologyId - ID of the technology
19355
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
19356
+ */
19357
+ async updateProductsInSubcollection(technologyId, updates) {
19358
+ const productsRef = (0, import_firestore61.collection)(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
19359
+ const productsSnapshot = await (0, import_firestore61.getDocs)(productsRef);
19360
+ if (productsSnapshot.empty) {
19361
+ return;
19362
+ }
19363
+ const batch = (0, import_firestore61.writeBatch)(this.db);
19364
+ for (const productDoc of productsSnapshot.docs) {
19365
+ const productRef = productDoc.ref;
19366
+ const updateFields = {};
19367
+ if (updates.categoryId !== void 0) {
19368
+ updateFields.categoryId = updates.categoryId;
19369
+ }
19370
+ if (updates.subcategoryId !== void 0) {
19371
+ updateFields.subcategoryId = updates.subcategoryId;
19372
+ }
19373
+ if (updates.technologyName !== void 0) {
19374
+ updateFields.technologyName = updates.technologyName;
19375
+ }
19376
+ if (Object.keys(updateFields).length > 0) {
19377
+ batch.update(productRef, updateFields);
19378
+ }
19379
+ }
19380
+ await batch.commit();
19381
+ }
19341
19382
  };
19342
19383
 
19343
19384
  // src/backoffice/services/product.service.ts
@@ -19426,9 +19467,8 @@ var ProductService = class extends BaseService {
19426
19467
  return snapshot.data().count;
19427
19468
  }
19428
19469
  /**
19429
- * Gets counts of active products grouped by technology.
19430
- * NOTE: Only counts top-level collection to avoid duplication during migration.
19431
- * Categories/subcategories not available in top-level structure.
19470
+ * Gets counts of active products grouped by category, subcategory, and technology.
19471
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
19432
19472
  */
19433
19473
  async getProductCounts() {
19434
19474
  const counts = {
@@ -19436,14 +19476,18 @@ var ProductService = class extends BaseService {
19436
19476
  bySubcategory: {},
19437
19477
  byTechnology: {}
19438
19478
  };
19439
- const q = (0, import_firestore62.query)(this.getTopLevelProductsRef(), (0, import_firestore62.where)("isActive", "==", true));
19479
+ const q = (0, import_firestore62.query)((0, import_firestore62.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore62.where)("isActive", "==", true));
19440
19480
  const snapshot = await (0, import_firestore62.getDocs)(q);
19441
19481
  snapshot.docs.forEach((doc44) => {
19442
19482
  const product = doc44.data();
19443
- if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
19444
- product.assignedTechnologyIds.forEach((techId) => {
19445
- counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
19446
- });
19483
+ if (product.categoryId) {
19484
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
19485
+ }
19486
+ if (product.subcategoryId) {
19487
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
19488
+ }
19489
+ if (product.technologyId) {
19490
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
19447
19491
  }
19448
19492
  });
19449
19493
  return counts;
package/dist/index.mjs CHANGED
@@ -19128,7 +19128,18 @@ var TechnologyService = class extends BaseService {
19128
19128
  });
19129
19129
  updateData.updatedAt = /* @__PURE__ */ new Date();
19130
19130
  const docRef = doc41(this.technologiesRef, id);
19131
+ const beforeTech = await this.getById(id);
19131
19132
  await updateDoc38(docRef, updateData);
19133
+ const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
19134
+ const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
19135
+ const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
19136
+ if (categoryChanged || subcategoryChanged || nameChanged) {
19137
+ await this.updateProductsInSubcollection(id, {
19138
+ categoryId: updateData.categoryId,
19139
+ subcategoryId: updateData.subcategoryId,
19140
+ technologyName: updateData.name
19141
+ });
19142
+ }
19132
19143
  return this.getById(id);
19133
19144
  }
19134
19145
  /**
@@ -19653,6 +19664,36 @@ var TechnologyService = class extends BaseService {
19653
19664
  byBrand
19654
19665
  };
19655
19666
  }
19667
+ /**
19668
+ * Updates products in technology subcollection when technology metadata changes
19669
+ * @param technologyId - ID of the technology
19670
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
19671
+ */
19672
+ async updateProductsInSubcollection(technologyId, updates) {
19673
+ const productsRef = collection36(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
19674
+ const productsSnapshot = await getDocs36(productsRef);
19675
+ if (productsSnapshot.empty) {
19676
+ return;
19677
+ }
19678
+ const batch = writeBatch7(this.db);
19679
+ for (const productDoc of productsSnapshot.docs) {
19680
+ const productRef = productDoc.ref;
19681
+ const updateFields = {};
19682
+ if (updates.categoryId !== void 0) {
19683
+ updateFields.categoryId = updates.categoryId;
19684
+ }
19685
+ if (updates.subcategoryId !== void 0) {
19686
+ updateFields.subcategoryId = updates.subcategoryId;
19687
+ }
19688
+ if (updates.technologyName !== void 0) {
19689
+ updateFields.technologyName = updates.technologyName;
19690
+ }
19691
+ if (Object.keys(updateFields).length > 0) {
19692
+ batch.update(productRef, updateFields);
19693
+ }
19694
+ }
19695
+ await batch.commit();
19696
+ }
19656
19697
  };
19657
19698
 
19658
19699
  // src/backoffice/services/product.service.ts
@@ -19757,9 +19798,8 @@ var ProductService = class extends BaseService {
19757
19798
  return snapshot.data().count;
19758
19799
  }
19759
19800
  /**
19760
- * Gets counts of active products grouped by technology.
19761
- * NOTE: Only counts top-level collection to avoid duplication during migration.
19762
- * Categories/subcategories not available in top-level structure.
19801
+ * Gets counts of active products grouped by category, subcategory, and technology.
19802
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
19763
19803
  */
19764
19804
  async getProductCounts() {
19765
19805
  const counts = {
@@ -19767,14 +19807,18 @@ var ProductService = class extends BaseService {
19767
19807
  bySubcategory: {},
19768
19808
  byTechnology: {}
19769
19809
  };
19770
- const q = query37(this.getTopLevelProductsRef(), where37("isActive", "==", true));
19810
+ const q = query37(collectionGroup3(this.db, PRODUCTS_COLLECTION), where37("isActive", "==", true));
19771
19811
  const snapshot = await getDocs37(q);
19772
19812
  snapshot.docs.forEach((doc44) => {
19773
19813
  const product = doc44.data();
19774
- if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
19775
- product.assignedTechnologyIds.forEach((techId) => {
19776
- counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
19777
- });
19814
+ if (product.categoryId) {
19815
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
19816
+ }
19817
+ if (product.subcategoryId) {
19818
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
19819
+ }
19820
+ if (product.technologyId) {
19821
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
19778
19822
  }
19779
19823
  });
19780
19824
  return counts;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.12.41",
4
+ "version": "1.12.42",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -134,9 +134,8 @@ export class ProductService extends BaseService implements IProductService {
134
134
  }
135
135
 
136
136
  /**
137
- * Gets counts of active products grouped by technology.
138
- * NOTE: Only counts top-level collection to avoid duplication during migration.
139
- * Categories/subcategories not available in top-level structure.
137
+ * Gets counts of active products grouped by category, subcategory, and technology.
138
+ * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
140
139
  */
141
140
  async getProductCounts(): Promise<{
142
141
  byCategory: Record<string, number>;
@@ -149,18 +148,22 @@ export class ProductService extends BaseService implements IProductService {
149
148
  byTechnology: {} as Record<string, number>,
150
149
  };
151
150
 
152
- // Query top-level collection only (to avoid duplication during migration)
153
- const q = query(this.getTopLevelProductsRef(), where('isActive', '==', true));
151
+ // Query technology subcollections (which have synced legacy fields)
152
+ const q = query(collectionGroup(this.db, PRODUCTS_COLLECTION), where('isActive', '==', true));
154
153
  const snapshot = await getDocs(q);
155
154
 
156
155
  snapshot.docs.forEach(doc => {
157
156
  const product = doc.data() as Product;
158
157
 
159
- // Count by technology using assignedTechnologyIds
160
- if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
161
- product.assignedTechnologyIds.forEach(techId => {
162
- counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
163
- });
158
+ // Use legacy fields from subcollections
159
+ if (product.categoryId) {
160
+ counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
161
+ }
162
+ if (product.subcategoryId) {
163
+ counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
164
+ }
165
+ if (product.technologyId) {
166
+ counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
164
167
  }
165
168
  });
166
169
 
@@ -242,7 +242,25 @@ export class TechnologyService extends BaseService implements ITechnologyService
242
242
  updateData.updatedAt = new Date();
243
243
 
244
244
  const docRef = doc(this.technologiesRef, id);
245
+
246
+ // Get the technology before update to check what changed
247
+ const beforeTech = await this.getById(id);
248
+
245
249
  await updateDoc(docRef, updateData);
250
+
251
+ // If categoryId, subcategoryId, or name changed, update all products in subcollection
252
+ const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
253
+ const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
254
+ const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
255
+
256
+ if (categoryChanged || subcategoryChanged || nameChanged) {
257
+ await this.updateProductsInSubcollection(id, {
258
+ categoryId: updateData.categoryId,
259
+ subcategoryId: updateData.subcategoryId,
260
+ technologyName: updateData.name,
261
+ });
262
+ }
263
+
246
264
  return this.getById(id);
247
265
  }
248
266
 
@@ -889,4 +907,44 @@ export class TechnologyService extends BaseService implements ITechnologyService
889
907
  byBrand,
890
908
  };
891
909
  }
910
+
911
+ /**
912
+ * Updates products in technology subcollection when technology metadata changes
913
+ * @param technologyId - ID of the technology
914
+ * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
915
+ */
916
+ private async updateProductsInSubcollection(
917
+ technologyId: string,
918
+ updates: { categoryId?: string; subcategoryId?: string; technologyName?: string }
919
+ ): Promise<void> {
920
+ const productsRef = collection(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
921
+ const productsSnapshot = await getDocs(productsRef);
922
+
923
+ if (productsSnapshot.empty) {
924
+ return;
925
+ }
926
+
927
+ const batch = writeBatch(this.db);
928
+
929
+ for (const productDoc of productsSnapshot.docs) {
930
+ const productRef = productDoc.ref;
931
+ const updateFields: any = {};
932
+
933
+ if (updates.categoryId !== undefined) {
934
+ updateFields.categoryId = updates.categoryId;
935
+ }
936
+ if (updates.subcategoryId !== undefined) {
937
+ updateFields.subcategoryId = updates.subcategoryId;
938
+ }
939
+ if (updates.technologyName !== undefined) {
940
+ updateFields.technologyName = updates.technologyName;
941
+ }
942
+
943
+ if (Object.keys(updateFields).length > 0) {
944
+ batch.update(productRef, updateFields);
945
+ }
946
+ }
947
+
948
+ await batch.commit();
949
+ }
892
950
  }
@@ -41,15 +41,16 @@ export interface Product {
41
41
  indications?: string[];
42
42
  contraindications?: ContraindicationDynamic[];
43
43
 
44
- // DEPRECATED: Kept for backward compatibility with subcollection structure
45
- // These fields exist in old products in /technologies/{id}/products/
46
- /** @deprecated Use assignedTechnologyIds instead */
44
+ // LEGACY FIELDS: Only present in technology subcollections (/technologies/{id}/products/)
45
+ // These fields are synced by Cloud Functions for backward compatibility
46
+ // NOT stored in top-level /products collection
47
+ /** Present only in subcollections - synced from technology metadata */
47
48
  technologyId?: string;
48
- /** @deprecated Will be removed in future version */
49
+ /** Present only in subcollections - synced from technology name */
49
50
  technologyName?: string;
50
- /** @deprecated Not needed in top-level collection */
51
+ /** Present only in subcollections - synced from technology categoryId */
51
52
  categoryId?: string;
52
- /** @deprecated Not needed in top-level collection */
53
+ /** Present only in subcollections - synced from technology subcategoryId */
53
54
  subcategoryId?: string;
54
55
  }
55
56