179 lines
6.4 KiB
Python
179 lines
6.4 KiB
Python
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
|