frontend költség beállítások
This commit is contained in:
25
backend/app/models/fleet_finance/__init__.py
Normal file
25
backend/app/models/fleet_finance/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/models/fleet_finance/__init__.py
|
||||
"""
|
||||
fleet_finance schema: Flotta pénzügyi adatok (költségek, finanszírozás, biztosítás, adók).
|
||||
Áthelyezve a vehicle sémából: AssetCost, CostCategory, AssetFinancials.
|
||||
"""
|
||||
|
||||
from .models import (
|
||||
AssetCost,
|
||||
AssetCostStatusEnum,
|
||||
CostCategory,
|
||||
AssetFinancials,
|
||||
InsuranceProvider,
|
||||
VehicleInsurancePolicy,
|
||||
VehicleTaxObligation,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AssetCost",
|
||||
"AssetCostStatusEnum",
|
||||
"CostCategory",
|
||||
"AssetFinancials",
|
||||
"InsuranceProvider",
|
||||
"VehicleInsurancePolicy",
|
||||
"VehicleTaxObligation",
|
||||
]
|
||||
316
backend/app/models/fleet_finance/models.py
Normal file
316
backend/app/models/fleet_finance/models.py
Normal file
@@ -0,0 +1,316 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/models/fleet_finance/models.py
|
||||
"""
|
||||
fleet_finance schema: Flotta pénzügyi adatok.
|
||||
- CostCategory: Standardizált költségkategóriák hierarchiája (áthelyezve vehicle -> fleet_finance)
|
||||
- AssetCost: Eszközhöz kapcsolódó tényleges költségnapló (áthelyezve vehicle -> fleet_finance)
|
||||
- AssetFinancials: Beszerzés és értékcsökkenés (áthelyezve vehicle -> fleet_finance, kibővítve finanszírozási adatokkal)
|
||||
- InsuranceProvider: Biztosítók katalógusa (ÚJ)
|
||||
- VehicleInsurancePolicy: Jármű biztosítási kötvények (ÚJ)
|
||||
- VehicleTaxObligation: Jármű adókötelezettségek (ÚJ)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
import enum
|
||||
from datetime import datetime, date
|
||||
from typing import Optional, List, TYPE_CHECKING
|
||||
from sqlalchemy import (
|
||||
String, Boolean, DateTime, ForeignKey, Numeric, text, Text,
|
||||
UniqueConstraint, Integer, Date
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID, JSONB
|
||||
from sqlalchemy.sql import func
|
||||
from app.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.vehicle.asset import Asset
|
||||
from app.models.marketplace.organization import Organization
|
||||
from app.models.system.document import Document
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# CostCategory (áthelyezve vehicle -> fleet_finance)
|
||||
# =============================================================================
|
||||
|
||||
class CostCategory(Base):
|
||||
"""
|
||||
Standardizált költségkategóriák hierarchikus fája.
|
||||
Rendszerkategóriák (is_system=True) nem törölhetők, csak felhasználói kategóriák.
|
||||
Áthelyezve a vehicle sémából a fleet_finance sémába.
|
||||
"""
|
||||
__tablename__ = "cost_categories"
|
||||
__table_args__ = {"schema": "fleet_finance", "extend_existing": True}
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
parent_id: Mapped[Optional[int]] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("fleet_finance.cost_categories.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True
|
||||
)
|
||||
code: Mapped[str] = mapped_column(String(50), unique=True, index=True, nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
is_system: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false")
|
||||
visibility: Mapped[str] = mapped_column(String(20), default="both", server_default="'both'")
|
||||
min_tier: Mapped[str] = mapped_column(String(20), default="free", server_default="'free'")
|
||||
accounting_code: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), onupdate=func.now(), server_default=func.now())
|
||||
|
||||
# Hierarchikus kapcsolatok
|
||||
parent: Mapped[Optional["CostCategory"]] = relationship(
|
||||
"CostCategory",
|
||||
remote_side=[id],
|
||||
back_populates="children",
|
||||
foreign_keys=[parent_id]
|
||||
)
|
||||
children: Mapped[list["CostCategory"]] = relationship(
|
||||
"CostCategory",
|
||||
back_populates="parent",
|
||||
foreign_keys=[parent_id]
|
||||
)
|
||||
|
||||
# Kapcsolódó költségek (AssetCost)
|
||||
asset_costs: Mapped[list["AssetCost"]] = relationship("AssetCost", back_populates="category")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"CostCategory(id={self.id}, code='{self.code}', name='{self.name}')"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# AssetCostStatusEnum
|
||||
# =============================================================================
|
||||
|
||||
class AssetCostStatusEnum(str, enum.Enum):
|
||||
"""Költség státuszok a jóváhagyási munkafolyamathoz."""
|
||||
DRAFT = "DRAFT"
|
||||
PENDING_APPROVAL = "PENDING_APPROVAL"
|
||||
APPROVED = "APPROVED"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# AssetCost (áthelyezve vehicle -> fleet_finance)
|
||||
# =============================================================================
|
||||
|
||||
class AssetCost(Base):
|
||||
""" II. Üzemeltetés és TCO kimutatás. Áthelyezve a vehicle sémából. """
|
||||
__tablename__ = "asset_costs"
|
||||
__table_args__ = {"schema": "fleet_finance"}
|
||||
id: Mapped[uuid.UUID] = mapped_column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
asset_id: Mapped[uuid.UUID] = mapped_column(PG_UUID(as_uuid=True), ForeignKey("vehicle.assets.id"), nullable=False)
|
||||
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey("fleet.organizations.id"), nullable=False)
|
||||
|
||||
category_id: Mapped[int] = mapped_column(Integer, ForeignKey("fleet_finance.cost_categories.id"), index=True, nullable=False)
|
||||
amount_net: Mapped[float] = mapped_column(Numeric(18, 2), nullable=False)
|
||||
amount_gross: Mapped[Optional[float]] = mapped_column(Numeric(18, 2), nullable=True)
|
||||
vat_rate: Mapped[Optional[float]] = mapped_column(Numeric(5, 2), nullable=True)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="HUF")
|
||||
date: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
invoice_number: Mapped[Optional[str]] = mapped_column(String(100), index=True)
|
||||
document_id: Mapped[Optional[uuid.UUID]] = mapped_column(PG_UUID(as_uuid=True), ForeignKey("system.documents.id"), nullable=True)
|
||||
|
||||
# Státusz a jóváhagyási munkafolyamathoz
|
||||
status: Mapped[str] = mapped_column(String(30), default="DRAFT", server_default=text("'DRAFT'"), index=True)
|
||||
|
||||
# Kétirányú hivatkozás az AssetEvent felé (kettős könyvelés elkerülése)
|
||||
linked_asset_event_id: Mapped[Optional[uuid.UUID]] = mapped_column(
|
||||
PG_UUID(as_uuid=True),
|
||||
ForeignKey("vehicle.asset_events.id"),
|
||||
nullable=True,
|
||||
index=True
|
||||
)
|
||||
|
||||
# === BESZÁLLÍTÓI HIVATKOZÁSOK (B2B expansion) ===
|
||||
# Hivatkozás a fleet.organizations táblában lévő beszállítóra
|
||||
vendor_organization_id: Mapped[Optional[int]] = mapped_column(
|
||||
Integer, ForeignKey("fleet.organizations.id"), nullable=True, index=True
|
||||
)
|
||||
# Szabadon gépelhető beszállító név (ha nincs a rendszerben)
|
||||
external_vendor_name: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
|
||||
|
||||
# === KÖNYVELÉSI DÁTUMOK ===
|
||||
invoice_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
fulfillment_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
|
||||
data: Mapped[dict] = mapped_column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
asset: Mapped["Asset"] = relationship("Asset", back_populates="costs")
|
||||
organization: Mapped["Organization"] = relationship("Organization", foreign_keys=[organization_id])
|
||||
category: Mapped["CostCategory"] = relationship("CostCategory", back_populates="asset_costs")
|
||||
|
||||
# Kapcsolat a hivatkozott eseményhez
|
||||
linked_event: Mapped[Optional["AssetEvent"]] = relationship(
|
||||
"AssetEvent",
|
||||
foreign_keys=[linked_asset_event_id],
|
||||
post_update=True
|
||||
)
|
||||
|
||||
# Beszállító kapcsolat
|
||||
vendor_organization: Mapped[Optional["Organization"]] = relationship(
|
||||
"Organization", foreign_keys=[vendor_organization_id]
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# AssetFinancials (áthelyezve vehicle -> fleet_finance, kibővítve)
|
||||
# =============================================================================
|
||||
|
||||
class AssetFinancials(Base):
|
||||
"""
|
||||
I. Beszerzés és IV. Értékcsökkenés (Amortizáció).
|
||||
Áthelyezve a vehicle sémából a fleet_finance sémába.
|
||||
Kibővítve finanszírozási adatokkal (lízing, hitel).
|
||||
"""
|
||||
__tablename__ = "asset_financials"
|
||||
__table_args__ = {"schema": "fleet_finance"}
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
asset_id: Mapped[uuid.UUID] = mapped_column(PG_UUID(as_uuid=True), ForeignKey("vehicle.assets.id"), unique=True)
|
||||
|
||||
# === BESZERZÉS ===
|
||||
purchase_price_net: Mapped[float] = mapped_column(Numeric(18, 2))
|
||||
purchase_price_gross: Mapped[float] = mapped_column(Numeric(18, 2))
|
||||
vat_rate: Mapped[float] = mapped_column(Numeric(5, 2), default=27.00)
|
||||
activation_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
verified_purchase_date: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
||||
financing_type: Mapped[str] = mapped_column(String(50))
|
||||
accounting_details: Mapped[dict] = mapped_column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
|
||||
# === FINANSZÍROZÁS (ÚJ) ===
|
||||
down_payment: Mapped[Optional[float]] = mapped_column(Numeric(18, 2), nullable=True)
|
||||
monthly_installment: Mapped[Optional[float]] = mapped_column(Numeric(18, 2), nullable=True)
|
||||
residual_value: Mapped[Optional[float]] = mapped_column(Numeric(18, 2), nullable=True)
|
||||
contract_number: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
|
||||
financing_provider: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
|
||||
interest_rate: Mapped[Optional[float]] = mapped_column(Numeric(5, 2), nullable=True)
|
||||
total_contract_value: Mapped[Optional[float]] = mapped_column(Numeric(18, 2), nullable=True)
|
||||
lease_start_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
lease_end_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
|
||||
# === KAPCSOLATOK ===
|
||||
asset: Mapped["Asset"] = relationship("Asset", back_populates="financials")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# InsuranceProvider (ÚJ)
|
||||
# =============================================================================
|
||||
|
||||
class InsuranceProvider(Base):
|
||||
"""
|
||||
Biztosítók katalógusa.
|
||||
Tárolja a biztosítók elérhetőségeit és szolgáltatásait.
|
||||
"""
|
||||
__tablename__ = "insurance_providers"
|
||||
__table_args__ = {"schema": "fleet_finance"}
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(150), nullable=False, index=True)
|
||||
country_code: Mapped[Optional[str]] = mapped_column(String(2), index=True, nullable=True, comment="ISO 3166-1 alpha-2 országkód (pl. 'HU'). Ha NULL, akkor globális.")
|
||||
claim_phone: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
|
||||
claim_url: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
||||
services_offered: Mapped[dict] = mapped_column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, server_default=text("true"))
|
||||
|
||||
# Kapcsolatok
|
||||
policies: Mapped[List["VehicleInsurancePolicy"]] = relationship(
|
||||
"VehicleInsurancePolicy", back_populates="provider"
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"InsuranceProvider(id={self.id}, name='{self.name}')"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# VehicleInsurancePolicy (ÚJ)
|
||||
# =============================================================================
|
||||
|
||||
class VehicleInsurancePolicy(Base):
|
||||
"""
|
||||
Jármű biztosítási kötvények.
|
||||
Minden kötvény egy járműhöz (asset) és egy biztosítóhoz (provider) tartozik.
|
||||
"""
|
||||
__tablename__ = "vehicle_insurance_policies"
|
||||
__table_args__ = {"schema": "fleet_finance"}
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
asset_id: Mapped[uuid.UUID] = mapped_column(
|
||||
PG_UUID(as_uuid=True), ForeignKey("vehicle.assets.id"), nullable=False, index=True
|
||||
)
|
||||
provider_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey("fleet_finance.insurance_providers.id"), nullable=False, index=True
|
||||
)
|
||||
|
||||
insurance_type: Mapped[str] = mapped_column(
|
||||
String(20), nullable=False, comment="KGFB, CASCO"
|
||||
)
|
||||
policy_number: Mapped[str] = mapped_column(String(100), nullable=False, index=True)
|
||||
start_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
expiry_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
premium_amount: Mapped[float] = mapped_column(Numeric(18, 2), nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="HUF")
|
||||
|
||||
# Dokumentum kapcsolat (PDF kötvény)
|
||||
document_id: Mapped[Optional[uuid.UUID]] = mapped_column(
|
||||
PG_UUID(as_uuid=True), ForeignKey("system.documents.id"), nullable=True
|
||||
)
|
||||
|
||||
# Kapcsolatok
|
||||
asset: Mapped["Asset"] = relationship("Asset")
|
||||
provider: Mapped["InsuranceProvider"] = relationship(
|
||||
"InsuranceProvider", back_populates="policies"
|
||||
)
|
||||
document: Mapped[Optional["Document"]] = relationship("Document")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"VehicleInsurancePolicy(id={self.id}, asset_id={self.asset_id}, "
|
||||
f"type='{self.insurance_type}', policy='{self.policy_number}')"
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# VehicleTaxObligation (ÚJ)
|
||||
# =============================================================================
|
||||
|
||||
class VehicleTaxObligation(Base):
|
||||
"""
|
||||
Jármű adókötelezettségek.
|
||||
Tárolja a különböző típusú adókat (súlyadó, cégautóadó, stb.).
|
||||
"""
|
||||
__tablename__ = "vehicle_tax_obligations"
|
||||
__table_args__ = {"schema": "fleet_finance"}
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
asset_id: Mapped[uuid.UUID] = mapped_column(
|
||||
PG_UUID(as_uuid=True), ForeignKey("vehicle.assets.id"), nullable=False, index=True
|
||||
)
|
||||
|
||||
tax_type: Mapped[str] = mapped_column(
|
||||
String(30), nullable=False, comment="WEIGHT_TAX, COMPANY_CAR_TAX"
|
||||
)
|
||||
tax_year: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
|
||||
amount: Mapped[float] = mapped_column(Numeric(18, 2), nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="HUF")
|
||||
due_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
||||
payment_status: Mapped[str] = mapped_column(
|
||||
String(20), default="pending", server_default=text("'pending'")
|
||||
)
|
||||
|
||||
# Dokumentum kapcsolat (PDF adóbevallás)
|
||||
document_id: Mapped[Optional[uuid.UUID]] = mapped_column(
|
||||
PG_UUID(as_uuid=True), ForeignKey("system.documents.id"), nullable=True
|
||||
)
|
||||
|
||||
# Kapcsolatok
|
||||
asset: Mapped["Asset"] = relationship("Asset")
|
||||
document: Mapped[Optional["Document"]] = relationship("Document")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"VehicleTaxObligation(id={self.id}, asset_id={self.asset_id}, "
|
||||
f"type='{self.tax_type}', year={self.tax_year})"
|
||||
)
|
||||
Reference in New Issue
Block a user