Unified contacts model: Rentman-style type field (company/person), inline addresses, ContactPerson 1:N, all Rentman fields except rental-specific

This commit is contained in:
Agent Zero
2026-07-19 21:12:49 +02:00
parent d80feb2a3a
commit cf75680583
14 changed files with 1411 additions and 869 deletions
+9 -47
View File
@@ -1,51 +1,13 @@
"""Company model — with soft-delete, FTS tsvector, and tenant scoping."""
"""Backward-compat shim — Company is now Contact with type='company'.
from __future__ import annotations
This module re-exports Contact as Company for code that still imports
from app.models.company. The old companies table no longer exists;
all company data lives in the contacts table with type='company'.
"""
import uuid
from typing import Any
from app.models.contact import Contact, ContactPerson
from sqlalchemy import Computed, DateTime, ForeignKey, Index, String, Text
from sqlalchemy.dialects.postgresql import TSVECTOR
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column
# Backward-compat: Company is now just a Contact with type='company'
Company = Contact
from app.core.db import Base, TenantMixin
class Company(Base, TenantMixin):
"""Company entity with full-text search support."""
__tablename__ = "companies"
__table_args__ = (
Index("ix_companies_tenant_deleted", "tenant_id", "deleted_at"),
Index("ix_companies_tenant_name", "tenant_id", "name"),
Index("ix_companies_industry", "tenant_id", "industry"),
Index("ix_companies_search_vec", "search_tsv", postgresql_using="gin"),
)
id: Mapped[uuid.UUID] = mapped_column(
PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
name: Mapped[str] = mapped_column(String(100), nullable=False)
account_number: Mapped[str | None] = mapped_column(String(40), nullable=True)
industry: Mapped[str | None] = mapped_column(String(50), nullable=True)
phone: Mapped[str | None] = mapped_column(String(30), nullable=True)
email: Mapped[str | None] = mapped_column(String(255), nullable=True)
website: Mapped[str | None] = mapped_column(String(500), nullable=True)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
# FTS vector
search_tsv: Mapped[Any] = mapped_column(
TSVECTOR,
Computed(
"to_tsvector('english', coalesce(name, '') || ' ' || coalesce(description, '') || ' ' || coalesce(industry, ''))",
persisted=True,
),
nullable=True,
)
created_by: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
updated_by: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
__all__ = ["Company", "ContactPerson"]