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:
+3
-2
@@ -1,3 +1,4 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
@@ -7,11 +8,11 @@ class Account(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
currency: str = "USD"
|
||||
balance: float = 0.0
|
||||
balance: Decimal = Field(default=Decimal("0"))
|
||||
|
||||
@field_validator("balance")
|
||||
@classmethod
|
||||
def _balance_non_negative(cls, v: float) -> float:
|
||||
def _balance_non_negative(cls, v: Decimal) -> Decimal:
|
||||
if v < 0:
|
||||
raise ValueError("balance must be non-negative")
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user