mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-20 17:41:55 +02:00
Lock invoices, delete them
This commit is contained in:
@ -2359,6 +2359,22 @@
|
||||
"description": "Voir toutes les notes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "permission.permission",
|
||||
"pk": 151,
|
||||
"fields": {
|
||||
"model": [
|
||||
"treasury",
|
||||
"invoice"
|
||||
],
|
||||
"query": "{}",
|
||||
"type": "delete",
|
||||
"mask": 3,
|
||||
"field": "",
|
||||
"permanent": false,
|
||||
"description": "Supprimer une facture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "permission.role",
|
||||
"pk": 1,
|
||||
@ -2539,7 +2555,8 @@
|
||||
143,
|
||||
146,
|
||||
147,
|
||||
150
|
||||
150,
|
||||
151
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2695,7 +2712,8 @@
|
||||
147,
|
||||
148,
|
||||
149,
|
||||
150
|
||||
150,
|
||||
151
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -4,9 +4,8 @@
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit
|
||||
from django import forms
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from note_kfet.inputs import DatePickerInput, AmountInput
|
||||
from note_kfet.inputs import AmountInput
|
||||
|
||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
|
||||
|
||||
@ -16,19 +15,25 @@ class InvoiceForm(forms.ModelForm):
|
||||
Create and generate invoices.
|
||||
"""
|
||||
|
||||
# Django forms don't support date fields. We have to add it manually
|
||||
date = forms.DateField(
|
||||
initial=timezone.now,
|
||||
widget=DatePickerInput(),
|
||||
)
|
||||
def clean(self):
|
||||
if self.instance and self.instance.locked:
|
||||
for field_name in self.fields:
|
||||
self.cleaned_data[field_name] = getattr(self.instance, field_name)
|
||||
self.errors.clear()
|
||||
return self.cleaned_data
|
||||
return super().clean()
|
||||
|
||||
def clean_date(self):
|
||||
self.instance.date = self.data.get("date")
|
||||
return self.instance.date
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
If the invoice is locked, don't save it
|
||||
"""
|
||||
if not self.instance.locked:
|
||||
super().save(commit)
|
||||
return self.instance
|
||||
|
||||
class Meta:
|
||||
model = Invoice
|
||||
exclude = ('bde', 'tex', )
|
||||
exclude = ('bde', 'date', 'tex', )
|
||||
|
||||
|
||||
class ProductForm(forms.ModelForm):
|
||||
|
@ -61,6 +61,13 @@ class Invoice(models.Model):
|
||||
|
||||
acquitted = models.BooleanField(
|
||||
verbose_name=_("Acquitted"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
locked = models.BooleanField(
|
||||
verbose_name=_("Locked"),
|
||||
help_text=_("An invoice can't be edited when it is locked."),
|
||||
default=False,
|
||||
)
|
||||
|
||||
tex = models.TextField(
|
||||
@ -74,6 +81,12 @@ class Invoice(models.Model):
|
||||
The advantage is to never change the template.
|
||||
Warning: editing this model regenerate the tex source, so be careful.
|
||||
"""
|
||||
|
||||
old_invoice = Invoice.objects.filter(id=self.id)
|
||||
if old_invoice.exists():
|
||||
if old_invoice.get().locked:
|
||||
raise ValidationError(_("This invoice is locked and can no longer be edited."))
|
||||
|
||||
products = self.products.all()
|
||||
|
||||
self.place = "Gif-sur-Yvette"
|
||||
@ -103,7 +116,7 @@ class Product(models.Model):
|
||||
|
||||
invoice = models.ForeignKey(
|
||||
Invoice,
|
||||
on_delete=models.PROTECT,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="products",
|
||||
verbose_name=_("invoice"),
|
||||
)
|
||||
|
@ -14,19 +14,39 @@ class InvoiceTable(tables.Table):
|
||||
"""
|
||||
List all invoices.
|
||||
"""
|
||||
id = tables.LinkColumn("treasury:invoice_update",
|
||||
args=[A("pk")],
|
||||
text=lambda record: _("Invoice #{:d}").format(record.id), )
|
||||
id = tables.LinkColumn(
|
||||
"treasury:invoice_update",
|
||||
args=[A("pk")],
|
||||
text=lambda record: _("Invoice #{:d}").format(record.id),
|
||||
)
|
||||
|
||||
invoice = tables.LinkColumn("treasury:invoice_render",
|
||||
verbose_name=_("Invoice"),
|
||||
args=[A("pk")],
|
||||
accessor="pk",
|
||||
text="",
|
||||
attrs={
|
||||
'a': {'class': 'fa fa-file-pdf-o'},
|
||||
'td': {'data-turbolinks': 'false'}
|
||||
})
|
||||
invoice = tables.LinkColumn(
|
||||
"treasury:invoice_render",
|
||||
verbose_name=_("Invoice"),
|
||||
args=[A("pk")],
|
||||
accessor="pk",
|
||||
text="",
|
||||
attrs={
|
||||
'a': {'class': 'fa fa-file-pdf-o'},
|
||||
'td': {'data-turbolinks': 'false'}
|
||||
}
|
||||
)
|
||||
|
||||
delete = tables.LinkColumn(
|
||||
'treasury:invoice_delete',
|
||||
args=[A('pk')],
|
||||
verbose_name=_("delete"),
|
||||
text=_("Delete"),
|
||||
attrs={
|
||||
'th': {
|
||||
'id': 'delete-membership-header'
|
||||
},
|
||||
'a': {
|
||||
'class': 'btn btn-danger',
|
||||
'data-type': 'delete-membership'
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
class Meta:
|
||||
attrs = {
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from .views import InvoiceCreateView, InvoiceListView, InvoiceUpdateView, InvoiceRenderView, RemittanceListView,\
|
||||
RemittanceCreateView, RemittanceUpdateView, LinkTransactionToRemittanceView, UnlinkTransactionToRemittanceView,\
|
||||
SogeCreditListView, SogeCreditManageView
|
||||
from .views import InvoiceCreateView, InvoiceListView, InvoiceUpdateView, InvoiceDeleteView, InvoiceRenderView,\
|
||||
RemittanceListView, RemittanceCreateView, RemittanceUpdateView, LinkTransactionToRemittanceView,\
|
||||
UnlinkTransactionToRemittanceView, SogeCreditListView, SogeCreditManageView
|
||||
|
||||
app_name = 'treasury'
|
||||
urlpatterns = [
|
||||
@ -13,6 +13,7 @@ urlpatterns = [
|
||||
path('invoice/', InvoiceListView.as_view(), name='invoice_list'),
|
||||
path('invoice/create/', InvoiceCreateView.as_view(), name='invoice_create'),
|
||||
path('invoice/<int:pk>/', InvoiceUpdateView.as_view(), name='invoice_update'),
|
||||
path('invoice/<int:pk>/delete/', InvoiceDeleteView.as_view(), name='invoice_delete'),
|
||||
path('invoice/render/<int:pk>/', InvoiceRenderView.as_view(), name='invoice_render'),
|
||||
|
||||
# Remittance app paths
|
||||
|
@ -18,7 +18,7 @@ from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import CreateView, UpdateView, DetailView
|
||||
from django.views.generic.base import View, TemplateView
|
||||
from django.views.generic.edit import BaseFormView
|
||||
from django.views.generic.edit import BaseFormView, DeleteView
|
||||
from django_tables2 import SingleTableView
|
||||
from note.models import SpecialTransaction, NoteSpecial, Alias
|
||||
from note_kfet.settings.base import BASE_DIR
|
||||
@ -97,14 +97,20 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||
form.helper = FormHelper()
|
||||
# Remove form tag on the generation of the form in the template (already present on the template)
|
||||
form.helper.form_tag = False
|
||||
# Fill the intial value for the date field, with the initial date of the model instance
|
||||
form.fields['date'].initial = form.instance.date
|
||||
# The formset handles the set of the products
|
||||
form_set = ProductFormSet(instance=form.instance)
|
||||
form_set = ProductFormSet(instance=self.object)
|
||||
context['formset'] = form_set
|
||||
context['helper'] = ProductFormSetHelper()
|
||||
context['no_cache'] = True
|
||||
|
||||
if self.object.locked:
|
||||
for field_name in form.fields:
|
||||
form.fields[field_name].disabled = True
|
||||
for f in form_set.forms:
|
||||
for field_name in f.fields:
|
||||
f.fields[field_name].disabled = True
|
||||
|
||||
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
@ -131,6 +137,17 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||
return reverse_lazy('treasury:invoice_list')
|
||||
|
||||
|
||||
class InvoiceDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
||||
"""
|
||||
Delete a non-validated WEI registration
|
||||
"""
|
||||
model = Invoice
|
||||
extra_context = {"title": _("Delete invoice")}
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('treasury:invoice_list')
|
||||
|
||||
|
||||
class InvoiceRenderView(LoginRequiredMixin, View):
|
||||
"""
|
||||
Render Invoice as a generated PDF with the given information and a LaTeX template
|
||||
|
Reference in New Issue
Block a user