Files
Andros Fenollosa 19f4e84a30 Remove user FK from all models, add goals and promises
- Remove user ForeignKey from all 7 models (single-user app)
- Update all views, handlers, forms, admin, API, seed, and tests
- Add MonthlyGoal model with goals and promises sections
- Goals/promises: add, toggle (strikethrough), delete via LiveView
2026-03-18 15:18:50 +01:00

260 lines
6.3 KiB
Python

from django.template.loader import render_to_string
from liveview import liveview_handler, send
from app.expenses.models import Category, FixedExpenseConcept, Subcategory
def _render_categories(editing_category=None, editing_subcategory=None):
categories = Category.objects.prefetch_related("subcategories").all()
return render_to_string(
"pages/expenses/partials/categories_section.html",
{
"categories": categories,
"editing_category": editing_category,
"editing_subcategory": editing_subcategory,
},
)
def _render_fixed_expenses(editing_id=None):
fixed_expenses = FixedExpenseConcept.objects.all()
return render_to_string(
"pages/expenses/partials/fixed_expenses_section.html",
{"fixed_expenses": fixed_expenses, "editing_id": editing_id},
)
# --- Categories ---
@liveview_handler("add_category")
def add_category(consumer, content):
form = content.get("form", {})
name = form.get("cat_name", "").strip()
order = form.get("cat_order", "0")
if not name:
return
try:
order = int(order)
except ValueError:
order = 0
Category.objects.create(name=name, order=order)
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("edit_category")
def edit_category(consumer, content):
data = content.get("data", {})
cat_id = data.get("data_id", "")
if not cat_id:
return
try:
category = Category.objects.get(id=cat_id)
except Category.DoesNotExist:
return
html = _render_categories(editing_category=category.id)
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("save_category")
def save_category(consumer, content):
form = content.get("form", {})
cat_id = form.get("cat_id", "")
name = form.get("cat_name", "").strip()
order = form.get("cat_order", "0")
if not cat_id or not name:
return
try:
category = Category.objects.get(id=cat_id)
category.name = name
category.order = int(order)
category.save()
except (Category.DoesNotExist, ValueError):
return
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("delete_category")
def delete_category(consumer, content):
data = content.get("data", {})
cat_id = data.get("data_id", "")
if not cat_id:
return
Category.objects.filter(id=cat_id).delete()
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("cancel_edit_settings")
def cancel_edit_settings(consumer, content):
data = content.get("data", {})
section = data.get("data_section", "categories")
if section == "fixed_expenses":
html = _render_fixed_expenses()
send(consumer, {"target": "#fixed-expenses-section", "html": html})
else:
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
# --- Subcategories ---
@liveview_handler("add_subcategory")
def add_subcategory(consumer, content):
form = content.get("form", {})
name = form.get("sub_name", "").strip()
order = form.get("sub_order", "0")
cat_id = form.get("sub_category_id", "")
if not name or not cat_id:
return
try:
category = Category.objects.get(id=cat_id)
order = int(order)
except (Category.DoesNotExist, ValueError):
return
Subcategory.objects.create(name=name, order=order, category=category)
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("edit_subcategory")
def edit_subcategory(consumer, content):
data = content.get("data", {})
sub_id = data.get("data_id", "")
if not sub_id:
return
try:
sub = Subcategory.objects.get(id=sub_id)
except Subcategory.DoesNotExist:
return
html = _render_categories(editing_subcategory=sub.id)
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("save_subcategory")
def save_subcategory(consumer, content):
form = content.get("form", {})
sub_id = form.get("sub_id", "")
name = form.get("sub_name", "").strip()
order = form.get("sub_order", "0")
if not sub_id or not name:
return
try:
sub = Subcategory.objects.get(id=sub_id)
sub.name = name
sub.order = int(order)
sub.save()
except (Subcategory.DoesNotExist, ValueError):
return
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
@liveview_handler("delete_subcategory")
def delete_subcategory_handler(consumer, content):
data = content.get("data", {})
sub_id = data.get("data_id", "")
if not sub_id:
return
try:
sub = Subcategory.objects.get(id=sub_id)
if sub.order == 99:
return
other = Subcategory.objects.get(category=sub.category, order=99)
sub.expenses.update(subcategory=other)
sub.delete()
except Subcategory.DoesNotExist:
return
html = _render_categories()
send(consumer, {"target": "#categories-section", "html": html})
# --- Fixed Expenses ---
@liveview_handler("add_fixed_expense")
def add_fixed_expense(consumer, content):
form = content.get("form", {})
name = form.get("fe_name", "").strip()
order = form.get("fe_order", "0")
if not name:
return
try:
order = int(order)
except ValueError:
order = 0
FixedExpenseConcept.objects.create(name=name, order=order)
html = _render_fixed_expenses()
send(consumer, {"target": "#fixed-expenses-section", "html": html})
@liveview_handler("edit_fixed_expense")
def edit_fixed_expense(consumer, content):
data = content.get("data", {})
fe_id = data.get("data_id", "")
if not fe_id:
return
html = _render_fixed_expenses(editing_id=int(fe_id))
send(consumer, {"target": "#fixed-expenses-section", "html": html})
@liveview_handler("save_fixed_expense")
def save_fixed_expense(consumer, content):
form = content.get("form", {})
fe_id = form.get("fe_id", "")
name = form.get("fe_name", "").strip()
order = form.get("fe_order", "0")
if not fe_id or not name:
return
try:
fe = FixedExpenseConcept.objects.get(id=fe_id)
fe.name = name
fe.order = int(order)
fe.save()
except (FixedExpenseConcept.DoesNotExist, ValueError):
return
html = _render_fixed_expenses()
send(consumer, {"target": "#fixed-expenses-section", "html": html})
@liveview_handler("delete_fixed_expense")
def delete_fixed_expense_handler(consumer, content):
data = content.get("data", {})
fe_id = data.get("data_id", "")
if not fe_id:
return
FixedExpenseConcept.objects.filter(id=fe_id).delete()
html = _render_fixed_expenses()
send(consumer, {"target": "#fixed-expenses-section", "html": html})