Feat: Tierärzte-Verwaltung (Sprint 4)
Neue Praxen-Tab in Gesundheit: Tierarzt-Stammdaten (Name, Adresse, Telefon, Notfall-Nr, E-Mail, Website, Notizen), Anruf- und Notfall-Schnellzugriff via tel:-Links, Soft-Delete (aktiv=0) für Praxiswechsel ohne Datenverlust. Tierarzt-Dropdown beim Eintragen von Tierarzt-Besuchen. SW-Cache → by-v7.
This commit is contained in:
parent
c06d9e24a7
commit
fc0f48c6d0
7 changed files with 371 additions and 42 deletions
|
|
@ -42,6 +42,8 @@ class HealthCreate(BaseModel):
|
|||
schweregrad: Optional[str] = None # leicht | mittel | schwer
|
||||
reaktion: Optional[str] = None
|
||||
erinnerung: Optional[int] = 1
|
||||
# Tierarzt-Verknüpfung
|
||||
tierarzt_id: Optional[int] = None
|
||||
|
||||
|
||||
class HealthUpdate(BaseModel):
|
||||
|
|
@ -62,6 +64,7 @@ class HealthUpdate(BaseModel):
|
|||
schweregrad: Optional[str] = None
|
||||
reaktion: Optional[str] = None
|
||||
erinnerung: Optional[int] = None
|
||||
tierarzt_id: Optional[int] = None
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
|
@ -113,13 +116,13 @@ async def create_health(dog_id: int, data: HealthCreate,
|
|||
(dog_id, typ, bezeichnung, datum, naechstes, notiz,
|
||||
wert, einheit, charge_nr, tierarzt_name, kosten, diagnose,
|
||||
dosierung, haeufigkeit, aktiv, bis_datum,
|
||||
schweregrad, reaktion, erinnerung)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
schweregrad, reaktion, erinnerung, tierarzt_id)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(dog_id, data.typ, data.bezeichnung, data.datum, data.naechstes,
|
||||
data.notiz, data.wert, data.einheit, data.charge_nr,
|
||||
data.tierarzt_name, data.kosten, data.diagnose, data.dosierung,
|
||||
data.haeufigkeit, data.aktiv, data.bis_datum,
|
||||
data.schweregrad, data.reaktion, data.erinnerung)
|
||||
data.schweregrad, data.reaktion, data.erinnerung, data.tierarzt_id)
|
||||
)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM health WHERE dog_id=? ORDER BY id DESC LIMIT 1",
|
||||
|
|
|
|||
91
backend/routes/tieraerzte.py
Normal file
91
backend/routes/tieraerzte.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
"""BAN YARO — Tierärzte Routes (user-level, nie löschen)"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from database import db
|
||||
from auth import get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class TierarztCreate(BaseModel):
|
||||
name: str
|
||||
adresse: Optional[str] = None
|
||||
telefon: Optional[str] = None
|
||||
notfall_telefon: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
website: Optional[str] = None
|
||||
notizen: Optional[str] = None
|
||||
ist_notfallpraxis: bool = False
|
||||
|
||||
|
||||
class TierarztUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
adresse: Optional[str] = None
|
||||
telefon: Optional[str] = None
|
||||
notfall_telefon: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
website: Optional[str] = None
|
||||
notizen: Optional[str] = None
|
||||
ist_notfallpraxis: Optional[bool] = None
|
||||
aktiv: Optional[bool] = None # False = inaktiv (Umzug etc.)
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def list_tieraerzte(user=Depends(get_current_user)):
|
||||
"""Alle Tierärzte des Users — aktive zuerst, dann inaktive (für Historienansicht)."""
|
||||
with db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM tieraerzte WHERE user_id=? ORDER BY aktiv DESC, name",
|
||||
(user["id"],)
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
@router.post("", status_code=201)
|
||||
async def create_tierarzt(data: TierarztCreate, user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
conn.execute(
|
||||
"""INSERT INTO tieraerzte
|
||||
(user_id, name, adresse, telefon, notfall_telefon,
|
||||
email, website, notizen, ist_notfallpraxis)
|
||||
VALUES (?,?,?,?,?,?,?,?,?)""",
|
||||
(user["id"], data.name, data.adresse, data.telefon,
|
||||
data.notfall_telefon, data.email, data.website,
|
||||
data.notizen, int(data.ist_notfallpraxis))
|
||||
)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM tieraerzte WHERE user_id=? ORDER BY id DESC LIMIT 1",
|
||||
(user["id"],)
|
||||
).fetchone()
|
||||
return dict(row)
|
||||
|
||||
|
||||
@router.patch("/{tierarzt_id}")
|
||||
async def update_tierarzt(tierarzt_id: int, data: TierarztUpdate,
|
||||
user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
entry = conn.execute(
|
||||
"SELECT id FROM tieraerzte WHERE id=? AND user_id=?",
|
||||
(tierarzt_id, user["id"])
|
||||
).fetchone()
|
||||
if not entry:
|
||||
raise HTTPException(404, "Tierarzt nicht gefunden.")
|
||||
|
||||
updates = {k: v for k, v in data.model_dump().items() if v is not None}
|
||||
if "ist_notfallpraxis" in updates:
|
||||
updates["ist_notfallpraxis"] = int(updates["ist_notfallpraxis"])
|
||||
if "aktiv" in updates:
|
||||
updates["aktiv"] = int(updates["aktiv"])
|
||||
if not updates:
|
||||
row = conn.execute("SELECT * FROM tieraerzte WHERE id=?", (tierarzt_id,)).fetchone()
|
||||
return dict(row)
|
||||
|
||||
set_clause = ", ".join(f"{k}=?" for k in updates)
|
||||
conn.execute(
|
||||
f"UPDATE tieraerzte SET {set_clause} WHERE id=?",
|
||||
list(updates.values()) + [tierarzt_id]
|
||||
)
|
||||
row = conn.execute("SELECT * FROM tieraerzte WHERE id=?", (tierarzt_id,)).fetchone()
|
||||
return dict(row)
|
||||
Loading…
Add table
Add a link
Reference in a new issue