File size: 3,148 Bytes
f91bd05
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import csv
import io
from typing import Dict, Any

def parse_bank_csv(content: bytes) -> Dict[str, Any]:
    """
    Parse a bank CSV file and return categorized transactions with summary statistics.

    Args:
        content: Raw bytes of the CSV file

    Returns:
        Dict with keys:
        - transactions: List of transaction dicts with date, description, amount
        - total_income: Sum of positive amounts
        - total_expenses: Sum of absolute negative amounts
        - net: Total income minus total expenses
        - count: Number of transactions
        - monthly_estimate: Average monthly expenses based on unique months in data
    """
    text = content.decode('utf-8', errors='replace')
    lines = text.strip().split('\n')

    transactions = []
    total_income = 0
    total_expenses = 0

    # Try to detect format
    try:
        # Try semicolon first (German standard)
        if lines:
            dialect = csv.Sniffer().sniff(lines[0], delimiters=';,\t')
            reader = csv.DictReader(io.StringIO(text), delimiter=dialect.delimiter)
        else:
            reader = csv.DictReader(io.StringIO(text), delimiter=';')
    except csv.Error:
        reader = csv.DictReader(io.StringIO(text), delimiter=';')

    for row in reader:
        amount = None
        date_str = None
        description = ""

        for key, val in row.items():
            if not key:
                continue
            key_lower = key.lower().strip()

            # Amount detection
            if key_lower in ('betrag', 'amount', 'umsatz', 'betrag (eur)', 'wert'):
                try:
                    amount = float(val.replace('.', '').replace(',', '.').strip().strip('"'))
                except (ValueError, AttributeError):
                    pass

            # Date detection
            if key_lower in ('buchungstag', 'datum', 'date', 'buchungsdatum', 'valuta'):
                date_str = val.strip().strip('"')

            # Description detection
            if key_lower in ('verwendungszweck', 'buchungstext', 'description', 'empfaenger',
                           'auftraggeber / beguenstigter', 'zahlungsempfaenger', 'beschreibung'):
                if val and val.strip():
                    description = val.strip().strip('"')[:100]

        if amount is not None:
            if amount > 0:
                total_income += amount
            else:
                total_expenses += abs(amount)
            transactions.append({
                "date": date_str or "",
                "description": description,
                "amount": amount,
            })

    # Calculate monthly estimate based on unique months in data
    unique_months = len(set(t['date'][:7] for t in transactions if t['date']))
    monthly_estimate = total_expenses / max(1, unique_months) if transactions else 0

    return {
        "transactions": transactions,
        "total_income": round(total_income, 2),
        "total_expenses": round(total_expenses, 2),
        "net": round(total_income - total_expenses, 2),
        "count": len(transactions),
        "monthly_estimate": round(monthly_estimate, 2),
    }