STABLE: Final schema sync, optimized gitignore
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import enum
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any, List, Optional
|
||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, JSON, text, Numeric, BigInteger
|
||||
from sqlalchemy.dialects.postgresql import ENUM as PG_ENUM
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import ENUM as PG_ENUM, UUID as PG_UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base_class import Base
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
||||
|
||||
# MB 2.0: A központi aszinkron adatbázis motorból húzzuk be a Base-t
|
||||
from app.database import Base
|
||||
|
||||
class OrgType(str, enum.Enum):
|
||||
individual = "individual"
|
||||
@@ -25,114 +29,118 @@ class OrgUserRole(str, enum.Enum):
|
||||
class Organization(Base):
|
||||
"""
|
||||
Szervezet entitás. Lehet flotta (user) és szolgáltató (service) egyszerre.
|
||||
A képességeket a kapcsolódó profilok (pl. ServiceProfile) határozzák meg.
|
||||
Minden üzleti adat a 'data' sémába kerül.
|
||||
"""
|
||||
__tablename__ = "organizations"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
|
||||
# Kapcsolat a címekkel (szintén a data sémában)
|
||||
address_id: Mapped[Optional[uuid.UUID]] = mapped_column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"))
|
||||
|
||||
is_anonymized = Column(Boolean, default=False, server_default=text("false"))
|
||||
anonymized_at = Column(DateTime(timezone=True), nullable=True)
|
||||
is_anonymized: Mapped[bool] = mapped_column(Boolean, default=False, server_default=text("false"))
|
||||
anonymized_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
full_name = Column(String, nullable=False) # Hivatalos név
|
||||
name = Column(String, nullable=False) # Rövid név
|
||||
display_name = Column(String(50))
|
||||
folder_slug = Column(String(12), unique=True, index=True)
|
||||
full_name: Mapped[str] = mapped_column(String, nullable=False)
|
||||
name: Mapped[str] = mapped_column(String, nullable=False)
|
||||
display_name: Mapped[Optional[str]] = mapped_column(String(50))
|
||||
folder_slug: Mapped[str] = mapped_column(String(12), unique=True, index=True)
|
||||
|
||||
default_currency = Column(String(3), default="HUF")
|
||||
country_code = Column(String(2), default="HU")
|
||||
language = Column(String(5), default="hu")
|
||||
default_currency: Mapped[str] = mapped_column(String(3), default="HUF")
|
||||
country_code: Mapped[str] = mapped_column(String(2), default="HU")
|
||||
language: Mapped[str] = mapped_column(String(5), default="hu")
|
||||
|
||||
# Cím adatok (redundáns a gyors kereséshez, de address_id a SSoT)
|
||||
address_zip = Column(String(10))
|
||||
address_city = Column(String(100))
|
||||
address_street_name = Column(String(150))
|
||||
address_street_type = Column(String(50))
|
||||
address_house_number = Column(String(20))
|
||||
address_hrsz = Column(String(50))
|
||||
address_zip: Mapped[Optional[str]] = mapped_column(String(10))
|
||||
address_city: Mapped[Optional[str]] = mapped_column(String(100))
|
||||
address_street_name: Mapped[Optional[str]] = mapped_column(String(150))
|
||||
address_street_type: Mapped[Optional[str]] = mapped_column(String(50))
|
||||
address_house_number: Mapped[Optional[str]] = mapped_column(String(20))
|
||||
address_hrsz: Mapped[Optional[str]] = mapped_column(String(50))
|
||||
|
||||
tax_number = Column(String(20), unique=True, index=True) # Robot horgony
|
||||
reg_number = Column(String(50))
|
||||
tax_number: Mapped[Optional[str]] = mapped_column(String(20), unique=True, index=True)
|
||||
reg_number: Mapped[Optional[str]] = mapped_column(String(50))
|
||||
|
||||
org_type = Column(
|
||||
PG_ENUM(OrgType, name="orgtype", inherit_schema=True),
|
||||
org_type: Mapped[OrgType] = mapped_column(
|
||||
PG_ENUM(OrgType, name="orgtype", schema="data"),
|
||||
default=OrgType.individual
|
||||
)
|
||||
|
||||
status = Column(String(30), default="pending_verification")
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
status: Mapped[str] = mapped_column(String(30), default="pending_verification")
|
||||
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
|
||||
# --- ÚJ: Előfizetés és Méret korlátok ---
|
||||
subscription_plan = Column(String(30), server_default=text("'FREE'"), index=True)
|
||||
base_asset_limit = Column(Integer, server_default=text("1"))
|
||||
purchased_extra_slots = Column(Integer, server_default=text("0"))
|
||||
subscription_plan: Mapped[str] = mapped_column(String(30), server_default=text("'FREE'"), index=True)
|
||||
base_asset_limit: Mapped[int] = mapped_column(Integer, server_default=text("1"))
|
||||
purchased_extra_slots: Mapped[int] = mapped_column(Integer, server_default=text("0"))
|
||||
|
||||
notification_settings = Column(JSON, server_default=text("'{\"notify_owner\": true, \"alert_days_before\": [30, 15, 7, 1]}'::jsonb"))
|
||||
external_integration_config = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
notification_settings: Mapped[Any] = mapped_column(JSON, server_default=text("'{\"notify_owner\": true, \"alert_days_before\": [30, 15, 7, 1]}'::jsonb"))
|
||||
external_integration_config: Mapped[Any] = mapped_column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
owner_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_verified = Column(Boolean, default=False)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# --- ÚJ: Dual Twin Tulajdonjog logika ---
|
||||
# Individual esetén False, Business esetén True
|
||||
is_ownership_transferable = Column(Boolean, server_default=text("true"))
|
||||
# KRITIKUS: A júzer az 'identity' sémában van!
|
||||
owner_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("identity.users.id"))
|
||||
|
||||
# Kapcsolatok
|
||||
assets = relationship("AssetAssignment", back_populates="organization", cascade="all, delete-orphan")
|
||||
members = relationship("OrganizationMember", back_populates="organization", cascade="all, delete-orphan")
|
||||
owner = relationship("User", back_populates="owned_organizations")
|
||||
financials = relationship("OrganizationFinancials", back_populates="organization", cascade="all, delete-orphan")
|
||||
service_profile = relationship("ServiceProfile", back_populates="organization", uselist=False)
|
||||
branches = relationship("Branch", back_populates="organization", cascade="all, delete-orphan")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
is_verified: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), onupdate=func.now())
|
||||
is_ownership_transferable: Mapped[bool] = mapped_column(Boolean, server_default=text("true"))
|
||||
|
||||
# Kapcsolatok (Relationships)
|
||||
assets: Mapped[List["AssetAssignment"]] = relationship("AssetAssignment", back_populates="organization", cascade="all, delete-orphan")
|
||||
members: Mapped[List["OrganizationMember"]] = relationship("OrganizationMember", back_populates="organization", cascade="all, delete-orphan")
|
||||
owner: Mapped[Optional["User"]] = relationship("User", back_populates="owned_organizations")
|
||||
financials: Mapped[List["OrganizationFinancials"]] = relationship("OrganizationFinancials", back_populates="organization", cascade="all, delete-orphan")
|
||||
service_profile: Mapped[Optional["ServiceProfile"]] = relationship("ServiceProfile", back_populates="organization", uselist=False)
|
||||
branches: Mapped[List["Branch"]] = relationship("Branch", back_populates="organization", cascade="all, delete-orphan")
|
||||
|
||||
class OrganizationFinancials(Base):
|
||||
"""Cégek éves gazdasági adatai elemzéshez."""
|
||||
__tablename__ = "organization_financials"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
year = Column(Integer, nullable=False)
|
||||
turnover = Column(Numeric(18, 2))
|
||||
profit = Column(Numeric(18, 2))
|
||||
employee_count = Column(Integer)
|
||||
source = Column(String(50)) # pl. 'manual', 'crawler', 'api'
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
organization = relationship("Organization", back_populates="financials")
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
year: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
turnover: Mapped[Optional[float]] = mapped_column(Numeric(18, 2))
|
||||
profit: Mapped[Optional[float]] = mapped_column(Numeric(18, 2))
|
||||
employee_count: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
source: Mapped[Optional[str]] = mapped_column(String(50))
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
organization: Mapped["Organization"] = relationship("Organization", back_populates="financials")
|
||||
|
||||
class OrganizationMember(Base):
|
||||
"""Kapcsolótábla a személyek és szervezetek között."""
|
||||
__tablename__ = "organization_members"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
person_id = Column(BigInteger, ForeignKey("data.persons.id"), nullable=True) # Ghost támogatás
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
|
||||
role = Column(PG_ENUM(OrgUserRole, name="orguserrole", inherit_schema=True), default=OrgUserRole.DRIVER)
|
||||
permissions = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
is_permanent = Column(Boolean, default=False)
|
||||
is_verified = Column(Boolean, default=False) # <--- JAVÍTÁS: Ez az oszlop hiányzott!
|
||||
# KRITIKUS: User és Person az identity sémában lakik!
|
||||
user_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("identity.users.id"))
|
||||
person_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("identity.persons.id"))
|
||||
|
||||
role: Mapped[OrgUserRole] = mapped_column(
|
||||
PG_ENUM(OrgUserRole, name="orguserrole", schema="data"),
|
||||
default=OrgUserRole.DRIVER
|
||||
)
|
||||
permissions: Mapped[Any] = mapped_column(JSON, server_default=text("'{}'::jsonb"))
|
||||
is_permanent: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
is_verified: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
|
||||
organization = relationship("Organization", back_populates="members")
|
||||
user = relationship("User")
|
||||
person = relationship("Person", back_populates="memberships")
|
||||
organization: Mapped["Organization"] = relationship("Organization", back_populates="members")
|
||||
user: Mapped[Optional["User"]] = relationship("User")
|
||||
person: Mapped[Optional["Person"]] = relationship("Person", back_populates="memberships")
|
||||
|
||||
class OrganizationSalesAssignment(Base):
|
||||
"""Összeköti a céget az aktuális üzletkötővel a jutalék miatt."""
|
||||
__tablename__ = "org_sales_assignments"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"))
|
||||
agent_user_id = Column(Integer, ForeignKey("data.users.id")) # Ő kapja a Farming díjat
|
||||
assigned_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
is_active = Column(Boolean, default=True)
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
organization_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("data.organizations.id"))
|
||||
|
||||
# KRITIKUS: Az ügynök (agent) júzer az identity sémában van
|
||||
agent_user_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("identity.users.id"))
|
||||
|
||||
assigned_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
Reference in New Issue
Block a user