castle/helper
padreug 4b327a0aab Extends account lookup for user accounts
Implements account lookup logic for user-specific accounts,
specifically Liabilities:Payable and Assets:Receivable.

This allows the system to automatically map Beancount accounts
to corresponding accounts in the Castle system based on user ID.

Improves error messages when user accounts are not properly configured.
2025-11-08 23:51:07 +01:00
..
btc_eur_rates.csv Adds Beancount import helper script 2025-11-08 23:18:42 +01:00
import_beancount.py Extends account lookup for user accounts 2025-11-08 23:51:07 +01:00
README.md Adds Beancount import helper script 2025-11-08 23:18:42 +01:00

Castle Beancount Import Helper

Import Beancount ledger transactions into Castle accounting extension.

📁 Files

  • import_beancount.py - Main import script
  • btc_eur_rates.csv - Daily BTC/EUR rates (create your own)
  • README.md - This file

🚀 Setup

1. Create BTC/EUR Rates CSV

Create btc_eur_rates.csv in this directory with your actual rates:

date,btc_eur_rate
2025-07-01,86500
2025-07-02,87200
2025-07-03,87450

2. Update User Mappings

Edit import_beancount.py and update the USER_MAPPINGS dictionary:

USER_MAPPINGS = {
    "Pat": "actual_wallet_id_for_pat",
    "Alice": "actual_wallet_id_for_alice",
    "Bob": "actual_wallet_id_for_bob",
}

How to get wallet IDs:

  • Check your LNbits admin panel
  • Or query: curl -X GET http://localhost:5000/api/v1/wallet -H "X-Api-Key: user_invoice_key"

3. Set API Key

export CASTLE_ADMIN_KEY="your_lnbits_admin_invoice_key"
export LNBITS_URL="http://localhost:5000"  # Optional

📖 Usage

cd /path/to/castle/helper

# Test with dry run
python import_beancount.py ledger.beancount --dry-run

# Actually import
python import_beancount.py ledger.beancount

📄 Beancount File Format

Your Beancount transactions must have an Equity:<name> account:

2025-07-06 * "Foix market"
  Expenses:Groceries              69.40 EUR
  Equity:Pat

2025-07-07 * "Gas station"
  Expenses:Transport              45.00 EUR
  Equity:Alice

Requirements:

  • Every transaction must have an Equity:<name> account
  • Account names must match exactly what's in Castle
  • The name after Equity: must be in USER_MAPPINGS

🔄 How It Works

  1. Loads rates from btc_eur_rates.csv
  2. Loads accounts from Castle API automatically
  3. Maps users - Extracts user name from Equity:Name accounts
  4. Parses Beancount transactions
  5. Converts EUR → sats using daily rate
  6. Uploads to Castle with metadata

📊 Example Output

$ python import_beancount.py ledger.beancount
======================================================================
🏰 Beancount to Castle Import Script
======================================================================

📊 Loaded 15 daily rates from btc_eur_rates.csv
   Date range: 2025-07-01 to 2025-07-15

🏦 Loaded 28 accounts from Castle

👥 User ID mappings:
   - Pat → wallet_abc123
   - Alice → wallet_def456
   - Bob → wallet_ghi789

📄 Found 25 potential transactions in ledger.beancount

✅ Transaction 1: 2025-07-06 - Foix market (User: Pat) (Rate: 87,891 EUR/BTC)
✅ Transaction 2: 2025-07-07 - Gas station (User: Alice) (Rate: 88,100 EUR/BTC)
✅ Transaction 3: 2025-07-08 - Restaurant (User: Bob) (Rate: 88,350 EUR/BTC)

======================================================================
📊 Summary: 25 succeeded, 0 failed, 0 skipped
======================================================================

✅ Successfully imported 25 transactions to Castle!

Troubleshooting

"No account found in Castle"

Error: No account found in Castle with name 'Expenses:XYZ'

Solution: Create the account in Castle first with that exact name.

"No user ID mapping found"

Error: No user ID mapping found for 'Pat'

Solution: Add Pat to the USER_MAPPINGS dictionary in the script.

"No BTC/EUR rate found"

Error: No BTC/EUR rate found for 2025-07-15

Solution: Add that date to btc_eur_rates.csv.

"Could not determine user ID"

Error: Could not determine user ID for transaction

Solution: Every transaction needs an Equity:<name> account (e.g., Equity:Pat).

📝 Transaction Metadata

Each imported transaction includes:

{
  "meta": {
    "source": "beancount_import",
    "imported_at": "2025-11-08T12:00:00",
    "btc_eur_rate": 87891.0,
    "user_id": "wallet_abc123"
  }
}

And each line includes:

{
  "metadata": {
    "fiat_currency": "EUR",
    "fiat_amount": "69.400",
    "fiat_rate": 1137.88,
    "btc_rate": 87891.0
  }
}

This preserves the original EUR amount and exchange rate for auditing.