Sanitizes reference links for Beancount
Ensures that user-provided reference strings for expense, receivable, and revenue entries are sanitized before being included as Beancount links. This prevents issues caused by invalid characters in the links, improving compatibility with Beancount's link format. A new utility function is introduced to handle the sanitization process.
This commit is contained in:
parent
a6b67b7416
commit
51ae2e8e47
2 changed files with 34 additions and 9 deletions
|
|
@ -14,6 +14,31 @@ Key concepts:
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_link(text: str) -> str:
|
||||||
|
"""
|
||||||
|
Sanitize a string to make it valid for Beancount links.
|
||||||
|
|
||||||
|
Beancount links can only contain: A-Z, a-z, 0-9, -, _, /, .
|
||||||
|
All other characters are replaced with hyphens.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> sanitize_link("Test (pending)")
|
||||||
|
'Test-pending'
|
||||||
|
>>> sanitize_link("Invoice #123")
|
||||||
|
'Invoice-123'
|
||||||
|
>>> sanitize_link("castle-abc123")
|
||||||
|
'castle-abc123'
|
||||||
|
"""
|
||||||
|
# Replace any character that's not alphanumeric, dash, underscore, slash, or period with a hyphen
|
||||||
|
sanitized = re.sub(r'[^A-Za-z0-9\-_/.]', '-', text)
|
||||||
|
# Remove consecutive hyphens
|
||||||
|
sanitized = re.sub(r'-+', '-', sanitized)
|
||||||
|
# Remove leading/trailing hyphens
|
||||||
|
sanitized = sanitized.strip('-')
|
||||||
|
return sanitized
|
||||||
|
|
||||||
|
|
||||||
def format_transaction(
|
def format_transaction(
|
||||||
|
|
|
||||||
18
views_api.py
18
views_api.py
|
|
@ -802,7 +802,7 @@ async def api_create_expense_entry(
|
||||||
|
|
||||||
# Format as Beancount entry and submit to Fava
|
# Format as Beancount entry and submit to Fava
|
||||||
from .fava_client import get_fava_client
|
from .fava_client import get_fava_client
|
||||||
from .beancount_format import format_expense_entry
|
from .beancount_format import format_expense_entry, sanitize_link
|
||||||
|
|
||||||
fava = get_fava_client()
|
fava = get_fava_client()
|
||||||
|
|
||||||
|
|
@ -814,10 +814,10 @@ async def api_create_expense_entry(
|
||||||
import uuid
|
import uuid
|
||||||
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
||||||
|
|
||||||
# Add castle ID as reference/link
|
# Add castle ID as reference/link (sanitized for Beancount)
|
||||||
castle_reference = f"castle-{entry_id}"
|
castle_reference = f"castle-{entry_id}"
|
||||||
if data.reference:
|
if data.reference:
|
||||||
castle_reference = f"{data.reference}-{entry_id}"
|
castle_reference = f"{sanitize_link(data.reference)}-{entry_id}"
|
||||||
|
|
||||||
# Format Beancount entry
|
# Format Beancount entry
|
||||||
entry = format_expense_entry(
|
entry = format_expense_entry(
|
||||||
|
|
@ -930,7 +930,7 @@ async def api_create_receivable_entry(
|
||||||
|
|
||||||
# Format as Beancount entry and submit to Fava
|
# Format as Beancount entry and submit to Fava
|
||||||
from .fava_client import get_fava_client
|
from .fava_client import get_fava_client
|
||||||
from .beancount_format import format_receivable_entry
|
from .beancount_format import format_receivable_entry, sanitize_link
|
||||||
|
|
||||||
fava = get_fava_client()
|
fava = get_fava_client()
|
||||||
|
|
||||||
|
|
@ -942,10 +942,10 @@ async def api_create_receivable_entry(
|
||||||
import uuid
|
import uuid
|
||||||
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
||||||
|
|
||||||
# Add castle ID as reference/link
|
# Add castle ID as reference/link (sanitized for Beancount)
|
||||||
castle_reference = f"castle-{entry_id}"
|
castle_reference = f"castle-{entry_id}"
|
||||||
if data.reference:
|
if data.reference:
|
||||||
castle_reference = f"{data.reference}-{entry_id}"
|
castle_reference = f"{sanitize_link(data.reference)}-{entry_id}"
|
||||||
|
|
||||||
# Format Beancount entry
|
# Format Beancount entry
|
||||||
entry = format_receivable_entry(
|
entry = format_receivable_entry(
|
||||||
|
|
@ -1007,7 +1007,7 @@ async def api_create_revenue_entry(
|
||||||
Submits entry to Fava/Beancount.
|
Submits entry to Fava/Beancount.
|
||||||
"""
|
"""
|
||||||
from .fava_client import get_fava_client
|
from .fava_client import get_fava_client
|
||||||
from .beancount_format import format_revenue_entry
|
from .beancount_format import format_revenue_entry, sanitize_link
|
||||||
|
|
||||||
# Get revenue account
|
# Get revenue account
|
||||||
revenue_account = await get_account_by_name(data.revenue_account)
|
revenue_account = await get_account_by_name(data.revenue_account)
|
||||||
|
|
@ -1057,10 +1057,10 @@ async def api_create_revenue_entry(
|
||||||
import uuid
|
import uuid
|
||||||
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
entry_id = str(uuid.uuid4()).replace("-", "")[:16]
|
||||||
|
|
||||||
# Add castle ID as reference/link
|
# Add castle ID as reference/link (sanitized for Beancount)
|
||||||
castle_reference = f"castle-{entry_id}"
|
castle_reference = f"castle-{entry_id}"
|
||||||
if data.reference:
|
if data.reference:
|
||||||
castle_reference = f"{data.reference}-{entry_id}"
|
castle_reference = f"{sanitize_link(data.reference)}-{entry_id}"
|
||||||
|
|
||||||
entry = format_revenue_entry(
|
entry = format_revenue_entry(
|
||||||
payment_account=payment_account.name,
|
payment_account=payment_account.name,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue