from __future__ import annotations from decimal import Decimal from app.extensions import db from app.models import AllocationSuggestion, Category, CommunityAccount, Month, MonthlyEntryValue def test_health_route(client): response = client.get("/health") assert response.status_code == 200 assert response.json["status"] == "ok" def test_first_run_redirects_to_setup(empty_client): response = empty_client.get("/", follow_redirects=False) assert response.status_code == 302 assert "/auth/setup" in response.headers["Location"] def test_current_month_is_available_after_login(logged_in_client): response = logged_in_client.get("/") assert response.status_code == 200 assert b"2026-04" in response.data or b"2026-05" in response.data assert b"Dauerauftr\xc3\xa4ge pr\xc3\xbcfen" in response.data assert b"Extern mitzuteilen" in response.data def test_analytics_route_uses_new_cost_focused_sections(logged_in_client): response = logged_in_client.get("/analytics") content = response.get_data(as_text=True) assert response.status_code == 200 assert "Kategorien im Monat" in content assert "Kosten nach Zuordnung" in content assert "Budgets im Monatsverlauf" in content assert "Größte Einträge im Monat" in content assert "Sparkonten" in content assert "category-chart-back" in content assert "entry-drilldown-chart" not in content assert '"Pers\\u00f6nliche Auszahlung"' in content assert "Person A" in content assert "Person B" in content def test_planning_detail_refreshes_stale_suggestions_after_distribution_sync(logged_in_client): month = Month.query.filter_by(label="2026-04").first() sparen_value = next( item for item in month.entry_values if item.entry.name == "Sparziel" ) sparen_allocation = next( item for item in month.allocations if item.target_account.slug == "sparen" ) sparen_value.planned_amount = Decimal("0.00") sparen_allocation.amount = Decimal("1539.20") for suggestion in month.suggestions: suggestion.suggested_amount = Decimal("0.00") db.session.commit() response = logged_in_client.get("/planning/2026-04") db.session.refresh(sparen_value) refreshed_suggestions = AllocationSuggestion.query.filter_by(month_id=month.id).all() assert response.status_code == 200 assert sparen_value.planned_amount == Decimal("1539.20") assert sum((item.suggested_amount for item in refreshed_suggestions), Decimal("0.00")) > Decimal("0.00") def test_community_entry_can_be_updated_via_annual_amount(app, logged_in_client): month = Month.query.filter_by(label="2026-04").first() value = next( item for item in month.entry_values if item.entry.name == "Miete" ) response = logged_in_client.post( f"/planning/{month.label}/entry", data={ "value_id": value.id, "return_dialog": f"category-dialog-{value.entry.category_id}", "entry_name": value.entry.name, "category_id": value.entry.category_id, "planned_amount": "", "annual_amount": "1800.00", "benefit_scope": value.entry.benefit_scope, "note": value.note or "", }, ) updated_value = db.session.get(MonthlyEntryValue, value.id) assert response.status_code == 302 assert updated_value.planned_amount == Decimal("150.00") def test_distribution_dialog_shows_direct_budget_form(logged_in_client): response = logged_in_client.get("/planning/2026-04") assert response.status_code == 200 assert b"Budget direkt anpassen" in response.data assert b"Sparkonto" in response.data def test_planning_shows_budgets_and_community_accounts(logged_in_client): response = logged_in_client.get("/planning/2026-04") assert response.status_code == 200 assert b"Budgets" in response.data assert b"Gemeinschaftskonten" in response.data assert b"Privatkonto 1" in response.data assert b"Privatkonto 2" in response.data def test_community_account_can_assign_budget_categories(logged_in_client): community_account = CommunityAccount.query.filter_by(slug="hauptkonto").first() category = Category.query.filter_by(slug="wohnen").first() response = logged_in_client.post( f"/planning/2026-04/community-accounts/{community_account.id}", data={ "name": community_account.name, "description": community_account.description or "", "category_ids": [str(category.id)], }, ) db.session.refresh(category) assert response.status_code == 302 assert category.community_account_id == community_account.id def test_community_account_rejects_budget_assigned_to_other_account(logged_in_client): primary_account = CommunityAccount.query.filter_by(slug="hauptkonto").first() secondary_response = logged_in_client.post( "/planning/2026-04/community-accounts", data={"name": "Fixkostenkonto", "description": ""}, follow_redirects=True, ) assert secondary_response.status_code == 200 secondary_account = CommunityAccount.query.filter_by(slug="fixkostenkonto").first() category = Category.query.filter_by(slug="wohnen").first() category.community_account_id = primary_account.id db.session.commit() response = logged_in_client.post( f"/planning/2026-04/community-accounts/{secondary_account.id}", data={ "name": secondary_account.name, "description": secondary_account.description or "", "category_ids": [str(category.id)], }, follow_redirects=True, ) db.session.refresh(category) assert response.status_code == 200 assert category.community_account_id == primary_account.id assert b"bereits anderen Konten zugewiesen" in response.data def test_community_account_can_be_deleted_and_unassigns_budgets(logged_in_client): community_account = CommunityAccount.query.filter_by(slug="hauptkonto").first() category = Category.query.filter_by(slug="wohnen").first() category.community_account_id = community_account.id db.session.commit() response = logged_in_client.post( f"/planning/2026-04/community-accounts/{community_account.id}/delete" ) db.session.refresh(category) db.session.refresh(community_account) assert response.status_code == 302 assert community_account.is_active is False assert category.community_account_id is None