Surface user credit balance in GET /balance per libra-#41

Extends get_user_balance_bql and get_all_user_balances_bql to fold
Liabilities:Credit:User-X into the same query as Payable and Receivable.
Credit is the overpay-absorbing liability that libra owes the user going
forward — it carries the same sign as Payable, so the existing fiat
aggregation subtracts it from net obligation without further changes.

Adds UserBalance.account_balances to surface the BQL per-account
breakdown so libra extension UI and webapp can render Payable /
Receivable / Credit as distinct line items. The legacy `accounts` field
stays empty for back-compat with anything reading the older shape.

Prepares for libra-#33 / libra-#41: settlement netting (#14 task) will
write the overflow leg to credit; this changeset makes sure that, the
moment credit exists, the displayed net everywhere already reflects it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-07 11:56:35 +02:00
commit 50658440a4
3 changed files with 16 additions and 4 deletions

View file

@ -96,6 +96,11 @@ class UserBalance(BaseModel):
user_id: str
balance: int # positive = libra owes user, negative = user owes libra
accounts: list[Account] = []
# Per-account breakdown surfaced from get_user_balance_bql so UIs (libra
# extension dashboard + webapp) can render Payable / Receivable / Credit
# as distinct line items. Each entry: {"account": str, "sats": int,
# "eur": Decimal}. Wired up for libra-#41's display contract.
account_balances: list[dict] = []
fiat_balances: dict[str, Decimal] = {} # e.g. {"EUR": Decimal("250.0"), "USD": Decimal("100.0")}
# Lifetime totals (original entries only; not net of reconciliation)
total_expenses_sats: int = 0