@blackcode_sa/metaestetics-api 1.12.65 → 1.12.66
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 +2 -0
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.js +45 -4
- package/dist/admin/index.mjs +45 -4
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -11
- package/dist/index.mjs +53 -11
- 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 +689 -641
- 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 +10 -10
- 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 -1083
- 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 -163
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- 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 -2505
- 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 +1715 -1715
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +683 -636
- 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 +480 -480
- 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 -275
- 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 +132 -130
- 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 -217
- 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 +195 -189
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,433 +1,433 @@
|
|
|
1
|
-
import * as admin from "firebase-admin";
|
|
2
|
-
import { DoctorInfo } from "../../../types/clinic";
|
|
3
|
-
import { PROCEDURES_COLLECTION } from "../../../types/procedure";
|
|
4
|
-
import { PRACTITIONERS_COLLECTION } from "../../../types/practitioner";
|
|
5
|
-
import { PATIENTS_COLLECTION } from "../../../types/patient";
|
|
6
|
-
import { CLINICS_COLLECTION } from "../../../types/clinic";
|
|
7
|
-
|
|
8
|
-
const CALENDAR_SUBCOLLECTION_ID = "calendar";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @class PractitionerAggregationService
|
|
12
|
-
* @description Handles aggregation tasks related to practitioner data updates/deletions.
|
|
13
|
-
*/
|
|
14
|
-
export class PractitionerAggregationService {
|
|
15
|
-
private db: admin.firestore.Firestore;
|
|
16
|
-
|
|
17
|
-
constructor(firestore?: admin.firestore.Firestore) {
|
|
18
|
-
this.db = firestore || admin.firestore();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Adds practitioner information to a clinic when a new practitioner is created
|
|
23
|
-
* @param clinicId - ID of the clinic to update
|
|
24
|
-
* @param doctorInfo - Doctor information to add to the clinic
|
|
25
|
-
* @returns {Promise<void>}
|
|
26
|
-
*/
|
|
27
|
-
async addPractitionerToClinic(
|
|
28
|
-
clinicId: string,
|
|
29
|
-
doctorInfo: DoctorInfo
|
|
30
|
-
): Promise<void> {
|
|
31
|
-
if (!clinicId || !doctorInfo) {
|
|
32
|
-
console.log(
|
|
33
|
-
"[PractitionerAggregationService] Missing clinicId or doctorInfo for adding practitioner to clinic. Skipping."
|
|
34
|
-
);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const practitionerId = doctorInfo.id;
|
|
39
|
-
console.log(
|
|
40
|
-
`[PractitionerAggregationService] Adding practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
await clinicRef.update({
|
|
47
|
-
doctors: admin.firestore.FieldValue.arrayUnion(practitionerId),
|
|
48
|
-
doctorsInfo: admin.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
49
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
console.log(
|
|
53
|
-
`[PractitionerAggregationService] Successfully added practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
54
|
-
);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error(
|
|
57
|
-
`[PractitionerAggregationService] Error adding practitioner ${practitionerId} to clinic ${clinicId}:`,
|
|
58
|
-
error
|
|
59
|
-
);
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Updates practitioner information in associated clinics
|
|
66
|
-
* @param clinicIds - IDs of clinics associated with the practitioner
|
|
67
|
-
* @param doctorInfo - Updated doctor information
|
|
68
|
-
* @returns {Promise<void>}
|
|
69
|
-
*/
|
|
70
|
-
async updatePractitionerInfoInClinics(
|
|
71
|
-
clinicIds: string[],
|
|
72
|
-
doctorInfo: DoctorInfo
|
|
73
|
-
): Promise<void> {
|
|
74
|
-
if (!clinicIds || clinicIds.length === 0 || !doctorInfo) {
|
|
75
|
-
console.log(
|
|
76
|
-
"[PractitionerAggregationService] Missing clinicIds or doctorInfo for updating practitioner in clinics. Skipping."
|
|
77
|
-
);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const batch = this.db.batch();
|
|
82
|
-
const practitionerId = doctorInfo.id;
|
|
83
|
-
|
|
84
|
-
console.log(
|
|
85
|
-
`[PractitionerAggregationService] Starting batch update of practitioner ${practitionerId} in ${clinicIds.length} clinics.`
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
for (const clinicId of clinicIds) {
|
|
89
|
-
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
90
|
-
|
|
91
|
-
// Remove old doctor info based on ID matcher
|
|
92
|
-
batch.update(clinicRef, {
|
|
93
|
-
doctorsInfo: admin.firestore.FieldValue.arrayRemove({
|
|
94
|
-
id: practitionerId,
|
|
95
|
-
}),
|
|
96
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
97
|
-
});
|
|
98
|
-
// Add updated doctor info
|
|
99
|
-
batch.update(clinicRef, {
|
|
100
|
-
doctorsInfo: admin.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
101
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
await batch.commit();
|
|
107
|
-
console.log(
|
|
108
|
-
`[PractitionerAggregationService] Successfully updated practitioner ${practitionerId} info in ${clinicIds.length} clinics.`
|
|
109
|
-
);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.error(
|
|
112
|
-
`[PractitionerAggregationService] Error updating practitioner ${practitionerId} info in clinics:`,
|
|
113
|
-
error
|
|
114
|
-
);
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Updates practitioner information in associated procedures
|
|
121
|
-
* @param procedureIds - IDs of procedures associated with the practitioner
|
|
122
|
-
* @param doctorInfo - Updated doctor information
|
|
123
|
-
* @returns {Promise<void>}
|
|
124
|
-
*/
|
|
125
|
-
async updatePractitionerInfoInProcedures(
|
|
126
|
-
procedureIds: string[],
|
|
127
|
-
doctorInfo: DoctorInfo
|
|
128
|
-
): Promise<void> {
|
|
129
|
-
if (!procedureIds || procedureIds.length === 0 || !doctorInfo) {
|
|
130
|
-
console.log(
|
|
131
|
-
"[PractitionerAggregationService] Missing procedureIds or doctorInfo for updating practitioner in procedures. Skipping."
|
|
132
|
-
);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const batch = this.db.batch();
|
|
137
|
-
const practitionerId = doctorInfo.id;
|
|
138
|
-
|
|
139
|
-
console.log(
|
|
140
|
-
`[PractitionerAggregationService] Starting batch update of practitioner ${practitionerId} in ${procedureIds.length} procedures.`
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
for (const procedureId of procedureIds) {
|
|
144
|
-
const procedureRef = this.db
|
|
145
|
-
.collection(PROCEDURES_COLLECTION)
|
|
146
|
-
.doc(procedureId);
|
|
147
|
-
|
|
148
|
-
// Update the embedded doctorInfo object directly
|
|
149
|
-
batch.update(procedureRef, {
|
|
150
|
-
doctorInfo: doctorInfo,
|
|
151
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
await batch.commit();
|
|
157
|
-
console.log(
|
|
158
|
-
`[PractitionerAggregationService] Successfully updated practitioner ${practitionerId} info in ${procedureIds.length} procedures.`
|
|
159
|
-
);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error(
|
|
162
|
-
`[PractitionerAggregationService] Error updating practitioner ${practitionerId} info in procedures:`,
|
|
163
|
-
error
|
|
164
|
-
);
|
|
165
|
-
throw error;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Updates practitioner information in calendar events
|
|
171
|
-
* @param practitionerId - ID of the practitioner
|
|
172
|
-
* @param practitionerInfo - Updated practitioner information
|
|
173
|
-
* @returns {Promise<void>}
|
|
174
|
-
*/
|
|
175
|
-
async updatePractitionerInfoInCalendarEvents(
|
|
176
|
-
practitionerId: string,
|
|
177
|
-
practitionerInfo: DoctorInfo
|
|
178
|
-
): Promise<void> {
|
|
179
|
-
if (!practitionerId || !practitionerInfo) {
|
|
180
|
-
console.log(
|
|
181
|
-
"[PractitionerAggregationService] Missing practitionerId or practitionerInfo for calendar update. Skipping."
|
|
182
|
-
);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
console.log(
|
|
187
|
-
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to update practitioner info.`
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
const now = admin.firestore.Timestamp.now();
|
|
191
|
-
// Use a Collection Group query
|
|
192
|
-
const calendarEventsQuery = this.db
|
|
193
|
-
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
194
|
-
.where("practitionerId", "==", practitionerId)
|
|
195
|
-
.where("eventTime.start", ">", now);
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
const snapshot = await calendarEventsQuery.get();
|
|
199
|
-
if (snapshot.empty) {
|
|
200
|
-
console.log(
|
|
201
|
-
`[PractitionerAggregationService] No upcoming calendar events found for practitioner ${practitionerId}. No doctor info updates needed.`
|
|
202
|
-
);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const batch = this.db.batch();
|
|
207
|
-
snapshot.docs.forEach((doc) => {
|
|
208
|
-
console.log(
|
|
209
|
-
`[PractitionerAggregationService] Updating practitioner info for calendar event ${doc.ref.path}`
|
|
210
|
-
);
|
|
211
|
-
batch.update(doc.ref, {
|
|
212
|
-
practitionerInfo: practitionerInfo,
|
|
213
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
await batch.commit();
|
|
218
|
-
console.log(
|
|
219
|
-
`[PractitionerAggregationService] Successfully updated practitioner info in ${snapshot.size} upcoming calendar events for practitioner ${practitionerId}.`
|
|
220
|
-
);
|
|
221
|
-
} catch (error) {
|
|
222
|
-
console.error(
|
|
223
|
-
`[PractitionerAggregationService] Error updating practitioner info in calendar events for practitioner ${practitionerId}:`,
|
|
224
|
-
error
|
|
225
|
-
);
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Removes practitioner from clinics when a practitioner is deleted
|
|
232
|
-
* @param clinicIds - IDs of clinics associated with the practitioner
|
|
233
|
-
* @param practitionerId - ID of the deleted practitioner
|
|
234
|
-
* @returns {Promise<void>}
|
|
235
|
-
*/
|
|
236
|
-
async removePractitionerFromClinics(
|
|
237
|
-
clinicIds: string[],
|
|
238
|
-
practitionerId: string
|
|
239
|
-
): Promise<void> {
|
|
240
|
-
if (!clinicIds || clinicIds.length === 0 || !practitionerId) {
|
|
241
|
-
console.log(
|
|
242
|
-
"[PractitionerAggregationService] Missing clinicIds or practitionerId for removing practitioner from clinics. Skipping."
|
|
243
|
-
);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const batch = this.db.batch();
|
|
248
|
-
|
|
249
|
-
console.log(
|
|
250
|
-
`[PractitionerAggregationService] Starting batch removal of practitioner ${practitionerId} from ${clinicIds.length} clinics.`
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
for (const clinicId of clinicIds) {
|
|
254
|
-
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
255
|
-
|
|
256
|
-
// Remove doctor ID from doctors array
|
|
257
|
-
batch.update(clinicRef, {
|
|
258
|
-
doctors: admin.firestore.FieldValue.arrayRemove(practitionerId),
|
|
259
|
-
// Remove all doctor info objects where id matches the practitioner ID
|
|
260
|
-
doctorsInfo: admin.firestore.FieldValue.arrayRemove({
|
|
261
|
-
id: practitionerId,
|
|
262
|
-
}),
|
|
263
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
await batch.commit();
|
|
269
|
-
console.log(
|
|
270
|
-
`[PractitionerAggregationService] Successfully removed practitioner ${practitionerId} from ${clinicIds.length} clinics.`
|
|
271
|
-
);
|
|
272
|
-
} catch (error) {
|
|
273
|
-
console.error(
|
|
274
|
-
`[PractitionerAggregationService] Error removing practitioner ${practitionerId} from clinics:`,
|
|
275
|
-
error
|
|
276
|
-
);
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Cancels all upcoming calendar events for a deleted practitioner
|
|
283
|
-
* @param practitionerId - ID of the deleted practitioner
|
|
284
|
-
* @returns {Promise<void>}
|
|
285
|
-
*/
|
|
286
|
-
async cancelUpcomingCalendarEventsForPractitioner(
|
|
287
|
-
practitionerId: string
|
|
288
|
-
): Promise<void> {
|
|
289
|
-
if (!practitionerId) {
|
|
290
|
-
console.log(
|
|
291
|
-
"[PractitionerAggregationService] Missing practitionerId for canceling calendar events. Skipping."
|
|
292
|
-
);
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
console.log(
|
|
297
|
-
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to cancel.`
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
const now = admin.firestore.Timestamp.now();
|
|
301
|
-
// Use a Collection Group query
|
|
302
|
-
const calendarEventsQuery = this.db
|
|
303
|
-
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
304
|
-
.where("practitionerId", "==", practitionerId)
|
|
305
|
-
.where("eventTime.start", ">", now);
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
const snapshot = await calendarEventsQuery.get();
|
|
309
|
-
if (snapshot.empty) {
|
|
310
|
-
console.log(
|
|
311
|
-
`[PractitionerAggregationService] No upcoming calendar events found for practitioner ${practitionerId}. No events to cancel.`
|
|
312
|
-
);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const batch = this.db.batch();
|
|
317
|
-
snapshot.docs.forEach((doc) => {
|
|
318
|
-
console.log(
|
|
319
|
-
`[PractitionerAggregationService] Canceling calendar event ${doc.ref.path}`
|
|
320
|
-
);
|
|
321
|
-
batch.update(doc.ref, {
|
|
322
|
-
status: "CANCELED",
|
|
323
|
-
cancelReason: "Practitioner deleted",
|
|
324
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
await batch.commit();
|
|
329
|
-
console.log(
|
|
330
|
-
`[PractitionerAggregationService] Successfully canceled ${snapshot.size} upcoming calendar events for practitioner ${practitionerId}.`
|
|
331
|
-
);
|
|
332
|
-
} catch (error) {
|
|
333
|
-
console.error(
|
|
334
|
-
`[PractitionerAggregationService] Error canceling calendar events for practitioner ${practitionerId}:`,
|
|
335
|
-
error
|
|
336
|
-
);
|
|
337
|
-
throw error;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Removes practitioner from patients when a practitioner is deleted
|
|
343
|
-
* @param patientIds - IDs of patients associated with the practitioner
|
|
344
|
-
* @param practitionerId - ID of the deleted practitioner
|
|
345
|
-
* @returns {Promise<void>}
|
|
346
|
-
*/
|
|
347
|
-
async removePractitionerFromPatients(
|
|
348
|
-
patientIds: string[],
|
|
349
|
-
practitionerId: string
|
|
350
|
-
): Promise<void> {
|
|
351
|
-
if (!patientIds || patientIds.length === 0 || !practitionerId) {
|
|
352
|
-
console.log(
|
|
353
|
-
"[PractitionerAggregationService] Missing patientIds or practitionerId for removing practitioner from patients. Skipping."
|
|
354
|
-
);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const batch = this.db.batch();
|
|
359
|
-
|
|
360
|
-
console.log(
|
|
361
|
-
`[PractitionerAggregationService] Starting batch removal of practitioner ${practitionerId} from ${patientIds.length} patients.`
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
for (const patientId of patientIds) {
|
|
365
|
-
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
366
|
-
|
|
367
|
-
// Remove doctor ID from doctorIds array
|
|
368
|
-
batch.update(patientRef, {
|
|
369
|
-
doctorIds: admin.firestore.FieldValue.arrayRemove(practitionerId),
|
|
370
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
try {
|
|
375
|
-
await batch.commit();
|
|
376
|
-
console.log(
|
|
377
|
-
`[PractitionerAggregationService] Successfully removed practitioner ${practitionerId} from ${patientIds.length} patients.`
|
|
378
|
-
);
|
|
379
|
-
} catch (error) {
|
|
380
|
-
console.error(
|
|
381
|
-
`[PractitionerAggregationService] Error removing practitioner ${practitionerId} from patients:`,
|
|
382
|
-
error
|
|
383
|
-
);
|
|
384
|
-
throw error;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Inactivates all procedures associated with a deleted practitioner
|
|
390
|
-
* @param procedureIds - IDs of procedures provided by the practitioner
|
|
391
|
-
* @returns {Promise<void>}
|
|
392
|
-
*/
|
|
393
|
-
async inactivateProceduresForPractitioner(
|
|
394
|
-
procedureIds: string[]
|
|
395
|
-
): Promise<void> {
|
|
396
|
-
if (!procedureIds || procedureIds.length === 0) {
|
|
397
|
-
console.log(
|
|
398
|
-
"[PractitionerAggregationService] No procedure IDs provided for inactivation. Skipping."
|
|
399
|
-
);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const batch = this.db.batch();
|
|
404
|
-
|
|
405
|
-
console.log(
|
|
406
|
-
`[PractitionerAggregationService] Starting inactivation of ${procedureIds.length} procedures.`
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
for (const procedureId of procedureIds) {
|
|
410
|
-
const procedureRef = this.db
|
|
411
|
-
.collection(PROCEDURES_COLLECTION)
|
|
412
|
-
.doc(procedureId);
|
|
413
|
-
|
|
414
|
-
batch.update(procedureRef, {
|
|
415
|
-
isActive: false,
|
|
416
|
-
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
try {
|
|
421
|
-
await batch.commit();
|
|
422
|
-
console.log(
|
|
423
|
-
`[PractitionerAggregationService] Successfully inactivated ${procedureIds.length} procedures.`
|
|
424
|
-
);
|
|
425
|
-
} catch (error) {
|
|
426
|
-
console.error(
|
|
427
|
-
`[PractitionerAggregationService] Error committing batch inactivation of procedures:`,
|
|
428
|
-
error
|
|
429
|
-
);
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
1
|
+
import * as admin from "firebase-admin";
|
|
2
|
+
import { DoctorInfo } from "../../../types/clinic";
|
|
3
|
+
import { PROCEDURES_COLLECTION } from "../../../types/procedure";
|
|
4
|
+
import { PRACTITIONERS_COLLECTION } from "../../../types/practitioner";
|
|
5
|
+
import { PATIENTS_COLLECTION } from "../../../types/patient";
|
|
6
|
+
import { CLINICS_COLLECTION } from "../../../types/clinic";
|
|
7
|
+
|
|
8
|
+
const CALENDAR_SUBCOLLECTION_ID = "calendar";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @class PractitionerAggregationService
|
|
12
|
+
* @description Handles aggregation tasks related to practitioner data updates/deletions.
|
|
13
|
+
*/
|
|
14
|
+
export class PractitionerAggregationService {
|
|
15
|
+
private db: admin.firestore.Firestore;
|
|
16
|
+
|
|
17
|
+
constructor(firestore?: admin.firestore.Firestore) {
|
|
18
|
+
this.db = firestore || admin.firestore();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Adds practitioner information to a clinic when a new practitioner is created
|
|
23
|
+
* @param clinicId - ID of the clinic to update
|
|
24
|
+
* @param doctorInfo - Doctor information to add to the clinic
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async addPractitionerToClinic(
|
|
28
|
+
clinicId: string,
|
|
29
|
+
doctorInfo: DoctorInfo
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
if (!clinicId || !doctorInfo) {
|
|
32
|
+
console.log(
|
|
33
|
+
"[PractitionerAggregationService] Missing clinicId or doctorInfo for adding practitioner to clinic. Skipping."
|
|
34
|
+
);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const practitionerId = doctorInfo.id;
|
|
39
|
+
console.log(
|
|
40
|
+
`[PractitionerAggregationService] Adding practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await clinicRef.update({
|
|
47
|
+
doctors: admin.firestore.FieldValue.arrayUnion(practitionerId),
|
|
48
|
+
doctorsInfo: admin.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
49
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log(
|
|
53
|
+
`[PractitionerAggregationService] Successfully added practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
54
|
+
);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error(
|
|
57
|
+
`[PractitionerAggregationService] Error adding practitioner ${practitionerId} to clinic ${clinicId}:`,
|
|
58
|
+
error
|
|
59
|
+
);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Updates practitioner information in associated clinics
|
|
66
|
+
* @param clinicIds - IDs of clinics associated with the practitioner
|
|
67
|
+
* @param doctorInfo - Updated doctor information
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async updatePractitionerInfoInClinics(
|
|
71
|
+
clinicIds: string[],
|
|
72
|
+
doctorInfo: DoctorInfo
|
|
73
|
+
): Promise<void> {
|
|
74
|
+
if (!clinicIds || clinicIds.length === 0 || !doctorInfo) {
|
|
75
|
+
console.log(
|
|
76
|
+
"[PractitionerAggregationService] Missing clinicIds or doctorInfo for updating practitioner in clinics. Skipping."
|
|
77
|
+
);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const batch = this.db.batch();
|
|
82
|
+
const practitionerId = doctorInfo.id;
|
|
83
|
+
|
|
84
|
+
console.log(
|
|
85
|
+
`[PractitionerAggregationService] Starting batch update of practitioner ${practitionerId} in ${clinicIds.length} clinics.`
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
for (const clinicId of clinicIds) {
|
|
89
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
90
|
+
|
|
91
|
+
// Remove old doctor info based on ID matcher
|
|
92
|
+
batch.update(clinicRef, {
|
|
93
|
+
doctorsInfo: admin.firestore.FieldValue.arrayRemove({
|
|
94
|
+
id: practitionerId,
|
|
95
|
+
}),
|
|
96
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
97
|
+
});
|
|
98
|
+
// Add updated doctor info
|
|
99
|
+
batch.update(clinicRef, {
|
|
100
|
+
doctorsInfo: admin.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
101
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await batch.commit();
|
|
107
|
+
console.log(
|
|
108
|
+
`[PractitionerAggregationService] Successfully updated practitioner ${practitionerId} info in ${clinicIds.length} clinics.`
|
|
109
|
+
);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(
|
|
112
|
+
`[PractitionerAggregationService] Error updating practitioner ${practitionerId} info in clinics:`,
|
|
113
|
+
error
|
|
114
|
+
);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Updates practitioner information in associated procedures
|
|
121
|
+
* @param procedureIds - IDs of procedures associated with the practitioner
|
|
122
|
+
* @param doctorInfo - Updated doctor information
|
|
123
|
+
* @returns {Promise<void>}
|
|
124
|
+
*/
|
|
125
|
+
async updatePractitionerInfoInProcedures(
|
|
126
|
+
procedureIds: string[],
|
|
127
|
+
doctorInfo: DoctorInfo
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
if (!procedureIds || procedureIds.length === 0 || !doctorInfo) {
|
|
130
|
+
console.log(
|
|
131
|
+
"[PractitionerAggregationService] Missing procedureIds or doctorInfo for updating practitioner in procedures. Skipping."
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const batch = this.db.batch();
|
|
137
|
+
const practitionerId = doctorInfo.id;
|
|
138
|
+
|
|
139
|
+
console.log(
|
|
140
|
+
`[PractitionerAggregationService] Starting batch update of practitioner ${practitionerId} in ${procedureIds.length} procedures.`
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
for (const procedureId of procedureIds) {
|
|
144
|
+
const procedureRef = this.db
|
|
145
|
+
.collection(PROCEDURES_COLLECTION)
|
|
146
|
+
.doc(procedureId);
|
|
147
|
+
|
|
148
|
+
// Update the embedded doctorInfo object directly
|
|
149
|
+
batch.update(procedureRef, {
|
|
150
|
+
doctorInfo: doctorInfo,
|
|
151
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
await batch.commit();
|
|
157
|
+
console.log(
|
|
158
|
+
`[PractitionerAggregationService] Successfully updated practitioner ${practitionerId} info in ${procedureIds.length} procedures.`
|
|
159
|
+
);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(
|
|
162
|
+
`[PractitionerAggregationService] Error updating practitioner ${practitionerId} info in procedures:`,
|
|
163
|
+
error
|
|
164
|
+
);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Updates practitioner information in calendar events
|
|
171
|
+
* @param practitionerId - ID of the practitioner
|
|
172
|
+
* @param practitionerInfo - Updated practitioner information
|
|
173
|
+
* @returns {Promise<void>}
|
|
174
|
+
*/
|
|
175
|
+
async updatePractitionerInfoInCalendarEvents(
|
|
176
|
+
practitionerId: string,
|
|
177
|
+
practitionerInfo: DoctorInfo
|
|
178
|
+
): Promise<void> {
|
|
179
|
+
if (!practitionerId || !practitionerInfo) {
|
|
180
|
+
console.log(
|
|
181
|
+
"[PractitionerAggregationService] Missing practitionerId or practitionerInfo for calendar update. Skipping."
|
|
182
|
+
);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log(
|
|
187
|
+
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to update practitioner info.`
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const now = admin.firestore.Timestamp.now();
|
|
191
|
+
// Use a Collection Group query
|
|
192
|
+
const calendarEventsQuery = this.db
|
|
193
|
+
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
194
|
+
.where("practitionerId", "==", practitionerId)
|
|
195
|
+
.where("eventTime.start", ">", now);
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const snapshot = await calendarEventsQuery.get();
|
|
199
|
+
if (snapshot.empty) {
|
|
200
|
+
console.log(
|
|
201
|
+
`[PractitionerAggregationService] No upcoming calendar events found for practitioner ${practitionerId}. No doctor info updates needed.`
|
|
202
|
+
);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const batch = this.db.batch();
|
|
207
|
+
snapshot.docs.forEach((doc) => {
|
|
208
|
+
console.log(
|
|
209
|
+
`[PractitionerAggregationService] Updating practitioner info for calendar event ${doc.ref.path}`
|
|
210
|
+
);
|
|
211
|
+
batch.update(doc.ref, {
|
|
212
|
+
practitionerInfo: practitionerInfo,
|
|
213
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
await batch.commit();
|
|
218
|
+
console.log(
|
|
219
|
+
`[PractitionerAggregationService] Successfully updated practitioner info in ${snapshot.size} upcoming calendar events for practitioner ${practitionerId}.`
|
|
220
|
+
);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error(
|
|
223
|
+
`[PractitionerAggregationService] Error updating practitioner info in calendar events for practitioner ${practitionerId}:`,
|
|
224
|
+
error
|
|
225
|
+
);
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Removes practitioner from clinics when a practitioner is deleted
|
|
232
|
+
* @param clinicIds - IDs of clinics associated with the practitioner
|
|
233
|
+
* @param practitionerId - ID of the deleted practitioner
|
|
234
|
+
* @returns {Promise<void>}
|
|
235
|
+
*/
|
|
236
|
+
async removePractitionerFromClinics(
|
|
237
|
+
clinicIds: string[],
|
|
238
|
+
practitionerId: string
|
|
239
|
+
): Promise<void> {
|
|
240
|
+
if (!clinicIds || clinicIds.length === 0 || !practitionerId) {
|
|
241
|
+
console.log(
|
|
242
|
+
"[PractitionerAggregationService] Missing clinicIds or practitionerId for removing practitioner from clinics. Skipping."
|
|
243
|
+
);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const batch = this.db.batch();
|
|
248
|
+
|
|
249
|
+
console.log(
|
|
250
|
+
`[PractitionerAggregationService] Starting batch removal of practitioner ${practitionerId} from ${clinicIds.length} clinics.`
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
for (const clinicId of clinicIds) {
|
|
254
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
255
|
+
|
|
256
|
+
// Remove doctor ID from doctors array
|
|
257
|
+
batch.update(clinicRef, {
|
|
258
|
+
doctors: admin.firestore.FieldValue.arrayRemove(practitionerId),
|
|
259
|
+
// Remove all doctor info objects where id matches the practitioner ID
|
|
260
|
+
doctorsInfo: admin.firestore.FieldValue.arrayRemove({
|
|
261
|
+
id: practitionerId,
|
|
262
|
+
}),
|
|
263
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
await batch.commit();
|
|
269
|
+
console.log(
|
|
270
|
+
`[PractitionerAggregationService] Successfully removed practitioner ${practitionerId} from ${clinicIds.length} clinics.`
|
|
271
|
+
);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error(
|
|
274
|
+
`[PractitionerAggregationService] Error removing practitioner ${practitionerId} from clinics:`,
|
|
275
|
+
error
|
|
276
|
+
);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Cancels all upcoming calendar events for a deleted practitioner
|
|
283
|
+
* @param practitionerId - ID of the deleted practitioner
|
|
284
|
+
* @returns {Promise<void>}
|
|
285
|
+
*/
|
|
286
|
+
async cancelUpcomingCalendarEventsForPractitioner(
|
|
287
|
+
practitionerId: string
|
|
288
|
+
): Promise<void> {
|
|
289
|
+
if (!practitionerId) {
|
|
290
|
+
console.log(
|
|
291
|
+
"[PractitionerAggregationService] Missing practitionerId for canceling calendar events. Skipping."
|
|
292
|
+
);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(
|
|
297
|
+
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to cancel.`
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const now = admin.firestore.Timestamp.now();
|
|
301
|
+
// Use a Collection Group query
|
|
302
|
+
const calendarEventsQuery = this.db
|
|
303
|
+
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
304
|
+
.where("practitionerId", "==", practitionerId)
|
|
305
|
+
.where("eventTime.start", ">", now);
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const snapshot = await calendarEventsQuery.get();
|
|
309
|
+
if (snapshot.empty) {
|
|
310
|
+
console.log(
|
|
311
|
+
`[PractitionerAggregationService] No upcoming calendar events found for practitioner ${practitionerId}. No events to cancel.`
|
|
312
|
+
);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const batch = this.db.batch();
|
|
317
|
+
snapshot.docs.forEach((doc) => {
|
|
318
|
+
console.log(
|
|
319
|
+
`[PractitionerAggregationService] Canceling calendar event ${doc.ref.path}`
|
|
320
|
+
);
|
|
321
|
+
batch.update(doc.ref, {
|
|
322
|
+
status: "CANCELED",
|
|
323
|
+
cancelReason: "Practitioner deleted",
|
|
324
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
await batch.commit();
|
|
329
|
+
console.log(
|
|
330
|
+
`[PractitionerAggregationService] Successfully canceled ${snapshot.size} upcoming calendar events for practitioner ${practitionerId}.`
|
|
331
|
+
);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(
|
|
334
|
+
`[PractitionerAggregationService] Error canceling calendar events for practitioner ${practitionerId}:`,
|
|
335
|
+
error
|
|
336
|
+
);
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Removes practitioner from patients when a practitioner is deleted
|
|
343
|
+
* @param patientIds - IDs of patients associated with the practitioner
|
|
344
|
+
* @param practitionerId - ID of the deleted practitioner
|
|
345
|
+
* @returns {Promise<void>}
|
|
346
|
+
*/
|
|
347
|
+
async removePractitionerFromPatients(
|
|
348
|
+
patientIds: string[],
|
|
349
|
+
practitionerId: string
|
|
350
|
+
): Promise<void> {
|
|
351
|
+
if (!patientIds || patientIds.length === 0 || !practitionerId) {
|
|
352
|
+
console.log(
|
|
353
|
+
"[PractitionerAggregationService] Missing patientIds or practitionerId for removing practitioner from patients. Skipping."
|
|
354
|
+
);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const batch = this.db.batch();
|
|
359
|
+
|
|
360
|
+
console.log(
|
|
361
|
+
`[PractitionerAggregationService] Starting batch removal of practitioner ${practitionerId} from ${patientIds.length} patients.`
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
for (const patientId of patientIds) {
|
|
365
|
+
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
366
|
+
|
|
367
|
+
// Remove doctor ID from doctorIds array
|
|
368
|
+
batch.update(patientRef, {
|
|
369
|
+
doctorIds: admin.firestore.FieldValue.arrayRemove(practitionerId),
|
|
370
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
await batch.commit();
|
|
376
|
+
console.log(
|
|
377
|
+
`[PractitionerAggregationService] Successfully removed practitioner ${practitionerId} from ${patientIds.length} patients.`
|
|
378
|
+
);
|
|
379
|
+
} catch (error) {
|
|
380
|
+
console.error(
|
|
381
|
+
`[PractitionerAggregationService] Error removing practitioner ${practitionerId} from patients:`,
|
|
382
|
+
error
|
|
383
|
+
);
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Inactivates all procedures associated with a deleted practitioner
|
|
390
|
+
* @param procedureIds - IDs of procedures provided by the practitioner
|
|
391
|
+
* @returns {Promise<void>}
|
|
392
|
+
*/
|
|
393
|
+
async inactivateProceduresForPractitioner(
|
|
394
|
+
procedureIds: string[]
|
|
395
|
+
): Promise<void> {
|
|
396
|
+
if (!procedureIds || procedureIds.length === 0) {
|
|
397
|
+
console.log(
|
|
398
|
+
"[PractitionerAggregationService] No procedure IDs provided for inactivation. Skipping."
|
|
399
|
+
);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const batch = this.db.batch();
|
|
404
|
+
|
|
405
|
+
console.log(
|
|
406
|
+
`[PractitionerAggregationService] Starting inactivation of ${procedureIds.length} procedures.`
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
for (const procedureId of procedureIds) {
|
|
410
|
+
const procedureRef = this.db
|
|
411
|
+
.collection(PROCEDURES_COLLECTION)
|
|
412
|
+
.doc(procedureId);
|
|
413
|
+
|
|
414
|
+
batch.update(procedureRef, {
|
|
415
|
+
isActive: false,
|
|
416
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
await batch.commit();
|
|
422
|
+
console.log(
|
|
423
|
+
`[PractitionerAggregationService] Successfully inactivated ${procedureIds.length} procedures.`
|
|
424
|
+
);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
console.error(
|
|
427
|
+
`[PractitionerAggregationService] Error committing batch inactivation of procedures:`,
|
|
428
|
+
error
|
|
429
|
+
);
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|