Convert USD and EUR to CRC in analytics endpoints
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s

All three analytics endpoints (by-category, monthly-trend, daily-spending)
now convert foreign currency amounts to CRC using current exchange rates.
EUR/CRC rate derived from ExchangeRate-API (USD-based cross rate).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-04-07 20:41:38 -06:00
parent efe6d88286
commit 9a80f2a997
2 changed files with 82 additions and 5 deletions

View File

@@ -10,6 +10,7 @@ from app.auth import get_current_user
from app.db import get_session
from app.models.models import Category, Transaction
from app.services.budget_projection import get_cycle_range
from app.services.exchange_rate import get_current_rate, get_eur_crc_rate
router = APIRouter(prefix="/analytics", tags=["analytics"])
@@ -37,6 +38,17 @@ class DailySpending(BaseModel):
count: int
def _get_crc_multipliers(session: Session) -> dict[str, float]:
"""Return multipliers to convert each currency to CRC."""
usd_rate = get_current_rate(session)
eur_rate = get_eur_crc_rate()
return {
"CRC": 1.0,
"USD": usd_rate.sell_rate if usd_rate else 0.0,
"EUR": eur_rate if eur_rate else 0.0,
}
@router.get("/by-category", response_model=list[CategorySpending])
def spending_by_category(
cycle_year: Optional[int] = None,
@@ -44,10 +56,18 @@ def spending_by_category(
session: Session = Depends(get_session),
_user: str = Depends(get_current_user),
):
rates = _get_crc_multipliers(session)
query = (
select(
Transaction.category_id,
func.sum(Transaction.amount).label("total"),
func.sum(
case(
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
else_=Transaction.amount,
)
).label("total"),
func.count().label("count"),
)
.where(Transaction.transaction_type == "COMPRA")
@@ -88,7 +108,12 @@ def monthly_trend(
session: Session = Depends(get_session),
_user: str = Depends(get_current_user),
):
"""Monthly spending totals using billing cycle boundaries (18th-18th)."""
"""Monthly spending totals using billing cycle boundaries (18th-18th).
total_crc includes all currencies converted to CRC at current rates.
total_usd is the raw USD amount (unconverted) for display purposes.
"""
rates = _get_crc_multipliers(session)
now = datetime.now()
results = []
month_names = [
@@ -106,8 +131,9 @@ def monthly_trend(
func.coalesce(
func.sum(
case(
(Transaction.currency == "CRC", Transaction.amount),
else_=0,
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
else_=Transaction.amount,
)
),
0,
@@ -163,10 +189,18 @@ def daily_spending(
session: Session = Depends(get_session),
_user: str = Depends(get_current_user),
):
rates = _get_crc_multipliers(session)
query = (
select(
func.date(Transaction.date).label("day"),
func.sum(Transaction.amount).label("total"),
func.sum(
case(
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
else_=Transaction.amount,
)
).label("total"),
func.count().label("count"),
)
.where(Transaction.transaction_type == "COMPRA")