from datetime import date, datetime from decimal import Decimal from sqlalchemy import Date, DateTime, ForeignKey, Integer, Numeric, String, Text, UniqueConstraint, func from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base import Base class Car(Base): __tablename__ = "cars" id: Mapped[int] = mapped_column(primary_key=True) owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(160)) make: Mapped[str | None] = mapped_column(String(80)) model: Mapped[str | None] = mapped_column(String(80)) trim: Mapped[str | None] = mapped_column(String(120)) year: Mapped[int | None] plate_number: Mapped[str | None] = mapped_column(String(32)) vin: Mapped[str | None] = mapped_column(String(32)) fuel_type: Mapped[str | None] = mapped_column(String(32)) target_consumption_l_per_100km: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) fuel_tank_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) engine_oil_type: Mapped[str | None] = mapped_column(String(80)) engine_oil_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) transmission_fluid_type: Mapped[str | None] = mapped_column(String(80)) transmission_fluid_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) coolant_type: Mapped[str | None] = mapped_column(String(80)) brake_fluid_type: Mapped[str | None] = mapped_column(String(80)) tire_pressure_front_bar: Mapped[Decimal | None] = mapped_column(Numeric(4, 2)) tire_pressure_rear_bar: Mapped[Decimal | None] = mapped_column(Numeric(4, 2)) purchase_date: Mapped[date | None] = mapped_column(Date) purchase_price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) current_odometer: Mapped[int | None] created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) owner = relationship("User", back_populates="cars") fuel_entries = relationship("FuelEntry", back_populates="car", cascade="all, delete-orphan") service_entries = relationship("ServiceEntry", back_populates="car", cascade="all, delete-orphan") service_links = relationship("CarServiceLink", back_populates="car", cascade="all, delete-orphan") class CarMake(Base): __tablename__ = "car_makes" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(80), unique=True, index=True) country: Mapped[str | None] = mapped_column(String(80)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) models = relationship("CarModel", back_populates="make", cascade="all, delete-orphan") class CarModel(Base): __tablename__ = "car_models" __table_args__ = (UniqueConstraint("make_id", "name", name="uq_car_models_make_name"),) id: Mapped[int] = mapped_column(primary_key=True) make_id: Mapped[int] = mapped_column(ForeignKey("car_makes.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(100), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) make = relationship("CarMake", back_populates="models") trims = relationship("CarTrim", back_populates="model", cascade="all, delete-orphan") class CarTrim(Base): __tablename__ = "car_trims" __table_args__ = (UniqueConstraint("model_id", "name", name="uq_car_trims_model_name"),) id: Mapped[int] = mapped_column(primary_key=True) model_id: Mapped[int] = mapped_column(ForeignKey("car_models.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(120), index=True) body_type: Mapped[str | None] = mapped_column(String(60)) fuel_type: Mapped[str | None] = mapped_column(String(32)) transmission: Mapped[str | None] = mapped_column(String(32)) drive_type: Mapped[str | None] = mapped_column(String(32)) year_from: Mapped[int | None] = mapped_column(Integer) year_to: Mapped[int | None] = mapped_column(Integer) market: Mapped[str | None] = mapped_column(String(80)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) model = relationship("CarModel", back_populates="trims") class ServiceCenter(Base): __tablename__ = "service_centers" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(160), unique=True, index=True) telegram_chat_id: Mapped[str | None] = mapped_column(String(80), unique=True, index=True) contact_phone: Mapped[str | None] = mapped_column(String(40)) address: Mapped[str | None] = mapped_column(String(240)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) car_links = relationship("CarServiceLink", back_populates="service_center", cascade="all, delete-orphan") inbox_messages = relationship("ServiceInboxMessage", back_populates="service_center") class CarServiceLink(Base): __tablename__ = "car_service_links" __table_args__ = (UniqueConstraint("car_id", "service_center_id", name="uq_car_service_link"),) id: Mapped[int] = mapped_column(primary_key=True) car_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) external_vehicle_ref: Mapped[str | None] = mapped_column(String(120), index=True) is_active: Mapped[bool] = mapped_column(default=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) car = relationship("Car", back_populates="service_links") service_center = relationship("ServiceCenter", back_populates="car_links") class ServiceInboxMessage(Base): __tablename__ = "service_inbox_messages" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="SET NULL"), index=True) car_id: Mapped[int | None] = mapped_column(ForeignKey("cars.id", ondelete="SET NULL"), index=True) source_chat_id: Mapped[str | None] = mapped_column(String(80), index=True) raw_text: Mapped[str] = mapped_column(Text) parsed_status: Mapped[str] = mapped_column(String(32), default="pending", index=True) parsed_payload: Mapped[str | None] = mapped_column(Text) error: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) service_center = relationship("ServiceCenter", back_populates="inbox_messages")