@blackcode_sa/metaestetics-api 1.12.62 → 1.12.64
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 +4 -2
- package/dist/admin/index.d.ts +4 -2
- package/dist/admin/index.js +4 -45
- package/dist/admin/index.mjs +4 -45
- package/dist/backoffice/index.d.mts +86 -1
- package/dist/backoffice/index.d.ts +86 -1
- package/dist/backoffice/index.js +308 -0
- package/dist/backoffice/index.mjs +306 -0
- package/dist/index.d.mts +99 -3
- package/dist/index.d.ts +99 -3
- package/dist/index.js +545 -281
- package/dist/index.mjs +867 -603
- package/package.json +119 -119
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1844 -1844
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +641 -689
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +75 -75
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +40 -40
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +318 -318
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +11 -8
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +395 -395
- package/src/backoffice/services/technology.service.ts +1083 -1070
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +62 -62
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +163 -161
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -163
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2505 -2082
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +13 -13
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +1682 -1682
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +636 -683
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/appointment/index.ts +481 -453
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +489 -489
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +44 -44
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +265 -265
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -273
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +130 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +493 -493
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -216
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +189 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,314 +1,314 @@
|
|
|
1
|
-
import { Firestore, updateDoc, serverTimestamp, doc, getDoc } from 'firebase/firestore';
|
|
2
|
-
import {
|
|
3
|
-
Appointment,
|
|
4
|
-
ExtendedProcedureInfo,
|
|
5
|
-
AppointmentProductMetadata,
|
|
6
|
-
APPOINTMENTS_COLLECTION,
|
|
7
|
-
} from '../../../types/appointment';
|
|
8
|
-
import { getAppointmentOrThrow, initializeMetadata } from './zone-management.utils';
|
|
9
|
-
import { PROCEDURES_COLLECTION } from '../../../types/procedure';
|
|
10
|
-
import {
|
|
11
|
-
initializeFormsForExtendedProcedure,
|
|
12
|
-
removeFormsForExtendedProcedure,
|
|
13
|
-
} from './form-initialization.utils';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Aggregates products from a procedure into appointmentProducts
|
|
17
|
-
* @param db Firestore instance
|
|
18
|
-
* @param procedureId Procedure ID to fetch
|
|
19
|
-
* @param existingProducts Current appointment products
|
|
20
|
-
* @returns Updated appointment products array
|
|
21
|
-
*/
|
|
22
|
-
async function aggregateProductsFromProcedure(
|
|
23
|
-
db: Firestore,
|
|
24
|
-
procedureId: string,
|
|
25
|
-
existingProducts: AppointmentProductMetadata[],
|
|
26
|
-
): Promise<AppointmentProductMetadata[]> {
|
|
27
|
-
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
28
|
-
const procedureSnap = await getDoc(procedureRef);
|
|
29
|
-
|
|
30
|
-
if (!procedureSnap.exists()) {
|
|
31
|
-
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const procedureData = procedureSnap.data();
|
|
35
|
-
|
|
36
|
-
// Get procedure products from productsMetadata array
|
|
37
|
-
const productsMetadata = procedureData.productsMetadata || [];
|
|
38
|
-
|
|
39
|
-
// Map procedure products to AppointmentProductMetadata
|
|
40
|
-
// Filter out any entries without products (safety check for product-free procedures like consultations)
|
|
41
|
-
const newProducts: AppointmentProductMetadata[] = productsMetadata
|
|
42
|
-
.filter((pp: any) => pp && pp.product)
|
|
43
|
-
.map((pp: any) => {
|
|
44
|
-
// Each item in productsMetadata is a ProcedureProduct with embedded Product
|
|
45
|
-
const product = pp.product;
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
productId: product.id,
|
|
49
|
-
productName: product.name,
|
|
50
|
-
brandId: product.brandId,
|
|
51
|
-
brandName: product.brandName,
|
|
52
|
-
procedureId: procedureId,
|
|
53
|
-
price: pp.price, // Price from ProcedureProduct
|
|
54
|
-
currency: pp.currency, // Currency from ProcedureProduct
|
|
55
|
-
unitOfMeasurement: pp.pricingMeasure, // PricingMeasure from ProcedureProduct
|
|
56
|
-
};
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Merge with existing products, avoiding duplicates
|
|
60
|
-
const productMap = new Map<string, AppointmentProductMetadata>();
|
|
61
|
-
|
|
62
|
-
// Add existing products
|
|
63
|
-
existingProducts.forEach(p => {
|
|
64
|
-
const key = `${p.productId}-${p.procedureId}`;
|
|
65
|
-
productMap.set(key, p);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Add new products
|
|
69
|
-
newProducts.forEach(p => {
|
|
70
|
-
const key = `${p.productId}-${p.procedureId}`;
|
|
71
|
-
if (!productMap.has(key)) {
|
|
72
|
-
productMap.set(key, p);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
return Array.from(productMap.values());
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Creates ExtendedProcedureInfo from procedure document
|
|
81
|
-
* @param db Firestore instance
|
|
82
|
-
* @param procedureId Procedure ID
|
|
83
|
-
* @returns Extended procedure info
|
|
84
|
-
*/
|
|
85
|
-
async function createExtendedProcedureInfo(
|
|
86
|
-
db: Firestore,
|
|
87
|
-
procedureId: string,
|
|
88
|
-
): Promise<ExtendedProcedureInfo> {
|
|
89
|
-
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
90
|
-
const procedureSnap = await getDoc(procedureRef);
|
|
91
|
-
|
|
92
|
-
if (!procedureSnap.exists()) {
|
|
93
|
-
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const data = procedureSnap.data();
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
procedureId: procedureId,
|
|
100
|
-
procedureName: data.name,
|
|
101
|
-
procedureFamily: data.family, // Use embedded family object
|
|
102
|
-
procedureCategoryId: data.category.id, // Access embedded category
|
|
103
|
-
procedureCategoryName: data.category.name, // Access embedded category
|
|
104
|
-
procedureSubCategoryId: data.subcategory.id, // Access embedded subcategory
|
|
105
|
-
procedureSubCategoryName: data.subcategory.name, // Access embedded subcategory
|
|
106
|
-
procedureTechnologyId: data.technology.id, // Access embedded technology
|
|
107
|
-
procedureTechnologyName: data.technology.name, // Access embedded technology
|
|
108
|
-
procedureProducts: (data.productsMetadata || [])
|
|
109
|
-
.filter((pp: any) => pp && pp.product) // Safety check for product-free procedures
|
|
110
|
-
.map((pp: any) => ({
|
|
111
|
-
productId: pp.product.id, // Access embedded product
|
|
112
|
-
productName: pp.product.name, // Access embedded product
|
|
113
|
-
brandId: pp.product.brandId, // Access embedded product
|
|
114
|
-
brandName: pp.product.brandName, // Access embedded product
|
|
115
|
-
})),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Adds an extended procedure to an appointment
|
|
121
|
-
* Automatically aggregates products into appointmentProducts
|
|
122
|
-
* @param db Firestore instance
|
|
123
|
-
* @param appointmentId Appointment ID
|
|
124
|
-
* @param procedureId Procedure ID to add
|
|
125
|
-
* @returns Updated appointment
|
|
126
|
-
*/
|
|
127
|
-
export async function addExtendedProcedureUtil(
|
|
128
|
-
db: Firestore,
|
|
129
|
-
appointmentId: string,
|
|
130
|
-
procedureId: string,
|
|
131
|
-
): Promise<Appointment> {
|
|
132
|
-
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
133
|
-
const metadata = initializeMetadata(appointment);
|
|
134
|
-
|
|
135
|
-
// Check if procedure is already added
|
|
136
|
-
const existingProcedure = metadata.extendedProcedures?.find(p => p.procedureId === procedureId);
|
|
137
|
-
if (existingProcedure) {
|
|
138
|
-
throw new Error(`Procedure ${procedureId} is already added to this appointment`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Create extended procedure info
|
|
142
|
-
const extendedProcedureInfo = await createExtendedProcedureInfo(db, procedureId);
|
|
143
|
-
|
|
144
|
-
// Get procedure data for forms and products
|
|
145
|
-
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
146
|
-
const procedureSnap = await getDoc(procedureRef);
|
|
147
|
-
|
|
148
|
-
if (!procedureSnap.exists()) {
|
|
149
|
-
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const procedureData = procedureSnap.data();
|
|
153
|
-
|
|
154
|
-
// Aggregate products
|
|
155
|
-
const updatedProducts = await aggregateProductsFromProcedure(
|
|
156
|
-
db,
|
|
157
|
-
procedureId,
|
|
158
|
-
metadata.appointmentProducts || [],
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
// Initialize forms for extended procedure
|
|
162
|
-
let updatedLinkedFormIds = appointment.linkedFormIds || [];
|
|
163
|
-
let updatedLinkedForms = appointment.linkedForms || [];
|
|
164
|
-
let updatedPendingUserFormsIds = appointment.pendingUserFormsIds || [];
|
|
165
|
-
|
|
166
|
-
if (procedureData.documentationTemplates && procedureData.documentationTemplates.length > 0) {
|
|
167
|
-
const formInitResult = await initializeFormsForExtendedProcedure(
|
|
168
|
-
db,
|
|
169
|
-
appointmentId,
|
|
170
|
-
procedureId,
|
|
171
|
-
procedureData.documentationTemplates,
|
|
172
|
-
appointment.patientId,
|
|
173
|
-
appointment.practitionerId,
|
|
174
|
-
appointment.clinicBranchId,
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
// Merge form IDs and info
|
|
178
|
-
updatedLinkedFormIds = [...updatedLinkedFormIds, ...formInitResult.allLinkedFormIds];
|
|
179
|
-
updatedLinkedForms = [...updatedLinkedForms, ...formInitResult.initializedFormsInfo];
|
|
180
|
-
updatedPendingUserFormsIds = [
|
|
181
|
-
...updatedPendingUserFormsIds,
|
|
182
|
-
...formInitResult.pendingUserFormsIds,
|
|
183
|
-
];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Add extended procedure
|
|
187
|
-
const extendedProcedures = [...(metadata.extendedProcedures || []), extendedProcedureInfo];
|
|
188
|
-
|
|
189
|
-
// Update appointment
|
|
190
|
-
const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
191
|
-
await updateDoc(appointmentRef, {
|
|
192
|
-
'metadata.extendedProcedures': extendedProcedures,
|
|
193
|
-
'metadata.appointmentProducts': updatedProducts,
|
|
194
|
-
linkedFormIds: updatedLinkedFormIds,
|
|
195
|
-
linkedForms: updatedLinkedForms,
|
|
196
|
-
pendingUserFormsIds: updatedPendingUserFormsIds,
|
|
197
|
-
updatedAt: serverTimestamp(),
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
return getAppointmentOrThrow(db, appointmentId);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Removes an extended procedure from an appointment
|
|
205
|
-
* Also removes:
|
|
206
|
-
* - Associated products from appointmentProducts
|
|
207
|
-
* - Associated products from zonesData (all zones)
|
|
208
|
-
* - Associated forms
|
|
209
|
-
* @param db Firestore instance
|
|
210
|
-
* @param appointmentId Appointment ID
|
|
211
|
-
* @param procedureId Procedure ID to remove
|
|
212
|
-
* @returns Updated appointment
|
|
213
|
-
*/
|
|
214
|
-
export async function removeExtendedProcedureUtil(
|
|
215
|
-
db: Firestore,
|
|
216
|
-
appointmentId: string,
|
|
217
|
-
procedureId: string,
|
|
218
|
-
): Promise<Appointment> {
|
|
219
|
-
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
220
|
-
const metadata = initializeMetadata(appointment);
|
|
221
|
-
|
|
222
|
-
if (!metadata.extendedProcedures || metadata.extendedProcedures.length === 0) {
|
|
223
|
-
throw new Error('No extended procedures found for this appointment');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Find and remove the procedure
|
|
227
|
-
const procedureIndex = metadata.extendedProcedures.findIndex(p => p.procedureId === procedureId);
|
|
228
|
-
if (procedureIndex === -1) {
|
|
229
|
-
throw new Error(`Extended procedure ${procedureId} not found in this appointment`);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Remove procedure
|
|
233
|
-
metadata.extendedProcedures.splice(procedureIndex, 1);
|
|
234
|
-
|
|
235
|
-
// Remove products associated with this procedure from appointmentProducts
|
|
236
|
-
const updatedProducts = (metadata.appointmentProducts || []).filter(
|
|
237
|
-
p => p.procedureId !== procedureId,
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
// Remove products from zonesData that belong to this procedure
|
|
241
|
-
const updatedZonesData = { ...(metadata.zonesData || {}) };
|
|
242
|
-
let productsRemovedFromZones = 0;
|
|
243
|
-
|
|
244
|
-
Object.keys(updatedZonesData).forEach(zoneId => {
|
|
245
|
-
const originalLength = updatedZonesData[zoneId].length;
|
|
246
|
-
updatedZonesData[zoneId] = updatedZonesData[zoneId].filter(item => {
|
|
247
|
-
// Keep notes and items that don't belong to this procedure
|
|
248
|
-
if (item.type === 'note') return true;
|
|
249
|
-
if (item.type === 'item' && item.belongingProcedureId !== procedureId) return true;
|
|
250
|
-
return false;
|
|
251
|
-
});
|
|
252
|
-
productsRemovedFromZones += originalLength - updatedZonesData[zoneId].length;
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
console.log(
|
|
256
|
-
`🗑️ [removeExtendedProcedure] Removed ${productsRemovedFromZones} products from zones for procedure ${procedureId}`,
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
// Remove forms associated with this procedure
|
|
260
|
-
const removedFormIds = await removeFormsForExtendedProcedure(db, appointmentId, procedureId);
|
|
261
|
-
|
|
262
|
-
// Update appointment form arrays
|
|
263
|
-
const updatedLinkedFormIds = (appointment.linkedFormIds || []).filter(
|
|
264
|
-
formId => !removedFormIds.includes(formId),
|
|
265
|
-
);
|
|
266
|
-
const updatedLinkedForms = (appointment.linkedForms || []).filter(
|
|
267
|
-
form => !removedFormIds.includes(form.formId),
|
|
268
|
-
);
|
|
269
|
-
const updatedPendingUserFormsIds = (appointment.pendingUserFormsIds || []).filter(
|
|
270
|
-
formId => !removedFormIds.includes(formId),
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
// Update appointment
|
|
274
|
-
const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
275
|
-
await updateDoc(appointmentRef, {
|
|
276
|
-
'metadata.extendedProcedures': metadata.extendedProcedures,
|
|
277
|
-
'metadata.appointmentProducts': updatedProducts,
|
|
278
|
-
'metadata.zonesData': updatedZonesData,
|
|
279
|
-
linkedFormIds: updatedLinkedFormIds,
|
|
280
|
-
linkedForms: updatedLinkedForms,
|
|
281
|
-
pendingUserFormsIds: updatedPendingUserFormsIds,
|
|
282
|
-
updatedAt: serverTimestamp(),
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
return getAppointmentOrThrow(db, appointmentId);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Gets all extended procedures for an appointment
|
|
290
|
-
* @param db Firestore instance
|
|
291
|
-
* @param appointmentId Appointment ID
|
|
292
|
-
* @returns Array of extended procedures
|
|
293
|
-
*/
|
|
294
|
-
export async function getExtendedProceduresUtil(
|
|
295
|
-
db: Firestore,
|
|
296
|
-
appointmentId: string,
|
|
297
|
-
): Promise<ExtendedProcedureInfo[]> {
|
|
298
|
-
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
299
|
-
return appointment.metadata?.extendedProcedures || [];
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Gets all aggregated products for an appointment
|
|
304
|
-
* @param db Firestore instance
|
|
305
|
-
* @param appointmentId Appointment ID
|
|
306
|
-
* @returns Array of appointment products
|
|
307
|
-
*/
|
|
308
|
-
export async function getAppointmentProductsUtil(
|
|
309
|
-
db: Firestore,
|
|
310
|
-
appointmentId: string,
|
|
311
|
-
): Promise<AppointmentProductMetadata[]> {
|
|
312
|
-
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
313
|
-
return appointment.metadata?.appointmentProducts || [];
|
|
314
|
-
}
|
|
1
|
+
import { Firestore, updateDoc, serverTimestamp, doc, getDoc } from 'firebase/firestore';
|
|
2
|
+
import {
|
|
3
|
+
Appointment,
|
|
4
|
+
ExtendedProcedureInfo,
|
|
5
|
+
AppointmentProductMetadata,
|
|
6
|
+
APPOINTMENTS_COLLECTION,
|
|
7
|
+
} from '../../../types/appointment';
|
|
8
|
+
import { getAppointmentOrThrow, initializeMetadata } from './zone-management.utils';
|
|
9
|
+
import { PROCEDURES_COLLECTION } from '../../../types/procedure';
|
|
10
|
+
import {
|
|
11
|
+
initializeFormsForExtendedProcedure,
|
|
12
|
+
removeFormsForExtendedProcedure,
|
|
13
|
+
} from './form-initialization.utils';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Aggregates products from a procedure into appointmentProducts
|
|
17
|
+
* @param db Firestore instance
|
|
18
|
+
* @param procedureId Procedure ID to fetch
|
|
19
|
+
* @param existingProducts Current appointment products
|
|
20
|
+
* @returns Updated appointment products array
|
|
21
|
+
*/
|
|
22
|
+
async function aggregateProductsFromProcedure(
|
|
23
|
+
db: Firestore,
|
|
24
|
+
procedureId: string,
|
|
25
|
+
existingProducts: AppointmentProductMetadata[],
|
|
26
|
+
): Promise<AppointmentProductMetadata[]> {
|
|
27
|
+
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
28
|
+
const procedureSnap = await getDoc(procedureRef);
|
|
29
|
+
|
|
30
|
+
if (!procedureSnap.exists()) {
|
|
31
|
+
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const procedureData = procedureSnap.data();
|
|
35
|
+
|
|
36
|
+
// Get procedure products from productsMetadata array
|
|
37
|
+
const productsMetadata = procedureData.productsMetadata || [];
|
|
38
|
+
|
|
39
|
+
// Map procedure products to AppointmentProductMetadata
|
|
40
|
+
// Filter out any entries without products (safety check for product-free procedures like consultations)
|
|
41
|
+
const newProducts: AppointmentProductMetadata[] = productsMetadata
|
|
42
|
+
.filter((pp: any) => pp && pp.product)
|
|
43
|
+
.map((pp: any) => {
|
|
44
|
+
// Each item in productsMetadata is a ProcedureProduct with embedded Product
|
|
45
|
+
const product = pp.product;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
productId: product.id,
|
|
49
|
+
productName: product.name,
|
|
50
|
+
brandId: product.brandId,
|
|
51
|
+
brandName: product.brandName,
|
|
52
|
+
procedureId: procedureId,
|
|
53
|
+
price: pp.price, // Price from ProcedureProduct
|
|
54
|
+
currency: pp.currency, // Currency from ProcedureProduct
|
|
55
|
+
unitOfMeasurement: pp.pricingMeasure, // PricingMeasure from ProcedureProduct
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Merge with existing products, avoiding duplicates
|
|
60
|
+
const productMap = new Map<string, AppointmentProductMetadata>();
|
|
61
|
+
|
|
62
|
+
// Add existing products
|
|
63
|
+
existingProducts.forEach(p => {
|
|
64
|
+
const key = `${p.productId}-${p.procedureId}`;
|
|
65
|
+
productMap.set(key, p);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Add new products
|
|
69
|
+
newProducts.forEach(p => {
|
|
70
|
+
const key = `${p.productId}-${p.procedureId}`;
|
|
71
|
+
if (!productMap.has(key)) {
|
|
72
|
+
productMap.set(key, p);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return Array.from(productMap.values());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates ExtendedProcedureInfo from procedure document
|
|
81
|
+
* @param db Firestore instance
|
|
82
|
+
* @param procedureId Procedure ID
|
|
83
|
+
* @returns Extended procedure info
|
|
84
|
+
*/
|
|
85
|
+
async function createExtendedProcedureInfo(
|
|
86
|
+
db: Firestore,
|
|
87
|
+
procedureId: string,
|
|
88
|
+
): Promise<ExtendedProcedureInfo> {
|
|
89
|
+
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
90
|
+
const procedureSnap = await getDoc(procedureRef);
|
|
91
|
+
|
|
92
|
+
if (!procedureSnap.exists()) {
|
|
93
|
+
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const data = procedureSnap.data();
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
procedureId: procedureId,
|
|
100
|
+
procedureName: data.name,
|
|
101
|
+
procedureFamily: data.family, // Use embedded family object
|
|
102
|
+
procedureCategoryId: data.category.id, // Access embedded category
|
|
103
|
+
procedureCategoryName: data.category.name, // Access embedded category
|
|
104
|
+
procedureSubCategoryId: data.subcategory.id, // Access embedded subcategory
|
|
105
|
+
procedureSubCategoryName: data.subcategory.name, // Access embedded subcategory
|
|
106
|
+
procedureTechnologyId: data.technology.id, // Access embedded technology
|
|
107
|
+
procedureTechnologyName: data.technology.name, // Access embedded technology
|
|
108
|
+
procedureProducts: (data.productsMetadata || [])
|
|
109
|
+
.filter((pp: any) => pp && pp.product) // Safety check for product-free procedures
|
|
110
|
+
.map((pp: any) => ({
|
|
111
|
+
productId: pp.product.id, // Access embedded product
|
|
112
|
+
productName: pp.product.name, // Access embedded product
|
|
113
|
+
brandId: pp.product.brandId, // Access embedded product
|
|
114
|
+
brandName: pp.product.brandName, // Access embedded product
|
|
115
|
+
})),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Adds an extended procedure to an appointment
|
|
121
|
+
* Automatically aggregates products into appointmentProducts
|
|
122
|
+
* @param db Firestore instance
|
|
123
|
+
* @param appointmentId Appointment ID
|
|
124
|
+
* @param procedureId Procedure ID to add
|
|
125
|
+
* @returns Updated appointment
|
|
126
|
+
*/
|
|
127
|
+
export async function addExtendedProcedureUtil(
|
|
128
|
+
db: Firestore,
|
|
129
|
+
appointmentId: string,
|
|
130
|
+
procedureId: string,
|
|
131
|
+
): Promise<Appointment> {
|
|
132
|
+
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
133
|
+
const metadata = initializeMetadata(appointment);
|
|
134
|
+
|
|
135
|
+
// Check if procedure is already added
|
|
136
|
+
const existingProcedure = metadata.extendedProcedures?.find(p => p.procedureId === procedureId);
|
|
137
|
+
if (existingProcedure) {
|
|
138
|
+
throw new Error(`Procedure ${procedureId} is already added to this appointment`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create extended procedure info
|
|
142
|
+
const extendedProcedureInfo = await createExtendedProcedureInfo(db, procedureId);
|
|
143
|
+
|
|
144
|
+
// Get procedure data for forms and products
|
|
145
|
+
const procedureRef = doc(db, PROCEDURES_COLLECTION, procedureId);
|
|
146
|
+
const procedureSnap = await getDoc(procedureRef);
|
|
147
|
+
|
|
148
|
+
if (!procedureSnap.exists()) {
|
|
149
|
+
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const procedureData = procedureSnap.data();
|
|
153
|
+
|
|
154
|
+
// Aggregate products
|
|
155
|
+
const updatedProducts = await aggregateProductsFromProcedure(
|
|
156
|
+
db,
|
|
157
|
+
procedureId,
|
|
158
|
+
metadata.appointmentProducts || [],
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Initialize forms for extended procedure
|
|
162
|
+
let updatedLinkedFormIds = appointment.linkedFormIds || [];
|
|
163
|
+
let updatedLinkedForms = appointment.linkedForms || [];
|
|
164
|
+
let updatedPendingUserFormsIds = appointment.pendingUserFormsIds || [];
|
|
165
|
+
|
|
166
|
+
if (procedureData.documentationTemplates && procedureData.documentationTemplates.length > 0) {
|
|
167
|
+
const formInitResult = await initializeFormsForExtendedProcedure(
|
|
168
|
+
db,
|
|
169
|
+
appointmentId,
|
|
170
|
+
procedureId,
|
|
171
|
+
procedureData.documentationTemplates,
|
|
172
|
+
appointment.patientId,
|
|
173
|
+
appointment.practitionerId,
|
|
174
|
+
appointment.clinicBranchId,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Merge form IDs and info
|
|
178
|
+
updatedLinkedFormIds = [...updatedLinkedFormIds, ...formInitResult.allLinkedFormIds];
|
|
179
|
+
updatedLinkedForms = [...updatedLinkedForms, ...formInitResult.initializedFormsInfo];
|
|
180
|
+
updatedPendingUserFormsIds = [
|
|
181
|
+
...updatedPendingUserFormsIds,
|
|
182
|
+
...formInitResult.pendingUserFormsIds,
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Add extended procedure
|
|
187
|
+
const extendedProcedures = [...(metadata.extendedProcedures || []), extendedProcedureInfo];
|
|
188
|
+
|
|
189
|
+
// Update appointment
|
|
190
|
+
const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
191
|
+
await updateDoc(appointmentRef, {
|
|
192
|
+
'metadata.extendedProcedures': extendedProcedures,
|
|
193
|
+
'metadata.appointmentProducts': updatedProducts,
|
|
194
|
+
linkedFormIds: updatedLinkedFormIds,
|
|
195
|
+
linkedForms: updatedLinkedForms,
|
|
196
|
+
pendingUserFormsIds: updatedPendingUserFormsIds,
|
|
197
|
+
updatedAt: serverTimestamp(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return getAppointmentOrThrow(db, appointmentId);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Removes an extended procedure from an appointment
|
|
205
|
+
* Also removes:
|
|
206
|
+
* - Associated products from appointmentProducts
|
|
207
|
+
* - Associated products from zonesData (all zones)
|
|
208
|
+
* - Associated forms
|
|
209
|
+
* @param db Firestore instance
|
|
210
|
+
* @param appointmentId Appointment ID
|
|
211
|
+
* @param procedureId Procedure ID to remove
|
|
212
|
+
* @returns Updated appointment
|
|
213
|
+
*/
|
|
214
|
+
export async function removeExtendedProcedureUtil(
|
|
215
|
+
db: Firestore,
|
|
216
|
+
appointmentId: string,
|
|
217
|
+
procedureId: string,
|
|
218
|
+
): Promise<Appointment> {
|
|
219
|
+
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
220
|
+
const metadata = initializeMetadata(appointment);
|
|
221
|
+
|
|
222
|
+
if (!metadata.extendedProcedures || metadata.extendedProcedures.length === 0) {
|
|
223
|
+
throw new Error('No extended procedures found for this appointment');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Find and remove the procedure
|
|
227
|
+
const procedureIndex = metadata.extendedProcedures.findIndex(p => p.procedureId === procedureId);
|
|
228
|
+
if (procedureIndex === -1) {
|
|
229
|
+
throw new Error(`Extended procedure ${procedureId} not found in this appointment`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Remove procedure
|
|
233
|
+
metadata.extendedProcedures.splice(procedureIndex, 1);
|
|
234
|
+
|
|
235
|
+
// Remove products associated with this procedure from appointmentProducts
|
|
236
|
+
const updatedProducts = (metadata.appointmentProducts || []).filter(
|
|
237
|
+
p => p.procedureId !== procedureId,
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// Remove products from zonesData that belong to this procedure
|
|
241
|
+
const updatedZonesData = { ...(metadata.zonesData || {}) };
|
|
242
|
+
let productsRemovedFromZones = 0;
|
|
243
|
+
|
|
244
|
+
Object.keys(updatedZonesData).forEach(zoneId => {
|
|
245
|
+
const originalLength = updatedZonesData[zoneId].length;
|
|
246
|
+
updatedZonesData[zoneId] = updatedZonesData[zoneId].filter(item => {
|
|
247
|
+
// Keep notes and items that don't belong to this procedure
|
|
248
|
+
if (item.type === 'note') return true;
|
|
249
|
+
if (item.type === 'item' && item.belongingProcedureId !== procedureId) return true;
|
|
250
|
+
return false;
|
|
251
|
+
});
|
|
252
|
+
productsRemovedFromZones += originalLength - updatedZonesData[zoneId].length;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
console.log(
|
|
256
|
+
`🗑️ [removeExtendedProcedure] Removed ${productsRemovedFromZones} products from zones for procedure ${procedureId}`,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
// Remove forms associated with this procedure
|
|
260
|
+
const removedFormIds = await removeFormsForExtendedProcedure(db, appointmentId, procedureId);
|
|
261
|
+
|
|
262
|
+
// Update appointment form arrays
|
|
263
|
+
const updatedLinkedFormIds = (appointment.linkedFormIds || []).filter(
|
|
264
|
+
formId => !removedFormIds.includes(formId),
|
|
265
|
+
);
|
|
266
|
+
const updatedLinkedForms = (appointment.linkedForms || []).filter(
|
|
267
|
+
form => !removedFormIds.includes(form.formId),
|
|
268
|
+
);
|
|
269
|
+
const updatedPendingUserFormsIds = (appointment.pendingUserFormsIds || []).filter(
|
|
270
|
+
formId => !removedFormIds.includes(formId),
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// Update appointment
|
|
274
|
+
const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
275
|
+
await updateDoc(appointmentRef, {
|
|
276
|
+
'metadata.extendedProcedures': metadata.extendedProcedures,
|
|
277
|
+
'metadata.appointmentProducts': updatedProducts,
|
|
278
|
+
'metadata.zonesData': updatedZonesData,
|
|
279
|
+
linkedFormIds: updatedLinkedFormIds,
|
|
280
|
+
linkedForms: updatedLinkedForms,
|
|
281
|
+
pendingUserFormsIds: updatedPendingUserFormsIds,
|
|
282
|
+
updatedAt: serverTimestamp(),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return getAppointmentOrThrow(db, appointmentId);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Gets all extended procedures for an appointment
|
|
290
|
+
* @param db Firestore instance
|
|
291
|
+
* @param appointmentId Appointment ID
|
|
292
|
+
* @returns Array of extended procedures
|
|
293
|
+
*/
|
|
294
|
+
export async function getExtendedProceduresUtil(
|
|
295
|
+
db: Firestore,
|
|
296
|
+
appointmentId: string,
|
|
297
|
+
): Promise<ExtendedProcedureInfo[]> {
|
|
298
|
+
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
299
|
+
return appointment.metadata?.extendedProcedures || [];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Gets all aggregated products for an appointment
|
|
304
|
+
* @param db Firestore instance
|
|
305
|
+
* @param appointmentId Appointment ID
|
|
306
|
+
* @returns Array of appointment products
|
|
307
|
+
*/
|
|
308
|
+
export async function getAppointmentProductsUtil(
|
|
309
|
+
db: Firestore,
|
|
310
|
+
appointmentId: string,
|
|
311
|
+
): Promise<AppointmentProductMetadata[]> {
|
|
312
|
+
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
313
|
+
return appointment.metadata?.appointmentProducts || [];
|
|
314
|
+
}
|