# 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 `!` to `x` (VOID)
- Entry **never affects balances**
- Entry appears with grey cancel icon (voided)

## Balance Calculation

Only entries with `flag='*'` (CLEARED) are included in balance calculations:

```sql
-- 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

1. **views_api.py**
   - Line 284: Set expenses to `JournalEntryFlag.PENDING` on creation
   - Lines 181-197: Added `/api/v1/entries/pending` endpoint
   - Lines 972-1011: Added approve endpoint
   - Lines 1013-1053: Added reject endpoint

2. **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

3. **index.html**
   - Lines 157-209: Added "Pending Expense Approvals" card

4. **index.js**
   - Line 68: Added `pendingExpenses` data 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

## User Experience

### For Regular Users
1. Submit expense via "Add Expense" button
2. See expense with orange pending icon (⏱️) in transaction list
3. Balance does NOT change yet
4. Wait for admin approval

### For Admin (Super User)
1. See "Pending Expense Approvals" card at top of page
2. Review expense details
3. Click "Approve" → User's balance updates
4. 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 `meta` field tracks who created and reviewed each entry

## Testing

1. **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
   }
   ```

2. **Verify it's pending**
   - Check user balance → should NOT include this expense
   - Check transaction list → should show orange pending icon

3. **Login as admin and approve**
   - See expense in "Pending Expense Approvals"
   - Click "Approve"
   - Verify user balance updates

4. **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
