docbot/src/db/models.py

195 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from datetime import datetime
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy.sql import func
from sqlalchemy import String, ForeignKey, BigInteger, UniqueConstraint, Text, DateTime
from sqlalchemy.dialects.postgresql import ARRAY
import enum
from typing import List, Optional
class Base(DeclarativeBase):
pass
class Sessions(Base):
__tablename__ = "sessions"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(8), unique=True, nullable=False)
patient_id: Mapped[int] = mapped_column(
ForeignKey("patients.id", ondelete="CASCADE"), nullable=False)
patient: Mapped["Patients"] = relationship(back_populates="sessions")
sent_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
consulted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
doctor_id: Mapped[int] = mapped_column(ForeignKey("doctors.id"))
session_status_history: Mapped[List["SessionStatusHistory"]] = relationship(
back_populates="sessions", cascade="all, delete-orphan")
session_date_time_history: Mapped[List["SessionDateTimeHistory"]] = relationship(
back_populates="sessions", cascade="all, delete-orphan")
paid_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
class SessionDateTimeHistory(Base):
__tablename__ = "session_date_time_history"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
sessions_id: Mapped[int] = mapped_column(ForeignKey("sessions.id", ondelete="CASCADE"), nullable=False)
sessions: Mapped["Sessions"] = relationship(back_populates="session_date_time_history")
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
consultation_date_time: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
who_updated: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
class SessionStatusHistory(Base):
__tablename__ = "session_status_history"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
sessions_id: Mapped[int] = mapped_column(ForeignKey("sessions.id", ondelete="CASCADE"), nullable=False)
sessions: Mapped["Sessions"] = relationship(back_populates="session_status_history")
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
status: Mapped[str] = mapped_column(String(50), nullable=False, default="pending")
who_updated: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
class Admins(Base):
__tablename__ = "admins"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
telegram_id: Mapped[int] = mapped_column(BigInteger, unique=True, nullable=False)
created_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
available_payment_methods: Mapped[Optional[List[str]]] = mapped_column(
ARRAY(String), nullable=True)
class Patients(Base):
__tablename__ = "patients"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
telegram_id: Mapped[int] = mapped_column(BigInteger, unique=True, nullable=False)
phone: Mapped[Optional[str]] = mapped_column(nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
accepted_terms: Mapped[bool] = mapped_column(default=False, nullable=True)
sessions: Mapped[List["Sessions"]] = relationship(
back_populates="patient", cascade="all, delete-orphan")
class Doctors(Base):
__tablename__ = "doctors"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(unique=True, nullable=True)
time_zone: Mapped[Optional[str]] = mapped_column(nullable=True)
telegram_id: Mapped[int] = mapped_column(BigInteger, unique=True, nullable=False)
name: Mapped[str] = mapped_column(nullable=False)
available_formats: Mapped[Optional[List[str]]
] = mapped_column(ARRAY(String), nullable=True)
is_active: Mapped[bool] = mapped_column(default=False, nullable=False)
is_verified: Mapped[bool] = mapped_column(default=False, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
referral_code_id: Mapped[int] = mapped_column(
ForeignKey("referral_codes.id"), nullable=False)
specialties: Mapped[List[str]] = mapped_column(
ARRAY(String), nullable=False, default=list)
referral: Mapped["ReferralCode"] = relationship(
back_populates="doctor", uselist=False)
sessions: Mapped[List["Sessions"]] = relationship()
form_links: Mapped[List["FormLink"]] = relationship(
back_populates="doctor", cascade="all, delete-orphan")
payment_methods: Mapped[List["PaymentMethod"]] = relationship(
back_populates="doctor", cascade="all, delete-orphan")
verification_requests: Mapped[List["VerificationRequests"]] = relationship(
back_populates="doctor", cascade="all, delete-orphan")
def __repr__(self) -> str:
return f"<Doctors(telegram_id={self.telegram_id!r}, name={self.name!r}, is_active={self.is_active})>"
class ReferralCode(Base):
__tablename__ = "referral_codes"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(unique=True, nullable=False)
is_used: Mapped[bool] = mapped_column(default=False, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
used_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
doctor: Mapped[Optional["Doctors"]] = relationship(
back_populates="referral", uselist=False)
def __repr__(self) -> str:
return f"<ReferralCode(code={self.code!r}, is_used={self.is_used})>"
class VerificationRequests(Base):
__tablename__ = "verification_requests"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
doctor_id: Mapped[int] = mapped_column(
ForeignKey("doctors.id", ondelete="CASCADE"), unique=True, nullable=False)
code: Mapped[str] = mapped_column(unique=True, nullable=False)
sent_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
reviewed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
status: Mapped[str] = mapped_column(default=False, nullable=False)
# Связь поправлена — связь с doctor через doctor_id
doctor: Mapped["Doctors"] = relationship(
back_populates="verification_requests")
def __repr__(self) -> str:
return f"<VerificationRequests(code={self.code!r}, status={self.status!r}, sent_at={self.sent_at!r})>"
class FormLink(Base):
__tablename__ = "form_links"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
doctor_id: Mapped[int] = mapped_column(
ForeignKey("doctors.id", ondelete="CASCADE"), unique=True, nullable=False)
url: Mapped[str] = mapped_column(nullable=False)
label: Mapped[Optional[str]] = mapped_column(nullable=True)
is_active: Mapped[bool] = mapped_column(default=True, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
doctor: Mapped["Doctors"] = relationship(back_populates="form_links")
class PaymentMethod(Base):
__tablename__ = "payment_methods"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
doctor_id: Mapped[int] = mapped_column(
ForeignKey("doctors.id", ondelete="CASCADE"), unique=True, nullable=False)
method: Mapped[str] = mapped_column(nullable=False)
details: Mapped[Optional[str]] = mapped_column(nullable=True)
payment_api_key: Mapped[str] = mapped_column(nullable=False)
is_active: Mapped[bool] = mapped_column(default=True, nullable=False)
is_primary: Mapped[bool] = mapped_column(default=True, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
doctor: Mapped["Doctors"] = relationship(back_populates="payment_methods")
class PaymentsRegistered(Base):
__tablename__ = "payments_registered"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(8), unique=True, nullable=False)
mapped: Mapped[bool] = mapped_column(nullable=True)
class NotificationType(enum.Enum):
PAYMENT_RECEIVED = "payment_received"
FIRST_REMINDER_SENT = "first_reminder_sent"
class SessionNotification(Base):
__tablename__ = "session_notifications"
__table_args__ = (
UniqueConstraint("session_id", "type", name="uq_session_notification_once"),
)
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
session_id: Mapped[int] = mapped_column(ForeignKey("sessions.id", ondelete="CASCADE"), nullable=False)
patient_id: Mapped[int] = mapped_column(ForeignKey("patients.id", ondelete="CASCADE"), nullable=False)
type: Mapped[NotificationType] = mapped_column(nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
sent_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
last_error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)