Added views for invoices

Added class-based views for all operations
Added corresponding urls
Updated transaction page to use new views
This commit is contained in:
Edgar P. Burkhart 2022-12-28 11:52:24 +01:00
parent d8c95fac25
commit 033698b38a
Signed by: edpibu
GPG key ID: 9833D3C5A25BD227
9 changed files with 168 additions and 51 deletions

View file

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.0.1\n" "Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-28 10:16+0100\n" "POT-Creation-Date: 2022-12-28 11:47+0100\n"
"PO-Revision-Date: 2022-12-21 17:30+0100\n" "PO-Revision-Date: 2022-12-21 17:30+0100\n"
"Last-Translator: edpibu <git@edgarpierre.fr>\n" "Last-Translator: edpibu <git@edgarpierre.fr>\n"
"Language-Team: edpibu <git@edgarpierre.fr>\n" "Language-Team: edpibu <git@edgarpierre.fr>\n"
@ -23,8 +23,9 @@ msgstr ""
msgid "Category" msgid "Category"
msgstr "Catégorie" msgstr "Catégorie"
#: .\main\models.py:16 .\main\models.py:41 .\main\models.py:107 #: .\main\models.py:16 .\main\models.py:41 .\main\models.py:114
#: .\main\templates\main\tag\transaction_table.html:7 #: .\main\templates\main\tag\transaction_table.html:7
#: .\main\templates\main\transaction_form.html:27
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
@ -41,7 +42,7 @@ msgstr "Budget"
msgid "Categories" msgid "Categories"
msgstr "Catégories" msgstr "Catégories"
#: .\main\models.py:41 .\main\models.py:79 .\main\templates\main\base.html:39 #: .\main\models.py:41 .\main\models.py:86 .\main\templates\main\base.html:39
msgid "Transaction" msgid "Transaction"
msgstr "Transaction" msgstr "Transaction"
@ -49,12 +50,12 @@ msgstr "Transaction"
msgid "Description" msgid "Description"
msgstr "Description" msgstr "Description"
#: .\main\models.py:45 .\main\models.py:146 .\main\templates\main\index.html:40 #: .\main\models.py:45 .\main\models.py:169 .\main\templates\main\index.html:40
#: .\main\templates\main\tag\transaction_table.html:8 #: .\main\templates\main\tag\transaction_table.html:8
msgid "Value" msgid "Value"
msgstr "Valeur" msgstr "Valeur"
#: .\main\models.py:47 .\main\models.py:144 .\main\templates\main\index.html:39 #: .\main\models.py:47 .\main\models.py:167 .\main\templates\main\index.html:39
#: .\main\templates\main\tag\transaction_table.html:6 #: .\main\templates\main\tag\transaction_table.html:6
msgid "Date" msgid "Date"
msgstr "Date" msgstr "Date"
@ -71,35 +72,35 @@ msgstr "Commerçant"
msgid "Payment" msgid "Payment"
msgstr "Paiement" msgstr "Paiement"
#: .\main\models.py:80 .\main\templates\main\category.html:26 #: .\main\models.py:87 .\main\templates\main\category.html:26
#: .\main\templates\main\index.html:17 .\main\templates\main\index.html:42 #: .\main\templates\main\index.html:17 .\main\templates\main\index.html:42
#: .\main\templates\main\snapshot.html:78 #: .\main\templates\main\snapshot.html:78
#: .\main\templates\main\transactions.html:15 #: .\main\templates\main\transactions.html:15
msgid "Transactions" msgid "Transactions"
msgstr "Transactions" msgstr "Transactions"
#: .\main\models.py:107 .\main\models.py:125 #: .\main\models.py:114 .\main\models.py:148
msgid "Invoice" msgid "Invoice"
msgstr "Facture" msgstr "Facture"
#: .\main\models.py:112 .\main\models.py:157 #: .\main\models.py:119 .\main\models.py:180
msgid "File" msgid "File"
msgstr "Fichier" msgstr "Fichier"
#: .\main\models.py:126 #: .\main\models.py:149 .\main\templates\main\transaction_form.html:23
msgid "Invoices" msgid "Invoices"
msgstr "Factures" msgstr "Factures"
#: .\main\models.py:163 #: .\main\models.py:186
#, python-format #, python-format
msgid "%(date)s snapshot" msgid "%(date)s snapshot"
msgstr "Relevé du %(date)s" msgstr "Relevé du %(date)s"
#: .\main\models.py:265 .\main\templates\main\base.html:49 #: .\main\models.py:288 .\main\templates\main\base.html:49
msgid "Snapshot" msgid "Snapshot"
msgstr "Relevé" msgstr "Relevé"
#: .\main\models.py:266 .\main\templates\main\index.html:35 #: .\main\models.py:289 .\main\templates\main\index.html:35
msgid "Snapshots" msgid "Snapshots"
msgstr "Relevés" msgstr "Relevés"
@ -113,8 +114,8 @@ msgstr "Se déconnecter"
#: .\main\templates\main\confirm_delete.html:19 #: .\main\templates\main\confirm_delete.html:19
#, python-format #, python-format
msgid "Are you sure you want do delete <%(object)s> ?" msgid "Are you sure you want do delete <strong>%(object)s</strong> ?"
msgstr "Êtes-vous sûr de vouloir supprimer <%(object)s> ?" msgstr "Êtes-vous sûr de vouloir supprimer <strong>%(object)s</strong> ?"
#: .\main\templates\main\confirm_delete.html:23 #: .\main\templates\main\confirm_delete.html:23
msgid "Cancel" msgid "Cancel"
@ -124,6 +125,17 @@ msgstr "Annuler"
msgid "Confirm" msgid "Confirm"
msgstr "Confirmer" msgstr "Confirmer"
#: .\main\templates\main\form\base.html:17
#: .\main\templates\main\tag\form_buttons.html:4
#: .\main\templates\main\transaction_form.html:34
msgid "Delete"
msgstr "Supprimer"
#: .\main\templates\main\form\base.html:20
#: .\main\templates\main\tag\form_buttons.html:8
msgid "Save"
msgstr "Enregistrer"
#: .\main\templates\main\index.html:41 #: .\main\templates\main\index.html:41
msgid "Difference" msgid "Difference"
msgstr "Différence" msgstr "Différence"
@ -136,16 +148,6 @@ msgstr "Valide"
msgid "Log In" msgid "Log In"
msgstr "Se connecter" msgstr "Se connecter"
#: .\main\templates\main\tag\form_buttons.html:4 #: .\main\templates\main\transaction_form.html:39
msgid "Delete" msgid "New invoice"
msgstr "Supprimer" msgstr "Nouvelle facture"
#: .\main\templates\main\tag\form_buttons.html:8
msgid "Save"
msgstr "Enregistrer"
#~ msgid "Add invoice"
#~ msgstr "Ajouter une facture"
#~ msgid "Add"
#~ msgstr "Ajouter"

View file

@ -66,6 +66,13 @@ class Transaction(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse("transaction", kwargs={"pk": self.pk}) return reverse("transaction", kwargs={"pk": self.pk})
def get_delete_url(self):
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)
@ -112,15 +119,33 @@ class Invoice(models.Model):
verbose_name=_("File"), verbose_name=_("File"),
max_length=128, max_length=128,
) )
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE) transaction = models.ForeignKey(
Transaction, on_delete=models.CASCADE, editable=False
)
def __str__(self): def __str__(self):
return f"{self.name}: {self.transaction}" if hasattr(self, "transaction"):
return f"{self.name} {self.transaction.name}"
return self.name
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
self.file.delete() self.file.delete()
super().delete(*args, **kwargs) super().delete(*args, **kwargs)
def get_absolute_url(self):
return reverse(
"invoice", kwargs={"transaction_pk": self.transaction.pk, "pk": self.pk}
)
def get_delete_url(self):
return reverse(
"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")
@ -132,7 +157,7 @@ class InvoiceForm(ModelForm):
class Meta: class Meta:
model = Invoice model = Invoice
fields = ["name", "file"] fields = "__all__"
def snapshot_path(instance, filename): def snapshot_path(instance, filename):

View file

@ -16,7 +16,7 @@
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<p> <p>
{% blocktranslate %}Are you sure you want do delete <{{ object }}> ?{% endblocktranslate %} {% blocktranslate %}Are you sure you want do delete <strong>{{ object }}</strong> ?{% endblocktranslate %}
</p> </p>
{{ form }} {{ form }}
<div class="buttons"> <div class="buttons">

View file

@ -1,6 +1,5 @@
{% load i18n %} {% load i18n %}
{% block fields %} {% block fields %}
{% csrf_token %}
{% if form.non_field_errors %} {% if form.non_field_errors %}
<ul class='errorlist'> <ul class='errorlist'>
{% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %} {% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %}
@ -12,3 +11,12 @@
<div>{{ field }}</div> <div>{{ field }}</div>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
{% block buttons %}
<div class="buttons">
{% if not form.instance.adding %}
<a class="btn del" href="{{ form.instance.get_delete_url }}">{% translate "Delete" %}</a>
{% endif %}
<input type="reset" />
<input type="submit" value="{% translate 'Save' %}" />
</div>
{% endblock %}

View 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>{{ form.instance }}</h1>
{% spaceless %}
<form id="transaction" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
</form>
{% endspaceless %}
{% endblock %}

View file

@ -12,11 +12,32 @@
type="text/css"/> type="text/css"/>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<h1>{{ transaction }}</h1> <h1>{{ form.instance }}</h1>
{% spaceless %} {% spaceless %}
<form id="transaction" action="" method="post"> <form id="transaction" method="post">
{% csrf_token %}
{{ form }} {{ form }}
{% form_buttons form.instance %} </form>
</form> {% endspaceless %}
{% endspaceless %} {% if not form.instance.adding %}
{% endblock %} <h2>{% translate "Invoices" %}</h2>
<div id="invoices" class="table col1-1-1">
<div class="header">
<strong class="attach center"><i class="fa fa-file"></i></strong>
<strong class="name">{% translate "Name" %}</strong>
<strong class="attach right"><i class="fa fa-trash-can"></i></strong>
</div>
{% for inv in transaction.invoices %}
<div class="invoice">
<a href="{{ inv.file.url }}"><i class="fa-regular fa-file"></i></a>
<a href="{{ inv.get_absolute_url }}">{{ inv.name }}</a>
<a href="{{ inv.get_delete_url }}" class="right">{% translate "Delete" %}</a>
</div>
{% endfor %}
<div class="invoice new">
<i class="fa fa-file-circle-plus"></i>
<a href="{% url "invoice" transaction.pk %}">{% translate "New invoice" %}</a>
</div>
</div>
{% endif %}
{% endblock %}

View file

@ -8,14 +8,27 @@ urlpatterns = [
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("transaction", views.TransactionCreateView.as_view(), name="transaction"), path("transaction", views.TransactionCreateView.as_view(), name="transaction"),
path(
"transaction/<transaction_pk>/invoice",
views.InvoiceCreateView.as_view(),
name="invoice",
),
path("transaction/<pk>", views.TransactionUpdateView.as_view(), name="transaction"), path("transaction/<pk>", views.TransactionUpdateView.as_view(), name="transaction"),
path( path(
"transaction/delete/<pk>", "transaction/<transaction_pk>/invoice/<pk>",
views.InvoiceUpdateView.as_view(),
name="invoice",
),
path(
"transaction/<pk>/delete",
views.TransactionDeleteView.as_view(), views.TransactionDeleteView.as_view(),
name="del_transaction", name="del_transaction",
), ),
path("del_invoice/<uuid>/<invoice_id>", views.del_invoice, name="del_invoice"), path(
path("invoice/<uuid>", views.invoice, name="invoice"), "transaction/<transaction_pk>/invoice/<pk>/delete",
views.InvoiceDeleteView.as_view(),
name="del_invoice",
),
path("category", views.category, name="category"), path("category", views.category, name="category"),
path("category/<uuid>", views.category, name="category"), path("category/<uuid>", views.category, name="category"),
path("category/<uuid>/del", views.del_category, name="del_category"), path("category/<uuid>/del", views.del_category, name="del_category"),

View file

@ -61,29 +61,55 @@ class TransactionCreateView(LoginRequiredMixin, CreateView):
form_class = TransactionForm form_class = TransactionForm
class InvoiceCreateView(LoginRequiredMixin, CreateView):
model = Invoice
form_class = InvoiceForm
def form_valid(self, form):
form.instance.transaction = get_object_or_404(
Transaction, pk=self.kwargs["transaction_pk"]
)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("transaction", kwargs={"pk": self.object.transaction.pk})
class TransactionUpdateView(LoginRequiredMixin, UpdateView): class TransactionUpdateView(LoginRequiredMixin, UpdateView):
model = Transaction model = Transaction
form_class = TransactionForm form_class = TransactionForm
class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
model = Invoice
form_class = InvoiceForm
def get_success_url(self):
return reverse_lazy("transaction", kwargs={"pk": self.object.transaction.pk})
def get_queryset(self):
return Invoice.objects.filter(
transaction=get_object_or_404(Transaction, pk=self.kwargs["transaction_pk"])
)
class TransactionDeleteView(LoginRequiredMixin, DeleteView): class TransactionDeleteView(LoginRequiredMixin, DeleteView):
model = Transaction model = Transaction
template_name = "main/confirm_delete.html" template_name = "main/confirm_delete.html"
success_url = reverse_lazy("index") success_url = reverse_lazy("index")
@login_required class InvoiceDeleteView(LoginRequiredMixin, DeleteView):
def invoice(request, uuid): model = Invoice
_invoice = get_object_or_404(Invoice, id=uuid) template_name = "main/confirm_delete.html"
with _invoice.file.open() as _file:
return HttpResponse(_file.read(), content_type="application/pdf")
def get_success_url(self):
return reverse_lazy("transaction", kwargs={"pk": self.object.transaction.pk})
@login_required def get_queryset(self):
def del_invoice(request, uuid, invoice_id): return Invoice.objects.filter(
_invoice = get_object_or_404(Invoice, id=invoice_id) transaction=get_object_or_404(Transaction, pk=self.kwargs["transaction_pk"])
_invoice.delete() )
return redirect(transaction, uuid=uuid)
@login_required @login_required