From d24acfd32293dddb58cb28733991b5315d510eb1 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 21 Dec 2025 17:49:37 +0100 Subject: [PATCH] Extract duplicate AppointmentResponse construction to helper - Created _to_appointment_response() helper function - Replaced 5 duplicate AppointmentResponse constructions with helper calls - Helper handles both explicit user_email and eager-loaded user relationship cases --- backend/routes/booking.py | 84 ++++++++++++++------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/backend/routes/booking.py b/backend/routes/booking.py index 770d2da..6d39eea 100644 --- a/backend/routes/booking.py +++ b/backend/routes/booking.py @@ -22,6 +22,30 @@ from shared_constants import SLOT_DURATION_MINUTES, MIN_ADVANCE_DAYS, MAX_ADVANC router = APIRouter(prefix="/api/booking", tags=["booking"]) +def _to_appointment_response( + appointment: Appointment, + user_email: str | None = None, +) -> AppointmentResponse: + """Convert an Appointment model to AppointmentResponse schema. + + Args: + appointment: The appointment model instance + user_email: Optional user email. If not provided, uses appointment.user.email + """ + email = user_email if user_email is not None else appointment.user.email + return AppointmentResponse( + id=appointment.id, + user_id=appointment.user_id, + user_email=email, + slot_start=appointment.slot_start, + slot_end=appointment.slot_end, + note=appointment.note, + status=appointment.status.value, + created_at=appointment.created_at, + cancelled_at=appointment.cancelled_at, + ) + + def _get_bookable_date_range() -> tuple[date, date]: """Get the valid date range for booking (tomorrow to +30 days).""" today = date.today() @@ -180,17 +204,7 @@ async def create_booking( detail="This slot has already been booked. Please select another slot.", ) - return AppointmentResponse( - id=appointment.id, - user_id=appointment.user_id, - user_email=current_user.email, - slot_start=appointment.slot_start, - slot_end=appointment.slot_end, - note=appointment.note, - status=appointment.status.value, - created_at=appointment.created_at, - cancelled_at=appointment.cancelled_at, - ) + return _to_appointment_response(appointment, current_user.email) # ============================================================================= @@ -214,17 +228,7 @@ async def get_my_appointments( appointments = result.scalars().all() return [ - AppointmentResponse( - id=apt.id, - user_id=apt.user_id, - user_email=current_user.email, - slot_start=apt.slot_start, - slot_end=apt.slot_end, - note=apt.note, - status=apt.status.value, - created_at=apt.created_at, - cancelled_at=apt.cancelled_at, - ) + _to_appointment_response(apt, current_user.email) for apt in appointments ] @@ -270,17 +274,7 @@ async def cancel_my_appointment( await db.commit() await db.refresh(appointment) - return AppointmentResponse( - id=appointment.id, - user_id=appointment.user_id, - user_email=current_user.email, - slot_start=appointment.slot_start, - slot_end=appointment.slot_end, - note=appointment.note, - status=appointment.status.value, - created_at=appointment.created_at, - cancelled_at=appointment.cancelled_at, - ) + return _to_appointment_response(appointment, current_user.email) # ============================================================================= @@ -315,17 +309,7 @@ async def get_all_appointments( # Build responses using the eager-loaded user relationship records = [ - AppointmentResponse( - id=apt.id, - user_id=apt.user_id, - user_email=apt.user.email, # Uses eager-loaded relationship - slot_start=apt.slot_start, - slot_end=apt.slot_end, - note=apt.note, - status=apt.status.value, - created_at=apt.created_at, - cancelled_at=apt.cancelled_at, - ) + _to_appointment_response(apt) # Uses eager-loaded relationship for apt in appointments ] @@ -375,14 +359,4 @@ async def admin_cancel_appointment( await db.commit() await db.refresh(appointment) - return AppointmentResponse( - id=appointment.id, - user_id=appointment.user_id, - user_email=appointment.user.email, # Uses eager-loaded relationship - slot_start=appointment.slot_start, - slot_end=appointment.slot_end, - note=appointment.note, - status=appointment.status.value, - created_at=appointment.created_at, - cancelled_at=appointment.cancelled_at, - ) + return _to_appointment_response(appointment) # Uses eager-loaded relationship