diff --git a/expenses_manager/expenses/templates/categories/confirm_delete.html b/expenses_manager/expenses/templates/categories/confirm_delete.html new file mode 100644 index 0000000..87b4140 --- /dev/null +++ b/expenses_manager/expenses/templates/categories/confirm_delete.html @@ -0,0 +1,38 @@ +{% extends "expenses/base.html" %} + +{% block title %} + Categorías +{% endblock %} + +{% block content %} +

Eliminar categoría

+ +

¿Seguro que quieres eliminar la categoría {{ category.name }}?

+ + {% if expense_count %} +

+ Esta categoría tiene {{ expense_count }} gasto{{ expense_count|pluralize }} asociado{{ expense_count|pluralize }} + y no se puede eliminar. Reasigna esos gastos a otra categoría primero. +

+ {% else %} + {% if children %} +

+ Atención: también se eliminarán sus subcategorías: + {% for child in children %}{{child.name}}{% if not forloop.last %}, {% endif %}{% endfor %}. +

+ {% endif %} + + {% if goal_count %} +

+ Atención: se eliminarán también {{ goal_count }} objetivo{{ goal_count|pluralize }} asociado{{ goal_count|pluralize }} a esta categoría. +

+ {% endif %} + {% endif %} + +
+ {% csrf_token %} + {{ form.as_p }} + + Cancelar +
+{% endblock %} \ No newline at end of file diff --git a/expenses_manager/expenses/templates/categories/form.html b/expenses_manager/expenses/templates/categories/form.html new file mode 100644 index 0000000..e45d9c1 --- /dev/null +++ b/expenses_manager/expenses/templates/categories/form.html @@ -0,0 +1,16 @@ +{% extends "expenses/base.html" %} + +{% block title %} + Categorías +{% endblock %} + +{% block content %} +

Editar categoría

+ +
+ {% csrf_token %} + {{ form.as_p }} + + Cancelar +
+{% endblock %} \ No newline at end of file diff --git a/expenses_manager/expenses/templates/categories/list.html b/expenses_manager/expenses/templates/categories/list.html index f89d645..24826ab 100644 --- a/expenses_manager/expenses/templates/categories/list.html +++ b/expenses_manager/expenses/templates/categories/list.html @@ -30,6 +30,10 @@ {{ category.name }} {% if category.parent %}{{ category.parent.name }}{% endif %} + + Editar + Eliminar + {% endfor %} diff --git a/expenses_manager/expenses/urls.py b/expenses_manager/expenses/urls.py index 47e1f56..ad395e9 100644 --- a/expenses_manager/expenses/urls.py +++ b/expenses_manager/expenses/urls.py @@ -24,6 +24,8 @@ urlpatterns = [ path('fuel/create/', views.fuel_create, name='fuel_create'), path('fuel//edit/', views.fuel_edit, name='fuel_edit'), path('categories/', views.category_list, name='category_list'), + path('categories//edit/', views.category_edit, name='category_edit'), + path('categories//delete/', views.category_delete, name='category_delete'), path('settings/', views.settings_index, name='settings_index'), path('goals/', views.goal_list, name='goal_list'), path('goals/new/', views.goal_create, name='goal_create'), diff --git a/expenses_manager/expenses/views.py b/expenses_manager/expenses/views.py index ecd3f04..69817c0 100644 --- a/expenses_manager/expenses/views.py +++ b/expenses_manager/expenses/views.py @@ -13,8 +13,8 @@ from .forms import ( GoalForm, ) -from django.db.models import Sum from django.core.paginator import Paginator +from django.db.models import Sum, ProtectedError from django.db.models.functions import ExtractMonth, ExtractYear, ExtractDay from django.contrib.auth.decorators import login_required @@ -859,6 +859,60 @@ def category_list(request): ) +@login_required +def category_edit(request, pk): + category = get_object_or_404(Category, pk=pk, owner=request.user) + + if request.method == "POST": + form = CategoryForm(request.POST, instance=category, user=request.user) + if form.is_valid(): + form.save() + messages.success(request, "Categoría actualizada") + return redirect("category_list") + else: + form = CategoryForm(instance=category, user=request.user) + + return render( + request, + "categories/form.html", + { + "active_menu": "settings", + "form":form, + "category": category, + } + ) + + +@login_required +def category_delete(request, pk): + category = get_object_or_404(Category, pk=pk, owner=request.user) + + if request.method == "POST": + try: + category.delete() + except ProtectedError: + messages.error( + request, + f"No se puede eliminar «{category.name}»; tiene gastos asociados. " + "Reasigna esos gastos a otra categoría antes de borrarla." + ) + else: + messages.success(request, "Categoría eliminada.") + return redirect("category_list") + + return render( + request, + "categories/confirm_delete.html", + { + "active_menu": "settings", + "category": category, + "children": category.children.all(), + "expense_count": category.expenses.count(), + "goal_count": category.goal_set.count(), + }, + ) + + @login_required def goal_list(request): goals = Goal.objects.filter(owner=request.user)