import json from dataclasses import dataclass, field from pathlib import Path from cashflow_model.account import Account from cashflow_model.asset import Asset from cashflow_model.currency import DEFAULT_RATES, ExchangeRate from cashflow_model.liability import Liability from cashflow_model.recurring import RecurringCashflow from cashflow_model.scenario import ForecastScenario from cashflow_model.transaction import Transaction @dataclass class FinancialModel: base_currency: str = "RUB" accounts: list[Account] = field(default_factory=list) transactions: list[Transaction] = field(default_factory=list) recurring: list[RecurringCashflow] = field(default_factory=list) assets: list[Asset] = field(default_factory=list) liabilities: list[Liability] = field(default_factory=list) scenarios: list[ForecastScenario] = field(default_factory=list) exchange_rates: list[ExchangeRate] = field(default_factory=lambda: DEFAULT_RATES.copy()) def to_dict(self) -> dict: return { "base_currency": self.base_currency, "accounts": [a.to_dict() for a in self.accounts], "transactions": [t.to_dict() for t in self.transactions], "recurring": [r.to_dict() for r in self.recurring], "assets": [a.to_dict() for a in self.assets], "liabilities": [li.to_dict() for li in self.liabilities], "scenarios": [s.to_dict() for s in self.scenarios], "exchange_rates": [r.to_dict() for r in self.exchange_rates], } @classmethod def from_dict(cls, data: dict) -> "FinancialModel": return cls( base_currency=data.get("base_currency", "RUB"), accounts=[Account.from_dict(a) for a in data.get("accounts", [])], transactions=[Transaction.from_dict(t) for t in data.get("transactions", [])], recurring=[RecurringCashflow.from_dict(r) for r in data.get("recurring", [])], assets=[Asset.from_dict(a) for a in data.get("assets", [])], liabilities=[Liability.from_dict(li) for li in data.get("liabilities", [])], scenarios=[ForecastScenario.from_dict(s) for s in data.get("scenarios", [])], exchange_rates=[ExchangeRate.from_dict(r) for r in data.get("exchange_rates", [])], ) def save(self, path: str | Path) -> None: path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) with open(path, "w", encoding="utf-8") as f: json.dump(self.to_dict(), f, indent=2, ensure_ascii=False) @classmethod def load(cls, path: str | Path) -> "FinancialModel": path = Path(path) with open(path, "r", encoding="utf-8") as f: data = json.load(f) return cls.from_dict(data)