Upload app/models/deal_stage_history.py

This commit is contained in:
2026-06-04 00:06:18 +00:00
parent 449fc28670
commit b561b3ec02
+44
View File
@@ -0,0 +1,44 @@
"""DealStageHistory model: audit trail of stage transitions for a deal."""
from __future__ import annotations
from typing import TYPE_CHECKING, Optional
from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base, OrgScopedMixin, TimestampMixin
from app.models.deal import DealStage
if TYPE_CHECKING:
from app.models.user import User
from app.models.deal import Deal
class DealStageHistory(Base, TimestampMixin, OrgScopedMixin):
"""Records each deal stage transition. Append-only — no soft-delete."""
__tablename__ = "deal_stage_history"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
deal_id: Mapped[int] = mapped_column(
ForeignKey("deals.id"), nullable=False, index=True
)
from_stage: Mapped[Optional[DealStage]] = mapped_column(String(32), nullable=True)
to_stage: Mapped[DealStage] = mapped_column(String(32), nullable=False)
changed_by: Mapped[int] = mapped_column(
ForeignKey("users.id"), nullable=False
)
deal: Mapped["Deal"] = relationship(
"Deal", back_populates="stage_history", lazy="joined"
)
changer: Mapped["User"] = relationship(
"User", foreign_keys=[changed_by], lazy="joined"
)
def __repr__(self) -> str:
return f"<DealStageHistory id={self.id} deal={self.deal_id} {self.from_stage}->{self.to_stage}>"
__all__ = ["DealStageHistory"]