@blackcode_sa/metaestetics-api 1.12.45 → 1.12.47

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.
@@ -762,8 +762,8 @@ interface Procedure {
762
762
  subcategory: Subcategory;
763
763
  /** Technology used in this procedure */
764
764
  technology: Technology;
765
- /** Default product used in this procedure */
766
- product: Product;
765
+ /** Default product used in this procedure (optional for consultations) */
766
+ product?: Product;
767
767
  /** Default price of the procedure */
768
768
  price: number;
769
769
  /** Currency for the price */
@@ -771,7 +771,7 @@ interface Procedure {
771
771
  /** How the price is measured (per ml, per zone, etc.) - for default product*/
772
772
  pricingMeasure: PricingMeasure;
773
773
  /** Duration of the procedure in minutes */
774
- productsMetadata: ProcedureProduct[];
774
+ productsMetadata?: ProcedureProduct[];
775
775
  duration: number;
776
776
  /** Blocking conditions that prevent this procedure */
777
777
  blockingConditions: BlockingCondition[];
@@ -3466,7 +3466,8 @@ declare class DocumentManagerAdminService {
3466
3466
 
3467
3467
  /**
3468
3468
  * Ensures that the free consultation infrastructure exists in the database
3469
- * Creates category, subcategory, technology, and product if they don't exist
3469
+ * Creates category, subcategory, and technology if they don't exist
3470
+ * Note: Consultations are product-free procedures, so no product is created
3470
3471
  * @param db - Firestore database instance (optional, defaults to admin.firestore())
3471
3472
  * @returns Promise<boolean> - Always returns true after ensuring infrastructure exists
3472
3473
  */
@@ -762,8 +762,8 @@ interface Procedure {
762
762
  subcategory: Subcategory;
763
763
  /** Technology used in this procedure */
764
764
  technology: Technology;
765
- /** Default product used in this procedure */
766
- product: Product;
765
+ /** Default product used in this procedure (optional for consultations) */
766
+ product?: Product;
767
767
  /** Default price of the procedure */
768
768
  price: number;
769
769
  /** Currency for the price */
@@ -771,7 +771,7 @@ interface Procedure {
771
771
  /** How the price is measured (per ml, per zone, etc.) - for default product*/
772
772
  pricingMeasure: PricingMeasure;
773
773
  /** Duration of the procedure in minutes */
774
- productsMetadata: ProcedureProduct[];
774
+ productsMetadata?: ProcedureProduct[];
775
775
  duration: number;
776
776
  /** Blocking conditions that prevent this procedure */
777
777
  blockingConditions: BlockingCondition[];
@@ -3466,7 +3466,8 @@ declare class DocumentManagerAdminService {
3466
3466
 
3467
3467
  /**
3468
3468
  * Ensures that the free consultation infrastructure exists in the database
3469
- * Creates category, subcategory, technology, and product if they don't exist
3469
+ * Creates category, subcategory, and technology if they don't exist
3470
+ * Note: Consultations are product-free procedures, so no product is created
3470
3471
  * @param db - Firestore database instance (optional, defaults to admin.firestore())
3471
3472
  * @returns Promise<boolean> - Always returns true after ensuring infrastructure exists
3472
3473
  */
@@ -7825,7 +7825,7 @@ var BookingAdmin = class {
7825
7825
  procedureTechnologyName: (procedureTechnology == null ? void 0 : procedureTechnology.name) || "",
7826
7826
  procedureProductBrandId: (procedureProduct == null ? void 0 : procedureProduct.brandId) || "",
7827
7827
  procedureProductBrandName: (procedureProduct == null ? void 0 : procedureProduct.brandName) || "",
7828
- procedureProducts: productsMetadata.map((pp) => ({
7828
+ procedureProducts: productsMetadata.filter((pp) => pp && pp.product).map((pp) => ({
7829
7829
  productId: pp.product.id,
7830
7830
  productName: pp.product.name,
7831
7831
  brandId: pp.product.brandId,
@@ -7835,7 +7835,7 @@ var BookingAdmin = class {
7835
7835
  }
7836
7836
  _generateAppointmentProductsFromProcedure(procedure) {
7837
7837
  const productsMetadata = procedure.productsMetadata || [];
7838
- return productsMetadata.map((pp) => {
7838
+ return productsMetadata.filter((pp) => pp && pp.product).map((pp) => {
7839
7839
  const product = pp.product;
7840
7840
  return {
7841
7841
  productId: product.id,
@@ -7863,9 +7863,6 @@ var SUBCATEGORIES_COLLECTION = "subcategories";
7863
7863
  // src/backoffice/types/technology.types.ts
7864
7864
  var TECHNOLOGIES_COLLECTION = "technologies";
7865
7865
 
7866
- // src/backoffice/types/product.types.ts
7867
- var PRODUCTS_COLLECTION = "products";
7868
-
7869
7866
  // src/admin/free-consultation/free-consultation-utils.admin.ts
7870
7867
  async function freeConsultationInfrastructure(db) {
7871
7868
  const firestore18 = db || admin16.firestore();
@@ -7950,32 +7947,12 @@ async function createFreeConsultationInfrastructure(db) {
7950
7947
  updatedAt: now
7951
7948
  };
7952
7949
  batch.set(technologyRef, technologyData);
7953
- const productRef = db.collection(TECHNOLOGIES_COLLECTION).doc("free-consultation-tech").collection(PRODUCTS_COLLECTION).doc("free-consultation-product");
7954
- const productData = {
7955
- id: "free-consultation-product",
7956
- name: "Free Consultation Service",
7957
- description: "No physical product required for consultation services",
7958
- brandId: "consultation-brand",
7959
- brandName: "Consultation Services",
7960
- technologyId: "free-consultation-tech",
7961
- technologyName: "Free Consultation Technology",
7962
- categoryId: "consultation",
7963
- subcategoryId: "free-consultation",
7964
- isActive: true,
7965
- createdAt: now,
7966
- updatedAt: now,
7967
- technicalDetails: "Virtual consultation service - no physical product required",
7968
- warnings: [],
7969
- indications: ["Initial patient assessment", "Treatment planning", "Patient education"],
7970
- contraindications: []
7971
- };
7972
- batch.set(productRef, productData);
7973
7950
  await batch.commit();
7974
7951
  console.log("[freeConsultationInfrastructure] Successfully created:");
7975
7952
  console.log(" \u2713 Category: consultation");
7976
7953
  console.log(" \u2713 Subcategory: free-consultation");
7977
7954
  console.log(" \u2713 Technology: free-consultation-tech");
7978
- console.log(" \u2713 Product: free-consultation-product");
7955
+ console.log(" \u2139 No product needed - consultations are product-free procedures");
7979
7956
  }
7980
7957
 
7981
7958
  // src/admin/mailing/practitionerInvite/templates/invitation.template.ts
@@ -7763,7 +7763,7 @@ var BookingAdmin = class {
7763
7763
  procedureTechnologyName: (procedureTechnology == null ? void 0 : procedureTechnology.name) || "",
7764
7764
  procedureProductBrandId: (procedureProduct == null ? void 0 : procedureProduct.brandId) || "",
7765
7765
  procedureProductBrandName: (procedureProduct == null ? void 0 : procedureProduct.brandName) || "",
7766
- procedureProducts: productsMetadata.map((pp) => ({
7766
+ procedureProducts: productsMetadata.filter((pp) => pp && pp.product).map((pp) => ({
7767
7767
  productId: pp.product.id,
7768
7768
  productName: pp.product.name,
7769
7769
  brandId: pp.product.brandId,
@@ -7773,7 +7773,7 @@ var BookingAdmin = class {
7773
7773
  }
7774
7774
  _generateAppointmentProductsFromProcedure(procedure) {
7775
7775
  const productsMetadata = procedure.productsMetadata || [];
7776
- return productsMetadata.map((pp) => {
7776
+ return productsMetadata.filter((pp) => pp && pp.product).map((pp) => {
7777
7777
  const product = pp.product;
7778
7778
  return {
7779
7779
  productId: product.id,
@@ -7801,9 +7801,6 @@ var SUBCATEGORIES_COLLECTION = "subcategories";
7801
7801
  // src/backoffice/types/technology.types.ts
7802
7802
  var TECHNOLOGIES_COLLECTION = "technologies";
7803
7803
 
7804
- // src/backoffice/types/product.types.ts
7805
- var PRODUCTS_COLLECTION = "products";
7806
-
7807
7804
  // src/admin/free-consultation/free-consultation-utils.admin.ts
7808
7805
  async function freeConsultationInfrastructure(db) {
7809
7806
  const firestore18 = db || admin16.firestore();
@@ -7888,32 +7885,12 @@ async function createFreeConsultationInfrastructure(db) {
7888
7885
  updatedAt: now
7889
7886
  };
7890
7887
  batch.set(technologyRef, technologyData);
7891
- const productRef = db.collection(TECHNOLOGIES_COLLECTION).doc("free-consultation-tech").collection(PRODUCTS_COLLECTION).doc("free-consultation-product");
7892
- const productData = {
7893
- id: "free-consultation-product",
7894
- name: "Free Consultation Service",
7895
- description: "No physical product required for consultation services",
7896
- brandId: "consultation-brand",
7897
- brandName: "Consultation Services",
7898
- technologyId: "free-consultation-tech",
7899
- technologyName: "Free Consultation Technology",
7900
- categoryId: "consultation",
7901
- subcategoryId: "free-consultation",
7902
- isActive: true,
7903
- createdAt: now,
7904
- updatedAt: now,
7905
- technicalDetails: "Virtual consultation service - no physical product required",
7906
- warnings: [],
7907
- indications: ["Initial patient assessment", "Treatment planning", "Patient education"],
7908
- contraindications: []
7909
- };
7910
- batch.set(productRef, productData);
7911
7888
  await batch.commit();
7912
7889
  console.log("[freeConsultationInfrastructure] Successfully created:");
7913
7890
  console.log(" \u2713 Category: consultation");
7914
7891
  console.log(" \u2713 Subcategory: free-consultation");
7915
7892
  console.log(" \u2713 Technology: free-consultation-tech");
7916
- console.log(" \u2713 Product: free-consultation-product");
7893
+ console.log(" \u2139 No product needed - consultations are product-free procedures");
7917
7894
  }
7918
7895
 
7919
7896
  // src/admin/mailing/practitionerInvite/templates/invitation.template.ts
package/dist/index.d.mts CHANGED
@@ -3667,8 +3667,8 @@ interface Procedure {
3667
3667
  subcategory: Subcategory;
3668
3668
  /** Technology used in this procedure */
3669
3669
  technology: Technology;
3670
- /** Default product used in this procedure */
3671
- product: Product;
3670
+ /** Default product used in this procedure (optional for consultations) */
3671
+ product?: Product;
3672
3672
  /** Default price of the procedure */
3673
3673
  price: number;
3674
3674
  /** Currency for the price */
@@ -3676,7 +3676,7 @@ interface Procedure {
3676
3676
  /** How the price is measured (per ml, per zone, etc.) - for default product*/
3677
3677
  pricingMeasure: PricingMeasure;
3678
3678
  /** Duration of the procedure in minutes */
3679
- productsMetadata: ProcedureProduct[];
3679
+ productsMetadata?: ProcedureProduct[];
3680
3680
  duration: number;
3681
3681
  /** Blocking conditions that prevent this procedure */
3682
3682
  blockingConditions: BlockingCondition[];
@@ -3725,9 +3725,9 @@ interface CreateProcedureData {
3725
3725
  categoryId: string;
3726
3726
  subcategoryId: string;
3727
3727
  technologyId: string;
3728
- productId: string;
3728
+ productId?: string;
3729
3729
  price: number;
3730
- productsMetadata: {
3730
+ productsMetadata?: {
3731
3731
  productId: string;
3732
3732
  price: number;
3733
3733
  currency: Currency;
@@ -5515,7 +5515,7 @@ declare class ProcedureService extends BaseService {
5515
5515
  private processMediaArray;
5516
5516
  /**
5517
5517
  * Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
5518
- * @param productsMetadata Array of validated procedure product data
5518
+ * @param productsMetadata Array of validated procedure product data (optional)
5519
5519
  * @param technologyId Technology ID to fetch products from
5520
5520
  * @returns Array of ProcedureProduct objects with full product information
5521
5521
  */
package/dist/index.d.ts CHANGED
@@ -3667,8 +3667,8 @@ interface Procedure {
3667
3667
  subcategory: Subcategory;
3668
3668
  /** Technology used in this procedure */
3669
3669
  technology: Technology;
3670
- /** Default product used in this procedure */
3671
- product: Product;
3670
+ /** Default product used in this procedure (optional for consultations) */
3671
+ product?: Product;
3672
3672
  /** Default price of the procedure */
3673
3673
  price: number;
3674
3674
  /** Currency for the price */
@@ -3676,7 +3676,7 @@ interface Procedure {
3676
3676
  /** How the price is measured (per ml, per zone, etc.) - for default product*/
3677
3677
  pricingMeasure: PricingMeasure;
3678
3678
  /** Duration of the procedure in minutes */
3679
- productsMetadata: ProcedureProduct[];
3679
+ productsMetadata?: ProcedureProduct[];
3680
3680
  duration: number;
3681
3681
  /** Blocking conditions that prevent this procedure */
3682
3682
  blockingConditions: BlockingCondition[];
@@ -3725,9 +3725,9 @@ interface CreateProcedureData {
3725
3725
  categoryId: string;
3726
3726
  subcategoryId: string;
3727
3727
  technologyId: string;
3728
- productId: string;
3728
+ productId?: string;
3729
3729
  price: number;
3730
- productsMetadata: {
3730
+ productsMetadata?: {
3731
3731
  productId: string;
3732
3732
  price: number;
3733
3733
  currency: Currency;
@@ -5515,7 +5515,7 @@ declare class ProcedureService extends BaseService {
5515
5515
  private processMediaArray;
5516
5516
  /**
5517
5517
  * Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
5518
- * @param productsMetadata Array of validated procedure product data
5518
+ * @param productsMetadata Array of validated procedure product data (optional)
5519
5519
  * @param technologyId Technology ID to fetch products from
5520
5520
  * @returns Array of ProcedureProduct objects with full product information
5521
5521
  */
package/dist/index.js CHANGED
@@ -661,7 +661,8 @@ var recommendedProcedureTimeframeSchema = import_zod3.z.object({
661
661
  });
662
662
  var recommendedProcedureSchema = import_zod3.z.object({
663
663
  procedure: extendedProcedureInfoSchema,
664
- note: import_zod3.z.string().min(1, "Note is required").max(MAX_STRING_LENGTH_LONG, "Note too long"),
664
+ note: import_zod3.z.string().max(MAX_STRING_LENGTH_LONG, "Note too long"),
665
+ // Note is now optional (no min length)
665
666
  timeframe: recommendedProcedureTimeframeSchema
666
667
  });
667
668
  var appointmentMetadataSchema = import_zod3.z.object({
@@ -1553,7 +1554,7 @@ function calculateItemSubtotal(item) {
1553
1554
  const price = item.price || 0;
1554
1555
  return price * quantity;
1555
1556
  }
1556
- function calculateFinalBilling(zonesData, taxRate = 0.2) {
1557
+ function calculateFinalBilling(zonesData, taxRate = 0.081) {
1557
1558
  let subtotalAll = 0;
1558
1559
  Object.values(zonesData).forEach((items) => {
1559
1560
  items.forEach((item) => {
@@ -1617,7 +1618,7 @@ async function addItemToZoneUtil(db, appointmentId, zoneId, item) {
1617
1618
  updatedAt: now
1618
1619
  };
1619
1620
  zonesData[zoneId].push(itemWithSubtotal);
1620
- const finalbilling = calculateFinalBilling(zonesData);
1621
+ const finalbilling = calculateFinalBilling(zonesData, 0.081);
1621
1622
  const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
1622
1623
  await (0, import_firestore4.updateDoc)(appointmentRef, {
1623
1624
  "metadata.zonesData": zonesData,
@@ -1641,7 +1642,7 @@ async function removeItemFromZoneUtil(db, appointmentId, zoneId, itemIndex) {
1641
1642
  if (items.length === 0) {
1642
1643
  delete metadata.zonesData[zoneId];
1643
1644
  }
1644
- const finalbilling = calculateFinalBilling(metadata.zonesData);
1645
+ const finalbilling = calculateFinalBilling(metadata.zonesData, 0.081);
1645
1646
  const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
1646
1647
  await (0, import_firestore4.updateDoc)(appointmentRef, {
1647
1648
  "metadata.zonesData": metadata.zonesData,
@@ -1678,7 +1679,7 @@ async function updateZoneItemUtil(db, appointmentId, zoneId, itemIndex, updates)
1678
1679
  itemIndex,
1679
1680
  newSubtotal: items[itemIndex].subtotal
1680
1681
  });
1681
- const finalbilling = calculateFinalBilling(metadata.zonesData);
1682
+ const finalbilling = calculateFinalBilling(metadata.zonesData, 0.081);
1682
1683
  const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
1683
1684
  await (0, import_firestore4.updateDoc)(appointmentRef, {
1684
1685
  "metadata.zonesData": metadata.zonesData,
@@ -1840,7 +1841,7 @@ async function aggregateProductsFromProcedure(db, procedureId, existingProducts)
1840
1841
  }
1841
1842
  const procedureData = procedureSnap.data();
1842
1843
  const productsMetadata = procedureData.productsMetadata || [];
1843
- const newProducts = productsMetadata.map((pp) => {
1844
+ const newProducts = productsMetadata.filter((pp) => pp && pp.product).map((pp) => {
1844
1845
  const product = pp.product;
1845
1846
  return {
1846
1847
  productId: product.id,
@@ -1893,7 +1894,7 @@ async function createExtendedProcedureInfo(db, procedureId) {
1893
1894
  // Access embedded technology
1894
1895
  procedureTechnologyName: data.technology.name,
1895
1896
  // Access embedded technology
1896
- procedureProducts: (data.productsMetadata || []).map((pp) => ({
1897
+ procedureProducts: (data.productsMetadata || []).filter((pp) => pp && pp.product).map((pp) => ({
1897
1898
  productId: pp.product.id,
1898
1899
  // Access embedded product
1899
1900
  productName: pp.product.name,
@@ -1909,9 +1910,7 @@ async function addExtendedProcedureUtil(db, appointmentId, procedureId) {
1909
1910
  var _a;
1910
1911
  const appointment = await getAppointmentOrThrow(db, appointmentId);
1911
1912
  const metadata = initializeMetadata(appointment);
1912
- const existingProcedure = (_a = metadata.extendedProcedures) == null ? void 0 : _a.find(
1913
- (p) => p.procedureId === procedureId
1914
- );
1913
+ const existingProcedure = (_a = metadata.extendedProcedures) == null ? void 0 : _a.find((p) => p.procedureId === procedureId);
1915
1914
  if (existingProcedure) {
1916
1915
  throw new Error(`Procedure ${procedureId} is already added to this appointment`);
1917
1916
  }
@@ -1942,7 +1941,10 @@ async function addExtendedProcedureUtil(db, appointmentId, procedureId) {
1942
1941
  );
1943
1942
  updatedLinkedFormIds = [...updatedLinkedFormIds, ...formInitResult.allLinkedFormIds];
1944
1943
  updatedLinkedForms = [...updatedLinkedForms, ...formInitResult.initializedFormsInfo];
1945
- updatedPendingUserFormsIds = [...updatedPendingUserFormsIds, ...formInitResult.pendingUserFormsIds];
1944
+ updatedPendingUserFormsIds = [
1945
+ ...updatedPendingUserFormsIds,
1946
+ ...formInitResult.pendingUserFormsIds
1947
+ ];
1946
1948
  }
1947
1949
  const extendedProcedures = [...metadata.extendedProcedures || [], extendedProcedureInfo];
1948
1950
  const appointmentRef = (0, import_firestore7.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
@@ -1962,9 +1964,7 @@ async function removeExtendedProcedureUtil(db, appointmentId, procedureId) {
1962
1964
  if (!metadata.extendedProcedures || metadata.extendedProcedures.length === 0) {
1963
1965
  throw new Error("No extended procedures found for this appointment");
1964
1966
  }
1965
- const procedureIndex = metadata.extendedProcedures.findIndex(
1966
- (p) => p.procedureId === procedureId
1967
- );
1967
+ const procedureIndex = metadata.extendedProcedures.findIndex((p) => p.procedureId === procedureId);
1968
1968
  if (procedureIndex === -1) {
1969
1969
  throw new Error(`Extended procedure ${procedureId} not found in this appointment`);
1970
1970
  }
@@ -1972,6 +1972,20 @@ async function removeExtendedProcedureUtil(db, appointmentId, procedureId) {
1972
1972
  const updatedProducts = (metadata.appointmentProducts || []).filter(
1973
1973
  (p) => p.procedureId !== procedureId
1974
1974
  );
1975
+ const updatedZonesData = { ...metadata.zonesData || {} };
1976
+ let productsRemovedFromZones = 0;
1977
+ Object.keys(updatedZonesData).forEach((zoneId) => {
1978
+ const originalLength = updatedZonesData[zoneId].length;
1979
+ updatedZonesData[zoneId] = updatedZonesData[zoneId].filter((item) => {
1980
+ if (item.type === "note") return true;
1981
+ if (item.type === "item" && item.belongingProcedureId !== procedureId) return true;
1982
+ return false;
1983
+ });
1984
+ productsRemovedFromZones += originalLength - updatedZonesData[zoneId].length;
1985
+ });
1986
+ console.log(
1987
+ `\u{1F5D1}\uFE0F [removeExtendedProcedure] Removed ${productsRemovedFromZones} products from zones for procedure ${procedureId}`
1988
+ );
1975
1989
  const removedFormIds = await removeFormsForExtendedProcedure(db, appointmentId, procedureId);
1976
1990
  const updatedLinkedFormIds = (appointment.linkedFormIds || []).filter(
1977
1991
  (formId) => !removedFormIds.includes(formId)
@@ -1986,6 +2000,7 @@ async function removeExtendedProcedureUtil(db, appointmentId, procedureId) {
1986
2000
  await (0, import_firestore7.updateDoc)(appointmentRef, {
1987
2001
  "metadata.extendedProcedures": metadata.extendedProcedures,
1988
2002
  "metadata.appointmentProducts": updatedProducts,
2003
+ "metadata.zonesData": updatedZonesData,
1989
2004
  linkedFormIds: updatedLinkedFormIds,
1990
2005
  linkedForms: updatedLinkedForms,
1991
2006
  pendingUserFormsIds: updatedPendingUserFormsIds,
@@ -2024,7 +2039,7 @@ async function createExtendedProcedureInfoForRecommended(db, procedureId) {
2024
2039
  procedureSubCategoryName: data.subcategory.name,
2025
2040
  procedureTechnologyId: data.technology.id,
2026
2041
  procedureTechnologyName: data.technology.name,
2027
- procedureProducts: (data.productsMetadata || []).map((pp) => ({
2042
+ procedureProducts: (data.productsMetadata || []).filter((pp) => pp && pp.product).map((pp) => ({
2028
2043
  productId: pp.product.id,
2029
2044
  productName: pp.product.name,
2030
2045
  brandId: pp.product.brandId,
@@ -8712,15 +8727,8 @@ var PractitionerService = class extends BaseService {
8712
8727
  price: 0,
8713
8728
  currency: "EUR" /* EUR */,
8714
8729
  pricingMeasure: "per_session" /* PER_SESSION */,
8715
- productsMetadata: [
8716
- {
8717
- productId: "free-consultation-product",
8718
- price: 0,
8719
- currency: "EUR" /* EUR */,
8720
- pricingMeasure: "per_session" /* PER_SESSION */,
8721
- isDefault: true
8722
- }
8723
- ],
8730
+ productsMetadata: void 0,
8731
+ // No products needed for consultations
8724
8732
  duration: 30,
8725
8733
  // 30 minutes consultation
8726
8734
  practitionerId,
@@ -16314,11 +16322,11 @@ var createProcedureSchema = import_zod26.z.object({
16314
16322
  categoryId: import_zod26.z.string().min(1),
16315
16323
  subcategoryId: import_zod26.z.string().min(1),
16316
16324
  technologyId: import_zod26.z.string().min(1),
16317
- productId: import_zod26.z.string().min(1),
16325
+ productId: import_zod26.z.string().min(1).optional(),
16318
16326
  price: import_zod26.z.number().min(0),
16319
16327
  currency: import_zod26.z.nativeEnum(Currency),
16320
16328
  pricingMeasure: import_zod26.z.nativeEnum(PricingMeasure),
16321
- productsMetadata: import_zod26.z.array(procedureProductDataSchema).min(1),
16329
+ productsMetadata: import_zod26.z.array(procedureProductDataSchema).min(1).optional(),
16322
16330
  duration: import_zod26.z.number().min(1).max(480),
16323
16331
  // Max 8 hours
16324
16332
  practitionerId: import_zod26.z.string().min(1),
@@ -16355,10 +16363,10 @@ var procedureSchema = import_zod26.z.object({
16355
16363
  // We'll validate the full subcategory object separately
16356
16364
  technology: import_zod26.z.any(),
16357
16365
  // We'll validate the full technology object separately
16358
- product: import_zod26.z.any(),
16359
- // We'll validate the full product object separately
16360
- productsMetadata: import_zod26.z.array(storedProcedureProductSchema).min(1),
16361
- // Use stored format schema
16366
+ product: import_zod26.z.any().optional(),
16367
+ // We'll validate the full product object separately (optional for consultations)
16368
+ productsMetadata: import_zod26.z.array(storedProcedureProductSchema).optional(),
16369
+ // Use stored format schema (optional for consultations)
16362
16370
  price: import_zod26.z.number().min(0),
16363
16371
  currency: import_zod26.z.nativeEnum(Currency),
16364
16372
  pricingMeasure: import_zod26.z.nativeEnum(PricingMeasure),
@@ -16451,11 +16459,14 @@ var ProcedureService = class extends BaseService {
16451
16459
  }
16452
16460
  /**
16453
16461
  * Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
16454
- * @param productsMetadata Array of validated procedure product data
16462
+ * @param productsMetadata Array of validated procedure product data (optional)
16455
16463
  * @param technologyId Technology ID to fetch products from
16456
16464
  * @returns Array of ProcedureProduct objects with full product information
16457
16465
  */
16458
16466
  async transformProductsMetadata(productsMetadata, technologyId) {
16467
+ if (!productsMetadata || productsMetadata.length === 0) {
16468
+ return [];
16469
+ }
16459
16470
  const transformedProducts = [];
16460
16471
  for (const productData of productsMetadata) {
16461
16472
  const product = await this.productService.getById(technologyId, productData.productId);
@@ -16482,12 +16493,16 @@ var ProcedureService = class extends BaseService {
16482
16493
  async createProcedure(data) {
16483
16494
  var _a, _b, _c;
16484
16495
  const validatedData = createProcedureSchema.parse(data);
16496
+ if (!validatedData.productId) {
16497
+ throw new Error("productId is required for regular procedures. Use createConsultationProcedure for product-free procedures.");
16498
+ }
16485
16499
  const procedureId = this.generateId();
16486
16500
  const [category, subcategory, technology, product] = await Promise.all([
16487
16501
  this.categoryService.getById(validatedData.categoryId),
16488
16502
  this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
16489
16503
  this.technologyService.getById(validatedData.technologyId),
16490
16504
  this.productService.getById(validatedData.technologyId, validatedData.productId)
16505
+ // Safe: validated above
16491
16506
  ]);
16492
16507
  if (!category || !subcategory || !technology || !product) {
16493
16508
  throw new Error("One or more required base entities not found");
@@ -16596,6 +16611,9 @@ var ProcedureService = class extends BaseService {
16596
16611
  if (!practitionerIds || practitionerIds.length === 0) {
16597
16612
  throw new Error("Practitioner IDs array cannot be empty.");
16598
16613
  }
16614
+ if (!baseData.productId) {
16615
+ throw new Error("productId is required for regular procedures. Use createConsultationProcedure for product-free procedures.");
16616
+ }
16599
16617
  const validationData = { ...baseData, practitionerId: practitionerIds[0] };
16600
16618
  const validatedData = createProcedureSchema.parse(validationData);
16601
16619
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
@@ -16603,6 +16621,7 @@ var ProcedureService = class extends BaseService {
16603
16621
  this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
16604
16622
  this.technologyService.getById(validatedData.technologyId),
16605
16623
  this.productService.getById(validatedData.technologyId, validatedData.productId),
16624
+ // Safe: validated above
16606
16625
  (0, import_firestore55.getDoc)((0, import_firestore55.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
16607
16626
  ]);
16608
16627
  if (!category || !subcategory || !technology || !product) {
@@ -17463,20 +17482,6 @@ var ProcedureService = class extends BaseService {
17463
17482
  rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
17464
17483
  services: practitioner.procedures || []
17465
17484
  };
17466
- const consultationProduct = {
17467
- id: "consultation-no-product",
17468
- name: "No Product Required",
17469
- description: "Consultation procedures do not require specific products",
17470
- brandId: "consultation-brand",
17471
- brandName: "Consultation",
17472
- technologyId: data.technologyId,
17473
- technologyName: technology.name,
17474
- categoryId: technology.categoryId,
17475
- subcategoryId: technology.subcategoryId,
17476
- isActive: true,
17477
- createdAt: /* @__PURE__ */ new Date(),
17478
- updatedAt: /* @__PURE__ */ new Date()
17479
- };
17480
17485
  const { productsMetadata: _, ...dataWithoutProductsMetadata } = data;
17481
17486
  const newProcedure = {
17482
17487
  id: procedureId,
@@ -17486,10 +17491,10 @@ var ProcedureService = class extends BaseService {
17486
17491
  category,
17487
17492
  subcategory,
17488
17493
  technology,
17489
- product: consultationProduct,
17490
- // Use placeholder product
17494
+ product: void 0,
17495
+ // No product needed for consultations
17491
17496
  productsMetadata: transformedProductsMetadata,
17492
- // Use transformed data, not original
17497
+ // Empty array for consultations
17493
17498
  blockingConditions: technology.blockingConditions,
17494
17499
  contraindications: technology.contraindications || [],
17495
17500
  contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],