Removes voided/flagged entry flags

Updates journal entry flags to align with Beancount's limited flag support.
Beancount only uses cleared (*) and pending (!) flags.

Removes the VOID and FLAGGED flags and recommends using tags instead
(e.g., "! + #voided" for voided entries, "! + #review" for flagged entries).

Updates the API to reflect this change, removing the ability to directly
"reject" an expense entry via the void flag.  Instead, instructs users to
add the #voided tag in Fava.

Updates reconciliation summary to count entries with voided/review tags
instead of voided/flagged flags.
This commit is contained in:
padreug 2025-11-09 23:26:30 +01:00
parent de3e4e65af
commit 9350f05d74
2 changed files with 21 additions and 17 deletions

View file

@ -15,11 +15,18 @@ class AccountType(str, Enum):
class JournalEntryFlag(str, Enum): class JournalEntryFlag(str, Enum):
"""Transaction status flags (Beancount-style)""" """Transaction status flags (Beancount-compatible)
Beancount only supports two user-facing flags:
- * (CLEARED): Completed transactions
- ! (PENDING): Transactions needing attention
For voided/flagged transactions, use tags instead:
- Voided: Use "!" flag + #voided tag
- Flagged: Use "!" flag + #review tag
"""
CLEARED = "*" # Fully reconciled/confirmed CLEARED = "*" # Fully reconciled/confirmed
PENDING = "!" # Not yet confirmed/awaiting approval PENDING = "!" # Not yet confirmed/awaiting approval
FLAGGED = "#" # Needs review/attention
VOID = "x" # Voided/cancelled entry
class Account(BaseModel): class Account(BaseModel):

View file

@ -1924,19 +1924,14 @@ async def api_reject_expense_entry(
detail=f"Entry is not pending (current status: {entry.flag.value})", detail=f"Entry is not pending (current status: {entry.flag.value})",
) )
# Update flag to voided # Since entries are now in Fava/Beancount, voiding requires editing the Beancount file
await db.execute( # Beancount doesn't have a "void" flag - recommend using ! flag + #voided tag
""" raise HTTPException(
UPDATE journal_entries status_code=HTTPStatus.NOT_IMPLEMENTED,
SET flag = :flag detail="To reject/void entry, open Fava and either delete the transaction or add the #voided tag. "
WHERE id = :id "Beancount only supports * (cleared) and ! (pending) flags."
""",
{"flag": JournalEntryFlag.VOID.value, "id": entry_id}
) )
# Return updated entry
return await get_journal_entry(entry_id)
# ===== BALANCE ASSERTION ENDPOINTS ===== # ===== BALANCE ASSERTION ENDPOINTS =====
@ -2136,11 +2131,13 @@ async def api_get_reconciliation_summary(
fava = get_fava_client() fava = get_fava_client()
all_entries = await fava.query_transactions(limit=1000, include_pending=True) all_entries = await fava.query_transactions(limit=1000, include_pending=True)
# Count entries by flag # Count entries by flag (Beancount only supports * and !)
cleared = len([e for e in all_entries if e.get("flag") == "*"]) cleared = len([e for e in all_entries if e.get("flag") == "*"])
pending_entries = len([e for e in all_entries if e.get("flag") == "!"]) pending_entries = len([e for e in all_entries if e.get("flag") == "!"])
flagged = len([e for e in all_entries if e.get("flag") == "#"])
voided = len([e for e in all_entries if e.get("flag") == "x"]) # Count entries with special tags
voided = len([e for e in all_entries if "voided" in e.get("tags", [])])
flagged = len([e for e in all_entries if "review" in e.get("tags", []) or "flagged" in e.get("tags", [])])
# Get all accounts # Get all accounts
accounts = await get_all_accounts() accounts = await get_all_accounts()