36 lines
1.4 KiB
Python
36 lines
1.4 KiB
Python
import csv
|
|
import io
|
|
from decimal import Decimal
|
|
from fastapi import APIRouter
|
|
from fastapi.responses import StreamingResponse
|
|
from database import connect
|
|
from models import CATEGORIES
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def safe_cell(value):
|
|
text = str(value or '')
|
|
return "'" + text if text.lstrip().startswith(('=', '+', '-', '@')) or text.startswith(('\t', '\r', '\n')) else text
|
|
|
|
|
|
def csv_rows():
|
|
stream = io.StringIO(newline='')
|
|
writer = csv.writer(stream, delimiter=';', lineterminator='\r\n')
|
|
yield '\ufeff'
|
|
writer.writerow(['Datum', 'Position', 'Kategorie', 'Betrag', 'Notiz', 'Erwartet', 'Erhalten'])
|
|
yield stream.getvalue()
|
|
stream.seek(0); stream.truncate(0)
|
|
with connect() as db:
|
|
for row in db.execute('SELECT i.*, a.name FROM income_entries i JOIN assets a ON a.id=i.asset_id ORDER BY date DESC, i.id DESC'):
|
|
writer.writerow([row['date'], safe_cell(row['name']), CATEGORIES[row['category']],
|
|
f"{Decimal(row['amount'])/100:.2f}".replace('.', ','), safe_cell(row['note']),
|
|
'Ja' if row['expected'] else 'Nein', 'Ja' if row['received'] else 'Nein'])
|
|
yield stream.getvalue()
|
|
stream.seek(0); stream.truncate(0)
|
|
|
|
|
|
@router.get('/export/income.csv')
|
|
def export():
|
|
return StreamingResponse(csv_rows(), media_type='text/csv; charset=utf-8', headers={'Content-Disposition': 'attachment; filename="income.csv"'})
|