fix: add SQLite compatibility for Decimal types
SQLite doesn't support Decimal natively - it stores DECIMAL columns as REAL (float). This caused sqlite3.ProgrammingError when writing Decimal values. Changes: - Add prepare_for_db() helper to convert Decimal→float before writes - Add Pydantic validators to convert float→Decimal on model creation - Update CRUD layer tests to verify float params for SQLite - Add SQLite round-trip tests to verify precision is preserved The data flow is now: Decimal (calculations) → float (prepare_for_db) → SQLite → float → Decimal (validators) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d245047487
commit
904b3f1d61
3 changed files with 323 additions and 60 deletions
37
models.py
37
models.py
|
|
@ -7,6 +7,16 @@ from typing import Optional
|
|||
from pydantic import BaseModel, validator
|
||||
|
||||
|
||||
def _to_decimal(v):
|
||||
"""Convert a value to Decimal, handling floats from database."""
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, Decimal):
|
||||
return v
|
||||
# Convert via string to avoid float precision issues
|
||||
return Decimal(str(v))
|
||||
|
||||
|
||||
# DCA Client Models
|
||||
class CreateDcaClientData(BaseModel):
|
||||
user_id: str
|
||||
|
|
@ -27,6 +37,10 @@ class DcaClient(BaseModel):
|
|||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@validator('fixed_mode_daily_limit', pre=True)
|
||||
def convert_fixed_mode_daily_limit(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
@ -65,6 +79,10 @@ class DcaDeposit(BaseModel):
|
|||
created_at: datetime
|
||||
confirmed_at: Optional[datetime]
|
||||
|
||||
@validator('amount', pre=True)
|
||||
def convert_amount(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
@ -99,6 +117,10 @@ class DcaPayment(BaseModel):
|
|||
created_at: datetime
|
||||
transaction_time: Optional[datetime] = None # Original ATM transaction time
|
||||
|
||||
@validator('amount_fiat', 'exchange_rate', pre=True)
|
||||
def convert_decimals(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
@ -111,6 +133,10 @@ class ClientBalanceSummary(BaseModel):
|
|||
remaining_balance: Decimal # Available balance for DCA in GTQ
|
||||
currency: str
|
||||
|
||||
@validator('total_deposits', 'total_payments', 'remaining_balance', pre=True)
|
||||
def convert_decimals(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
@ -165,6 +191,13 @@ class StoredLamassuTransaction(BaseModel):
|
|||
clients_count: int # Number of clients who received distributions
|
||||
distributions_total_sats: int # Total sats distributed to clients
|
||||
|
||||
@validator(
|
||||
'fiat_amount', 'commission_percentage', 'discount',
|
||||
'effective_commission', 'exchange_rate', pre=True
|
||||
)
|
||||
def convert_decimals(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
@ -228,6 +261,10 @@ class LamassuConfig(BaseModel):
|
|||
# DCA Client Limits
|
||||
max_daily_limit_gtq: Decimal = Decimal("2000") # Maximum daily limit for Fixed mode clients
|
||||
|
||||
@validator('max_daily_limit_gtq', pre=True)
|
||||
def convert_max_daily_limit(cls, v):
|
||||
return _to_decimal(v)
|
||||
|
||||
class Config:
|
||||
json_encoders = {Decimal: lambda v: float(v)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue