1
0
Fork 0
forked from aiolabs/libra

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

@ -21,13 +21,13 @@ Phase 3 of the Beancount-inspired refactor focused on **separating business logi
- Easier to audit and verify
- Clear architecture
### 2. CastleInventory for Position Tracking ✅
### 2. LibraInventory for Position Tracking ✅
**Purpose**: Track balances across multiple currencies with cost basis information (following Beancount's Inventory pattern)
**Implementation** (`core/inventory.py`):
**CastlePosition** (Lines 11-84):
**LibraPosition** (Lines 11-84):
- Immutable dataclass representing a single position
- Tracks currency, amount, cost basis, and metadata
- Supports addition and negation operations
@ -35,7 +35,7 @@ Phase 3 of the Beancount-inspired refactor focused on **separating business logi
```python
@dataclass(frozen=True)
class CastlePosition:
class LibraPosition:
currency: str # "SATS", "EUR", "USD"
amount: Decimal
cost_currency: Optional[str] = None
@ -44,7 +44,7 @@ class CastlePosition:
metadata: Dict[str, Any] = field(default_factory=dict)
```
**CastleInventory** (Lines 87-201):
**LibraInventory** (Lines 87-201):
- Container for multiple positions
- Positions keyed by `(currency, cost_currency)` tuple
- Methods for querying balances:
@ -83,7 +83,7 @@ class AccountType(str, Enum):
- Liabilities/Equity/Revenue: Credit balance (credit - debit)
2. **`build_inventory_from_entry_lines()`** (Lines 56-117):
- Build CastleInventory from journal entry lines
- Build LibraInventory from journal entry lines
- Handles both sats and fiat currency tracking
- Accounts for account type when determining sign
@ -123,7 +123,7 @@ class AccountType(str, Enum):
- Checks both sats and fiat within tolerance
3. **`validate_receivable_entry()`** (Lines 180-199):
- Validates receivable (user owes castle) entries
- Validates receivable (user owes libra) entries
- Ensures positive amount
- Ensures revenue account type
@ -216,10 +216,10 @@ views_api.py → crud.py → core/
## File Structure
```
lnbits/extensions/castle/
lnbits/extensions/libra/
├── core/
│ ├── __init__.py # Module exports
│ ├── inventory.py # CastleInventory, CastlePosition
│ ├── inventory.py # LibraInventory, LibraPosition
│ ├── balance.py # BalanceCalculator
│ └── validation.py # Validation functions
├── crud.py # DB operations (refactored to use core/)
@ -230,22 +230,22 @@ lnbits/extensions/castle/
## Usage Examples
### Using CastleInventory
### Using LibraInventory
```python
from decimal import Decimal
from castle.core.inventory import CastleInventory, CastlePosition
from libra.core.inventory import LibraInventory, LibraPosition
# Create inventory
inv = CastleInventory()
inv = LibraInventory()
# Add positions
inv.add_position(CastlePosition(
inv.add_position(LibraPosition(
currency="SATS",
amount=Decimal("100000")
))
inv.add_position(CastlePosition(
inv.add_position(LibraPosition(
currency="SATS",
amount=Decimal("50000"),
cost_currency="EUR",
@ -264,7 +264,7 @@ data = inv.to_dict()
### Using BalanceCalculator
```python
from castle.core.balance import BalanceCalculator, AccountType
from libra.core.balance import BalanceCalculator, AccountType
# Calculate account balance
balance = BalanceCalculator.calculate_account_balance(
@ -297,7 +297,7 @@ is_valid = BalanceCalculator.check_balance_matches(
### Using Validation
```python
from castle.core.validation import validate_journal_entry, ValidationError
from libra.core.validation import validate_journal_entry, ValidationError
entry = {
"id": "abc123",
@ -320,8 +320,8 @@ except ValidationError as e:
## Testing Checklist
- [x] CastleInventory created and tested
- [x] CastlePosition addition works
- [x] LibraInventory created and tested
- [x] LibraPosition addition works
- [x] Inventory balance calculations work
- [x] BalanceCalculator account balance calculation works
- [x] BalanceCalculator inventory building works
@ -348,10 +348,10 @@ except ValidationError as e:
## Conclusion
Phase 3 successfully refactors Castle's accounting logic into a clean, testable core module. By following Beancount's architecture patterns, we've created:
Phase 3 successfully refactors Libra's accounting logic into a clean, testable core module. By following Beancount's architecture patterns, we've created:
- **Pure accounting logic** separated from database concerns
- **CastleInventory** for position tracking across currencies
- **LibraInventory** for position tracking across currencies
- **BalanceCalculator** for consistent balance calculations
- **Comprehensive validation** for data integrity