@blackcode_sa/metaestetics-api 1.5.28 → 1.5.29
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 +1199 -1
- package/dist/admin/index.d.ts +1199 -1
- package/dist/admin/index.js +1337 -2
- package/dist/admin/index.mjs +1333 -2
- package/dist/backoffice/index.d.mts +99 -7
- package/dist/backoffice/index.d.ts +99 -7
- package/dist/index.d.mts +4035 -2364
- package/dist/index.d.ts +4035 -2364
- package/dist/index.js +2616 -1929
- package/dist/index.mjs +2646 -1952
- package/package.json +1 -1
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +642 -0
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -0
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -0
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +508 -0
- package/src/admin/index.ts +53 -4
- package/src/index.ts +28 -4
- package/src/services/clinic/clinic.service.ts +320 -107
- package/src/services/clinic/utils/clinic.utils.ts +66 -117
- package/src/services/clinic/utils/filter.utils.d.ts +23 -0
- package/src/services/clinic/utils/filter.utils.ts +264 -0
- package/src/services/practitioner/practitioner.service.ts +616 -5
- package/src/services/procedure/procedure.service.ts +599 -352
- package/src/services/reviews/reviews.service.ts +842 -0
- package/src/types/clinic/index.ts +24 -56
- package/src/types/practitioner/index.ts +34 -33
- package/src/types/procedure/index.ts +32 -0
- package/src/types/profile/index.ts +1 -1
- package/src/types/reviews/index.ts +126 -0
- package/src/validations/clinic.schema.ts +37 -64
- package/src/validations/practitioner.schema.ts +42 -32
- package/src/validations/procedure.schema.ts +11 -3
- package/src/validations/reviews.schema.ts +189 -0
- package/src/services/clinic/utils/review.utils.ts +0 -93
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import * as admin from "firebase-admin";
|
|
2
|
+
import { PRACTITIONERS_COLLECTION } from "../../../types/practitioner";
|
|
3
|
+
import { PROCEDURES_COLLECTION } from "../../../types/procedure";
|
|
4
|
+
import { CLINICS_COLLECTION } from "../../../types/clinic";
|
|
5
|
+
import { ProcedureSummaryInfo } from "../../../types/procedure";
|
|
6
|
+
|
|
7
|
+
const CALENDAR_SUBCOLLECTION_ID = "calendar";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @class ProcedureAggregationService
|
|
11
|
+
* @description Handles aggregation tasks related to procedure data updates/deletions.
|
|
12
|
+
*/
|
|
13
|
+
export class ProcedureAggregationService {
|
|
14
|
+
private db: admin.firestore.Firestore;
|
|
15
|
+
|
|
16
|
+
constructor(firestore?: admin.firestore.Firestore) {
|
|
17
|
+
this.db = firestore || admin.firestore();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Adds procedure information to a practitioner when a new procedure is created
|
|
22
|
+
* @param practitionerId - ID of the practitioner who performs the procedure
|
|
23
|
+
* @param procedureSummary - Summary information about the procedure
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*/
|
|
26
|
+
async addProcedureToPractitioner(
|
|
27
|
+
practitionerId: string,
|
|
28
|
+
procedureSummary: ProcedureSummaryInfo
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
if (!practitionerId || !procedureSummary) {
|
|
31
|
+
console.log(
|
|
32
|
+
"[ProcedureAggregationService] Missing practitionerId or procedureSummary for adding procedure to practitioner. Skipping."
|
|
33
|
+
);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const procedureId = procedureSummary.id;
|
|
38
|
+
console.log(
|
|
39
|
+
`[ProcedureAggregationService] Adding procedure ${procedureId} to practitioner ${practitionerId}.`
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const practitionerRef = this.db
|
|
43
|
+
.collection(PRACTITIONERS_COLLECTION)
|
|
44
|
+
.doc(practitionerId);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await practitionerRef.update({
|
|
48
|
+
procedureIds: admin.firestore.FieldValue.arrayUnion(procedureId),
|
|
49
|
+
proceduresInfo: admin.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
50
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
`[ProcedureAggregationService] Successfully added procedure ${procedureId} to practitioner ${practitionerId}.`
|
|
55
|
+
);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(
|
|
58
|
+
`[ProcedureAggregationService] Error adding procedure ${procedureId} to practitioner ${practitionerId}:`,
|
|
59
|
+
error
|
|
60
|
+
);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Adds procedure information to a clinic when a new procedure is created
|
|
67
|
+
* @param clinicId - ID of the clinic where the procedure is performed
|
|
68
|
+
* @param procedureSummary - Summary information about the procedure
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
async addProcedureToClinic(
|
|
72
|
+
clinicId: string,
|
|
73
|
+
procedureSummary: ProcedureSummaryInfo
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
if (!clinicId || !procedureSummary) {
|
|
76
|
+
console.log(
|
|
77
|
+
"[ProcedureAggregationService] Missing clinicId or procedureSummary for adding procedure to clinic. Skipping."
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const procedureId = procedureSummary.id;
|
|
83
|
+
console.log(
|
|
84
|
+
`[ProcedureAggregationService] Adding procedure ${procedureId} to clinic ${clinicId}.`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await clinicRef.update({
|
|
91
|
+
procedures: admin.firestore.FieldValue.arrayUnion(procedureId),
|
|
92
|
+
proceduresInfo: admin.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
93
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
console.log(
|
|
97
|
+
`[ProcedureAggregationService] Successfully added procedure ${procedureId} to clinic ${clinicId}.`
|
|
98
|
+
);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(
|
|
101
|
+
`[ProcedureAggregationService] Error adding procedure ${procedureId} to clinic ${clinicId}:`,
|
|
102
|
+
error
|
|
103
|
+
);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Updates procedure information in a practitioner document
|
|
110
|
+
* @param practitionerId - ID of the practitioner who performs the procedure
|
|
111
|
+
* @param procedureSummary - Updated summary information about the procedure
|
|
112
|
+
* @returns {Promise<void>}
|
|
113
|
+
*/
|
|
114
|
+
async updateProcedureInfoInPractitioner(
|
|
115
|
+
practitionerId: string,
|
|
116
|
+
procedureSummary: ProcedureSummaryInfo
|
|
117
|
+
): Promise<void> {
|
|
118
|
+
if (!practitionerId || !procedureSummary) {
|
|
119
|
+
console.log(
|
|
120
|
+
"[ProcedureAggregationService] Missing practitionerId or procedureSummary for updating procedure in practitioner. Skipping."
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const procedureId = procedureSummary.id;
|
|
126
|
+
console.log(
|
|
127
|
+
`[ProcedureAggregationService] Updating procedure ${procedureId} info in practitioner ${practitionerId}.`
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const practitionerRef = this.db
|
|
131
|
+
.collection(PRACTITIONERS_COLLECTION)
|
|
132
|
+
.doc(practitionerId);
|
|
133
|
+
|
|
134
|
+
// This requires a transaction to avoid race conditions
|
|
135
|
+
try {
|
|
136
|
+
await this.db.runTransaction(async (transaction) => {
|
|
137
|
+
const practitionerDoc = await transaction.get(practitionerRef);
|
|
138
|
+
if (!practitionerDoc.exists) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Practitioner ${practitionerId} does not exist for procedure update`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const practitionerData = practitionerDoc.data();
|
|
145
|
+
if (!practitionerData) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Practitioner ${practitionerId} data is empty for procedure update`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Get current procedures info array
|
|
152
|
+
const proceduresInfo = practitionerData.proceduresInfo || [];
|
|
153
|
+
|
|
154
|
+
// Remove the old procedure summary
|
|
155
|
+
const updatedProceduresInfo = proceduresInfo.filter(
|
|
156
|
+
(p: ProcedureSummaryInfo) => p.id !== procedureId
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Add the updated procedure summary
|
|
160
|
+
updatedProceduresInfo.push(procedureSummary);
|
|
161
|
+
|
|
162
|
+
// Update the practitioner document
|
|
163
|
+
transaction.update(practitionerRef, {
|
|
164
|
+
proceduresInfo: updatedProceduresInfo,
|
|
165
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
console.log(
|
|
170
|
+
`[ProcedureAggregationService] Successfully updated procedure ${procedureId} info in practitioner ${practitionerId}.`
|
|
171
|
+
);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
console.error(
|
|
174
|
+
`[ProcedureAggregationService] Error updating procedure ${procedureId} info in practitioner ${practitionerId}:`,
|
|
175
|
+
error
|
|
176
|
+
);
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Updates procedure information in a clinic document
|
|
183
|
+
* @param clinicId - ID of the clinic where the procedure is performed
|
|
184
|
+
* @param procedureSummary - Updated summary information about the procedure
|
|
185
|
+
* @returns {Promise<void>}
|
|
186
|
+
*/
|
|
187
|
+
async updateProcedureInfoInClinic(
|
|
188
|
+
clinicId: string,
|
|
189
|
+
procedureSummary: ProcedureSummaryInfo
|
|
190
|
+
): Promise<void> {
|
|
191
|
+
if (!clinicId || !procedureSummary) {
|
|
192
|
+
console.log(
|
|
193
|
+
"[ProcedureAggregationService] Missing clinicId or procedureSummary for updating procedure in clinic. Skipping."
|
|
194
|
+
);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const procedureId = procedureSummary.id;
|
|
199
|
+
console.log(
|
|
200
|
+
`[ProcedureAggregationService] Updating procedure ${procedureId} info in clinic ${clinicId}.`
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
204
|
+
|
|
205
|
+
// This requires a transaction to avoid race conditions
|
|
206
|
+
try {
|
|
207
|
+
await this.db.runTransaction(async (transaction) => {
|
|
208
|
+
const clinicDoc = await transaction.get(clinicRef);
|
|
209
|
+
if (!clinicDoc.exists) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`Clinic ${clinicId} does not exist for procedure update`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const clinicData = clinicDoc.data();
|
|
216
|
+
if (!clinicData) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Clinic ${clinicId} data is empty for procedure update`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Get current procedures info array
|
|
223
|
+
const proceduresInfo = clinicData.proceduresInfo || [];
|
|
224
|
+
|
|
225
|
+
// Remove the old procedure summary
|
|
226
|
+
const updatedProceduresInfo = proceduresInfo.filter(
|
|
227
|
+
(p: ProcedureSummaryInfo) => p.id !== procedureId
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// Add the updated procedure summary
|
|
231
|
+
updatedProceduresInfo.push(procedureSummary);
|
|
232
|
+
|
|
233
|
+
// Update the clinic document
|
|
234
|
+
transaction.update(clinicRef, {
|
|
235
|
+
proceduresInfo: updatedProceduresInfo,
|
|
236
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
console.log(
|
|
241
|
+
`[ProcedureAggregationService] Successfully updated procedure ${procedureId} info in clinic ${clinicId}.`
|
|
242
|
+
);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error(
|
|
245
|
+
`[ProcedureAggregationService] Error updating procedure ${procedureId} info in clinic ${clinicId}:`,
|
|
246
|
+
error
|
|
247
|
+
);
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Updates procedure information in calendar events
|
|
254
|
+
* @param procedureId - ID of the procedure
|
|
255
|
+
* @param procedureInfo - Updated procedure information
|
|
256
|
+
* @returns {Promise<void>}
|
|
257
|
+
*/
|
|
258
|
+
async updateProcedureInfoInCalendarEvents(
|
|
259
|
+
procedureId: string,
|
|
260
|
+
procedureInfo: any
|
|
261
|
+
): Promise<void> {
|
|
262
|
+
if (!procedureId || !procedureInfo) {
|
|
263
|
+
console.log(
|
|
264
|
+
"[ProcedureAggregationService] Missing procedureId or procedureInfo for calendar update. Skipping."
|
|
265
|
+
);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
console.log(
|
|
270
|
+
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to update procedure info.`
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
const now = admin.firestore.Timestamp.now();
|
|
274
|
+
// Use a Collection Group query
|
|
275
|
+
const calendarEventsQuery = this.db
|
|
276
|
+
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
277
|
+
.where("procedureId", "==", procedureId)
|
|
278
|
+
.where("eventTime.start", ">", now);
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
const snapshot = await calendarEventsQuery.get();
|
|
282
|
+
if (snapshot.empty) {
|
|
283
|
+
console.log(
|
|
284
|
+
`[ProcedureAggregationService] No upcoming calendar events found for procedure ${procedureId}. No procedure info updates needed.`
|
|
285
|
+
);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const batch = this.db.batch();
|
|
290
|
+
snapshot.docs.forEach((doc) => {
|
|
291
|
+
console.log(
|
|
292
|
+
`[ProcedureAggregationService] Updating procedure info for calendar event ${doc.ref.path}`
|
|
293
|
+
);
|
|
294
|
+
batch.update(doc.ref, {
|
|
295
|
+
procedureInfo: procedureInfo,
|
|
296
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
await batch.commit();
|
|
301
|
+
console.log(
|
|
302
|
+
`[ProcedureAggregationService] Successfully updated procedure info in ${snapshot.size} upcoming calendar events for procedure ${procedureId}.`
|
|
303
|
+
);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error(
|
|
306
|
+
`[ProcedureAggregationService] Error updating procedure info in calendar events for procedure ${procedureId}:`,
|
|
307
|
+
error
|
|
308
|
+
);
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Cancels all upcoming calendar events for a procedure
|
|
315
|
+
* @param procedureId - ID of the procedure
|
|
316
|
+
* @returns {Promise<void>}
|
|
317
|
+
*/
|
|
318
|
+
async cancelUpcomingCalendarEventsForProcedure(
|
|
319
|
+
procedureId: string
|
|
320
|
+
): Promise<void> {
|
|
321
|
+
if (!procedureId) {
|
|
322
|
+
console.log(
|
|
323
|
+
"[ProcedureAggregationService] Missing procedureId for canceling calendar events. Skipping."
|
|
324
|
+
);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
console.log(
|
|
329
|
+
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to cancel.`
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const now = admin.firestore.Timestamp.now();
|
|
333
|
+
// Use a Collection Group query
|
|
334
|
+
const calendarEventsQuery = this.db
|
|
335
|
+
.collectionGroup(CALENDAR_SUBCOLLECTION_ID)
|
|
336
|
+
.where("procedureId", "==", procedureId)
|
|
337
|
+
.where("eventTime.start", ">", now);
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
const snapshot = await calendarEventsQuery.get();
|
|
341
|
+
if (snapshot.empty) {
|
|
342
|
+
console.log(
|
|
343
|
+
`[ProcedureAggregationService] No upcoming calendar events found for procedure ${procedureId}. No events to cancel.`
|
|
344
|
+
);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const batch = this.db.batch();
|
|
349
|
+
snapshot.docs.forEach((doc) => {
|
|
350
|
+
console.log(
|
|
351
|
+
`[ProcedureAggregationService] Canceling calendar event ${doc.ref.path}`
|
|
352
|
+
);
|
|
353
|
+
batch.update(doc.ref, {
|
|
354
|
+
status: "CANCELED",
|
|
355
|
+
cancelReason: "Procedure deleted or inactivated",
|
|
356
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
await batch.commit();
|
|
361
|
+
console.log(
|
|
362
|
+
`[ProcedureAggregationService] Successfully canceled ${snapshot.size} upcoming calendar events for procedure ${procedureId}.`
|
|
363
|
+
);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.error(
|
|
366
|
+
`[ProcedureAggregationService] Error canceling calendar events for procedure ${procedureId}:`,
|
|
367
|
+
error
|
|
368
|
+
);
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Removes procedure from a practitioner when a procedure is deleted or inactivated
|
|
375
|
+
* @param practitionerId - ID of the practitioner who performs the procedure
|
|
376
|
+
* @param procedureId - ID of the procedure
|
|
377
|
+
* @returns {Promise<void>}
|
|
378
|
+
*/
|
|
379
|
+
async removeProcedureFromPractitioner(
|
|
380
|
+
practitionerId: string,
|
|
381
|
+
procedureId: string
|
|
382
|
+
): Promise<void> {
|
|
383
|
+
if (!practitionerId || !procedureId) {
|
|
384
|
+
console.log(
|
|
385
|
+
"[ProcedureAggregationService] Missing practitionerId or procedureId for removing procedure from practitioner. Skipping."
|
|
386
|
+
);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
console.log(
|
|
391
|
+
`[ProcedureAggregationService] Removing procedure ${procedureId} from practitioner ${practitionerId}.`
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
const practitionerRef = this.db
|
|
395
|
+
.collection(PRACTITIONERS_COLLECTION)
|
|
396
|
+
.doc(practitionerId);
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
await this.db.runTransaction(async (transaction) => {
|
|
400
|
+
const practitionerDoc = await transaction.get(practitionerRef);
|
|
401
|
+
if (!practitionerDoc.exists) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
`Practitioner ${practitionerId} does not exist for procedure removal`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const practitionerData = practitionerDoc.data();
|
|
408
|
+
if (!practitionerData) {
|
|
409
|
+
throw new Error(
|
|
410
|
+
`Practitioner ${practitionerId} data is empty for procedure removal`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Get current procedures info array
|
|
415
|
+
const proceduresInfo = practitionerData.proceduresInfo || [];
|
|
416
|
+
|
|
417
|
+
// Remove the procedure summary
|
|
418
|
+
const updatedProceduresInfo = proceduresInfo.filter(
|
|
419
|
+
(p: ProcedureSummaryInfo) => p.id !== procedureId
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
// Update the practitioner document
|
|
423
|
+
transaction.update(practitionerRef, {
|
|
424
|
+
procedureIds: admin.firestore.FieldValue.arrayRemove(procedureId),
|
|
425
|
+
proceduresInfo: updatedProceduresInfo,
|
|
426
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
console.log(
|
|
431
|
+
`[ProcedureAggregationService] Successfully removed procedure ${procedureId} from practitioner ${practitionerId}.`
|
|
432
|
+
);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.error(
|
|
435
|
+
`[ProcedureAggregationService] Error removing procedure ${procedureId} from practitioner ${practitionerId}:`,
|
|
436
|
+
error
|
|
437
|
+
);
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Removes procedure from a clinic when a procedure is deleted or inactivated
|
|
444
|
+
* @param clinicId - ID of the clinic where the procedure is performed
|
|
445
|
+
* @param procedureId - ID of the procedure
|
|
446
|
+
* @returns {Promise<void>}
|
|
447
|
+
*/
|
|
448
|
+
async removeProcedureFromClinic(
|
|
449
|
+
clinicId: string,
|
|
450
|
+
procedureId: string
|
|
451
|
+
): Promise<void> {
|
|
452
|
+
if (!clinicId || !procedureId) {
|
|
453
|
+
console.log(
|
|
454
|
+
"[ProcedureAggregationService] Missing clinicId or procedureId for removing procedure from clinic. Skipping."
|
|
455
|
+
);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
console.log(
|
|
460
|
+
`[ProcedureAggregationService] Removing procedure ${procedureId} from clinic ${clinicId}.`
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
await this.db.runTransaction(async (transaction) => {
|
|
467
|
+
const clinicDoc = await transaction.get(clinicRef);
|
|
468
|
+
if (!clinicDoc.exists) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`Clinic ${clinicId} does not exist for procedure removal`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const clinicData = clinicDoc.data();
|
|
475
|
+
if (!clinicData) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
`Clinic ${clinicId} data is empty for procedure removal`
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Get current procedures info array
|
|
482
|
+
const proceduresInfo = clinicData.proceduresInfo || [];
|
|
483
|
+
|
|
484
|
+
// Remove the procedure summary
|
|
485
|
+
const updatedProceduresInfo = proceduresInfo.filter(
|
|
486
|
+
(p: ProcedureSummaryInfo) => p.id !== procedureId
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
// Update the clinic document
|
|
490
|
+
transaction.update(clinicRef, {
|
|
491
|
+
procedures: admin.firestore.FieldValue.arrayRemove(procedureId),
|
|
492
|
+
proceduresInfo: updatedProceduresInfo,
|
|
493
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
console.log(
|
|
498
|
+
`[ProcedureAggregationService] Successfully removed procedure ${procedureId} from clinic ${clinicId}.`
|
|
499
|
+
);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error(
|
|
502
|
+
`[ProcedureAggregationService] Error removing procedure ${procedureId} from clinic ${clinicId}:`,
|
|
503
|
+
error
|
|
504
|
+
);
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
package/src/admin/index.ts
CHANGED
|
@@ -5,8 +5,21 @@ import {
|
|
|
5
5
|
NotificationType,
|
|
6
6
|
} from "../types/notifications";
|
|
7
7
|
import { UserRole } from "../types";
|
|
8
|
+
// Import types needed by admin consumers (like Cloud Functions)
|
|
9
|
+
import { Clinic, ClinicLocation } from "../types/clinic";
|
|
10
|
+
import { ClinicInfo } from "../types/profile";
|
|
11
|
+
import { Practitioner } from "../types/practitioner";
|
|
12
|
+
import { DoctorInfo } from "../types/clinic";
|
|
13
|
+
import { Procedure, ProcedureSummaryInfo } from "../types/procedure";
|
|
14
|
+
import { PatientProfile } from "../types/patient";
|
|
8
15
|
|
|
9
|
-
//
|
|
16
|
+
// Explicitly import the services to re-export them by name
|
|
17
|
+
import { ClinicAggregationService } from "./aggregation/clinic/clinic.aggregation.service";
|
|
18
|
+
import { PractitionerAggregationService } from "./aggregation/practitioner/practitioner.aggregation.service";
|
|
19
|
+
import { ProcedureAggregationService } from "./aggregation/procedure/procedure.aggregation.service";
|
|
20
|
+
import { PatientAggregationService } from "./aggregation/patient/patient.aggregation.service";
|
|
21
|
+
|
|
22
|
+
// Re-export types
|
|
10
23
|
export type {
|
|
11
24
|
Notification,
|
|
12
25
|
BaseNotification,
|
|
@@ -16,13 +29,49 @@ export type {
|
|
|
16
29
|
AppointmentNotification,
|
|
17
30
|
} from "../types/notifications";
|
|
18
31
|
|
|
32
|
+
// Re-export types needed by cloud functions
|
|
33
|
+
export type { Clinic, ClinicLocation } from "../types/clinic";
|
|
34
|
+
export type { ClinicInfo } from "../types/profile";
|
|
35
|
+
export type { Practitioner } from "../types/practitioner";
|
|
36
|
+
export type { DoctorInfo } from "../types/clinic";
|
|
37
|
+
export type { Procedure, ProcedureSummaryInfo } from "../types/procedure";
|
|
38
|
+
export type { PatientProfile as Patient } from "../types/patient";
|
|
39
|
+
|
|
40
|
+
// Re-export enums/consts
|
|
19
41
|
export {
|
|
20
42
|
NotificationType,
|
|
21
43
|
NotificationStatus,
|
|
22
44
|
NOTIFICATIONS_COLLECTION,
|
|
23
45
|
} from "../types/notifications";
|
|
24
|
-
|
|
25
46
|
export { UserRole } from "../types";
|
|
26
47
|
|
|
27
|
-
// Export admin
|
|
28
|
-
export {
|
|
48
|
+
// Export admin classes/services explicitly by name
|
|
49
|
+
export {
|
|
50
|
+
NotificationsAdmin,
|
|
51
|
+
ClinicAggregationService,
|
|
52
|
+
PractitionerAggregationService,
|
|
53
|
+
ProcedureAggregationService,
|
|
54
|
+
PatientAggregationService,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Main entry point for the Admin module.
|
|
59
|
+
* This module contains services and utilities intended for administrative tasks,
|
|
60
|
+
* background processing, and potentially direct use by admin interfaces or Cloud Functions.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
// --- Aggregation Services --- //
|
|
64
|
+
// Placeholder: export * from "./aggregation/practitioner/practitioner.aggregation.service";
|
|
65
|
+
// Placeholder: export * from "./aggregation/procedure/procedure.aggregation.service";
|
|
66
|
+
// Placeholder: export * from "./aggregation/patient/patient.aggregation.service";
|
|
67
|
+
|
|
68
|
+
// --- Other Admin Services/Utilities (Add as needed) --- //
|
|
69
|
+
// Example: export * from './user-management/user-management.service';
|
|
70
|
+
// Example: export * from './reporting/reporting.service';
|
|
71
|
+
|
|
72
|
+
console.log("[Admin Module] Initialized and services exported.");
|
|
73
|
+
|
|
74
|
+
// Note: Ensure that services exported here are properly initialized
|
|
75
|
+
// if they have dependencies (like Firestore db) that need to be injected.
|
|
76
|
+
// The initialization pattern might differ depending on how this module is consumed
|
|
77
|
+
// (e.g., within a larger NestJS app vs. standalone Cloud Functions).
|
package/src/index.ts
CHANGED
|
@@ -131,7 +131,6 @@ export type {
|
|
|
131
131
|
CreatePractitionerData,
|
|
132
132
|
UpdatePractitionerData,
|
|
133
133
|
PractitionerClinicProcedures,
|
|
134
|
-
PractitionerReview,
|
|
135
134
|
PractitionerWorkingHours,
|
|
136
135
|
PractitionerClinicWorkingHours,
|
|
137
136
|
CreateDraftPractitionerData,
|
|
@@ -160,15 +159,12 @@ export type {
|
|
|
160
159
|
ClinicContactInfo,
|
|
161
160
|
WorkingHours,
|
|
162
161
|
ClinicTags,
|
|
163
|
-
ClinicReview,
|
|
164
162
|
ClinicAdminSignupData,
|
|
165
163
|
ContactPerson,
|
|
166
164
|
AdminToken,
|
|
167
165
|
AdminInfo,
|
|
168
166
|
CreateAdminTokenData,
|
|
169
167
|
DoctorInfo,
|
|
170
|
-
ServiceInfo,
|
|
171
|
-
ReviewInfo,
|
|
172
168
|
CreateDefaultClinicGroupData,
|
|
173
169
|
ClinicGroupSetupData,
|
|
174
170
|
ClinicBranchSetupData,
|
|
@@ -291,3 +287,31 @@ export type {
|
|
|
291
287
|
UpdateProcedureData,
|
|
292
288
|
} from "./types/procedure";
|
|
293
289
|
export { PROCEDURES_COLLECTION } from "./types/procedure";
|
|
290
|
+
|
|
291
|
+
// Review types
|
|
292
|
+
export type {
|
|
293
|
+
ClinicReview,
|
|
294
|
+
PractitionerReview,
|
|
295
|
+
ProcedureReview,
|
|
296
|
+
ClinicReviewInfo,
|
|
297
|
+
PractitionerReviewInfo,
|
|
298
|
+
ProcedureReviewInfo,
|
|
299
|
+
Review,
|
|
300
|
+
} from "./types/reviews";
|
|
301
|
+
|
|
302
|
+
export { REVIEWS_COLLECTION } from "./types/reviews/index";
|
|
303
|
+
|
|
304
|
+
// Review schemas
|
|
305
|
+
export {
|
|
306
|
+
clinicReviewSchema,
|
|
307
|
+
createClinicReviewSchema,
|
|
308
|
+
practitionerReviewSchema,
|
|
309
|
+
createPractitionerReviewSchema,
|
|
310
|
+
procedureReviewSchema,
|
|
311
|
+
createProcedureReviewSchema,
|
|
312
|
+
clinicReviewInfoSchema,
|
|
313
|
+
practitionerReviewInfoSchema,
|
|
314
|
+
procedureReviewInfoSchema,
|
|
315
|
+
reviewSchema,
|
|
316
|
+
createReviewSchema,
|
|
317
|
+
} from "./validations/reviews.schema";
|