Files
finanz-cockpit/README.md
T
mathias2784 44d4e58036
Tests / test (push) Successful in 16s
Tests / lint (push) Successful in 15s
Fix active category lookup and README usage examples
2026-10-27 19:07:21 +01:00

194 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
uv sync
alembic upgrade head
```
## Usage
### Import b4w Export
```python
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
```python
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
```python
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
```bash
# 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:
```python
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
```bash
# 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:
```python
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:
```bash
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