Update get_account_balance to use sum(weight) for SATS
Replace sum(position) with sum(weight) for efficient SATS aggregation from price notation. Also return fiat amount from sum(number). This simplifies the parsing logic and provides consistent SATS totals across all BQL-based balance methods. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
048d19f90b
commit
49d18c3e73
2 changed files with 27 additions and 22 deletions
|
|
@ -111,13 +111,16 @@ class FavaClient:
|
||||||
"""
|
"""
|
||||||
Get balance for a specific account (excluding pending transactions).
|
Get balance for a specific account (excluding pending transactions).
|
||||||
|
|
||||||
|
Uses sum(weight) for efficient SATS aggregation from price notation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
account_name: Full account name (e.g., "Assets:Receivable:User-abc123")
|
account_name: Full account name (e.g., "Assets:Receivable:User-abc123")
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict with:
|
Dict with:
|
||||||
- sats: int (balance in satoshis)
|
- sats: int (balance in satoshis from weight column)
|
||||||
- positions: dict (currency → amount with cost basis)
|
- fiat: Decimal (balance in fiat currency from number column)
|
||||||
|
- fiat_currency: str (currency code, defaults to EUR)
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
Excludes pending transactions (flag='!') from balance calculation.
|
Excludes pending transactions (flag='!') from balance calculation.
|
||||||
|
|
@ -125,12 +128,13 @@ class FavaClient:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
balance = await fava_client.get_account_balance("Assets:Receivable:User-abc")
|
balance = await fava_client.get_account_balance("Assets:Receivable:User-abc")
|
||||||
# Returns: {
|
# Returns: {"sats": 200000, "fiat": Decimal("150.00"), "fiat_currency": "EUR"}
|
||||||
# "sats": 200000,
|
|
||||||
# "positions": {"SATS": {"{100.00 EUR}": 200000}}
|
|
||||||
# }
|
|
||||||
"""
|
"""
|
||||||
query = f"SELECT sum(position) WHERE account = '{account_name}' AND flag != '!'"
|
from decimal import Decimal
|
||||||
|
|
||||||
|
# Use sum(weight) for SATS and sum(number) for fiat
|
||||||
|
# Note: BQL doesn't support != operator, so use flag = '*' to exclude pending
|
||||||
|
query = f"SELECT sum(number), sum(weight) WHERE account = '{account_name}' AND flag = '*'"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
||||||
|
|
@ -141,26 +145,26 @@ class FavaClient:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
if not data['data']['rows']:
|
if not data['data']['rows'] or not data['data']['rows'][0]:
|
||||||
return {"sats": 0, "positions": {}}
|
return {"sats": 0, "fiat": Decimal(0), "fiat_currency": "EUR"}
|
||||||
|
|
||||||
# Fava returns: [[account, {"SATS": {cost: amount}}]]
|
row = data['data']['rows'][0]
|
||||||
positions = data['data']['rows'][0][1] if data['data']['rows'] else {}
|
fiat_sum = row[0] if len(row) > 0 else 0
|
||||||
|
weight_sum = row[1] if len(row) > 1 else {}
|
||||||
|
|
||||||
# Sum up all SATS positions
|
# Parse fiat amount
|
||||||
|
fiat_amount = Decimal(str(fiat_sum)) if fiat_sum else Decimal(0)
|
||||||
|
|
||||||
|
# Parse SATS from weight column
|
||||||
total_sats = 0
|
total_sats = 0
|
||||||
if isinstance(positions, dict) and "SATS" in positions:
|
if isinstance(weight_sum, dict) and "SATS" in weight_sum:
|
||||||
sats_positions = positions["SATS"]
|
sats_value = weight_sum["SATS"]
|
||||||
if isinstance(sats_positions, dict):
|
total_sats = int(Decimal(str(sats_value)))
|
||||||
# Sum all amounts (with different cost bases)
|
|
||||||
total_sats = sum(int(amount) for amount in sats_positions.values())
|
|
||||||
elif isinstance(sats_positions, (int, float)):
|
|
||||||
# Simple number (no cost basis)
|
|
||||||
total_sats = int(sats_positions)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"sats": total_sats,
|
"sats": total_sats,
|
||||||
"positions": positions
|
"fiat": fiat_amount,
|
||||||
|
"fiat_currency": "EUR" # Default, could be extended to detect currency
|
||||||
}
|
}
|
||||||
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,8 @@ async def api_get_account_balance(account_id: str) -> dict:
|
||||||
return {
|
return {
|
||||||
"account_id": account_id,
|
"account_id": account_id,
|
||||||
"balance": balance_data["sats"], # Balance in satoshis
|
"balance": balance_data["sats"], # Balance in satoshis
|
||||||
"positions": balance_data["positions"] # Full Beancount positions with cost basis
|
"fiat": float(balance_data.get("fiat", 0)), # Fiat amount
|
||||||
|
"fiat_currency": balance_data.get("fiat_currency", "EUR")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue