Rename Castle Accounting extension to Libra

Full identifier rename: module path lnbits.extensions.castle →
lnbits.extensions.libra, DB ext_castle → ext_libra, URL prefix
/castle/ → /libra/, manifest id castle → libra, fava ledger slug
default castle-ledger → libra-ledger, Beancount source metadata
castle-api → libra-api and link prefixes castle-{entry,tx}- →
libra-{entry,tx}-, column castle_wallet_id → libra_wallet_id, all
Python/JS/HTML identifiers (castle_ext, CastleSettings,
castle_reference, castleWalletConfigured, etc.).

Display name "Castle Accounting" → "Libra" (the scales/balance
metaphor — fits double-entry bookkeeping).

No backward compat: production hosts will be force-updated. Old
castle-prefixed Beancount metadata in existing Fava ledgers is
historical; new entries use libra-* prefixes going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-05 10:24:46 +02:00
commit c174cda48d
44 changed files with 953 additions and 953 deletions

View file

@ -1,8 +1,8 @@
"""
Format Castle entries as Beancount transactions for Fava API.
Format Libra entries as Beancount transactions for Fava API.
All entries submitted to Fava must follow Beancount syntax.
This module converts Castle data models to Fava API format.
This module converts Libra data models to Fava API format.
Key concepts:
- Amounts are strings: "200000 SATS" or "100.00 EUR"
@ -35,8 +35,8 @@ def sanitize_link(text: str) -> str:
'Test-pending'
>>> sanitize_link("Invoice #123")
'Invoice-123'
>>> sanitize_link("castle-abc123")
'castle-abc123'
>>> sanitize_link("libra-abc123")
'libra-abc123'
"""
# Replace any character that's not alphanumeric, dash, underscore, slash, or period with a hyphen
sanitized = re.sub(r'[^A-Za-z0-9\-_/.]', '-', text)
@ -67,7 +67,7 @@ def format_transaction(
postings: List of posting dicts (formatted by format_posting)
payee: Optional payee
tags: Optional tags (e.g., ["expense-entry", "approved"])
links: Optional links (e.g., ["castle-abc123", "^invoice-xyz"])
links: Optional links (e.g., ["libra-abc123", "^invoice-xyz"])
meta: Optional transaction metadata
Returns:
@ -93,8 +93,8 @@ def format_transaction(
)
],
tags=["expense-entry"],
links=["castle-abc123"],
meta={"user-id": "abc123", "source": "castle-expense-entry"}
links=["libra-abc123"],
meta={"user-id": "abc123", "source": "libra-expense-entry"}
)
"""
return {
@ -150,7 +150,7 @@ def format_posting_with_cost(
"""
Format a posting with cost basis for Fava API.
This is the RECOMMENDED format for all Castle transactions.
This is the RECOMMENDED format for all Libra transactions.
Uses Beancount's cost basis syntax to preserve exchange rates.
IMPORTANT: Beancount cost syntax uses PER-UNIT cost, not total cost.
@ -381,7 +381,7 @@ def format_expense_entry(
# Build entry metadata
entry_meta = {
"user-id": user_id,
"source": "castle-api",
"source": "libra-api",
"entry-id": entry_id
}
@ -419,7 +419,7 @@ def format_receivable_entry(
entry_id: Optional[str] = None
) -> Dict[str, Any]:
"""
Format a receivable entry (user owes castle).
Format a receivable entry (user owes libra).
Uses price notation (@@ SATS) for BQL-queryable SATS tracking.
Generates unique receivable link (^rcv-{entry_id}) for settlement tracking.
@ -466,7 +466,7 @@ def format_receivable_entry(
entry_meta = {
"user-id": user_id,
"source": "castle-api",
"source": "libra-api",
"entry-id": entry_id
}
@ -512,7 +512,7 @@ def format_payment_entry(
amount_sats: Amount in satoshis (unsigned)
description: Payment description
entry_date: Date of payment
is_payable: True if castle paying user (payable), False if user paying castle (receivable)
is_payable: True if libra paying user (payable), False if user paying libra (receivable)
fiat_currency: Optional fiat currency
fiat_amount: Optional fiat amount (unsigned)
payment_hash: Lightning payment hash
@ -531,7 +531,7 @@ def format_payment_entry(
# Example: 908.44 EUR / 996896 SATS = 0.000911268 EUR/SAT (matches original receivable rate)
if fiat_currency and fiat_amount_abs and amount_sats_abs > 0:
if is_payable:
# Castle paying user: DR Payable, CR Lightning
# Libra paying user: DR Payable, CR Lightning
postings = [
format_posting_with_cost(
account=payable_or_receivable_account,
@ -546,7 +546,7 @@ def format_payment_entry(
)
]
else:
# User paying castle: DR Lightning, CR Receivable
# User paying libra: DR Lightning, CR Receivable
postings = [
format_posting_simple(
account=payment_account,
@ -633,7 +633,7 @@ def format_fiat_settlement_entry(
amount_sats: Equivalent amount in satoshis
description: Payment description
entry_date: Date of settlement
is_payable: True if castle paying user (payable), False if user paying castle (receivable)
is_payable: True if libra paying user (payable), False if user paying libra (receivable)
payment_method: Payment method (cash, bank_transfer, check, etc.)
reference: Optional reference
settled_entry_links: List of expense/receivable links being settled (e.g., ["exp-abc123", "exp-def456"])
@ -646,7 +646,7 @@ def format_fiat_settlement_entry(
# Build postings using price notation (@@ SATS) for BQL queryability
if is_payable:
# Castle paying user: DR Payable, CR Cash/Bank
# Libra paying user: DR Payable, CR Cash/Bank
postings = [
{
"account": payable_or_receivable_account,
@ -658,7 +658,7 @@ def format_fiat_settlement_entry(
}
]
else:
# User paying castle: DR Cash/Bank, CR Receivable
# User paying libra: DR Cash/Bank, CR Receivable
postings = [
{
"account": payment_account,
@ -815,7 +815,7 @@ def format_revenue_entry(
reference: Optional[str] = None
) -> Dict[str, Any]:
"""
Format a revenue entry (castle receives payment directly).
Format a revenue entry (libra receives payment directly).
Creates a cleared transaction (flag="*") since payment was received.
@ -869,7 +869,7 @@ def format_revenue_entry(
# Note: created-via is redundant with #revenue-entry tag
entry_meta = {
"source": "castle-api"
"source": "libra-api"
}
links = []