@blackcode_sa/metaestetics-api 1.12.0 → 1.12.2

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.mjs CHANGED
@@ -6639,7 +6639,9 @@ var PractitionerService = class extends BaseService {
6639
6639
  throw new Error(`Practitioner ${practitionerId} not found`);
6640
6640
  }
6641
6641
  const currentPractitioner = practitionerDoc.data();
6642
- let processedData = { ...validData };
6642
+ let processedData = {
6643
+ ...validData
6644
+ };
6643
6645
  if (validData.basicInfo) {
6644
6646
  processedData.basicInfo = await this.processBasicInfo(
6645
6647
  validData.basicInfo,
@@ -6873,7 +6875,9 @@ var PractitionerService = class extends BaseService {
6873
6875
  */
6874
6876
  async getPractitionersByFilters(filters) {
6875
6877
  try {
6876
- console.log("[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies");
6878
+ console.log(
6879
+ "[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies"
6880
+ );
6877
6881
  if (filters.location && filters.radiusInKm) {
6878
6882
  console.log("[PRACTITIONER_SERVICE] Executing geo query:", {
6879
6883
  location: filters.location,
@@ -6881,14 +6885,19 @@ var PractitionerService = class extends BaseService {
6881
6885
  serviceName: "PractitionerService"
6882
6886
  });
6883
6887
  if (!filters.location.latitude || !filters.location.longitude) {
6884
- console.warn("[PRACTITIONER_SERVICE] Invalid location data:", filters.location);
6888
+ console.warn(
6889
+ "[PRACTITIONER_SERVICE] Invalid location data:",
6890
+ filters.location
6891
+ );
6885
6892
  filters.location = void 0;
6886
6893
  filters.radiusInKm = void 0;
6887
6894
  }
6888
6895
  }
6889
6896
  if (filters.nameSearch && filters.nameSearch.trim()) {
6890
6897
  try {
6891
- console.log("[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search");
6898
+ console.log(
6899
+ "[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search"
6900
+ );
6892
6901
  const searchTerm = filters.nameSearch.trim().toLowerCase();
6893
6902
  const constraints = [];
6894
6903
  if (!filters.includeDraftPractitioners) {
@@ -6908,11 +6917,18 @@ var PractitionerService = class extends BaseService {
6908
6917
  }
6909
6918
  }
6910
6919
  constraints.push(limit7(filters.pagination || 10));
6911
- const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6920
+ const q = query10(
6921
+ collection10(this.db, PRACTITIONERS_COLLECTION),
6922
+ ...constraints
6923
+ );
6912
6924
  const querySnapshot = await getDocs10(q);
6913
- const practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6925
+ const practitioners = querySnapshot.docs.map(
6926
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
6927
+ );
6914
6928
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6915
- console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
6929
+ console.log(
6930
+ `[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`
6931
+ );
6916
6932
  if (practitioners.length < (filters.pagination || 10)) {
6917
6933
  return { practitioners, lastDoc: null };
6918
6934
  }
@@ -6922,7 +6938,9 @@ var PractitionerService = class extends BaseService {
6922
6938
  }
6923
6939
  }
6924
6940
  try {
6925
- console.log("[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering");
6941
+ console.log(
6942
+ "[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering"
6943
+ );
6926
6944
  const constraints = [];
6927
6945
  if (!filters.includeDraftPractitioners) {
6928
6946
  constraints.push(where10("status", "==", "active" /* ACTIVE */));
@@ -6931,14 +6949,22 @@ var PractitionerService = class extends BaseService {
6931
6949
  if (filters.certifications && filters.certifications.length > 0) {
6932
6950
  const certificationsToMatch = filters.certifications;
6933
6951
  constraints.push(
6934
- where10("certification.specialties", "array-contains-any", certificationsToMatch)
6952
+ where10(
6953
+ "certification.specialties",
6954
+ "array-contains-any",
6955
+ certificationsToMatch
6956
+ )
6935
6957
  );
6936
6958
  }
6937
6959
  if (filters.minRating !== void 0) {
6938
- constraints.push(where10("reviewInfo.averageRating", ">=", filters.minRating));
6960
+ constraints.push(
6961
+ where10("reviewInfo.averageRating", ">=", filters.minRating)
6962
+ );
6939
6963
  }
6940
6964
  if (filters.maxRating !== void 0) {
6941
- constraints.push(where10("reviewInfo.averageRating", "<=", filters.maxRating));
6965
+ constraints.push(
6966
+ where10("reviewInfo.averageRating", "<=", filters.maxRating)
6967
+ );
6942
6968
  }
6943
6969
  constraints.push(orderBy4("createdAt", "desc"));
6944
6970
  if (filters.location && filters.radiusInKm) {
@@ -6955,9 +6981,14 @@ var PractitionerService = class extends BaseService {
6955
6981
  }
6956
6982
  constraints.push(limit7(filters.pagination || 10));
6957
6983
  }
6958
- const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6984
+ const q = query10(
6985
+ collection10(this.db, PRACTITIONERS_COLLECTION),
6986
+ ...constraints
6987
+ );
6959
6988
  const querySnapshot = await getDocs10(q);
6960
- let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6989
+ let practitioners = querySnapshot.docs.map(
6990
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
6991
+ );
6961
6992
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
6962
6993
  const location = filters.location;
6963
6994
  const radiusInKm = filters.radiusInKm;
@@ -6976,7 +7007,9 @@ var PractitionerService = class extends BaseService {
6976
7007
  }
6977
7008
  practitioners = this.applyInMemoryFilters(practitioners, filters);
6978
7009
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6979
- console.log(`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`);
7010
+ console.log(
7011
+ `[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`
7012
+ );
6980
7013
  if (practitioners.length < (filters.pagination || 10)) {
6981
7014
  return { practitioners, lastDoc: null };
6982
7015
  }
@@ -6985,18 +7018,27 @@ var PractitionerService = class extends BaseService {
6985
7018
  console.log("[PRACTITIONER_SERVICE] Strategy 2 failed:", error);
6986
7019
  }
6987
7020
  try {
6988
- console.log("[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback");
7021
+ console.log(
7022
+ "[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback"
7023
+ );
6989
7024
  const constraints = [
6990
7025
  where10("isActive", "==", true),
6991
7026
  orderBy4("createdAt", "desc"),
6992
7027
  limit7(filters.pagination || 10)
6993
7028
  ];
6994
- const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7029
+ const q = query10(
7030
+ collection10(this.db, PRACTITIONERS_COLLECTION),
7031
+ ...constraints
7032
+ );
6995
7033
  const querySnapshot = await getDocs10(q);
6996
- let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7034
+ let practitioners = querySnapshot.docs.map(
7035
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
7036
+ );
6997
7037
  practitioners = this.applyInMemoryFilters(practitioners, filters);
6998
7038
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6999
- console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
7039
+ console.log(
7040
+ `[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`
7041
+ );
7000
7042
  if (practitioners.length < (filters.pagination || 10)) {
7001
7043
  return { practitioners, lastDoc: null };
7002
7044
  }
@@ -7005,19 +7047,28 @@ var PractitionerService = class extends BaseService {
7005
7047
  console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
7006
7048
  }
7007
7049
  try {
7008
- console.log("[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback");
7050
+ console.log(
7051
+ "[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback"
7052
+ );
7009
7053
  const constraints = [
7010
7054
  where10("isActive", "==", true),
7011
7055
  where10("status", "==", "active" /* ACTIVE */),
7012
7056
  orderBy4("createdAt", "desc"),
7013
7057
  limit7(filters.pagination || 10)
7014
7058
  ];
7015
- const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7059
+ const q = query10(
7060
+ collection10(this.db, PRACTITIONERS_COLLECTION),
7061
+ ...constraints
7062
+ );
7016
7063
  const querySnapshot = await getDocs10(q);
7017
- let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7064
+ let practitioners = querySnapshot.docs.map(
7065
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
7066
+ );
7018
7067
  practitioners = this.applyInMemoryFilters(practitioners, filters);
7019
7068
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7020
- console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
7069
+ console.log(
7070
+ `[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`
7071
+ );
7021
7072
  if (practitioners.length < (filters.pagination || 10)) {
7022
7073
  return { practitioners, lastDoc: null };
7023
7074
  }
@@ -7025,10 +7076,15 @@ var PractitionerService = class extends BaseService {
7025
7076
  } catch (error) {
7026
7077
  console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
7027
7078
  }
7028
- console.log("[PRACTITIONER_SERVICE] All strategies failed, returning empty result");
7079
+ console.log(
7080
+ "[PRACTITIONER_SERVICE] All strategies failed, returning empty result"
7081
+ );
7029
7082
  return { practitioners: [], lastDoc: null };
7030
7083
  } catch (error) {
7031
- console.error("[PRACTITIONER_SERVICE] Error filtering practitioners:", error);
7084
+ console.error(
7085
+ "[PRACTITIONER_SERVICE] Error filtering practitioners:",
7086
+ error
7087
+ );
7032
7088
  return { practitioners: [], lastDoc: null };
7033
7089
  }
7034
7090
  }
@@ -7048,63 +7104,93 @@ var PractitionerService = class extends BaseService {
7048
7104
  const fullNameLower = practitioner.fullNameLower || "";
7049
7105
  return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
7050
7106
  });
7051
- console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`);
7107
+ console.log(
7108
+ `[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`
7109
+ );
7052
7110
  }
7053
7111
  if (filters.certifications && filters.certifications.length > 0) {
7054
7112
  const certificationsToMatch = filters.certifications;
7055
7113
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7056
7114
  var _a;
7057
7115
  const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
7058
- return certificationsToMatch.some((cert) => practitionerCerts.includes(cert));
7116
+ return certificationsToMatch.some(
7117
+ (cert) => practitionerCerts.includes(cert)
7118
+ );
7059
7119
  });
7060
- console.log(`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`);
7120
+ console.log(
7121
+ `[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`
7122
+ );
7061
7123
  }
7062
7124
  if (filters.specialties && filters.specialties.length > 0) {
7063
7125
  const specialtiesToMatch = filters.specialties;
7064
7126
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7065
7127
  var _a;
7066
7128
  const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
7067
- return specialtiesToMatch.some((spec) => practitionerSpecs.includes(spec));
7129
+ return specialtiesToMatch.some(
7130
+ (spec) => practitionerSpecs.includes(spec)
7131
+ );
7068
7132
  });
7069
- console.log(`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`);
7133
+ console.log(
7134
+ `[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`
7135
+ );
7070
7136
  }
7071
7137
  if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
7072
7138
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7073
7139
  var _a;
7074
7140
  const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
7075
- if (filters.minRating !== void 0 && rating < filters.minRating) return false;
7076
- if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
7141
+ if (filters.minRating !== void 0 && rating < filters.minRating)
7142
+ return false;
7143
+ if (filters.maxRating !== void 0 && rating > filters.maxRating)
7144
+ return false;
7077
7145
  return true;
7078
7146
  });
7079
- console.log(`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`);
7147
+ console.log(
7148
+ `[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`
7149
+ );
7080
7150
  }
7081
7151
  if (filters.procedureFamily) {
7082
7152
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7083
7153
  const proceduresInfo = practitioner.proceduresInfo || [];
7084
- return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
7154
+ return proceduresInfo.some(
7155
+ (proc) => proc.family === filters.procedureFamily
7156
+ );
7085
7157
  });
7086
- console.log(`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`);
7158
+ console.log(
7159
+ `[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`
7160
+ );
7087
7161
  }
7088
7162
  if (filters.procedureCategory) {
7089
7163
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7090
7164
  const proceduresInfo = practitioner.proceduresInfo || [];
7091
- return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
7165
+ return proceduresInfo.some(
7166
+ (proc) => proc.categoryName === filters.procedureCategory
7167
+ );
7092
7168
  });
7093
- console.log(`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`);
7169
+ console.log(
7170
+ `[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`
7171
+ );
7094
7172
  }
7095
7173
  if (filters.procedureSubcategory) {
7096
7174
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7097
7175
  const proceduresInfo = practitioner.proceduresInfo || [];
7098
- return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
7176
+ return proceduresInfo.some(
7177
+ (proc) => proc.subcategoryName === filters.procedureSubcategory
7178
+ );
7099
7179
  });
7100
- console.log(`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`);
7180
+ console.log(
7181
+ `[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`
7182
+ );
7101
7183
  }
7102
7184
  if (filters.procedureTechnology) {
7103
7185
  filteredPractitioners = filteredPractitioners.filter((practitioner) => {
7104
7186
  const proceduresInfo = practitioner.proceduresInfo || [];
7105
- return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
7187
+ return proceduresInfo.some(
7188
+ (proc) => proc.technologyName === filters.procedureTechnology
7189
+ );
7106
7190
  });
7107
- console.log(`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`);
7191
+ console.log(
7192
+ `[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`
7193
+ );
7108
7194
  }
7109
7195
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
7110
7196
  const location = filters.location;
@@ -7120,7 +7206,9 @@ var PractitionerService = class extends BaseService {
7120
7206
  return distanceInKm <= radiusInKm;
7121
7207
  });
7122
7208
  });
7123
- console.log(`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`);
7209
+ console.log(
7210
+ `[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`
7211
+ );
7124
7212
  }
7125
7213
  return filteredPractitioners;
7126
7214
  }
@@ -7185,6 +7273,15 @@ var PractitionerService = class extends BaseService {
7185
7273
  price: 0,
7186
7274
  currency: "EUR" /* EUR */,
7187
7275
  pricingMeasure: "per_session" /* PER_SESSION */,
7276
+ productsMetadata: [
7277
+ {
7278
+ productId: "free-consultation-product",
7279
+ price: 0,
7280
+ currency: "EUR" /* EUR */,
7281
+ pricingMeasure: "per_session" /* PER_SESSION */,
7282
+ isDefault: true
7283
+ }
7284
+ ],
7188
7285
  duration: 30,
7189
7286
  // 30 minutes consultation
7190
7287
  practitionerId,
@@ -14981,67 +15078,141 @@ import {
14981
15078
  } from "firebase/firestore";
14982
15079
 
14983
15080
  // src/validations/procedure.schema.ts
15081
+ import { z as z25 } from "zod";
15082
+
15083
+ // src/validations/procedure-product.schema.ts
14984
15084
  import { z as z24 } from "zod";
14985
- var createProcedureSchema = z24.object({
14986
- name: z24.string().min(1).max(200),
14987
- // Optional: service will derive from name if not provided by client
14988
- nameLower: z24.string().min(1).max(200).optional(),
14989
- description: z24.string().min(1).max(2e3),
14990
- family: z24.nativeEnum(ProcedureFamily),
14991
- categoryId: z24.string().min(1),
14992
- subcategoryId: z24.string().min(1),
14993
- technologyId: z24.string().min(1),
14994
- productId: z24.string().min(1),
14995
- price: z24.number().min(0),
15085
+ var procedureProductDataSchema = z24.object({
15086
+ /**
15087
+ * The ID of the product. Must be a non-empty string.
15088
+ * @validation
15089
+ */
15090
+ productId: z24.string().min(1, "Product ID is required"),
15091
+ /**
15092
+ * The price of the product. Must be a non-negative number.
15093
+ * @validation
15094
+ */
15095
+ price: z24.number().min(0, "Price must be a non-negative number"),
15096
+ /**
15097
+ * The currency for the price. Must be one of the values from the Currency enum.
15098
+ * @validation
15099
+ */
14996
15100
  currency: z24.nativeEnum(Currency),
15101
+ /**
15102
+ * The pricing measure for the product. Must be one of the values from the PricingMeasure enum.
15103
+ * @validation
15104
+ */
14997
15105
  pricingMeasure: z24.nativeEnum(PricingMeasure),
14998
- duration: z24.number().min(1).max(480),
15106
+ /**
15107
+ * Whether this is the default product for the procedure.
15108
+ * @validation
15109
+ */
15110
+ isDefault: z24.boolean().optional()
15111
+ });
15112
+
15113
+ // src/validations/procedure.schema.ts
15114
+ var storedProcedureProductSchema = z25.object({
15115
+ /**
15116
+ * The full product object used in the procedure.
15117
+ */
15118
+ product: z25.any(),
15119
+ // We'll validate the full product object separately
15120
+ /**
15121
+ * The price of the procedure when using this specific product.
15122
+ */
15123
+ price: z25.number().min(0, "Price must be a non-negative number"),
15124
+ /**
15125
+ * The currency for the price of this product.
15126
+ */
15127
+ currency: z25.nativeEnum(Currency),
15128
+ /**
15129
+ * How the price is measured (e.g., per ml, per zone).
15130
+ */
15131
+ pricingMeasure: z25.nativeEnum(PricingMeasure),
15132
+ /**
15133
+ * Whether this is the default product for the procedure.
15134
+ */
15135
+ isDefault: z25.boolean().optional()
15136
+ });
15137
+ var createProcedureSchema = z25.object({
15138
+ name: z25.string().min(1).max(200),
15139
+ // Optional: service will derive from name if not provided by client
15140
+ nameLower: z25.string().min(1).max(200).optional(),
15141
+ description: z25.string().min(1).max(2e3),
15142
+ family: z25.nativeEnum(ProcedureFamily),
15143
+ categoryId: z25.string().min(1),
15144
+ subcategoryId: z25.string().min(1),
15145
+ technologyId: z25.string().min(1),
15146
+ productId: z25.string().min(1),
15147
+ price: z25.number().min(0),
15148
+ currency: z25.nativeEnum(Currency),
15149
+ pricingMeasure: z25.nativeEnum(PricingMeasure),
15150
+ productsMetadata: z25.array(procedureProductDataSchema).min(1),
15151
+ duration: z25.number().min(1).max(480),
14999
15152
  // Max 8 hours
15000
- practitionerId: z24.string().min(1),
15001
- clinicBranchId: z24.string().min(1),
15002
- photos: z24.array(mediaResourceSchema).optional()
15153
+ practitionerId: z25.string().min(1),
15154
+ clinicBranchId: z25.string().min(1),
15155
+ photos: z25.array(mediaResourceSchema).optional()
15003
15156
  });
15004
- var updateProcedureSchema = z24.object({
15005
- name: z24.string().min(3).max(100).optional(),
15006
- nameLower: z24.string().min(1).max(200).optional(),
15007
- description: z24.string().min(3).max(1e3).optional(),
15008
- price: z24.number().min(0).optional(),
15009
- currency: z24.nativeEnum(Currency).optional(),
15010
- pricingMeasure: z24.nativeEnum(PricingMeasure).optional(),
15011
- duration: z24.number().min(0).optional(),
15012
- isActive: z24.boolean().optional(),
15013
- practitionerId: z24.string().optional(),
15014
- categoryId: z24.string().optional(),
15015
- subcategoryId: z24.string().optional(),
15016
- technologyId: z24.string().optional(),
15017
- productId: z24.string().optional(),
15018
- clinicBranchId: z24.string().optional(),
15019
- photos: z24.array(mediaResourceSchema).optional()
15157
+ var updateProcedureSchema = z25.object({
15158
+ name: z25.string().min(3).max(100).optional(),
15159
+ nameLower: z25.string().min(1).max(200).optional(),
15160
+ description: z25.string().min(3).max(1e3).optional(),
15161
+ price: z25.number().min(0).optional(),
15162
+ currency: z25.nativeEnum(Currency).optional(),
15163
+ pricingMeasure: z25.nativeEnum(PricingMeasure).optional(),
15164
+ productsMetadata: z25.array(procedureProductDataSchema).min(1).optional(),
15165
+ duration: z25.number().min(0).optional(),
15166
+ isActive: z25.boolean().optional(),
15167
+ practitionerId: z25.string().optional(),
15168
+ categoryId: z25.string().optional(),
15169
+ subcategoryId: z25.string().optional(),
15170
+ technologyId: z25.string().optional(),
15171
+ productId: z25.string().optional(),
15172
+ clinicBranchId: z25.string().optional(),
15173
+ photos: z25.array(mediaResourceSchema).optional()
15020
15174
  });
15021
- var procedureSchema = createProcedureSchema.extend({
15022
- id: z24.string().min(1),
15023
- nameLower: z24.string().min(1).max(200),
15024
- category: z24.any(),
15175
+ var procedureSchema = z25.object({
15176
+ id: z25.string().min(1),
15177
+ name: z25.string().min(1).max(200),
15178
+ nameLower: z25.string().min(1).max(200),
15179
+ description: z25.string().min(1).max(2e3),
15180
+ family: z25.nativeEnum(ProcedureFamily),
15181
+ category: z25.any(),
15025
15182
  // We'll validate the full category object separately
15026
- subcategory: z24.any(),
15183
+ subcategory: z25.any(),
15027
15184
  // We'll validate the full subcategory object separately
15028
- technology: z24.any(),
15185
+ technology: z25.any(),
15029
15186
  // We'll validate the full technology object separately
15030
- product: z24.any(),
15187
+ product: z25.any(),
15031
15188
  // We'll validate the full product object separately
15032
- blockingConditions: z24.array(z24.any()),
15189
+ productsMetadata: z25.array(storedProcedureProductSchema).min(1),
15190
+ // Use stored format schema
15191
+ price: z25.number().min(0),
15192
+ currency: z25.nativeEnum(Currency),
15193
+ pricingMeasure: z25.nativeEnum(PricingMeasure),
15194
+ duration: z25.number().min(1).max(480),
15195
+ practitionerId: z25.string().min(1),
15196
+ clinicBranchId: z25.string().min(1),
15197
+ photos: z25.array(z25.string()).optional(),
15198
+ // Stored as URL strings
15199
+ blockingConditions: z25.array(z25.any()),
15033
15200
  // We'll validate blocking conditions separately
15034
- contraindications: z24.array(z24.any()),
15201
+ contraindications: z25.array(z25.any()),
15035
15202
  // We'll validate contraindications separately
15036
- treatmentBenefits: z24.array(z24.any()),
15203
+ contraindicationIds: z25.array(z25.string()),
15204
+ // Array of IDs for efficient querying
15205
+ treatmentBenefits: z25.array(z25.any()),
15037
15206
  // We'll validate treatment benefits separately
15038
- preRequirements: z24.array(z24.any()),
15207
+ treatmentBenefitIds: z25.array(z25.string()),
15208
+ // Array of IDs for efficient querying
15209
+ preRequirements: z25.array(z25.any()),
15039
15210
  // We'll validate requirements separately
15040
- postRequirements: z24.array(z24.any()),
15211
+ postRequirements: z25.array(z25.any()),
15041
15212
  // We'll validate requirements separately
15042
- certificationRequirement: z24.any(),
15213
+ certificationRequirement: z25.any(),
15043
15214
  // We'll validate certification requirement separately
15044
- documentationTemplates: z24.array(z24.any()),
15215
+ documentationTemplates: z25.array(z25.any()),
15045
15216
  // We'll validate documentation templates separately
15046
15217
  clinicInfo: clinicInfoSchema,
15047
15218
  // Clinic info validation
@@ -15049,9 +15220,9 @@ var procedureSchema = createProcedureSchema.extend({
15049
15220
  // Doctor info validation
15050
15221
  reviewInfo: procedureReviewInfoSchema,
15051
15222
  // Procedure review info validation
15052
- isActive: z24.boolean(),
15053
- createdAt: z24.date(),
15054
- updatedAt: z24.date()
15223
+ isActive: z25.boolean(),
15224
+ createdAt: z25.date(),
15225
+ updatedAt: z25.date()
15055
15226
  });
15056
15227
 
15057
15228
  // src/services/procedure/procedure.service.ts
@@ -15078,9 +15249,7 @@ var ProcedureService = class extends BaseService {
15078
15249
  return media;
15079
15250
  }
15080
15251
  if (media instanceof File || media instanceof Blob) {
15081
- console.log(
15082
- `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
15083
- );
15252
+ console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
15084
15253
  const metadata = await this.mediaService.uploadMedia(
15085
15254
  media,
15086
15255
  ownerId,
@@ -15102,17 +15271,38 @@ var ProcedureService = class extends BaseService {
15102
15271
  if (!mediaArray || mediaArray.length === 0) return [];
15103
15272
  const result = [];
15104
15273
  for (const media of mediaArray) {
15105
- const processedUrl = await this.processMedia(
15106
- media,
15107
- ownerId,
15108
- collectionName
15109
- );
15274
+ const processedUrl = await this.processMedia(media, ownerId, collectionName);
15110
15275
  if (processedUrl) {
15111
15276
  result.push(processedUrl);
15112
15277
  }
15113
15278
  }
15114
15279
  return result;
15115
15280
  }
15281
+ /**
15282
+ * Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
15283
+ * @param productsMetadata Array of validated procedure product data
15284
+ * @param technologyId Technology ID to fetch products from
15285
+ * @returns Array of ProcedureProduct objects with full product information
15286
+ */
15287
+ async transformProductsMetadata(productsMetadata, technologyId) {
15288
+ const transformedProducts = [];
15289
+ for (const productData of productsMetadata) {
15290
+ const product = await this.productService.getById(technologyId, productData.productId);
15291
+ if (!product) {
15292
+ throw new Error(
15293
+ `Product with ID ${productData.productId} not found for technology ${technologyId}`
15294
+ );
15295
+ }
15296
+ transformedProducts.push({
15297
+ product,
15298
+ price: productData.price,
15299
+ currency: productData.currency,
15300
+ pricingMeasure: productData.pricingMeasure,
15301
+ isDefault: productData.isDefault
15302
+ });
15303
+ }
15304
+ return transformedProducts;
15305
+ }
15116
15306
  /**
15117
15307
  * Creates a new procedure
15118
15308
  * @param data - The data for creating a new procedure
@@ -15124,41 +15314,23 @@ var ProcedureService = class extends BaseService {
15124
15314
  const procedureId = this.generateId();
15125
15315
  const [category, subcategory, technology, product] = await Promise.all([
15126
15316
  this.categoryService.getById(validatedData.categoryId),
15127
- this.subcategoryService.getById(
15128
- validatedData.categoryId,
15129
- validatedData.subcategoryId
15130
- ),
15317
+ this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15131
15318
  this.technologyService.getById(validatedData.technologyId),
15132
- this.productService.getById(
15133
- validatedData.technologyId,
15134
- validatedData.productId
15135
- )
15319
+ this.productService.getById(validatedData.technologyId, validatedData.productId)
15136
15320
  ]);
15137
15321
  if (!category || !subcategory || !technology || !product) {
15138
15322
  throw new Error("One or more required base entities not found");
15139
15323
  }
15140
- const clinicRef = doc30(
15141
- this.db,
15142
- CLINICS_COLLECTION,
15143
- validatedData.clinicBranchId
15144
- );
15324
+ const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15145
15325
  const clinicSnapshot = await getDoc32(clinicRef);
15146
15326
  if (!clinicSnapshot.exists()) {
15147
- throw new Error(
15148
- `Clinic with ID ${validatedData.clinicBranchId} not found`
15149
- );
15327
+ throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15150
15328
  }
15151
15329
  const clinic = clinicSnapshot.data();
15152
- const practitionerRef = doc30(
15153
- this.db,
15154
- PRACTITIONERS_COLLECTION,
15155
- validatedData.practitionerId
15156
- );
15330
+ const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
15157
15331
  const practitionerSnapshot = await getDoc32(practitionerRef);
15158
15332
  if (!practitionerSnapshot.exists()) {
15159
- throw new Error(
15160
- `Practitioner with ID ${validatedData.practitionerId} not found`
15161
- );
15333
+ throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
15162
15334
  }
15163
15335
  const practitioner = practitionerSnapshot.data();
15164
15336
  let processedPhotos = [];
@@ -15169,6 +15341,10 @@ var ProcedureService = class extends BaseService {
15169
15341
  "procedure-photos"
15170
15342
  );
15171
15343
  }
15344
+ const transformedProductsMetadata = await this.transformProductsMetadata(
15345
+ validatedData.productsMetadata,
15346
+ validatedData.technologyId
15347
+ );
15172
15348
  const clinicInfo = {
15173
15349
  id: clinicSnapshot.id,
15174
15350
  name: clinic.name,
@@ -15186,9 +15362,10 @@ var ProcedureService = class extends BaseService {
15186
15362
  rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
15187
15363
  services: practitioner.procedures || []
15188
15364
  };
15365
+ const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
15189
15366
  const newProcedure = {
15190
15367
  id: procedureId,
15191
- ...validatedData,
15368
+ ...validatedDataWithoutProductsMetadata,
15192
15369
  // Ensure nameLower is always set even if omitted by client
15193
15370
  nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
15194
15371
  photos: processedPhotos,
@@ -15197,6 +15374,8 @@ var ProcedureService = class extends BaseService {
15197
15374
  subcategory,
15198
15375
  technology,
15199
15376
  product,
15377
+ productsMetadata: transformedProductsMetadata,
15378
+ // Use transformed data, not original
15200
15379
  blockingConditions: technology.blockingConditions,
15201
15380
  contraindications: technology.contraindications || [],
15202
15381
  contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
@@ -15250,24 +15429,16 @@ var ProcedureService = class extends BaseService {
15250
15429
  const validatedData = createProcedureSchema.parse(validationData);
15251
15430
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
15252
15431
  this.categoryService.getById(validatedData.categoryId),
15253
- this.subcategoryService.getById(
15254
- validatedData.categoryId,
15255
- validatedData.subcategoryId
15256
- ),
15432
+ this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15257
15433
  this.technologyService.getById(validatedData.technologyId),
15258
- this.productService.getById(
15259
- validatedData.technologyId,
15260
- validatedData.productId
15261
- ),
15434
+ this.productService.getById(validatedData.technologyId, validatedData.productId),
15262
15435
  getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
15263
15436
  ]);
15264
15437
  if (!category || !subcategory || !technology || !product) {
15265
15438
  throw new Error("One or more required base entities not found");
15266
15439
  }
15267
15440
  if (!clinicSnapshot.exists()) {
15268
- throw new Error(
15269
- `Clinic with ID ${validatedData.clinicBranchId} not found`
15270
- );
15441
+ throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15271
15442
  }
15272
15443
  const clinic = clinicSnapshot.data();
15273
15444
  let processedPhotos = [];
@@ -15279,6 +15450,10 @@ var ProcedureService = class extends BaseService {
15279
15450
  "procedure-photos-batch"
15280
15451
  );
15281
15452
  }
15453
+ const transformedProductsMetadata = await this.transformProductsMetadata(
15454
+ validatedData.productsMetadata,
15455
+ validatedData.technologyId
15456
+ );
15282
15457
  const practitionersMap = /* @__PURE__ */ new Map();
15283
15458
  for (let i = 0; i < practitionerIds.length; i += 30) {
15284
15459
  const chunk = practitionerIds.slice(i, i + 30);
@@ -15293,12 +15468,8 @@ var ProcedureService = class extends BaseService {
15293
15468
  }
15294
15469
  if (practitionersMap.size !== practitionerIds.length) {
15295
15470
  const foundIds = Array.from(practitionersMap.keys());
15296
- const notFoundIds = practitionerIds.filter(
15297
- (id) => !foundIds.includes(id)
15298
- );
15299
- throw new Error(
15300
- `The following practitioners were not found: ${notFoundIds.join(", ")}`
15301
- );
15471
+ const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
15472
+ throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
15302
15473
  }
15303
15474
  const batch = writeBatch6(this.db);
15304
15475
  const createdProcedureIds = [];
@@ -15323,9 +15494,10 @@ var ProcedureService = class extends BaseService {
15323
15494
  const procedureId = this.generateId();
15324
15495
  createdProcedureIds.push(procedureId);
15325
15496
  const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, procedureId);
15497
+ const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
15326
15498
  const newProcedure = {
15327
15499
  id: procedureId,
15328
- ...validatedData,
15500
+ ...validatedDataWithoutProductsMetadata,
15329
15501
  nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
15330
15502
  practitionerId,
15331
15503
  // Override practitionerId with the correct one
@@ -15334,6 +15506,8 @@ var ProcedureService = class extends BaseService {
15334
15506
  subcategory,
15335
15507
  technology,
15336
15508
  product,
15509
+ productsMetadata: transformedProductsMetadata,
15510
+ // Use transformed data, not original
15337
15511
  blockingConditions: technology.blockingConditions,
15338
15512
  contraindications: technology.contraindications || [],
15339
15513
  contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
@@ -15368,10 +15542,7 @@ var ProcedureService = class extends BaseService {
15368
15542
  const fetchedProcedures = [];
15369
15543
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
15370
15544
  const chunk = createdProcedureIds.slice(i, i + 30);
15371
- const q = query29(
15372
- collection29(this.db, PROCEDURES_COLLECTION),
15373
- where29(documentId2(), "in", chunk)
15374
- );
15545
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
15375
15546
  const snapshot = await getDocs29(q);
15376
15547
  snapshot.forEach((doc38) => {
15377
15548
  fetchedProcedures.push(doc38.data());
@@ -15441,7 +15612,7 @@ var ProcedureService = class extends BaseService {
15441
15612
  * @returns The updated procedure
15442
15613
  */
15443
15614
  async updateProcedure(id, data) {
15444
- var _a, _b, _c;
15615
+ var _a, _b, _c, _d;
15445
15616
  const validatedData = updateProcedureSchema.parse(data);
15446
15617
  const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
15447
15618
  const procedureSnapshot = await getDoc32(procedureRef);
@@ -15449,7 +15620,19 @@ var ProcedureService = class extends BaseService {
15449
15620
  throw new Error(`Procedure with ID ${id} not found`);
15450
15621
  }
15451
15622
  const existingProcedure = procedureSnapshot.data();
15452
- let updatedProcedureData = { ...validatedData };
15623
+ let updatedProcedureData = {};
15624
+ if (validatedData.name !== void 0) updatedProcedureData.name = validatedData.name;
15625
+ if (validatedData.description !== void 0)
15626
+ updatedProcedureData.description = validatedData.description;
15627
+ if (validatedData.price !== void 0) updatedProcedureData.price = validatedData.price;
15628
+ if (validatedData.currency !== void 0)
15629
+ updatedProcedureData.currency = validatedData.currency;
15630
+ if (validatedData.pricingMeasure !== void 0)
15631
+ updatedProcedureData.pricingMeasure = validatedData.pricingMeasure;
15632
+ if (validatedData.duration !== void 0)
15633
+ updatedProcedureData.duration = validatedData.duration;
15634
+ if (validatedData.isActive !== void 0)
15635
+ updatedProcedureData.isActive = validatedData.isActive;
15453
15636
  let practitionerChanged = false;
15454
15637
  let clinicChanged = false;
15455
15638
  const oldPractitionerId = existingProcedure.practitionerId;
@@ -15463,6 +15646,16 @@ var ProcedureService = class extends BaseService {
15463
15646
  "procedure-photos"
15464
15647
  );
15465
15648
  }
15649
+ if (validatedData.productsMetadata !== void 0) {
15650
+ const technologyId = (_a = validatedData.technologyId) != null ? _a : existingProcedure.technology.id;
15651
+ if (!technologyId) {
15652
+ throw new Error("Technology ID is required for updating products metadata");
15653
+ }
15654
+ updatedProcedureData.productsMetadata = await this.transformProductsMetadata(
15655
+ validatedData.productsMetadata,
15656
+ technologyId
15657
+ );
15658
+ }
15466
15659
  if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
15467
15660
  practitionerChanged = true;
15468
15661
  const newPractitionerRef = doc30(
@@ -15472,9 +15665,7 @@ var ProcedureService = class extends BaseService {
15472
15665
  );
15473
15666
  const newPractitionerSnap = await getDoc32(newPractitionerRef);
15474
15667
  if (!newPractitionerSnap.exists())
15475
- throw new Error(
15476
- `New Practitioner ${validatedData.practitionerId} not found`
15477
- );
15668
+ throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15478
15669
  newPractitioner = newPractitionerSnap.data();
15479
15670
  updatedProcedureData.doctorInfo = {
15480
15671
  id: newPractitioner.id,
@@ -15482,17 +15673,13 @@ var ProcedureService = class extends BaseService {
15482
15673
  description: newPractitioner.basicInfo.bio || "",
15483
15674
  photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
15484
15675
  // Default to empty string if not a processed URL
15485
- rating: ((_a = newPractitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
15676
+ rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
15486
15677
  services: newPractitioner.procedures || []
15487
15678
  };
15488
15679
  }
15489
15680
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15490
15681
  clinicChanged = true;
15491
- const newClinicRef = doc30(
15492
- this.db,
15493
- CLINICS_COLLECTION,
15494
- validatedData.clinicBranchId
15495
- );
15682
+ const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15496
15683
  const newClinicSnap = await getDoc32(newClinicRef);
15497
15684
  if (!newClinicSnap.exists())
15498
15685
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15511,11 +15698,8 @@ var ProcedureService = class extends BaseService {
15511
15698
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15512
15699
  }
15513
15700
  if (validatedData.categoryId) {
15514
- const category = await this.categoryService.getById(
15515
- validatedData.categoryId
15516
- );
15517
- if (!category)
15518
- throw new Error(`Category ${validatedData.categoryId} not found`);
15701
+ const category = await this.categoryService.getById(validatedData.categoryId);
15702
+ if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
15519
15703
  updatedProcedureData.category = category;
15520
15704
  finalCategoryId = category.id;
15521
15705
  }
@@ -15530,34 +15714,26 @@ var ProcedureService = class extends BaseService {
15530
15714
  );
15531
15715
  updatedProcedureData.subcategory = subcategory;
15532
15716
  } else if (validatedData.subcategoryId) {
15533
- console.warn(
15534
- "Attempted to update subcategory without a valid categoryId"
15535
- );
15717
+ console.warn("Attempted to update subcategory without a valid categoryId");
15536
15718
  }
15537
15719
  let finalTechnologyId = existingProcedure.technology.id;
15538
15720
  if (validatedData.technologyId) {
15539
- const technology = await this.technologyService.getById(
15540
- validatedData.technologyId
15541
- );
15542
- if (!technology)
15543
- throw new Error(`Technology ${validatedData.technologyId} not found`);
15721
+ const technology = await this.technologyService.getById(validatedData.technologyId);
15722
+ if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
15544
15723
  updatedProcedureData.technology = technology;
15545
15724
  finalTechnologyId = technology.id;
15546
15725
  updatedProcedureData.blockingConditions = technology.blockingConditions;
15547
15726
  updatedProcedureData.contraindications = technology.contraindications || [];
15548
- updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
15727
+ updatedProcedureData.contraindicationIds = ((_c = technology.contraindications) == null ? void 0 : _c.map((c) => c.id)) || [];
15549
15728
  updatedProcedureData.treatmentBenefits = technology.benefits;
15550
- updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
15729
+ updatedProcedureData.treatmentBenefitIds = ((_d = technology.benefits) == null ? void 0 : _d.map((b) => b.id)) || [];
15551
15730
  updatedProcedureData.preRequirements = technology.requirements.pre;
15552
15731
  updatedProcedureData.postRequirements = technology.requirements.post;
15553
15732
  updatedProcedureData.certificationRequirement = technology.certificationRequirement;
15554
15733
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15555
15734
  }
15556
15735
  if (validatedData.productId && finalTechnologyId) {
15557
- const product = await this.productService.getById(
15558
- finalTechnologyId,
15559
- validatedData.productId
15560
- );
15736
+ const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15561
15737
  if (!product)
15562
15738
  throw new Error(
15563
15739
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15639,11 +15815,7 @@ var ProcedureService = class extends BaseService {
15639
15815
  limit21(pagination)
15640
15816
  );
15641
15817
  } else {
15642
- proceduresQuery = query29(
15643
- proceduresCollection,
15644
- orderBy17("name"),
15645
- limit21(pagination)
15646
- );
15818
+ proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit21(pagination));
15647
15819
  }
15648
15820
  } else {
15649
15821
  proceduresQuery = query29(proceduresCollection, orderBy17("name"));
@@ -15692,9 +15864,7 @@ var ProcedureService = class extends BaseService {
15692
15864
  */
15693
15865
  async getProceduresByFilters(filters) {
15694
15866
  try {
15695
- console.log(
15696
- "[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
15697
- );
15867
+ console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
15698
15868
  if (filters.location && filters.radiusInKm) {
15699
15869
  console.log("[PROCEDURE_SERVICE] Executing geo query:", {
15700
15870
  location: filters.location,
@@ -15702,10 +15872,7 @@ var ProcedureService = class extends BaseService {
15702
15872
  serviceName: "ProcedureService"
15703
15873
  });
15704
15874
  if (!filters.location.latitude || !filters.location.longitude) {
15705
- console.warn(
15706
- "[PROCEDURE_SERVICE] Invalid location data:",
15707
- filters.location
15708
- );
15875
+ console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
15709
15876
  filters.location = void 0;
15710
15877
  filters.radiusInKm = void 0;
15711
15878
  }
@@ -15725,19 +15892,13 @@ var ProcedureService = class extends BaseService {
15725
15892
  constraints.push(where29("family", "==", filters.procedureFamily));
15726
15893
  }
15727
15894
  if (filters.procedureCategory) {
15728
- constraints.push(
15729
- where29("category.id", "==", filters.procedureCategory)
15730
- );
15895
+ constraints.push(where29("category.id", "==", filters.procedureCategory));
15731
15896
  }
15732
15897
  if (filters.procedureSubcategory) {
15733
- constraints.push(
15734
- where29("subcategory.id", "==", filters.procedureSubcategory)
15735
- );
15898
+ constraints.push(where29("subcategory.id", "==", filters.procedureSubcategory));
15736
15899
  }
15737
15900
  if (filters.procedureTechnology) {
15738
- constraints.push(
15739
- where29("technology.id", "==", filters.procedureTechnology)
15740
- );
15901
+ constraints.push(where29("technology.id", "==", filters.procedureTechnology));
15741
15902
  }
15742
15903
  if (filters.minPrice !== void 0) {
15743
15904
  constraints.push(where29("price", ">=", filters.minPrice));
@@ -15746,32 +15907,20 @@ var ProcedureService = class extends BaseService {
15746
15907
  constraints.push(where29("price", "<=", filters.maxPrice));
15747
15908
  }
15748
15909
  if (filters.minRating !== void 0) {
15749
- constraints.push(
15750
- where29("reviewInfo.averageRating", ">=", filters.minRating)
15751
- );
15910
+ constraints.push(where29("reviewInfo.averageRating", ">=", filters.minRating));
15752
15911
  }
15753
15912
  if (filters.maxRating !== void 0) {
15754
- constraints.push(
15755
- where29("reviewInfo.averageRating", "<=", filters.maxRating)
15756
- );
15913
+ constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
15757
15914
  }
15758
15915
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15759
15916
  const benefitIdsToMatch = filters.treatmentBenefits;
15760
- constraints.push(
15761
- where29(
15762
- "treatmentBenefitIds",
15763
- "array-contains-any",
15764
- benefitIdsToMatch
15765
- )
15766
- );
15917
+ constraints.push(where29("treatmentBenefitIds", "array-contains-any", benefitIdsToMatch));
15767
15918
  }
15768
15919
  return constraints;
15769
15920
  };
15770
15921
  if (filters.nameSearch && filters.nameSearch.trim()) {
15771
15922
  try {
15772
- console.log(
15773
- "[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
15774
- );
15923
+ console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
15775
15924
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15776
15925
  const constraints = getBaseConstraints();
15777
15926
  constraints.push(where29("nameLower", ">=", searchTerm));
@@ -15787,18 +15936,13 @@ var ProcedureService = class extends BaseService {
15787
15936
  }
15788
15937
  }
15789
15938
  constraints.push(limit15(filters.pagination || 10));
15790
- const q = query29(
15791
- collection29(this.db, PROCEDURES_COLLECTION),
15792
- ...constraints
15793
- );
15939
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15794
15940
  const querySnapshot = await getDocs29(q);
15795
15941
  const procedures = querySnapshot.docs.map(
15796
15942
  (doc38) => ({ ...doc38.data(), id: doc38.id })
15797
15943
  );
15798
15944
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15799
- console.log(
15800
- `[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
15801
- );
15945
+ console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15802
15946
  if (procedures.length < (filters.pagination || 10)) {
15803
15947
  return { procedures, lastDoc: null };
15804
15948
  }
@@ -15809,9 +15953,7 @@ var ProcedureService = class extends BaseService {
15809
15953
  }
15810
15954
  if (filters.nameSearch && filters.nameSearch.trim()) {
15811
15955
  try {
15812
- console.log(
15813
- "[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
15814
- );
15956
+ console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
15815
15957
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15816
15958
  const constraints = getBaseConstraints();
15817
15959
  constraints.push(where29("name", ">=", searchTerm));
@@ -15827,18 +15969,13 @@ var ProcedureService = class extends BaseService {
15827
15969
  }
15828
15970
  }
15829
15971
  constraints.push(limit15(filters.pagination || 10));
15830
- const q = query29(
15831
- collection29(this.db, PROCEDURES_COLLECTION),
15832
- ...constraints
15833
- );
15972
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15834
15973
  const querySnapshot = await getDocs29(q);
15835
15974
  const procedures = querySnapshot.docs.map(
15836
15975
  (doc38) => ({ ...doc38.data(), id: doc38.id })
15837
15976
  );
15838
15977
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15839
- console.log(
15840
- `[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
15841
- );
15978
+ console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15842
15979
  if (procedures.length < (filters.pagination || 10)) {
15843
15980
  return { procedures, lastDoc: null };
15844
15981
  }
@@ -15863,19 +16000,14 @@ var ProcedureService = class extends BaseService {
15863
16000
  }
15864
16001
  }
15865
16002
  constraints.push(limit15(filters.pagination || 10));
15866
- const q = query29(
15867
- collection29(this.db, PROCEDURES_COLLECTION),
15868
- ...constraints
15869
- );
16003
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15870
16004
  const querySnapshot = await getDocs29(q);
15871
16005
  let procedures = querySnapshot.docs.map(
15872
16006
  (doc38) => ({ ...doc38.data(), id: doc38.id })
15873
16007
  );
15874
16008
  procedures = this.applyInMemoryFilters(procedures, filters);
15875
16009
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15876
- console.log(
15877
- `[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
15878
- );
16010
+ console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
15879
16011
  if (procedures.length < (filters.pagination || 10)) {
15880
16012
  return { procedures, lastDoc: null };
15881
16013
  }
@@ -15890,19 +16022,14 @@ var ProcedureService = class extends BaseService {
15890
16022
  orderBy17("createdAt", "desc"),
15891
16023
  limit15(filters.pagination || 10)
15892
16024
  ];
15893
- const q = query29(
15894
- collection29(this.db, PROCEDURES_COLLECTION),
15895
- ...constraints
15896
- );
16025
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15897
16026
  const querySnapshot = await getDocs29(q);
15898
16027
  let procedures = querySnapshot.docs.map(
15899
16028
  (doc38) => ({ ...doc38.data(), id: doc38.id })
15900
16029
  );
15901
16030
  procedures = this.applyInMemoryFilters(procedures, filters);
15902
16031
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15903
- console.log(
15904
- `[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
15905
- );
16032
+ console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
15906
16033
  if (procedures.length < (filters.pagination || 10)) {
15907
16034
  return { procedures, lastDoc: null };
15908
16035
  }
@@ -15910,9 +16037,7 @@ var ProcedureService = class extends BaseService {
15910
16037
  } catch (error) {
15911
16038
  console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
15912
16039
  }
15913
- console.log(
15914
- "[PROCEDURE_SERVICE] All strategies failed, returning empty result"
15915
- );
16040
+ console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
15916
16041
  return { procedures: [], lastDoc: null };
15917
16042
  } catch (error) {
15918
16043
  console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
@@ -15932,17 +16057,13 @@ var ProcedureService = class extends BaseService {
15932
16057
  const nameLower = procedure.nameLower || "";
15933
16058
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
15934
16059
  });
15935
- console.log(
15936
- `[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
15937
- );
16060
+ console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
15938
16061
  }
15939
16062
  if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
15940
16063
  filteredProcedures = filteredProcedures.filter((procedure) => {
15941
16064
  const price = procedure.price || 0;
15942
- if (filters.minPrice !== void 0 && price < filters.minPrice)
15943
- return false;
15944
- if (filters.maxPrice !== void 0 && price > filters.maxPrice)
15945
- return false;
16065
+ if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
16066
+ if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
15946
16067
  return true;
15947
16068
  });
15948
16069
  console.log(
@@ -15953,10 +16074,8 @@ var ProcedureService = class extends BaseService {
15953
16074
  filteredProcedures = filteredProcedures.filter((procedure) => {
15954
16075
  var _a;
15955
16076
  const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
15956
- if (filters.minRating !== void 0 && rating < filters.minRating)
15957
- return false;
15958
- if (filters.maxRating !== void 0 && rating > filters.maxRating)
15959
- return false;
16077
+ if (filters.minRating !== void 0 && rating < filters.minRating) return false;
16078
+ if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
15960
16079
  return true;
15961
16080
  });
15962
16081
  console.log(
@@ -16032,12 +16151,8 @@ var ProcedureService = class extends BaseService {
16032
16151
  procedure.distance = distance;
16033
16152
  return distance <= radiusInKm;
16034
16153
  });
16035
- console.log(
16036
- `[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
16037
- );
16038
- filteredProcedures.sort(
16039
- (a, b) => (a.distance || 0) - (b.distance || 0)
16040
- );
16154
+ console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
16155
+ filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
16041
16156
  }
16042
16157
  return filteredProcedures;
16043
16158
  }
@@ -16049,30 +16164,19 @@ var ProcedureService = class extends BaseService {
16049
16164
  if (!location || !radiusInKm) {
16050
16165
  return Promise.resolve({ procedures: [], lastDoc: null });
16051
16166
  }
16052
- const bounds = geohashQueryBounds5(
16053
- [location.latitude, location.longitude],
16054
- radiusInKm * 1e3
16055
- );
16167
+ const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
16056
16168
  const fetches = bounds.map((b) => {
16057
16169
  const constraints = [
16058
16170
  where29("clinicInfo.location.geohash", ">=", b[0]),
16059
16171
  where29("clinicInfo.location.geohash", "<=", b[1]),
16060
- where29(
16061
- "isActive",
16062
- "==",
16063
- filters.isActive !== void 0 ? filters.isActive : true
16064
- )
16172
+ where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
16065
16173
  ];
16066
- return getDocs29(
16067
- query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
16068
- );
16174
+ return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
16069
16175
  });
16070
16176
  return Promise.all(fetches).then((snaps) => {
16071
16177
  const collected = [];
16072
16178
  snaps.forEach((snap) => {
16073
- snap.docs.forEach(
16074
- (d) => collected.push({ ...d.data(), id: d.id })
16075
- );
16179
+ snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
16076
16180
  });
16077
16181
  const uniqueMap = /* @__PURE__ */ new Map();
16078
16182
  for (const p of collected) {
@@ -16083,9 +16187,7 @@ var ProcedureService = class extends BaseService {
16083
16187
  const pageSize = filters.pagination || 10;
16084
16188
  let startIndex = 0;
16085
16189
  if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
16086
- const idx = procedures.findIndex(
16087
- (p) => p.id === filters.lastDoc.id
16088
- );
16190
+ const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
16089
16191
  if (idx >= 0) startIndex = idx + 1;
16090
16192
  }
16091
16193
  const page = procedures.slice(startIndex, startIndex + pageSize);
@@ -16126,11 +16228,7 @@ var ProcedureService = class extends BaseService {
16126
16228
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
16127
16229
  }
16128
16230
  const clinic = clinicSnapshot.data();
16129
- const practitionerRef = doc30(
16130
- this.db,
16131
- PRACTITIONERS_COLLECTION,
16132
- data.practitionerId
16133
- );
16231
+ const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
16134
16232
  const practitionerSnapshot = await getDoc32(practitionerRef);
16135
16233
  if (!practitionerSnapshot.exists()) {
16136
16234
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -16138,12 +16236,12 @@ var ProcedureService = class extends BaseService {
16138
16236
  const practitioner = practitionerSnapshot.data();
16139
16237
  let processedPhotos = [];
16140
16238
  if (data.photos && data.photos.length > 0) {
16141
- processedPhotos = await this.processMediaArray(
16142
- data.photos,
16143
- procedureId,
16144
- "procedure-photos"
16145
- );
16239
+ processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
16146
16240
  }
16241
+ const transformedProductsMetadata = await this.transformProductsMetadata(
16242
+ data.productsMetadata,
16243
+ data.technologyId
16244
+ );
16147
16245
  const clinicInfo = {
16148
16246
  id: clinicSnapshot.id,
16149
16247
  name: clinic.name,
@@ -16174,9 +16272,10 @@ var ProcedureService = class extends BaseService {
16174
16272
  createdAt: /* @__PURE__ */ new Date(),
16175
16273
  updatedAt: /* @__PURE__ */ new Date()
16176
16274
  };
16275
+ const { productsMetadata: _, ...dataWithoutProductsMetadata } = data;
16177
16276
  const newProcedure = {
16178
16277
  id: procedureId,
16179
- ...data,
16278
+ ...dataWithoutProductsMetadata,
16180
16279
  nameLower: data.nameLower || data.name.toLowerCase(),
16181
16280
  photos: processedPhotos,
16182
16281
  category,
@@ -16184,6 +16283,8 @@ var ProcedureService = class extends BaseService {
16184
16283
  technology,
16185
16284
  product: consultationProduct,
16186
16285
  // Use placeholder product
16286
+ productsMetadata: transformedProductsMetadata,
16287
+ // Use transformed data, not original
16187
16288
  blockingConditions: technology.blockingConditions,
16188
16289
  contraindications: technology.contraindications || [],
16189
16290
  contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
@@ -16253,7 +16354,7 @@ import {
16253
16354
  deleteDoc as deleteDoc19,
16254
16355
  serverTimestamp as serverTimestamp26
16255
16356
  } from "firebase/firestore";
16256
- import { z as z25 } from "zod";
16357
+ import { z as z26 } from "zod";
16257
16358
  var ReviewService = class extends BaseService {
16258
16359
  constructor(db, auth, app) {
16259
16360
  super(db, auth, app);
@@ -16340,7 +16441,7 @@ var ReviewService = class extends BaseService {
16340
16441
  });
16341
16442
  return review;
16342
16443
  } catch (error) {
16343
- if (error instanceof z25.ZodError) {
16444
+ if (error instanceof z26.ZodError) {
16344
16445
  throw new Error(`Invalid review data: ${error.message}`);
16345
16446
  }
16346
16447
  throw error;