T3: Decimal for money — all monetary fields migrated from float
- All domain monetary fields now use Decimal: - Account.balance, Asset.value, Asset.growth_rate - Liability.balance, Liability.interest, Liability.payment - Transaction.amount, RecurringCashflow.amount - ExchangeRate.rate - ForecastScenario.income_multiplier, expense_multiplier, growth_multiplier - CurrencyConverter: all arithmetic in Decimal, quantize to 0.01 with ROUND_HALF_UP - ForecastService: Decimal arithmetic throughout (income, expenses, balance, growth, liability cost) - ScenarioService: Decimal multipliers, deepcopy safe with Decimal fields - assistant.py: _DecimalEncoder for json.dumps (Decimal -> str in JSON) Pydantic v2 + Decimal: - model_dump(mode='json') converts Decimal to str (JSON-safe) - model_validate() parses str back to Decimal - Round-trip preserves precision (100.50 stays 100.50) Tests: 63/63 pass.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
@@ -8,12 +9,12 @@ class Transaction(BaseModel):
|
||||
date: str = ""
|
||||
account: str = ""
|
||||
category: str = ""
|
||||
amount: float = 0.0
|
||||
amount: Decimal = Field(default=Decimal("0"))
|
||||
description: str = ""
|
||||
|
||||
@field_validator("amount")
|
||||
@classmethod
|
||||
def _amount_nonzero(cls, v: float) -> float:
|
||||
def _amount_nonzero(cls, v: Decimal) -> Decimal:
|
||||
if v == 0:
|
||||
raise ValueError("amount must be non-zero")
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user