Compare commits

..

No commits in common. "7356d02adad8794eedb1b5683dc1e255fa1f9732" and "667c6d3da1e88cab3fabbac37ab0532f63840036" have entirely different histories.

10 changed files with 72 additions and 260 deletions

View file

@ -1,80 +0,0 @@
# 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",
),
),
]

View file

@ -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,57 +19,7 @@ class UserModel(models.Model):
abstract = True abstract = True
class CustomModel(UserModel): class Category(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")
@ -86,6 +36,10 @@ class Category(CustomModel):
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)
@ -96,7 +50,15 @@ class Category(CustomModel):
verbose_name_plural = _("Categories") verbose_name_plural = _("Categories")
class Transaction(AccountModel): class CategoryForm(ModelForm):
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")
@ -130,6 +92,10 @@ class Transaction(AccountModel):
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)
@ -144,11 +110,28 @@ class Transaction(AccountModel):
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(CustomModel): class Invoice(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=_("Invoice"), verbose_name=_("Name") max_length=256, default=_("Invoice"), verbose_name=_("Name")
@ -182,16 +165,29 @@ class Invoice(CustomModel):
"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(AccountModel): class Snapshot(UserModel):
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(
@ -288,6 +284,10 @@ class Snapshot(AccountModel):
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,37 +327,9 @@ class Snapshot(AccountModel):
verbose_name_plural = _("Snapshots") verbose_name_plural = _("Snapshots")
class NummiForm(ModelForm): class SnapshotForm(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 = "__all__" fields = ["date", "value", "file"]

View file

@ -12,12 +12,10 @@ h1 img {
margin-right: var(--gap); margin-right: var(--gap);
} }
#categories > a, #categories > a {
#accounts > a {
display: inline-block; display: inline-block;
padding: 1em; padding: 1em;
} }
#categories > a > i, #categories > a > i {
#accounts > a > i {
margin-right: .5rem; margin-right: .5rem;
} }

View file

@ -14,7 +14,6 @@
.table.col1-1-1 {grid-template-columns: min-content auto min-content} .table.col1-1-1 {grid-template-columns: min-content auto min-content}
.table.col1-5 {grid-template-columns: min-content repeat(5, auto)} .table.col1-5 {grid-template-columns: min-content repeat(5, auto)}
.table.col1-6 {grid-template-columns: min-content repeat(6, auto)} .table.col1-6 {grid-template-columns: min-content repeat(6, auto)}
.table.col1-7 {grid-template-columns: min-content repeat(7, auto)}
.table > div { .table > div {
display: contents; display: contents;

View file

@ -1,22 +0,0 @@
{% 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 %}

View file

@ -33,11 +33,6 @@
<img src="{% static 'main/svg/logo.svg' %}" alt="" /> <img src="{% static 'main/svg/logo.svg' %}" alt="" />
<h1>Nummi</h1> <h1>Nummi</h1>
</a> </a>
<a href="{% url 'account' %}"
class="{% if request.resolver_match.url_name == 'account' %}cur{% endif %}"
accesskey="n">
{% translate "Account" %}
</a>
<a href="{% url 'transaction' %}" <a href="{% url 'transaction' %}"
class="{% if request.resolver_match.url_name == 'transaction' %}cur{% endif %}" class="{% if request.resolver_match.url_name == 'transaction' %}cur{% endif %}"
accesskey="n"> accesskey="n">

View file

@ -12,16 +12,6 @@
type="text/css"/> type="text/css"/>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
{% if accounts %}
<h2>{% translate "Accounts" %}</h2>
{% spaceless %}
<div id="accounts">
{% for acc in accounts %}
<a href="{% url 'account' acc.id %}"><i class="fa fa-{{ acc.icon }}"></i>{{ acc }}</a>
{% endfor %}
</div>
{% endspaceless %}
{% endif %}
{% if transactions %} {% if transactions %}
<h2> <h2>
{% translate "Transactions" %} {% translate "Transactions" %}
@ -43,11 +33,10 @@
{% endif %} {% endif %}
{% if snapshots %} {% if snapshots %}
<h2>{% translate "Snapshots" %}</h2> <h2>{% translate "Snapshots" %}</h2>
<div id="snapshots" class="table col1-6"> <div id="snapshots" class="table col1-5">
<div class="header"> <div class="header">
<strong class="attach center"><i class="fa fa-paperclip"></i></strong> <strong class="attach center"><i class="fa fa-paperclip"></i></strong>
<strong class="date center">{% translate "Date" %}</strong> <strong class="date center">{% translate "Date" %}</strong>
<strong class="account center">{% translate "Account" %}</strong>
<strong class="value center">{% translate "Value" %}</strong> <strong class="value center">{% translate "Value" %}</strong>
<strong class="diff center">{% translate "Difference" %}</strong> <strong class="diff center">{% translate "Difference" %}</strong>
<strong class="diff center">{% translate "Transactions" %}</strong> <strong class="diff center">{% translate "Transactions" %}</strong>
@ -65,14 +54,6 @@
<span class="date num center"> <span class="date num center">
<a href="{% url 'snapshot' snap.id %}">{{ snap.date|date:"Y-m-d" }}</a> <a href="{% url 'snapshot' snap.id %}">{{ snap.date|date:"Y-m-d" }}</a>
</span> </span>
<span class="account text center">
{% if trans.account %}
<i class="fa fa-{{ trans.account.icon }}"></i>
<a href="{% url 'account' trans.account.id %}">{{ trans.account }}</a>
{% else %}
{% endif %}
</span>
<span class="value num right">{{ snap.value|value }}</span> <span class="value num right">{{ snap.value|value }}</span>
<span class="diff num right">{{ snap.diff|pmvalue }}</span> <span class="diff num right">{{ snap.diff|pmvalue }}</span>
{% with sum=snap.sum %} {% with sum=snap.sum %}

View file

@ -1,6 +1,6 @@
{% load main_extras %} {% load main_extras %}
{% load i18n %} {% load i18n %}
<div id="transactions" class="table col1-7"> <div id="transactions" class="table col1-6">
<div class="header"> <div class="header">
<strong class="attach center"><i class="fa fa-paperclip"></i></strong> <strong class="attach center"><i class="fa fa-paperclip"></i></strong>
<strong class="date center">{% translate "Date" %}</strong> <strong class="date center">{% translate "Date" %}</strong>
@ -8,7 +8,6 @@
<strong class="value center">{% translate "Value" %}</strong> <strong class="value center">{% translate "Value" %}</strong>
<strong class="trader center">{% translate "Trader" %}</strong> <strong class="trader center">{% translate "Trader" %}</strong>
<strong class="category center">{% translate "Category" %}</strong> <strong class="category center">{% translate "Category" %}</strong>
<strong class="account center">{% translate "Account" %}</strong>
<strong class="description">{% translate "Description" %}</strong> <strong class="description">{% translate "Description" %}</strong>
</div> </div>
{% for trans in transactions %} {% for trans in transactions %}
@ -34,14 +33,6 @@
{% endif %} {% endif %}
</span> </span>
<span class="account text center">
{% if trans.account %}
<i class="fa fa-{{ trans.account.icon }}"></i>
<a href="{% url 'account' trans.account.id %}">{{ trans.account }}</a>
{% else %}
{% endif %}
</span>
<span class="description text">{{ trans.description }}</span> <span class="description text">{{ trans.description }}</span>
</div> </div>
{% endfor %} {% endfor %}

View file

@ -7,7 +7,6 @@ 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",
@ -16,7 +15,6 @@ 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>",
@ -25,11 +23,6 @@ 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(),

View file

@ -19,8 +19,6 @@ 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,
@ -37,7 +35,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | { return super().get_context_data(**kwargs) | {
"accounts": Account.objects.filter(user=self.request.user),
"transactions": Transaction.objects.filter(user=self.request.user)[:10], "transactions": Transaction.objects.filter(user=self.request.user)[:10],
"categories": Category.objects.filter(user=self.request.user), "categories": Category.objects.filter(user=self.request.user),
"snapshots": Snapshot.objects.filter(user=self.request.user), "snapshots": Snapshot.objects.filter(user=self.request.user),
@ -55,11 +52,6 @@ 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"
@ -76,11 +68,6 @@ 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
@ -111,11 +98,6 @@ 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
@ -150,16 +132,15 @@ class SnapshotUpdateView(UserMixin, UpdateView):
form_class = SnapshotForm form_class = SnapshotForm
class AccountDeleteView(NummiDeleteView): class TransactionDeleteView(UserMixin, DeleteView):
model = Account
class TransactionDeleteView(NummiDeleteView):
model = Transaction model = Transaction
template_name = "main/confirm_delete.html"
success_url = reverse_lazy("index")
class InvoiceDeleteView(NummiDeleteView): class InvoiceDeleteView(UserMixin, DeleteView):
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})
@ -170,12 +151,16 @@ class InvoiceDeleteView(NummiDeleteView):
) )
class CategoryDeleteView(NummiDeleteView): class CategoryDeleteView(UserMixin, DeleteView):
model = Category model = Category
template_name = "main/confirm_delete.html"
success_url = reverse_lazy("index")
class SnapshotDeleteView(NummiDeleteView): class SnapshotDeleteView(UserMixin, DeleteView):
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):