mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-12-25 00:13:45 +00:00
Creation d'articles contenant ou non les adhésion, nouveau system fin adh fin co
This commit is contained in:
parent
d069baf100
commit
8ed051fc54
7 changed files with 168 additions and 16 deletions
20
cotisations/migrations/0025_article_type_user.py
Normal file
20
cotisations/migrations/0025_article_type_user.py
Normal file
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
78
cotisations/migrations/0026_auto_20171028_0126.py
Normal file
78
cotisations/migrations/0026_auto_20171028_0126.py
Normal file
|
@ -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',
|
||||||
|
),
|
||||||
|
]
|
|
@ -127,15 +127,26 @@ class Vente(models.Model):
|
||||||
iscotisation"""
|
iscotisation"""
|
||||||
PRETTY_NAME = "Ventes effectuées"
|
PRETTY_NAME = "Ventes effectuées"
|
||||||
|
|
||||||
|
COTISATION_TYPE = (
|
||||||
|
('Connexion', 'Connexion'),
|
||||||
|
('Adhesion', 'Adhesion'),
|
||||||
|
('All', 'All'),
|
||||||
|
)
|
||||||
|
|
||||||
facture = models.ForeignKey('Facture', on_delete=models.CASCADE)
|
facture = models.ForeignKey('Facture', on_delete=models.CASCADE)
|
||||||
number = models.IntegerField(validators=[MinValueValidator(1)])
|
number = models.IntegerField(validators=[MinValueValidator(1)])
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
prix = models.DecimalField(max_digits=5, decimal_places=2)
|
prix = models.DecimalField(max_digits=5, decimal_places=2)
|
||||||
iscotisation = models.BooleanField()
|
|
||||||
duration = models.PositiveIntegerField(
|
duration = models.PositiveIntegerField(
|
||||||
help_text="Durée exprimée en mois entiers",
|
help_text="Durée exprimée en mois entiers",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True)
|
null=True)
|
||||||
|
type_cotisation = models.CharField(
|
||||||
|
choices=COTISATION_TYPE,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
max_length=255
|
||||||
|
)
|
||||||
|
|
||||||
def prix_total(self):
|
def prix_total(self):
|
||||||
"""Renvoie le prix_total de self (nombre*prix)"""
|
"""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
|
"""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
|
en argument l'user, la facture pour la quantitéi, et l'article pour
|
||||||
la durée"""
|
la durée"""
|
||||||
if not hasattr(self, 'cotisation'):
|
if not hasattr(self, 'cotisation') and self.type_cotisation:
|
||||||
cotisation = Cotisation(vente=self)
|
cotisation = Cotisation(vente=self)
|
||||||
|
cotisation.type_cotisation = self.type_cotisation
|
||||||
if date_start:
|
if date_start:
|
||||||
end_adhesion = Cotisation.objects.filter(
|
end_adhesion = Cotisation.objects.filter(
|
||||||
vente__in=Vente.objects.filter(
|
vente__in=Vente.objects.filter(
|
||||||
facture__in=Facture.objects.filter(
|
facture__in=Facture.objects.filter(
|
||||||
user=self.facture.user
|
user=self.facture.user
|
||||||
).exclude(valid=False))
|
).exclude(valid=False))
|
||||||
|
).filter(Q(type_cotisation='All') | Q(type_cotisation=self.type_cotisation)
|
||||||
).filter(
|
).filter(
|
||||||
date_start__lt=date_start
|
date_start__lt=date_start
|
||||||
).aggregate(Max('date_end'))['date_end__max']
|
).aggregate(Max('date_end'))['date_end__max']
|
||||||
|
elif self.type_cotisation=="Adhesion":
|
||||||
|
end_cotisation = self.facture.user.end_adhesion()
|
||||||
else:
|
else:
|
||||||
end_adhesion = self.facture.user.end_adhesion()
|
end_cotisation = self.facture.user.end_connexion()
|
||||||
date_start = date_start or timezone.now()
|
date_start = date_start or timezone.now()
|
||||||
end_adhesion = end_adhesion or date_start
|
end_cotisation = end_cotisation or date_start
|
||||||
date_max = max(end_adhesion, date_start)
|
date_max = max(end_cotisation, date_start)
|
||||||
cotisation.date_start = date_max
|
cotisation.date_start = date_max
|
||||||
cotisation.date_end = cotisation.date_start + relativedelta(
|
cotisation.date_end = cotisation.date_start + relativedelta(
|
||||||
months=self.duration*self.number
|
months=self.duration*self.number
|
||||||
|
@ -179,7 +194,7 @@ class Vente(models.Model):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# On verifie que si iscotisation, duration est présent
|
# 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\
|
raise ValidationError("Cotisation et durée doivent être présents\
|
||||||
ensembles")
|
ensembles")
|
||||||
self.update_cotisation()
|
self.update_cotisation()
|
||||||
|
@ -197,7 +212,7 @@ def vente_post_save(sender, **kwargs):
|
||||||
if hasattr(vente, 'cotisation'):
|
if hasattr(vente, 'cotisation'):
|
||||||
vente.cotisation.vente = vente
|
vente.cotisation.vente = vente
|
||||||
vente.cotisation.save()
|
vente.cotisation.save()
|
||||||
if vente.iscotisation:
|
if vente.type_cotisation:
|
||||||
vente.create_cotis()
|
vente.create_cotis()
|
||||||
vente.cotisation.save()
|
vente.cotisation.save()
|
||||||
user = vente.facture.user
|
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
|
"""Après suppression d'une vente, on synchronise l'user ldap (ex
|
||||||
suppression d'une cotisation"""
|
suppression d'une cotisation"""
|
||||||
vente = kwargs['instance']
|
vente = kwargs['instance']
|
||||||
if vente.iscotisation:
|
if vente.type_cotisation:
|
||||||
user = vente.facture.user
|
user = vente.facture.user
|
||||||
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
|
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"""
|
et duree si c'est une cotisation"""
|
||||||
PRETTY_NAME = "Articles en vente"
|
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)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
prix = models.DecimalField(max_digits=5, decimal_places=2)
|
prix = models.DecimalField(max_digits=5, decimal_places=2)
|
||||||
iscotisation = models.BooleanField()
|
|
||||||
duration = models.PositiveIntegerField(
|
duration = models.PositiveIntegerField(
|
||||||
help_text="Durée exprimée en mois entiers",
|
help_text="Durée exprimée en mois entiers",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[MinValueValidator(0)])
|
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):
|
def clean(self):
|
||||||
if self.name.lower() == "solde":
|
if self.name.lower() == "solde":
|
||||||
raise ValidationError("Solde est un nom d'article invalide")
|
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):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -275,7 +317,17 @@ class Cotisation(models.Model):
|
||||||
"""Objet cotisation, debut et fin, relié en onetoone à une vente"""
|
"""Objet cotisation, debut et fin, relié en onetoone à une vente"""
|
||||||
PRETTY_NAME = "Cotisations"
|
PRETTY_NAME = "Cotisations"
|
||||||
|
|
||||||
|
COTISATION_TYPE = (
|
||||||
|
('Connexion', 'Connexion'),
|
||||||
|
('Adhesion', 'Adhesion'),
|
||||||
|
('All', 'All'),
|
||||||
|
)
|
||||||
|
|
||||||
vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True)
|
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_start = models.DateTimeField()
|
||||||
date_end = models.DateTimeField()
|
date_end = models.DateTimeField()
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<tr>
|
<tr>
|
||||||
<th>Article</th>
|
<th>Article</th>
|
||||||
<th>Prix</th>
|
<th>Prix</th>
|
||||||
<th>Cotisation</th>
|
<th>Type Cotisation</th>
|
||||||
<th>Durée (mois)</th>
|
<th>Durée (mois)</th>
|
||||||
|
<th>Article pour</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -36,8 +37,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ article.name }}</td>
|
<td>{{ article.name }}</td>
|
||||||
<td>{{ article.prix }}</td>
|
<td>{{ article.prix }}</td>
|
||||||
<td>{{ article.iscotisation }}</td>
|
<td>{{ article.type_cotisation }}</td>
|
||||||
<td>{{ article.duration }}</td>
|
<td>{{ article.duration }}</td>
|
||||||
|
<td>{{ article.type_user }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if is_trez %}
|
{% if is_trez %}
|
||||||
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-article' article.id %}">
|
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-article' article.id %}">
|
||||||
|
|
|
@ -106,7 +106,7 @@ def new_facture(request, userid):
|
||||||
facture=new_facture_instance,
|
facture=new_facture_instance,
|
||||||
name=article.name,
|
name=article.name,
|
||||||
prix=article.prix,
|
prix=article.prix,
|
||||||
iscotisation=article.iscotisation,
|
type_cotisation=article.type_cotisation,
|
||||||
duration=article.duration,
|
duration=article.duration,
|
||||||
number=quantity
|
number=quantity
|
||||||
)
|
)
|
||||||
|
@ -114,7 +114,7 @@ def new_facture(request, userid):
|
||||||
new_vente.save()
|
new_vente.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
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):
|
for art_item in articles if art_item.cleaned_data):
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
|
@ -312,8 +312,6 @@ def credit_solde(request, userid):
|
||||||
facture=facture_instance,
|
facture=facture_instance,
|
||||||
name="solde",
|
name="solde",
|
||||||
prix=facture.cleaned_data['montant'],
|
prix=facture.cleaned_data['montant'],
|
||||||
iscotisation=False,
|
|
||||||
duration=0,
|
|
||||||
number=1
|
number=1
|
||||||
)
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
|
|
@ -56,6 +56,7 @@ def all_adherent(search_time=DT_NOW):
|
||||||
return User.objects.filter(
|
return User.objects.filter(
|
||||||
facture__in=Facture.objects.filter(
|
facture__in=Facture.objects.filter(
|
||||||
vente__in=Vente.objects.filter(
|
vente__in=Vente.objects.filter(
|
||||||
|
Q(type_cotisation='All') | Q(type_cotisation='Adhesion'),
|
||||||
cotisation__in=Cotisation.objects.filter(
|
cotisation__in=Cotisation.objects.filter(
|
||||||
vente__in=Vente.objects.filter(
|
vente__in=Vente.objects.filter(
|
||||||
facture__in=Facture.objects.all().exclude(valid=False)
|
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(
|
Q(facture__in=Facture.objects.filter(
|
||||||
vente__in=Vente.objects.filter(
|
vente__in=Vente.objects.filter(
|
||||||
cotisation__in=Cotisation.objects.filter(
|
cotisation__in=Cotisation.objects.filter(
|
||||||
|
Q(type_cotisation='All') | Q(type_cotisation='Connexion'),
|
||||||
vente__in=Vente.objects.filter(
|
vente__in=Vente.objects.filter(
|
||||||
facture__in=Facture.objects.all()
|
facture__in=Facture.objects.all()
|
||||||
.exclude(valid=False)
|
.exclude(valid=False)
|
||||||
|
|
|
@ -146,7 +146,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<th scope="row">Connexion</th>
|
<th scope="row">Connexion</th>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if request_user.has_access %}
|
{% if request_user.has_access %}
|
||||||
<font color="green">Active</font>
|
<font color="green">Active (jusqu'au {{ request.user.end_access }})</font>
|
||||||
{% else %}
|
{% else %}
|
||||||
<font color="red">Désactivée</font>
|
<font color="red">Désactivée</font>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in a new issue