mathias2784 e0c32319e8
Tests / test (push) Failing after 12s
Tests / lint (push) Failing after 11s
draft: category tree building
2026-10-28 07:12:31 +01:00
2026-10-10 20:47:51 +00:00
2026-10-27 18:08:10 +00:00
2026-10-27 18:08:10 +00:00
2026-10-28 07:12:31 +01:00
2026-10-27 18:08:10 +00:00
2026-10-27 18:08:10 +00:00
2026-09-04 14:56:51 +02:00
2026-09-12 10:13:59 +02:00
2026-09-02 20:20:48 +02:00
2026-10-27 18:08:10 +00:00
2026-09-04 14:56:51 +02:00
2026-10-27 18:08:10 +00:00
2026-10-27 18:08:10 +00:00
2026-09-12 21:00:00 +02:00
2026-10-27 18:08:10 +00:00

finanz-cockpit

Financial tracking application for German bank exports (b4w, comdirect) with unified transaction processing and category-based budget management.

Features

  • Dual-source ingestion: Import transactions from b4w and comdirect CSV exports
  • Unified transaction table: All transactions are consolidated into a single transactions table using business-key deduplication
  • Category hierarchy: Support for nested category structures (e.g., "Lebenshaltung:Essen:Supermarkt")
  • Budget tracking per category: Set and manage budgets with time-bounded or unbounded validity periods
  • Automatic overlap handling: Smart budget management handles partial/full overlaps automatically

Installation

uv sync
alembic upgrade head

Usage

Import b4w Export

from src.ingest.b4w import ingest_b4w
from src.db import get_session
from pathlib import Path

csv_path = Path("/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/b4w_export_dummy_01.csv")
with get_session() as session:
    ingest_b4w(csv_path, session)

Import comdirect Export

from src.ingest.comdirect import ingest_comdirect
from src.db import get_session
from pathlib import Path

csv_path = Path("/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/comdirect_giro_01.csv")
with get_session() as session:
    ingest_comdirect(
        session,
        csv_path,
        account_iban="DE89370400440532013000",
        account_currency="EUR",
    )

Set Category Budgets

from src.models.category import Category, CategoryBudget
from datetime import date
from src.domain_utils import set_category_budget
from src.db import get_session

# Create category hierarchy
cat = Category.from_str("Lebenshaltung:Essen:Supermarkt")

# Set budget for October-November 2026
budget = CategoryBudget(
    category=cat,
    amount_eur=150.00,
    valid_from=date(2026, 10, 1),
    valid_to=date(2026, 11, 30),
)
with get_session() as session:
    set_category_budget(session, budget)
    session.commit()

    # Budgets can also be unbounded (no dates specified)
    budget = CategoryBudget(
        category=cat,
        amount_eur=200.00,  # Monthly average
    )
    set_category_budget(session, budget)
    session.commit()

Testing

# Run all tests
pytest

# Run with coverage
pytest --cov=src --cov-report=term-missing

# Run a single test file
pytest tests/test_model_b4wexport.py -v

Project Structure

  • src/: Application code
    • main.py: CLI entrypoint for CSV ingestion
    • db.py: Database connection management
    • models/: Pydantic models + SQLAlchemy tables
    • ingest/: Data ingestion logic per source (b4w, comdirect)
    • domain_utils.py: Domain-level utilities (budget overlap handling)
  • tests/: Tests with fixtures in conftest.py
  • alembic/versions/: Database migrations

Data Models

Transaction Sources

  • b4w: B4wExport, Category
  • comdirect: ComdirectGiro, ComdirectCreditCard, ComdirectDepot
  • unified: Transaction, TransactionDb – consolidates all sources into one table

All models inherit from common base in src/models/common.py:

  • hash_id(): SHA256-based deduplication key
  • _parse_date_german(): Handles "07.09.2026" format and values like "offen", "--"
  • _parse_decimal_german(): Converts "1,23" to Decimal

Category Budgets

Budget tracking for categories with time-bounded or unbounded periods:

from src.models.category import Category, CategoryBudget

cat = Category(name="Lebenshaltung")
budget = CategoryBudget(
    category=cat,
    amount_eur=150.00,
    valid_from=date(2026, 10, 1),   # Optional: None for unbounded start
    valid_to=date(2026, 11, 30),     # Optional: None for unbounded end
)

set_category_budget(db_session, budget)

The set_category_budget() function handles overlap scenarios automatically:

  1. No overlap: Adds new budget alongside existing ones
  2. Partial overlap: Splits existing budget into non-overlapping parts + adds new budget
  3. Full overlap: Replaces existing budget entirely

Development

Setup

# Install dependencies
uv sync

# Run migrations
alembic upgrade head

# Run all tests
pytest

# Run with coverage report
pytest --cov=src --cov-report=html:htmlcov

Common Patterns

Database Session: Always use get_session() context manager:

from src.db import get_session

with get_session() as session:
    # query operations here
    session.commit()

CSV Format:

  • b4w: German bank export (CSV)
  • comdirect: CSV with fields like Buchungstag, Umsatz in EUR, Vorgang

Testing Workflow

Tests automatically run migrations via conftest.py. For testing without migrations:

export DATABASE_URL="sqlite://" pytest tests/test_db.py

Common Mistakes

  1. Global engine state: Always use get_session() context manager
  2. German date formats: Use _parse_date_german() for CSV parsing
  3. Migration setup: Tests auto-migrate, but integration tests need explicit alembic upgrade head
  4. Faker locale: Use Faker("de_DE") for realistic names/IBANs

License

MIT

S
Description
No description provided
Readme
545 KiB
Languages
Python 99.5%
Mako 0.5%