feat: stabilize KYC, international assets and multi-currency schema

- Split mother's name in KYC (last/first)
- Added mileage_unit and fuel_type to Assets
- Expanded AssetCost for international VAT and original currency
- Fixed SQLAlchemy IndexError in asset catalog lookup
- Added exchange_rate and ratings tables to models
This commit is contained in:
2026-02-08 23:41:07 +00:00
parent 451900ae1a
commit 24d35fe0c1
34 changed files with 709 additions and 347 deletions

133
backend/app/models/asset.py Normal file
View File

@@ -0,0 +1,133 @@
import uuid
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, JSON, Numeric, text
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
from sqlalchemy.sql import func
from app.db.base_class import Base
class AssetCatalog(Base):
"""Központi jármű katalógus (Admin/Bot által tölthető)"""
__tablename__ = "vehicle_catalog"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
make = Column(String, index=True, nullable=False)
model = Column(String, index=True, nullable=False)
generation = Column(String)
year_from = Column(Integer)
year_to = Column(Integer)
vehicle_class = Column(String) # land, sea, air
fuel_type = Column(String)
engine_code = Column(String)
assets = relationship("Asset", back_populates="catalog")
class Asset(Base):
"""A Jármű Identitás (Digital Twin törzsadatok)"""
__tablename__ = "assets"
__table_args__ = {"schema": "data"}
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
vin = Column(String(17), unique=True, index=True, nullable=False)
license_plate = Column(String(20), index=True)
name = Column(String)
year_of_manufacture = Column(Integer)
catalog_id = Column(Integer, ForeignKey("data.vehicle_catalog.id"))
# Nemzetközi mutatók
quality_index = Column(Numeric(3, 2), default=1.00)
system_mileage = Column(Integer, default=0)
mileage_unit = Column(String(10), default="km") # Nemzetközi: km, miles, hours
is_verified = Column(Boolean, default=False)
status = Column(String(20), default="active")
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
catalog = relationship("AssetCatalog", back_populates="assets")
assignments = relationship("AssetAssignment", back_populates="asset")
events = relationship("AssetEvent", back_populates="asset")
costs = relationship("AssetCost", back_populates="asset")
class AssetAssignment(Base):
"""Birtoklás követése (Kié a jármű és mettől meddig)"""
__tablename__ = "asset_assignments"
__table_args__ = {"schema": "data"}
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)
assigned_at = Column(DateTime(timezone=True), server_default=func.now())
released_at = Column(DateTime(timezone=True), nullable=True)
status = Column(String(30), default="active")
notes = Column(String)
asset = relationship("Asset", back_populates="assignments")
organization = relationship("Organization", back_populates="assets")
class AssetEvent(Base):
"""Élettörténeti események (Szerviz, km-óra állások, balesetek)"""
__tablename__ = "asset_events"
__table_args__ = {"schema": "data"}
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)
event_type = Column(String(50), nullable=False)
event_date = Column(DateTime(timezone=True), server_default=func.now())
recorded_mileage = Column(Integer)
description = Column(String)
data = Column(JSON, server_default=text("'{}'::jsonb"))
asset = relationship("Asset", back_populates="events")
class AssetCost(Base):
"""
Költségkezelő modell: Bruttó/Nettó/ÁFA és deviza támogatás.
"""
__tablename__ = "asset_costs"
__table_args__ = {"schema": "data"}
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)
cost_type = Column(String(50), nullable=False) # fuel, service, tax, insurance, toll
# Pénzügyi adatok
amount = Column(Numeric(18, 2), nullable=False) # Bruttó összeg
net_amount = Column(Numeric(18, 2)) # Nettó összeg
vat_amount = Column(Numeric(18, 2)) # ÁFA érték
vat_rate = Column(Numeric(5, 2)) # ÁFA kulcs (pl. 27.00)
# Nemzetközi deviza kezelés
currency = Column(String(3), default="HUF") # Riportálási deviza
original_currency = Column(String(3)) # Számla eredeti devizája
exchange_rate_at_cost = Column(Numeric(18, 6)) # Rögzítéskori árfolyam
date = Column(DateTime(timezone=True), server_default=func.now())
description = Column(String)
invoice_id = Column(String)
mileage_at_cost = Column(Integer)
data = Column(JSON, server_default=text("'{}'::jsonb"))
asset = relationship("Asset", back_populates="costs")
class ExchangeRate(Base):
"""Napi árfolyamok tárolása (ECB/MNB adatok alapján)"""
__tablename__ = "exchange_rates"
__table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
base_currency = Column(String(3), default="EUR")
target_currency = Column(String(3), nullable=False)
rate = Column(Numeric(18, 6), nullable=False)
rate_date = Column(DateTime(timezone=False), index=True)
provider = Column(String(50), default="ECB")
updated_at = Column(DateTime(timezone=True), server_default=func.now())