chore: sync uncommitted working tree changes before clone cleanup
This commit is contained in:
+13
-13
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from sqlalchemy import JSON, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -11,12 +11,12 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.user import User
|
||||
from app.models.activity import Activity
|
||||
from app.models.contact import Contact
|
||||
from app.models.deal import Deal
|
||||
from app.models.activity import Activity
|
||||
from app.models.note import Note
|
||||
from app.models.tag_link import TagLink
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class Industry(str, Enum):
|
||||
@@ -43,36 +43,36 @@ class Account(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
|
||||
website: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
|
||||
industry: Mapped[Optional[Industry]] = mapped_column(
|
||||
website: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
industry: Mapped[Industry | None] = mapped_column(
|
||||
String(32), nullable=True, index=True
|
||||
)
|
||||
size: Mapped[Optional[AccountSize]] = mapped_column(String(32), nullable=True)
|
||||
address: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON, nullable=True)
|
||||
size: Mapped[AccountSize | None] = mapped_column(String(32), nullable=True)
|
||||
address: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
|
||||
owner_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=False, index=True
|
||||
)
|
||||
|
||||
# Relationships
|
||||
owner: Mapped["User"] = relationship(
|
||||
owner: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[owner_id], lazy="joined"
|
||||
)
|
||||
contacts: Mapped[list["Contact"]] = relationship(
|
||||
contacts: Mapped[list[Contact]] = relationship(
|
||||
"Contact", back_populates="account", lazy="selectin"
|
||||
)
|
||||
deals: Mapped[list["Deal"]] = relationship(
|
||||
deals: Mapped[list[Deal]] = relationship(
|
||||
"Deal", back_populates="account", lazy="selectin"
|
||||
)
|
||||
activities: Mapped[list["Activity"]] = relationship(
|
||||
activities: Mapped[list[Activity]] = relationship(
|
||||
"Activity", back_populates="account", lazy="selectin"
|
||||
)
|
||||
notes: Mapped[list["Note"]] = relationship(
|
||||
notes: Mapped[list[Note]] = relationship(
|
||||
"Note",
|
||||
primaryjoin="and_(Account.id==foreign(Note.parent_id), Note.parent_type=='account')",
|
||||
viewonly=True,
|
||||
lazy="selectin",
|
||||
)
|
||||
tags: Mapped[list["TagLink"]] = relationship(
|
||||
tags: Mapped[list[TagLink]] = relationship(
|
||||
"TagLink",
|
||||
primaryjoin="and_(Account.id==foreign(TagLink.parent_id), TagLink.parent_type=='account')",
|
||||
viewonly=True,
|
||||
|
||||
+12
-12
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -12,10 +12,10 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.user import User
|
||||
from app.models.account import Account
|
||||
from app.models.contact import Contact
|
||||
from app.models.deal import Deal
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class ActivityType(str, Enum):
|
||||
@@ -36,20 +36,20 @@ class Activity(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
String(32), nullable=False, index=True
|
||||
)
|
||||
subject: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
body: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
due_date: Mapped[Optional[datetime]] = mapped_column(
|
||||
body: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
due_date: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True, index=True
|
||||
)
|
||||
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
completed_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True
|
||||
)
|
||||
account_id: Mapped[Optional[int]] = mapped_column(
|
||||
account_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
contact_id: Mapped[Optional[int]] = mapped_column(
|
||||
contact_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("contacts.id"), nullable=True, index=True
|
||||
)
|
||||
deal_id: Mapped[Optional[int]] = mapped_column(
|
||||
deal_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("deals.id"), nullable=True, index=True
|
||||
)
|
||||
owner_id: Mapped[int] = mapped_column(
|
||||
@@ -57,16 +57,16 @@ class Activity(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
)
|
||||
|
||||
# Relationships
|
||||
account: Mapped[Optional["Account"]] = relationship(
|
||||
account: Mapped[Account | None] = relationship(
|
||||
"Account", back_populates="activities", lazy="selectin"
|
||||
)
|
||||
contact: Mapped[Optional["Contact"]] = relationship(
|
||||
contact: Mapped[Contact | None] = relationship(
|
||||
"Contact", back_populates="activities", lazy="selectin"
|
||||
)
|
||||
deal: Mapped[Optional["Deal"]] = relationship(
|
||||
deal: Mapped[Deal | None] = relationship(
|
||||
"Deal", back_populates="activities", lazy="selectin"
|
||||
)
|
||||
owner: Mapped["User"] = relationship(
|
||||
owner: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[owner_id], lazy="joined"
|
||||
)
|
||||
|
||||
|
||||
+1
-2
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
@@ -31,7 +30,7 @@ class TimestampMixin:
|
||||
class SoftDeleteMixin:
|
||||
"""Adds deleted_at column for soft-delete pattern."""
|
||||
|
||||
deleted_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
default=None,
|
||||
|
||||
+10
-10
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -10,11 +10,11 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.user import User
|
||||
from app.models.account import Account
|
||||
from app.models.activity import Activity
|
||||
from app.models.note import Note
|
||||
from app.models.tag_link import TagLink
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class Contact(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
@@ -23,9 +23,9 @@ class Contact(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
first_name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
last_name: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
|
||||
email: Mapped[Optional[str]] = mapped_column(String(255), nullable=True, index=True)
|
||||
phone: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
account_id: Mapped[Optional[int]] = mapped_column(
|
||||
email: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True)
|
||||
phone: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
account_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
owner_id: Mapped[int] = mapped_column(
|
||||
@@ -33,22 +33,22 @@ class Contact(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
)
|
||||
|
||||
# Relationships
|
||||
account: Mapped[Optional["Account"]] = relationship(
|
||||
account: Mapped[Account | None] = relationship(
|
||||
"Account", back_populates="contacts", lazy="selectin"
|
||||
)
|
||||
owner: Mapped["User"] = relationship(
|
||||
owner: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[owner_id], lazy="joined"
|
||||
)
|
||||
activities: Mapped[list["Activity"]] = relationship(
|
||||
activities: Mapped[list[Activity]] = relationship(
|
||||
"Activity", back_populates="contact", lazy="selectin"
|
||||
)
|
||||
notes: Mapped[list["Note"]] = relationship(
|
||||
notes: Mapped[list[Note]] = relationship(
|
||||
"Note",
|
||||
primaryjoin="and_(Contact.id==foreign(Note.parent_id), Note.parent_type=='contact')",
|
||||
viewonly=True,
|
||||
lazy="selectin",
|
||||
)
|
||||
tags: Mapped[list["TagLink"]] = relationship(
|
||||
tags: Mapped[list[TagLink]] = relationship(
|
||||
"TagLink",
|
||||
primaryjoin="and_(Contact.id==foreign(TagLink.parent_id), TagLink.parent_type=='contact')",
|
||||
viewonly=True,
|
||||
|
||||
+11
-11
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Date, ForeignKey, Numeric, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -13,12 +13,12 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.user import User
|
||||
from app.models.account import Account
|
||||
from app.models.activity import Activity
|
||||
from app.models.deal_stage_history import DealStageHistory
|
||||
from app.models.note import Note
|
||||
from app.models.tag_link import TagLink
|
||||
from app.models.deal_stage_history import DealStageHistory
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class DealStage(str, Enum):
|
||||
@@ -48,39 +48,39 @@ class Deal(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
server_default=DealStage.lead.value,
|
||||
index=True,
|
||||
)
|
||||
close_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
close_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
account_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=False, index=True
|
||||
)
|
||||
owner_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=False, index=True
|
||||
)
|
||||
won_lost_reason: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
|
||||
won_lost_reason: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
|
||||
# Relationships
|
||||
account: Mapped["Account"] = relationship(
|
||||
account: Mapped[Account] = relationship(
|
||||
"Account", back_populates="deals", lazy="selectin"
|
||||
)
|
||||
owner: Mapped["User"] = relationship(
|
||||
owner: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[owner_id], lazy="joined"
|
||||
)
|
||||
stage_history: Mapped[list["DealStageHistory"]] = relationship(
|
||||
stage_history: Mapped[list[DealStageHistory]] = relationship(
|
||||
"DealStageHistory",
|
||||
back_populates="deal",
|
||||
cascade="all, delete-orphan",
|
||||
lazy="selectin",
|
||||
order_by="DealStageHistory.created_at",
|
||||
)
|
||||
activities: Mapped[list["Activity"]] = relationship(
|
||||
activities: Mapped[list[Activity]] = relationship(
|
||||
"Activity", back_populates="deal", lazy="selectin"
|
||||
)
|
||||
notes: Mapped[list["Note"]] = relationship(
|
||||
notes: Mapped[list[Note]] = relationship(
|
||||
"Note",
|
||||
primaryjoin="and_(Deal.id==foreign(Note.parent_id), Note.parent_type=='deal')",
|
||||
viewonly=True,
|
||||
lazy="selectin",
|
||||
)
|
||||
tags: Mapped[list["TagLink"]] = relationship(
|
||||
tags: Mapped[list[TagLink]] = relationship(
|
||||
"TagLink",
|
||||
primaryjoin="and_(Deal.id==foreign(TagLink.parent_id), TagLink.parent_type=='deal')",
|
||||
viewonly=True,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -11,8 +11,8 @@ 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
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class DealStageHistory(Base, TimestampMixin, OrgScopedMixin):
|
||||
@@ -24,16 +24,16 @@ class DealStageHistory(Base, TimestampMixin, OrgScopedMixin):
|
||||
deal_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("deals.id"), nullable=False, index=True
|
||||
)
|
||||
from_stage: Mapped[Optional[DealStage]] = mapped_column(String(32), nullable=True)
|
||||
from_stage: Mapped[DealStage | None] = 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: Mapped[Deal] = relationship(
|
||||
"Deal", back_populates="stage_history", lazy="joined"
|
||||
)
|
||||
changer: Mapped["User"] = relationship(
|
||||
changer: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[changed_by], lazy="joined"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ class Note(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
# Service layer (note_service.create_note) validates existence.
|
||||
parent_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
|
||||
|
||||
author: Mapped["User"] = relationship(
|
||||
author: Mapped[User] = relationship(
|
||||
"User", foreign_keys=[author_id], lazy="joined"
|
||||
)
|
||||
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -18,13 +18,13 @@ class Org(Base, TimestampMixin):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
logo_url: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)
|
||||
logo_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||||
default_currency: Mapped[str] = mapped_column(
|
||||
String(3), nullable=False, default="EUR", server_default="EUR"
|
||||
)
|
||||
|
||||
# Relationship to users (defined here to resolve circular import)
|
||||
users: Mapped[list["User"]] = relationship(
|
||||
users: Mapped[list[User]] = relationship(
|
||||
back_populates="org",
|
||||
lazy="selectin",
|
||||
cascade="all, delete-orphan",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ class Tag(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
)
|
||||
|
||||
# Relationships
|
||||
links: Mapped[list["TagLink"]] = relationship(
|
||||
links: Mapped[list[TagLink]] = relationship(
|
||||
"TagLink", back_populates="tag", cascade="all, delete-orphan", lazy="selectin"
|
||||
)
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class TagLink(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
# Service layer (tag_service.link_tag) validates existence.
|
||||
parent_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
|
||||
|
||||
tag: Mapped["Tag"] = relationship("Tag", back_populates="links", lazy="joined")
|
||||
tag: Mapped[Tag] = relationship("Tag", back_populates="links", lazy="joined")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<TagLink id={self.id} tag={self.tag_id} parent={self.parent_type}:{self.parent_id}>"
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, String, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -38,13 +38,13 @@ class User(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin):
|
||||
default=UserRole.sales_rep,
|
||||
server_default=UserRole.sales_rep.value,
|
||||
)
|
||||
avatar_url: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)
|
||||
avatar_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||||
email_notifications: Mapped[bool] = mapped_column(
|
||||
Boolean, nullable=False, default=True, server_default="1"
|
||||
)
|
||||
|
||||
# Relationship back to org (string reference avoids circular import at runtime)
|
||||
org: Mapped["Org"] = relationship(back_populates="users", lazy="joined")
|
||||
org: Mapped[Org] = relationship(back_populates="users", lazy="joined")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<User id={self.id} email={self.email!r} role={self.role}>"
|
||||
|
||||
Reference in New Issue
Block a user