Creates accounts in Fava if they don't exist
This change ensures that user-specific accounts are automatically created in the Fava/Beancount ledger when they are first requested. It checks for the existence of the account via a Fava query and creates it via an Open directive if it's missing. This simplifies account management and ensures that all necessary accounts are available for transactions. This implementation adds a new `add_account` method to the `FavaClient` class which makes use of the /add_entries endpoint to create an account using an Open Directive.
This commit is contained in:
parent
51ae2e8e47
commit
b6886793ee
2 changed files with 113 additions and 2 deletions
46
crud.py
46
crud.py
|
|
@ -2,6 +2,7 @@ import json
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
from lnbits.db import Database
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
|
|
@ -96,6 +97,10 @@ async def get_or_create_user_account(
|
|||
"""
|
||||
Get or create a user-specific account with hierarchical naming.
|
||||
|
||||
This function checks if the account exists in Fava/Beancount and creates it
|
||||
if it doesn't exist. The account is also registered in Castle's database for
|
||||
metadata tracking (permissions, descriptions, etc.).
|
||||
|
||||
Examples:
|
||||
get_or_create_user_account("af983632", AccountType.ASSET, "Accounts Receivable")
|
||||
→ "Assets:Receivable:User-af983632"
|
||||
|
|
@ -104,11 +109,13 @@ async def get_or_create_user_account(
|
|||
→ "Liabilities:Payable:User-af983632"
|
||||
"""
|
||||
from .account_utils import format_hierarchical_account_name
|
||||
from .fava_client import get_fava_client
|
||||
from loguru import logger
|
||||
|
||||
# Generate hierarchical account name
|
||||
account_name = format_hierarchical_account_name(account_type, base_name, user_id)
|
||||
|
||||
# Try to find existing account with this hierarchical name
|
||||
# Try to find existing account with this hierarchical name in Castle DB
|
||||
account = await db.fetchone(
|
||||
"""
|
||||
SELECT * FROM accounts
|
||||
|
|
@ -119,7 +126,42 @@ async def get_or_create_user_account(
|
|||
)
|
||||
|
||||
if not account:
|
||||
# Create new account with hierarchical name
|
||||
# Check if account exists in Fava/Beancount
|
||||
fava = get_fava_client()
|
||||
try:
|
||||
# Query Fava for this account
|
||||
query = f"SELECT account WHERE account = '{account_name}'"
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
response = await client.get(
|
||||
f"{fava.base_url}/query",
|
||||
params={"query_string": query}
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Check if account exists in Fava
|
||||
fava_has_account = len(result.get("data", {}).get("rows", [])) > 0
|
||||
|
||||
if not fava_has_account:
|
||||
# Create account in Fava/Beancount via Open directive
|
||||
logger.info(f"Creating account in Fava: {account_name}")
|
||||
await fava.add_account(
|
||||
account_name=account_name,
|
||||
currencies=["EUR", "SATS", "USD"], # Support common currencies
|
||||
metadata={
|
||||
"user_id": user_id,
|
||||
"description": f"User-specific {account_type.value} account"
|
||||
}
|
||||
)
|
||||
logger.info(f"Created account in Fava: {account_name}")
|
||||
else:
|
||||
logger.info(f"Account already exists in Fava: {account_name}")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not check/create account in Fava: {e}")
|
||||
# Continue anyway - account creation in Castle DB is still useful for metadata
|
||||
|
||||
# Create account in Castle DB for metadata tracking
|
||||
account = await create_account(
|
||||
CreateAccount(
|
||||
name=account_name,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue