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:
parent
d8c95fac25
commit
033698b38a
9 changed files with 168 additions and 51 deletions
Binary file not shown.
|
@ -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"
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
22
nummi/main/templates/main/invoice_form.html
Normal file
22
nummi/main/templates/main/invoice_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>{{ form.instance }}</h1>
|
||||||
|
{% spaceless %}
|
||||||
|
<form id="transaction" method="post" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
</form>
|
||||||
|
{% endspaceless %}
|
||||||
|
{% endblock %}
|
|
@ -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 %}
|
||||||
{% endblock %}
|
{% if not form.instance.adding %}
|
||||||
|
<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 %}
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue