diff --git a/cotisations/forms.py b/cotisations/forms.py
index 7ad9e413..ccf9d5d6 100644
--- a/cotisations/forms.py
+++ b/cotisations/forms.py
@@ -46,7 +46,7 @@ from django.shortcuts import get_object_or_404
from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
-from .models import Article, Paiement, Facture, Banque
+from .models import Article, Paiement, Facture, Banque, CustomInvoice
from .payment_methods import balance
@@ -131,24 +131,13 @@ class SelectClubArticleForm(Form):
self.fields['article'].queryset = Article.find_allowed_articles(user)
-# TODO : change Facture to Invoice
-class NewFactureFormPdf(Form):
+class CustomInvoiceForm(FormRevMixin, ModelForm):
"""
- Form used to create a custom PDF invoice.
+ Form used to create a custom invoice.
"""
- paid = forms.BooleanField(label=_l("Paid"), required=False)
- # TODO : change dest field to recipient
- dest = forms.CharField(
- required=True,
- max_length=255,
- label=_l("Recipient")
- )
- # TODO : change chambre field to address
- chambre = forms.CharField(
- required=False,
- max_length=10,
- label=_l("Address")
- )
+ class Meta:
+ model = CustomInvoice
+ fields = '__all__'
class ArticleForm(FormRevMixin, ModelForm):
diff --git a/cotisations/migrations/0031_custom_invoice.py b/cotisations/migrations/0031_custom_invoice.py
new file mode 100644
index 00000000..52921739
--- /dev/null
+++ b/cotisations/migrations/0031_custom_invoice.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-21 20:01
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import re2o.field_permissions
+import re2o.mixins
+
+
+def reattribute_ids(apps, schema_editor):
+ Facture = apps.get_model('cotisations', 'Facture')
+ BaseInvoice = apps.get_model('cotisations', 'BaseInvoice')
+
+ for f in Facture.objects.all():
+ base = BaseInvoice.objects.create(id=f.pk, date=f.date)
+ f.baseinvoice_ptr = base
+ f.save()
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cotisations', '0030_custom_payment'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BaseInvoice',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
+ ],
+ bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, re2o.field_permissions.FieldPermissionModelMixin, models.Model),
+ ),
+ migrations.CreateModel(
+ name='CustomInvoice',
+ fields=[
+ ('baseinvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice')),
+ ('recipient', models.CharField(max_length=255, verbose_name='Recipient')),
+ ('payment', models.CharField(max_length=255, verbose_name='Payment type')),
+ ('address', models.CharField(max_length=255, verbose_name='Address')),
+ ('paid', models.BooleanField(verbose_name='Paid')),
+ ],
+ bases=('cotisations.baseinvoice',),
+ options={'permissions': (('view_custom_invoice', 'Can view a custom invoice'),)},
+ ),
+ migrations.AddField(
+ model_name='facture',
+ name='baseinvoice_ptr',
+ field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', null=True),
+ preserve_default=False,
+ ),
+ migrations.RunPython(reattribute_ids),
+ migrations.AlterField(
+ model_name='vente',
+ name='facture',
+ field=models.ForeignKey(on_delete=models.CASCADE, verbose_name='Invoice', to='cotisations.BaseInvoice')
+ ),
+ migrations.RemoveField(
+ model_name='facture',
+ name='id',
+ ),
+ migrations.RemoveField(
+ model_name='facture',
+ name='date',
+ ),
+ migrations.AlterField(
+ model_name='facture',
+ name='baseinvoice_ptr',
+ field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice'),
+ )
+ ]
diff --git a/cotisations/models.py b/cotisations/models.py
index 52d71b58..c4515cc7 100644
--- a/cotisations/models.py
+++ b/cotisations/models.py
@@ -55,8 +55,52 @@ from cotisations.utils import find_payment_method
from cotisations.validators import check_no_balance
+class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
+ date = models.DateTimeField(
+ auto_now_add=True,
+ verbose_name=_l("Date")
+ )
+
+ # TODO : change prix to price
+ def prix(self):
+ """
+ Returns: the raw price without the quantities.
+ Deprecated, use :total_price instead.
+ """
+ price = Vente.objects.filter(
+ facture=self
+ ).aggregate(models.Sum('prix'))['prix__sum']
+ return price
+
+ # TODO : change prix to price
+ def prix_total(self):
+ """
+ Returns: the total price for an invoice. Sum all the articles' prices
+ and take the quantities into account.
+ """
+ # TODO : change Vente to somethingelse
+ return Vente.objects.filter(
+ facture=self
+ ).aggregate(
+ total=models.Sum(
+ models.F('prix')*models.F('number'),
+ output_field=models.FloatField()
+ )
+ )['total'] or 0
+
+ def name(self):
+ """
+ Returns : a string with the name of all the articles in the invoice.
+ Used for reprensenting the invoice with a string.
+ """
+ name = ' - '.join(Vente.objects.filter(
+ facture=self
+ ).values_list('name', flat=True))
+ return name
+
+
# TODO : change facture to invoice
-class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
+class Facture(BaseInvoice):
"""
The model for an invoice. It reprensents the fact that a user paid for
something (it can be multiple article paid at once).
@@ -92,10 +136,6 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
blank=True,
verbose_name=_l("Cheque number")
)
- date = models.DateTimeField(
- auto_now_add=True,
- verbose_name=_l("Date")
- )
# TODO : change name to validity for clarity
valid = models.BooleanField(
default=True,
@@ -130,43 +170,6 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
Usefull in history display"""
return self.vente_set.all()
- # TODO : change prix to price
- def prix(self):
- """
- Returns: the raw price without the quantities.
- Deprecated, use :total_price instead.
- """
- price = Vente.objects.filter(
- facture=self
- ).aggregate(models.Sum('prix'))['prix__sum']
- return price
-
- # TODO : change prix to price
- def prix_total(self):
- """
- Returns: the total price for an invoice. Sum all the articles' prices
- and take the quantities into account.
- """
- # TODO : change Vente to somethingelse
- return Vente.objects.filter(
- facture=self
- ).aggregate(
- total=models.Sum(
- models.F('prix')*models.F('number'),
- output_field=models.FloatField()
- )
- )['total'] or 0
-
- def name(self):
- """
- Returns : a string with the name of all the articles in the invoice.
- Used for reprensenting the invoice with a string.
- """
- name = ' - '.join(Vente.objects.filter(
- facture=self
- ).values_list('name', flat=True))
- return name
-
def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_facture'):
return False, _("You don't have the right to edit an invoice.")
@@ -265,6 +268,28 @@ def facture_post_delete(**kwargs):
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
+class CustomInvoice(BaseInvoice):
+ class Meta:
+ permissions = (
+ ('view_custom_invoice', _l("Can view a custom invoice")),
+ )
+ recipient = models.CharField(
+ max_length=255,
+ verbose_name=_l("Recipient")
+ )
+ payment = models.CharField(
+ max_length=255,
+ verbose_name=_l("Payment type")
+ )
+ address = models.CharField(
+ max_length=255,
+ verbose_name=_l("Address")
+ )
+ paid = models.BooleanField(
+ verbose_name="Paid"
+ )
+
+
# TODO : change Vente to Purchase
class Vente(RevMixin, AclMixin, models.Model):
"""
@@ -288,7 +313,7 @@ class Vente(RevMixin, AclMixin, models.Model):
# TODO : change facture to invoice
facture = models.ForeignKey(
- 'Facture',
+ 'BaseInvoice',
on_delete=models.CASCADE,
verbose_name=_l("Invoice")
)
@@ -355,6 +380,10 @@ class Vente(RevMixin, AclMixin, models.Model):
cotisation_type defined (which means the article sold represents
a cotisation)
"""
+ try:
+ invoice = self.facture.facture
+ except Facture.DoesNotExist:
+ return
if not hasattr(self, 'cotisation') and self.type_cotisation:
cotisation = Cotisation(vente=self)
cotisation.type_cotisation = self.type_cotisation
@@ -362,7 +391,7 @@ class Vente(RevMixin, AclMixin, models.Model):
end_cotisation = Cotisation.objects.filter(
vente__in=Vente.objects.filter(
facture__in=Facture.objects.filter(
- user=self.facture.user
+ user=invoice.user
).exclude(valid=False))
).filter(
Q(type_cotisation='All') |
@@ -371,9 +400,9 @@ class Vente(RevMixin, AclMixin, models.Model):
date_start__lt=date_start
).aggregate(Max('date_end'))['date_end__max']
elif self.type_cotisation == "Adhesion":
- end_cotisation = self.facture.user.end_adhesion()
+ end_cotisation = invoice.user.end_adhesion()
else:
- end_cotisation = self.facture.user.end_connexion()
+ end_cotisation = invoice.user.end_connexion()
date_start = date_start or timezone.now()
end_cotisation = end_cotisation or date_start
date_max = max(end_cotisation, date_start)
@@ -445,6 +474,10 @@ def vente_post_save(**kwargs):
LDAP user when a purchase has been saved.
"""
purchase = kwargs['instance']
+ try:
+ purchase.facture.facture
+ except Facture.DoesNotExist:
+ return
if hasattr(purchase, 'cotisation'):
purchase.cotisation.vente = purchase
purchase.cotisation.save()
@@ -462,8 +495,12 @@ def vente_post_delete(**kwargs):
Synchronise the LDAP user after a purchase has been deleted.
"""
purchase = kwargs['instance']
+ try:
+ invoice = purchase.facture.facture
+ except Facture.DoesNotExist:
+ return
if purchase.type_cotisation:
- user = purchase.facture.user
+ user = invoice.user
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
diff --git a/cotisations/templates/cotisations/aff_custom_invoice.html b/cotisations/templates/cotisations/aff_custom_invoice.html
new file mode 100644
index 00000000..1a477613
--- /dev/null
+++ b/cotisations/templates/cotisations/aff_custom_invoice.html
@@ -0,0 +1,108 @@
+{% comment %}
+Re2o est un logiciel d'administration développé initiallement au rezometz. Il
+se veut agnostique au réseau considéré, de manière à être installable en
+quelques clics.
+
+Copyright © 2017 Gabriel Détraz
+Copyright © 2017 Goulven Kermarec
+Copyright © 2017 Augustin Lemesle
+Copyright © 2018 Hugo Levy-Falk
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+{% endcomment %}
+{% load i18n %}
+{% load acl %}
+
+
+ {% if custom_invoice_list.paginator %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
+ {% endif %}
+
+
+
+
+ |
+ {% trans "Recipient" as tr_recip %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_user %}
+ |
+ {% trans "Designation" %} |
+ {% trans "Total price" %} |
+
+ {% trans "Payment method" as tr_payment_method %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='payement' text=tr_payment_method %}
+ |
+
+ {% trans "Date" as tr_date %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='date' text=tr_date %}
+ |
+
+ {% trans "Invoice id" as tr_invoice_id %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='id' text=tr_invoice_id %}
+ |
+ {% trans "Paid" %} |
+ |
+ |
+
+
+ {% for invoice in custom_invoice_list %}
+
+ | {{ invoice.recipient }} |
+ {{ invoice.name }} |
+ {{ invoice.prix_total }} |
+ {{ invoice.payment }} |
+ {{ invoice.date }} |
+ {{ invoice.id }} |
+ {{ invoice.paid }} |
+
+
+
+
+
+ |
+
+
+ {% trans "PDF" %}
+
+ |
+
+ {% endfor %}
+
+
+ {% if custom_invoice_list.paginator %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
+ {% endif %}
+
diff --git a/cotisations/templates/cotisations/index_custom_invoice.html b/cotisations/templates/cotisations/index_custom_invoice.html
new file mode 100644
index 00000000..67d00126
--- /dev/null
+++ b/cotisations/templates/cotisations/index_custom_invoice.html
@@ -0,0 +1,36 @@
+{% extends "cotisations/sidebar.html" %}
+{% comment %}
+Re2o est un logiciel d'administration développé initiallement au rezometz. Il
+se veut agnostique au réseau considéré, de manière à être installable en
+quelques clics.
+
+Copyright © 2017 Gabriel Détraz
+Copyright © 2017 Goulven Kermarec
+Copyright © 2017 Augustin Lemesle
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+{% endcomment %}
+{% load acl %}
+{% load i18n %}
+
+{% block title %}{% trans "Custom invoices" %}{% endblock %}
+
+{% block content %}
+{% trans "Custom invoices list" %}
+{% can_create CustomInvoice %}
+{% include "buttons/add.html" with href='cotisations:new-custom-invoice'%}
+{% acl_end %}
+{% include 'cotisations/aff_custom_invoice.html' with custom_invoice_list=custom_invoice_list %}
+{% endblock %}
diff --git a/cotisations/templates/cotisations/sidebar.html b/cotisations/templates/cotisations/sidebar.html
index 296730f2..8d37bb6a 100644
--- a/cotisations/templates/cotisations/sidebar.html
+++ b/cotisations/templates/cotisations/sidebar.html
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block sidebar %}
{% can_change Facture pdf %}
-
+
{% trans "Create an invoice" %}
@@ -40,6 +40,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Invoices" %}
{% acl_end %}
+ {% can_view_all CustomInvoice %}
+
+ {% trans "Custom invoices" %}
+
+ {% acl_end %}
{% can_view_all Article %}
{% trans "Available articles" %}
diff --git a/cotisations/urls.py b/cotisations/urls.py
index 470ccbfa..edc448fe 100644
--- a/cotisations/urls.py
+++ b/cotisations/urls.py
@@ -52,9 +52,29 @@ urlpatterns = [
name='facture-pdf'
),
url(
- r'^new_facture_pdf/$',
- views.new_facture_pdf,
- name='new-facture-pdf'
+ r'^index_custom_invoice/$',
+ views.index_custom_invoice,
+ name='index-custom-invoice'
+ ),
+ url(
+ r'^new_custom_invoice/$',
+ views.new_custom_invoice,
+ name='new-custom-invoice'
+ ),
+ url(
+ r'^edit_custom_invoice/(?P[0-9]+)$',
+ views.edit_custom_invoice,
+ name='edit-custom-invoice'
+ ),
+ url(
+ r'^custom_invoice_pdf/(?P[0-9]+)$',
+ views.custom_invoice_pdf,
+ name='custom-invoice-pdf',
+ ),
+ url(
+ r'^del_custom_invoice/(?P[0-9]+)$',
+ views.del_custom_invoice,
+ name='del-custom-invoice'
),
url(
r'^credit_solde/(?P[0-9]+)$',
diff --git a/cotisations/views.py b/cotisations/views.py
index 66eb66f5..90bc3632 100644
--- a/cotisations/views.py
+++ b/cotisations/views.py
@@ -58,7 +58,15 @@ from re2o.acl import (
can_change,
)
from preferences.models import AssoOption, GeneralOption
-from .models import Facture, Article, Vente, Paiement, Banque
+from .models import (
+ Facture,
+ Article,
+ Vente,
+ Paiement,
+ Banque,
+ CustomInvoice,
+ BaseInvoice
+)
from .forms import (
FactureForm,
ArticleForm,
@@ -67,10 +75,10 @@ from .forms import (
DelPaiementForm,
BanqueForm,
DelBanqueForm,
- NewFactureFormPdf,
SelectUserArticleForm,
SelectClubArticleForm,
- RechargeForm
+ RechargeForm,
+ CustomInvoiceForm
)
from .tex import render_invoice
from .payment_methods.forms import payment_method_factory
@@ -178,10 +186,10 @@ def new_facture(request, user, userid):
# TODO : change facture to invoice
@login_required
-@can_change(Facture, 'pdf')
-def new_facture_pdf(request):
+@can_create(CustomInvoice)
+def new_custom_invoice(request):
"""
- View used to generate a custom PDF invoice. It's mainly used to
+ View used to generate a custom invoice. It's mainly used to
get invoices that are not taken into account, for the administrative
point of view.
"""
@@ -190,7 +198,7 @@ def new_facture_pdf(request):
Q(type_user='All') | Q(type_user=request.user.class_name)
)
# Building the invocie form and the article formset
- invoice_form = NewFactureFormPdf(request.POST or None)
+ invoice_form = CustomInvoiceForm(request.POST or None)
if request.user.is_class_club:
articles_formset = formset_factory(SelectClubArticleForm)(
request.POST or None,
@@ -202,44 +210,31 @@ def new_facture_pdf(request):
form_kwargs={'user': request.user}
)
if invoice_form.is_valid() and articles_formset.is_valid():
- # Get the article list and build an list out of it
- # contiaining (article_name, article_price, quantity, total_price)
- articles_info = []
- for articles_form in articles_formset:
- if articles_form.cleaned_data:
- article = articles_form.cleaned_data['article']
- quantity = articles_form.cleaned_data['quantity']
- articles_info.append({
- 'name': article.name,
- 'price': article.prix,
- 'quantity': quantity,
- 'total_price': article.prix * quantity
- })
- paid = invoice_form.cleaned_data['paid']
- recipient = invoice_form.cleaned_data['dest']
- address = invoice_form.cleaned_data['chambre']
- total_price = sum(a['total_price'] for a in articles_info)
-
- return render_invoice(request, {
- 'DATE': timezone.now(),
- 'recipient_name': recipient,
- 'address': address,
- 'article': articles_info,
- 'total': total_price,
- 'paid': paid,
- 'asso_name': AssoOption.get_cached_value('name'),
- 'line1': AssoOption.get_cached_value('adresse1'),
- 'line2': AssoOption.get_cached_value('adresse2'),
- 'siret': AssoOption.get_cached_value('siret'),
- 'email': AssoOption.get_cached_value('contact'),
- 'phone': AssoOption.get_cached_value('telephone'),
- 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
- })
+ new_invoice_instance = invoice_form.save()
+ for art_item in articles_formset:
+ if art_item.cleaned_data:
+ article = art_item.cleaned_data['article']
+ quantity = art_item.cleaned_data['quantity']
+ Vente.objects.create(
+ facture=new_invoice_instance,
+ name=article.name,
+ prix=article.prix,
+ type_cotisation=article.type_cotisation,
+ duration=article.duration,
+ number=quantity
+ )
+ messages.success(
+ request,
+ _('The custom invoice was successfully created.')
+ )
+ return redirect(reverse('cotisations:index-custom-invoice'))
+
+
return form({
'factureform': invoice_form,
'action_name': _("Create"),
'articlesformset': articles_formset,
- 'articles': articles
+ 'articlelist': articles
}, 'cotisations/facture.html', request)
@@ -292,7 +287,7 @@ def facture_pdf(request, facture, **_kwargs):
def edit_facture(request, facture, **_kwargs):
"""
View used to edit an existing invoice.
- Articles can be added or remove to the invoice and quantity
+ Articles can be added or removed to the invoice and quantity
can be set as desired. This is also the view used to invalidate
an invoice.
"""
@@ -347,6 +342,100 @@ def del_facture(request, facture, **_kwargs):
}, 'cotisations/delete.html', request)
+@login_required
+@can_edit(CustomInvoice)
+def edit_custom_invoice(request, invoice, **kwargs):
+ # Building the invocie form and the article formset
+ invoice_form = CustomInvoiceForm(
+ request.POST or None,
+ instance=invoice
+ )
+ purchases_objects = Vente.objects.filter(facture=invoice)
+ purchase_form_set = modelformset_factory(
+ Vente,
+ fields=('name', 'number'),
+ extra=0,
+ max_num=len(purchases_objects)
+ )
+ purchase_form = purchase_form_set(
+ request.POST or None,
+ queryset=purchases_objects
+ )
+ if invoice_form.is_valid() and purchase_form.is_valid():
+ if invoice_form.changed_data:
+ invoice_form.save()
+ purchase_form.save()
+ messages.success(
+ request,
+ _("The invoice has been successfully edited.")
+ )
+ return redirect(reverse('cotisations:index-custom-invoice'))
+
+ return form({
+ 'factureform': invoice_form,
+ 'venteform': purchase_form
+ }, 'cotisations/edit_facture.html', request)
+
+
+@login_required
+@can_view(CustomInvoice)
+def custom_invoice_pdf(request, invoice, **_kwargs):
+ """
+ View used to generate a PDF file from an existing invoice in database
+ Creates a line for each Purchase (thus article sold) and generate the
+ invoice with the total price, the payment method, the address and the
+ legal information for the user.
+ """
+ # TODO : change vente to purchase
+ purchases_objects = Vente.objects.all().filter(facture=invoice)
+ # Get the article list and build an list out of it
+ # contiaining (article_name, article_price, quantity, total_price)
+ purchases_info = []
+ for purchase in purchases_objects:
+ purchases_info.append({
+ 'name': purchase.name,
+ 'price': purchase.prix,
+ 'quantity': purchase.number,
+ 'total_price': purchase.prix_total
+ })
+ return render_invoice(request, {
+ 'paid': invoice.paid,
+ 'fid': invoice.id,
+ 'DATE': invoice.date,
+ 'recipient_name': invoice.recipient,
+ 'address': invoice.address,
+ 'article': purchases_info,
+ 'total': invoice.prix_total(),
+ 'asso_name': AssoOption.get_cached_value('name'),
+ 'line1': AssoOption.get_cached_value('adresse1'),
+ 'line2': AssoOption.get_cached_value('adresse2'),
+ 'siret': AssoOption.get_cached_value('siret'),
+ 'email': AssoOption.get_cached_value('contact'),
+ 'phone': AssoOption.get_cached_value('telephone'),
+ 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
+ })
+
+
+# TODO : change facture to invoice
+@login_required
+@can_delete(CustomInvoice)
+def del_custom_invoice(request, invoice, **_kwargs):
+ """
+ View used to delete an existing invocie.
+ """
+ if request.method == "POST":
+ invoice.delete()
+ messages.success(
+ request,
+ _("The invoice has been successfully deleted.")
+ )
+ return redirect(reverse('cotisations:index-custom-invoice'))
+ return form({
+ 'objet': invoice,
+ 'objet_name': _("Invoice")
+ }, 'cotisations/delete.html', request)
+
+
@login_required
@can_create(Article)
def add_article(request):
@@ -681,8 +770,31 @@ def index_banque(request):
})
+@login_required
+@can_view_all(CustomInvoice)
+def index_custom_invoice(request):
+ """View used to display every custom invoice."""
+ pagination_number = GeneralOption.get_cached_value('pagination_number')
+ custom_invoice_list = CustomInvoice.objects.prefetch_related('vente_set')
+ custom_invoice_list = SortTable.sort(
+ custom_invoice_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.COTISATIONS_CUSTOM
+ )
+ custom_invoice_list = re2o_paginator(
+ request,
+ custom_invoice_list,
+ pagination_number,
+ )
+ return render(request, 'cotisations/index_custom_invoice.html', {
+ 'custom_invoice_list': custom_invoice_list
+ })
+
+
@login_required
@can_view_all(Facture)
+@can_view_all(CustomInvoice)
def index(request):
"""
View used to display the list of all exisitng invoices.
@@ -698,7 +810,7 @@ def index(request):
)
invoice_list = re2o_paginator(request, invoice_list, pagination_number)
return render(request, 'cotisations/index.html', {
- 'facture_list': invoice_list
+ 'facture_list': invoice_list,
})
diff --git a/re2o/utils.py b/re2o/utils.py
index 75304369..6f7870f0 100644
--- a/re2o/utils.py
+++ b/re2o/utils.py
@@ -250,6 +250,14 @@ class SortTable:
'cotis_id': ['id'],
'default': ['-date']
}
+ COTISATIONS_CUSTOM = {
+ 'invoice_date': ['date'],
+ 'invoice_id': ['id'],
+ 'invoice_recipient': ['recipient'],
+ 'invoice_address': ['address'],
+ 'invoice_payment': ['payment'],
+ 'default': ['-date']
+ }
COTISATIONS_CONTROL = {
'control_name': ['user__adherent__name'],
'control_surname': ['user__surname'],
diff --git a/templates/buttons/add.html b/templates/buttons/add.html
index 17058b89..33148a7b 100644
--- a/templates/buttons/add.html
+++ b/templates/buttons/add.html
@@ -21,6 +21,6 @@ You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
-
+