01 Refactor currency handling in client models and calculations: Update models to store values in GTQ instead of centavos, adjust cost basis calculations, and modify API responses and frontend currency formatting to reflect the new structure.
Some checks failed
CI / lint (push) Has been cancelled
CI / tests (3.10) (push) Has been cancelled
CI / tests (3.9) (push) Has been cancelled
/ release (push) Has been cancelled
/ pullrequest (push) Has been cancelled

This commit is contained in:
padreug 2025-07-06 00:00:48 +02:00
parent 8c3faeec3f
commit 8d442b7c6f
5 changed files with 16 additions and 69 deletions

View file

@ -103,7 +103,7 @@ async def get_client_dashboard_summary(user_id: str) -> Optional[ClientDashboard
# Calculate metrics
total_invested = confirmed_deposits # Total invested = all confirmed deposits
remaining_balance = confirmed_deposits - dca_spent # Remaining = deposits - DCA spending
avg_cost_basis = total_sats / (dca_spent / 100) if dca_spent > 0 else 0 # Cost basis = sats / GTQ (convert centavos to GTQ)
avg_cost_basis = total_sats / dca_spent if dca_spent > 0 else 0 # Cost basis = sats / GTQ
# Calculate current fiat value of total sats
current_sats_fiat_value = 0.0
@ -248,7 +248,7 @@ async def get_client_analytics(user_id: str, time_range: str = "30d") -> Optiona
# Build cost basis history
cost_basis_history = []
for record in cost_basis_data:
avg_cost_basis = record["cumulative_sats"] / (record["cumulative_fiat"] / 100) if record["cumulative_fiat"] > 0 else 0 # Convert centavos to GTQ
avg_cost_basis = record["cumulative_sats"] / record["cumulative_fiat"] if record["cumulative_fiat"] > 0 else 0 # Cost basis = sats / GTQ
# Use transaction_date (which is COALESCE(transaction_time, created_at))
date_to_use = record["transaction_date"]
if date_to_use is None:

View file

@ -1,53 +0,0 @@
# Currency conversion utilities for Client Extension API boundary
from decimal import Decimal
from typing import Union
def gtq_to_centavos(gtq_amount: Union[float, int, str]) -> int:
"""Convert GTQ to centavos for database storage"""
return int(Decimal(str(gtq_amount)) * 100)
def centavos_to_gtq(centavos: int) -> float:
"""Convert centavos to GTQ for API responses"""
return float(centavos) / 100
def format_gtq_currency(centavos: int) -> str:
"""Format centavos as GTQ currency string"""
gtq_amount = centavos_to_gtq(centavos)
return f"Q{gtq_amount:.2f}"
# Conversion helpers for client API responses
def dashboard_summary_db_to_api(summary_db) -> dict:
"""Convert database dashboard summary to API response"""
return {
"user_id": summary_db.user_id,
"total_sats_accumulated": summary_db.total_sats_accumulated,
"total_fiat_invested_gtq": centavos_to_gtq(summary_db.total_fiat_invested),
"pending_fiat_deposits_gtq": centavos_to_gtq(summary_db.pending_fiat_deposits),
"current_sats_fiat_value_gtq": centavos_to_gtq(int(summary_db.current_sats_fiat_value)),
"average_cost_basis": summary_db.average_cost_basis,
"current_fiat_balance_gtq": centavos_to_gtq(summary_db.current_fiat_balance),
"total_transactions": summary_db.total_transactions,
"dca_mode": summary_db.dca_mode,
"dca_status": summary_db.dca_status,
"last_transaction_date": summary_db.last_transaction_date,
"currency": summary_db.currency
}
def transaction_db_to_api(transaction_db) -> dict:
"""Convert database transaction to API response"""
return {
"id": transaction_db.id,
"amount_sats": transaction_db.amount_sats,
"amount_fiat_gtq": centavos_to_gtq(transaction_db.amount_fiat),
"exchange_rate": transaction_db.exchange_rate,
"transaction_type": transaction_db.transaction_type,
"status": transaction_db.status,
"created_at": transaction_db.created_at,
"transaction_time": transaction_db.transaction_time,
"lamassu_transaction_id": transaction_db.lamassu_transaction_id
}

View file

@ -36,16 +36,16 @@ class ClientTransactionAPI(BaseModel):
lamassu_transaction_id: Optional[str] = None
# Internal Models for Client Dashboard (Database storage in centavos)
# Internal Models for Client Dashboard (Database storage in GTQ)
class ClientDashboardSummary(BaseModel):
"""Internal model - client dashboard summary stored in centavos"""
"""Internal model - client dashboard summary stored in GTQ"""
user_id: str
total_sats_accumulated: int
total_fiat_invested: int # Confirmed deposits (in centavos)
pending_fiat_deposits: int # Pending deposits awaiting confirmation (in centavos)
current_sats_fiat_value: float # Current fiat value of total sats (in centavos)
average_cost_basis: float # Average sats per fiat unit
current_fiat_balance: int # Available balance for DCA (in centavos)
total_fiat_invested: float # Confirmed deposits in GTQ
pending_fiat_deposits: float # Pending deposits awaiting confirmation in GTQ
current_sats_fiat_value: float # Current fiat value of total sats in GTQ
average_cost_basis: float # Average sats per GTQ
current_fiat_balance: float # Available balance for DCA in GTQ
total_transactions: int
dca_mode: str # 'flow' or 'fixed'
dca_status: str # 'active' or 'inactive'
@ -54,10 +54,10 @@ class ClientDashboardSummary(BaseModel):
class ClientTransaction(BaseModel):
"""Internal model - client transaction stored in centavos"""
"""Internal model - client transaction stored in GTQ"""
id: str
amount_sats: int
amount_fiat: int # Stored in centavos (GTQ * 100) for precision
amount_fiat: float # Amount in GTQ (e.g., 150.75)
exchange_rate: float
transaction_type: str # 'flow', 'fixed', 'manual'
status: str

View file

@ -183,8 +183,8 @@ window.app = Vue.createApp({
// Dashboard Methods
formatCurrency(amount) {
if (!amount) return 'Q 0.00';
// Convert centavos to GTQ (divide by 100) for display
const gtqAmount = amount / 100;
// Amount is already in GTQ
const gtqAmount = amount;
return new Intl.NumberFormat('es-GT', {
style: 'currency',
currency: 'GTQ',
@ -193,8 +193,8 @@ window.app = Vue.createApp({
formatCurrencyWithCode(amount, currencyCode) {
if (!amount) return `${currencyCode} 0.00`;
// Convert centavos to currency units (divide by 100) for display
const currencyAmount = amount / 100;
// Amount is already in GTQ
const currencyAmount = amount;
try {
return new Intl.NumberFormat('en-US', {
style: 'currency',

View file

@ -199,7 +199,7 @@ async def api_export_transactions(
writer.writerow([
tx.created_at.isoformat(),
tx.amount_sats,
tx.amount_fiat / 100, # Convert centavos to GTQ for CSV export
tx.amount_fiat, # Amount already in GTQ
tx.exchange_rate,
tx.transaction_type,
tx.status