mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-05-19 10:28:48 +02:00
Convert all currencies to CRC and poll rates every 6h
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
Budget/transactions/salarios totals summed Transaction.amount directly,
so USD/EUR entries were treated as CRC and effectively disappeared from
the dashboard (the analytics fix in 9a80f2a only covered analytics).
Adds a shared get_converted_amount_expr() helper driven by the full
Currency enum — USD/EUR via ExchangeRate-API, BTC/XMR via CoinGecko —
and wires it into every func.sum(Transaction.amount) site.
Also starts a background task in the FastAPI lifespan that force-refreshes
every currency 4x/day, persisting USD to the DB and updating in-memory
caches for the rest. Failures are swallowed per-currency so a CoinGecko
outage cannot take out USD/EUR, and the last-known rate is always retained.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +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
|
||||
from app.services.exchange_rate import get_converted_amount_expr
|
||||
|
||||
router = APIRouter(prefix="/analytics", tags=["analytics"])
|
||||
|
||||
@@ -38,17 +38,6 @@ 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,
|
||||
@@ -56,18 +45,12 @@ def spending_by_category(
|
||||
session: Session = Depends(get_session),
|
||||
_user: str = Depends(get_current_user),
|
||||
):
|
||||
rates = _get_crc_multipliers(session)
|
||||
amount_crc = get_converted_amount_expr(session)
|
||||
|
||||
query = (
|
||||
select(
|
||||
Transaction.category_id,
|
||||
func.sum(
|
||||
case(
|
||||
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
|
||||
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
|
||||
else_=Transaction.amount,
|
||||
)
|
||||
).label("total"),
|
||||
func.sum(amount_crc).label("total"),
|
||||
func.count().label("count"),
|
||||
)
|
||||
.where(Transaction.transaction_type == "COMPRA")
|
||||
@@ -113,7 +96,7 @@ def monthly_trend(
|
||||
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)
|
||||
amount_crc = get_converted_amount_expr(session)
|
||||
now = datetime.now()
|
||||
results = []
|
||||
month_names = [
|
||||
@@ -128,16 +111,7 @@ def monthly_trend(
|
||||
row = session.exec(
|
||||
select(
|
||||
func.count(),
|
||||
func.coalesce(
|
||||
func.sum(
|
||||
case(
|
||||
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
|
||||
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
|
||||
else_=Transaction.amount,
|
||||
)
|
||||
),
|
||||
0,
|
||||
),
|
||||
func.coalesce(func.sum(amount_crc), 0),
|
||||
func.coalesce(
|
||||
func.sum(
|
||||
case(
|
||||
@@ -189,18 +163,12 @@ def daily_spending(
|
||||
session: Session = Depends(get_session),
|
||||
_user: str = Depends(get_current_user),
|
||||
):
|
||||
rates = _get_crc_multipliers(session)
|
||||
amount_crc = get_converted_amount_expr(session)
|
||||
|
||||
query = (
|
||||
select(
|
||||
func.date(Transaction.date).label("day"),
|
||||
func.sum(
|
||||
case(
|
||||
(Transaction.currency == "USD", Transaction.amount * rates["USD"]),
|
||||
(Transaction.currency == "EUR", Transaction.amount * rates["EUR"]),
|
||||
else_=Transaction.amount,
|
||||
)
|
||||
).label("total"),
|
||||
func.sum(amount_crc).label("total"),
|
||||
func.count().label("count"),
|
||||
)
|
||||
.where(Transaction.transaction_type == "COMPRA")
|
||||
|
||||
Reference in New Issue
Block a user