diff --git a/backend/app/models/valuation.py b/backend/app/models/valuation.py new file mode 100644 index 0000000..149c617 --- /dev/null +++ b/backend/app/models/valuation.py @@ -0,0 +1,115 @@ +import enum +from datetime import datetime, date, timezone +from decimal import Decimal +from sqlalchemy import ( + String, Boolean, Date, DateTime, DECIMAL, Integer, Text, + ForeignKey, Enum as SAEnum +) +from sqlalchemy.orm import Mapped, mapped_column, relationship +from app.core.database import Base + + +class ValuationStatus(str, enum.Enum): + bozza = "bozza" + inviata = "inviata" + in_lavorazione = "in_lavorazione" + completata = "completata" + vinta = "vinta" + persa = "persa" + + +class ValuationPriority(str, enum.Enum): + contratto = "contratto" + preventivo = "preventivo" + valutazione = "valutazione" + + +class RetakeRegime(str, enum.Enum): + nuovo = "nuovo" + usato = "usato" + + +class Valuation(Base): + __tablename__ = "valuations" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + plate: Mapped[str] = mapped_column(String(10), ForeignKey("vehicle_registry.plate"), nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) + group_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("groups.id")) + motornet_code: Mapped[str | None] = mapped_column(String(20), ForeignKey("vehicle_versions.motornet_code")) + mileage: Mapped[int | None] = mapped_column(Integer) + retake_regime: Mapped[RetakeRegime | None] = mapped_column(SAEnum(RetakeRegime)) + expected_return_date: Mapped[date | None] = mapped_column(Date) + interest_fuel: Mapped[str | None] = mapped_column(String(50)) + priority: Mapped[ValuationPriority] = mapped_column( + SAEnum(ValuationPriority), default=ValuationPriority.valutazione + ) + notes: Mapped[str | None] = mapped_column(Text) + status: Mapped[ValuationStatus] = mapped_column( + SAEnum(ValuationStatus), default=ValuationStatus.bozza, index=True + ) + final_value: Mapped[Decimal | None] = mapped_column(DECIMAL(10, 2)) + evaluator_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("users.id")) + evaluator_notes: Mapped[str | None] = mapped_column(Text) + is_frozen: Mapped[bool] = mapped_column(Boolean, default=False) + priority_rank: Mapped[int] = mapped_column(Integer, default=3) + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) + ) + updated_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), + default=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + ) + + photos: Mapped[list["ValuationPhoto"]] = relationship("ValuationPhoto", back_populates="valuation") + comments: Mapped[list["ValuationComment"]] = relationship("ValuationComment", back_populates="valuation") + history: Mapped[list["ValuationHistory"]] = relationship("ValuationHistory", back_populates="valuation") + contracts: Mapped[list["ValuationContract"]] = relationship("ValuationContract", back_populates="valuation") + motornet_valuations: Mapped[list["MotornetValuation"]] = relationship("MotornetValuation", back_populates="valuation") + + +class ValuationPhoto(Base): + __tablename__ = "valuation_photos" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + valuation_id: Mapped[int] = mapped_column(Integer, ForeignKey("valuations.id"), nullable=False) + filename: Mapped[str] = mapped_column(String(255), nullable=False) + storage_path: Mapped[str] = mapped_column(String(500), nullable=False) + uploaded_by: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) + uploaded_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) + ) + + valuation: Mapped["Valuation"] = relationship("Valuation", back_populates="photos") + + +class ValuationComment(Base): + __tablename__ = "valuation_comments" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + valuation_id: Mapped[int] = mapped_column(Integer, ForeignKey("valuations.id"), nullable=False) + user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) + content: Mapped[str] = mapped_column(Text, nullable=False) + visible_to_all: Mapped[bool] = mapped_column(Boolean, default=True) + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) + ) + + valuation: Mapped["Valuation"] = relationship("Valuation", back_populates="comments") + + +class ValuationHistory(Base): + __tablename__ = "valuation_history" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + valuation_id: Mapped[int] = mapped_column(Integer, ForeignKey("valuations.id"), nullable=False) + changed_by: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) + field_name: Mapped[str] = mapped_column(String(100), nullable=False) + old_value: Mapped[str | None] = mapped_column(Text) + new_value: Mapped[str | None] = mapped_column(Text) + changed_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) + ) + + valuation: Mapped["Valuation"] = relationship("Valuation", back_populates="history")