From 898ae901e0950b38a1e791e3609b241944d38810 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 28 Oct 2017 04:59:40 +0200 Subject: [PATCH] =?UTF-8?q?Creation=20d'articles=20contenant=20ou=20non=20?= =?UTF-8?q?les=20adh=C3=A9sion,=20nouveau=20system=20fin=20adh=20fin=20co?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0025_article_type_user.py | 20 +++++ .../migrations/0026_auto_20171028_0126.py | 78 +++++++++++++++++++ cotisations/models.py | 70 ++++++++++++++--- .../templates/cotisations/aff_article.html | 6 +- cotisations/views.py | 6 +- re2o/utils.py | 2 + templates/base.html | 2 +- 7 files changed, 168 insertions(+), 16 deletions(-) create mode 100644 cotisations/migrations/0025_article_type_user.py create mode 100644 cotisations/migrations/0026_auto_20171028_0126.py diff --git a/cotisations/migrations/0025_article_type_user.py b/cotisations/migrations/0025_article_type_user.py new file mode 100644 index 00000000..5ad329fa --- /dev/null +++ b/cotisations/migrations/0025_article_type_user.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-27 03:02 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0024_auto_20171015_2033'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='type_user', + field=models.CharField(choices=[('Adherent', 'Adherent'), ('Club', 'Club'), ('All', 'All')], default='All', max_length=255), + ), + ] diff --git a/cotisations/migrations/0026_auto_20171028_0126.py b/cotisations/migrations/0026_auto_20171028_0126.py new file mode 100644 index 00000000..cf992ae1 --- /dev/null +++ b/cotisations/migrations/0026_auto_20171028_0126.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-27 23:26 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def create_type(apps, schema_editor): + Cotisation = apps.get_model('cotisations', 'Cotisation') + Vente = apps.get_model('cotisations', 'Vente') + Article = apps.get_model('cotisations', 'Article') + db_alias = schema_editor.connection.alias + articles = Articles.objects.using(db_alias).all() + ventes = Vente.objects.using(db_alias).all() + cotisations = Cotisation.objects.using(db_alias).all() + for article in articles: + if article.iscotisation: + article.type_cotisation='All' + article.save(using=db_alias) + for vente in ventes: + if vente.iscotisation: + vente.type_cotisation='All' + vente.save(using=db_alias) + for cotisation in cotisations: + cotisation.type_cotisation='All' + cotisation.save(using=db_alias) + +def delete_type(apps, schema_editor): + Vente = apps.get_model('cotisations', 'Vente') + Article = apps.get_model('cotisations', 'Article') + db_alias = schema_editor.connection.alias + articles = Articles.objects.using(db_alias).all() + ventes = Vente.objects.using(db_alias).all() + for article in articles: + if article.type_cotisation: + article.iscotisation=True + else: + article.iscotisation=False + article.save(using=db_alias) + for vente in ventes: + if vente.iscotisation: + vente.iscotisation=True + else: + vente.iscotisation=False + vente.save(using=db_alias) + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0025_article_type_user'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='type_cotisation', + field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], default=None, max_length=255, null=True), + ), + migrations.AddField( + model_name='cotisation', + name='type_cotisation', + field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255), + ), + migrations.AddField( + model_name='vente', + name='type_cotisation', + field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, null=True), + ), + migrations.RunPython(create_type, delete_type), + migrations.RemoveField( + model_name='article', + name='iscotisation', + ), + migrations.RemoveField( + model_name='vente', + name='iscotisation', + ), + ] diff --git a/cotisations/models.py b/cotisations/models.py index 0b3aef35..22daaf9a 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -127,15 +127,26 @@ class Vente(models.Model): iscotisation""" PRETTY_NAME = "Ventes effectuées" + COTISATION_TYPE = ( + ('Connexion', 'Connexion'), + ('Adhesion', 'Adhesion'), + ('All', 'All'), + ) + facture = models.ForeignKey('Facture', on_delete=models.CASCADE) number = models.IntegerField(validators=[MinValueValidator(1)]) name = models.CharField(max_length=255) prix = models.DecimalField(max_digits=5, decimal_places=2) - iscotisation = models.BooleanField() duration = models.PositiveIntegerField( help_text="Durée exprimée en mois entiers", blank=True, null=True) + type_cotisation = models.CharField( + choices=COTISATION_TYPE, + blank=True, + null=True, + max_length=255 + ) def prix_total(self): """Renvoie le prix_total de self (nombre*prix)""" @@ -155,22 +166,26 @@ class Vente(models.Model): """Update et crée l'objet cotisation associé à une facture, prend en argument l'user, la facture pour la quantitéi, et l'article pour la durée""" - if not hasattr(self, 'cotisation'): + if not hasattr(self, 'cotisation') and self.type_cotisation: cotisation = Cotisation(vente=self) + cotisation.type_cotisation = self.type_cotisation if date_start: end_adhesion = Cotisation.objects.filter( vente__in=Vente.objects.filter( facture__in=Facture.objects.filter( user=self.facture.user ).exclude(valid=False)) + ).filter(Q(type_cotisation='All') | Q(type_cotisation=self.type_cotisation) ).filter( date_start__lt=date_start ).aggregate(Max('date_end'))['date_end__max'] + elif self.type_cotisation=="Adhesion": + end_cotisation = self.facture.user.end_adhesion() else: - end_adhesion = self.facture.user.end_adhesion() + end_cotisation = self.facture.user.end_connexion() date_start = date_start or timezone.now() - end_adhesion = end_adhesion or date_start - date_max = max(end_adhesion, date_start) + end_cotisation = end_cotisation or date_start + date_max = max(end_cotisation, date_start) cotisation.date_start = date_max cotisation.date_end = cotisation.date_start + relativedelta( months=self.duration*self.number @@ -179,7 +194,7 @@ class Vente(models.Model): def save(self, *args, **kwargs): # On verifie que si iscotisation, duration est présent - if self.iscotisation and not self.duration: + if self.type_cotisation and not self.duration: raise ValidationError("Cotisation et durée doivent être présents\ ensembles") self.update_cotisation() @@ -197,7 +212,7 @@ def vente_post_save(sender, **kwargs): if hasattr(vente, 'cotisation'): vente.cotisation.vente = vente vente.cotisation.save() - if vente.iscotisation: + if vente.type_cotisation: vente.create_cotis() vente.cotisation.save() user = vente.facture.user @@ -209,7 +224,7 @@ def vente_post_delete(sender, **kwargs): """Après suppression d'une vente, on synchronise l'user ldap (ex suppression d'une cotisation""" vente = kwargs['instance'] - if vente.iscotisation: + if vente.type_cotisation: user = vente.facture.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) @@ -219,18 +234,45 @@ class Article(models.Model): et duree si c'est une cotisation""" PRETTY_NAME = "Articles en vente" + USER_TYPES = ( + ('Adherent', 'Adherent'), + ('Club', 'Club'), + ('All', 'All'), + ) + + COTISATION_TYPE = ( + ('Connexion', 'Connexion'), + ('Adhesion', 'Adhesion'), + ('All', 'All'), + ) + name = models.CharField(max_length=255, unique=True) prix = models.DecimalField(max_digits=5, decimal_places=2) - iscotisation = models.BooleanField() duration = models.PositiveIntegerField( help_text="Durée exprimée en mois entiers", blank=True, null=True, validators=[MinValueValidator(0)]) + type_user = models.CharField( + choices=USER_TYPES, + default='All', + max_length=255 + ) + type_cotisation = models.CharField( + choices=COTISATION_TYPE, + default=None, + blank=True, + null=True, + max_length=255 + ) def clean(self): if self.name.lower() == "solde": raise ValidationError("Solde est un nom d'article invalide") + if self.type_cotisation and not self.duration: + raise ValidationError( + "La durée est obligatoire si il s'agit d'une cotisation" + ) def __str__(self): return self.name @@ -275,7 +317,17 @@ class Cotisation(models.Model): """Objet cotisation, debut et fin, relié en onetoone à une vente""" PRETTY_NAME = "Cotisations" + COTISATION_TYPE = ( + ('Connexion', 'Connexion'), + ('Adhesion', 'Adhesion'), + ('All', 'All'), + ) + vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True) + type_cotisation = models.CharField( + choices=COTISATION_TYPE, + max_length=255, + ) date_start = models.DateTimeField() date_end = models.DateTimeField() diff --git a/cotisations/templates/cotisations/aff_article.html b/cotisations/templates/cotisations/aff_article.html index b756f746..3a0b21f6 100644 --- a/cotisations/templates/cotisations/aff_article.html +++ b/cotisations/templates/cotisations/aff_article.html @@ -27,8 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc., Article Prix - Cotisation + Type Cotisation Durée (mois) + Article pour @@ -36,8 +37,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ article.name }} {{ article.prix }} - {{ article.iscotisation }} + {{ article.type_cotisation }} {{ article.duration }} + {{ article.type_user }} {% if is_trez %} diff --git a/cotisations/views.py b/cotisations/views.py index f0481996..2331e34b 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -106,7 +106,7 @@ def new_facture(request, userid): facture=new_facture_instance, name=article.name, prix=article.prix, - iscotisation=article.iscotisation, + type_cotisation=article.type_cotisation, duration=article.duration, number=quantity ) @@ -114,7 +114,7 @@ def new_facture(request, userid): new_vente.save() reversion.set_user(request.user) reversion.set_comment("Création") - if any(art_item.cleaned_data['article'].iscotisation + if any(art_item.cleaned_data['article'].type_cotisation for art_item in articles if art_item.cleaned_data): messages.success( request, @@ -312,8 +312,6 @@ def credit_solde(request, userid): facture=facture_instance, name="solde", prix=facture.cleaned_data['montant'], - iscotisation=False, - duration=0, number=1 ) with transaction.atomic(), reversion.create_revision(): diff --git a/re2o/utils.py b/re2o/utils.py index d3c87557..0fa6a84c 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -56,6 +56,7 @@ def all_adherent(search_time=DT_NOW): return User.objects.filter( facture__in=Facture.objects.filter( vente__in=Vente.objects.filter( + Q(type_cotisation='All') | Q(type_cotisation='Adhesion'), cotisation__in=Cotisation.objects.filter( vente__in=Vente.objects.filter( facture__in=Facture.objects.all().exclude(valid=False) @@ -94,6 +95,7 @@ def all_has_access(search_time=DT_NOW): Q(facture__in=Facture.objects.filter( vente__in=Vente.objects.filter( cotisation__in=Cotisation.objects.filter( + Q(type_cotisation='All') | Q(type_cotisation='Connexion'), vente__in=Vente.objects.filter( facture__in=Facture.objects.all() .exclude(valid=False) diff --git a/templates/base.html b/templates/base.html index dfaca5eb..83bea233 100644 --- a/templates/base.html +++ b/templates/base.html @@ -146,7 +146,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Connexion {% if request_user.has_access %} - Active + Active (jusqu'au {{ request.user.end_access }}) {% else %} Désactivée {% endif %}