Files

87 lines
3.8 KiB
Python

from datetime import date
from decimal import Decimal
from typing import Annotated
from fastapi import APIRouter, Form, HTTPException, Query, Request
from fastapi.responses import RedirectResponse
from services.asset_service import create_asset as create_asset_record
from models import CATEGORIES
from services.income_service import assets, available_years, get_entry, list_entries, save_entry, delete_entry
from views import render
router = APIRouter()
def form_page(request, data, error=None, status=200, entry_id=None):
return render(request, 'income_form.html', {'data': data, 'assets': assets(), 'error': error, 'entry_id': entry_id}, status)
@router.get('/income')
def history(request: Request, year: str | None = None,
month: str | None = None,
asset_id: str | None = None, category: str | None = None,
page: Annotated[int, Query(ge=1, le=1000000)] = 1):
def number(value, maximum):
if not value:
return None
try:
parsed = int(value)
if not 1 <= parsed <= maximum:
raise ValueError
return parsed
except ValueError:
raise HTTPException(422, 'Ungültiger Filter.') from None
year, month, asset_id = number(year, 9999), number(month, 12), number(asset_id, 9223372036854775807)
category = category or None
if category is not None and category not in CATEGORIES:
raise HTTPException(422, 'Ungültige Kategorie.')
rows = list_entries(year, month, asset_id, category, limit=101, offset=(page-1)*100)
return render(request, 'income.html', dict(entries=rows[:100], more=len(rows)>100, page=page,
assets=assets(), years=available_years(), filters=dict(year=year, month=month, asset_id=asset_id, category=category)))
@router.get('/income/new')
def new(request: Request):
return form_page(request, {'date': date.today().isoformat(), 'received': True, 'expected': False,
'asset_id': request.query_params.get('asset_id', ''), 'category': 'dividend'})
@router.get('/income/{entry_id}/edit')
def edit(request: Request, entry_id: int):
data = get_entry(entry_id)
data['amount'] = str(Decimal(data['amount']) / 100).replace('.', ',')
return form_page(request, data, entry_id=entry_id)
@router.post('/income/new')
@router.post('/income/{entry_id}/edit')
def save(request: Request, date: Annotated[str, Form()] = '', asset_id: Annotated[str, Form()] = '',
category: Annotated[str, Form()] = '', amount: Annotated[str, Form()] = '',
note: Annotated[str, Form()] = '', expected: Annotated[str, Form()] = '',
received: Annotated[str, Form()] = '', entry_id: int | None = None):
data = dict(date=date, asset_id=asset_id, category=category, amount=amount, note=note, expected=expected, received=received)
try:
save_entry(data, entry_id)
except ValueError as error:
return form_page(request, data, str(error), 422, entry_id)
return RedirectResponse('/?message=saved', status_code=303)
@router.post('/income/{entry_id}/delete')
def delete(entry_id: int):
delete_entry(entry_id)
return RedirectResponse('/?message=deleted', status_code=303)
@router.get('/assets/new')
def new_asset(request: Request):
return render(request, 'asset_form.html', {'data': {}})
@router.post('/assets/new')
def create_asset(request: Request, name: Annotated[str, Form()], asset_type: Annotated[str, Form()], ticker: Annotated[str, Form()] = ''):
try:
asset_id = create_asset_record(name, asset_type, ticker, reuse=True)['id']
except ValueError as error:
return render(request, 'asset_form.html', {'data': dict(name=name, asset_type=asset_type, ticker=ticker), 'error': str(error)}, 422)
return RedirectResponse(f'/income/new?asset_id={asset_id}', status_code=303)