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.
This commit is contained in:
parent
8c3faeec3f
commit
8d442b7c6f
5 changed files with 16 additions and 69 deletions
4
crud.py
4
crud.py
|
|
@ -103,7 +103,7 @@ async def get_client_dashboard_summary(user_id: str) -> Optional[ClientDashboard
|
||||||
# Calculate metrics
|
# Calculate metrics
|
||||||
total_invested = confirmed_deposits # Total invested = all confirmed deposits
|
total_invested = confirmed_deposits # Total invested = all confirmed deposits
|
||||||
remaining_balance = confirmed_deposits - dca_spent # Remaining = deposits - DCA spending
|
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
|
# Calculate current fiat value of total sats
|
||||||
current_sats_fiat_value = 0.0
|
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
|
# Build cost basis history
|
||||||
cost_basis_history = []
|
cost_basis_history = []
|
||||||
for record in cost_basis_data:
|
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))
|
# Use transaction_date (which is COALESCE(transaction_time, created_at))
|
||||||
date_to_use = record["transaction_date"]
|
date_to_use = record["transaction_date"]
|
||||||
if date_to_use is None:
|
if date_to_use is None:
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
18
models.py
18
models.py
|
|
@ -36,16 +36,16 @@ class ClientTransactionAPI(BaseModel):
|
||||||
lamassu_transaction_id: Optional[str] = None
|
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):
|
class ClientDashboardSummary(BaseModel):
|
||||||
"""Internal model - client dashboard summary stored in centavos"""
|
"""Internal model - client dashboard summary stored in GTQ"""
|
||||||
user_id: str
|
user_id: str
|
||||||
total_sats_accumulated: int
|
total_sats_accumulated: int
|
||||||
total_fiat_invested: int # Confirmed deposits (in centavos)
|
total_fiat_invested: float # Confirmed deposits in GTQ
|
||||||
pending_fiat_deposits: int # Pending deposits awaiting confirmation (in centavos)
|
pending_fiat_deposits: float # Pending deposits awaiting confirmation in GTQ
|
||||||
current_sats_fiat_value: float # Current fiat value of total sats (in centavos)
|
current_sats_fiat_value: float # Current fiat value of total sats in GTQ
|
||||||
average_cost_basis: float # Average sats per fiat unit
|
average_cost_basis: float # Average sats per GTQ
|
||||||
current_fiat_balance: int # Available balance for DCA (in centavos)
|
current_fiat_balance: float # Available balance for DCA in GTQ
|
||||||
total_transactions: int
|
total_transactions: int
|
||||||
dca_mode: str # 'flow' or 'fixed'
|
dca_mode: str # 'flow' or 'fixed'
|
||||||
dca_status: str # 'active' or 'inactive'
|
dca_status: str # 'active' or 'inactive'
|
||||||
|
|
@ -54,10 +54,10 @@ class ClientDashboardSummary(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class ClientTransaction(BaseModel):
|
class ClientTransaction(BaseModel):
|
||||||
"""Internal model - client transaction stored in centavos"""
|
"""Internal model - client transaction stored in GTQ"""
|
||||||
id: str
|
id: str
|
||||||
amount_sats: int
|
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
|
exchange_rate: float
|
||||||
transaction_type: str # 'flow', 'fixed', 'manual'
|
transaction_type: str # 'flow', 'fixed', 'manual'
|
||||||
status: str
|
status: str
|
||||||
|
|
|
||||||
|
|
@ -183,8 +183,8 @@ window.app = Vue.createApp({
|
||||||
// Dashboard Methods
|
// Dashboard Methods
|
||||||
formatCurrency(amount) {
|
formatCurrency(amount) {
|
||||||
if (!amount) return 'Q 0.00';
|
if (!amount) return 'Q 0.00';
|
||||||
// Convert centavos to GTQ (divide by 100) for display
|
// Amount is already in GTQ
|
||||||
const gtqAmount = amount / 100;
|
const gtqAmount = amount;
|
||||||
return new Intl.NumberFormat('es-GT', {
|
return new Intl.NumberFormat('es-GT', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
currency: 'GTQ',
|
currency: 'GTQ',
|
||||||
|
|
@ -193,8 +193,8 @@ window.app = Vue.createApp({
|
||||||
|
|
||||||
formatCurrencyWithCode(amount, currencyCode) {
|
formatCurrencyWithCode(amount, currencyCode) {
|
||||||
if (!amount) return `${currencyCode} 0.00`;
|
if (!amount) return `${currencyCode} 0.00`;
|
||||||
// Convert centavos to currency units (divide by 100) for display
|
// Amount is already in GTQ
|
||||||
const currencyAmount = amount / 100;
|
const currencyAmount = amount;
|
||||||
try {
|
try {
|
||||||
return new Intl.NumberFormat('en-US', {
|
return new Intl.NumberFormat('en-US', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ async def api_export_transactions(
|
||||||
writer.writerow([
|
writer.writerow([
|
||||||
tx.created_at.isoformat(),
|
tx.created_at.isoformat(),
|
||||||
tx.amount_sats,
|
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.exchange_rate,
|
||||||
tx.transaction_type,
|
tx.transaction_type,
|
||||||
tx.status
|
tx.status
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue