@blackcode_sa/metaestetics-api 1.6.3 → 1.6.5
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 +439 -25
- package/dist/admin/index.d.ts +439 -25
- package/dist/admin/index.js +36107 -2493
- package/dist/admin/index.mjs +36093 -2461
- package/dist/backoffice/index.d.mts +254 -1
- package/dist/backoffice/index.d.ts +254 -1
- package/dist/backoffice/index.js +86 -12
- package/dist/backoffice/index.mjs +86 -13
- package/dist/index.d.mts +1434 -621
- package/dist/index.d.ts +1434 -621
- package/dist/index.js +1381 -970
- package/dist/index.mjs +1433 -1016
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +321 -0
- package/src/admin/booking/booking.admin.ts +376 -3
- package/src/admin/index.ts +15 -1
- package/src/admin/notifications/notifications.admin.ts +1 -1
- package/src/admin/requirements/README.md +128 -0
- package/src/admin/requirements/patient-requirements.admin.service.ts +482 -0
- package/src/backoffice/types/product.types.ts +2 -0
- package/src/index.ts +16 -1
- package/src/services/appointment/appointment.service.ts +386 -250
- package/src/services/clinic/clinic-admin.service.ts +3 -0
- package/src/services/clinic/clinic-group.service.ts +8 -0
- package/src/services/documentation-templates/documentation-template.service.ts +24 -16
- package/src/services/documentation-templates/filled-document.service.ts +253 -136
- package/src/services/patient/patientRequirements.service.ts +285 -0
- package/src/services/procedure/procedure.service.ts +1 -0
- package/src/types/appointment/index.ts +136 -11
- package/src/types/documentation-templates/index.ts +34 -2
- package/src/types/notifications/README.md +77 -0
- package/src/types/notifications/index.ts +154 -27
- package/src/types/patient/patient-requirements.ts +81 -0
- package/src/types/procedure/index.ts +7 -0
- package/src/validations/appointment.schema.ts +298 -62
- package/src/validations/documentation-templates/template.schema.ts +55 -0
- package/src/validations/documentation-templates.schema.ts +9 -14
- package/src/validations/notification.schema.ts +3 -3
- package/src/validations/patient/patient-requirements.schema.ts +75 -0
- package/src/validations/procedure.schema.ts +3 -0
package/package.json
CHANGED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import * as admin from "firebase-admin";
|
|
2
|
+
import {
|
|
3
|
+
Appointment,
|
|
4
|
+
AppointmentStatus,
|
|
5
|
+
APPOINTMENTS_COLLECTION,
|
|
6
|
+
} from "../../../types/appointment"; // Assuming APPOINTMENTS_COLLECTION is exported here
|
|
7
|
+
import {
|
|
8
|
+
PatientRequirementInstance,
|
|
9
|
+
PatientRequirementOverallStatus,
|
|
10
|
+
PatientInstructionStatus,
|
|
11
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
12
|
+
} from "../../../types/patient/patient-requirements";
|
|
13
|
+
import {
|
|
14
|
+
Requirement as RequirementTemplate,
|
|
15
|
+
REQUIREMENTS_COLLECTION as REQUIREMENTS_TEMPLATES_COLLECTION,
|
|
16
|
+
RequirementType as RequirementTemplateType,
|
|
17
|
+
} from "../../../backoffice/types/requirement.types";
|
|
18
|
+
import { PATIENTS_COLLECTION } from "../../../types/patient";
|
|
19
|
+
|
|
20
|
+
// Dependent Admin Services
|
|
21
|
+
import { PatientRequirementsAdminService } from "../../requirements/patient-requirements.admin.service";
|
|
22
|
+
import { NotificationsAdmin } from "../../notifications/notifications.admin";
|
|
23
|
+
// import { CalendarAdminService } from "../../calendar/calendar.admin.service"; // Placeholder - To be created
|
|
24
|
+
// import { AppointmentMailingService } from "../mailing/appointment/appointment.mailing.service"; // Placeholder - To be created
|
|
25
|
+
// import { PatientAdminService } from "../patient/patient.admin.service"; // Placeholder for specific patient admin actions
|
|
26
|
+
// import { PractitionerAdminService } from "../practitioner/practitioner.admin.service"; // Placeholder for specific practitioner admin actions
|
|
27
|
+
// import { ClinicAdminService } from "../clinic/clinic.admin.service"; // Placeholder for specific clinic admin actions
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @class AppointmentAggregationService
|
|
31
|
+
* @description Handles aggregation tasks and side effects related to appointment lifecycle events.
|
|
32
|
+
* This service is intended to be used primarily by background functions (e.g., Cloud Functions)
|
|
33
|
+
* triggered by changes in the appointments collection.
|
|
34
|
+
*/
|
|
35
|
+
export class AppointmentAggregationService {
|
|
36
|
+
private db: admin.firestore.Firestore;
|
|
37
|
+
private patientRequirementsAdminService: PatientRequirementsAdminService;
|
|
38
|
+
private notificationsAdmin: NotificationsAdmin;
|
|
39
|
+
// private calendarAdminService: CalendarAdminService; // Placeholder
|
|
40
|
+
// private appointmentMailingService: AppointmentMailingService; // Placeholder
|
|
41
|
+
// private patientAdminService: PatientAdminService; // Placeholder
|
|
42
|
+
// private practitionerAdminService: PractitionerAdminService; // Placeholder
|
|
43
|
+
// private clinicAdminService: ClinicAdminService; // Placeholder
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Constructor for AppointmentAggregationService.
|
|
47
|
+
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
48
|
+
*/
|
|
49
|
+
constructor(firestore?: admin.firestore.Firestore) {
|
|
50
|
+
this.db = firestore || admin.firestore();
|
|
51
|
+
this.patientRequirementsAdminService = new PatientRequirementsAdminService(
|
|
52
|
+
this.db
|
|
53
|
+
);
|
|
54
|
+
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
55
|
+
// this.calendarAdminService = new CalendarAdminService(this.db); // Placeholder
|
|
56
|
+
// this.appointmentMailingService = new AppointmentMailingService(this.db /*, mailgunClient */); // Placeholder
|
|
57
|
+
// this.patientAdminService = new PatientAdminService(this.db); // Placeholder
|
|
58
|
+
// this.practitionerAdminService = new PractitionerAdminService(this.db); // Placeholder
|
|
59
|
+
// this.clinicAdminService = new ClinicAdminService(this.db); // Placeholder
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Handles side effects when an appointment is confirmed.
|
|
64
|
+
* - Creates PRE-appointment PatientRequirementInstances.
|
|
65
|
+
* - Triggers calendar event creation.
|
|
66
|
+
* - Triggers email/push notifications.
|
|
67
|
+
* - Manages patient-clinic-practitioner links.
|
|
68
|
+
* @param appointment - The confirmed Appointment object.
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
async handleAppointmentConfirmed(appointment: Appointment): Promise<void> {
|
|
72
|
+
console.log(
|
|
73
|
+
`[AppointmentAggregationService] Handling confirmed appointment: ${appointment.id}`
|
|
74
|
+
);
|
|
75
|
+
// 1. Create PRE-appointment PatientRequirementInstances
|
|
76
|
+
// - Fetch RequirementTemplates for procedureId
|
|
77
|
+
// - Construct and save PatientRequirementInstance documents
|
|
78
|
+
// - Rely on PatientRequirementInstance triggers for notification scheduling
|
|
79
|
+
|
|
80
|
+
// 2. Trigger calendar event creation (e.g., this.calendarAdminService.createEventForAppointment(appointment))
|
|
81
|
+
|
|
82
|
+
// 3. Trigger email/push notifications (e.g., this.appointmentMailingService.sendAppointmentConfirmedEmail(appointment))
|
|
83
|
+
|
|
84
|
+
// 4. Manage patient-clinic-practitioner links (e.g., this.managePatientClinicPractitionerLinks(appointment, 'create'))
|
|
85
|
+
|
|
86
|
+
// Example: Placeholder for creating pre-requirements
|
|
87
|
+
// const requirementTemplates = await this.fetchRequirementTemplates(appointment.procedureId, 'PRE');
|
|
88
|
+
// for (const template of requirementTemplates) {
|
|
89
|
+
// await this.createPatientRequirementInstance(appointment, template, 'PRE');
|
|
90
|
+
// }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Handles side effects when an appointment is completed.
|
|
95
|
+
* - Creates POST-appointment PatientRequirementInstances.
|
|
96
|
+
* - Triggers review request notifications.
|
|
97
|
+
* @param appointment - The completed Appointment object.
|
|
98
|
+
* @returns {Promise<void>}
|
|
99
|
+
*/
|
|
100
|
+
async handleAppointmentCompleted(appointment: Appointment): Promise<void> {
|
|
101
|
+
console.log(
|
|
102
|
+
`[AppointmentAggregationService] Handling completed appointment: ${appointment.id}`
|
|
103
|
+
);
|
|
104
|
+
// 1. Create POST-appointment PatientRequirementInstances
|
|
105
|
+
// - Fetch RequirementTemplates for procedureId
|
|
106
|
+
// - Construct and save PatientRequirementInstance documents
|
|
107
|
+
|
|
108
|
+
// 2. Trigger review request (e.g., this.appointmentMailingService.sendReviewRequestEmail(appointment))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Handles side effects when an appointment is cancelled.
|
|
113
|
+
* - Updates overallStatus of related PatientRequirementInstances to CANCELLED_APPOINTMENT.
|
|
114
|
+
* - Triggers calendar event cancellation/update.
|
|
115
|
+
* - Triggers email/push notifications for cancellation.
|
|
116
|
+
* - Evaluates patient-clinic-practitioner links.
|
|
117
|
+
* @param appointment - The cancelled Appointment object.
|
|
118
|
+
* @param previousStatus - The status of the appointment before cancellation.
|
|
119
|
+
* @returns {Promise<void>}
|
|
120
|
+
*/
|
|
121
|
+
async handleAppointmentCancelled(
|
|
122
|
+
appointment: Appointment,
|
|
123
|
+
previousStatus?: AppointmentStatus
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
console.log(
|
|
126
|
+
`[AppointmentAggregationService] Handling cancelled appointment: ${appointment.id}, previous status: ${previousStatus}`
|
|
127
|
+
);
|
|
128
|
+
// 1. Update related PatientRequirementInstances' overallStatus
|
|
129
|
+
// - Query instances by appointment.id
|
|
130
|
+
// - Update overallStatus to PatientRequirementOverallStatus.CANCELLED_APPOINTMENT
|
|
131
|
+
// - PatientRequirementsAdminService (via trigger) should handle notification cancellations.
|
|
132
|
+
|
|
133
|
+
// 2. Trigger calendar event cancellation (e.g., this.calendarAdminService.cancelEventForAppointment(appointment))
|
|
134
|
+
|
|
135
|
+
// 3. Trigger email notifications (e.g., this.appointmentMailingService.sendAppointmentCancelledEmail(appointment))
|
|
136
|
+
|
|
137
|
+
// 4. Evaluate patient-clinic-practitioner links for removal
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Handles side effects when an appointment is rescheduled.
|
|
142
|
+
* - Updates/recreates PRE-appointment PatientRequirementInstances based on new times.
|
|
143
|
+
* - Triggers calendar event updates.
|
|
144
|
+
* - Triggers email/push notifications for rescheduling.
|
|
145
|
+
* @param appointment - The rescheduled Appointment object with new times.
|
|
146
|
+
* @param previousAppointmentData - The appointment data before rescheduling.
|
|
147
|
+
* @returns {Promise<void>}
|
|
148
|
+
*/
|
|
149
|
+
async handleAppointmentRescheduled(
|
|
150
|
+
appointment: Appointment,
|
|
151
|
+
previousAppointmentData: Appointment
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
console.log(
|
|
154
|
+
`[AppointmentAggregationService] Handling rescheduled appointment: ${appointment.id}`
|
|
155
|
+
);
|
|
156
|
+
// 1. Manage PatientRequirementInstances for PRE-requirements:
|
|
157
|
+
// - Mark old instances as SUPERSEDED_RESCHEDULE.
|
|
158
|
+
// - Create new instances for the new time OR update existing ones (more complex).
|
|
159
|
+
// - PatientRequirementsAdminService (via trigger) will manage notification updates.
|
|
160
|
+
|
|
161
|
+
// 2. Trigger calendar event update (e.g., this.calendarAdminService.updateEventForAppointment(appointment, previousAppointmentData))
|
|
162
|
+
|
|
163
|
+
// 3. Trigger email notifications for reschedule (e.g., this.appointmentMailingService.sendAppointmentRescheduledEmail(appointment))
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Manages the links between a patient and the clinic/practitioner associated with an appointment.
|
|
168
|
+
* Adds links on creation, potentially removes them on cancellation if it's the only link.
|
|
169
|
+
* @param appointment - The appointment object.
|
|
170
|
+
* @param action - 'create' to add links, 'cancel' to evaluate removal.
|
|
171
|
+
* @returns {Promise<void>}
|
|
172
|
+
*/
|
|
173
|
+
async managePatientClinicPractitionerLinks(
|
|
174
|
+
appointment: Appointment,
|
|
175
|
+
action: "create" | "cancel"
|
|
176
|
+
): Promise<void> {
|
|
177
|
+
console.log(
|
|
178
|
+
`[AppointmentAggregationService] Managing patient-clinic-practitioner links for appointment ${appointment.id}, action: ${action}`
|
|
179
|
+
);
|
|
180
|
+
// Logic to add patientId to clinic.patientIds / practitioner.patientIds if 'create'
|
|
181
|
+
// Logic to check and potentially remove if 'cancel' and no other appointments link them.
|
|
182
|
+
// This would likely involve calling methods on a PatientAdminService, ClinicAdminService, PractitionerAdminService
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Placeholder for a more generic calendar update trigger.
|
|
187
|
+
* @param appointment The appointment data.
|
|
188
|
+
* @param action The type of action ('create', 'update', 'delete').
|
|
189
|
+
* @param previousAppointmentData Optional, for 'update' actions.
|
|
190
|
+
* @returns {Promise<void>}
|
|
191
|
+
*/
|
|
192
|
+
async triggerCalendarUpdate(
|
|
193
|
+
appointment: Appointment,
|
|
194
|
+
action: "create" | "update" | "delete",
|
|
195
|
+
previousAppointmentData?: Appointment
|
|
196
|
+
): Promise<void> {
|
|
197
|
+
console.log(
|
|
198
|
+
`[AppointmentAggregationService] Triggering calendar update for appointment ${appointment.id}, action: ${action}`
|
|
199
|
+
);
|
|
200
|
+
// Call methods on a dedicated CalendarAdminService
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Placeholder for a more generic email notification trigger.
|
|
205
|
+
* @param appointment The appointment data.
|
|
206
|
+
* @param emailType A string identifying the type of email (e.g., 'APPOINTMENT_CONFIRMED_PATIENT').
|
|
207
|
+
* @param previousAppointmentData Optional, for context.
|
|
208
|
+
* @returns {Promise<void>}
|
|
209
|
+
*/
|
|
210
|
+
async triggerEmailNotification(
|
|
211
|
+
appointment: Appointment,
|
|
212
|
+
emailType: string,
|
|
213
|
+
previousAppointmentData?: Appointment
|
|
214
|
+
): Promise<void> {
|
|
215
|
+
console.log(
|
|
216
|
+
`[AppointmentAggregationService] Triggering email type '${emailType}' for appointment ${appointment.id}`
|
|
217
|
+
);
|
|
218
|
+
// Call methods on a dedicated AppointmentMailingService
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Handles logic for sending a review request after appointment completion.
|
|
223
|
+
* @param appointment - The completed appointment.
|
|
224
|
+
* @returns {Promise<void>}
|
|
225
|
+
*/
|
|
226
|
+
async handleReviewRequest(appointment: Appointment): Promise<void> {
|
|
227
|
+
console.log(
|
|
228
|
+
`[AppointmentAggregationService] Handling review request for appointment ${appointment.id}`
|
|
229
|
+
);
|
|
230
|
+
// Logic to schedule or send a review request notification/email.
|
|
231
|
+
// Might involve checking if a review already exists.
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// --- Helper methods --- //
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Fetches requirement templates based on procedure ID and type (PRE/POST).
|
|
238
|
+
* @param procedureId The ID of the procedure.
|
|
239
|
+
* @param type 'PRE' or 'POST'.
|
|
240
|
+
* @returns {Promise<RequirementTemplate[]>}
|
|
241
|
+
*/
|
|
242
|
+
private async fetchRequirementTemplates(
|
|
243
|
+
procedureId: string,
|
|
244
|
+
type: "PRE" | "POST" // Assuming type is stored on the template
|
|
245
|
+
): Promise<RequirementTemplate[]> {
|
|
246
|
+
console.log(
|
|
247
|
+
`[AppointmentAggregationService] Fetching '${type}' requirement templates for procedure ${procedureId}`
|
|
248
|
+
);
|
|
249
|
+
// const templatesSnapshot = await this.db
|
|
250
|
+
// .collection(REQUIREMENTS_TEMPLATES_COLLECTION)
|
|
251
|
+
// .where("procedureIds", "array-contains", procedureId)
|
|
252
|
+
// .where("type", "==", type) // Assuming a 'type' field on the template
|
|
253
|
+
// .where("isActive", "==", true)
|
|
254
|
+
// .get();
|
|
255
|
+
// return templatesSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as RequirementTemplate));
|
|
256
|
+
return []; // Placeholder
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Creates a PatientRequirementInstance document.
|
|
261
|
+
* @param appointment The parent appointment.
|
|
262
|
+
* @param template The RequirementTemplate to base the instance on.
|
|
263
|
+
* @param type 'PRE' or 'POST'.
|
|
264
|
+
* @returns {Promise<string>} ID of the created instance.
|
|
265
|
+
*/
|
|
266
|
+
private async createPatientRequirementInstance(
|
|
267
|
+
appointment: Appointment,
|
|
268
|
+
template: RequirementTemplate,
|
|
269
|
+
type: "PRE" | "POST"
|
|
270
|
+
): Promise<string> {
|
|
271
|
+
console.log(
|
|
272
|
+
`[AppointmentAggregationService] Creating '${type}' PatientRequirementInstance for appointment ${appointment.id} from template ${template.id}`
|
|
273
|
+
);
|
|
274
|
+
const newInstanceRef = this.db
|
|
275
|
+
.collection(PATIENTS_COLLECTION)
|
|
276
|
+
.doc(appointment.patientId)
|
|
277
|
+
.collection(PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME)
|
|
278
|
+
.doc(); // Auto-generate ID
|
|
279
|
+
|
|
280
|
+
// const instructions = template.instructions.map(instrTemplate => ({
|
|
281
|
+
// ...instrTemplate, // Spread common fields like instructionText, instructionId (if pre-defined)
|
|
282
|
+
// instructionId: instrTemplate.instructionId || this.db.collection('_').doc().id, // Ensure unique ID
|
|
283
|
+
// status: PatientInstructionStatus.PENDING_NOTIFICATION,
|
|
284
|
+
// dueTime: this.calculateInstructionDueTime(appointment, instrTemplate, type),
|
|
285
|
+
// createdAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
286
|
+
// updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
287
|
+
// }));
|
|
288
|
+
|
|
289
|
+
// const instanceData: Omit<PatientRequirementInstance, 'id' | 'createdAt' | 'updatedAt'> = {
|
|
290
|
+
// patientId: appointment.patientId,
|
|
291
|
+
// appointmentId: appointment.id,
|
|
292
|
+
// originalRequirementId: template.id,
|
|
293
|
+
// requirementName: template.name,
|
|
294
|
+
// type: type, // 'PRE' or 'POST'
|
|
295
|
+
// overallStatus: PatientRequirementOverallStatus.ACTIVE,
|
|
296
|
+
// instructions: instructions,
|
|
297
|
+
// // ... other fields like clinicId, practitionerId if needed from appointment
|
|
298
|
+
// };
|
|
299
|
+
|
|
300
|
+
// await newInstanceRef.set({
|
|
301
|
+
// ...instanceData,
|
|
302
|
+
// createdAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
303
|
+
// updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
304
|
+
// });
|
|
305
|
+
// return newInstanceRef.id;
|
|
306
|
+
return newInstanceRef.id; // Placeholder
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Calculates the due time for an instruction.
|
|
311
|
+
* @param appointment The appointment.
|
|
312
|
+
* @param instructionTemplate The instruction template from RequirementTemplate.
|
|
313
|
+
* @param type 'PRE' or 'POST'.
|
|
314
|
+
* @returns {admin.firestore.Timestamp}
|
|
315
|
+
*/
|
|
316
|
+
// private calculateInstructionDueTime(appointment: Appointment, instructionTemplate: any, type: 'PRE' | 'POST'): admin.firestore.Timestamp {
|
|
317
|
+
// const baseTime = type === 'PRE' ? appointment.appointmentStartTime : appointment.appointmentEndTime;
|
|
318
|
+
// // Logic to add/subtract instructionTemplate.offset (e.g., { value: 24, unit: 'hours' }) from baseTime
|
|
319
|
+
// return baseTime; // Placeholder
|
|
320
|
+
// }
|
|
321
|
+
}
|