feat: v1.7 overhaul - identity hash, triple wallet, financial ledger, and security audit system
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/models/__init__.py
|
||||
|
||||
from app.db.base_class import Base
|
||||
|
||||
# Identitás és Jogosultság
|
||||
from .identity import User, Person, Wallet, UserRole, VerificationToken, SocialAccount
|
||||
|
||||
# Szervezeti struktúra
|
||||
from .organization import Organization, OrganizationMember
|
||||
# Szervezeti struktúra (HOZZÁADVA: OrganizationSalesAssignment)
|
||||
from .organization import Organization, OrganizationMember, OrganizationSalesAssignment
|
||||
|
||||
# Járművek és Eszközök (Digital Twin)
|
||||
from .asset import (
|
||||
@@ -13,24 +14,25 @@ from .asset import (
|
||||
AssetFinancials, AssetTelemetry, AssetReview, ExchangeRate
|
||||
)
|
||||
|
||||
# Szerviz és Szakértelem (ÚJ)
|
||||
# Szerviz és Szakértelem
|
||||
from .service import ServiceProfile, ExpertiseTag, ServiceExpertise, ServiceStaging
|
||||
|
||||
# Földrajzi adatok és Címek
|
||||
from .address import Address, GeoPostalCode, GeoStreet, GeoStreetType
|
||||
from .address import Address, GeoPostalCode, GeoStreet, GeoStreetType, Branch
|
||||
|
||||
# Gamification és Economy
|
||||
from .gamification import PointRule, LevelConfig, UserStats, Badge, UserBadge, Rating, PointsLedger
|
||||
|
||||
# Rendszerkonfiguráció és Alapok
|
||||
from .system_config import SystemParameter
|
||||
# Rendszerkonfiguráció (HASZNÁLJUK a frissített system.py-t!)
|
||||
from .system import SystemParameter
|
||||
from .document import Document
|
||||
from .translation import Translation
|
||||
|
||||
# Üzleti logika és Előfizetés
|
||||
from .core_logic import SubscriptionTier, OrganizationSubscription, CreditTransaction, ServiceSpecialty
|
||||
|
||||
# Naplózás és Biztonság
|
||||
# Naplózás és Biztonság (HOZZÁADVA: audit.py modellek)
|
||||
from .audit import SecurityAuditLog, OperationalLog, FinancialLedger # <--- KRITIKUS!
|
||||
from .history import AuditLog, VehicleOwnership
|
||||
from .security import PendingAction
|
||||
|
||||
@@ -42,16 +44,15 @@ ServiceRecord = AssetEvent
|
||||
|
||||
__all__ = [
|
||||
"Base", "User", "Person", "Wallet", "UserRole", "VerificationToken", "SocialAccount",
|
||||
"Organization", "OrganizationMember",
|
||||
"Organization", "OrganizationMember", "OrganizationSalesAssignment",
|
||||
"Asset", "AssetCatalog", "AssetCost", "AssetEvent", "AssetFinancials",
|
||||
"AssetTelemetry", "AssetReview", "ExchangeRate",
|
||||
"Address", "GeoPostalCode", "GeoStreet", "GeoStreetType",
|
||||
"PointRule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger",
|
||||
"Address", "GeoPostalCode", "GeoStreet", "GeoStreetType", "Branch",
|
||||
"Point_Rule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger",
|
||||
"SystemParameter", "Document", "Translation", "PendingAction",
|
||||
"SubscriptionTier", "OrganizationSubscription",
|
||||
"CreditTransaction", "ServiceSpecialty", "AuditLog", "VehicleOwnership",
|
||||
# --- SZERVIZ MODUL (Tisztítva) ---
|
||||
"SecurityAuditLog", "OperationalLog", "FinancialLedger", # <--- KRITIKUS!
|
||||
"ServiceProfile", "ExpertiseTag", "ServiceExpertise", "ServiceStaging",
|
||||
# --- ALIASOK ---
|
||||
"Vehicle", "UserVehicle", "VehicleCatalog", "ServiceRecord"
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,9 @@
|
||||
import uuid
|
||||
from sqlalchemy import Column, String, Integer, ForeignKey, Text, DateTime, Float
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
||||
from sqlalchemy.sql import func
|
||||
# Hozzáadva: Boolean, text, func
|
||||
from sqlalchemy import Column, String, Integer, ForeignKey, Text, DateTime, Float, Boolean, text, func
|
||||
# PostgreSQL specifikus típusok
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID, JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base_class import Base
|
||||
|
||||
class GeoPostalCode(Base):
|
||||
@@ -45,4 +47,44 @@ class Address(Base):
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
# Add to /app/models/address.py
|
||||
class Branch(Base):
|
||||
"""
|
||||
Telephely entitás. A fizikai helyszín, ahol a szolgáltatás vagy flotta-kezelés zajlik.
|
||||
Minden cégnek van legalább egy 'Main' telephelye.
|
||||
"""
|
||||
__tablename__ = "branches"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
|
||||
|
||||
name = Column(String(100), nullable=False) # pl. "Központi iroda", "Dunakeszi Szerviz"
|
||||
is_main = Column(Boolean, default=False)
|
||||
|
||||
# Részletes címadatok (Denormalizált a gyors kereséshez)
|
||||
postal_code = Column(String(10), index=True)
|
||||
city = Column(String(100), index=True)
|
||||
street_name = Column(String(150))
|
||||
street_type = Column(String(50))
|
||||
house_number = Column(String(20))
|
||||
stairwell = Column(String(20))
|
||||
floor = Column(String(20))
|
||||
door = Column(String(20))
|
||||
hrsz = Column(String(50)) # Helyrajzi szám
|
||||
|
||||
# Telephely specifikus adatok
|
||||
opening_hours = Column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
branch_rating = Column(Float, default=0.0)
|
||||
|
||||
status = Column(String(30), default="active")
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
organization = relationship("Organization", back_populates="branches")
|
||||
address = relationship("Address")
|
||||
# Kapcsolat a szerviz értékelésekkel
|
||||
reviews = relationship("Rating", primaryjoin="and_(Branch.id==foreign(Rating.target_id), Rating.target_type=='branch')")
|
||||
@@ -24,6 +24,16 @@ class AssetCatalog(Base):
|
||||
year_to = Column(Integer)
|
||||
vehicle_class = Column(String)
|
||||
fuel_type = Column(String, index=True)
|
||||
|
||||
# --- ÚJ OSZLOPOK (Ezeket add hozzá!) ---
|
||||
power_kw = Column(Integer, index=True)
|
||||
engine_capacity = Column(Integer, index=True)
|
||||
max_weight_kg = Column(Integer)
|
||||
axle_count = Column(Integer)
|
||||
euro_class = Column(String(20))
|
||||
body_type = Column(String(100))
|
||||
# ---------------------------------------
|
||||
|
||||
engine_code = Column(String)
|
||||
factory_data = Column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
|
||||
@@ -101,11 +111,17 @@ class AssetAssignment(Base):
|
||||
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
asset_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.assets.id"), nullable=False)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
|
||||
# ÚJ: Telephelyi hozzárendelés
|
||||
branch_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.branches.id"), nullable=True)
|
||||
|
||||
assigned_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
released_at = Column(DateTime(timezone=True), nullable=True)
|
||||
status = Column(String(30), default="active")
|
||||
|
||||
asset = relationship("Asset", back_populates="assignments")
|
||||
organization = relationship("Organization")
|
||||
branch = relationship("Branch") # Új kapcsolat
|
||||
|
||||
class AssetEvent(Base):
|
||||
__tablename__ = "asset_events"
|
||||
@@ -144,4 +160,27 @@ class ExchangeRate(Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
base_currency = Column(String(3), default="EUR")
|
||||
target_currency = Column(String(3), unique=True)
|
||||
rate = Column(Numeric(18, 6), nullable=False)
|
||||
rate = Column(Numeric(18, 6), nullable=False)
|
||||
|
||||
class CatalogDiscovery(Base):
|
||||
"""
|
||||
Discovery tábla: Ide gyűjtjük a piaci 'neveket' (pl. Citroen C3).
|
||||
A Robot innen indulva keresi meg az összes létező technikai variánst.
|
||||
"""
|
||||
__tablename__ = "catalog_discovery"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
make = Column(String(100), nullable=False, index=True)
|
||||
model = Column(String(100), nullable=False, index=True)
|
||||
vehicle_class = Column(String(50), index=True) # car, motorcycle, truck, stb.
|
||||
source = Column(String(50)) # 'hasznaltauto', 'mobile.de'
|
||||
status = Column(String(20), server_default=text("'pending'"), index=True)
|
||||
attempts = Column(Integer, default=0)
|
||||
last_attempt = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
# EGYESÍTETT __table_args__
|
||||
__table_args__ = (
|
||||
UniqueConstraint('make', 'model', 'vehicle_class', name='_make_model_class_uc'),
|
||||
{"schema": "data"}
|
||||
)
|
||||
@@ -1,16 +1,56 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, JSON, ForeignKey, text
|
||||
from sqlalchemy import Column, Integer, String, DateTime, JSON, ForeignKey, text, Numeric, Boolean, BigInteger
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base_class import Base
|
||||
|
||||
class AuditLog(Base):
|
||||
__tablename__ = "audit_logs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
class SecurityAuditLog(Base):
|
||||
""" Kiemelt biztonsági események és a 4-szem elv. """
|
||||
__tablename__ = "security_audit_logs"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
id = Column(Integer, primary_key=True)
|
||||
action = Column(String(50)) # 'ROLE_CHANGE', 'MANUAL_CREDIT_ADJUST', 'SUB_EXTEND'
|
||||
|
||||
actor_id = Column(Integer, ForeignKey("data.users.id")) # Aki kezdeményezte
|
||||
target_id = Column(Integer, ForeignKey("data.users.id")) # Akivel történt
|
||||
|
||||
# 4-szem elv: csak akkor válik élessé, ha ez nem NULL
|
||||
confirmed_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
is_critical = Column(Boolean, default=False) # Szuperadmin hívásoknál True
|
||||
|
||||
payload_before = Column(JSON)
|
||||
payload_after = Column(JSON)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class OperationalLog(Base):
|
||||
""" Napi üzemi események (Operational). """
|
||||
__tablename__ = "operational_logs"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True) # <--- EZ HIÁNYZOTT!
|
||||
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="SET NULL"), nullable=True)
|
||||
action = Column(String(100), nullable=False) # pl. "LOGIN", "REGISTER", "DELETE_ASSET"
|
||||
resource_type = Column(String(50)) # pl. "User", "Asset", "Organization"
|
||||
action = Column(String(100), nullable=False) # pl. "ADD_VEHICLE", "UPDATE_COST"
|
||||
resource_type = Column(String(50)) # pl. "Asset", "Expense"
|
||||
resource_id = Column(String(100))
|
||||
details = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
ip_address = Column(String(45))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class FinancialLedger(Base):
|
||||
""" Minden pénz- és kreditmozgás központi naplója. """
|
||||
__tablename__ = "financial_ledger"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"))
|
||||
person_id = Column(BigInteger, ForeignKey("data.persons.id"))
|
||||
|
||||
amount = Column(Numeric(18, 4), nullable=False)
|
||||
currency = Column(String(10)) # 'HUF', 'CREDIT', 'COIN'
|
||||
|
||||
transaction_type = Column(String(50)) # 'PURCHASE', 'HUNTING_COMMISSION', 'FARMING_COMMISSION'
|
||||
|
||||
# Üzletkötői követhetőség
|
||||
related_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
|
||||
details = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
@@ -9,29 +9,34 @@ from app.db.base_class import Base
|
||||
class UserRole(str, enum.Enum):
|
||||
superadmin = "superadmin"
|
||||
admin = "admin"
|
||||
region_admin = "region_admin"
|
||||
country_admin = "country_admin"
|
||||
moderator = "moderator"
|
||||
sales_agent = "sales_agent"
|
||||
user = "user"
|
||||
service = "service"
|
||||
service_owner = "service_owner"
|
||||
fleet_manager = "fleet_manager"
|
||||
driver = "driver"
|
||||
|
||||
class Person(Base):
|
||||
"""
|
||||
Természetes személy identitása.
|
||||
A bot által talált személyek is ide kerülnek (is_ghost=True).
|
||||
Azonosítás: Név + Anyja neve + Születési adatok alapján.
|
||||
Természetes személy identitása. A DNS szint.
|
||||
Itt tároljuk az örök adatokat, amik nem vesznek el account törléskor.
|
||||
"""
|
||||
__tablename__ = "persons"
|
||||
__table_args__ = {"schema": "data"}
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
id_uuid = Column(PG_UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
|
||||
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
|
||||
|
||||
# --- KRITIKUS: EGYEDI AZONOSÍTÓ HASH (Normalizált adatokból) ---
|
||||
identity_hash = Column(String(64), unique=True, index=True, nullable=True)
|
||||
|
||||
last_name = Column(String, nullable=False)
|
||||
first_name = Column(String, nullable=False)
|
||||
phone = Column(String, nullable=True)
|
||||
|
||||
# --- TERMÉSZETES AZONOSÍTÓK (Azonosításhoz, nem publikus) ---
|
||||
mothers_last_name = Column(String)
|
||||
mothers_first_name = Column(String)
|
||||
birth_place = Column(String)
|
||||
@@ -40,8 +45,14 @@ class Person(Base):
|
||||
identity_docs = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
ice_contact = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
is_active = Column(Boolean, default=False, nullable=False)
|
||||
is_ghost = Column(Boolean, default=True, nullable=False) # Bot találta = True, Regisztrált = False
|
||||
# --- ÖRÖK ADATOK (Person szint) ---
|
||||
lifetime_xp = Column(BigInteger, server_default=text("0"))
|
||||
penalty_points = Column(Integer, server_default=text("0")) # 0-3 szint
|
||||
social_reputation = Column(Numeric(3, 2), server_default=text("1.00")) # 1.00 = 100%
|
||||
|
||||
is_sales_agent = Column(Boolean, server_default=text("false"))
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
is_ghost = Column(Boolean, default=False, nullable=False)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
@@ -50,28 +61,39 @@ class Person(Base):
|
||||
memberships = relationship("OrganizationMember", back_populates="person")
|
||||
|
||||
class User(Base):
|
||||
"""
|
||||
Login entitás. Bármikor törölhető (GDPR), de Person-höz kötött.
|
||||
"""
|
||||
__tablename__ = "users"
|
||||
__table_args__ = {"schema": "data"}
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String, unique=True, index=True, nullable=False)
|
||||
hashed_password = Column(String, nullable=True)
|
||||
role = Column(Enum(UserRole), default=UserRole.user)
|
||||
is_active = Column(Boolean, default=False)
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
|
||||
person_id = Column(BigInteger, ForeignKey("data.persons.id"), nullable=True)
|
||||
folder_slug = Column(String(12), unique=True, index=True)
|
||||
|
||||
refresh_token_hash = Column(String(255), nullable=True)
|
||||
two_factor_secret = Column(String(100), nullable=True)
|
||||
two_factor_enabled = Column(Boolean, default=False)
|
||||
# --- ELŐFIZETÉS ÉS VIP (Időkorlátos logika) ---
|
||||
subscription_plan = Column(String(30), server_default=text("'FREE'"))
|
||||
subscription_expires_at = Column(DateTime(timezone=True), nullable=True)
|
||||
is_vip = Column(Boolean, server_default=text("false"))
|
||||
|
||||
# --- REFERRAL ÉS SALES (Üzletkötői hálózat) ---
|
||||
referral_code = Column(String(20), unique=True)
|
||||
referred_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
# Farming üzletkötő (Átruházható cégkezelő)
|
||||
current_sales_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
|
||||
is_active = Column(Boolean, default=False)
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
folder_slug = Column(String(12), unique=True, index=True)
|
||||
|
||||
preferred_language = Column(String(5), server_default="hu")
|
||||
region_code = Column(String(5), server_default="HU")
|
||||
preferred_currency = Column(String(3), server_default="HUF")
|
||||
|
||||
scope_level = Column(String(30), server_default="individual")
|
||||
scope_level = Column(String(30), server_default="individual") # global, region, country, entity, individual
|
||||
scope_id = Column(String(50))
|
||||
custom_permissions = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
@@ -79,18 +101,25 @@ class User(Base):
|
||||
|
||||
person = relationship("Person", back_populates="users")
|
||||
wallet = relationship("Wallet", back_populates="user", uselist=False)
|
||||
stats = relationship("UserStats", back_populates="user", uselist=False)
|
||||
ownership_history = relationship("VehicleOwnership", back_populates="user")
|
||||
owned_organizations = relationship("Organization", back_populates="owner")
|
||||
social_accounts = relationship("SocialAccount", back_populates="user", cascade="all, delete-orphan")
|
||||
|
||||
class Wallet(Base):
|
||||
__tablename__ = "wallets"; __table_args__ = {"schema": "data"}
|
||||
""" A 3-as felosztású pénztárca. """
|
||||
__tablename__ = "wallets"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), unique=True)
|
||||
coin_balance = Column(Numeric(18, 2), default=0.00); credit_balance = Column(Numeric(18, 2), default=0.00); currency = Column(String(3), default="HUF")
|
||||
|
||||
earned_credits = Column(Numeric(18, 4), server_default=text("0")) # Munka + Referral
|
||||
purchased_credits = Column(Numeric(18, 4), server_default=text("0")) # Vásárolt
|
||||
service_coins = Column(Numeric(18, 4), server_default=text("0")) # Csak hirdetésre!
|
||||
|
||||
currency = Column(String(3), default="HUF")
|
||||
user = relationship("User", back_populates="wallet")
|
||||
|
||||
# ... (VerificationToken és SocialAccount változatlan) ...
|
||||
|
||||
class VerificationToken(Base):
|
||||
__tablename__ = "verification_tokens"; __table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
@@ -61,6 +61,11 @@ class Organization(Base):
|
||||
status = Column(String(30), default="pending_verification")
|
||||
is_deleted = 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"))
|
||||
|
||||
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"))
|
||||
|
||||
@@ -70,6 +75,10 @@ class Organization(Base):
|
||||
|
||||
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"))
|
||||
|
||||
# Kapcsolatok
|
||||
assets = relationship("AssetAssignment", back_populates="organization", cascade="all, delete-orphan")
|
||||
@@ -77,6 +86,7 @@ class Organization(Base):
|
||||
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")
|
||||
|
||||
class OrganizationFinancials(Base):
|
||||
"""Cégek éves gazdasági adatai elemzéshez."""
|
||||
@@ -111,4 +121,15 @@ class OrganizationMember(Base):
|
||||
|
||||
organization = relationship("Organization", back_populates="members")
|
||||
user = relationship("User")
|
||||
person = relationship("Person", back_populates="memberships")
|
||||
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)
|
||||
@@ -86,12 +86,17 @@ class ServiceStaging(Base):
|
||||
name = Column(String, nullable=False, index=True)
|
||||
|
||||
# --- Strukturált cím adatok (A kérésedre bontva) ---
|
||||
postal_code = Column(String(10), nullable=True, index=True) # Irányítószám
|
||||
city = Column(String(100), nullable=True, index=True) # Település
|
||||
street = Column(String(255), nullable=True) # Utca és közterület jellege (pl. Diófa utca)
|
||||
house_number = Column(String(50), nullable=True) # Házszám, emelet, ajtó
|
||||
full_address = Column(String, nullable=True) # Az eredeti, egybefüggő cím (ha van)
|
||||
|
||||
postal_code = Column(String(10), index=True)
|
||||
city = Column(String(100), index=True)
|
||||
street_name = Column(String(150))
|
||||
street_type = Column(String(50)) # utca, út, tér...
|
||||
house_number = Column(String(20))
|
||||
stairwell = Column(String(20)) # lépcsőház
|
||||
floor = Column(String(20)) # emelet
|
||||
door = Column(String(20)) # ajtó
|
||||
hrsz = Column(String(50)) # helyrajzi szám
|
||||
|
||||
full_address = Column(String) # Eredeti string (audit célból)
|
||||
# --- Elérhetőségek ---
|
||||
contact_phone = Column(String, nullable=True)
|
||||
email = Column(String, nullable=True)
|
||||
@@ -111,4 +116,14 @@ class ServiceStaging(Base):
|
||||
status = Column(String(20), server_default=text("'pending'"), index=True)
|
||||
trust_score = Column(Integer, default=0)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class DiscoveryParameter(Base):
|
||||
__tablename__ = "discovery_parameters"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
city = Column(String(100), nullable=False)
|
||||
keyword = Column(String(100), nullable=False) # pl. "autóvillamosság"
|
||||
country_code = Column(String(2), default="HU")
|
||||
is_active = Column(Boolean, default=True)
|
||||
last_run_at = Column(DateTime(timezone=True))
|
||||
@@ -7,7 +7,11 @@ class SystemParameter(Base):
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
key = Column(String, primary_key=True, index=True, nullable=False)
|
||||
# Csoportosítás az Admin felületnek (pl. 'xp', 'scout', 'routing')
|
||||
category = Column(String, index=True, server_default="general")
|
||||
value = Column(JSON, nullable=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
description = Column(String)
|
||||
# Kötelező audit mező: ki módosította utoljára?
|
||||
last_modified_by = Column(String, nullable=True)
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now(), server_default=func.now())
|
||||
Reference in New Issue
Block a user