@blackcode_sa/metaestetics-api 1.5.32 → 1.5.34
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 +226 -1
- package/dist/admin/index.d.ts +226 -1
- package/dist/admin/index.js +597 -14
- package/dist/admin/index.mjs +596 -14
- package/dist/backoffice/index.d.mts +2 -0
- package/dist/backoffice/index.d.ts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +234 -0
- package/src/admin/booking/booking.calculator.ts +686 -0
- package/src/admin/booking/booking.types.ts +56 -0
- package/src/admin/booking/index.ts +3 -0
- package/src/admin/index.ts +9 -0
- package/src/services/appointment/appointment.service.ts +603 -0
- package/src/services/appointment/index.ts +2 -0
- package/src/services/appointment/utils/appointment.utils.ts +590 -0
- package/src/types/appointment/index.ts +161 -0
- package/src/types/procedure/index.ts +2 -0
- package/src/validations/appointment.schema.ts +125 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Timestamp } from "firebase/firestore";
|
|
2
|
+
import { Clinic } from "../../types/clinic";
|
|
3
|
+
import { Practitioner } from "../../types/practitioner";
|
|
4
|
+
import { Procedure } from "../../types/procedure";
|
|
5
|
+
import { CalendarEvent } from "../../types/calendar";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Request parameters for calculating available booking slots
|
|
9
|
+
*/
|
|
10
|
+
export interface BookingAvailabilityRequest {
|
|
11
|
+
/** The clinic for which to calculate booking slots */
|
|
12
|
+
clinic: Clinic;
|
|
13
|
+
|
|
14
|
+
/** The practitioner for which to calculate booking slots */
|
|
15
|
+
practitioner: Practitioner;
|
|
16
|
+
|
|
17
|
+
/** The procedure for which to calculate booking slots */
|
|
18
|
+
procedure: Procedure;
|
|
19
|
+
|
|
20
|
+
/** The timeframe for which to calculate booking slots */
|
|
21
|
+
timeframe: {
|
|
22
|
+
start: Timestamp;
|
|
23
|
+
end: Timestamp;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Calendar events for the clinic during the specified timeframe */
|
|
27
|
+
clinicCalendarEvents: CalendarEvent[];
|
|
28
|
+
|
|
29
|
+
/** Calendar events for the practitioner during the specified timeframe */
|
|
30
|
+
practitionerCalendarEvents: CalendarEvent[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Represents a single available booking slot
|
|
35
|
+
*/
|
|
36
|
+
export interface AvailableSlot {
|
|
37
|
+
/** Start time of the available booking slot */
|
|
38
|
+
start: Timestamp;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Response with available booking slots
|
|
43
|
+
*/
|
|
44
|
+
export interface BookingAvailabilityResponse {
|
|
45
|
+
/** Array of available booking slots */
|
|
46
|
+
availableSlots: AvailableSlot[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Represents a time interval with start and end times
|
|
51
|
+
* Used internally for availability calculations
|
|
52
|
+
*/
|
|
53
|
+
export interface TimeInterval {
|
|
54
|
+
start: Timestamp;
|
|
55
|
+
end: Timestamp;
|
|
56
|
+
}
|
package/src/admin/index.ts
CHANGED
|
@@ -27,6 +27,9 @@ import { PatientAggregationService } from "./aggregation/patient/patient.aggrega
|
|
|
27
27
|
import { BaseMailingService } from "./mailing/base.mailing.service";
|
|
28
28
|
import { PractitionerInviteMailingService } from "./mailing/practitionerInvite/practitionerInvite.mailing";
|
|
29
29
|
|
|
30
|
+
// Import booking services
|
|
31
|
+
import { BookingAdmin } from "./booking/booking.admin";
|
|
32
|
+
|
|
30
33
|
// Re-export types
|
|
31
34
|
export type {
|
|
32
35
|
Notification,
|
|
@@ -69,6 +72,12 @@ export {
|
|
|
69
72
|
// Export mailing services
|
|
70
73
|
export { BaseMailingService, PractitionerInviteMailingService };
|
|
71
74
|
|
|
75
|
+
// Export booking services
|
|
76
|
+
export { BookingAdmin };
|
|
77
|
+
|
|
78
|
+
// Also export booking types
|
|
79
|
+
export * from "./booking/booking.types";
|
|
80
|
+
|
|
72
81
|
/**
|
|
73
82
|
* Main entry point for the Admin module.
|
|
74
83
|
* This module contains services and utilities intended for administrative tasks,
|
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Firestore,
|
|
3
|
+
Timestamp,
|
|
4
|
+
DocumentSnapshot,
|
|
5
|
+
serverTimestamp,
|
|
6
|
+
} from "firebase/firestore";
|
|
7
|
+
import { Auth } from "firebase/auth";
|
|
8
|
+
import { FirebaseApp } from "firebase/app";
|
|
9
|
+
import { BaseService } from "../base.service";
|
|
10
|
+
import {
|
|
11
|
+
Appointment,
|
|
12
|
+
AppointmentStatus,
|
|
13
|
+
CreateAppointmentData,
|
|
14
|
+
UpdateAppointmentData,
|
|
15
|
+
SearchAppointmentsParams,
|
|
16
|
+
PaymentStatus,
|
|
17
|
+
} from "../../types/appointment";
|
|
18
|
+
import {
|
|
19
|
+
createAppointmentSchema,
|
|
20
|
+
updateAppointmentSchema,
|
|
21
|
+
searchAppointmentsSchema,
|
|
22
|
+
} from "../../validations/appointment.schema";
|
|
23
|
+
|
|
24
|
+
// Import other services needed (dependency injection pattern)
|
|
25
|
+
import { CalendarServiceV2 } from "../calendar/calendar-refactored.service";
|
|
26
|
+
import { PatientService } from "../patient/patient.service";
|
|
27
|
+
import { PractitionerService } from "../practitioner/practitioner.service";
|
|
28
|
+
import { ClinicService } from "../clinic/clinic.service";
|
|
29
|
+
|
|
30
|
+
// Import utility functions
|
|
31
|
+
import {
|
|
32
|
+
fetchAggregatedInfoUtil,
|
|
33
|
+
createAppointmentUtil,
|
|
34
|
+
updateAppointmentUtil,
|
|
35
|
+
getAppointmentByIdUtil,
|
|
36
|
+
searchAppointmentsUtil,
|
|
37
|
+
} from "./utils/appointment.utils";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* AppointmentService is responsible for managing appointments,
|
|
41
|
+
* including creating, updating, retrieving, and searching appointments.
|
|
42
|
+
* It serves as the main entry point for working with appointment data.
|
|
43
|
+
*/
|
|
44
|
+
export class AppointmentService extends BaseService {
|
|
45
|
+
private calendarService: CalendarServiceV2;
|
|
46
|
+
private patientService: PatientService;
|
|
47
|
+
private practitionerService: PractitionerService;
|
|
48
|
+
private clinicService: ClinicService;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new AppointmentService instance.
|
|
52
|
+
*
|
|
53
|
+
* @param db Firestore instance
|
|
54
|
+
* @param auth Firebase Auth instance
|
|
55
|
+
* @param app Firebase App instance
|
|
56
|
+
* @param calendarService Calendar service instance
|
|
57
|
+
* @param patientService Patient service instance
|
|
58
|
+
* @param practitionerService Practitioner service instance
|
|
59
|
+
* @param clinicService Clinic service instance
|
|
60
|
+
*/
|
|
61
|
+
constructor(
|
|
62
|
+
db: Firestore,
|
|
63
|
+
auth: Auth,
|
|
64
|
+
app: FirebaseApp,
|
|
65
|
+
calendarService: CalendarServiceV2,
|
|
66
|
+
patientService: PatientService,
|
|
67
|
+
practitionerService: PractitionerService,
|
|
68
|
+
clinicService: ClinicService
|
|
69
|
+
) {
|
|
70
|
+
super(db, auth, app);
|
|
71
|
+
this.calendarService = calendarService;
|
|
72
|
+
this.patientService = patientService;
|
|
73
|
+
this.practitionerService = practitionerService;
|
|
74
|
+
this.clinicService = clinicService;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Creates a new appointment.
|
|
79
|
+
*
|
|
80
|
+
* @param data Data needed to create the appointment
|
|
81
|
+
* @returns The created appointment
|
|
82
|
+
*/
|
|
83
|
+
async createAppointment(data: CreateAppointmentData): Promise<Appointment> {
|
|
84
|
+
try {
|
|
85
|
+
console.log("[APPOINTMENT_SERVICE] Creating appointment");
|
|
86
|
+
|
|
87
|
+
// Validate input data
|
|
88
|
+
const validatedData = await createAppointmentSchema.parseAsync(data);
|
|
89
|
+
|
|
90
|
+
// Fetch all required aggregated information
|
|
91
|
+
const aggregatedInfo = await fetchAggregatedInfoUtil(
|
|
92
|
+
this.db,
|
|
93
|
+
validatedData.clinicBranchId,
|
|
94
|
+
validatedData.practitionerId,
|
|
95
|
+
validatedData.patientId,
|
|
96
|
+
validatedData.procedureId
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Create the appointment using the utility function
|
|
100
|
+
const appointment = await createAppointmentUtil(
|
|
101
|
+
this.db,
|
|
102
|
+
validatedData as CreateAppointmentData,
|
|
103
|
+
aggregatedInfo,
|
|
104
|
+
this.generateId.bind(this)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
console.log(
|
|
108
|
+
`[APPOINTMENT_SERVICE] Appointment created with ID: ${appointment.id}`
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return appointment;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("[APPOINTMENT_SERVICE] Error creating appointment:", error);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Gets an appointment by ID.
|
|
120
|
+
*
|
|
121
|
+
* @param appointmentId ID of the appointment to retrieve
|
|
122
|
+
* @returns The appointment or null if not found
|
|
123
|
+
*/
|
|
124
|
+
async getAppointmentById(appointmentId: string): Promise<Appointment | null> {
|
|
125
|
+
try {
|
|
126
|
+
console.log(
|
|
127
|
+
`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
|
|
131
|
+
|
|
132
|
+
console.log(
|
|
133
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${
|
|
134
|
+
appointment ? "found" : "not found"
|
|
135
|
+
}`
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
return appointment;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(
|
|
141
|
+
`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
|
|
142
|
+
error
|
|
143
|
+
);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Updates an existing appointment.
|
|
150
|
+
*
|
|
151
|
+
* @param appointmentId ID of the appointment to update
|
|
152
|
+
* @param data Update data for the appointment
|
|
153
|
+
* @returns The updated appointment
|
|
154
|
+
*/
|
|
155
|
+
async updateAppointment(
|
|
156
|
+
appointmentId: string,
|
|
157
|
+
data: UpdateAppointmentData
|
|
158
|
+
): Promise<Appointment> {
|
|
159
|
+
try {
|
|
160
|
+
console.log(
|
|
161
|
+
`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Validate input data
|
|
165
|
+
const validatedData = await updateAppointmentSchema.parseAsync(data);
|
|
166
|
+
|
|
167
|
+
// Update the appointment using the utility function
|
|
168
|
+
const updatedAppointment = await updateAppointmentUtil(
|
|
169
|
+
this.db,
|
|
170
|
+
appointmentId,
|
|
171
|
+
validatedData
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
console.log(
|
|
175
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return updatedAppointment;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error(
|
|
181
|
+
`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
|
|
182
|
+
error
|
|
183
|
+
);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Searches for appointments based on various criteria.
|
|
190
|
+
*
|
|
191
|
+
* @param params Search parameters
|
|
192
|
+
* @returns Found appointments and the last document for pagination
|
|
193
|
+
*/
|
|
194
|
+
async searchAppointments(params: SearchAppointmentsParams): Promise<{
|
|
195
|
+
appointments: Appointment[];
|
|
196
|
+
lastDoc: DocumentSnapshot | null;
|
|
197
|
+
}> {
|
|
198
|
+
try {
|
|
199
|
+
console.log(
|
|
200
|
+
"[APPOINTMENT_SERVICE] Searching appointments with params:",
|
|
201
|
+
params
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// Validate search parameters
|
|
205
|
+
await searchAppointmentsSchema.parseAsync(params);
|
|
206
|
+
|
|
207
|
+
// Search for appointments using the utility function
|
|
208
|
+
const result = await searchAppointmentsUtil(this.db, params);
|
|
209
|
+
|
|
210
|
+
console.log(
|
|
211
|
+
`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
return result;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(
|
|
217
|
+
"[APPOINTMENT_SERVICE] Error searching appointments:",
|
|
218
|
+
error
|
|
219
|
+
);
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gets appointments for a specific patient.
|
|
226
|
+
*
|
|
227
|
+
* @param patientId ID of the patient
|
|
228
|
+
* @param options Optional parameters for filtering and pagination
|
|
229
|
+
* @returns Found appointments and the last document for pagination
|
|
230
|
+
*/
|
|
231
|
+
async getPatientAppointments(
|
|
232
|
+
patientId: string,
|
|
233
|
+
options?: {
|
|
234
|
+
startDate?: Date;
|
|
235
|
+
endDate?: Date;
|
|
236
|
+
status?: AppointmentStatus | AppointmentStatus[];
|
|
237
|
+
limit?: number;
|
|
238
|
+
startAfter?: DocumentSnapshot;
|
|
239
|
+
}
|
|
240
|
+
): Promise<{
|
|
241
|
+
appointments: Appointment[];
|
|
242
|
+
lastDoc: DocumentSnapshot | null;
|
|
243
|
+
}> {
|
|
244
|
+
console.log(
|
|
245
|
+
`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
const searchParams: SearchAppointmentsParams = {
|
|
249
|
+
patientId,
|
|
250
|
+
startDate: options?.startDate,
|
|
251
|
+
endDate: options?.endDate,
|
|
252
|
+
status: options?.status,
|
|
253
|
+
limit: options?.limit,
|
|
254
|
+
startAfter: options?.startAfter,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return this.searchAppointments(searchParams);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Gets appointments for a specific practitioner.
|
|
262
|
+
*
|
|
263
|
+
* @param practitionerId ID of the practitioner
|
|
264
|
+
* @param options Optional parameters for filtering and pagination
|
|
265
|
+
* @returns Found appointments and the last document for pagination
|
|
266
|
+
*/
|
|
267
|
+
async getPractitionerAppointments(
|
|
268
|
+
practitionerId: string,
|
|
269
|
+
options?: {
|
|
270
|
+
startDate?: Date;
|
|
271
|
+
endDate?: Date;
|
|
272
|
+
status?: AppointmentStatus | AppointmentStatus[];
|
|
273
|
+
limit?: number;
|
|
274
|
+
startAfter?: DocumentSnapshot;
|
|
275
|
+
}
|
|
276
|
+
): Promise<{
|
|
277
|
+
appointments: Appointment[];
|
|
278
|
+
lastDoc: DocumentSnapshot | null;
|
|
279
|
+
}> {
|
|
280
|
+
console.log(
|
|
281
|
+
`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const searchParams: SearchAppointmentsParams = {
|
|
285
|
+
practitionerId,
|
|
286
|
+
startDate: options?.startDate,
|
|
287
|
+
endDate: options?.endDate,
|
|
288
|
+
status: options?.status,
|
|
289
|
+
limit: options?.limit,
|
|
290
|
+
startAfter: options?.startAfter,
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
return this.searchAppointments(searchParams);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Gets appointments for a specific clinic.
|
|
298
|
+
*
|
|
299
|
+
* @param clinicBranchId ID of the clinic branch
|
|
300
|
+
* @param options Optional parameters for filtering and pagination
|
|
301
|
+
* @returns Found appointments and the last document for pagination
|
|
302
|
+
*/
|
|
303
|
+
async getClinicAppointments(
|
|
304
|
+
clinicBranchId: string,
|
|
305
|
+
options?: {
|
|
306
|
+
practitionerId?: string;
|
|
307
|
+
startDate?: Date;
|
|
308
|
+
endDate?: Date;
|
|
309
|
+
status?: AppointmentStatus | AppointmentStatus[];
|
|
310
|
+
limit?: number;
|
|
311
|
+
startAfter?: DocumentSnapshot;
|
|
312
|
+
}
|
|
313
|
+
): Promise<{
|
|
314
|
+
appointments: Appointment[];
|
|
315
|
+
lastDoc: DocumentSnapshot | null;
|
|
316
|
+
}> {
|
|
317
|
+
console.log(
|
|
318
|
+
`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
const searchParams: SearchAppointmentsParams = {
|
|
322
|
+
clinicBranchId,
|
|
323
|
+
practitionerId: options?.practitionerId,
|
|
324
|
+
startDate: options?.startDate,
|
|
325
|
+
endDate: options?.endDate,
|
|
326
|
+
status: options?.status,
|
|
327
|
+
limit: options?.limit,
|
|
328
|
+
startAfter: options?.startAfter,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
return this.searchAppointments(searchParams);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Updates the status of an appointment.
|
|
336
|
+
*
|
|
337
|
+
* @param appointmentId ID of the appointment
|
|
338
|
+
* @param newStatus New status to set
|
|
339
|
+
* @param cancellationReason Required if canceling the appointment
|
|
340
|
+
* @param canceledBy Required if canceling the appointment
|
|
341
|
+
* @returns The updated appointment
|
|
342
|
+
*/
|
|
343
|
+
async updateAppointmentStatus(
|
|
344
|
+
appointmentId: string,
|
|
345
|
+
newStatus: AppointmentStatus,
|
|
346
|
+
cancellationReason?: string,
|
|
347
|
+
canceledBy?: "patient" | "clinic" | "practitioner" | "system"
|
|
348
|
+
): Promise<Appointment> {
|
|
349
|
+
console.log(
|
|
350
|
+
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
// Create update data based on the new status
|
|
354
|
+
const updateData: UpdateAppointmentData = { status: newStatus };
|
|
355
|
+
|
|
356
|
+
// Add cancellation details if applicable
|
|
357
|
+
if (
|
|
358
|
+
newStatus === AppointmentStatus.CANCELED_CLINIC ||
|
|
359
|
+
newStatus === AppointmentStatus.CANCELED_PATIENT
|
|
360
|
+
) {
|
|
361
|
+
if (!cancellationReason) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
"Cancellation reason is required when canceling an appointment"
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
if (!canceledBy) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
"Canceled by is required when canceling an appointment"
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
updateData.cancellationReason = cancellationReason;
|
|
373
|
+
updateData.canceledBy = canceledBy;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Add confirmation time if confirming
|
|
377
|
+
if (newStatus === AppointmentStatus.CONFIRMED) {
|
|
378
|
+
updateData.confirmationTime = Timestamp.now();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Confirms an appointment.
|
|
386
|
+
*
|
|
387
|
+
* @param appointmentId ID of the appointment to confirm
|
|
388
|
+
* @returns The confirmed appointment
|
|
389
|
+
*/
|
|
390
|
+
async confirmAppointment(appointmentId: string): Promise<Appointment> {
|
|
391
|
+
console.log(
|
|
392
|
+
`[APPOINTMENT_SERVICE] Confirming appointment: ${appointmentId}`
|
|
393
|
+
);
|
|
394
|
+
return this.updateAppointmentStatus(
|
|
395
|
+
appointmentId,
|
|
396
|
+
AppointmentStatus.CONFIRMED
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Cancels an appointment from the clinic side.
|
|
402
|
+
*
|
|
403
|
+
* @param appointmentId ID of the appointment to cancel
|
|
404
|
+
* @param reason Reason for cancellation
|
|
405
|
+
* @returns The canceled appointment
|
|
406
|
+
*/
|
|
407
|
+
async cancelAppointmentByClinic(
|
|
408
|
+
appointmentId: string,
|
|
409
|
+
reason: string
|
|
410
|
+
): Promise<Appointment> {
|
|
411
|
+
console.log(
|
|
412
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by clinic: ${appointmentId}`
|
|
413
|
+
);
|
|
414
|
+
return this.updateAppointmentStatus(
|
|
415
|
+
appointmentId,
|
|
416
|
+
AppointmentStatus.CANCELED_CLINIC,
|
|
417
|
+
reason,
|
|
418
|
+
"clinic"
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Cancels an appointment from the patient side.
|
|
424
|
+
*
|
|
425
|
+
* @param appointmentId ID of the appointment to cancel
|
|
426
|
+
* @param reason Reason for cancellation
|
|
427
|
+
* @returns The canceled appointment
|
|
428
|
+
*/
|
|
429
|
+
async cancelAppointmentByPatient(
|
|
430
|
+
appointmentId: string,
|
|
431
|
+
reason: string
|
|
432
|
+
): Promise<Appointment> {
|
|
433
|
+
console.log(
|
|
434
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by patient: ${appointmentId}`
|
|
435
|
+
);
|
|
436
|
+
return this.updateAppointmentStatus(
|
|
437
|
+
appointmentId,
|
|
438
|
+
AppointmentStatus.CANCELED_PATIENT,
|
|
439
|
+
reason,
|
|
440
|
+
"patient"
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Marks an appointment as checked in.
|
|
446
|
+
*
|
|
447
|
+
* @param appointmentId ID of the appointment
|
|
448
|
+
* @returns The updated appointment
|
|
449
|
+
*/
|
|
450
|
+
async checkInAppointment(appointmentId: string): Promise<Appointment> {
|
|
451
|
+
console.log(
|
|
452
|
+
`[APPOINTMENT_SERVICE] Checking in appointment: ${appointmentId}`
|
|
453
|
+
);
|
|
454
|
+
return this.updateAppointmentStatus(
|
|
455
|
+
appointmentId,
|
|
456
|
+
AppointmentStatus.CHECKED_IN
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Marks an appointment as in progress.
|
|
462
|
+
*
|
|
463
|
+
* @param appointmentId ID of the appointment
|
|
464
|
+
* @returns The updated appointment
|
|
465
|
+
*/
|
|
466
|
+
async startAppointment(appointmentId: string): Promise<Appointment> {
|
|
467
|
+
console.log(`[APPOINTMENT_SERVICE] Starting appointment: ${appointmentId}`);
|
|
468
|
+
return this.updateAppointmentStatus(
|
|
469
|
+
appointmentId,
|
|
470
|
+
AppointmentStatus.IN_PROGRESS
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Marks an appointment as completed.
|
|
476
|
+
*
|
|
477
|
+
* @param appointmentId ID of the appointment
|
|
478
|
+
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
479
|
+
* @returns The updated appointment
|
|
480
|
+
*/
|
|
481
|
+
async completeAppointment(
|
|
482
|
+
appointmentId: string,
|
|
483
|
+
actualDurationMinutes?: number
|
|
484
|
+
): Promise<Appointment> {
|
|
485
|
+
console.log(
|
|
486
|
+
`[APPOINTMENT_SERVICE] Completing appointment: ${appointmentId}`
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
const updateData: UpdateAppointmentData = {
|
|
490
|
+
status: AppointmentStatus.COMPLETED,
|
|
491
|
+
actualDurationMinutes,
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Marks an appointment as no-show.
|
|
499
|
+
*
|
|
500
|
+
* @param appointmentId ID of the appointment
|
|
501
|
+
* @returns The updated appointment
|
|
502
|
+
*/
|
|
503
|
+
async markNoShow(appointmentId: string): Promise<Appointment> {
|
|
504
|
+
console.log(
|
|
505
|
+
`[APPOINTMENT_SERVICE] Marking appointment as no-show: ${appointmentId}`
|
|
506
|
+
);
|
|
507
|
+
return this.updateAppointmentStatus(
|
|
508
|
+
appointmentId,
|
|
509
|
+
AppointmentStatus.NO_SHOW
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Updates the payment status of an appointment.
|
|
515
|
+
*
|
|
516
|
+
* @param appointmentId ID of the appointment
|
|
517
|
+
* @param paymentStatus New payment status
|
|
518
|
+
* @param paymentTransactionId Optional transaction ID for the payment
|
|
519
|
+
* @returns The updated appointment
|
|
520
|
+
*/
|
|
521
|
+
async updatePaymentStatus(
|
|
522
|
+
appointmentId: string,
|
|
523
|
+
paymentStatus: PaymentStatus,
|
|
524
|
+
paymentTransactionId?: string
|
|
525
|
+
): Promise<Appointment> {
|
|
526
|
+
console.log(
|
|
527
|
+
`[APPOINTMENT_SERVICE] Updating payment status of appointment ${appointmentId} to ${paymentStatus}`
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
const updateData: UpdateAppointmentData = {
|
|
531
|
+
paymentStatus,
|
|
532
|
+
paymentTransactionId: paymentTransactionId || null,
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Marks pre-procedure requirements as completed.
|
|
540
|
+
*
|
|
541
|
+
* @param appointmentId ID of the appointment
|
|
542
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
543
|
+
* @returns The updated appointment
|
|
544
|
+
*/
|
|
545
|
+
async completePreRequirements(
|
|
546
|
+
appointmentId: string,
|
|
547
|
+
requirementIds: string[]
|
|
548
|
+
): Promise<Appointment> {
|
|
549
|
+
console.log(
|
|
550
|
+
`[APPOINTMENT_SERVICE] Marking pre-requirements as completed for appointment: ${appointmentId}`
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
const updateData: UpdateAppointmentData = {
|
|
554
|
+
completedPreRequirements: requirementIds,
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Marks post-procedure requirements as completed.
|
|
562
|
+
*
|
|
563
|
+
* @param appointmentId ID of the appointment
|
|
564
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
565
|
+
* @returns The updated appointment
|
|
566
|
+
*/
|
|
567
|
+
async completePostRequirements(
|
|
568
|
+
appointmentId: string,
|
|
569
|
+
requirementIds: string[]
|
|
570
|
+
): Promise<Appointment> {
|
|
571
|
+
console.log(
|
|
572
|
+
`[APPOINTMENT_SERVICE] Marking post-requirements as completed for appointment: ${appointmentId}`
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
const updateData: UpdateAppointmentData = {
|
|
576
|
+
completedPostRequirements: requirementIds,
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Updates the internal notes of an appointment.
|
|
584
|
+
*
|
|
585
|
+
* @param appointmentId ID of the appointment
|
|
586
|
+
* @param notes Updated internal notes
|
|
587
|
+
* @returns The updated appointment
|
|
588
|
+
*/
|
|
589
|
+
async updateInternalNotes(
|
|
590
|
+
appointmentId: string,
|
|
591
|
+
notes: string | null
|
|
592
|
+
): Promise<Appointment> {
|
|
593
|
+
console.log(
|
|
594
|
+
`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
const updateData: UpdateAppointmentData = {
|
|
598
|
+
internalNotes: notes,
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
602
|
+
}
|
|
603
|
+
}
|