@blackcode_sa/metaestetics-api 1.12.40 → 1.12.41

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/dist/index.js CHANGED
@@ -2337,7 +2337,7 @@ var AppointmentService = class extends BaseService {
2337
2337
  * @returns The updated appointment
2338
2338
  */
2339
2339
  async updateAppointment(appointmentId, data) {
2340
- var _a, _b;
2340
+ var _a, _b, _c, _d;
2341
2341
  try {
2342
2342
  console.log(`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`);
2343
2343
  if ((_a = data.metadata) == null ? void 0 : _a.zonePhotos) {
@@ -2360,18 +2360,34 @@ var AppointmentService = class extends BaseService {
2360
2360
  }
2361
2361
  data.metadata.zonePhotos = migratedZonePhotos;
2362
2362
  }
2363
- if (((_b = data.metadata) == null ? void 0 : _b.recommendedProcedures) && Array.isArray(data.metadata.recommendedProcedures)) {
2364
- const validRecommendations = data.metadata.recommendedProcedures.filter(
2365
- (rec) => rec.note && typeof rec.note === "string" && rec.note.trim().length > 0
2366
- );
2363
+ console.log(
2364
+ "[APPOINTMENT_SERVICE] \u{1F50D} BEFORE CLEANUP - recommendedProcedures:",
2365
+ JSON.stringify((_b = data.metadata) == null ? void 0 : _b.recommendedProcedures, null, 2)
2366
+ );
2367
+ if (((_c = data.metadata) == null ? void 0 : _c.recommendedProcedures) && Array.isArray(data.metadata.recommendedProcedures)) {
2368
+ const validRecommendations = data.metadata.recommendedProcedures.filter((rec) => {
2369
+ const isValid = rec.note && typeof rec.note === "string" && rec.note.trim().length > 0;
2370
+ if (!isValid) {
2371
+ console.log("[APPOINTMENT_SERVICE] \u274C INVALID recommendation found:", rec);
2372
+ }
2373
+ return isValid;
2374
+ });
2367
2375
  if (validRecommendations.length !== data.metadata.recommendedProcedures.length) {
2368
2376
  console.log(
2369
- `[APPOINTMENT_SERVICE] Removing ${data.metadata.recommendedProcedures.length - validRecommendations.length} invalid recommended procedures with empty notes`
2377
+ `[APPOINTMENT_SERVICE] \u{1F9F9} Removing ${data.metadata.recommendedProcedures.length - validRecommendations.length} invalid recommended procedures with empty notes`
2370
2378
  );
2371
2379
  data.metadata.recommendedProcedures = validRecommendations;
2380
+ } else {
2381
+ console.log("[APPOINTMENT_SERVICE] \u2705 All recommendedProcedures are valid");
2372
2382
  }
2373
2383
  }
2384
+ console.log(
2385
+ "[APPOINTMENT_SERVICE] \u{1F50D} AFTER CLEANUP - recommendedProcedures:",
2386
+ JSON.stringify((_d = data.metadata) == null ? void 0 : _d.recommendedProcedures, null, 2)
2387
+ );
2388
+ console.log("[APPOINTMENT_SERVICE] \u{1F50D} Starting Zod validation...");
2374
2389
  const validatedData = await updateAppointmentSchema.parseAsync(data);
2390
+ console.log("[APPOINTMENT_SERVICE] \u2705 Zod validation passed!");
2375
2391
  const updatedAppointment = await updateAppointmentUtil(this.db, appointmentId, validatedData);
2376
2392
  console.log(`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`);
2377
2393
  return updatedAppointment;
@@ -18631,6 +18647,11 @@ var SubcategoryService = class extends BaseService {
18631
18647
 
18632
18648
  // src/backoffice/services/technology.service.ts
18633
18649
  var import_firestore61 = require("firebase/firestore");
18650
+
18651
+ // src/backoffice/types/product.types.ts
18652
+ var PRODUCTS_COLLECTION = "products";
18653
+
18654
+ // src/backoffice/services/technology.service.ts
18634
18655
  var DEFAULT_CERTIFICATION_REQUIREMENT = {
18635
18656
  minimumLevel: "aesthetician" /* AESTHETICIAN */,
18636
18657
  requiredSpecialties: []
@@ -19228,18 +19249,109 @@ var TechnologyService = class extends BaseService {
19228
19249
  })
19229
19250
  );
19230
19251
  }
19252
+ // ==========================================
19253
+ // NEW METHODS: Product assignment management
19254
+ // ==========================================
19255
+ /**
19256
+ * Assigns multiple products to a technology
19257
+ * Updates each product's assignedTechnologyIds array
19258
+ */
19259
+ async assignProducts(technologyId, productIds) {
19260
+ const batch = (0, import_firestore61.writeBatch)(this.db);
19261
+ for (const productId of productIds) {
19262
+ const productRef = (0, import_firestore61.doc)(this.db, PRODUCTS_COLLECTION, productId);
19263
+ batch.update(productRef, {
19264
+ assignedTechnologyIds: (0, import_firestore61.arrayUnion)(technologyId),
19265
+ updatedAt: /* @__PURE__ */ new Date()
19266
+ });
19267
+ }
19268
+ await batch.commit();
19269
+ }
19270
+ /**
19271
+ * Unassigns multiple products from a technology
19272
+ * Updates each product's assignedTechnologyIds array
19273
+ */
19274
+ async unassignProducts(technologyId, productIds) {
19275
+ const batch = (0, import_firestore61.writeBatch)(this.db);
19276
+ for (const productId of productIds) {
19277
+ const productRef = (0, import_firestore61.doc)(this.db, PRODUCTS_COLLECTION, productId);
19278
+ batch.update(productRef, {
19279
+ assignedTechnologyIds: (0, import_firestore61.arrayRemove)(technologyId),
19280
+ updatedAt: /* @__PURE__ */ new Date()
19281
+ });
19282
+ }
19283
+ await batch.commit();
19284
+ }
19285
+ /**
19286
+ * Gets products assigned to a specific technology
19287
+ * Reads from top-level collection for immediate consistency (Cloud Functions may lag)
19288
+ */
19289
+ async getAssignedProducts(technologyId) {
19290
+ const q = (0, import_firestore61.query)(
19291
+ (0, import_firestore61.collection)(this.db, PRODUCTS_COLLECTION),
19292
+ (0, import_firestore61.where)("assignedTechnologyIds", "array-contains", technologyId),
19293
+ (0, import_firestore61.where)("isActive", "==", true),
19294
+ (0, import_firestore61.orderBy)("name")
19295
+ );
19296
+ const snapshot = await (0, import_firestore61.getDocs)(q);
19297
+ return snapshot.docs.map(
19298
+ (doc44) => ({
19299
+ id: doc44.id,
19300
+ ...doc44.data()
19301
+ })
19302
+ );
19303
+ }
19304
+ /**
19305
+ * Gets products NOT assigned to a specific technology
19306
+ */
19307
+ async getUnassignedProducts(technologyId) {
19308
+ const q = (0, import_firestore61.query)(
19309
+ (0, import_firestore61.collection)(this.db, PRODUCTS_COLLECTION),
19310
+ (0, import_firestore61.where)("isActive", "==", true),
19311
+ (0, import_firestore61.orderBy)("name")
19312
+ );
19313
+ const snapshot = await (0, import_firestore61.getDocs)(q);
19314
+ const allProducts = snapshot.docs.map(
19315
+ (doc44) => ({
19316
+ id: doc44.id,
19317
+ ...doc44.data()
19318
+ })
19319
+ );
19320
+ return allProducts.filter(
19321
+ (product) => {
19322
+ var _a;
19323
+ return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
19324
+ }
19325
+ );
19326
+ }
19327
+ /**
19328
+ * Gets product assignment statistics for a technology
19329
+ */
19330
+ async getProductStats(technologyId) {
19331
+ const products = await this.getAssignedProducts(technologyId);
19332
+ const byBrand = {};
19333
+ products.forEach((product) => {
19334
+ byBrand[product.brandName] = (byBrand[product.brandName] || 0) + 1;
19335
+ });
19336
+ return {
19337
+ totalAssigned: products.length,
19338
+ byBrand
19339
+ };
19340
+ }
19231
19341
  };
19232
19342
 
19233
19343
  // src/backoffice/services/product.service.ts
19234
19344
  var import_firestore62 = require("firebase/firestore");
19235
-
19236
- // src/backoffice/types/product.types.ts
19237
- var PRODUCTS_COLLECTION = "products";
19238
-
19239
- // src/backoffice/services/product.service.ts
19240
19345
  var ProductService = class extends BaseService {
19241
19346
  /**
19242
- * Gets reference to products collection under a technology
19347
+ * Gets reference to top-level products collection (source of truth)
19348
+ * @returns Firestore collection reference
19349
+ */
19350
+ getTopLevelProductsRef() {
19351
+ return (0, import_firestore62.collection)(this.db, PRODUCTS_COLLECTION);
19352
+ }
19353
+ /**
19354
+ * Gets reference to products collection under a technology (backward compatibility)
19243
19355
  * @param technologyId - ID of the technology
19244
19356
  * @returns Firestore collection reference
19245
19357
  */
@@ -19255,6 +19367,7 @@ var ProductService = class extends BaseService {
19255
19367
  ...product,
19256
19368
  brandId,
19257
19369
  technologyId,
19370
+ // Required for old subcollection structure
19258
19371
  createdAt: now,
19259
19372
  updatedAt: now,
19260
19373
  isActive: true
@@ -19313,31 +19426,24 @@ var ProductService = class extends BaseService {
19313
19426
  return snapshot.data().count;
19314
19427
  }
19315
19428
  /**
19316
- * Gets counts of active products grouped by category, subcategory, and technology.
19317
- * This uses a single collectionGroup query for efficiency.
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.
19318
19432
  */
19319
19433
  async getProductCounts() {
19320
- const q = (0, import_firestore62.query)((0, import_firestore62.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore62.where)("isActive", "==", true));
19321
- const snapshot = await (0, import_firestore62.getDocs)(q);
19322
19434
  const counts = {
19323
19435
  byCategory: {},
19324
19436
  bySubcategory: {},
19325
19437
  byTechnology: {}
19326
19438
  };
19327
- if (snapshot.empty) {
19328
- return counts;
19329
- }
19439
+ const q = (0, import_firestore62.query)(this.getTopLevelProductsRef(), (0, import_firestore62.where)("isActive", "==", true));
19440
+ const snapshot = await (0, import_firestore62.getDocs)(q);
19330
19441
  snapshot.docs.forEach((doc44) => {
19331
19442
  const product = doc44.data();
19332
- const { categoryId, subcategoryId, technologyId } = product;
19333
- if (categoryId) {
19334
- counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
19335
- }
19336
- if (subcategoryId) {
19337
- counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
19338
- }
19339
- if (technologyId) {
19340
- counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
19443
+ if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
19444
+ product.assignedTechnologyIds.forEach((techId) => {
19445
+ counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
19446
+ });
19341
19447
  }
19342
19448
  });
19343
19449
  return counts;
@@ -19416,6 +19522,160 @@ var ProductService = class extends BaseService {
19416
19522
  ...docSnap.data()
19417
19523
  };
19418
19524
  }
19525
+ // ==========================================
19526
+ // NEW METHODS: Top-level collection (preferred)
19527
+ // ==========================================
19528
+ /**
19529
+ * Creates a new product in the top-level collection
19530
+ */
19531
+ async createTopLevel(brandId, product, technologyIds = []) {
19532
+ const now = /* @__PURE__ */ new Date();
19533
+ const newProduct = {
19534
+ ...product,
19535
+ brandId,
19536
+ assignedTechnologyIds: technologyIds,
19537
+ createdAt: now,
19538
+ updatedAt: now,
19539
+ isActive: true
19540
+ };
19541
+ const productRef = await (0, import_firestore62.addDoc)(this.getTopLevelProductsRef(), newProduct);
19542
+ return { id: productRef.id, ...newProduct };
19543
+ }
19544
+ /**
19545
+ * Gets all products from the top-level collection
19546
+ */
19547
+ async getAllTopLevel(options) {
19548
+ const { rowsPerPage, lastVisible, brandId } = options;
19549
+ const constraints = [(0, import_firestore62.where)("isActive", "==", true), (0, import_firestore62.orderBy)("name")];
19550
+ if (brandId) {
19551
+ constraints.push((0, import_firestore62.where)("brandId", "==", brandId));
19552
+ }
19553
+ if (lastVisible) {
19554
+ constraints.push((0, import_firestore62.startAfter)(lastVisible));
19555
+ }
19556
+ constraints.push((0, import_firestore62.limit)(rowsPerPage));
19557
+ const q = (0, import_firestore62.query)(this.getTopLevelProductsRef(), ...constraints);
19558
+ const snapshot = await (0, import_firestore62.getDocs)(q);
19559
+ const products = snapshot.docs.map(
19560
+ (doc44) => ({
19561
+ id: doc44.id,
19562
+ ...doc44.data()
19563
+ })
19564
+ );
19565
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
19566
+ return { products, lastVisible: newLastVisible };
19567
+ }
19568
+ /**
19569
+ * Gets a product by ID from the top-level collection
19570
+ */
19571
+ async getByIdTopLevel(productId) {
19572
+ const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
19573
+ const docSnap = await (0, import_firestore62.getDoc)(docRef);
19574
+ if (!docSnap.exists()) return null;
19575
+ return {
19576
+ id: docSnap.id,
19577
+ ...docSnap.data()
19578
+ };
19579
+ }
19580
+ /**
19581
+ * Updates a product in the top-level collection
19582
+ */
19583
+ async updateTopLevel(productId, product) {
19584
+ const updateData = {
19585
+ ...product,
19586
+ updatedAt: /* @__PURE__ */ new Date()
19587
+ };
19588
+ const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
19589
+ await (0, import_firestore62.updateDoc)(docRef, updateData);
19590
+ return this.getByIdTopLevel(productId);
19591
+ }
19592
+ /**
19593
+ * Deletes a product from the top-level collection (soft delete)
19594
+ */
19595
+ async deleteTopLevel(productId) {
19596
+ await this.updateTopLevel(productId, {
19597
+ isActive: false
19598
+ });
19599
+ }
19600
+ /**
19601
+ * Assigns a product to a technology
19602
+ */
19603
+ async assignToTechnology(productId, technologyId) {
19604
+ const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
19605
+ await (0, import_firestore62.updateDoc)(docRef, {
19606
+ assignedTechnologyIds: (0, import_firestore62.arrayUnion)(technologyId),
19607
+ updatedAt: /* @__PURE__ */ new Date()
19608
+ });
19609
+ }
19610
+ /**
19611
+ * Unassigns a product from a technology
19612
+ */
19613
+ async unassignFromTechnology(productId, technologyId) {
19614
+ const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
19615
+ await (0, import_firestore62.updateDoc)(docRef, {
19616
+ assignedTechnologyIds: (0, import_firestore62.arrayRemove)(technologyId),
19617
+ updatedAt: /* @__PURE__ */ new Date()
19618
+ });
19619
+ }
19620
+ /**
19621
+ * Gets products assigned to a specific technology
19622
+ */
19623
+ async getAssignedProducts(technologyId) {
19624
+ const q = (0, import_firestore62.query)(
19625
+ this.getTopLevelProductsRef(),
19626
+ (0, import_firestore62.where)("assignedTechnologyIds", "array-contains", technologyId),
19627
+ (0, import_firestore62.where)("isActive", "==", true),
19628
+ (0, import_firestore62.orderBy)("name")
19629
+ );
19630
+ const snapshot = await (0, import_firestore62.getDocs)(q);
19631
+ return snapshot.docs.map(
19632
+ (doc44) => ({
19633
+ id: doc44.id,
19634
+ ...doc44.data()
19635
+ })
19636
+ );
19637
+ }
19638
+ /**
19639
+ * Gets products NOT assigned to a specific technology
19640
+ */
19641
+ async getUnassignedProducts(technologyId) {
19642
+ const q = (0, import_firestore62.query)(
19643
+ this.getTopLevelProductsRef(),
19644
+ (0, import_firestore62.where)("isActive", "==", true),
19645
+ (0, import_firestore62.orderBy)("name")
19646
+ );
19647
+ const snapshot = await (0, import_firestore62.getDocs)(q);
19648
+ const allProducts = snapshot.docs.map(
19649
+ (doc44) => ({
19650
+ id: doc44.id,
19651
+ ...doc44.data()
19652
+ })
19653
+ );
19654
+ return allProducts.filter(
19655
+ (product) => {
19656
+ var _a;
19657
+ return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
19658
+ }
19659
+ );
19660
+ }
19661
+ /**
19662
+ * Gets all products for a brand (from top-level collection)
19663
+ */
19664
+ async getByBrand(brandId) {
19665
+ const q = (0, import_firestore62.query)(
19666
+ this.getTopLevelProductsRef(),
19667
+ (0, import_firestore62.where)("brandId", "==", brandId),
19668
+ (0, import_firestore62.where)("isActive", "==", true),
19669
+ (0, import_firestore62.orderBy)("name")
19670
+ );
19671
+ const snapshot = await (0, import_firestore62.getDocs)(q);
19672
+ return snapshot.docs.map(
19673
+ (doc44) => ({
19674
+ id: doc44.id,
19675
+ ...doc44.data()
19676
+ })
19677
+ );
19678
+ }
19419
19679
  };
19420
19680
 
19421
19681
  // src/backoffice/services/constants.service.ts