Category overhaul (#20)
Reviewed-on: #20 Co-authored-by: Mathias <mathias2784@web.de>
This commit was merged in pull request #20.
This commit is contained in:
@@ -7,15 +7,17 @@
|
||||
uv sync
|
||||
|
||||
# Run migrations
|
||||
alembic upgrade head
|
||||
uv run alembic upgrade head
|
||||
|
||||
# Run all tests
|
||||
pytest
|
||||
uv run pytest
|
||||
|
||||
# Run a single test file
|
||||
pytest tests/test_model_b4wexport.py -v
|
||||
uv run pytest tests/test_model_b4wexport.py -v
|
||||
```
|
||||
|
||||
Use `uv run` for project commands so they use the project-managed Python environment and dependencies.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- **`src/`**: Application code
|
||||
@@ -53,10 +55,10 @@ with get_session() as session:
|
||||
|
||||
```bash
|
||||
# Tests automatically run migrations via conftest fixture
|
||||
pytest tests/ -v --tb=short
|
||||
uv run pytest tests/ -v --tb=short
|
||||
|
||||
# To test without migrations (in-memory SQLite), use DATABASE_URL="sqlite://"
|
||||
export DATABASE_URL="sqlite://" pytest tests/test_db.py
|
||||
DATABASE_URL="sqlite://" uv run pytest tests/test_db.py
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
@@ -71,7 +73,33 @@ Two sources with shared patterns:
|
||||
- **comdirect**: `ComdirectGiro`, `ComdirectCreditCard`, `ComdirectDepot`, import to `comdirect_giro` table
|
||||
- **unified**: `Transaction`, `TransactionDb` – both ingest pipelines project their staging rows (`import_b4w`, `comdirect_giro`) into one `transactions` table via `src/ingest/transactions.py` (`map_*` mappers + `consolidate_transactions`). Dedup uses a business-key `hash_id` (source + IBAN + value date + amount + text + counterparty) with a UNIQUE constraint and SQLite `INSERT OR IGNORE`, so re-imports are idempotent. Amounts are canonical signed (negative = money out). Depot/credit-card/tagesgeld are not projected yet.
|
||||
|
||||
All models inherit from common base in `src/models/_common.py`:
|
||||
## Category Budget Management (NEW)
|
||||
|
||||
Budget tracking for categories with time-bounded or unbounded periods:
|
||||
|
||||
```python
|
||||
from src.models.category import Category, CategoryBudget
|
||||
from datetime import date
|
||||
|
||||
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/replace budget - handles overlap automatically:
|
||||
from src.domain_utils import set_category_budget
|
||||
set_category_budget(db_session, budget)
|
||||
```
|
||||
|
||||
The `set_category_budget()` function intelligently handles three scenarios:
|
||||
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
|
||||
|
||||
All models inherit from common base in `src/models/common.py`:
|
||||
- `_hash()`: SHA256-based deduplication key
|
||||
- `_parse_date_german()`: Handles "07.09.2026" format and values like "offen", "--"
|
||||
- `_parse_decimal_german()`: Converts "1,23" to Decimal
|
||||
@@ -103,6 +131,22 @@ item = B4wExportFactory.build( # build() for partial, create() for full
|
||||
|
||||
## Testing Tips
|
||||
|
||||
- Run single test: `pytest tests/test_model_b4wexport.py -v`
|
||||
- Run single test: `uv run pytest tests/test_model_b4wexport.py -v`
|
||||
- View migrations: `ls alembic/versions/`
|
||||
- Test data location: `/scripts/dummy_data/`
|
||||
|
||||
### Type Checking (mypy)
|
||||
|
||||
```bash
|
||||
# Static type checking with mypy
|
||||
uv run mypy src/
|
||||
|
||||
# With test coverage
|
||||
uv run pytest --cov=src --cov-report=term-missing
|
||||
```
|
||||
|
||||
**Note**: Some comparisons between `date | None` types require explicit guards or type assertions to satisfy mypy, even when the logic is correct. See `src/domain_utils.py` for examples.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Don't be too verbose in docstrings and comments
|
||||
|
||||
Reference in New Issue
Block a user