diff --git a/app/apps/transactions/forms.py b/app/apps/transactions/forms.py index 486ab53..509ded2 100644 --- a/app/apps/transactions/forms.py +++ b/app/apps/transactions/forms.py @@ -615,7 +615,7 @@ class RecurringTransactionForm(forms.ModelForm): end_date = cleaned_data.get("end_date") if start_date and end_date and start_date > end_date: - raise forms.ValidationError("End date should be after the start date.") + raise forms.ValidationError(_("End date should be after the start date")) return cleaned_data diff --git a/app/apps/transactions/migrations/0022_rename_paused_recurringtransaction_is_paused.py b/app/apps/transactions/migrations/0022_rename_paused_recurringtransaction_is_paused.py new file mode 100644 index 0000000..c120562 --- /dev/null +++ b/app/apps/transactions/migrations/0022_rename_paused_recurringtransaction_is_paused.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2024-11-05 02:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('transactions', '0021_alter_transaction_account'), + ] + + operations = [ + migrations.RenameField( + model_name='recurringtransaction', + old_name='paused', + new_name='is_paused', + ), + ] diff --git a/app/apps/transactions/models.py b/app/apps/transactions/models.py index 291fea2..14889b9 100644 --- a/app/apps/transactions/models.py +++ b/app/apps/transactions/models.py @@ -328,7 +328,7 @@ class RecurringTransaction(models.Model): MONTH = "month", _("month(s)") YEAR = "year", _("year(s)") - paused = models.BooleanField(default=False, verbose_name=_("Paused")) + is_paused = models.BooleanField(default=False, verbose_name=_("Paused")) account = models.ForeignKey( "accounts.Account", on_delete=models.CASCADE, verbose_name=_("Account") ) @@ -444,8 +444,8 @@ class RecurringTransaction(models.Model): def generate_upcoming_transactions(cls): today = timezone.now().date() recurring_transactions = cls.objects.filter( - models.Q(models.Q(end_date__isnull=True) | models.Q(end_date__gte=today)) - & models.Q(paused=False) + Q(models.Q(end_date__isnull=True) | Q(end_date__gte=today)) + & Q(paused=False) ) for recurring_transaction in recurring_transactions: diff --git a/app/apps/transactions/urls.py b/app/apps/transactions/urls.py index eedcbdc..f69185d 100644 --- a/app/apps/transactions/urls.py +++ b/app/apps/transactions/urls.py @@ -127,6 +127,21 @@ urlpatterns = [ views.recurring_transactions_list, name="recurring_transaction_list", ), + path( + "recurring-trasanctions/list/active/", + views.active_recurring_transactions_list, + name="active_recurring_transaction_list", + ), + path( + "recurring-trasanctions/list/paused/", + views.paused_recurring_transactions_list, + name="paused_recurring_transaction_list", + ), + path( + "recurring-trasanctions/list/finished/", + views.finished_recurring_transactions_list, + name="finished_recurring_transaction_list", + ), path( "recurring-transactions/add/", views.recurring_transaction_add, @@ -152,4 +167,9 @@ urlpatterns = [ views.recurring_transaction_toggle_pause, name="recurring_transaction_toggle_pause", ), + path( + "recurring-transactions//finish/", + views.recurring_transaction_finish, + name="recurring_transaction_finish", + ), ] diff --git a/app/apps/transactions/views/recurring_transactions.py b/app/apps/transactions/views/recurring_transactions.py index 087a223..b496dc5 100644 --- a/app/apps/transactions/views/recurring_transactions.py +++ b/app/apps/transactions/views/recurring_transactions.py @@ -1,7 +1,11 @@ +from dateutil.relativedelta import relativedelta + from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 +from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods @@ -25,14 +29,60 @@ def recurring_transactions_index(request): @login_required @require_http_methods(["GET"]) def recurring_transactions_list(request): - recurring_transactions = RecurringTransaction.objects.all().order_by( - "-start_date", "description", "id" - ) - return render( request, "recurring_transactions/fragments/list.html", - {"recurring_transactions": recurring_transactions}, + ) + + +@only_htmx +@login_required +@require_http_methods(["GET"]) +def active_recurring_transactions_list(request): + today = timezone.localdate(timezone.now()) + recurring_transactions = RecurringTransaction.objects.filter( + Q(end_date__gte=today) | Q(end_date__isnull=True), + is_paused=False, + ).order_by("-start_date", "description", "id") + + print(recurring_transactions) + return render( + request, + "recurring_transactions/fragments/table.html", + {"recurring_transactions": recurring_transactions, "status": "active"}, + ) + + +@only_htmx +@login_required +@require_http_methods(["GET"]) +def paused_recurring_transactions_list(request): + today = timezone.localdate(timezone.now()) + recurring_transactions = RecurringTransaction.objects.filter( + Q(end_date__gte=today) | Q(end_date__isnull=True), + is_paused=True, + ).order_by("-start_date", "description", "id") + + return render( + request, + "recurring_transactions/fragments/table.html", + {"recurring_transactions": recurring_transactions, "status": "paused"}, + ) + + +@only_htmx +@login_required +@require_http_methods(["GET"]) +def finished_recurring_transactions_list(request): + today = timezone.localdate(timezone.now()) + recurring_transactions = RecurringTransaction.objects.filter( + Q(end_date__lte=today), + ).order_by("-start_date", "description", "id") + + return render( + request, + "recurring_transactions/fragments/table.html", + {"recurring_transactions": recurring_transactions, "status": "finished"}, ) @@ -110,33 +160,16 @@ def recurring_transaction_edit(request, recurring_transaction_id): ) -# @only_htmx -# @login_required -# @require_http_methods(["GET"]) -# def recurring_transaction_refresh(request, installment_plan_id): -# installment_plan = get_object_or_404(InstallmentPlan, id=installment_plan_id) -# installment_plan.update_transactions() -# -# messages.success(request, _("Installment Plan refreshed successfully")) -# -# return HttpResponse( -# status=204, -# headers={ -# "HX-Trigger": "updated, hide_offcanvas, toasts", -# }, -# ) - - @only_htmx @login_required @require_http_methods(["GET"]) def recurring_transaction_toggle_pause(request, recurring_transaction_id): - installment_plan = get_object_or_404( + recurring_transaction = get_object_or_404( RecurringTransaction, id=recurring_transaction_id ) - current_paused = installment_plan.paused - installment_plan.paused = not current_paused - installment_plan.save(update_fields=["paused"]) + current_paused = recurring_transaction.is_paused + recurring_transaction.is_paused = not current_paused + recurring_transaction.save(update_fields=["is_paused"]) if current_paused: messages.success(request, _("Recurring transaction unpaused successfully")) @@ -152,6 +185,29 @@ def recurring_transaction_toggle_pause(request, recurring_transaction_id): ) +@only_htmx +@login_required +@require_http_methods(["GET"]) +def recurring_transaction_finish(request, recurring_transaction_id): + recurring_transaction = get_object_or_404( + RecurringTransaction, id=recurring_transaction_id + ) + today = timezone.localdate(timezone.now()) - relativedelta(days=1) + + recurring_transaction.end_date = today + recurring_transaction.is_paused = True + recurring_transaction.save(update_fields=["end_date", "is_paused"]) + + messages.success(request, _("Recurring transaction finished successfully")) + + return HttpResponse( + status=204, + headers={ + "HX-Trigger": "updated, hide_offcanvas, toasts", + }, + ) + + @only_htmx @login_required @csrf_exempt diff --git a/app/templates/recurring_transactions/fragments/list.html b/app/templates/recurring_transactions/fragments/list.html index 58fc88b..b532788 100644 --- a/app/templates/recurring_transactions/fragments/list.html +++ b/app/templates/recurring_transactions/fragments/list.html @@ -14,82 +14,22 @@ {% endspaceless %} -
- {% if recurring_transactions %} - - - - - - - - - {% for recurring_transaction in recurring_transactions %} - - - - - {% endfor %} - -
{% translate 'Name' %}
-
- - - - - {% if recurring_transaction.paused %} - - {% else %} - - - {% endif %} - -
{{ recurring_transaction.description }}
- {% else %} - - {% endif %} +
+
+ +
+ +
+
-
diff --git a/app/templates/recurring_transactions/fragments/table.html b/app/templates/recurring_transactions/fragments/table.html new file mode 100644 index 0000000..e07e863 --- /dev/null +++ b/app/templates/recurring_transactions/fragments/table.html @@ -0,0 +1,109 @@ +{% load currency_display %} +{% load i18n %} +{% if status == "active" %} +
+{% elif status == 'paused' %} +
+{% elif status == 'finished' %} +
+{% endif %} + {% if recurring_transactions %} +
+ + + + + + + + + {% for recurring_transaction in recurring_transactions %} + + + + + {% endfor %} + +
{% translate 'Name' %}
+
+ + + + + {% if status != 'finished' %} + {% if recurring_transaction.is_paused %} + + {% else %} + + + {% endif %} + + + {% endif %} + +
+
{{ recurring_transaction.description }}
+
+ {% else %} + + {% endif %} +
diff --git a/app/templates/recurring_transactions/pages/index.html b/app/templates/recurring_transactions/pages/index.html index 44172c7..bfcc690 100644 --- a/app/templates/recurring_transactions/pages/index.html +++ b/app/templates/recurring_transactions/pages/index.html @@ -4,5 +4,5 @@ {% block title %}{% translate 'Recurring Transactions' %}{% endblock %} {% block content %} -
+
{% endblock %}