# 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. from django.db import models from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from dateutil.relativedelta import relativedelta from django.forms import ValidationError from django.core.validators import MinValueValidator from django.utils import timezone from machines.models import regen class Facture(models.Model): PRETTY_NAME = "Factures émises" user = models.ForeignKey('users.User', on_delete=models.PROTECT) paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT) banque = models.ForeignKey('Banque', on_delete=models.PROTECT, blank=True, null=True) cheque = models.CharField(max_length=255, blank=True) date = models.DateTimeField(auto_now_add=True) valid = models.BooleanField(default=True) control = models.BooleanField(default=False) def prix(self): prix = Vente.objects.filter(facture=self).aggregate(models.Sum('prix'))['prix__sum'] return prix def prix_total(self): return Vente.objects.filter(facture=self).aggregate(total=models.Sum(models.F('prix')*models.F('number'), output_field=models.FloatField()))['total'] def name(self): name = ' - '.join(Vente.objects.filter(facture=self).values_list('name', flat=True)) return name def __str__(self): return str(self.user) + ' ' + str(self.date) @receiver(post_save, sender=Facture) def facture_post_save(sender, **kwargs): facture = kwargs['instance'] user = facture.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) @receiver(post_delete, sender=Facture) def facture_post_delete(sender, **kwargs): user = kwargs['instance'].user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) class Vente(models.Model): PRETTY_NAME = "Ventes effectuées" 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.IntegerField(help_text="Durée exprimée en mois entiers", blank=True, null=True) def prix_total(self): return self.prix*self.number def update_cotisation(self): if hasattr(self, 'cotisation'): cotisation = self.cotisation cotisation.date_end = cotisation.date_start + relativedelta(months=self.duration*self.number) cotisation.save() return def create_cotis(self, date_start=False): """ 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'): cotisation=Cotisation(vente=self) 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(date_start__lt=date_start).aggregate(Max('date_end'))['date_end__max'] else: end_adhesion = self.facture.user.end_adhesion() date_start = date_start or timezone.now() end_adhesion = end_adhesion or date_start date_max = max(end_adhesion, date_start) cotisation.date_start = date_max cotisation.date_end = cotisation.date_start + relativedelta(months=self.duration*self.number) cotisation.save() return def save(self, *args, **kwargs): # On verifie que si iscotisation, duration est présent if self.iscotisation and not self.duration: raise ValidationError("Cotisation et durée doivent être présents ensembles") self.update_cotisation() super(Vente, self).save(*args, **kwargs) def __str__(self): return str(self.name) + ' ' + str(self.facture) @receiver(post_save, sender=Vente) def vente_post_save(sender, **kwargs): vente = kwargs['instance'] if vente.iscotisation: vente.create_cotis() user = vente.facture.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) @receiver(post_delete, sender=Vente) def vente_post_delete(sender, **kwargs): vente = kwargs['instance'] if vente.iscotisation: user = vente.facture.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) class Article(models.Model): PRETTY_NAME = "Articles en vente" name = models.CharField(max_length=255, unique=True) prix = models.DecimalField(max_digits=5, decimal_places=2) iscotisation = models.BooleanField() duration = models.IntegerField( help_text="Durée exprimée en mois entiers", blank=True, null=True, validators=[MinValueValidator(0)]) def clean(self): if self.name.lower() == "solde": raise ValidationError("Solde est un nom d'article invalide") def __str__(self): return self.name class Banque(models.Model): PRETTY_NAME = "Banques enregistrées" name = models.CharField(max_length=255) def __str__(self): return self.name class Paiement(models.Model): PRETTY_NAME = "Moyens de paiement" PAYMENT_TYPES = ( (0, 'Autre'), (1, 'Chèque'), ) moyen = models.CharField(max_length=255) type_paiement = models.IntegerField(choices=PAYMENT_TYPES, default=0, max_length=255) def __str__(self): return self.moyen def clean(self): self.moyen = self.moyen.title() class Cotisation(models.Model): PRETTY_NAME = "Cotisations" vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True) date_start = models.DateTimeField() date_end = models.DateTimeField() def __str__(self): return str(self.vente) @receiver(post_save, sender=Cotisation) def cotisation_post_save(sender, **kwargs): regen('dns') regen('dhcp') regen('mac_ip_list') @receiver(post_delete, sender=Cotisation) def vente_post_delete(sender, **kwargs): cotisation = kwargs['instance'] regen('mac_ip_list')