dak.c2s/backend/app/models/case.py
CCS Admin 83bc1f5865 fix: make index names unique across tables for PostgreSQL compatibility
PostgreSQL requires globally unique index names (unlike MySQL which scopes
them per table). Prefix generic names: idx_user→idx_al_user/idx_rt_user,
idx_token→idx_rt_token, idx_case/idx_code/idx_haupt→idx_icd_*.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:30:08 +00:00

196 lines
7.6 KiB
Python

"""Case and ICD code models."""
from __future__ import annotations
import datetime as dt
from typing import Optional
from sqlalchemy import (
Boolean,
CheckConstraint,
Date,
DateTime,
ForeignKey,
Index,
Integer,
SmallInteger,
String,
Text,
UniqueConstraint,
func,
text,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
class Case(Base):
__tablename__ = "cases"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
fall_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
crm_ticket_id: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
jahr: Mapped[int] = mapped_column(SmallInteger, nullable=False)
kw: Mapped[int] = mapped_column(SmallInteger, nullable=False)
datum: Mapped[dt.date] = mapped_column(Date, nullable=False)
anrede: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
vorname: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
nachname: Mapped[str] = mapped_column(String(100), nullable=False)
geburtsdatum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
kvnr: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
versicherung: Mapped[str] = mapped_column(
String(50), nullable=False, server_default="DAK"
)
icd: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
fallgruppe: Mapped[str] = mapped_column(String(20), nullable=False)
strasse: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
plz: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)
ort: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
email: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
ansprechpartner: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
telefonnummer: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
mobiltelefon: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
email2: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
telefon2: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
unterlagen: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
unterlagen_verschickt: Mapped[Optional[dt.date]] = mapped_column(
Date, nullable=True
)
erhalten: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True)
unterlagen_erhalten: Mapped[Optional[dt.date]] = mapped_column(
Date, nullable=True
)
unterlagen_an_gutachter: Mapped[Optional[dt.date]] = mapped_column(
Date, nullable=True
)
gutachten: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
gutachter: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
gutachten_erstellt: Mapped[Optional[dt.date]] = mapped_column(
Date, nullable=True
)
gutachten_versendet: Mapped[Optional[dt.date]] = mapped_column(
Date, nullable=True
)
schweigepflicht: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
ablehnung: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
abbruch: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
abbruch_datum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
gutachten_typ: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
therapieaenderung: Mapped[Optional[str]] = mapped_column(String(5), nullable=True)
ta_diagnosekorrektur: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
ta_unterversorgung: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
ta_uebertherapie: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
kurzbeschreibung: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
fragestellung: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
kommentar: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
sonstiges: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
abgerechnet: Mapped[bool] = mapped_column(
Boolean, nullable=False, server_default="0"
)
abrechnung_datum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
import_source: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
imported_at: Mapped[dt.datetime] = mapped_column(
DateTime, nullable=False, server_default=func.now()
)
updated_at: Mapped[dt.datetime] = mapped_column(
DateTime,
nullable=False,
server_default=func.now(),
onupdate=func.now(),
)
updated_by: Mapped[Optional[int]] = mapped_column(
Integer, ForeignKey("users.id"), nullable=True
)
icd_entered_by: Mapped[Optional[int]] = mapped_column(
Integer, ForeignKey("users.id"), nullable=True
)
icd_entered_at: Mapped[Optional[dt.datetime]] = mapped_column(
DateTime, nullable=True
)
coding_completed_by: Mapped[Optional[int]] = mapped_column(
Integer, ForeignKey("users.id"), nullable=True
)
coding_completed_at: Mapped[Optional[dt.datetime]] = mapped_column(
DateTime, nullable=True
)
# Relationships
icd_codes: Mapped[list[CaseICDCode]] = relationship(
back_populates="case", cascade="all, delete-orphan"
)
updated_by_user: Mapped[Optional["User"]] = relationship(
foreign_keys=[updated_by]
)
icd_entered_by_user: Mapped[Optional["User"]] = relationship(
foreign_keys=[icd_entered_by]
)
coding_completed_by_user: Mapped[Optional["User"]] = relationship(
foreign_keys=[coding_completed_by]
)
__table_args__ = (
UniqueConstraint("fall_id", name="uk_fall_id"),
Index("idx_jahr_kw", "jahr", "kw"),
Index("idx_kvnr", "kvnr"),
Index("idx_fallgruppe", "fallgruppe"),
Index("idx_datum", "datum"),
Index("idx_nachname_vorname", "nachname", "vorname"),
# Note: idx_pending_icd uses a functional index on left(icd, 20).
# We use text() for the expression column.
Index("idx_pending_icd", "jahr", "kw", "fallgruppe", text("left(icd, 20)")),
Index("idx_pending_coding", "gutachten", "gutachten_typ"),
CheckConstraint(
"fallgruppe IN ('onko','kardio','intensiv','galle','sd')",
name="chk_fallgruppe",
),
CheckConstraint(
"gutachten_typ IS NULL OR gutachten_typ IN ('Bestätigung','Alternative')",
name="chk_gutachten_typ",
),
CheckConstraint(
"therapieaenderung IS NULL OR therapieaenderung IN ('Ja','Nein')",
name="chk_ta",
),
)
class CaseICDCode(Base):
__tablename__ = "case_icd_codes"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
case_id: Mapped[int] = mapped_column(
Integer,
ForeignKey("cases.id", ondelete="CASCADE"),
nullable=False,
)
icd_code: Mapped[str] = mapped_column(String(20), nullable=False)
icd_hauptgruppe: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)
created_at: Mapped[dt.datetime] = mapped_column(
DateTime, nullable=False, server_default=func.now()
)
# Relationships
case: Mapped[Case] = relationship(back_populates="icd_codes")
__table_args__ = (
Index("idx_icd_case", "case_id"),
Index("idx_icd_code", "icd_code"),
Index("idx_icd_haupt", "icd_hauptgruppe"),
)