Initial commit - Migrated to Dev environment
This commit is contained in:
24
backend/app/models/__init__.py
Executable file
24
backend/app/models/__init__.py
Executable file
@@ -0,0 +1,24 @@
|
||||
from app.db.base import Base
|
||||
from .user import User, UserRole
|
||||
from .company import Company, CompanyMember, VehicleAssignment
|
||||
from .vehicle import (
|
||||
Vehicle,
|
||||
VehicleOwnership,
|
||||
VehicleBrand,
|
||||
EngineSpec,
|
||||
ServiceProvider,
|
||||
ServiceRecord,
|
||||
VehicleCategory,
|
||||
VehicleModel,
|
||||
VehicleVariant
|
||||
)
|
||||
|
||||
# Alias a kompatibilitás kedvéért
|
||||
UserVehicle = Vehicle
|
||||
|
||||
__all__ = [
|
||||
"Base", "User", "UserRole", "Vehicle", "VehicleOwnership", "VehicleBrand",
|
||||
"EngineSpec", "ServiceProvider", "ServiceRecord", "Company",
|
||||
"CompanyMember", "VehicleAssignment", "UserVehicle", "VehicleCategory",
|
||||
"VehicleModel", "VehicleVariant"
|
||||
]
|
||||
BIN
backend/app/models/__pycache__/__init__.cpython-312.pyc
Executable file
BIN
backend/app/models/__pycache__/__init__.cpython-312.pyc
Executable file
Binary file not shown.
BIN
backend/app/models/__pycache__/company.cpython-312.pyc
Executable file
BIN
backend/app/models/__pycache__/company.cpython-312.pyc
Executable file
Binary file not shown.
BIN
backend/app/models/__pycache__/user.cpython-312.pyc
Executable file
BIN
backend/app/models/__pycache__/user.cpython-312.pyc
Executable file
Binary file not shown.
BIN
backend/app/models/__pycache__/vehicle.cpython-312.pyc
Executable file
BIN
backend/app/models/__pycache__/vehicle.cpython-312.pyc
Executable file
Binary file not shown.
63
backend/app/models/company.py
Executable file
63
backend/app/models/company.py
Executable file
@@ -0,0 +1,63 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.dialects.postgresql import ENUM as PG_ENUM, UUID
|
||||
from app.db.base import Base
|
||||
import enum
|
||||
|
||||
# A Python enum marad, de a Column definíciónál pontosítunk
|
||||
class CompanyRole(str, enum.Enum):
|
||||
OWNER = "owner"
|
||||
MANAGER = "manager"
|
||||
DRIVER = "driver"
|
||||
|
||||
class Company(Base):
|
||||
__tablename__ = "companies"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
tax_number = Column(String, nullable=True)
|
||||
subscription_tier = Column(String, default="free")
|
||||
owner_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
|
||||
|
||||
members = relationship("CompanyMember", back_populates="company", cascade="all, delete-orphan")
|
||||
assignments = relationship("VehicleAssignment", back_populates="company")
|
||||
|
||||
class CompanyMember(Base):
|
||||
__tablename__ = "company_members"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
company_id = Column(Integer, ForeignKey("data.companies.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
|
||||
|
||||
# JAVÍTÁS: Kifejezetten megadjuk a natív Postgres típust
|
||||
role = Column(
|
||||
PG_ENUM('owner', 'manager', 'driver', name='companyrole', schema='data', create_type=False),
|
||||
nullable=False
|
||||
)
|
||||
|
||||
can_edit_service = Column(Boolean, default=False)
|
||||
can_see_costs = Column(Boolean, default=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
company = relationship("Company", back_populates="members")
|
||||
user = relationship("User")
|
||||
|
||||
class VehicleAssignment(Base):
|
||||
__tablename__ = "vehicle_assignments"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
company_id = Column(Integer, ForeignKey("data.companies.id"), nullable=False)
|
||||
vehicle_id = Column(UUID(as_uuid=True), ForeignKey("data.vehicles.id"), nullable=False)
|
||||
driver_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
|
||||
|
||||
start_date = Column(DateTime(timezone=True), server_default=func.now())
|
||||
end_date = Column(DateTime(timezone=True), nullable=True)
|
||||
notes = Column(String, nullable=True)
|
||||
|
||||
company = relationship("Company", back_populates="assignments")
|
||||
vehicle = relationship("Vehicle") # Itt már a Vehicle-re hivatkozunk
|
||||
driver = relationship("User", foreign_keys=[driver_id])
|
||||
42
backend/app/models/core_logic.py
Executable file
42
backend/app/models/core_logic.py
Executable file
@@ -0,0 +1,42 @@
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, DateTime, JSON, Numeric
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class SubscriptionTier(Base):
|
||||
__tablename__ = "subscription_tiers"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String, unique=True) # Free, Premium, VIP, Custom
|
||||
rules = Column(JSON) # {"max_vehicles": 5, "allow_api": true}
|
||||
is_custom = Column(Boolean, default=False)
|
||||
|
||||
class OrganizationSubscription(Base):
|
||||
__tablename__ = "org_subscriptions"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
org_id = Column(Integer, ForeignKey("data.organizations.id"))
|
||||
tier_id = Column(Integer, ForeignKey("data.subscription_tiers.id"))
|
||||
valid_from = Column(DateTime, server_default=func.now())
|
||||
valid_until = Column(DateTime)
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
class CreditTransaction(Base):
|
||||
__tablename__ = "credit_logs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
org_id = Column(Integer, ForeignKey("data.organizations.id"))
|
||||
amount = Column(Numeric(10, 2))
|
||||
description = Column(String)
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
|
||||
class ServiceSpecialty(Base):
|
||||
"""Fa struktúra a szerviz szolgáltatásokhoz"""
|
||||
__tablename__ = "service_specialties"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent_id = Column(Integer, ForeignKey("data.service_specialties.id"), nullable=True)
|
||||
name = Column(String, nullable=False)
|
||||
slug = Column(String, unique=True)
|
||||
|
||||
parent = relationship("ServiceSpecialty", remote_side=[id], backref="children")
|
||||
17
backend/app/models/email_log.py
Executable file
17
backend/app/models/email_log.py
Executable file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class EmailLog(Base):
|
||||
__tablename__ = "email_logs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, nullable=True) # Hozzáadva
|
||||
recipient = Column(String, index=True) # Hozzáadva
|
||||
email = Column(String, index=True)
|
||||
email_type = Column(String) # Frissítve a kódhoz
|
||||
type = Column(String) # Megtartva a kompatibilitás miatt
|
||||
provider_id = Column(Integer) # Hozzáadva
|
||||
status = Column(String) # Hozzáadva
|
||||
sent_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
21
backend/app/models/email_provider.py
Executable file
21
backend/app/models/email_provider.py
Executable file
@@ -0,0 +1,21 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, JSON, Float
|
||||
from app.db.base import Base
|
||||
|
||||
class EmailProviderConfig(Base):
|
||||
__tablename__ = "email_provider_configs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(50), unique=True) # Pl: SendGrid_Main, Office365_Backup
|
||||
provider_type = Column(String(20)) # SENDGRID, SMTP, MAILGUN
|
||||
priority = Column(Integer, default=1) # 1 = legfontosabb
|
||||
|
||||
# JSON-ban tároljuk a paramétereket (host, port, api_key, user, stb.)
|
||||
settings = Column(JSON, nullable=False)
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
# Failover figyelés
|
||||
fail_count = Column(Integer, default=0)
|
||||
max_fail_threshold = Column(Integer, default=3) # Hány hiba után kapcsoljon le?
|
||||
success_rate = Column(Float, default=100.0) # Statisztika az adminnak
|
||||
30
backend/app/models/email_system.py
Executable file
30
backend/app/models/email_system.py
Executable file
@@ -0,0 +1,30 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Text, Numeric
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class EmailProvider(Base):
|
||||
__tablename__ = 'email_providers'
|
||||
__table_args__ = {'schema': 'data'}
|
||||
id = Column(Integer, PRIMARY KEY=True)
|
||||
name = Column(String(50), nullable=False)
|
||||
priority = Column(Integer, default=1)
|
||||
provider_type = Column(String(10), default='SMTP')
|
||||
host = Column(String(255))
|
||||
port = Column(Integer)
|
||||
username = Column(String(255))
|
||||
password_hash = Column(String(255))
|
||||
is_active = Column(Boolean, default=True)
|
||||
daily_limit = Column(Integer, default=300)
|
||||
current_daily_usage = Column(Integer, default=0)
|
||||
|
||||
class EmailLog(Base):
|
||||
__tablename__ = 'email_logs'
|
||||
__table_args__ = {'schema': 'data'}
|
||||
id = Column(Integer, PRIMARY KEY=True)
|
||||
user_id = Column(Integer, ForeignKey('data.users.id'), nullable=True)
|
||||
email_type = Column(String(50))
|
||||
recipient = Column(String(255))
|
||||
provider_id = Column(Integer, ForeignKey('data.email_providers.id'))
|
||||
status = Column(String(20))
|
||||
sent_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
error_message = Column(Text)
|
||||
17
backend/app/models/email_template.py
Executable file
17
backend/app/models/email_template.py
Executable file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import Column, Integer, String, Text, Enum
|
||||
import enum
|
||||
from app.db.base import Base
|
||||
|
||||
class EmailType(str, enum.Enum):
|
||||
REGISTRATION = "REGISTRATION"
|
||||
PASSWORD_RESET = "PASSWORD_RESET"
|
||||
GDPR_NOTICE = "GDPR_NOTICE"
|
||||
|
||||
class EmailTemplate(Base):
|
||||
__tablename__ = "email_templates"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
type = Column(Enum(EmailType), unique=True, index=True)
|
||||
subject = Column(String(255), nullable=False)
|
||||
body_html = Column(Text, nullable=False) # Adminról szerkeszthető HTML tartalom
|
||||
50
backend/app/models/expense.py
Executable file
50
backend/app/models/expense.py
Executable file
@@ -0,0 +1,50 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, DateTime, Boolean, Date, JSON
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
# Költség Kategóriák
|
||||
class ExpenseCategory(str, enum.Enum):
|
||||
PURCHASE_PRICE = "PURCHASE_PRICE" # Vételár
|
||||
TRANSFER_TAX = "TRANSFER_TAX" # Vagyonszerzési illeték
|
||||
ADMIN_FEE = "ADMIN_FEE" # Eredetiség, forgalmi, törzskönyv
|
||||
VEHICLE_TAX = "VEHICLE_TAX" # Gépjárműadó
|
||||
INSURANCE = "INSURANCE" # Biztosítás
|
||||
REFUELING = "REFUELING" # Tankolás
|
||||
SERVICE = "SERVICE" # Szerviz / Javítás
|
||||
PARKING = "PARKING" # Parkolás
|
||||
TOLL = "TOLL" # Autópálya matrica
|
||||
FINE = "FINE" # Bírság
|
||||
TUNING_ACCESSORIES = "TUNING_ACCESSORIES" # Extrák
|
||||
OTHER = "OTHER" # Egyéb
|
||||
|
||||
class VehicleEvent(Base):
|
||||
__tablename__ = "vehicle_events"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
vehicle_id = Column(Integer, ForeignKey("data.user_vehicles.id"), nullable=False)
|
||||
|
||||
# Esemény típusa
|
||||
event_type = Column(Enum(ExpenseCategory, schema="data", name="expense_category_enum"), nullable=False)
|
||||
|
||||
date = Column(Date, nullable=False)
|
||||
|
||||
# Kilométeróra (KÖTELEZŐ!)
|
||||
odometer_value = Column(Integer, nullable=False)
|
||||
odometer_anomaly = Column(Boolean, default=False) # Ha csökkenést észlelünk, True lesz
|
||||
|
||||
# Pénzügyek
|
||||
cost_amount = Column(Integer, nullable=False, default=0) # HUF
|
||||
|
||||
# Leírás és Képek
|
||||
description = Column(String, nullable=True)
|
||||
image_paths = Column(JSON, nullable=True) # Lista a feltöltött képek (számla, fotó) útvonalairól
|
||||
|
||||
# Kapcsolat a szolgáltatóval
|
||||
# Ha is_diy=True, akkor a user maga csinálta.
|
||||
# Ha is_diy=False és service_provider_id=None, akkor ismeretlen helyen készült.
|
||||
is_diy = Column(Boolean, default=False)
|
||||
service_provider_id = Column(Integer, ForeignKey("data.service_providers.id"), nullable=True)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
70
backend/app/models/gamification.py
Executable file
70
backend/app/models/gamification.py
Executable file
@@ -0,0 +1,70 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from sqlalchemy import ForeignKey, String, Integer, DateTime, func, Boolean
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from app.db.base import Base
|
||||
|
||||
# Közös beállítás az összes táblához ebben a fájlban
|
||||
SCHEMA_ARGS = {"schema": "data"}
|
||||
|
||||
class PointRule(Base):
|
||||
__tablename__ = "point_rules"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
action_key: Mapped[str] = mapped_column(String, unique=True, index=True)
|
||||
points: Mapped[int] = mapped_column(Integer, default=0)
|
||||
description: Mapped[Optional[str]] = mapped_column(String)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
|
||||
class LevelConfig(Base):
|
||||
__tablename__ = "level_configs"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
level_number: Mapped[int] = mapped_column(Integer, unique=True)
|
||||
min_points: Mapped[int] = mapped_column(Integer)
|
||||
rank_name: Mapped[str] = mapped_column(String)
|
||||
|
||||
class RegionalSetting(Base):
|
||||
__tablename__ = "regional_settings"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
country_code: Mapped[str] = mapped_column(String, unique=True)
|
||||
currency: Mapped[str] = mapped_column(String, default="HUF")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
|
||||
class PointsLedger(Base):
|
||||
__tablename__ = "points_ledger"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
# JAVÍTVA: data.users.id hivatkozás
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"))
|
||||
points: Mapped[int] = mapped_column(Integer)
|
||||
reason: Mapped[str] = mapped_column(String)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())
|
||||
|
||||
class UserStats(Base):
|
||||
__tablename__ = "user_stats"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
# JAVÍTVA: data.users.id hivatkozás
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"), unique=True)
|
||||
total_points: Mapped[int] = mapped_column(Integer, default=0)
|
||||
current_level: Mapped[int] = mapped_column(Integer, default=1)
|
||||
last_activity: Mapped[datetime] = mapped_column(DateTime, default=func.now())
|
||||
|
||||
class Badge(Base):
|
||||
__tablename__ = "badges"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String, unique=True)
|
||||
description: Mapped[str] = mapped_column(String)
|
||||
icon_url: Mapped[Optional[str]] = mapped_column(String)
|
||||
|
||||
class UserBadge(Base):
|
||||
__tablename__ = "user_badges"
|
||||
__table_args__ = SCHEMA_ARGS
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
# JAVÍTVA: data.users.id hivatkozás
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.users.id"))
|
||||
badge_id: Mapped[int] = mapped_column(Integer, ForeignKey("data.badges.id"))
|
||||
earned_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())
|
||||
63
backend/app/models/history.py
Executable file
63
backend/app/models/history.py
Executable file
@@ -0,0 +1,63 @@
|
||||
# /opt/service_finder/backend/app/models/history.py
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, JSON, Date, Text
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
# --- 1. Jármű Birtoklási Előzmények (Ownership History) ---
|
||||
# Ez a tábla mondja meg, kié volt az autó egy adott időpillanatban.
|
||||
# Így biztosítjuk, hogy a régi tulajdonos adatai védve legyenek az újtól.
|
||||
class VehicleOwnership(Base):
|
||||
__tablename__ = "vehicle_ownerships"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
# Kapcsolatok
|
||||
vehicle_id = Column(Integer, ForeignKey("data.user_vehicles.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
|
||||
|
||||
# Időszak
|
||||
start_date = Column(Date, nullable=False, default=func.current_date()) # Mikor került hozzá
|
||||
end_date = Column(Date, nullable=True) # Ha NULL, akkor ő a jelenlegi tulajdonos!
|
||||
|
||||
# Jegyzet (pl. adásvételi szerződés száma)
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
# SQLAlchemy kapcsolatok (visszahivatkozások a fő modellekben kellenek majd)
|
||||
vehicle = relationship("UserVehicle", back_populates="ownership_history")
|
||||
user = relationship("User", back_populates="owned_vehicles")
|
||||
|
||||
|
||||
# --- 2. Audit Log (A "Fekete Doboz") ---
|
||||
# Minden kritikus módosítást itt tárolunk. Ez a rendszer "igazságügyi naplója".
|
||||
class AuditLog(Base):
|
||||
__tablename__ = "audit_logs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
# KI? (A felhasználó, aki a műveletet végezte)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
|
||||
# MIT? (Milyen objektumot érintett?)
|
||||
target_type = Column(String, index=True) # pl. "vehicle", "cost", "user_profile"
|
||||
target_id = Column(Integer, index=True) # pl. az autó ID-ja
|
||||
|
||||
# HOGYAN?
|
||||
action = Column(String, nullable=False) # CREATE, UPDATE, DELETE, LOGIN_FAILED, EXPORT_DATA
|
||||
|
||||
# RÉSZLETEK (Mi változott?)
|
||||
# Pl: {"field": "odometer", "old_value": 150000, "new_value": 120000} <- Visszatekerés gyanú!
|
||||
changes = Column(JSON, nullable=True)
|
||||
|
||||
# BIZTONSÁG
|
||||
ip_address = Column(String, nullable=True) # Honnan jött a kérés?
|
||||
user_agent = Column(String, nullable=True) # Milyen böngészőből?
|
||||
|
||||
# MIKOR?
|
||||
timestamp = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
# Kapcsolat (Opcionális, csak ha le akarjuk kérdezni a user adatait a logból)
|
||||
user = relationship("User")
|
||||
29
backend/app/models/legal.py
Executable file
29
backend/app/models/legal.py
Executable file
@@ -0,0 +1,29 @@
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Boolean
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class LegalDocument(Base):
|
||||
__tablename__ = "legal_documents"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(255))
|
||||
content = Column(Text, nullable=False)
|
||||
version = Column(String(20), nullable=False)
|
||||
|
||||
region_code = Column(String(5), default="HU")
|
||||
language = Column(String(5), default="hu")
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class LegalAcceptance(Base):
|
||||
__tablename__ = "legal_acceptances"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"))
|
||||
document_id = Column(Integer, ForeignKey("data.legal_documents.id"))
|
||||
accepted_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
ip_address = Column(String(45))
|
||||
user_agent = Column(Text)
|
||||
25
backend/app/models/logistics.py
Executable file
25
backend/app/models/logistics.py
Executable file
@@ -0,0 +1,25 @@
|
||||
from sqlalchemy import Column, Integer, String, Enum
|
||||
from app.db.base import Base
|
||||
import enum
|
||||
|
||||
# Enum definiálása
|
||||
class LocationType(str, enum.Enum):
|
||||
stop = "stop" # Megálló / Parkoló
|
||||
warehouse = "warehouse" # Raktár
|
||||
client = "client" # Ügyfél címe
|
||||
|
||||
class Location(Base):
|
||||
__tablename__ = "locations"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
|
||||
# FONTOS: Itt is megadjuk a schema="data"-t, hogy ne a public sémába akarja írni!
|
||||
type = Column(Enum(LocationType, schema="data", name="location_type_enum"), nullable=False)
|
||||
|
||||
# Koordináták (egyelőre String, később PostGIS)
|
||||
coordinates = Column(String, nullable=True)
|
||||
address_full = Column(String, nullable=True)
|
||||
|
||||
capacity = Column(Integer, nullable=True)
|
||||
36
backend/app/models/organization.py
Executable file
36
backend/app/models/organization.py
Executable file
@@ -0,0 +1,36 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, Boolean, Enum, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class OrgType(str, enum.Enum):
|
||||
INDIVIDUAL = "individual"
|
||||
SERVICE = "service"
|
||||
FLEET_OWNER = "fleet_owner"
|
||||
CLUB = "club"
|
||||
|
||||
class UITheme(str, enum.Enum):
|
||||
LIGHT = "light"
|
||||
DARK = "dark"
|
||||
SYSTEM = "system"
|
||||
|
||||
class Organization(Base):
|
||||
__tablename__ = "organizations"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
org_type = Column(Enum(OrgType), default=OrgType.INDIVIDUAL)
|
||||
|
||||
# Új UI beállítások a V2-höz
|
||||
theme = Column(Enum(UITheme), default=UITheme.SYSTEM)
|
||||
logo_url = Column(String, nullable=True)
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# Kapcsolatok
|
||||
# members = relationship("OrganizationMember", back_populates="organization")
|
||||
vehicles = relationship("UserVehicle", back_populates="current_org")
|
||||
26
backend/app/models/organization_member.py
Executable file
26
backend/app/models/organization_member.py
Executable file
@@ -0,0 +1,26 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, Boolean, Enum, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
# Átnevezve OrgUserRole-ra, hogy ne ütközzön a globális UserRole-al
|
||||
class OrgUserRole(str, enum.Enum):
|
||||
OWNER = "OWNER"
|
||||
ADMIN = "ADMIN"
|
||||
FLEET_MANAGER = "FLEET_MANAGER"
|
||||
DRIVER = "DRIVER"
|
||||
|
||||
class OrganizationMember(Base):
|
||||
__tablename__ = "organization_members"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
org_id = Column(Integer, ForeignKey("data.organizations.id", ondelete="CASCADE"))
|
||||
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"))
|
||||
# Itt is frissítjük a hivatkozást
|
||||
role = Column(Enum(OrgUserRole), default=OrgUserRole.DRIVER)
|
||||
|
||||
is_permanent = Column(Boolean, default=False)
|
||||
|
||||
organization = relationship("Organization", back_populates="members")
|
||||
# # # user = relationship("User", back_populates="memberships")
|
||||
71
backend/app/models/social.py
Executable file
71
backend/app/models/social.py
Executable file
@@ -0,0 +1,71 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, DateTime, Boolean, Text, UniqueConstraint
|
||||
from app.db.base import Base
|
||||
from datetime import datetime
|
||||
|
||||
# Enums (már schema="data" beállítással a biztonságért)
|
||||
class ModerationStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
approved = "approved"
|
||||
rejected = "rejected"
|
||||
|
||||
class SourceType(str, enum.Enum):
|
||||
manual = "manual"
|
||||
ocr = "ocr"
|
||||
api_import = "import"
|
||||
|
||||
class ServiceProvider(Base):
|
||||
__tablename__ = "service_providers"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
address = Column(String, nullable=False)
|
||||
category = Column(String)
|
||||
|
||||
status = Column(Enum(ModerationStatus, schema="data", name="moderation_status_enum"), default=ModerationStatus.pending, nullable=False)
|
||||
source = Column(Enum(SourceType, schema="data", name="source_type_enum"), default=SourceType.manual, nullable=False)
|
||||
|
||||
# --- ÚJ MEZŐ ---
|
||||
validation_score = Column(Integer, default=0) # A közösségi szavazatok összege
|
||||
# ---------------
|
||||
|
||||
evidence_image_path = Column(String, nullable=True)
|
||||
added_by_user_id = Column(Integer, ForeignKey("data.users.id"))
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
class Vote(Base):
|
||||
__tablename__ = "votes"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('user_id', 'provider_id', name='uq_user_provider_vote'),
|
||||
{"schema": "data"}
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), nullable=False)
|
||||
provider_id = Column(Integer, ForeignKey("data.service_providers.id"), nullable=False)
|
||||
vote_value = Column(Integer, nullable=False) # +1 vagy -1
|
||||
|
||||
class Competition(Base):
|
||||
__tablename__ = "competitions"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String, nullable=False) # Pl: "Januári Feltöltő Verseny"
|
||||
description = Column(Text)
|
||||
start_date = Column(DateTime, nullable=False)
|
||||
end_date = Column(DateTime, nullable=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
class UserScore(Base):
|
||||
__tablename__ = "user_scores"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('user_id', 'competition_id', name='uq_user_competition_score'),
|
||||
{"schema": "data"}
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"))
|
||||
competition_id = Column(Integer, ForeignKey("data.competitions.id"))
|
||||
points = Column(Integer, default=0)
|
||||
last_updated = Column(DateTime, default=datetime.utcnow)
|
||||
17
backend/app/models/staged_data.py
Executable file
17
backend/app/models/staged_data.py
Executable file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import Column, Integer, String, JSON, DateTime, func
|
||||
from app.db.base import Base
|
||||
|
||||
class StagedVehicleData(Base):
|
||||
"""Ide érkeznek a nyers, validálatlan adatok a külső forrásokból"""
|
||||
__tablename__ = "staged_vehicle_data"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
source_url = Column(String) # Honnan jött az adat?
|
||||
raw_data = Column(JSON) # A teljes leszedett JSON struktúra
|
||||
|
||||
# Feldolgozási állapot
|
||||
status = Column(String, default="PENDING") # PENDING, PROCESSED, ERROR
|
||||
error_log = Column(String, nullable=True)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
15
backend/app/models/system_settings.py
Executable file
15
backend/app/models/system_settings.py
Executable file
@@ -0,0 +1,15 @@
|
||||
from sqlalchemy import Column, String, JSON
|
||||
from app.db.base import Base
|
||||
|
||||
class SystemSetting(Base):
|
||||
"""
|
||||
Globális rendszerbeállítások tárolása.
|
||||
Kulcs-Érték párok (JSON támogatással a komplex szabályokhoz).
|
||||
Példa: key='FREE_VEHICLE_LIMIT', value='2'
|
||||
"""
|
||||
__tablename__ = "system_settings"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
key = Column(String, primary_key=True, index=True)
|
||||
value = Column(JSON, nullable=False)
|
||||
description = Column(String, nullable=True)
|
||||
15
backend/app/models/translation.py
Executable file
15
backend/app/models/translation.py
Executable file
@@ -0,0 +1,15 @@
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, UniqueConstraint
|
||||
from app.db.base import Base
|
||||
|
||||
class Translation(Base):
|
||||
__tablename__ = "translations"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("key", "lang_code", name="uq_translation_key_lang"),
|
||||
{"schema": "data"}
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
key = Column(String(100), nullable=False, index=True)
|
||||
lang_code = Column(String(5), nullable=False, index=True)
|
||||
value = Column(Text, nullable=False)
|
||||
is_published = Column(Boolean, default=False) # Publikálási állapot
|
||||
35
backend/app/models/user.py
Executable file
35
backend/app/models/user.py
Executable file
@@ -0,0 +1,35 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, Boolean, Date, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class UserRole(str, enum.Enum):
|
||||
ADMIN = "admin"
|
||||
USER = "user"
|
||||
SERVICE = "service"
|
||||
FLEET_MANAGER = "fleet_manager"
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String, unique=True, index=True, nullable=False)
|
||||
hashed_password = Column(String, nullable=False)
|
||||
first_name = Column(String)
|
||||
last_name = Column(String)
|
||||
birthday = Column(Date, nullable=True)
|
||||
role = Column(String, default=UserRole.USER)
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_superuser = Column(Boolean, default=False)
|
||||
is_company = Column(Boolean, default=False)
|
||||
company_name = Column(String, nullable=True)
|
||||
tax_number = Column(String, nullable=True)
|
||||
region_code = Column(String, default="HU")
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# Kapcsolatok
|
||||
# memberships = relationship("OrganizationMember", back_populates="user", cascade="all, delete-orphan")
|
||||
# vehicles = relationship("VehicleOwnership", back_populates="user", cascade="all, delete-orphan")
|
||||
77
backend/app/models/vehicle.py
Executable file
77
backend/app/models/vehicle.py
Executable file
@@ -0,0 +1,77 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, Numeric, DateTime, JSON, Date
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
import uuid
|
||||
from app.db.base import Base
|
||||
|
||||
class VehicleBrand(Base):
|
||||
__tablename__ = "vehicle_brands"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(100), nullable=False, unique=True)
|
||||
slug = Column(String(100), unique=True)
|
||||
country_of_origin = Column(String(50))
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
class ServiceProvider(Base):
|
||||
__tablename__ = "service_providers"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(255), nullable=False)
|
||||
official_brand_partner = Column(Boolean, default=False)
|
||||
technical_rating_pct = Column(Integer, default=80)
|
||||
social_rating_pct = Column(Integer, default=80)
|
||||
location_city = Column(String(100))
|
||||
service_type = Column(String(50))
|
||||
search_tags = Column(String)
|
||||
latitude = Column(Numeric(10, 8))
|
||||
longitude = Column(Numeric(11, 8))
|
||||
is_active = Column(Boolean, default=True)
|
||||
records = relationship("ServiceRecord", back_populates="provider")
|
||||
|
||||
class EngineSpec(Base):
|
||||
__tablename__ = "engine_specs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
engine_code = Column(String(50), unique=True)
|
||||
fuel_type = Column(String(20))
|
||||
power_kw = Column(Integer)
|
||||
default_service_interval_km = Column(Integer, default=15000)
|
||||
vehicles = relationship("Vehicle", back_populates="engine_spec")
|
||||
|
||||
class Vehicle(Base):
|
||||
__tablename__ = "vehicles"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
current_company_id = Column(Integer, ForeignKey("data.companies.id"))
|
||||
brand_id = Column(Integer, ForeignKey("data.vehicle_brands.id"))
|
||||
model_name = Column(String(100))
|
||||
engine_spec_id = Column(Integer, ForeignKey("data.engine_specs.id"))
|
||||
identification_number = Column(String(50), unique=True)
|
||||
license_plate = Column(String(20))
|
||||
tracking_mode = Column(String(10), default="km")
|
||||
current_rating_pct = Column(Integer, default=100)
|
||||
total_real_usage = Column(Numeric(15, 2), default=0)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
engine_spec = relationship("EngineSpec", back_populates="vehicles")
|
||||
service_records = relationship("ServiceRecord", back_populates="vehicle", cascade="all, delete-orphan")
|
||||
|
||||
# --- KOMPATIBILITÁSI RÉTEG A RÉGI KÓDOKHOZ ---
|
||||
VehicleOwnership = Vehicle
|
||||
VehicleModel = Vehicle
|
||||
VehicleVariant = Vehicle
|
||||
VehicleCategory = VehicleBrand # JAVÍTVA: Nagy "B" betűvel
|
||||
|
||||
class ServiceRecord(Base):
|
||||
__tablename__ = "service_records"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
vehicle_id = Column(UUID(as_uuid=True), ForeignKey("data.vehicles.id"))
|
||||
provider_id = Column(Integer, ForeignKey("data.service_providers.id"))
|
||||
service_date = Column(Date, nullable=False)
|
||||
usage_value = Column(Numeric(15, 2))
|
||||
repair_quality_pct = Column(Integer, default=100)
|
||||
|
||||
vehicle = relationship("Vehicle", back_populates="service_records")
|
||||
provider = relationship("ServiceProvider", back_populates="records") # JAVÍTVA
|
||||
54
backend/app/models/vehicle_catalog.py
Executable file
54
backend/app/models/vehicle_catalog.py
Executable file
@@ -0,0 +1,54 @@
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, Float, JSON, Date
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
# 1. Kategória (Autó, Motor, Kisteher...)
|
||||
class VehicleCategory(Base):
|
||||
__tablename__ = "vehicle_categories"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
name_key = Column(String, nullable=False) # i18n kulcs: 'CAR', 'MOTORCYCLE'
|
||||
|
||||
# 2. Márka (Audi, Honda, BMW...)
|
||||
class VehicleMake(Base):
|
||||
__tablename__ = "vehicle_makes"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String, unique=True, nullable=False)
|
||||
logo_url = Column(String, nullable=True)
|
||||
|
||||
# 3. Modell és Generáció (pl. Audi A3 -> A3 8V)
|
||||
class VehicleModel(Base):
|
||||
__tablename__ = "vehicle_models"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
make_id = Column(Integer, ForeignKey("data.vehicle_makes.id"))
|
||||
category_id = Column(Integer, ForeignKey("data.vehicle_categories.id"))
|
||||
name = Column(String, nullable=False)
|
||||
generation_name = Column(String, nullable=True) # pl: "8V Facelift"
|
||||
production_start_year = Column(Integer, nullable=True)
|
||||
production_end_year = Column(Integer, nullable=True)
|
||||
|
||||
# 4. Motor és Hajtáslánc (Technikai specifikációk)
|
||||
class VehicleEngine(Base):
|
||||
__tablename__ = "vehicle_engines"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
model_id = Column(Integer, ForeignKey("data.vehicle_models.id"))
|
||||
|
||||
engine_code = Column(String, nullable=True)
|
||||
fuel_type = Column(String, nullable=False) # 'Petrol', 'Diesel', 'Hybrid', 'EV'
|
||||
displacement_ccm = Column(Integer, nullable=True)
|
||||
power_kw = Column(Integer, nullable=True)
|
||||
torque_nm = Column(Integer, nullable=True)
|
||||
transmission_type = Column(String, nullable=True) # 'Manual', 'Automatic'
|
||||
gears_count = Column(Integer, nullable=True)
|
||||
drive_type = Column(String, nullable=True) # 'FWD', 'RWD', 'AWD'
|
||||
|
||||
# 5. Opciók Katalógusa (Gyári extrák listája)
|
||||
class VehicleOptionCatalog(Base):
|
||||
__tablename__ = "vehicle_options_catalog"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
category = Column(String) # 'Security', 'Comfort', 'Multimedia'
|
||||
name_key = Column(String) # 'MATRIX_LED'
|
||||
19
backend/app/models/vehicle_ownership.py
Executable file
19
backend/app/models/vehicle_ownership.py
Executable file
@@ -0,0 +1,19 @@
|
||||
from sqlalchemy import Column, Integer, ForeignKey, DateTime, Boolean
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class VehicleOwnership(Base):
|
||||
__tablename__ = "vehicle_ownerships"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
vehicle_id = Column(Integer, ForeignKey("data.vehicles.id"))
|
||||
org_id = Column(Integer, ForeignKey("data.organizations.id"))
|
||||
|
||||
# Érvényességi időablak
|
||||
start_date = Column(DateTime(timezone=True), server_default=func.now())
|
||||
end_date = Column(DateTime(timezone=True), nullable=True) # Ha eladja, ide kerül a dátum
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
# Csak ezen az ablakon belüli szervizeket láthatja az aktuális tulajdonos
|
||||
21
backend/app/models/verification_token.py
Executable file
21
backend/app/models/verification_token.py
Executable file
@@ -0,0 +1,21 @@
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Enum
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base import Base
|
||||
|
||||
class TokenType(str, enum.Enum):
|
||||
email_verify = "email_verify"
|
||||
password_reset = "password_reset"
|
||||
|
||||
class VerificationToken(Base):
|
||||
__tablename__ = "verification_tokens"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"), nullable=False)
|
||||
|
||||
token_hash = Column(String(64), unique=True, index=True, nullable=False)
|
||||
token_type = Column(Enum(TokenType, name="tokentype", schema="data"), nullable=False)
|
||||
|
||||
expires_at = Column(DateTime(timezone=True), nullable=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
Reference in New Issue
Block a user