diff --git a/src/db/models.py b/src/db/models.py index 29a9252..beae98f 100644 --- a/src/db/models.py +++ b/src/db/models.py @@ -1,86 +1,109 @@ -from sqlalchemy import Column, String, DateTime, ARRAY, Boolean, ForeignKey, Integer, Table, UniqueConstraint -from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import relationship +from __future__ import annotations +from datetime import datetime +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship +from sqlalchemy import String, DateTime, Boolean, ForeignKey, Integer, UniqueConstraint +from sqlalchemy.dialects.postgresql import UUID, ARRAY import uuid +from typing import List, Optional -Base = declarative_base() +class Base(DeclarativeBase): + pass class SessionCode(Base): __tablename__ = "session_codes" - id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) - code = Column(String(8), unique=True, nullable=False) - telegram_id = Column(Integer, nullable=False) - sent_at = Column(DateTime, nullable=False) - consulted_at = Column(DateTime, nullable=True) - doctor_id = Column(UUID, ForeignKey("doctors.id")) - form_link_response = Column(String, nullable=True) + + id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + code: Mapped[str] = mapped_column(String(8), unique=True, nullable=False) + patient_telegram_id: Mapped[int] = mapped_column(nullable=False) + sent_at: Mapped[datetime] = mapped_column(nullable=False) + consulted_at: Mapped[Optional[datetime]] = mapped_column(nullable=True) + doctor_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("doctors.id")) class Admins(Base): __tablename__ = "admins" - id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) - telegram_id = Column(Integer, unique=True, nullable=False) - created_at = Column(DateTime, nullable=True) - available_payment_methods = Column(ARRAY(String), nullable=True) + + id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + telegram_id: Mapped[int] = mapped_column(unique=True, nullable=False) + created_at: Mapped[Optional[datetime]] = mapped_column(nullable=True) + available_payment_methods: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True) class Doctors(Base): __tablename__ = "doctors" - id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) - telegram_id = Column(Integer, unique=True, nullable=False) - code = Column(String(8), unique=True, nullable=False) - name = Column(String, nullable=False) - available_formats = Column(ARRAY(String), nullable=True) - is_active = Column(Boolean, default=False, nullable=False) - is_verified = Column(Boolean, default=False, nullable=False) - created_at = Column(DateTime, nullable=False) - referral_code_id = Column(Integer, ForeignKey("referral_codes.id"), nullable=False) - specialties = Column(ARRAY(String), nullable=False, default=list) - referral = relationship("ReferralCode", back_populates="doctor") - session_codes = relationship("SessionCode") - form_links = relationship("FormLink", back_populates="doctor", cascade="all, delete-orphan") - payment_methods = relationship("PaymentMethod", back_populates="doctor", cascade="all, delete-orphan") + id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + telegram_id: Mapped[int] = mapped_column(unique=True, nullable=False) + code: Mapped[str] = mapped_column(String(8), 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(nullable=False) + 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) - def __repr__(self): + referral: Mapped["ReferralCode"] = relationship(back_populates="doctor", uselist=False) + session_codes: Mapped[List["SessionCode"]] = 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") + + def __repr__(self) -> str: return f"" class ReferralCode(Base): __tablename__ = "referral_codes" - id = Column(Integer, primary_key=True) - code = Column(String, unique=True, nullable=False) - is_used = Column(Boolean, default=False) - created_at = Column(DateTime, nullable=False) - used_at = Column(DateTime, nullable=True) - doctor = relationship("Doctors", back_populates="referral", uselist=False) - def __repr__(self): + id: Mapped[int] = mapped_column(primary_key=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(nullable=False) + used_at: Mapped[Optional[datetime]] = mapped_column(nullable=True) + doctor: Mapped[Optional["Doctors"]] = relationship(back_populates="referral", uselist=False) + + def __repr__(self) -> str: return f"" +class VerificationRequests(Base): + __tablename__ = "verification_requests" + + id: Mapped[int] = mapped_column(primary_key=True) + doctor_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("doctors.id", ondelete="CASCADE"), nullable=False) + code: Mapped[str] = mapped_column(unique=True, nullable=False) + sent_at: Mapped[datetime] = mapped_column(nullable=False) + reviewed_at: Mapped[Optional[datetime]] = mapped_column(nullable=True) + # Связь поправлена — связь с doctor через doctor_id + doctor: Mapped["Doctors"] = relationship() + + def __repr__(self) -> str: + return f"" + + class FormLink(Base): __tablename__ = "form_links" - id = Column(Integer, primary_key=True) - doctor_id = Column(UUID(as_uuid=True), ForeignKey("doctors.id", ondelete="CASCADE"), nullable=False) - url = Column(String, nullable=False) - label = Column(String, nullable=True) - is_active = Column(Boolean, default=True, nullable=False) - created_at = Column(DateTime, nullable=False) - doctor = relationship("Doctors", back_populates="form_links") + id: Mapped[int] = mapped_column(primary_key=True) + doctor_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("doctors.id", ondelete="CASCADE"), 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(nullable=False) + + doctor: Mapped["Doctors"] = relationship(back_populates="form_links") class PaymentMethod(Base): __tablename__ = "payment_methods" - id = Column(Integer, primary_key=True) - doctor_id = Column(UUID(as_uuid=True), ForeignKey("doctors.id", ondelete="CASCADE"), nullable=False) - method = Column(String, nullable=False) - details = Column(String, nullable=True) - is_active = Column(Boolean, default=True, nullable=False) - created_at = Column(DateTime, nullable=False) - doctor = relationship("Doctor", back_populates="payment_methods") \ No newline at end of file + id: Mapped[int] = mapped_column(primary_key=True) + doctor_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("doctors.id", ondelete="CASCADE"), nullable=False) + method: Mapped[str] = mapped_column(nullable=False) + details: Mapped[Optional[str]] = mapped_column(nullable=True) + is_active: Mapped[bool] = mapped_column(default=True, nullable=False) + created_at: Mapped[datetime] = mapped_column(nullable=False) + + doctor: Mapped["Doctors"] = relationship(back_populates="payment_methods") \ No newline at end of file diff --git a/src/docbot/handlers/doctors/register_handler.py b/src/docbot/handlers/doctors/register_handler.py index c0c09f3..a5ba083 100644 --- a/src/docbot/handlers/doctors/register_handler.py +++ b/src/docbot/handlers/doctors/register_handler.py @@ -9,7 +9,6 @@ from telegram.ext import ( from docbot.handlers.utils.cancel_handler import get_cancel_handler from docbot.services.referral_service import validate_referral_code, mark_referral_code_as_used -from core.enums.consultation_types import Consultation from core.enums.dialog_helpers import ConfirmationMessage, Acknowledgement ASK_REFERRAL_CODE = 1 @@ -20,7 +19,7 @@ SEND_DIPLOMA_ACK_INFO = 5 SEND_CONSULTATION_TYPE_ACK_INFO = 6 SEND_ME_REFERRAL_CODE_TEXT = ( - "📝 Пожалуйста, пришлите реферальный код, чтобы начать процесс регистрации." + "✌️ Пожалуйста, пришлите реферальный код, чтобы начать процесс регистрации." ) ACCEPT_OFFER_TEXT = ( "📝 Продолжая работу с ботом, вы соглашаетесь с условиями оферты и на обработку персональных данных! \n" @@ -161,8 +160,11 @@ async def receive_doctor_consultation_packages_acknowledgement_status(update: Up parse_mode="Markdown" ) - await mark_referral_code_as_used(context.user_data["ref_obj"], context.user_data["doctor_telegram_id"], - context.user_data["doctor_name"]) + await mark_referral_code_as_used( + context.user_data["ref_obj"], + context.user_data["doctor_telegram_id"], + context.user_data["doctor_name"] + ) return ConversationHandler.END @@ -191,7 +193,8 @@ def get_register_doctor_first_stage_handler() -> ConversationHandler: MessageHandler(filters.TEXT & ~filters.COMMAND, receive_doctor_diploma_acknowledgement_status) ], SEND_CONSULTATION_TYPE_ACK_INFO: [ - MessageHandler(filters.TEXT & ~filters.COMMAND, receive_doctor_consultation_packages_acknowledgement_status) + MessageHandler(filters.TEXT & ~filters.COMMAND, + receive_doctor_consultation_packages_acknowledgement_status) ], }, fallbacks=[get_cancel_handler()], diff --git a/src/docbot/services/session_service.py b/src/docbot/services/session_service.py index 79c597c..d910f69 100644 --- a/src/docbot/services/session_service.py +++ b/src/docbot/services/session_service.py @@ -19,8 +19,7 @@ async def create_session_code(telegram_id: int, form_link: str) -> str: async with session.begin(): session.add(SessionCode( code=code, - telegram_id=telegram_id, # храним как строку - form_link=form_link, + patient_telegram_id=telegram_id, sent_at=datetime.utcnow() )) return code @@ -51,7 +50,7 @@ async def get_pending_session(telegram_id: int) -> SessionCode | None: async with AsyncSessionLocal() as session: result = await session.execute( select(SessionCode) - .where(SessionCode.telegram_id.match(telegram_id)) + .where(SessionCode.patient_telegram_id.match(telegram_id)) .where(SessionCode.consulted_at.is_(None)) .order_by(SessionCode.sent_at.desc()) .limit(1) @@ -72,7 +71,7 @@ async def get_session_info(code: str) -> dict | None: if not sc: return None return { - "telegram_id": sc.telegram_id, + "telegram_id": sc.patient_telegram_id, "form_link": sc.form_link, "sent_at": sc.sent_at, "consulted_at": sc.consulted_at,