Fixed bugs 2 #15

Merged
jkuijperm merged 13 commits from dev into main 2026-07-24 09:38:43 +00:00
5 changed files with 115 additions and 1 deletions
Showing only changes of commit 03016209b0 - Show all commits

View File

@ -0,0 +1,38 @@
{% extends "expenses/base.html" %}
{% block title %}
Categorías
{% endblock %}
{% block content %}
<h2>Eliminar categoría</h2>
<p>¿Seguro que quieres eliminar la categoría <strong>{{ category.name }}</strong>?</p>
{% if expense_count %}
<p class="form-errors">
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.
</p>
{% else %}
{% if children %}
<p class="form-errors">
Atención: también se eliminarán sus subcategorías:
{% for child in children %}<strong>{{child.name}}</strong>{% if not forloop.last %}, {% endif %}{% endfor %}.
</p>
{% endif %}
{% if goal_count %}
<p class="form-errors">
Atención: se eliminarán también {{ goal_count }} objetivo{{ goal_count|pluralize }} asociado{{ goal_count|pluralize }} a esta categoría.
</p>
{% endif %}
{% endif %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn danger">Eliminar</button>
<a class="btn" href="{% url 'category_list' %}">Cancelar</a>
</form>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends "expenses/base.html" %}
{% block title %}
Categorías
{% endblock %}
{% block content %}
<h2>Editar categoría</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Guardar</button>
<a class="btn" href="{% url 'category_list' %}">Cancelar</a>
</form>
{% endblock %}

View File

@ -30,6 +30,10 @@
<tr> <tr>
<td>{{ category.name }}</td> <td>{{ category.name }}</td>
<td>{% if category.parent %}{{ category.parent.name }}{% endif %}</td> <td>{% if category.parent %}{{ category.parent.name }}{% endif %}</td>
<td class="table-actions">
<a href="{% url 'category_edit' category.id %}">Editar</a>
<a href="{% url 'category_delete' category.id %}" class="danger">Eliminar</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -24,6 +24,8 @@ urlpatterns = [
path('fuel/create/', views.fuel_create, name='fuel_create'), path('fuel/create/', views.fuel_create, name='fuel_create'),
path('fuel/<int:pk>/edit/', views.fuel_edit, name='fuel_edit'), path('fuel/<int:pk>/edit/', views.fuel_edit, name='fuel_edit'),
path('categories/', views.category_list, name='category_list'), path('categories/', views.category_list, name='category_list'),
path('categories/<int:pk>/edit/', views.category_edit, name='category_edit'),
path('categories/<int:pk>/delete/', views.category_delete, name='category_delete'),
path('settings/', views.settings_index, name='settings_index'), path('settings/', views.settings_index, name='settings_index'),
path('goals/', views.goal_list, name='goal_list'), path('goals/', views.goal_list, name='goal_list'),
path('goals/new/', views.goal_create, name='goal_create'), path('goals/new/', views.goal_create, name='goal_create'),

View File

@ -13,8 +13,8 @@ from .forms import (
GoalForm, GoalForm,
) )
from django.db.models import Sum
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db.models import Sum, ProtectedError
from django.db.models.functions import ExtractMonth, ExtractYear, ExtractDay from django.db.models.functions import ExtractMonth, ExtractYear, ExtractDay
from django.contrib.auth.decorators import login_required 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 @login_required
def goal_list(request): def goal_list(request):
goals = Goal.objects.filter(owner=request.user) goals = Goal.objects.filter(owner=request.user)