fix: start with empty budgets and savings categories

This commit is contained in:
2026-04-21 21:37:04 +02:00
parent 35af65dd25
commit 8bf37c82b6
3 changed files with 123 additions and 86 deletions
+5 -14
View File
@@ -266,7 +266,11 @@ def detail(label: str):
) )
month_values = {item.entry_id: item for item in month.entry_values} month_values = {item.entry_id: item for item in month.entry_values}
distribution_bucket = { distribution_bucket = {
"account": None, "account": type(
"SyntheticAccount",
(),
{"name": "Sparen & Verteilung", "slug": "sparen-und-verteilung"},
)(),
"categories": [], "categories": [],
"total": Decimal("0.00"), "total": Decimal("0.00"),
} }
@@ -337,12 +341,6 @@ def detail(label: str):
} }
) )
if account.slug in {"sparen", "urlaub", "freizeit"}: if account.slug in {"sparen", "urlaub", "freizeit"}:
if distribution_bucket["account"] is None:
distribution_bucket["account"] = type(
"SyntheticAccount",
(),
{"name": "Sparen & Verteilung", "slug": "sparen-und-verteilung"},
)()
distribution_bucket["categories"].append( distribution_bucket["categories"].append(
{ {
"category": type( "category": type(
@@ -372,12 +370,6 @@ def detail(label: str):
distribution_bucket["total"] += account_total distribution_bucket["total"] += account_total
continue continue
if account.slug in {"persoenlich-flo", "persoenlich-desi"}: if account.slug in {"persoenlich-flo", "persoenlich-desi"}:
if distribution_bucket["account"] is None:
distribution_bucket["account"] = type(
"SyntheticAccount",
(),
{"name": "Sparen & Verteilung", "slug": "sparen-und-verteilung"},
)()
personal_category = next( personal_category = next(
(item for item in distribution_bucket["categories"] if item.get("is_personal_split")), (item for item in distribution_bucket["categories"] if item.get("is_personal_split")),
None, None,
@@ -412,7 +404,6 @@ def detail(label: str):
planning_accounts.append( planning_accounts.append(
{"account": account, "categories": category_cards, "total": account_total} {"account": account, "categories": category_cards, "total": account_total}
) )
if distribution_bucket["account"] is not None:
personal_category = next( personal_category = next(
(item for item in distribution_bucket["categories"] if item.get("is_personal_split")), (item for item in distribution_bucket["categories"] if item.get("is_personal_split")),
None, None,
+48 -12
View File
@@ -137,6 +137,12 @@ EXAMPLE_ENTRY_NAMES = {
for entry_name in entries for entry_name in entries
} }
EXAMPLE_CATEGORY_KEYS = {
(account_slug, category_slug)
for account_slug, account_data in ACCOUNT_TREE.items()
for category_slug in account_data["categories"].keys()
}
def slugify(value: str) -> str: def slugify(value: str) -> str:
return ( return (
@@ -150,12 +156,7 @@ def slugify(value: str) -> str:
) )
def _deactivate_placeholder_entries() -> None: def _entry_has_user_data(entry: Entry) -> bool:
example_entries = (
Entry.query.filter(Entry.name.in_(sorted(EXAMPLE_ENTRY_NAMES)), Entry.is_active.is_(True)).all()
)
for entry in example_entries:
has_user_data = False
for value in entry.monthly_values: for value in entry.monthly_values:
if ( if (
to_decimal(value.planned_amount) != Decimal("0.00") to_decimal(value.planned_amount) != Decimal("0.00")
@@ -163,15 +164,45 @@ def _deactivate_placeholder_entries() -> None:
or value.created_by is not None or value.created_by is not None
or value.updated_by is not None or value.updated_by is not None
): ):
has_user_data = True return True
break
if entry.share_rules: if entry.share_rules:
has_user_data = True return True
if has_user_data: return False
def _deactivate_placeholder_entries() -> None:
example_entries = Entry.query.filter(
Entry.name.in_(sorted(EXAMPLE_ENTRY_NAMES)),
Entry.is_active.is_(True),
).all()
for entry in example_entries:
if _entry_has_user_data(entry):
continue continue
entry.is_active = False entry.is_active = False
def _deactivate_placeholder_categories() -> None:
categories = (
Category.query.join(Account)
.filter(Category.is_active.is_(True), Account.is_active.is_(True))
.all()
)
for category in categories:
account = category.account
if account is None or (account.slug, category.slug) not in EXAMPLE_CATEGORY_KEYS:
continue
active_entries = [entry for entry in category.entries if entry.is_active]
if not active_entries:
category.is_active = False
category.community_account_id = None
continue
if all(entry.name in EXAMPLE_ENTRY_NAMES and not _entry_has_user_data(entry) for entry in active_entries):
for entry in active_entries:
entry.is_active = False
category.is_active = False
category.community_account_id = None
def seed_data(include_example_entries: bool = False) -> None: def seed_data(include_example_entries: bool = False) -> None:
# Basisdaten nur für die fachliche Grundstruktur, ohne Demo-Benutzer, # Basisdaten nur für die fachliche Grundstruktur, ohne Demo-Benutzer,
# Beispiel-Personen oder vorausgefüllte Monatsdaten. # Beispiel-Personen oder vorausgefüllte Monatsdaten.
@@ -225,6 +256,8 @@ def seed_data(include_example_entries: bool = False) -> None:
sort_order += 1 sort_order += 1
category_sort = 1 category_sort = 1
account_categories[account_slug] = {} account_categories[account_slug] = {}
if not include_example_entries:
continue
for category_slug, entries in account_data["categories"].items(): for category_slug, entries in account_data["categories"].items():
category = Category.query.filter_by(account_id=account.id, slug=category_slug).first() category = Category.query.filter_by(account_id=account.id, slug=category_slug).first()
legacy_slug = LEGACY_CATEGORY_SLUGS.get((account_slug, category_slug)) legacy_slug = LEGACY_CATEGORY_SLUGS.get((account_slug, category_slug))
@@ -254,8 +287,6 @@ def seed_data(include_example_entries: bool = False) -> None:
category.community_account_id = community_accounts["hauptkonto"].id category.community_account_id = community_accounts["hauptkonto"].id
account_categories[account_slug][category_slug] = category account_categories[account_slug][category_slug] = category
category_sort += 1 category_sort += 1
if not include_example_entries:
continue
for index, entry_name in enumerate(entries, start=1): for index, entry_name in enumerate(entries, start=1):
default_amount = Decimal("0.00") default_amount = Decimal("0.00")
if entry_name == "Miete": if entry_name == "Miete":
@@ -362,6 +393,7 @@ def seed_data(include_example_entries: bool = False) -> None:
"Person 2", "Person 2",
} }
else: else:
_deactivate_placeholder_categories()
_deactivate_placeholder_entries() _deactivate_placeholder_entries()
for category in gemeinschaft.categories: for category in gemeinschaft.categories:
if category.slug not in ACCOUNT_TREE["gemeinschaftskonto"]["categories"]: if category.slug not in ACCOUNT_TREE["gemeinschaftskonto"]["categories"]:
@@ -369,6 +401,10 @@ def seed_data(include_example_entries: bool = False) -> None:
elif category.community_account_id is None: elif category.community_account_id is None:
category.community_account_id = community_accounts["hauptkonto"].id category.community_account_id = community_accounts["hauptkonto"].id
if not include_example_entries:
_deactivate_placeholder_categories()
_deactivate_placeholder_entries()
db.session.commit() db.session.commit()
+12 -2
View File
@@ -117,7 +117,6 @@
<section class="account-board"> <section class="account-board">
{% for account_data in planning_accounts %} {% for account_data in planning_accounts %}
{% if account_data.categories %}
<article class="panel account-panel premium-panel"> <article class="panel account-panel premium-panel">
<div class="panel-head account-head"> <div class="panel-head account-head">
<div> <div>
@@ -146,6 +145,7 @@
</button> </button>
{% endif %} {% endif %}
</div> </div>
{% if account_data.categories %}
<div class="category-summary-grid"> <div class="category-summary-grid">
{% for category_data in account_data.categories %} {% for category_data in account_data.categories %}
<button type="button" class="summary-category-card {% if category_data.distribution_hint and category_data.distribution_hint.status %}range-status-{{ category_data.distribution_hint.status }}{% endif %}" data-open-dialog="{{ category_data.dialog_id }}"> <button type="button" class="summary-category-card {% if category_data.distribution_hint and category_data.distribution_hint.status %}range-status-{{ category_data.distribution_hint.status }}{% endif %}" data-open-dialog="{{ category_data.dialog_id }}">
@@ -184,8 +184,18 @@
</button> </button>
{% endfor %} {% endfor %}
</div> </div>
</article> {% else %}
<div class="empty-state">
{% if account_data.account.slug == "gemeinschaftskonto" %}
Noch keine Budgets angelegt. Lege die erste Budget-Kategorie direkt hier an.
{% elif account_data.account.slug == "sparen-und-verteilung" %}
Noch keine Sparkonten angelegt. Lege Sparen, Urlaub oder weitere Verteilungsziele erst bei Bedarf an.
{% else %}
In diesem Bereich gibt es noch keine Kategorien.
{% endif %} {% endif %}
</div>
{% endif %}
</article>
{% endfor %} {% endfor %}
</section> </section>