Compare commits
17
Commits
master
..
e5534aba34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5534aba34 | ||
|
|
40e5a05ec9 | ||
|
|
048a6c6f38 | ||
|
|
d4ebab96d6 | ||
|
|
ea7854473f | ||
|
|
c0adc77f56 | ||
|
|
1fcaec8daf | ||
|
|
553e1a4c83 | ||
|
|
98a5e9332f | ||
|
|
2c7f8f4a67 | ||
|
|
dc98ea910f | ||
|
|
da0a78d2d0 | ||
|
|
5cea645062 | ||
|
|
ef1a65adeb | ||
|
|
696823406e | ||
|
|
c7e4b68dfb | ||
|
|
435f7b92bf |
@@ -23,29 +23,20 @@ alembic upgrade head
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
from src.ingest.b4w import ingest_b4w
|
from src.ingest.b4w import ingest_b4w
|
||||||
from src.db import get_session
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
csv_path = Path("/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/b4w_export_dummy_01.csv")
|
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)
|
||||||
ingest_b4w(csv_path, session)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Import comdirect Export
|
### Import comdirect Export
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from src.ingest.comdirect import ingest_comdirect
|
from src.ingest.comdirect import ingest_comdirect
|
||||||
from src.db import get_session
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
csv_path = Path("/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/comdirect_giro_01.csv")
|
csv_path = Path("/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/comdirect_giro_01.csv")
|
||||||
with get_session() as session:
|
ingest_comdirect(csv_path)
|
||||||
ingest_comdirect(
|
|
||||||
session,
|
|
||||||
csv_path,
|
|
||||||
account_iban="DE89370400440532013000",
|
|
||||||
account_currency="EUR",
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set Category Budgets
|
### Set Category Budgets
|
||||||
@@ -54,7 +45,6 @@ with get_session() as session:
|
|||||||
from src.models.category import Category, CategoryBudget
|
from src.models.category import Category, CategoryBudget
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from src.domain_utils import set_category_budget
|
from src.domain_utils import set_category_budget
|
||||||
from src.db import get_session
|
|
||||||
|
|
||||||
# Create category hierarchy
|
# Create category hierarchy
|
||||||
cat = Category.from_str("Lebenshaltung:Essen:Supermarkt")
|
cat = Category.from_str("Lebenshaltung:Essen:Supermarkt")
|
||||||
@@ -66,17 +56,14 @@ budget = CategoryBudget(
|
|||||||
valid_from=date(2026, 10, 1),
|
valid_from=date(2026, 10, 1),
|
||||||
valid_to=date(2026, 11, 30),
|
valid_to=date(2026, 11, 30),
|
||||||
)
|
)
|
||||||
with get_session() as session:
|
set_category_budget(db_session, budget)
|
||||||
set_category_budget(session, budget)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
# Budgets can also be unbounded (no dates specified)
|
# Budgets can also be unbounded (no dates specified)
|
||||||
budget = CategoryBudget(
|
budget = CategoryBudget(
|
||||||
category=cat,
|
category=cat,
|
||||||
amount_eur=200.00, # Monthly average
|
amount_eur=200.00, # Monthly average
|
||||||
)
|
)
|
||||||
set_category_budget(session, budget)
|
set_category_budget(db_session, budget)
|
||||||
session.commit()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
@@ -154,7 +141,7 @@ alembic upgrade head
|
|||||||
pytest
|
pytest
|
||||||
|
|
||||||
# Run with coverage report
|
# Run with coverage report
|
||||||
pytest --cov=src --cov-report=html:htmlcov
|
pytest --cov=src --cov-report=html -c .coverage htmlcov
|
||||||
```
|
```
|
||||||
|
|
||||||
### Common Patterns
|
### Common Patterns
|
||||||
|
|||||||
+1
-2
@@ -29,8 +29,7 @@ def find_category_db(session: Session, category: Category | None) -> CategoryDb
|
|||||||
return (
|
return (
|
||||||
session.query(CategoryDb)
|
session.query(CategoryDb)
|
||||||
.filter_by(name=node.name, parent_id=parent_id)
|
.filter_by(name=node.name, parent_id=parent_id)
|
||||||
.filter(CategoryDb.valid_to.is_(None))
|
.first()
|
||||||
.one_or_none()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return find_existing(category)
|
return find_existing(category)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"""Comprehensive tests for set_category_budget overlap handling."""
|
"""Comprehensive tests for set_category_budget overlap handling."""
|
||||||
|
|
||||||
from datetime import UTC, date, datetime
|
from datetime import date
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from src.domain_utils import find_category_db, set_category_budget
|
from src.domain_utils import find_category_db, set_category_budget
|
||||||
from src.models import Category, CategoryBudget, CategoryBudgetDb
|
from src.models import Category, CategoryBudget, CategoryBudgetDb
|
||||||
from src.models.category import CategoryDb, upsert_category
|
from src.models.category import upsert_category
|
||||||
from tests.factories import CategoryFactory
|
from tests.factories import CategoryFactory
|
||||||
|
|
||||||
# NOTE: MYPY errors suppressed for test fixtures - see AGENTS.md for type checking notes.
|
# NOTE: MYPY errors suppressed for test fixtures - see AGENTS.md for type checking notes.
|
||||||
@@ -615,33 +615,6 @@ class TestFindCategoryDb:
|
|||||||
result = find_category_db(db_session, Category(name="NonExistent"))
|
result = find_category_db(db_session, Category(name="NonExistent"))
|
||||||
assert result is None
|
assert result is None
|
||||||
|
|
||||||
def test_find_reintroduced_category_returns_active_version(
|
|
||||||
self, db_session: Session
|
|
||||||
):
|
|
||||||
category = Category(name="Reintroduced")
|
|
||||||
historical = CategoryDb(
|
|
||||||
name=category.name,
|
|
||||||
valid_to=datetime(2026, 1, 1, tzinfo=UTC),
|
|
||||||
last_action="retired",
|
|
||||||
)
|
|
||||||
db_session.add(historical)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
active = upsert_category(db_session, category, do_commit=False)
|
|
||||||
assert active is not None
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
result = find_category_db(db_session, category)
|
|
||||||
assert result is not None
|
|
||||||
assert result.id == active.id
|
|
||||||
|
|
||||||
set_category_budget(
|
|
||||||
db_session,
|
|
||||||
CategoryBudget(category=category, amount_eur=100.00),
|
|
||||||
)
|
|
||||||
budget = db_session.query(CategoryBudgetDb).one()
|
|
||||||
assert budget.category_id == active.id
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetCategoryBudgetErrorHandling:
|
class TestSetCategoryBudgetErrorHandling:
|
||||||
"""Test error handling in set_category_budget."""
|
"""Test error handling in set_category_budget."""
|
||||||
|
|||||||
Reference in New Issue
Block a user