Add account creation and selection
This commit is contained in:
parent
667c6d3da1
commit
f2df88d091
5 changed files with 219 additions and 68 deletions
|
@ -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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,12 +2,12 @@ import pathlib
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.core.validators import FileExtensionValidator
|
from django.core.validators import FileExtensionValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
|
|
||||||
class UserModel(models.Model):
|
class UserModel(models.Model):
|
||||||
|
@ -19,7 +19,57 @@ class UserModel(models.Model):
|
||||||
abstract = True
|
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)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=64, default=_("Category"), verbose_name=_("Name")
|
max_length=64, default=_("Category"), verbose_name=_("Name")
|
||||||
|
@ -36,10 +86,6 @@ class Category(UserModel):
|
||||||
def get_delete_url(self):
|
def get_delete_url(self):
|
||||||
return reverse("del_category", kwargs={"pk": self.pk})
|
return reverse("del_category", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
@property
|
|
||||||
def adding(self):
|
|
||||||
return self._state.adding
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def transactions(self):
|
def transactions(self):
|
||||||
return Transaction.objects.filter(category=self)
|
return Transaction.objects.filter(category=self)
|
||||||
|
@ -50,15 +96,7 @@ class Category(UserModel):
|
||||||
verbose_name_plural = _("Categories")
|
verbose_name_plural = _("Categories")
|
||||||
|
|
||||||
|
|
||||||
class CategoryForm(ModelForm):
|
class Transaction(AccountModel):
|
||||||
template_name = "main/form/base.html"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Category
|
|
||||||
fields = ["name", "icon", "budget"]
|
|
||||||
|
|
||||||
|
|
||||||
class Transaction(UserModel):
|
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=256, default=_("Transaction"), verbose_name=_("Name")
|
max_length=256, default=_("Transaction"), verbose_name=_("Name")
|
||||||
|
@ -92,10 +130,6 @@ class Transaction(UserModel):
|
||||||
def get_delete_url(self):
|
def get_delete_url(self):
|
||||||
return reverse("del_transaction", kwargs={"pk": self.pk})
|
return reverse("del_transaction", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
@property
|
|
||||||
def adding(self):
|
|
||||||
return self._state.adding
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def invoices(self):
|
def invoices(self):
|
||||||
return Invoice.objects.filter(transaction=self)
|
return Invoice.objects.filter(transaction=self)
|
||||||
|
@ -110,28 +144,11 @@ class Transaction(UserModel):
|
||||||
verbose_name_plural = _("Transactions")
|
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):
|
def invoice_path(instance, filename):
|
||||||
return pathlib.Path("invoices", str(instance.id)).with_suffix(".pdf")
|
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)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=256, default=_("Invoice"), verbose_name=_("Name")
|
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}
|
"del_invoice", kwargs={"transaction_pk": self.transaction.pk, "pk": self.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def adding(self):
|
|
||||||
return self._state.adding
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Invoice")
|
verbose_name = _("Invoice")
|
||||||
verbose_name_plural = _("Invoices")
|
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):
|
def snapshot_path(instance, filename):
|
||||||
return pathlib.Path("snapshots", str(instance.id)).with_suffix(".pdf")
|
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)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
date = models.DateField(default=date.today, verbose_name=_("Date"))
|
date = models.DateField(default=date.today, verbose_name=_("Date"))
|
||||||
value = models.DecimalField(
|
value = models.DecimalField(
|
||||||
|
@ -284,10 +288,6 @@ class Snapshot(UserModel):
|
||||||
def get_delete_url(self):
|
def get_delete_url(self):
|
||||||
return reverse("del_snapshot", kwargs={"pk": self.pk})
|
return reverse("del_snapshot", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
@property
|
|
||||||
def adding(self):
|
|
||||||
return self._state.adding
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum(self):
|
def sum(self):
|
||||||
if self.previous is None:
|
if self.previous is None:
|
||||||
|
@ -327,9 +327,37 @@ class Snapshot(UserModel):
|
||||||
verbose_name_plural = _("Snapshots")
|
verbose_name_plural = _("Snapshots")
|
||||||
|
|
||||||
|
|
||||||
class SnapshotForm(ModelForm):
|
class NummiForm(ModelForm):
|
||||||
template_name = "main/form/base.html"
|
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:
|
class Meta:
|
||||||
model = Snapshot
|
model = Snapshot
|
||||||
fields = ["date", "value", "file"]
|
fields = "__all__"
|
||||||
|
|
22
nummi/main/templates/main/account_form.html
Normal file
22
nummi/main/templates/main/account_form.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "main/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load main_extras %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block link %}
|
||||||
|
{{ block.super }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="{% static 'main/css/form.css' %}"
|
||||||
|
type="text/css"/>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="{% static 'main/css/table.css' %}"
|
||||||
|
type="text/css"/>
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
<h1>
|
||||||
|
<i class="fa fa-{{ form.instance.icon }}"></i> {{ form.instance }}
|
||||||
|
</h1>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -7,6 +7,7 @@ urlpatterns = [
|
||||||
path("login", views.LoginView.as_view(), name="login"),
|
path("login", views.LoginView.as_view(), name="login"),
|
||||||
path("logout", views.LogoutView.as_view(), name="logout"),
|
path("logout", views.LogoutView.as_view(), name="logout"),
|
||||||
path("transactions", views.TransactionListView.as_view(), name="transactions"),
|
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", views.TransactionCreateView.as_view(), name="transaction"),
|
||||||
path(
|
path(
|
||||||
"transaction/<transaction_pk>/invoice",
|
"transaction/<transaction_pk>/invoice",
|
||||||
|
@ -15,6 +16,7 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
path("category", views.CategoryCreateView.as_view(), name="category"),
|
path("category", views.CategoryCreateView.as_view(), name="category"),
|
||||||
path("snapshot", views.SnapshotCreateView.as_view(), name="snapshot"),
|
path("snapshot", views.SnapshotCreateView.as_view(), name="snapshot"),
|
||||||
|
path("account/<pk>", views.AccountUpdateView.as_view(), name="account"),
|
||||||
path("transaction/<pk>", views.TransactionUpdateView.as_view(), name="transaction"),
|
path("transaction/<pk>", views.TransactionUpdateView.as_view(), name="transaction"),
|
||||||
path(
|
path(
|
||||||
"transaction/<transaction_pk>/invoice/<pk>",
|
"transaction/<transaction_pk>/invoice/<pk>",
|
||||||
|
@ -23,6 +25,11 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
path("category/<pk>", views.CategoryUpdateView.as_view(), name="category"),
|
path("category/<pk>", views.CategoryUpdateView.as_view(), name="category"),
|
||||||
path("snapshot/<pk>", views.SnapshotUpdateView.as_view(), name="snapshot"),
|
path("snapshot/<pk>", views.SnapshotUpdateView.as_view(), name="snapshot"),
|
||||||
|
path(
|
||||||
|
"account/<pk>/delete",
|
||||||
|
views.AccountDeleteView.as_view(),
|
||||||
|
name="del_account",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"transaction/<pk>/delete",
|
"transaction/<pk>/delete",
|
||||||
views.TransactionDeleteView.as_view(),
|
views.TransactionDeleteView.as_view(),
|
||||||
|
|
|
@ -19,6 +19,8 @@ from django.views.generic import (
|
||||||
from django.views.generic.edit import ProcessFormView
|
from django.views.generic.edit import ProcessFormView
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
|
Account,
|
||||||
|
AccountForm,
|
||||||
Category,
|
Category,
|
||||||
CategoryForm,
|
CategoryForm,
|
||||||
Invoice,
|
Invoice,
|
||||||
|
@ -52,6 +54,11 @@ class UserCreateView(LoginRequiredMixin, CreateView):
|
||||||
return super().form_valid(form)
|
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):
|
class LoginView(auth_views.LoginView):
|
||||||
template_name = "main/login.html"
|
template_name = "main/login.html"
|
||||||
next_page = "index"
|
next_page = "index"
|
||||||
|
@ -68,6 +75,11 @@ class TransactionListView(UserMixin, ListView):
|
||||||
context_object_name = "transactions"
|
context_object_name = "transactions"
|
||||||
|
|
||||||
|
|
||||||
|
class AccountCreateView(UserCreateView):
|
||||||
|
model = Account
|
||||||
|
form_class = AccountForm
|
||||||
|
|
||||||
|
|
||||||
class TransactionCreateView(UserCreateView):
|
class TransactionCreateView(UserCreateView):
|
||||||
model = Transaction
|
model = Transaction
|
||||||
form_class = TransactionForm
|
form_class = TransactionForm
|
||||||
|
@ -98,6 +110,11 @@ class SnapshotCreateView(UserCreateView):
|
||||||
form_class = SnapshotForm
|
form_class = SnapshotForm
|
||||||
|
|
||||||
|
|
||||||
|
class AccountUpdateView(UserMixin, UpdateView):
|
||||||
|
model = Account
|
||||||
|
form_class = AccountForm
|
||||||
|
|
||||||
|
|
||||||
class TransactionUpdateView(UserMixin, UpdateView):
|
class TransactionUpdateView(UserMixin, UpdateView):
|
||||||
model = Transaction
|
model = Transaction
|
||||||
form_class = TransactionForm
|
form_class = TransactionForm
|
||||||
|
@ -132,15 +149,16 @@ class SnapshotUpdateView(UserMixin, UpdateView):
|
||||||
form_class = SnapshotForm
|
form_class = SnapshotForm
|
||||||
|
|
||||||
|
|
||||||
class TransactionDeleteView(UserMixin, DeleteView):
|
class AccountDeleteView(NummiDeleteView):
|
||||||
|
model = Account
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionDeleteView(NummiDeleteView):
|
||||||
model = Transaction
|
model = Transaction
|
||||||
template_name = "main/confirm_delete.html"
|
|
||||||
success_url = reverse_lazy("index")
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDeleteView(UserMixin, DeleteView):
|
class InvoiceDeleteView(NummiDeleteView):
|
||||||
model = Invoice
|
model = Invoice
|
||||||
template_name = "main/confirm_delete.html"
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("transaction", kwargs={"pk": self.object.transaction.pk})
|
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
|
model = Category
|
||||||
template_name = "main/confirm_delete.html"
|
|
||||||
success_url = reverse_lazy("index")
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotDeleteView(UserMixin, DeleteView):
|
class SnapshotDeleteView(NummiDeleteView):
|
||||||
model = Snapshot
|
model = Snapshot
|
||||||
template_name = "main/confirm_delete.html"
|
|
||||||
success_url = reverse_lazy("index")
|
|
||||||
|
|
||||||
|
|
||||||
class SearchView(UserMixin, ListView, ProcessFormView):
|
class SearchView(UserMixin, ListView, ProcessFormView):
|
||||||
|
|
Loading…
Reference in a new issue