"""SQLAlchemy model for sales (Verkauf).""" import enum import uuid from datetime import date, datetime from decimal import Decimal from typing import TYPE_CHECKING from sqlalchemy import ( Boolean, CheckConstraint, Date, DateTime, ForeignKey, Numeric, String, func, ) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base if TYPE_CHECKING: from app.models.contact import Contact from app.models.vehicle import Vehicle class SaleStatus(str, enum.Enum): draft = "draft" completed = "completed" cancelled = "cancelled" class Sale(Base): """Sale entity linking a vehicle to a buyer (and optionally a seller).""" __tablename__ = "sales" __table_args__ = ( CheckConstraint( "status IN ('draft', 'completed', 'cancelled')", name="ck_sales_status", ), ) id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, ) vehicle_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("vehicles.id", ondelete="RESTRICT"), nullable=False, index=True, ) buyer_contact_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("contacts.id", ondelete="RESTRICT"), nullable=False, index=True, ) seller_contact_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("contacts.id", ondelete="SET NULL"), nullable=True, index=True, ) sale_price: Mapped[Decimal] = mapped_column( Numeric(12, 2), nullable=False ) sale_date: Mapped[date] = mapped_column( Date, nullable=False, default=func.current_date() ) status: Mapped[str] = mapped_column( String(20), nullable=False, default="draft" ) is_gwg: Mapped[bool] = mapped_column( Boolean, nullable=False, default=False ) contract_pdf_path: Mapped[str | None] = mapped_column( String(500), nullable=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now(), ) vehicle: Mapped["Vehicle"] = relationship(lazy="selectin") buyer: Mapped["Contact"] = relationship( "Contact", foreign_keys=[buyer_contact_id], lazy="selectin", ) seller: Mapped["Contact | None"] = relationship( "Contact", foreign_keys=[seller_contact_id], lazy="selectin", ) def __repr__(self) -> str: return f"" def to_dict(self) -> dict: """Serialize sale for API responses.""" return { "id": str(self.id), "vehicle_id": str(self.vehicle_id), "buyer_contact_id": str(self.buyer_contact_id), "seller_contact_id": ( str(self.seller_contact_id) if self.seller_contact_id else None ), "sale_price": float(self.sale_price) if self.sale_price is not None else None, "sale_date": self.sale_date.isoformat() if self.sale_date else None, "status": self.status, "is_gwg": self.is_gwg, "contract_pdf_path": self.contract_pdf_path, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None, }