From f2df88d0914c18e47f8e4302baf4f22c76ac2f2c Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Thu, 29 Dec 2022 19:45:07 +0100 Subject: [PATCH] Add account creation and selection --- ...nt_snapshot_account_transaction_account.py | 80 ++++++++++ nummi/main/models.py | 142 +++++++++++------- nummi/main/templates/main/account_form.html | 22 +++ nummi/main/urls.py | 7 + nummi/main/views.py | 36 +++-- 5 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 nummi/main/migrations/0013_account_snapshot_account_transaction_account.py create mode 100644 nummi/main/templates/main/account_form.html diff --git a/nummi/main/migrations/0013_account_snapshot_account_transaction_account.py b/nummi/main/migrations/0013_account_snapshot_account_transaction_account.py new file mode 100644 index 0000000..d4a0e82 --- /dev/null +++ b/nummi/main/migrations/0013_account_snapshot_account_transaction_account.py @@ -0,0 +1,80 @@ +# Generated by Django 4.1.4 on 2022-12-29 18:32 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("main", "0012_alter_snapshot_date"), + ] + + operations = [ + migrations.CreateModel( + name="Account", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "name", + models.CharField( + default="Account", max_length=64, verbose_name="Nom" + ), + ), + ( + "icon", + models.CharField( + default="folder", max_length=64, verbose_name="IcĂ´ne" + ), + ), + ( + "user", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Utilisateur", + ), + ), + ], + options={ + "verbose_name": "Account", + "verbose_name_plural": "Accounts", + "ordering": ["name"], + }, + ), + migrations.AddField( + model_name="snapshot", + name="account", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.account", + verbose_name="Account", + ), + ), + migrations.AddField( + model_name="transaction", + name="account", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.account", + verbose_name="Account", + ), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index f9d25f7..8e86065 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -2,12 +2,12 @@ import pathlib import uuid from datetime import date +from django.contrib.auth.models import User from django.core.validators import FileExtensionValidator from django.db import models from django.forms import ModelForm from django.urls import reverse from django.utils.translation import gettext as _ -from django.contrib.auth.models import User class UserModel(models.Model): @@ -19,7 +19,57 @@ class UserModel(models.Model): abstract = True -class Category(UserModel): +class CustomModel(UserModel): + @property + def adding(self): + return self._state.adding + + class Meta: + abstract = True + + +class Account(CustomModel): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + name = models.CharField(max_length=64, default=_("Account"), verbose_name=_("Name")) + icon = models.CharField(max_length=64, default="folder", verbose_name=_("Icon")) + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse("account", kwargs={"pk": self.pk}) + + def get_delete_url(self): + return reverse("del_account", kwargs={"pk": self.pk}) + + @property + def transactions(self): + return Transaction.objects.filter(account=self) + + @property + def snapshots(self): + return Snapshot.objects.filter(account=self) + + class Meta: + ordering = ["name"] + verbose_name = _("Account") + verbose_name_plural = _("Accounts") + + +class AccountModel(CustomModel): + account = models.ForeignKey( + Account, + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name=_("Account"), + ) + + class Meta: + abstract = True + + +class Category(CustomModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField( max_length=64, default=_("Category"), verbose_name=_("Name") @@ -36,10 +86,6 @@ class Category(UserModel): def get_delete_url(self): return reverse("del_category", kwargs={"pk": self.pk}) - @property - def adding(self): - return self._state.adding - @property def transactions(self): return Transaction.objects.filter(category=self) @@ -50,15 +96,7 @@ class Category(UserModel): verbose_name_plural = _("Categories") -class CategoryForm(ModelForm): - template_name = "main/form/base.html" - - class Meta: - model = Category - fields = ["name", "icon", "budget"] - - -class Transaction(UserModel): +class Transaction(AccountModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField( max_length=256, default=_("Transaction"), verbose_name=_("Name") @@ -92,10 +130,6 @@ class Transaction(UserModel): def get_delete_url(self): return reverse("del_transaction", kwargs={"pk": self.pk}) - @property - def adding(self): - return self._state.adding - @property def invoices(self): return Invoice.objects.filter(transaction=self) @@ -110,28 +144,11 @@ class Transaction(UserModel): verbose_name_plural = _("Transactions") -class TransactionForm(ModelForm): - template_name = "main/form/base.html" - - class Meta: - model = Transaction - fields = [ - "date", - "name", - "value", - "trader", - "category", - "real_date", - "payment", - "description", - ] - - def invoice_path(instance, filename): return pathlib.Path("invoices", str(instance.id)).with_suffix(".pdf") -class Invoice(UserModel): +class Invoice(CustomModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField( max_length=256, default=_("Invoice"), verbose_name=_("Name") @@ -165,29 +182,16 @@ class Invoice(UserModel): "del_invoice", kwargs={"transaction_pk": self.transaction.pk, "pk": self.pk} ) - @property - def adding(self): - return self._state.adding - class Meta: verbose_name = _("Invoice") verbose_name_plural = _("Invoices") -class InvoiceForm(ModelForm): - template_name = "main/form/base.html" - prefix = "invoice" - - class Meta: - model = Invoice - fields = "__all__" - - def snapshot_path(instance, filename): return pathlib.Path("snapshots", str(instance.id)).with_suffix(".pdf") -class Snapshot(UserModel): +class Snapshot(AccountModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) date = models.DateField(default=date.today, verbose_name=_("Date")) value = models.DecimalField( @@ -284,10 +288,6 @@ class Snapshot(UserModel): def get_delete_url(self): return reverse("del_snapshot", kwargs={"pk": self.pk}) - @property - def adding(self): - return self._state.adding - @property def sum(self): if self.previous is None: @@ -327,9 +327,37 @@ class Snapshot(UserModel): verbose_name_plural = _("Snapshots") -class SnapshotForm(ModelForm): +class NummiForm(ModelForm): template_name = "main/form/base.html" + +class AccountForm(NummiForm): + class Meta: + model = Account + fields = "__all__" + + +class CategoryForm(NummiForm): + class Meta: + model = Category + fields = "__all__" + + +class TransactionForm(NummiForm): + class Meta: + model = Transaction + fields = "__all__" + + +class InvoiceForm(NummiForm): + prefix = "invoice" + + class Meta: + model = Invoice + fields = "__all__" + + +class SnapshotForm(NummiForm): class Meta: model = Snapshot - fields = ["date", "value", "file"] + fields = "__all__" diff --git a/nummi/main/templates/main/account_form.html b/nummi/main/templates/main/account_form.html new file mode 100644 index 0000000..ce55c42 --- /dev/null +++ b/nummi/main/templates/main/account_form.html @@ -0,0 +1,22 @@ +{% extends "main/base.html" %} +{% load static %} +{% load main_extras %} +{% load i18n %} +{% block link %} + {{ block.super }} + + +{% endblock %} +{% block body %} +

+ {{ form.instance }} +

+
+ {% csrf_token %} + {{ form }} +
+{% endblock %} diff --git a/nummi/main/urls.py b/nummi/main/urls.py index ba79575..d4abfe1 100644 --- a/nummi/main/urls.py +++ b/nummi/main/urls.py @@ -7,6 +7,7 @@ urlpatterns = [ path("login", views.LoginView.as_view(), name="login"), path("logout", views.LogoutView.as_view(), name="logout"), path("transactions", views.TransactionListView.as_view(), name="transactions"), + path("account", views.AccountCreateView.as_view(), name="account"), path("transaction", views.TransactionCreateView.as_view(), name="transaction"), path( "transaction//invoice", @@ -15,6 +16,7 @@ urlpatterns = [ ), path("category", views.CategoryCreateView.as_view(), name="category"), path("snapshot", views.SnapshotCreateView.as_view(), name="snapshot"), + path("account/", views.AccountUpdateView.as_view(), name="account"), path("transaction/", views.TransactionUpdateView.as_view(), name="transaction"), path( "transaction//invoice/", @@ -23,6 +25,11 @@ urlpatterns = [ ), path("category/", views.CategoryUpdateView.as_view(), name="category"), path("snapshot/", views.SnapshotUpdateView.as_view(), name="snapshot"), + path( + "account//delete", + views.AccountDeleteView.as_view(), + name="del_account", + ), path( "transaction//delete", views.TransactionDeleteView.as_view(), diff --git a/nummi/main/views.py b/nummi/main/views.py index 8e5cd72..495a9d6 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -19,6 +19,8 @@ from django.views.generic import ( from django.views.generic.edit import ProcessFormView from .models import ( + Account, + AccountForm, Category, CategoryForm, Invoice, @@ -52,6 +54,11 @@ class UserCreateView(LoginRequiredMixin, CreateView): return super().form_valid(form) +class NummiDeleteView(UserMixin, DeleteView): + template_name = "main/confirm_delete.html" + success_url = reverse_lazy("index") + + class LoginView(auth_views.LoginView): template_name = "main/login.html" next_page = "index" @@ -68,6 +75,11 @@ class TransactionListView(UserMixin, ListView): context_object_name = "transactions" +class AccountCreateView(UserCreateView): + model = Account + form_class = AccountForm + + class TransactionCreateView(UserCreateView): model = Transaction form_class = TransactionForm @@ -98,6 +110,11 @@ class SnapshotCreateView(UserCreateView): form_class = SnapshotForm +class AccountUpdateView(UserMixin, UpdateView): + model = Account + form_class = AccountForm + + class TransactionUpdateView(UserMixin, UpdateView): model = Transaction form_class = TransactionForm @@ -132,15 +149,16 @@ class SnapshotUpdateView(UserMixin, UpdateView): form_class = SnapshotForm -class TransactionDeleteView(UserMixin, DeleteView): +class AccountDeleteView(NummiDeleteView): + model = Account + + +class TransactionDeleteView(NummiDeleteView): model = Transaction - template_name = "main/confirm_delete.html" - success_url = reverse_lazy("index") -class InvoiceDeleteView(UserMixin, DeleteView): +class InvoiceDeleteView(NummiDeleteView): model = Invoice - template_name = "main/confirm_delete.html" def get_success_url(self): return reverse_lazy("transaction", kwargs={"pk": self.object.transaction.pk}) @@ -151,16 +169,12 @@ class InvoiceDeleteView(UserMixin, DeleteView): ) -class CategoryDeleteView(UserMixin, DeleteView): +class CategoryDeleteView(NummiDeleteView): model = Category - template_name = "main/confirm_delete.html" - success_url = reverse_lazy("index") -class SnapshotDeleteView(UserMixin, DeleteView): +class SnapshotDeleteView(NummiDeleteView): model = Snapshot - template_name = "main/confirm_delete.html" - success_url = reverse_lazy("index") class SearchView(UserMixin, ListView, ProcessFormView):