Spaces:
Sleeping
Sleeping
| """Appointment routes — list, cancel, and complete.""" | |
| from datetime import datetime | |
| from zoneinfo import ZoneInfo | |
| from fastapi import APIRouter, Depends, HTTPException | |
| from core import data_manager, google_services | |
| from core import settings_manager as settings | |
| from api.deps import get_current_session | |
| router = APIRouter(prefix="/api/appointments", tags=["appointments"]) | |
| def list_appointments(status: str | None = None, provider_id: str | None = None, session: dict = Depends(get_current_session)): | |
| appts = data_manager.get_all_appointments(status=status) | |
| if session.get("user_role") == "provider": | |
| # Providers see only their own appointments | |
| appts = [a for a in appts if a.get("provider_id") == session.get("provider_id")] | |
| elif provider_id: | |
| appts = [a for a in appts if a.get("provider_id") == provider_id] | |
| return appts | |
| def cancel_appointment(appointment_id: str, session: dict = Depends(get_current_session)): | |
| if session.get("user_role") == "provider": | |
| raise HTTPException(status_code=403, detail="Providers cannot cancel appointments") | |
| appt = next((a for a in data_manager.get_all_appointments() if a.get("id") == appointment_id), None) | |
| if not appt: | |
| raise HTTPException(status_code=404, detail="Appointment not found") | |
| cancelled = data_manager.cancel_appointment(appointment_id) | |
| if not cancelled: | |
| raise HTTPException(status_code=500, detail="Cancellation failed") | |
| # Delete Google Calendar event (non-critical) | |
| if appt.get("google_event_id"): | |
| try: | |
| google_services.delete_calendar_event(appt["google_event_id"]) | |
| except Exception: | |
| pass | |
| # Send cancellation notifications (non-critical) | |
| try: | |
| provider = data_manager.get_provider_by_id(appt["provider_id"]) | |
| patient = data_manager.get_patient_by_id(appt["patient_id"]) | |
| appointment_details = { | |
| "patient_name": appt.get("patient_name", ""), | |
| "provider_name": appt.get("provider_name", ""), | |
| "date": appt.get("date", ""), | |
| "start_time": appt.get("start_time", ""), | |
| "end_time": appt.get("end_time", ""), | |
| "address": appt.get("visit_address", ""), | |
| } | |
| google_services.send_cancellation_notification( | |
| provider_email=provider.get("email", "") if provider else "", | |
| patient_email=patient.get("email", "") if patient else "", | |
| appointment_details=appointment_details, | |
| ) | |
| except Exception: | |
| pass | |
| data_manager.log_action( | |
| user=session["current_user"], | |
| action="CANCEL", | |
| details=( | |
| f"Cancelled {appt.get('visit_level', '')} visit for " | |
| f"{appt.get('patient_name', '')} with {appt.get('provider_name', '')} " | |
| f"on {appt.get('date', '')} at {appt.get('start_time', '')}" | |
| ), | |
| appointment_id=appointment_id, | |
| ) | |
| return {"ok": True} | |
| def complete_appointment(appointment_id: str, session: dict = Depends(get_current_session)): | |
| """Mark an appointment as completed. Provider-only; only allowed once the | |
| appointment's start time has passed (compared in the platform timezone).""" | |
| appt = next((a for a in data_manager.get_all_appointments() if a.get("id") == appointment_id), None) | |
| if not appt: | |
| raise HTTPException(status_code=404, detail="Appointment not found") | |
| if session.get("user_role") == "provider" and session.get("provider_id") != appt.get("provider_id"): | |
| raise HTTPException(status_code=403, detail="Can only complete your own appointments") | |
| if appt.get("status") != "scheduled": | |
| raise HTTPException(status_code=400, detail=f"Cannot complete appointment with status '{appt.get('status')}'") | |
| # Compare in the platform timezone so a UTC server doesn't mis-evaluate. | |
| try: | |
| start_dt = datetime.strptime(f"{appt['date']} {appt['start_time']}", "%Y-%m-%d %H:%M") | |
| except (KeyError, ValueError): | |
| raise HTTPException(status_code=500, detail="Appointment has invalid date/time") | |
| now_local = datetime.now(ZoneInfo(settings.get_timezone())).replace(tzinfo=None) | |
| if now_local < start_dt: | |
| raise HTTPException(status_code=400, detail="Appointment has not started yet") | |
| completed = data_manager.complete_appointment(appointment_id) | |
| if not completed: | |
| raise HTTPException(status_code=500, detail="Failed to mark complete") | |
| data_manager.log_action( | |
| user=session["current_user"], | |
| action="COMPLETE", | |
| details=( | |
| f"Completed {appt.get('visit_level', '')} visit for " | |
| f"{appt.get('patient_name', '')} with {appt.get('provider_name', '')} " | |
| f"on {appt.get('date', '')} at {appt.get('start_time', '')}" | |
| ), | |
| appointment_id=appointment_id, | |
| ) | |
| return {"ok": True, "appointment": completed} | |