149 lines
6.3 KiB
Python
149 lines
6.3 KiB
Python
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Enum, Boolean
|
|
from sqlalchemy.orm import relationship, declarative_base
|
|
import enum
|
|
from datetime import datetime
|
|
from .logging_config import setup_logging, DEBUG_LOGGING
|
|
import logging
|
|
|
|
Base = declarative_base()
|
|
|
|
setup_logging()
|
|
models_logger = logging.getLogger("hoa_app.models")
|
|
|
|
class RoleEnum(str, enum.Enum):
|
|
admin = "admin"
|
|
user = "user"
|
|
|
|
class Role(Base):
|
|
__tablename__ = "roles"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(Enum(RoleEnum), unique=True, nullable=False)
|
|
users = relationship("User", back_populates="role")
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
username = Column(String, unique=True, index=True, nullable=False)
|
|
password_hash = Column(String, nullable=False)
|
|
role_id = Column(Integer, ForeignKey("roles.id"))
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
role = relationship("Role", back_populates="users")
|
|
|
|
class Bucket(Base):
|
|
__tablename__ = "buckets"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, unique=True, nullable=False)
|
|
description = Column(String)
|
|
accounts = relationship("Account", back_populates="bucket")
|
|
|
|
class AccountType(Base):
|
|
__tablename__ = "account_types"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, unique=True, nullable=False)
|
|
accounts = relationship("Account", back_populates="account_type")
|
|
def __init__(self, **kwargs):
|
|
super().__init__(**kwargs)
|
|
if DEBUG_LOGGING:
|
|
models_logger.debug(f"AccountType created: {self.name}")
|
|
|
|
class Account(Base):
|
|
__tablename__ = "accounts"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
bucket_id = Column(Integer, ForeignKey("buckets.id"))
|
|
account_type_id = Column(Integer, ForeignKey("account_types.id"))
|
|
name = Column(String, nullable=False)
|
|
institution_name = Column(String, nullable=False)
|
|
interest_rate = Column(Float, default=0.0)
|
|
maturity_date = Column(DateTime, nullable=True)
|
|
balance = Column(Float, default=0.0)
|
|
last_validated_at = Column(DateTime, default=datetime.utcnow)
|
|
bucket = relationship("Bucket", back_populates="accounts")
|
|
account_type = relationship("AccountType", back_populates="accounts")
|
|
transactions = relationship("Transaction", back_populates="account", foreign_keys="[Transaction.account_id]")
|
|
cash_flows = relationship("CashFlow", back_populates="account")
|
|
balance_history = relationship("AccountBalanceHistory", back_populates="account", cascade="all, delete-orphan")
|
|
|
|
def __init__(self, **kwargs):
|
|
super().__init__(**kwargs)
|
|
if DEBUG_LOGGING:
|
|
models_logger.debug(f"Account created: {self.name} at {self.institution_name}")
|
|
|
|
def set_balance(self, new_balance):
|
|
if self.balance != new_balance:
|
|
if DEBUG_LOGGING:
|
|
models_logger.debug(f"Balance update for account {self.id}: {self.balance} -> {new_balance}")
|
|
self.balance = new_balance
|
|
self.last_validated_at = datetime.utcnow()
|
|
if DEBUG_LOGGING:
|
|
models_logger.debug(f"last_validated_at updated for account {self.id}: {self.last_validated_at}")
|
|
|
|
class TransactionTypeEnum(str, enum.Enum):
|
|
deposit = "deposit"
|
|
withdrawal = "withdrawal"
|
|
transfer = "transfer"
|
|
|
|
class Transaction(Base):
|
|
__tablename__ = "transactions"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
account_id = Column(Integer, ForeignKey("accounts.id"))
|
|
type = Column(Enum(TransactionTypeEnum), nullable=False)
|
|
amount = Column(Float, nullable=False)
|
|
date = Column(DateTime, default=datetime.utcnow)
|
|
description = Column(String)
|
|
related_account_id = Column(Integer, ForeignKey("accounts.id"), nullable=True)
|
|
reconciled = Column(Boolean, default=False) # NEW FIELD
|
|
account = relationship("Account", back_populates="transactions", foreign_keys=[account_id])
|
|
related_account = relationship("Account", foreign_keys=[related_account_id])
|
|
|
|
class CashFlowTypeEnum(str, enum.Enum):
|
|
inflow = "inflow"
|
|
outflow = "outflow"
|
|
|
|
class CashFlow(Base):
|
|
__tablename__ = "cash_flows"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
account_id = Column(Integer, ForeignKey("accounts.id"))
|
|
type = Column(Enum(CashFlowTypeEnum), nullable=False)
|
|
estimate_actual = Column(Boolean, default=True) # True=estimate, False=actual
|
|
amount = Column(Float, nullable=False)
|
|
date = Column(DateTime, nullable=False)
|
|
description = Column(String)
|
|
account = relationship("Account", back_populates="cash_flows")
|
|
|
|
class AccountBalanceHistory(Base):
|
|
__tablename__ = "account_balance_history"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
account_id = Column(Integer, ForeignKey("accounts.id"), nullable=False, index=True)
|
|
balance = Column(Float, nullable=False)
|
|
date = Column(DateTime, nullable=False, index=True)
|
|
account = relationship("Account", back_populates="balance_history")
|
|
|
|
class CashFlowCategoryTypeEnum(str, enum.Enum):
|
|
income = "income"
|
|
expense = "expense"
|
|
|
|
class CashFlowFundingTypeEnum(str, enum.Enum):
|
|
operating = "Operating"
|
|
reserve = "Reserve"
|
|
|
|
class CashFlowCategory(Base):
|
|
__tablename__ = "cash_flow_categories"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, unique=True, nullable=False)
|
|
category_type = Column(Enum(CashFlowCategoryTypeEnum), nullable=False)
|
|
funding_type = Column(Enum(CashFlowFundingTypeEnum), nullable=False)
|
|
entries = relationship("CashFlowEntry", back_populates="category")
|
|
|
|
class CashFlowEntry(Base):
|
|
__tablename__ = "cash_flow_entries"
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
category_id = Column(Integer, ForeignKey("cash_flow_categories.id"), nullable=False)
|
|
year = Column(Integer, nullable=False)
|
|
month = Column(Integer, nullable=False)
|
|
projected_amount = Column(Float, nullable=True)
|
|
actual_amount = Column(Float, nullable=True)
|
|
created_by = Column(Integer, ForeignKey("users.id"), nullable=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
category = relationship("CashFlowCategory", back_populates="entries")
|
|
user = relationship("User") |