Implements expense approval workflow

Adds an admin approval workflow for user-submitted expenses. This ensures that only valid expenses affect user balances.

The workflow includes pending expense states, admin approval/rejection actions, balance filtering, and UI updates.
This commit is contained in:
padreug 2025-10-23 00:50:15 +02:00
parent 018a074915
commit 3b371e3bec
4 changed files with 207 additions and 22 deletions

View file

@ -178,6 +178,25 @@ async def api_get_user_entries(
return await get_journal_entries_by_user(wallet.wallet.user, limit)
@castle_api_router.get("/api/v1/entries/pending")
async def api_get_pending_entries(
wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[JournalEntry]:
"""Get all pending expense entries that need approval (admin only)"""
from lnbits.settings import settings as lnbits_settings
if wallet.wallet.user != lnbits_settings.super_user:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN,
detail="Only super user can access this endpoint",
)
# Get all journal entries and filter for pending flag
all_entries = await get_all_journal_entries(limit=1000)
pending_entries = [e for e in all_entries if e.flag == JournalEntryFlag.PENDING]
return pending_entries
@castle_api_router.get("/api/v1/entries/{entry_id}")
async def api_get_journal_entry(entry_id: str) -> JournalEntry:
"""Get a specific journal entry"""
@ -950,25 +969,6 @@ async def api_reject_manual_payment_request(
# ===== EXPENSE APPROVAL ENDPOINTS =====
@castle_api_router.get("/api/v1/entries/pending")
async def api_get_pending_entries(
wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[JournalEntry]:
"""Get all pending expense entries that need approval (admin only)"""
from lnbits.settings import settings as lnbits_settings
if wallet.wallet.user != lnbits_settings.super_user:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN,
detail="Only super user can access this endpoint",
)
# Get all journal entries and filter for pending flag
all_entries = await get_all_journal_entries(limit=1000)
pending_entries = [e for e in all_entries if e.flag == JournalEntryFlag.PENDING]
return pending_entries
@castle_api_router.post("/api/v1/entries/{entry_id}/approve")
async def api_approve_expense_entry(
entry_id: str,