No description
  • Python 75.3%
  • HTML 13.7%
  • JavaScript 11%
Find a file
Padreug 116df46d38 Net settlement + credit overflow on /receivables/settle (libra-#33, libra-#41)
When the caller omits settled_entry_links (the default), the endpoint
auto-detects open entries across both directions for the user and writes
a single transaction that:

  - Zeros every per-user account that has an open balance, not just the
    net (the libra-#33 bug — previously the 2-leg form left both Payable
    and Receivable carrying non-zero balances after a complete cash
    settlement, while only netting the cash side).
  - Routes any cash above the net obligation to Liabilities:Credit:User-X
    (libra-#41), so over-payment lands on a real liability account
    instead of silently drifting.
  - Attaches every reconciled source entry's link
    (exp-..., rcv-...) so a reader scanning the settlement transaction
    can trace what it cleared.

Cash less than the net obligation, with no explicit links, returns 400
with a structured diff (cash_paid, net_obligation, receivable_total,
payable_total). The operator either pays the exact net or passes
settled_entry_links to settle a specific subset; partial settlement
without a coherent target is not silently absorbed.

The legacy explicit-links code path is unchanged — callers that pass
settled_entry_links keep the 2-leg shape with no auto-detection. None
of the callers in libra or aiolabs/webapp currently use that field, but
the contract is preserved for the partial-settle-of-specific-entries
flow.

format_fiat_net_settlement_entry is the new helper for the 2/3/4-leg
shape; it enforces the cash-balance constraint inline so callers can't
accidentally produce an unbalanced transaction.

tests/test_settlement_api.py (6 tests) locks in:
  - Nancy's #33 scenario: receivable 100 + payable 50 + cash 50
    zeros both per-user accounts, links both source entries
  - Overpay: cash 70 against net 50 → credit balance 20
  - Pure receivable overpay → credit appears
  - Underpay without explicit links → 400 with diff
  - No open receivables → 400 with hint pointing at /payables/pay
  - Explicit settled_entry_links uses legacy 2-leg path

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-07 15:39:45 +02:00
core Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
docs Clean up awkward "the Libra" phrasing left over from rename 2026-05-07 08:37:30 +02:00
helper Clean up awkward "the Libra" phrasing left over from rename 2026-05-07 08:37:30 +02:00
static fix(dashboard): detect voided rows by tag, not by flag char 2026-06-06 20:47:42 +02:00
templates/libra fix(dashboard): detect voided rows by tag, not by flag char 2026-06-06 20:47:42 +02:00
tests Net settlement + credit overflow on /receivables/settle (libra-#33, libra-#41) 2026-06-07 15:39:45 +02:00
.gitignore initial commit 2025-10-22 12:33:45 +02:00
__init__.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
account_sync.py Polish account-creation flow: insertion point, user_id consistency, startup race 2026-06-06 19:36:39 +02:00
account_utils.py Clean up awkward "the Libra" phrasing left over from rename 2026-05-07 08:37:30 +02:00
auth.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
beancount_format.py Net settlement + credit overflow on /receivables/settle (libra-#33, libra-#41) 2026-06-07 15:39:45 +02:00
CLAUDE.md Update CLAUDE.md to reflect Fava-as-sole-source-of-truth for journal entries 2026-06-06 14:48:57 +02:00
config.json Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
crud.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
description.md Clean up awkward "the Libra" phrasing left over from rename 2026-05-07 08:37:30 +02:00
fava_client.py Surface user credit balance in GET /balance per libra-#41 2026-06-07 15:39:45 +02:00
manifest.json Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
MIGRATION_SQUASH_SUMMARY.md Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
migrations.py Expose SUBMIT_INCOME in permission management UI 2026-05-16 19:55:28 +02:00
migrations_old.py.bak Squash 16 migrations into single clean initial migration 2025-11-10 21:51:11 +01:00
models.py Surface user credit balance in GET /balance per libra-#41 2026-06-07 15:39:45 +02:00
package.json Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
permission_management.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
README.md Clean up awkward "the Libra" phrasing left over from rename 2026-05-07 08:37:30 +02:00
services.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
tasks.py Polish account-creation flow: insertion point, user_id consistency, startup race 2026-06-06 19:36:39 +02:00
views.py Rename Castle Accounting extension to Libra 2026-05-05 10:24:46 +02:00
views_api.py Net settlement + credit overflow on /receivables/settle (libra-#33, libra-#41) 2026-06-07 15:39:45 +02:00

Libra Extension for LNbits

A full-featured double-entry accounting system for collective projects, integrated with LNbits Lightning payments.

Overview

Libra enables collectives like co-living spaces, makerspaces, and community projects to:

  • Track expenses and revenue with proper accounting
  • Manage individual member balances
  • Record contributions as equity or reimbursable expenses
  • Track accounts receivable (what members owe)
  • Generate Lightning invoices for settlements

Installation

This extension is designed to be installed in the lnbits/extensions/ directory.

cd lnbits/extensions/
# Copy or clone the libra directory here

Enable the extension through the LNbits admin interface or by adding it to your configuration.

Usage

For Members

  1. Add an Expense: Record money you spent on behalf of the collective

    • Choose "Liability" if you want reimbursement
    • Choose "Equity" if it's a contribution
  2. View Your Balance: See if the collective owes you money or vice versa

  3. Pay Outstanding Balance: Generate a Lightning invoice to settle what you owe

For Admins

  1. Create Accounts Receivable: Record when someone owes the collective money

  2. Record Revenue: Track income received by the collective

  3. View All Transactions: See complete accounting history

  4. Make Payments: Record payments to members

Architecture

Data Models

  • Account: Individual accounts in the chart of accounts
  • JournalEntry: Transaction header with description and date
  • EntryLine: Individual debit/credit lines (always balanced)

Account Types

  • Assets: Things the organization owns (Cash, Bank, Accounts Receivable)
  • Liabilities: What the organization owes (Accounts Payable to members)
  • Equity: Member contributions and retained earnings
  • Revenue: Income streams
  • Expenses: Operating costs

Database Schema

The extension creates three tables:

  • libra.accounts - Chart of accounts
  • libra.journal_entries - Transaction headers
  • libra.entry_lines - Debit/credit lines

API Reference

See description.md for full API documentation.

Development

To modify this extension:

  1. Edit models in models.py
  2. Add database migrations in migrations.py
  3. Implement business logic in crud.py
  4. Create API endpoints in views_api.py
  5. Update UI in templates/libra/index.html

Contributing

Contributions welcome! Please ensure:

  • Journal entries always balance
  • User permissions are properly checked
  • Database transactions are atomic

License

MIT License - feel free to use and modify for your collective!