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.
4.8 KiB
4.8 KiB
Expense Approval Workflow
Overview
The Castle extension now requires admin approval for all user-submitted expenses. This prevents invalid or incorrect expenses from affecting balances until they are verified by the Castle admin.
How It Works
1. User Submits Expense
- User fills out the expense form with description, amount, category, etc.
- Expense is created with
flag='!'(PENDING status) - Entry is saved to the database but does not affect balances
2. Admin Reviews Pending Expenses
- Admin sees "Pending Expense Approvals" card on the main page
- Card shows all pending expenses with:
- Description and amount
- User who submitted it
- Date submitted
- Fiat amount (if applicable)
- Reference number
3. Admin Takes Action
Option A: Approve
- Admin clicks "Approve" button
- Entry flag changes from
!to*(CLEARED) - Entry now affects balances (user's balance updates)
- User sees the expense in their transaction history
- Entry appears with green checkmark icon
Option B: Reject
- Admin clicks "Reject" button
- Entry flag changes from
!tox(VOID) - Entry never affects balances
- Entry appears with grey cancel icon (voided)
Balance Calculation
Only entries with flag='*' (CLEARED) are included in balance calculations:
-- Balance query excludes pending/flagged/voided entries
SELECT SUM(debit), SUM(credit)
FROM entry_lines el
JOIN journal_entries je ON el.journal_entry_id = je.id
WHERE el.account_id = :account_id
AND je.flag = '*' -- Only cleared entries
Transaction Flags
| Flag | Symbol | Status | Affects Balance | Description |
|---|---|---|---|---|
* |
✅ | CLEARED | Yes | Confirmed and reconciled |
! |
⏱️ | PENDING | No | Awaiting approval |
# |
🚩 | FLAGGED | No | Needs review |
x |
❌ | VOID | No | Cancelled/rejected |
API Endpoints
Get Pending Entries (Admin Only)
GET /castle/api/v1/entries/pending
Authorization: Admin Key
Returns: list[JournalEntry]
Approve Expense (Admin Only)
POST /castle/api/v1/entries/{entry_id}/approve
Authorization: Admin Key
Returns: JournalEntry (with flag='*')
Reject Expense (Admin Only)
POST /castle/api/v1/entries/{entry_id}/reject
Authorization: Admin Key
Returns: JournalEntry (with flag='x')
Implementation Details
Files Modified
-
views_api.py
- Line 284: Set expenses to
JournalEntryFlag.PENDINGon creation - Lines 181-197: Added
/api/v1/entries/pendingendpoint - Lines 972-1011: Added approve endpoint
- Lines 1013-1053: Added reject endpoint
- Line 284: Set expenses to
-
crud.py
- Lines 315-329: Updated
get_account_balance()to filter by flag - Lines 367-376: Updated fiat balance calculation to filter by flag
- Lines 238-269: Fixed
get_all_journal_entries()to parse flag/meta
- Lines 315-329: Updated
-
index.html
- Lines 157-209: Added "Pending Expense Approvals" card
-
index.js
- Line 68: Added
pendingExpensesdata property - Lines 497-511: Added
loadPendingExpenses()method - Lines 545-563: Added
approveExpense()method - Lines 564-580: Added
rejectExpense()method - Line 731: Load pending expenses on page load for admins
- Line 68: Added
User Experience
For Regular Users
- Submit expense via "Add Expense" button
- See expense with orange pending icon (⏱️) in transaction list
- Balance does NOT change yet
- Wait for admin approval
For Admin (Super User)
- See "Pending Expense Approvals" card at top of page
- Review expense details
- Click "Approve" → User's balance updates
- Click "Reject" → Expense is voided, no balance change
Security
- All approval endpoints require admin key
- Super user check prevents regular users from approving their own expenses
- Voided entries are never included in balance calculations
- Full audit trail in
metafield tracks who created and reviewed each entry
Testing
-
Submit test expense as regular user
POST /castle/api/v1/entries/expense { "description": "Test groceries", "amount": 50.00, "currency": "EUR", "expense_account": "utilities", "is_equity": false } -
Verify it's pending
- Check user balance → should NOT include this expense
- Check transaction list → should show orange pending icon
-
Login as admin and approve
- See expense in "Pending Expense Approvals"
- Click "Approve"
- Verify user balance updates
-
Submit another expense and reject it
- Submit expense
- Admin clicks "Reject"
- Verify balance never changed
- Entry shows grey cancel icon
Future Enhancements
- Email notifications when expense is approved/rejected
- Bulk approve/reject multiple expenses
- Admin notes when rejecting (reason for rejection)
- Expense revision system (user can edit and resubmit rejected expenses)
- Approval workflow with multiple approvers