Files
erp-nutzfahrzeuge/backend/app/models/contact.py
T

220 lines
6.0 KiB
Python
Raw Normal View History

"""SQLAlchemy models for contacts and contact persons."""
import enum
import uuid
from datetime import datetime
from sqlalchemy import (
Boolean,
CheckConstraint,
DateTime,
ForeignKey,
String,
func,
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
class ContactRole(str, enum.Enum):
kaeufer = "kaeufer"
verkaeufer = "verkaeufer"
beide = "beide"
class VatIdStatus(str, enum.Enum):
ungeprueft = "ungeprueft"
geprueft = "geprueft"
ungueltig = "ungueltig"
manuell_bestaetigt = "manuell_bestaetigt"
class Contact(Base):
"""Contact entity representing a company or private contact."""
__tablename__ = "contacts"
__table_args__ = (
CheckConstraint(
"role IN ('kaeufer', 'verkaeufer', 'beide')",
name="ck_contacts_role",
),
CheckConstraint(
"vat_id_status IN ('ungeprueft', 'geprueft', 'ungueltig', 'manuell_bestaetigt')",
name="ck_contacts_vat_id_status",
),
CheckConstraint(
"char_length(address_country) = 2",
name="ck_contacts_country_alpha2",
),
)
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
primary_key=True,
default=uuid.uuid4,
)
company_name: Mapped[str] = mapped_column(
String(255),
nullable=False,
index=True,
)
legal_form: Mapped[str | None] = mapped_column(
String(50),
nullable=True,
)
address_street: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
)
address_zip: Mapped[str | None] = mapped_column(
String(10),
nullable=True,
)
address_city: Mapped[str | None] = mapped_column(
String(100),
nullable=True,
)
address_country: Mapped[str] = mapped_column(
String(2),
nullable=False,
default="DE",
index=True,
)
vat_id: Mapped[str | None] = mapped_column(
String(20),
nullable=True,
)
phone: Mapped[str | None] = mapped_column(
String(50),
nullable=True,
)
email: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
)
website: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
)
role: Mapped[str] = mapped_column(
String(20),
nullable=False,
index=True,
)
vat_id_status: Mapped[str] = mapped_column(
String(20),
nullable=False,
default="ungeprueft",
)
is_private: Mapped[bool] = mapped_column(
Boolean,
nullable=False,
default=False,
)
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(),
)
deleted_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
index=True,
)
contact_persons: Mapped[list["ContactPerson"]] = relationship(
back_populates="contact",
cascade="all, delete-orphan",
lazy="selectin",
)
def __repr__(self) -> str:
return f"<Contact id={self.id} company_name={self.company_name}>"
def to_dict(self) -> dict:
"""Serialize contact for API responses."""
return {
"id": str(self.id),
"company_name": self.company_name,
"legal_form": self.legal_form,
"address_street": self.address_street,
"address_zip": self.address_zip,
"address_city": self.address_city,
"address_country": self.address_country,
"vat_id": self.vat_id,
"phone": self.phone,
"email": self.email,
"website": self.website,
"role": self.role,
"vat_id_status": self.vat_id_status,
"is_private": self.is_private,
"created_at": (self.created_at.isoformat() if self.created_at else None),
"updated_at": (self.updated_at.isoformat() if self.updated_at else None),
"deleted_at": (self.deleted_at.isoformat() if self.deleted_at else None),
"contact_persons": [p.to_dict() for p in (self.contact_persons or [])],
}
class ContactPerson(Base):
"""Contact person associated with a contact (company)."""
__tablename__ = "contact_persons"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
primary_key=True,
default=uuid.uuid4,
)
contact_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("contacts.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
name: Mapped[str] = mapped_column(
String(255),
nullable=False,
)
function: Mapped[str | None] = mapped_column(
String(100),
nullable=True,
)
phone: Mapped[str | None] = mapped_column(
String(50),
nullable=True,
)
email: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
server_default=func.now(),
)
contact: Mapped["Contact"] = relationship(back_populates="contact_persons")
def __repr__(self) -> str:
return f"<ContactPerson id={self.id} name={self.name}>"
def to_dict(self) -> dict:
"""Serialize contact person for API responses."""
return {
"id": str(self.id),
"contact_id": str(self.contact_id),
"name": self.name,
"function": self.function,
"phone": self.phone,
"email": self.email,
"created_at": (self.created_at.isoformat() if self.created_at else None),
}