""" Dual-currency dashboard figures. The AR Ledger shows every movement in the marketplace's local currency AND in USD, converted at each TRANSACTION DATE's exchange rate (a daily override when one exists, the marketplace month rate otherwise). The opening balance has no transaction date, so it converts at the month rate. Also the regression for the fx-daily endpoint: after payouts moved out of _daily_rows into _payout_events, fx_daily still unpacked 4-tuples and crashed on every session with data — the "Daily exchange rates" table never rendered. Fixture dates (make_amazon_xlsx, USA, month-end 2026-01-31, lag 2 → cutoff Jan 29): revenue: Jan 5 +1000 · Jan 10 +300 · Jan 15 +2000 · Jan 20 +80 · Jan 31 +500 payouts: Jan 6 −1000 (received) · Jan 12 −300 (received) · Jan 30 −2000 (in transit) → closing = 3880 − 1300 = 2580 """ from __future__ import annotations from fastapi.testclient import TestClient from app.api.main import app from app.db.database import init_db from tests.test_payout_receipts import _fresh def test_fx_daily_no_longer_crashes_and_covers_payout_dates(): init_db() with TestClient(app) as c: sid = _fresh(c, "fx daily regression") r = c.get(f"/api/sessions/{sid}/fx-daily") assert r.status_code == 200 data = r.json() assert data["available"] is True by_date = {row["date"]: row for row in data["rows"]} # Revenue sits on its transaction date… assert by_date["2026-01-15"]["revenue"] == 2000.0 # …and payouts on their effective date, in the same table. assert by_date["2026-01-06"]["payouts"] == -1000.0 assert by_date["2026-01-30"]["payouts"] == -2000.0 # USA converts 1:1 — USD total equals local total = 3880 − 3300 net movement. assert data["month_rate"] == 1.0 assert data["total_local"] == 580.0 assert data["total_usd"] == data["total_local"] def test_ledger_detail_shows_usd_at_transaction_date_rates(): init_db() with TestClient(app) as c: sid = _fresh(c, "dual currency ledger") # Daily override for the big revenue day; every other date uses the month rate. assert c.put(f"/api/sessions/{sid}/fx-daily", json=[ {"marketplace": "USA", "rate_date": "2026-01-15", "rate": 1.25}, ]).status_code == 200 d = c.get(f"/api/sessions/{sid}/ledger-detail").json() per = {p["key"]: p for p in d["periods"]} # Jan 15's revenue converts at ITS OWN day's rate… assert per["2026-01-15"]["revenue"] == 2000.0 assert per["2026-01-15"]["revenue_usd"] == 2500.0 # …every other date at the month rate (1.0 for USA). assert per["2026-01-05"]["revenue_usd"] == per["2026-01-05"]["revenue"] == 1000.0 assert per["2026-01-06"]["payouts_received_usd"] == -1000.0 assert per["2026-01-30"]["payouts_in_transit_usd"] == -2000.0 # Opening has no transaction date → month rate; the USD running balance then # absorbs the daily-rate spread: closing_usd = closing + 2000 × (1.25 − 1). assert d["month_rate"] == 1.0 assert d["opening_usd"] == 0.0 assert d["closing"] == 2580.0 assert d["closing_usd"] == 3080.0 assert d["in_transit_total_usd"] == -2000.0 # The local-currency figures are untouched by the daily override. assert per["2026-01-15"]["balance"] == per["2026-01-15"]["balance_usd"] - 500.0 def test_weekend_transactions_use_the_previous_banking_days_fixing(): """2026-01-10 is a Saturday — no fixing is published. The rate effective on it is the previous banking day's PROVIDER fixing (Friday the 9th), not the month rate. Manual rates never carry forward: they are deliberate single-date overrides (which is also why the test above sees the month rate everywhere but Jan 15).""" init_db() with TestClient(app) as c: sid = _fresh(c, "weekend carry forward") assert c.put(f"/api/sessions/{sid}/fx-daily", json=[ {"marketplace": "USA", "rate_date": "2026-01-09", "rate": 1.5, "source": "frankfurter"}, ]).status_code == 200 d = c.get(f"/api/sessions/{sid}/ledger-detail").json() per = {p["key"]: p for p in d["periods"]} # Saturday's revenue converts at Friday's fixing: 300 × 1.5. assert per["2026-01-10"]["revenue_usd"] == 450.0 fxd = c.get(f"/api/sessions/{sid}/fx-daily").json() by_date = {r["date"]: r for r in fxd["rows"]} assert by_date["2026-01-10"]["rate"] == 1.5 assert "2026-01-09" in by_date["2026-01-10"]["source"] # carry-forward disclosed # Dates before the first fixing still fall back to the month rate. assert by_date["2026-01-05"]["rate"] == 1.0 assert by_date["2026-01-05"]["source"] == "month rate"