| """Appointment router — OWNER: Person B.""" |
|
|
| from __future__ import annotations |
|
|
| from datetime import datetime, timedelta, timezone |
|
|
| from fastapi import APIRouter, HTTPException, Request |
|
|
| from app.agents.appointment import api as appt_api |
| from app.contracts import BookingResult, CommunicationDraft |
|
|
| router = APIRouter() |
|
|
|
|
| @router.post("/book", response_model=BookingResult) |
| def book(payload: dict) -> BookingResult: |
| """Book an appointment. |
| |
| Body: {patient_id, doctor_id (optional), window_start_iso, window_end_iso} |
| """ |
| patient_id = payload.get("patient_id", "p-001") |
| doctor_id = payload.get("doctor_id") |
| try: |
| w_start = datetime.fromisoformat(payload["window_start_iso"]).replace(tzinfo=timezone.utc) |
| w_end = datetime.fromisoformat(payload["window_end_iso"]).replace(tzinfo=timezone.utc) |
| except (KeyError, ValueError): |
| now = datetime.now(timezone.utc) |
| w_start = now + timedelta(days=1, hours=9) |
| w_end = now + timedelta(days=8, hours=17) |
|
|
| return appt_api.book( |
| patient_id=patient_id, |
| requested_window=(w_start, w_end), |
| doctor_id=doctor_id, |
| ) |
|
|
|
|
| @router.post("/cancel", response_model=BookingResult) |
| def cancel(payload: dict) -> BookingResult: |
| """Cancel an appointment. Body: {appointment_id, reason}""" |
| appointment_id = payload.get("appointment_id", "") |
| if not appointment_id: |
| raise HTTPException(status_code=422, detail="appointment_id is required") |
| return appt_api.cancel(appointment_id, reason=payload.get("reason", "patient request")) |
|
|
|
|
| @router.post("/webhook/whatsapp", response_model=CommunicationDraft) |
| async def whatsapp_webhook(request: Request) -> CommunicationDraft: |
| """Twilio inbound webhook (form-encoded POST). |
| |
| Parses Twilio's payload, routes into the appointment agent, and echoes the reply |
| back to the patient via Twilio (best-effort — webhook always returns 200). |
| """ |
| from app.integrations.whatsapp import parse_inbound |
|
|
| form_data = await request.form() |
| parsed = parse_inbound(dict(form_data)) |
| draft = appt_api.handle_inbound_message(channel="whatsapp", payload=parsed) |
|
|
| try: |
| from app.integrations.whatsapp import send as wa_send |
| wa_send(to=parsed["from"], body=draft.body) |
| except Exception: |
| pass |
|
|
| return draft |
|
|
|
|
| @router.post("/inbound", response_model=CommunicationDraft) |
| def web_inbound(payload: dict) -> CommunicationDraft: |
| """Web / simulator inbound — used by patient_tab.py and tests/wa_sim.py.""" |
| return appt_api.handle_inbound_message(channel="web", payload=payload) |
|
|