@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.
- package/dist/admin/index.d.mts +5 -4
- package/dist/admin/index.d.ts +5 -4
- package/dist/admin/index.js +3 -26
- package/dist/admin/index.mjs +3 -26
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +53 -48
- package/dist/index.mjs +53 -48
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +21 -17
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +4 -31
- package/src/services/appointment/utils/appointment.utils.ts +2 -2
- package/src/services/appointment/utils/extended-procedure.utils.ts +82 -53
- package/src/services/appointment/utils/recommended-procedure.utils.ts +8 -6
- package/src/services/appointment/utils/zone-management.utils.ts +7 -7
- package/src/services/practitioner/practitioner.service.ts +2 -10
- package/src/services/procedure/procedure.service.ts +22 -22
- package/src/types/procedure/index.ts +5 -5
- package/src/validations/appointment.schema.ts +60 -53
- package/src/validations/procedure.schema.ts +4 -4
package/dist/admin/index.d.mts
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
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
|
*/
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
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
|
*/
|
package/dist/admin/index.js
CHANGED
|
@@ -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(" \
|
|
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
|
package/dist/admin/index.mjs
CHANGED
|
@@ -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(" \
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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().
|
|
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.
|
|
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 = [
|
|
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).
|
|
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:
|
|
17490
|
-
//
|
|
17494
|
+
product: void 0,
|
|
17495
|
+
// No product needed for consultations
|
|
17491
17496
|
productsMetadata: transformedProductsMetadata,
|
|
17492
|
-
//
|
|
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)) || [],
|