Skip to content

Commit 1b63b49

Browse files
committed
fix
1 parent aa16ecd commit 1b63b49

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

services/patient-service/src/modules/appointments/appointment.repository.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,34 @@ export class AppointmentRepository {
154154
return `${hours}:${minutes}`;
155155
});
156156
}
157+
158+
async updateAppointmentTime(
159+
appointmentId: string,
160+
newTime: Date,
161+
newDuration: number
162+
) {
163+
const result = await pool.query(
164+
`
165+
UPDATE appointments
166+
SET appointment_time = $2,
167+
duration_minutes = $3,
168+
updated_at = now()
169+
WHERE id = $1
170+
RETURNING *;
171+
`,
172+
[appointmentId, newTime, newDuration]
173+
);
174+
175+
return result.rows[0];
176+
}
177+
178+
async getAppointmentById(id: string) {
179+
const result = await pool.query(
180+
`SELECT * FROM appointments WHERE id = $1`,
181+
[id]
182+
);
183+
return result.rows[0] || null;
184+
}
157185
}
158186

159187
export const appointmentRepository = new AppointmentRepository();

services/patient-service/src/modules/appointments/appointment.service.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,121 @@ export class AppointmentService {
378378
doctor_current_patient: doctorQueue.doctor_status.current_patient,
379379
};
380380
}
381+
382+
async setPriority(appointmentId: string, priority: 'NORMAL' | 'HIGH') {
383+
const appointment =
384+
await appointmentRepository.getAppointmentById(appointmentId);
385+
386+
if (!appointment) throw new Error('NOT_FOUND');
387+
388+
return appointmentRepository.updatePriority(appointmentId, priority);
389+
}
390+
391+
async cancelAppointment(appointmentId: string, patientId: string) {
392+
const appointment =
393+
await appointmentRepository.getAppointmentById(appointmentId);
394+
395+
if (!appointment) throw new Error('NOT_FOUND');
396+
397+
if (appointment.patient_id !== patientId) throw new Error('FORBIDDEN');
398+
399+
if (appointment.status !== 'SCHEDULED') throw new Error('CANNOT_CANCEL');
400+
401+
// Check if it's too late (e.g. less than 1 hour before)
402+
const now = new Date();
403+
const apptTime = new Date(appointment.appointment_time);
404+
const diffHours = (apptTime.getTime() - now.getTime()) / 3600000;
405+
406+
if (diffHours < 1) throw new Error('TOO_LATE_TO_CANCEL');
407+
408+
return this.updateStatus(appointmentId, 'CANCELLED');
409+
}
410+
411+
async rescheduleAppointment(
412+
appointmentId: string,
413+
patientId: string,
414+
newTimeStr: string
415+
) {
416+
const appointment =
417+
await appointmentRepository.getAppointmentById(appointmentId);
418+
419+
if (!appointment) throw new Error('NOT_FOUND');
420+
421+
if (appointment.patient_id !== patientId) throw new Error('FORBIDDEN');
422+
423+
if (appointment.status !== 'SCHEDULED')
424+
throw new Error('CANNOT_RESCHEDULE');
425+
426+
const now = new Date();
427+
const newTime = new Date(newTimeStr);
428+
429+
if (newTime <= now) {
430+
throw new Error('PAST_TIME_NOT_ALLOWED');
431+
}
432+
433+
// Check if too late to change current one
434+
const apptTime = new Date(appointment.appointment_time);
435+
const diffHours = (apptTime.getTime() - now.getTime()) / 3600000;
436+
437+
if (diffHours < 1) throw new Error('TOO_LATE_TO_RESCHEDULE');
438+
439+
// Validate new slot
440+
const dayOfWeek = newTime.getDay();
441+
const availabilityResponse = await axios.get(
442+
`${process.env.STAFF_SERVICE_URL}/staff/availability/${appointment.doctor_id}/${dayOfWeek}`
443+
);
444+
445+
const availability = availabilityResponse.data;
446+
if (!availability) throw new Error('DOCTOR_NOT_AVAILABLE');
447+
448+
const { start_time, end_time, slot_duration } = availability;
449+
450+
const start = new Date(newTime);
451+
start.setHours(
452+
Number(start_time.split(':')[0]),
453+
Number(start_time.split(':')[1]),
454+
0,
455+
0
456+
);
457+
458+
const end = new Date(newTime);
459+
end.setHours(
460+
Number(end_time.split(':')[0]),
461+
Number(end_time.split(':')[1]),
462+
0,
463+
0
464+
);
465+
466+
if (newTime < start || newTime >= end) {
467+
throw new Error('OUTSIDE_WORKING_HOURS');
468+
}
469+
470+
const diffMinutes = (newTime.getTime() - start.getTime()) / 60000;
471+
if (diffMinutes % slot_duration !== 0) {
472+
throw new Error('INVALID_SLOT_TIME');
473+
}
474+
475+
// Check if slot taken
476+
const dateStr = newTime.toISOString().split('T')[0];
477+
const booked = await appointmentRepository.getBookedSlots(
478+
appointment.doctor_id,
479+
dateStr
480+
);
481+
482+
const hours = newTime.getHours().toString().padStart(2, '0');
483+
const minutes = newTime.getMinutes().toString().padStart(2, '0');
484+
const timeStr = `${hours}:${minutes}`;
485+
486+
if (booked.includes(timeStr)) {
487+
throw new Error('SLOT_TAKEN');
488+
}
489+
490+
return appointmentRepository.updateAppointmentTime(
491+
appointmentId,
492+
newTime,
493+
slot_duration
494+
);
495+
}
381496
}
382497

383498
export const appointmentService = new AppointmentService();

0 commit comments

Comments
 (0)