diff --git a/api/permissions.py b/api/permissions.py
index 3054acd2..8753202e 100644
--- a/api/permissions.py
+++ b/api/permissions.py
@@ -239,7 +239,9 @@ class AutodetectACLPermission(permissions.BasePermission):
if getattr(view, "_ignore_model_permissions", False):
return True
- if not getattr(view, "queryset", getattr(view, "get_queryset", None)):
+ # Bypass permission verifications if it is a functional view
+ # (permissions are handled by ACL)
+ if not hasattr(view, "queryset") and not hasattr(view, "get_queryset"):
return True
if not request.user or not request.user.is_authenticated:
diff --git a/cotisations/forms.py b/cotisations/forms.py
index 0f135963..f9e44686 100644
--- a/cotisations/forms.py
+++ b/cotisations/forms.py
@@ -46,6 +46,7 @@ from django.shortcuts import get_object_or_404
from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
+from re2o.widgets import AutocompleteModelWidget
from .models import (
Article,
Paiement,
@@ -79,6 +80,10 @@ class FactureForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
class Meta:
model = Facture
fields = "__all__"
+ widgets = {
+ "user": AutocompleteModelWidget(url="/users/user-autocomplete"),
+ "banque": AutocompleteModelWidget(url="/cotisations/banque-autocomplete"),
+ }
def clean(self):
cleaned_data = super(FactureForm, self).clean()
diff --git a/cotisations/migrations/0051_auto_20201228_1636.py b/cotisations/migrations/0051_auto_20201228_1636.py
new file mode 100644
index 00000000..572c9634
--- /dev/null
+++ b/cotisations/migrations/0051_auto_20201228_1636.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.29 on 2020-12-28 15:36
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("cotisations", "0050_auto_20201102_2342"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="article",
+ name="duration_connection",
+ field=models.PositiveIntegerField(
+ verbose_name="duration of the connection (in months)"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="article",
+ name="duration_days_connection",
+ field=models.PositiveIntegerField(
+ verbose_name="duration of the connection (in days, will be added to duration in months)"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="article",
+ name="duration_days_membership",
+ field=models.PositiveIntegerField(
+ verbose_name="duration of the membership (in days, will be added to duration in months)"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="article",
+ name="duration_membership",
+ field=models.PositiveIntegerField(
+ verbose_name="duration of the membership (in months)"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="vente",
+ name="duration_days_connection",
+ field=models.PositiveIntegerField(
+ default=0,
+ verbose_name="duration of the connection (in days, will be added to duration in months)",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="vente",
+ name="duration_days_membership",
+ field=models.PositiveIntegerField(
+ default=0,
+ verbose_name="duration of the membership (in days, will be added to duration in months)",
+ ),
+ ),
+ ]
diff --git a/cotisations/models.py b/cotisations/models.py
index b3480561..5dc18e4f 100644
--- a/cotisations/models.py
+++ b/cotisations/models.py
@@ -98,7 +98,7 @@ class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def name_detailed(self):
"""
- Return:
+ Return:
- a list of strings with the name of all article in the invoice
and their quantity.
"""
@@ -248,8 +248,8 @@ class Facture(BaseInvoice):
@staticmethod
def can_change_control(user_request, *_args, **_kwargs):
- """ Returns True if the user can change the 'controlled' status of
- this invoice """
+ """Returns True if the user can change the 'controlled' status of
+ this invoice"""
can = user_request.has_perm("cotisations.change_facture_control")
return (
can,
@@ -293,8 +293,7 @@ class Facture(BaseInvoice):
"""Returns every subscription associated with this invoice."""
return Cotisation.objects.filter(
vente__in=self.vente_set.filter(
- ~(Q(duration_membership=0)) |\
- ~(Q(duration_days_membership=0))
+ ~(Q(duration_membership=0)) | ~(Q(duration_days_membership=0))
)
)
@@ -454,7 +453,7 @@ class Vente(RevMixin, AclMixin, models.Model):
number = models.IntegerField(
validators=[MinValueValidator(1)], verbose_name=_("amount")
)
- # TODO : change this field for a ForeinKey to Article
+ # TODO : change this field for a ForeinKey to Article
# Note: With a foreign key, modifing an Article modifis the Purchase, wich is bad.
# To use a foreign key, you need to make Article read only
name = models.CharField(max_length=255, verbose_name=_("article"))
@@ -467,16 +466,18 @@ class Vente(RevMixin, AclMixin, models.Model):
)
duration_days_connection = models.PositiveIntegerField(
default=0,
- validators=[MinValueValidator(0)],
- verbose_name=_("duration of the connection (in days, will be added to duration in months)"),
+ verbose_name=_(
+ "duration of the connection (in days, will be added to duration in months)"
+ ),
)
duration_membership = models.PositiveIntegerField(
default=0, verbose_name=_("duration of the membership (in months)")
)
duration_days_membership = models.PositiveIntegerField(
default=0,
- validators=[MinValueValidator(0)],
- verbose_name=_("duration of the membership (in days, will be added to duration in months)"),
+ verbose_name=_(
+ "duration of the membership (in days, will be added to duration in months)"
+ ),
)
class Meta:
@@ -513,7 +514,7 @@ class Vente(RevMixin, AclMixin, models.Model):
def create_cotis(self, date_start_con=False, date_start_memb=False):
"""
- Creates a cotisation without initializing the dates (start and end ar set to self.facture.facture.date)
+ Creates a cotisation without initializing the dates (start and end ar set to self.facture.facture.date)
and without saving it. You should use Facture.reorder_purchases to set the right dates.
"""
try:
@@ -631,12 +632,14 @@ class Vente(RevMixin, AclMixin, models.Model):
return str(self.name) + " " + str(self.facture)
def test_membership_or_connection(self):
- """ Test if the purchase include membership or connecton
- """
- return self.duration_membership or \
- self.duration_days_membership or \
- self.duration_connection or \
- self.duration_days_connection
+ """Test if the purchase include membership or connecton"""
+ return (
+ self.duration_membership
+ or self.duration_days_membership
+ or self.duration_connection
+ or self.duration_days_connection
+ )
+
# TODO : change vente to purchase
@receiver(post_save, sender=Vente)
@@ -704,20 +707,20 @@ class Article(RevMixin, AclMixin, models.Model):
)
duration_membership = models.PositiveIntegerField(
- validators=[MinValueValidator(0)],
verbose_name=_("duration of the membership (in months)")
)
duration_days_membership = models.PositiveIntegerField(
- validators=[MinValueValidator(0)],
- verbose_name=_("duration of the membership (in days, will be added to duration in months)"),
+ verbose_name=_(
+ "duration of the membership (in days, will be added to duration in months)"
+ ),
)
duration_connection = models.PositiveIntegerField(
- validators=[MinValueValidator(0)],
verbose_name=_("duration of the connection (in months)")
)
duration_days_connection = models.PositiveIntegerField(
- validators=[MinValueValidator(0)],
- verbose_name=_("duration of the connection (in days, will be added to duration in months)"),
+ verbose_name=_(
+ "duration of the connection (in days, will be added to duration in months)"
+ ),
)
need_membership = models.BooleanField(
@@ -793,8 +796,8 @@ class Article(RevMixin, AclMixin, models.Model):
if target_user is not None and not target_user.is_adherent():
objects_pool = objects_pool.filter(
Q(duration_membership__gt=0)
- |Q(duration_days_membership__gt=0)
- |Q(need_membership=False)
+ | Q(duration_days_membership__gt=0)
+ | Q(need_membership=False)
)
if user.has_perm("cotisations.buy_every_article"):
return objects_pool
@@ -884,7 +887,9 @@ class Paiement(RevMixin, AclMixin, models.Model):
# In case a cotisation was bought, inform the user, the
# cotisation time has been extended too
- if any(sell.test_membership_or_connection() for sell in invoice.vente_set.all()):
+ if any(
+ sell.test_membership_or_connection() for sell in invoice.vente_set.all()
+ ):
messages.success(
request,
_(
@@ -956,9 +961,13 @@ class Cotisation(RevMixin, AclMixin, models.Model):
vente = models.OneToOneField(
"Vente", on_delete=models.CASCADE, null=True, verbose_name=_("purchase")
)
- date_start_con = models.DateTimeField(verbose_name=_("start date for the connection"))
+ date_start_con = models.DateTimeField(
+ verbose_name=_("start date for the connection")
+ )
date_end_con = models.DateTimeField(verbose_name=_("end date for the connection"))
- date_start_memb = models.DateTimeField(verbose_name=_("start date for the membership"))
+ date_start_memb = models.DateTimeField(
+ verbose_name=_("start date for the membership")
+ )
date_end_memb = models.DateTimeField(verbose_name=_("end date for the membership"))
class Meta:
diff --git a/cotisations/templates/cotisations/edit_facture.html b/cotisations/templates/cotisations/edit_facture.html
index ca55cb66..b2f58df9 100644
--- a/cotisations/templates/cotisations/edit_facture.html
+++ b/cotisations/templates/cotisations/edit_facture.html
@@ -25,13 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %}
{% load staticfiles%}
-{% load massive_bootstrap_form %}
{% load i18n %}
{% block title %}{% trans "Creation and editing of invoices" %}{% endblock %}
{% block content %}
{% bootstrap_form_errors factureform %}
+{{ factureform.media }}