mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-26 14:42:25 +00:00
Merge branch 'master' into 'massive_use_bft_tag'
# Conflicts: # topologie/views.py
This commit is contained in:
commit
210fa28d74
21 changed files with 985 additions and 327 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ settings_local.py
|
||||||
re2o.png
|
re2o.png
|
||||||
__pycache__/*
|
__pycache__/*
|
||||||
static_files/*
|
static_files/*
|
||||||
|
static/logo/*
|
||||||
|
|
|
@ -28,23 +28,37 @@ from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from .models import Facture, Article, Banque, Paiement, Cotisation, Vente
|
from .models import Facture, Article, Banque, Paiement, Cotisation, Vente
|
||||||
|
|
||||||
|
|
||||||
class FactureAdmin(VersionAdmin):
|
class FactureAdmin(VersionAdmin):
|
||||||
list_display = ('user','paiement','date','valid','control')
|
"""Class admin d'une facture, tous les champs"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class VenteAdmin(VersionAdmin):
|
class VenteAdmin(VersionAdmin):
|
||||||
list_display = ('facture','name','prix','number','iscotisation','duration')
|
"""Class admin d'une vente, tous les champs (facture related)"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ArticleAdmin(VersionAdmin):
|
class ArticleAdmin(VersionAdmin):
|
||||||
list_display = ('name','prix','iscotisation','duration')
|
"""Class admin d'un article en vente"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BanqueAdmin(VersionAdmin):
|
class BanqueAdmin(VersionAdmin):
|
||||||
list_display = ('name',)
|
"""Class admin de la liste des banques (facture related)"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PaiementAdmin(VersionAdmin):
|
class PaiementAdmin(VersionAdmin):
|
||||||
list_display = ('moyen','type_paiement')
|
"""Class admin d'un moyen de paiement (facture related"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CotisationAdmin(VersionAdmin):
|
class CotisationAdmin(VersionAdmin):
|
||||||
list_display = ('vente','date_start','date_end')
|
"""Class admin d'une cotisation (date de debut et de fin),
|
||||||
|
Vente related"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Facture, FactureAdmin)
|
admin.site.register(Facture, FactureAdmin)
|
||||||
admin.site.register(Article, ArticleAdmin)
|
admin.site.register(Article, ArticleAdmin)
|
||||||
|
|
|
@ -19,16 +19,33 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Forms de l'application cotisation de re2o. Dépendance avec les models,
|
||||||
|
importé par les views.
|
||||||
|
|
||||||
|
Permet de créer une nouvelle facture pour un user (NewFactureForm),
|
||||||
|
et de l'editer (soit l'user avec EditFactureForm,
|
||||||
|
soit le trésorier avec TrezEdit qui a plus de possibilités que self
|
||||||
|
notamment sur le controle trésorier)
|
||||||
|
|
||||||
|
SelectArticleForm est utilisée lors de la creation d'une facture en
|
||||||
|
parrallèle de NewFacture pour le choix des articles désirés.
|
||||||
|
(la vue correspondante est unique)
|
||||||
|
|
||||||
|
ArticleForm, BanqueForm, PaiementForm permettent aux admin d'ajouter,
|
||||||
|
éditer ou supprimer une banque/moyen de paiement ou un article
|
||||||
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.forms import ModelForm, Form
|
from django.forms import ModelForm, Form
|
||||||
from django import forms
|
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from .models import Article, Paiement, Facture, Banque, Vente
|
from .models import Article, Paiement, Facture, Banque
|
||||||
|
|
||||||
|
|
||||||
class NewFactureForm(ModelForm):
|
class NewFactureForm(ModelForm):
|
||||||
|
"""Creation d'une facture, moyen de paiement, banque et numero
|
||||||
|
de cheque"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(NewFactureForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(NewFactureForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
@ -36,8 +53,10 @@ class NewFactureForm(ModelForm):
|
||||||
self.fields['banque'].required = False
|
self.fields['banque'].required = False
|
||||||
self.fields['cheque'].label = 'Numero de chèque'
|
self.fields['cheque'].label = 'Numero de chèque'
|
||||||
self.fields['banque'].empty_label = "Non renseigné"
|
self.fields['banque'].empty_label = "Non renseigné"
|
||||||
self.fields['paiement'].empty_label = "Séléctionner un moyen de paiement"
|
self.fields['paiement'].empty_label = "Séléctionner\
|
||||||
self.fields['paiement'].widget.attrs['data-cheque'] = Paiement.objects.filter(type_paiement=1).first().id
|
un moyen de paiement"
|
||||||
|
self.fields['paiement'].widget.attrs['data-cheque'] = Paiement.objects\
|
||||||
|
.filter(type_paiement=1).first().id
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Facture
|
model = Facture
|
||||||
|
@ -49,45 +68,76 @@ class NewFactureForm(ModelForm):
|
||||||
cheque = cleaned_data.get("cheque")
|
cheque = cleaned_data.get("cheque")
|
||||||
banque = cleaned_data.get("banque")
|
banque = cleaned_data.get("banque")
|
||||||
if not paiement:
|
if not paiement:
|
||||||
raise forms.ValidationError("Le moyen de paiement est obligatoire.")
|
raise forms.ValidationError("Le moyen de paiement est obligatoire")
|
||||||
elif paiement.type_paiement == "check" and not (cheque and banque):
|
elif paiement.type_paiement == "check" and not (cheque and banque):
|
||||||
raise forms.ValidationError("Le numéro de chèque et la banque sont obligatoires.")
|
raise forms.ValidationError("Le numéro de chèque et\
|
||||||
|
la banque sont obligatoires.")
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class CreditSoldeForm(NewFactureForm):
|
class CreditSoldeForm(NewFactureForm):
|
||||||
|
"""Permet de faire des opérations sur le solde si il est activé"""
|
||||||
class Meta(NewFactureForm.Meta):
|
class Meta(NewFactureForm.Meta):
|
||||||
model = Facture
|
model = Facture
|
||||||
fields = ['paiement', 'banque', 'cheque']
|
fields = ['paiement', 'banque', 'cheque']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(CreditSoldeForm, self).__init__(*args, **kwargs)
|
super(CreditSoldeForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['paiement'].queryset = Paiement.objects.exclude(moyen='solde').exclude(moyen="Solde")
|
self.fields['paiement'].queryset = Paiement.objects.exclude(
|
||||||
|
moyen='solde'
|
||||||
|
).exclude(moyen="Solde")
|
||||||
|
|
||||||
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
|
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
|
||||||
|
|
||||||
|
|
||||||
class SelectArticleForm(Form):
|
class SelectArticleForm(Form):
|
||||||
article = forms.ModelChoiceField(queryset=Article.objects.all(), label="Article", required=True)
|
"""Selection d'un article lors de la creation d'une facture"""
|
||||||
quantity = forms.IntegerField(label="Quantité", validators=[MinValueValidator(1)], required=True)
|
article = forms.ModelChoiceField(
|
||||||
|
queryset=Article.objects.all(),
|
||||||
|
label="Article",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
quantity = forms.IntegerField(
|
||||||
|
label="Quantité",
|
||||||
|
validators=[MinValueValidator(1)],
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NewFactureFormPdf(Form):
|
class NewFactureFormPdf(Form):
|
||||||
article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article")
|
"""Creation d'un pdf facture par le trésorier"""
|
||||||
number = forms.IntegerField(label="Quantité", validators=[MinValueValidator(1)])
|
article = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Article.objects.all(),
|
||||||
|
label="Article"
|
||||||
|
)
|
||||||
|
number = forms.IntegerField(
|
||||||
|
label="Quantité",
|
||||||
|
validators=[MinValueValidator(1)]
|
||||||
|
)
|
||||||
paid = forms.BooleanField(label="Payé", required=False)
|
paid = forms.BooleanField(label="Payé", required=False)
|
||||||
dest = forms.CharField(required=True, max_length=255, label="Destinataire")
|
dest = forms.CharField(required=True, max_length=255, label="Destinataire")
|
||||||
chambre = forms.CharField(required=False, max_length=10, label="Adresse")
|
chambre = forms.CharField(required=False, max_length=10, label="Adresse")
|
||||||
fid = forms.CharField(required=True, max_length=10, label="Numéro de la facture")
|
fid = forms.CharField(
|
||||||
|
required=True,
|
||||||
|
max_length=10,
|
||||||
|
label="Numéro de la facture"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EditFactureForm(NewFactureForm):
|
class EditFactureForm(NewFactureForm):
|
||||||
|
"""Edition d'une facture : moyen de paiement, banque, user parent"""
|
||||||
class Meta(NewFactureForm.Meta):
|
class Meta(NewFactureForm.Meta):
|
||||||
fields = ['paiement', 'banque', 'cheque', 'user']
|
fields = ['paiement', 'banque', 'cheque', 'user']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(EditFactureForm, self).__init__(*args, **kwargs)
|
super(EditFactureForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['user'].label = 'Adherent'
|
self.fields['user'].label = 'Adherent'
|
||||||
self.fields['user'].empty_label = "Séléctionner l'adhérent propriétaire"
|
self.fields['user'].empty_label = "Séléctionner\
|
||||||
|
l'adhérent propriétaire"
|
||||||
|
|
||||||
|
|
||||||
class TrezEditFactureForm(EditFactureForm):
|
class TrezEditFactureForm(EditFactureForm):
|
||||||
|
"""Vue pour édition controle trésorier"""
|
||||||
class Meta(EditFactureForm.Meta):
|
class Meta(EditFactureForm.Meta):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
@ -98,6 +148,7 @@ class TrezEditFactureForm(EditFactureForm):
|
||||||
|
|
||||||
|
|
||||||
class ArticleForm(ModelForm):
|
class ArticleForm(ModelForm):
|
||||||
|
"""Creation d'un article. Champs : nom, cotisation, durée"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Article
|
model = Article
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -107,10 +158,20 @@ class ArticleForm(ModelForm):
|
||||||
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
self.fields['name'].label = "Désignation de l'article"
|
self.fields['name'].label = "Désignation de l'article"
|
||||||
|
|
||||||
|
|
||||||
class DelArticleForm(Form):
|
class DelArticleForm(Form):
|
||||||
articles = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Articles actuels", widget=forms.CheckboxSelectMultiple)
|
"""Suppression d'un ou plusieurs articles en vente. Choix
|
||||||
|
parmis les modèles"""
|
||||||
|
articles = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Article.objects.all(),
|
||||||
|
label="Articles actuels",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PaiementForm(ModelForm):
|
class PaiementForm(ModelForm):
|
||||||
|
"""Creation d'un moyen de paiement, champ text moyen et type
|
||||||
|
permettant d'indiquer si il s'agit d'un chèque ou non pour le form"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Paiement
|
model = Paiement
|
||||||
fields = ['moyen', 'type_paiement']
|
fields = ['moyen', 'type_paiement']
|
||||||
|
@ -121,10 +182,19 @@ class PaiementForm(ModelForm):
|
||||||
self.fields['moyen'].label = 'Moyen de paiement à ajouter'
|
self.fields['moyen'].label = 'Moyen de paiement à ajouter'
|
||||||
self.fields['type_paiement'].label = 'Type de paiement à ajouter'
|
self.fields['type_paiement'].label = 'Type de paiement à ajouter'
|
||||||
|
|
||||||
|
|
||||||
class DelPaiementForm(Form):
|
class DelPaiementForm(Form):
|
||||||
paiements = forms.ModelMultipleChoiceField(queryset=Paiement.objects.all(), label="Moyens de paiement actuels", widget=forms.CheckboxSelectMultiple)
|
"""Suppression d'un ou plusieurs moyens de paiements, selection
|
||||||
|
parmis les models"""
|
||||||
|
paiements = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Paiement.objects.all(),
|
||||||
|
label="Moyens de paiement actuels",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BanqueForm(ModelForm):
|
class BanqueForm(ModelForm):
|
||||||
|
"""Creation d'une banque, field name"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Banque
|
model = Banque
|
||||||
fields = ['name']
|
fields = ['name']
|
||||||
|
@ -134,5 +204,11 @@ class BanqueForm(ModelForm):
|
||||||
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
self.fields['name'].label = 'Banque à ajouter'
|
self.fields['name'].label = 'Banque à ajouter'
|
||||||
|
|
||||||
|
|
||||||
class DelBanqueForm(Form):
|
class DelBanqueForm(Form):
|
||||||
banques = forms.ModelMultipleChoiceField(queryset=Banque.objects.all(), label="Banques actuelles", widget=forms.CheckboxSelectMultiple)
|
"""Selection d'une ou plusieurs banques, pour suppression"""
|
||||||
|
banques = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Banque.objects.all(),
|
||||||
|
label="Banques actuelles",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
|
@ -20,59 +20,111 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des models bdd pour les factures et cotisation.
|
||||||
|
Pièce maitresse : l'ensemble du code intelligent se trouve ici,
|
||||||
|
dans les clean et save des models ainsi que de leur methodes supplémentaires.
|
||||||
|
|
||||||
|
Facture : reliée à un user, elle a un moyen de paiement, une banque (option),
|
||||||
|
une ou plusieurs ventes
|
||||||
|
|
||||||
|
Article : liste des articles en vente, leur prix, etc
|
||||||
|
|
||||||
|
Vente : ensemble des ventes effectuées, reliées à une facture (foreignkey)
|
||||||
|
|
||||||
|
Banque : liste des banques existantes
|
||||||
|
|
||||||
|
Cotisation : objets de cotisation, contenant un début et une fin. Reliées
|
||||||
|
aux ventes, en onetoone entre une vente et une cotisation.
|
||||||
|
Crées automatiquement au save des ventes.
|
||||||
|
|
||||||
|
Post_save et Post_delete : sychronisation des services et régénération
|
||||||
|
des services d'accès réseau (ex dhcp) lors de la vente d'une cotisation
|
||||||
|
par exemple
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from django.db.models.signals import post_save, post_delete
|
from django.db.models.signals import post_save, post_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
|
|
||||||
from django.db.models import Max
|
from django.db.models import Max
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from machines.models import regen
|
from machines.models import regen
|
||||||
|
|
||||||
|
|
||||||
class Facture(models.Model):
|
class Facture(models.Model):
|
||||||
|
""" Définition du modèle des factures. Une facture regroupe une ou
|
||||||
|
plusieurs ventes, rattachée à un user, et reliée à un moyen de paiement
|
||||||
|
et si il y a lieu un numero pour les chèques. Possède les valeurs
|
||||||
|
valides et controle (trésorerie)"""
|
||||||
PRETTY_NAME = "Factures émises"
|
PRETTY_NAME = "Factures émises"
|
||||||
|
|
||||||
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
||||||
paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT)
|
paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT)
|
||||||
banque = models.ForeignKey('Banque', on_delete=models.PROTECT, blank=True, null=True)
|
banque = models.ForeignKey(
|
||||||
|
'Banque',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True)
|
||||||
cheque = models.CharField(max_length=255, blank=True)
|
cheque = models.CharField(max_length=255, blank=True)
|
||||||
date = models.DateTimeField(auto_now_add=True)
|
date = models.DateTimeField(auto_now_add=True)
|
||||||
valid = models.BooleanField(default=True)
|
valid = models.BooleanField(default=True)
|
||||||
control = models.BooleanField(default=False)
|
control = models.BooleanField(default=False)
|
||||||
|
|
||||||
def prix(self):
|
def prix(self):
|
||||||
prix = Vente.objects.filter(facture=self).aggregate(models.Sum('prix'))['prix__sum']
|
"""Renvoie le prix brut sans les quantités. Méthode
|
||||||
|
dépréciée"""
|
||||||
|
prix = Vente.objects.filter(
|
||||||
|
facture=self
|
||||||
|
).aggregate(models.Sum('prix'))['prix__sum']
|
||||||
return prix
|
return prix
|
||||||
|
|
||||||
def prix_total(self):
|
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']
|
"""Prix total : somme des produits prix_unitaire et quantité des
|
||||||
|
ventes de l'objet"""
|
||||||
|
return Vente.objects.filter(
|
||||||
|
facture=self
|
||||||
|
).aggregate(
|
||||||
|
total=models.Sum(
|
||||||
|
models.F('prix')*models.F('number'),
|
||||||
|
output_field=models.FloatField()
|
||||||
|
)
|
||||||
|
)['total']
|
||||||
|
|
||||||
def name(self):
|
def name(self):
|
||||||
name = ' - '.join(Vente.objects.filter(facture=self).values_list('name', flat=True))
|
"""String, somme des name des ventes de self"""
|
||||||
|
name = ' - '.join(Vente.objects.filter(
|
||||||
|
facture=self
|
||||||
|
).values_list('name', flat=True))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.user) + ' ' + str(self.date)
|
return str(self.user) + ' ' + str(self.date)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Facture)
|
@receiver(post_save, sender=Facture)
|
||||||
def facture_post_save(sender, **kwargs):
|
def facture_post_save(sender, **kwargs):
|
||||||
|
"""Post save d'une facture, synchronise l'user ldap"""
|
||||||
facture = kwargs['instance']
|
facture = kwargs['instance']
|
||||||
user = facture.user
|
user = facture.user
|
||||||
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
|
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Facture)
|
@receiver(post_delete, sender=Facture)
|
||||||
def facture_post_delete(sender, **kwargs):
|
def facture_post_delete(sender, **kwargs):
|
||||||
|
"""Après la suppression d'une facture, on synchronise l'user ldap"""
|
||||||
user = kwargs['instance'].user
|
user = kwargs['instance'].user
|
||||||
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
|
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
|
||||||
|
|
||||||
|
|
||||||
class Vente(models.Model):
|
class Vente(models.Model):
|
||||||
|
"""Objet vente, contient une quantité, une facture parente, un nom,
|
||||||
|
un prix. Peut-être relié à un objet cotisation, via le boolean
|
||||||
|
iscotisation"""
|
||||||
PRETTY_NAME = "Ventes effectuées"
|
PRETTY_NAME = "Ventes effectuées"
|
||||||
|
|
||||||
facture = models.ForeignKey('Facture', on_delete=models.CASCADE)
|
facture = models.ForeignKey('Facture', on_delete=models.CASCADE)
|
||||||
|
@ -80,44 +132,67 @@ class Vente(models.Model):
|
||||||
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()
|
iscotisation = models.BooleanField()
|
||||||
duration = models.IntegerField(help_text="Durée exprimée en mois entiers", blank=True, null=True)
|
duration = models.IntegerField(
|
||||||
|
help_text="Durée exprimée en mois entiers",
|
||||||
|
blank=True,
|
||||||
|
null=True)
|
||||||
|
|
||||||
def prix_total(self):
|
def prix_total(self):
|
||||||
|
"""Renvoie le prix_total de self (nombre*prix)"""
|
||||||
return self.prix*self.number
|
return self.prix*self.number
|
||||||
|
|
||||||
def update_cotisation(self):
|
def update_cotisation(self):
|
||||||
|
"""Mets à jour l'objet related cotisation de la vente, si
|
||||||
|
il existe : update la date de fin à partir de la durée de
|
||||||
|
la vente"""
|
||||||
if hasattr(self, 'cotisation'):
|
if hasattr(self, 'cotisation'):
|
||||||
cotisation = self.cotisation
|
cotisation = self.cotisation
|
||||||
cotisation.date_end = cotisation.date_start + relativedelta(months=self.duration*self.number)
|
cotisation.date_end = cotisation.date_start + relativedelta(
|
||||||
|
months=self.duration*self.number)
|
||||||
return
|
return
|
||||||
|
|
||||||
def create_cotis(self, date_start=False):
|
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"""
|
"""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'):
|
||||||
cotisation = Cotisation(vente=self)
|
cotisation = Cotisation(vente=self)
|
||||||
if date_start:
|
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']
|
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:
|
else:
|
||||||
end_adhesion = self.facture.user.end_adhesion()
|
end_adhesion = self.facture.user.end_adhesion()
|
||||||
date_start = date_start or timezone.now()
|
date_start = date_start or timezone.now()
|
||||||
end_adhesion = end_adhesion or date_start
|
end_adhesion = end_adhesion or date_start
|
||||||
date_max = max(end_adhesion, date_start)
|
date_max = max(end_adhesion, date_start)
|
||||||
cotisation.date_start = date_max
|
cotisation.date_start = date_max
|
||||||
cotisation.date_end = cotisation.date_start + relativedelta(months=self.duration*self.number)
|
cotisation.date_end = cotisation.date_start + relativedelta(
|
||||||
|
months=self.duration*self.number
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
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.iscotisation and not self.duration:
|
||||||
raise ValidationError("Cotisation et durée doivent être présents ensembles")
|
raise ValidationError("Cotisation et durée doivent être présents\
|
||||||
|
ensembles")
|
||||||
self.update_cotisation()
|
self.update_cotisation()
|
||||||
super(Vente, self).save(*args, **kwargs)
|
super(Vente, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.name) + ' ' + str(self.facture)
|
return str(self.name) + ' ' + str(self.facture)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Vente)
|
@receiver(post_save, sender=Vente)
|
||||||
def vente_post_save(sender, **kwargs):
|
def vente_post_save(sender, **kwargs):
|
||||||
|
"""Post save d'une vente, déclencge la création de l'objet cotisation
|
||||||
|
si il y a lieu(si iscotisation) """
|
||||||
vente = kwargs['instance']
|
vente = kwargs['instance']
|
||||||
if hasattr(vente, 'cotisation'):
|
if hasattr(vente, 'cotisation'):
|
||||||
vente.cotisation.vente = vente
|
vente.cotisation.vente = vente
|
||||||
|
@ -128,14 +203,20 @@ def vente_post_save(sender, **kwargs):
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Vente)
|
@receiver(post_delete, sender=Vente)
|
||||||
def vente_post_delete(sender, **kwargs):
|
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']
|
vente = kwargs['instance']
|
||||||
if vente.iscotisation:
|
if vente.iscotisation:
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
|
"""Liste des articles en vente : prix, nom, et attribut iscotisation
|
||||||
|
et duree si c'est une cotisation"""
|
||||||
PRETTY_NAME = "Articles en vente"
|
PRETTY_NAME = "Articles en vente"
|
||||||
|
|
||||||
name = models.CharField(max_length=255, unique=True)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
|
@ -154,7 +235,9 @@ class Article(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Banque(models.Model):
|
class Banque(models.Model):
|
||||||
|
"""Liste des banques"""
|
||||||
PRETTY_NAME = "Banques enregistrées"
|
PRETTY_NAME = "Banques enregistrées"
|
||||||
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
@ -162,7 +245,9 @@ class Banque(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Paiement(models.Model):
|
class Paiement(models.Model):
|
||||||
|
"""Moyens de paiement"""
|
||||||
PRETTY_NAME = "Moyens de paiement"
|
PRETTY_NAME = "Moyens de paiement"
|
||||||
PAYMENT_TYPES = (
|
PAYMENT_TYPES = (
|
||||||
(0, 'Autre'),
|
(0, 'Autre'),
|
||||||
|
@ -179,11 +264,15 @@ class Paiement(models.Model):
|
||||||
self.moyen = self.moyen.title()
|
self.moyen = self.moyen.title()
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
"""Un seul type de paiement peut-etre cheque..."""
|
||||||
if Paiement.objects.filter(type_paiement=1).count() > 1:
|
if Paiement.objects.filter(type_paiement=1).count() > 1:
|
||||||
raise ValidationError("On ne peut avoir plusieurs mode de paiement chèque")
|
raise ValidationError("On ne peut avoir plusieurs mode de paiement\
|
||||||
|
chèque")
|
||||||
super(Paiement, self).save(*args, **kwargs)
|
super(Paiement, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Cotisation(models.Model):
|
class Cotisation(models.Model):
|
||||||
|
"""Objet cotisation, debut et fin, relié en onetoone à une vente"""
|
||||||
PRETTY_NAME = "Cotisations"
|
PRETTY_NAME = "Cotisations"
|
||||||
|
|
||||||
vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True)
|
vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True)
|
||||||
|
@ -193,15 +282,19 @@ class Cotisation(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.vente)
|
return str(self.vente)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Cotisation)
|
@receiver(post_save, sender=Cotisation)
|
||||||
def cotisation_post_save(sender, **kwargs):
|
def cotisation_post_save(sender, **kwargs):
|
||||||
|
"""Après modification d'une cotisation, regeneration des services"""
|
||||||
regen('dns')
|
regen('dns')
|
||||||
regen('dhcp')
|
regen('dhcp')
|
||||||
regen('mac_ip_list')
|
regen('mac_ip_list')
|
||||||
regen('mailing')
|
regen('mailing')
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Cotisation)
|
@receiver(post_delete, sender=Cotisation)
|
||||||
def vente_post_delete(sender, **kwargs):
|
def vente_post_delete(sender, **kwargs):
|
||||||
|
"""Après suppression d'une vente, régénération des services"""
|
||||||
cotisation = kwargs['instance']
|
cotisation = kwargs['instance']
|
||||||
regen('mac_ip_list')
|
regen('mac_ip_list')
|
||||||
regen('mailing')
|
regen('mailing')
|
||||||
|
|
|
@ -27,30 +27,96 @@ from django.conf.urls import url
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^new_facture/(?P<userid>[0-9]+)$', views.new_facture, name='new-facture'),
|
url(r'^new_facture/(?P<userid>[0-9]+)$',
|
||||||
url(r'^edit_facture/(?P<factureid>[0-9]+)$', views.edit_facture, name='edit-facture'),
|
views.new_facture,
|
||||||
url(r'^del_facture/(?P<factureid>[0-9]+)$', views.del_facture, name='del-facture'),
|
name='new-facture'
|
||||||
url(r'^facture_pdf/(?P<factureid>[0-9]+)$', views.facture_pdf, name='facture-pdf'),
|
),
|
||||||
url(r'^new_facture_pdf/$', views.new_facture_pdf, name='new-facture-pdf'),
|
url(r'^edit_facture/(?P<factureid>[0-9]+)$',
|
||||||
url(r'^credit_solde/(?P<userid>[0-9]+)$', views.credit_solde, name='credit-solde'),
|
views.edit_facture,
|
||||||
url(r'^add_article/$', views.add_article, name='add-article'),
|
name='edit-facture'
|
||||||
url(r'^edit_article/(?P<articleid>[0-9]+)$', views.edit_article, name='edit-article'),
|
),
|
||||||
url(r'^del_article/$', views.del_article, name='del-article'),
|
url(r'^del_facture/(?P<factureid>[0-9]+)$',
|
||||||
url(r'^add_paiement/$', views.add_paiement, name='add-paiement'),
|
views.del_facture,
|
||||||
url(r'^edit_paiement/(?P<paiementid>[0-9]+)$', views.edit_paiement, name='edit-paiement'),
|
name='del-facture'
|
||||||
url(r'^del_paiement/$', views.del_paiement, name='del-paiement'),
|
),
|
||||||
url(r'^add_banque/$', views.add_banque, name='add-banque'),
|
url(r'^facture_pdf/(?P<factureid>[0-9]+)$',
|
||||||
url(r'^edit_banque/(?P<banqueid>[0-9]+)$', views.edit_banque, name='edit-banque'),
|
views.facture_pdf,
|
||||||
url(r'^del_banque/$', views.del_banque, name='del-banque'),
|
name='facture-pdf'
|
||||||
url(r'^index_article/$', views.index_article, name='index-article'),
|
),
|
||||||
url(r'^index_banque/$', views.index_banque, name='index-banque'),
|
url(r'^new_facture_pdf/$',
|
||||||
url(r'^index_paiement/$', views.index_paiement, name='index-paiement'),
|
views.new_facture_pdf,
|
||||||
url(r'^history/(?P<object>facture)/(?P<id>[0-9]+)$', views.history, name='history'),
|
name='new-facture-pdf'
|
||||||
url(r'^history/(?P<object>article)/(?P<id>[0-9]+)$', views.history, name='history'),
|
),
|
||||||
url(r'^history/(?P<object>paiement)/(?P<id>[0-9]+)$', views.history, name='history'),
|
url(r'^credit_solde/(?P<userid>[0-9]+)$',
|
||||||
url(r'^history/(?P<object>banque)/(?P<id>[0-9]+)$', views.history, name='history'),
|
views.credit_solde,
|
||||||
url(r'^control/$', views.control, name='control'),
|
name='credit-solde'
|
||||||
|
),
|
||||||
|
url(r'^add_article/$',
|
||||||
|
views.add_article,
|
||||||
|
name='add-article'
|
||||||
|
),
|
||||||
|
url(r'^edit_article/(?P<articleid>[0-9]+)$',
|
||||||
|
views.edit_article,
|
||||||
|
name='edit-article'
|
||||||
|
),
|
||||||
|
url(r'^del_article/$',
|
||||||
|
views.del_article,
|
||||||
|
name='del-article'
|
||||||
|
),
|
||||||
|
url(r'^add_paiement/$',
|
||||||
|
views.add_paiement,
|
||||||
|
name='add-paiement'
|
||||||
|
),
|
||||||
|
url(r'^edit_paiement/(?P<paiementid>[0-9]+)$',
|
||||||
|
views.edit_paiement,
|
||||||
|
name='edit-paiement'
|
||||||
|
),
|
||||||
|
url(r'^del_paiement/$',
|
||||||
|
views.del_paiement,
|
||||||
|
name='del-paiement'
|
||||||
|
),
|
||||||
|
url(r'^add_banque/$',
|
||||||
|
views.add_banque,
|
||||||
|
name='add-banque'
|
||||||
|
),
|
||||||
|
url(r'^edit_banque/(?P<banqueid>[0-9]+)$',
|
||||||
|
views.edit_banque,
|
||||||
|
name='edit-banque'
|
||||||
|
),
|
||||||
|
url(r'^del_banque/$',
|
||||||
|
views.del_banque,
|
||||||
|
name='del-banque'
|
||||||
|
),
|
||||||
|
url(r'^index_article/$',
|
||||||
|
views.index_article,
|
||||||
|
name='index-article'
|
||||||
|
),
|
||||||
|
url(r'^index_banque/$',
|
||||||
|
views.index_banque,
|
||||||
|
name='index-banque'
|
||||||
|
),
|
||||||
|
url(r'^index_paiement/$',
|
||||||
|
views.index_paiement,
|
||||||
|
name='index-paiement'
|
||||||
|
),
|
||||||
|
url(r'^history/(?P<object>facture)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(r'^history/(?P<object>article)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(r'^history/(?P<object>paiement)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'),
|
||||||
|
url(r'^history/(?P<object>banque)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(r'^control/$',
|
||||||
|
views.control,
|
||||||
|
name='control'
|
||||||
|
),
|
||||||
url(r'^$', views.index, name='index'),
|
url(r'^$', views.index, name='index'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,40 +24,41 @@
|
||||||
# Goulven Kermarec, Gabriel Détraz
|
# Goulven Kermarec, Gabriel Détraz
|
||||||
# Gplv2
|
# Gplv2
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.template.context_processors import csrf
|
|
||||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
from django.template import Context, RequestContext, loader
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db.models import Max, ProtectedError
|
from django.db.models import ProtectedError
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.forms import modelformset_factory, formset_factory
|
from django.forms import modelformset_factory, formset_factory
|
||||||
import os
|
from django.utils import timezone
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
from reversion.models import Version
|
from reversion.models import Version
|
||||||
|
# Import des models, forms et fonctions re2o
|
||||||
from .models import Facture, Article, Vente, Cotisation, Paiement, Banque
|
|
||||||
from .forms import NewFactureForm, TrezEditFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm, NewFactureFormPdf, CreditSoldeForm, SelectArticleForm
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from .tex import render_tex
|
|
||||||
from re2o.settings import LOGO_PATH
|
from re2o.settings import LOGO_PATH
|
||||||
from re2o import settings
|
from re2o import settings
|
||||||
|
from re2o.views import form
|
||||||
from preferences.models import OptionalUser, AssoOption, GeneralOption
|
from preferences.models import OptionalUser, AssoOption, GeneralOption
|
||||||
|
from .models import Facture, Article, Vente, Paiement, Banque
|
||||||
|
from .forms import NewFactureForm, TrezEditFactureForm, EditFactureForm
|
||||||
|
from .forms import ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm
|
||||||
|
from .forms import BanqueForm, DelBanqueForm, NewFactureFormPdf
|
||||||
|
from .forms import SelectArticleForm, CreditSoldeForm
|
||||||
|
from .tex import render_tex
|
||||||
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
def form(ctx, template, request):
|
|
||||||
c = ctx
|
|
||||||
c.update(csrf(request))
|
|
||||||
return render(request, template, c)
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def new_facture(request, userid):
|
def new_facture(request, userid):
|
||||||
|
"""Creation d'une facture pour un user. Renvoie la liste des articles
|
||||||
|
et crée des factures dans un formset. Utilise un peu de js coté template
|
||||||
|
pour ajouter des articles.
|
||||||
|
Parse les article et boucle dans le formset puis save les ventes,
|
||||||
|
enfin sauve la facture parente.
|
||||||
|
TODO : simplifier cette fonction, déplacer l'intelligence coté models
|
||||||
|
Facture et Vente."""
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=userid)
|
user = User.objects.get(pk=userid)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
|
@ -70,50 +71,80 @@ def new_facture(request, userid):
|
||||||
facture_form = NewFactureForm(request.POST or None, instance=facture)
|
facture_form = NewFactureForm(request.POST or None, instance=facture)
|
||||||
article_formset = formset_factory(SelectArticleForm)(request.POST or None)
|
article_formset = formset_factory(SelectArticleForm)(request.POST or None)
|
||||||
if facture_form.is_valid() and article_formset.is_valid():
|
if facture_form.is_valid() and article_formset.is_valid():
|
||||||
new_facture = facture_form.save(commit=False)
|
new_facture_instance = facture_form.save(commit=False)
|
||||||
articles = article_formset
|
articles = article_formset
|
||||||
# Si au moins un article est rempli
|
# Si au moins un article est rempli
|
||||||
if any(art.cleaned_data for art in articles):
|
if any(art.cleaned_data for art in articles):
|
||||||
options, created = OptionalUser.objects.get_or_create()
|
options, _created = OptionalUser.objects.get_or_create()
|
||||||
user_solde = options.user_solde
|
user_solde = options.user_solde
|
||||||
solde_negatif = options.solde_negatif
|
solde_negatif = options.solde_negatif
|
||||||
# Si on paye par solde, que l'option est activée, on vérifie que le négatif n'est pas atteint
|
# Si on paye par solde, que l'option est activée,
|
||||||
|
# on vérifie que le négatif n'est pas atteint
|
||||||
if user_solde:
|
if user_solde:
|
||||||
if new_facture.paiement == Paiement.objects.get_or_create(moyen='solde')[0]:
|
if new_facture_instance.paiement == Paiement.objects.get_or_create(
|
||||||
|
moyen='solde'
|
||||||
|
)[0]:
|
||||||
prix_total = 0
|
prix_total = 0
|
||||||
for art_item in articles:
|
for art_item in articles:
|
||||||
if art_item.cleaned_data:
|
if art_item.cleaned_data:
|
||||||
prix_total += art_item.cleaned_data['article'].prix*art_item.cleaned_data['quantity']
|
prix_total += art_item.cleaned_data['article']\
|
||||||
|
.prix*art_item.cleaned_data['quantity']
|
||||||
if float(user.solde) - float(prix_total) < solde_negatif:
|
if float(user.solde) - float(prix_total) < solde_negatif:
|
||||||
messages.error(request, "Le solde est insuffisant pour effectuer l'opération")
|
messages.error(request, "Le solde est insuffisant pour\
|
||||||
|
effectuer l'opération")
|
||||||
return redirect("/users/profil/" + userid)
|
return redirect("/users/profil/" + userid)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_facture.save()
|
new_facture_instance.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
for art_item in articles:
|
for art_item in articles:
|
||||||
if art_item.cleaned_data:
|
if art_item.cleaned_data:
|
||||||
article = art_item.cleaned_data['article']
|
article = art_item.cleaned_data['article']
|
||||||
quantity = art_item.cleaned_data['quantity']
|
quantity = art_item.cleaned_data['quantity']
|
||||||
new_vente = Vente.objects.create(facture=new_facture, name=article.name, prix=article.prix, iscotisation=article.iscotisation, duration=article.duration, number=quantity)
|
new_vente = Vente.objects.create(
|
||||||
|
facture=new_facture_instance,
|
||||||
|
name=article.name,
|
||||||
|
prix=article.prix,
|
||||||
|
iscotisation=article.iscotisation,
|
||||||
|
duration=article.duration,
|
||||||
|
number=quantity
|
||||||
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
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 for art_item in articles if art_item.cleaned_data):
|
if any(art_item.cleaned_data['article'].iscotisation
|
||||||
messages.success(request, "La cotisation a été prolongée pour l'adhérent %s jusqu'au %s" % (user.pseudo, user.end_adhesion()) )
|
for art_item in articles if art_item.cleaned_data):
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
"La cotisation a été prolongée\
|
||||||
|
pour l'adhérent %s jusqu'au %s" % (
|
||||||
|
user.pseudo, user.end_adhesion()
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
messages.success(request, "La facture a été crée")
|
messages.success(request, "La facture a été crée")
|
||||||
return redirect("/users/profil/" + userid)
|
return redirect("/users/profil/" + userid)
|
||||||
messages.error(request, u"Il faut au moins un article valide pour créer une facture" )
|
messages.error(
|
||||||
return form({'factureform': facture_form, 'venteform': article_formset, 'articlelist': article_list}, 'cotisations/new_facture.html', request)
|
request,
|
||||||
|
u"Il faut au moins un article valide pour créer une facture"
|
||||||
|
)
|
||||||
|
return form({
|
||||||
|
'factureform': facture_form,
|
||||||
|
'venteform': article_formset,
|
||||||
|
'articlelist': article_list
|
||||||
|
}, 'cotisations/new_facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def new_facture_pdf(request):
|
def new_facture_pdf(request):
|
||||||
|
"""Permet de générer un pdf d'une facture. Réservée
|
||||||
|
au trésorier, permet d'emettre des factures sans objet
|
||||||
|
Vente ou Facture correspondant en bdd"""
|
||||||
facture_form = NewFactureFormPdf(request.POST or None)
|
facture_form = NewFactureFormPdf(request.POST or None)
|
||||||
if facture_form.is_valid():
|
if facture_form.is_valid():
|
||||||
options, created = AssoOption.objects.get_or_create()
|
options, _created = AssoOption.objects.get_or_create()
|
||||||
tbl = []
|
tbl = []
|
||||||
article = facture_form.cleaned_data['article']
|
article = facture_form.cleaned_data['article']
|
||||||
quantite = facture_form.cleaned_data['number']
|
quantite = facture_form.cleaned_data['number']
|
||||||
|
@ -121,71 +152,131 @@ def new_facture_pdf(request):
|
||||||
destinataire = facture_form.cleaned_data['dest']
|
destinataire = facture_form.cleaned_data['dest']
|
||||||
chambre = facture_form.cleaned_data['chambre']
|
chambre = facture_form.cleaned_data['chambre']
|
||||||
fid = facture_form.cleaned_data['fid']
|
fid = facture_form.cleaned_data['fid']
|
||||||
for a in article:
|
for art in article:
|
||||||
tbl.append([a, quantite, a.prix * quantite])
|
tbl.append([art, quantite, art.prix * quantite])
|
||||||
prix_total = sum(a[2] for a in tbl)
|
prix_total = sum(a[2] for a in tbl)
|
||||||
user = {'name': destinataire, 'room': chambre}
|
user = {'name': destinataire, 'room': chambre}
|
||||||
return render_tex(request, 'cotisations/factures.tex', {'DATE' : timezone.now(),'dest':user,'fid':fid, 'article':tbl, 'total':prix_total, 'paid':paid, 'asso_name':options.name, 'line1':options.adresse1, 'line2':options.adresse2, 'siret':options.siret, 'email':options.contact, 'phone':options.telephone, 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)})
|
return render_tex(request, 'cotisations/factures.tex', {
|
||||||
return form({'factureform': facture_form}, 'cotisations/facture.html', request)
|
'DATE': timezone.now(),
|
||||||
|
'dest': user,
|
||||||
|
'fid': fid,
|
||||||
|
'article': tbl,
|
||||||
|
'total': prix_total,
|
||||||
|
'paid': paid,
|
||||||
|
'asso_name': options.name,
|
||||||
|
'line1': options.adresse1,
|
||||||
|
'line2': options.adresse2,
|
||||||
|
'siret': options.siret,
|
||||||
|
'email': options.contact,
|
||||||
|
'phone': options.telephone,
|
||||||
|
'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
|
||||||
|
})
|
||||||
|
return form({
|
||||||
|
'factureform': facture_form
|
||||||
|
}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def facture_pdf(request, factureid):
|
def facture_pdf(request, factureid):
|
||||||
|
"""Affiche en pdf une facture. Cree une ligne par Vente de la facture,
|
||||||
|
et génére une facture avec le total, le moyen de paiement, l'adresse
|
||||||
|
de l'adhérent, etc. Réservée à self pour un user sans droits,
|
||||||
|
les droits cableurs permettent d'afficher toute facture"""
|
||||||
try:
|
try:
|
||||||
facture = Facture.objects.get(pk=factureid)
|
facture = Facture.objects.get(pk=factureid)
|
||||||
except Facture.DoesNotExist:
|
except Facture.DoesNotExist:
|
||||||
messages.error(request, u"Facture inexistante")
|
messages.error(request, u"Facture inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
if not request.user.has_perms(('cableur',)) and facture.user != request.user:
|
if not request.user.has_perms(('cableur',))\
|
||||||
messages.error(request, "Vous ne pouvez pas afficher une facture ne vous appartenant pas sans droit cableur")
|
and facture.user != request.user:
|
||||||
|
messages.error(request, "Vous ne pouvez pas afficher une facture ne vous\
|
||||||
|
appartenant pas sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
if not facture.valid:
|
if not facture.valid:
|
||||||
messages.error(request, "Vous ne pouvez pas afficher une facture non valide")
|
messages.error(request, "Vous ne pouvez pas afficher\
|
||||||
|
une facture non valide")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
vente = Vente.objects.all().filter(facture=facture)
|
ventes_objects = Vente.objects.all().filter(facture=facture)
|
||||||
ventes = []
|
ventes = []
|
||||||
options, created = AssoOption.objects.get_or_create()
|
options, _created = AssoOption.objects.get_or_create()
|
||||||
for v in vente:
|
for vente in ventes_objects:
|
||||||
ventes.append([v, v.number, v.prix_total])
|
ventes.append([vente, vente.number, vente.prix_total])
|
||||||
return render_tex(request, 'cotisations/factures.tex', {'paid':True, 'fid':facture.id, 'DATE':facture.date,'dest':facture.user, 'article':ventes, 'total': facture.prix_total(), 'asso_name':options.name, 'line1': options.adresse1, 'line2':options.adresse2, 'siret':options.siret, 'email':options.contact, 'phone':options.telephone, 'tpl_path':os.path.join(settings.BASE_DIR, LOGO_PATH)})
|
return render_tex(request, 'cotisations/factures.tex', {
|
||||||
|
'paid': True,
|
||||||
|
'fid': facture.id,
|
||||||
|
'DATE': facture.date,
|
||||||
|
'dest': facture.user,
|
||||||
|
'article': ventes,
|
||||||
|
'total': facture.prix_total(),
|
||||||
|
'asso_name': options.name,
|
||||||
|
'line1': options.adresse1,
|
||||||
|
'line2': options.adresse2,
|
||||||
|
'siret': options.siret,
|
||||||
|
'email': options.contact,
|
||||||
|
'phone': options.telephone,
|
||||||
|
'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def edit_facture(request, factureid):
|
def edit_facture(request, factureid):
|
||||||
|
"""Permet l'édition d'une facture. On peut y éditer les ventes
|
||||||
|
déjà effectuer, ou rendre une facture invalide (non payées, chèque
|
||||||
|
en bois etc). Mets à jour les durée de cotisation attenantes"""
|
||||||
try:
|
try:
|
||||||
facture = Facture.objects.get(pk=factureid)
|
facture = Facture.objects.get(pk=factureid)
|
||||||
except Facture.DoesNotExist:
|
except Facture.DoesNotExist:
|
||||||
messages.error(request, u"Facture inexistante")
|
messages.error(request, u"Facture inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
if request.user.has_perms(['tresorier']):
|
if request.user.has_perms(['tresorier']):
|
||||||
facture_form = TrezEditFactureForm(request.POST or None, instance=facture)
|
facture_form = TrezEditFactureForm(
|
||||||
|
request.POST or None,
|
||||||
|
instance=facture
|
||||||
|
)
|
||||||
elif facture.control or not facture.valid:
|
elif facture.control or not facture.valid:
|
||||||
messages.error(request, "Vous ne pouvez pas editer une facture controlée ou invalidée par le trésorier")
|
messages.error(request, "Vous ne pouvez pas editer une facture\
|
||||||
|
controlée ou invalidée par le trésorier")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
else:
|
else:
|
||||||
facture_form = EditFactureForm(request.POST or None, instance=facture)
|
facture_form = EditFactureForm(request.POST or None, instance=facture)
|
||||||
ventes_objects = Vente.objects.filter(facture=facture)
|
ventes_objects = Vente.objects.filter(facture=facture)
|
||||||
vente_form_set = modelformset_factory(Vente, fields=('name','number'), extra=0, max_num=len(ventes_objects))
|
vente_form_set = modelformset_factory(
|
||||||
|
Vente,
|
||||||
|
fields=('name', 'number'),
|
||||||
|
extra=0,
|
||||||
|
max_num=len(ventes_objects)
|
||||||
|
)
|
||||||
vente_form = vente_form_set(request.POST or None, queryset=ventes_objects)
|
vente_form = vente_form_set(request.POST or None, queryset=ventes_objects)
|
||||||
if facture_form.is_valid() and vente_form.is_valid():
|
if facture_form.is_valid() and vente_form.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
facture_form.save()
|
facture_form.save()
|
||||||
vente_form.save()
|
vente_form.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for form in vente_form for field in facture_form.changed_data + form.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for form in vente_form for field
|
||||||
|
in facture_form.changed_data + form.changed_data))
|
||||||
messages.success(request, "La facture a bien été modifiée")
|
messages.success(request, "La facture a bien été modifiée")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
return form({'factureform': facture_form, 'venteform': vente_form}, 'cotisations/edit_facture.html', request)
|
return form({
|
||||||
|
'factureform': facture_form,
|
||||||
|
'venteform': vente_form
|
||||||
|
}, 'cotisations/edit_facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def del_facture(request, factureid):
|
def del_facture(request, factureid):
|
||||||
|
"""Suppression d'une facture. Supprime en cascade les ventes
|
||||||
|
et cotisations filles"""
|
||||||
try:
|
try:
|
||||||
facture = Facture.objects.get(pk=factureid)
|
facture = Facture.objects.get(pk=factureid)
|
||||||
except Facture.DoesNotExist:
|
except Facture.DoesNotExist:
|
||||||
messages.error(request, u"Facture inexistante")
|
messages.error(request, u"Facture inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
if (facture.control or not facture.valid):
|
if facture.control or not facture.valid:
|
||||||
messages.error(request, "Vous ne pouvez pas editer une facture controlée ou invalidée par le trésorier")
|
messages.error(request, "Vous ne pouvez pas editer une facture\
|
||||||
|
controlée ou invalidée par le trésorier")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -193,7 +284,11 @@ def del_facture(request, factureid):
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
messages.success(request, "La facture a été détruite")
|
messages.success(request, "La facture a été détruite")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
return form({'objet': facture, 'objet_name': 'facture'}, 'cotisations/delete.html', request)
|
return form({
|
||||||
|
'objet': facture,
|
||||||
|
'objet_name': 'facture'
|
||||||
|
}, 'cotisations/delete.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
|
@ -212,7 +307,14 @@ def credit_solde(request, userid):
|
||||||
facture_instance.save()
|
facture_instance.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
new_vente = Vente.objects.create(facture=facture_instance, name="solde", prix=facture.cleaned_data['montant'], iscotisation=False, duration=0, number=1)
|
new_vente = Vente.objects.create(
|
||||||
|
facture=facture_instance,
|
||||||
|
name="solde",
|
||||||
|
prix=facture.cleaned_data['montant'],
|
||||||
|
iscotisation=False,
|
||||||
|
duration=0,
|
||||||
|
number=1
|
||||||
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_vente.save()
|
new_vente.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
|
@ -225,6 +327,13 @@ def credit_solde(request, userid):
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def add_article(request):
|
def add_article(request):
|
||||||
|
"""Ajoute un article. Champs : désignation,
|
||||||
|
prix, est-ce une cotisation et si oui sa durée
|
||||||
|
Réservé au trésorier
|
||||||
|
Nota bene : les ventes déjà effectuées ne sont pas reliées
|
||||||
|
aux articles en vente. La désignation, le prix... sont
|
||||||
|
copiés à la création de la facture. Un changement de prix n'a
|
||||||
|
PAS de conséquence sur les ventes déjà faites"""
|
||||||
article = ArticleForm(request.POST or None)
|
article = ArticleForm(request.POST or None)
|
||||||
if article.is_valid():
|
if article.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -235,9 +344,12 @@ def add_article(request):
|
||||||
return redirect("/cotisations/index_article/")
|
return redirect("/cotisations/index_article/")
|
||||||
return form({'factureform': article}, 'cotisations/facture.html', request)
|
return form({'factureform': article}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def edit_article(request, articleid):
|
def edit_article(request, articleid):
|
||||||
|
"""Edition d'un article (designation, prix, etc)
|
||||||
|
Réservé au trésorier"""
|
||||||
try:
|
try:
|
||||||
article_instance = Article.objects.get(pk=articleid)
|
article_instance = Article.objects.get(pk=articleid)
|
||||||
except Article.DoesNotExist:
|
except Article.DoesNotExist:
|
||||||
|
@ -248,14 +360,20 @@ def edit_article(request, articleid):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
article.save()
|
article.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in article.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in article.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
messages.success(request, "Type d'article modifié")
|
messages.success(request, "Type d'article modifié")
|
||||||
return redirect("/cotisations/index_article/")
|
return redirect("/cotisations/index_article/")
|
||||||
return form({'factureform': article}, 'cotisations/facture.html', request)
|
return form({'factureform': article}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def del_article(request):
|
def del_article(request):
|
||||||
|
"""Suppression d'un article en vente"""
|
||||||
article = DelArticleForm(request.POST or None)
|
article = DelArticleForm(request.POST or None)
|
||||||
if article.is_valid():
|
if article.is_valid():
|
||||||
article_del = article.cleaned_data['articles']
|
article_del = article.cleaned_data['articles']
|
||||||
|
@ -266,9 +384,12 @@ def del_article(request):
|
||||||
return redirect("/cotisations/index_article")
|
return redirect("/cotisations/index_article")
|
||||||
return form({'factureform': article}, 'cotisations/facture.html', request)
|
return form({'factureform': article}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def add_paiement(request):
|
def add_paiement(request):
|
||||||
|
"""Ajoute un moyen de paiement. Relié aux factures
|
||||||
|
via foreign key"""
|
||||||
paiement = PaiementForm(request.POST or None)
|
paiement = PaiementForm(request.POST or None)
|
||||||
if paiement.is_valid():
|
if paiement.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -279,9 +400,11 @@ def add_paiement(request):
|
||||||
return redirect("/cotisations/index_paiement/")
|
return redirect("/cotisations/index_paiement/")
|
||||||
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def edit_paiement(request, paiementid):
|
def edit_paiement(request, paiementid):
|
||||||
|
"""Edition d'un moyen de paiement"""
|
||||||
try:
|
try:
|
||||||
paiement_instance = Paiement.objects.get(pk=paiementid)
|
paiement_instance = Paiement.objects.get(pk=paiementid)
|
||||||
except Paiement.DoesNotExist:
|
except Paiement.DoesNotExist:
|
||||||
|
@ -292,14 +415,20 @@ def edit_paiement(request, paiementid):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
paiement.save()
|
paiement.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in paiement.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in paiement.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
messages.success(request, "Type de paiement modifié")
|
messages.success(request, "Type de paiement modifié")
|
||||||
return redirect("/cotisations/index_paiement/")
|
return redirect("/cotisations/index_paiement/")
|
||||||
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def del_paiement(request):
|
def del_paiement(request):
|
||||||
|
"""Suppression d'un moyen de paiement"""
|
||||||
paiement = DelPaiementForm(request.POST or None)
|
paiement = DelPaiementForm(request.POST or None)
|
||||||
if paiement.is_valid():
|
if paiement.is_valid():
|
||||||
paiement_dels = paiement.cleaned_data['paiements']
|
paiement_dels = paiement.cleaned_data['paiements']
|
||||||
|
@ -309,15 +438,24 @@ def del_paiement(request):
|
||||||
paiement_del.delete()
|
paiement_del.delete()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Destruction")
|
reversion.set_comment("Destruction")
|
||||||
messages.success(request, "Le moyen de paiement a été supprimé")
|
messages.success(
|
||||||
|
request,
|
||||||
|
"Le moyen de paiement a été supprimé"
|
||||||
|
)
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "Le moyen de paiement %s est affecté à au moins une facture, vous ne pouvez pas le supprimer" % paiement_del)
|
messages.error(
|
||||||
|
request,
|
||||||
|
"Le moyen de paiement %s est affecté à au moins une\
|
||||||
|
facture, vous ne pouvez pas le supprimer" % paiement_del
|
||||||
|
)
|
||||||
return redirect("/cotisations/index_paiement/")
|
return redirect("/cotisations/index_paiement/")
|
||||||
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def add_banque(request):
|
def add_banque(request):
|
||||||
|
"""Ajoute une banque à la liste des banques"""
|
||||||
banque = BanqueForm(request.POST or None)
|
banque = BanqueForm(request.POST or None)
|
||||||
if banque.is_valid():
|
if banque.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -328,9 +466,11 @@ def add_banque(request):
|
||||||
return redirect("/cotisations/index_banque/")
|
return redirect("/cotisations/index_banque/")
|
||||||
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def edit_banque(request, banqueid):
|
def edit_banque(request, banqueid):
|
||||||
|
"""Edite le nom d'une banque"""
|
||||||
try:
|
try:
|
||||||
banque_instance = Banque.objects.get(pk=banqueid)
|
banque_instance = Banque.objects.get(pk=banqueid)
|
||||||
except Banque.DoesNotExist:
|
except Banque.DoesNotExist:
|
||||||
|
@ -341,14 +481,20 @@ def edit_banque(request, banqueid):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
banque.save()
|
banque.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in banque.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in banque.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
messages.success(request, "Banque modifiée")
|
messages.success(request, "Banque modifiée")
|
||||||
return redirect("/cotisations/index_banque/")
|
return redirect("/cotisations/index_banque/")
|
||||||
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def del_banque(request):
|
def del_banque(request):
|
||||||
|
"""Supprime une banque"""
|
||||||
banque = DelBanqueForm(request.POST or None)
|
banque = DelBanqueForm(request.POST or None)
|
||||||
if banque.is_valid():
|
if banque.is_valid():
|
||||||
banque_dels = banque.cleaned_data['banques']
|
banque_dels = banque.cleaned_data['banques']
|
||||||
|
@ -360,17 +506,25 @@ def del_banque(request):
|
||||||
reversion.set_comment("Destruction")
|
reversion.set_comment("Destruction")
|
||||||
messages.success(request, "La banque a été supprimée")
|
messages.success(request, "La banque a été supprimée")
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "La banque %s est affectée à au moins une facture, vous ne pouvez pas la supprimer" % banque_del)
|
messages.error(request, "La banque %s est affectée à au moins\
|
||||||
|
une facture, vous ne pouvez pas la supprimer" % banque_del)
|
||||||
return redirect("/cotisations/index_banque/")
|
return redirect("/cotisations/index_banque/")
|
||||||
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('tresorier')
|
@permission_required('tresorier')
|
||||||
def control(request):
|
def control(request):
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
"""Pour le trésorier, vue pour controler en masse les
|
||||||
|
factures.Case à cocher, pratique"""
|
||||||
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
facture_list = Facture.objects.order_by('date').reverse()
|
facture_list = Facture.objects.order_by('date').reverse()
|
||||||
controlform_set = modelformset_factory(Facture, fields=('control','valid'), extra=0)
|
controlform_set = modelformset_factory(
|
||||||
|
Facture,
|
||||||
|
fields=('control', 'valid'),
|
||||||
|
extra=0
|
||||||
|
)
|
||||||
paginator = Paginator(facture_list, pagination_number)
|
paginator = Paginator(facture_list, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -379,7 +533,9 @@ def control(request):
|
||||||
facture_list = paginator.page(1)
|
facture_list = paginator.page(1)
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
facture_list = paginator.page(paginator.num.pages)
|
facture_list = paginator.page(paginator.num.pages)
|
||||||
page_query = Facture.objects.order_by('date').reverse().filter(id__in=[facture.id for facture in facture_list])
|
page_query = Facture.objects.order_by('date').reverse().filter(
|
||||||
|
id__in=[facture.id for facture in facture_list]
|
||||||
|
)
|
||||||
controlform = controlform_set(request.POST or None, queryset=page_query)
|
controlform = controlform_set(request.POST or None, queryset=page_query)
|
||||||
if controlform.is_valid():
|
if controlform.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -387,32 +543,50 @@ def control(request):
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Controle trésorier")
|
reversion.set_comment("Controle trésorier")
|
||||||
return redirect("/cotisations/control/")
|
return redirect("/cotisations/control/")
|
||||||
return render(request, 'cotisations/control.html', {'facture_list': facture_list, 'controlform': controlform})
|
return render(request, 'cotisations/control.html', {
|
||||||
|
'facture_list': facture_list,
|
||||||
|
'controlform': controlform
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_article(request):
|
def index_article(request):
|
||||||
|
"""Affiche l'ensemble des articles en vente"""
|
||||||
article_list = Article.objects.order_by('name')
|
article_list = Article.objects.order_by('name')
|
||||||
return render(request, 'cotisations/index_article.html', {'article_list':article_list})
|
return render(request, 'cotisations/index_article.html', {
|
||||||
|
'article_list': article_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_paiement(request):
|
def index_paiement(request):
|
||||||
|
"""Affiche l'ensemble des moyens de paiement en vente"""
|
||||||
paiement_list = Paiement.objects.order_by('moyen')
|
paiement_list = Paiement.objects.order_by('moyen')
|
||||||
return render(request, 'cotisations/index_paiement.html', {'paiement_list':paiement_list})
|
return render(request, 'cotisations/index_paiement.html', {
|
||||||
|
'paiement_list': paiement_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_banque(request):
|
def index_banque(request):
|
||||||
|
"""Affiche l'ensemble des banques"""
|
||||||
banque_list = Banque.objects.order_by('name')
|
banque_list = Banque.objects.order_by('name')
|
||||||
return render(request, 'cotisations/index_banque.html', {'banque_list':banque_list})
|
return render(request, 'cotisations/index_banque.html', {
|
||||||
|
'banque_list': banque_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index(request):
|
def index(request):
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
"""Affiche l'ensemble des factures, pour les cableurs et +"""
|
||||||
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
facture_list = Facture.objects.order_by('date').select_related('user').select_related('paiement').prefetch_related('vente_set').reverse()
|
facture_list = Facture.objects.order_by('date').select_related('user')\
|
||||||
|
.select_related('paiement').prefetch_related('vente_set').reverse()
|
||||||
paginator = Paginator(facture_list, pagination_number)
|
paginator = Paginator(facture_list, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -423,41 +597,47 @@ def index(request):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
facture_list = paginator.page(paginator.num_pages)
|
facture_list = paginator.page(paginator.num_pages)
|
||||||
return render(request, 'cotisations/index.html', {'facture_list': facture_list})
|
return render(request, 'cotisations/index.html', {
|
||||||
|
'facture_list': facture_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def history(request, object, id):
|
def history(request, object, object_id):
|
||||||
|
"""Affiche l'historique de chaque objet"""
|
||||||
if object == 'facture':
|
if object == 'facture':
|
||||||
try:
|
try:
|
||||||
object_instance = Facture.objects.get(pk=id)
|
object_instance = Facture.objects.get(pk=object_id)
|
||||||
except Facture.DoesNotExist:
|
except Facture.DoesNotExist:
|
||||||
messages.error(request, "Facture inexistante")
|
messages.error(request, "Facture inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
if not request.user.has_perms(('cableur',)) and object_instance.user != request.user:
|
if not request.user.has_perms(('cableur',))\
|
||||||
messages.error(request, "Vous ne pouvez pas afficher l'historique d'une facture d'un autre user que vous sans droit cableur")
|
and object_instance.user != request.user:
|
||||||
|
messages.error(request, "Vous ne pouvez pas afficher l'historique\
|
||||||
|
d'une facture d'un autre user que vous sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
elif object == 'paiement' and request.user.has_perms(('cableur',)):
|
elif object == 'paiement' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = Paiement.objects.get(pk=id)
|
object_instance = Paiement.objects.get(pk=object_id)
|
||||||
except Paiement.DoesNotExist:
|
except Paiement.DoesNotExist:
|
||||||
messages.error(request, "Paiement inexistant")
|
messages.error(request, "Paiement inexistant")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
elif object == 'article' and request.user.has_perms(('cableur',)):
|
elif object == 'article' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = Article.objects.get(pk=id)
|
object_instance = Article.objects.get(pk=object_id)
|
||||||
except Article.DoesNotExist:
|
except Article.DoesNotExist:
|
||||||
messages.error(request, "Article inexistante")
|
messages.error(request, "Article inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
elif object == 'banque' and request.user.has_perms(('cableur',)):
|
elif object == 'banque' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = Banque.objects.get(pk=id)
|
object_instance = Banque.objects.get(pk=object_id)
|
||||||
except Banque.DoesNotExist:
|
except Banque.DoesNotExist:
|
||||||
messages.error(request, "Banque inexistante")
|
messages.error(request, "Banque inexistante")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Objet inconnu")
|
messages.error(request, "Objet inconnu")
|
||||||
return redirect("/cotisations/")
|
return redirect("/cotisations/")
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
reversions = Version.objects.get_for_object(object_instance)
|
reversions = Version.objects.get_for_object(object_instance)
|
||||||
paginator = Paginator(reversions, pagination_number)
|
paginator = Paginator(reversions, pagination_number)
|
||||||
|
@ -470,4 +650,7 @@ def history(request, object, id):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
reversions = paginator.page(paginator.num_pages)
|
reversions = paginator.page(paginator.num_pages)
|
||||||
return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance})
|
return render(request, 're2o/history.html', {
|
||||||
|
'reversions': reversions,
|
||||||
|
'object': object_instance
|
||||||
|
})
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# se veut agnostique au réseau considéré, de manière à être installable en
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||||
# quelques clics.
|
# quelques clics.
|
||||||
#
|
#
|
||||||
|
# Copyirght © 2017 Daniel Stan
|
||||||
# Copyright © 2017 Gabriel Détraz
|
# Copyright © 2017 Gabriel Détraz
|
||||||
# Copyright © 2017 Goulven Kermarec
|
# Copyright © 2017 Goulven Kermarec
|
||||||
# Copyright © 2017 Augustin Lemesle
|
# Copyright © 2017 Augustin Lemesle
|
||||||
|
@ -30,20 +31,18 @@ moment de l'authentification, en WiFi, filaire, ou par les NAS eux-mêmes.
|
||||||
|
|
||||||
Inspirés d'autres exemples trouvés ici :
|
Inspirés d'autres exemples trouvés ici :
|
||||||
https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
|
https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
|
||||||
|
|
||||||
|
Inspiré du travail de Daniel Stan au Crans
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import netaddr
|
import netaddr
|
||||||
import radiusd # Module magique freeradius (radiusd.py is dummy)
|
import radiusd # Module magique freeradius (radiusd.py is dummy)
|
||||||
import os
|
|
||||||
import binascii
|
import binascii
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
import os, sys
|
import os, sys
|
||||||
|
|
||||||
|
|
||||||
import os, sys
|
|
||||||
|
|
||||||
proj_path = "/var/www/re2o/"
|
proj_path = "/var/www/re2o/"
|
||||||
# This is so Django knows where to find stuff.
|
# This is so Django knows where to find stuff.
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
|
||||||
|
|
|
@ -29,9 +29,9 @@ from django.template import Context, RequestContext, loader
|
||||||
from preferences.models import Service
|
from preferences.models import Service
|
||||||
|
|
||||||
def form(ctx, template, request):
|
def form(ctx, template, request):
|
||||||
c = ctx
|
context = ctx
|
||||||
c.update(csrf(request))
|
context.update(csrf(request))
|
||||||
return render(request, template, c)
|
return render(request, template, context)
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
|
@ -20,6 +20,9 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Fichier définissant les administration des models dans l'interface admin
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -28,18 +31,27 @@ from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from .models import Port, Room, Switch, Stack
|
from .models import Port, Room, Switch, Stack
|
||||||
|
|
||||||
|
|
||||||
class StackAdmin(VersionAdmin):
|
class StackAdmin(VersionAdmin):
|
||||||
|
"""Administration d'une stack de switches (inclus des switches)"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SwitchAdmin(VersionAdmin):
|
class SwitchAdmin(VersionAdmin):
|
||||||
|
"""Administration d'un switch"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PortAdmin(VersionAdmin):
|
class PortAdmin(VersionAdmin):
|
||||||
|
"""Administration d'un port de switches"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RoomAdmin(VersionAdmin):
|
class RoomAdmin(VersionAdmin):
|
||||||
|
"""Administration d'un chambre"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Port, PortAdmin)
|
admin.site.register(Port, PortAdmin)
|
||||||
admin.site.register(Room, RoomAdmin)
|
admin.site.register(Room, RoomAdmin)
|
||||||
admin.site.register(Switch, SwitchAdmin)
|
admin.site.register(Switch, SwitchAdmin)
|
||||||
|
|
|
@ -19,14 +19,27 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Un forms le plus simple possible pour les objets topologie de re2o.
|
||||||
|
|
||||||
|
Permet de créer et supprimer : un Port de switch, relié à un switch.
|
||||||
|
|
||||||
|
Permet de créer des stacks et d'y ajouter des switchs (StackForm)
|
||||||
|
|
||||||
|
Permet de créer, supprimer et editer un switch (EditSwitchForm,
|
||||||
|
NewSwitchForm)
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .models import Port, Switch, Room, Stack
|
|
||||||
from django.forms import ModelForm, Form
|
|
||||||
from machines.models import Interface
|
from machines.models import Interface
|
||||||
|
from django.forms import ModelForm
|
||||||
|
from .models import Port, Switch, Room, Stack
|
||||||
|
|
||||||
|
|
||||||
class PortForm(ModelForm):
|
class PortForm(ModelForm):
|
||||||
|
"""Formulaire pour la création d'un port d'un switch
|
||||||
|
Relié directement au modèle port"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Port
|
model = Port
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -35,25 +48,45 @@ class PortForm(ModelForm):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(PortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(PortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EditPortForm(ModelForm):
|
class EditPortForm(ModelForm):
|
||||||
|
"""Form pour l'édition d'un port de switche : changement des reglages
|
||||||
|
radius ou vlan, ou attribution d'une chambre, autre port ou machine
|
||||||
|
|
||||||
|
Un port est relié à une chambre, un autre port (uplink) ou une machine
|
||||||
|
(serveur ou borne), mutuellement exclusif
|
||||||
|
Optimisation sur les queryset pour machines et port_related pour
|
||||||
|
optimiser le temps de chargement avec select_related (vraiment
|
||||||
|
lent sans)"""
|
||||||
class Meta(PortForm.Meta):
|
class Meta(PortForm.Meta):
|
||||||
fields = ['room', 'related', 'machine_interface', 'radius', 'vlan_force', 'details']
|
fields = ['room', 'related', 'machine_interface', 'radius',
|
||||||
|
'vlan_force', 'details']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditPortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditPortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
self.fields['machine_interface'].queryset = Interface.objects.all().select_related('domain__extension')
|
self.fields['machine_interface'].queryset = Interface.objects.all()\
|
||||||
self.fields['related'].queryset = Port.objects.all().select_related('switch__switch_interface__domain__extension').order_by('switch', 'port')
|
.select_related('domain__extension')
|
||||||
|
self.fields['related'].queryset = Port.objects.all()\
|
||||||
|
.select_related('switch__switch_interface__domain__extension')\
|
||||||
|
.order_by('switch', 'port')
|
||||||
|
|
||||||
|
|
||||||
class AddPortForm(ModelForm):
|
class AddPortForm(ModelForm):
|
||||||
|
"""Permet d'ajouter un port de switch. Voir EditPortForm pour plus
|
||||||
|
d'informations"""
|
||||||
class Meta(PortForm.Meta):
|
class Meta(PortForm.Meta):
|
||||||
fields = ['port', 'room', 'machine_interface', 'related', 'radius', 'vlan_force', 'details']
|
fields = ['port', 'room', 'machine_interface', 'related',
|
||||||
|
'radius', 'vlan_force', 'details']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(AddPortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(AddPortForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class StackForm(ModelForm):
|
class StackForm(ModelForm):
|
||||||
|
"""Permet d'edition d'une stack : stack_id, et switches membres
|
||||||
|
de la stack"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Stack
|
model = Stack
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -62,7 +95,9 @@ class StackForm(ModelForm):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(StackForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(StackForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EditSwitchForm(ModelForm):
|
class EditSwitchForm(ModelForm):
|
||||||
|
"""Permet d'éditer un switch : nom et nombre de ports"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Switch
|
model = Switch
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -73,7 +108,10 @@ class EditSwitchForm(ModelForm):
|
||||||
self.fields['location'].label = 'Localisation'
|
self.fields['location'].label = 'Localisation'
|
||||||
self.fields['number'].label = 'Nombre de ports'
|
self.fields['number'].label = 'Nombre de ports'
|
||||||
|
|
||||||
|
|
||||||
class NewSwitchForm(ModelForm):
|
class NewSwitchForm(ModelForm):
|
||||||
|
"""Permet de créer un switch : emplacement, paramètres machine,
|
||||||
|
membre d'un stack (option), nombre de ports (number)"""
|
||||||
class Meta(EditSwitchForm.Meta):
|
class Meta(EditSwitchForm.Meta):
|
||||||
fields = ['location', 'number', 'details', 'stack', 'stack_member_id']
|
fields = ['location', 'number', 'details', 'stack', 'stack_member_id']
|
||||||
|
|
||||||
|
@ -81,7 +119,9 @@ class NewSwitchForm(ModelForm):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(NewSwitchForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(NewSwitchForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EditRoomForm(ModelForm):
|
class EditRoomForm(ModelForm):
|
||||||
|
"""Permet d'éediter le nom et commentaire d'une prise murale"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Room
|
model = Room
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -89,4 +129,3 @@ class EditRoomForm(ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditRoomForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditRoomForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,27 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des modèles de l'application topologie.
|
||||||
|
|
||||||
|
On défini les models suivants :
|
||||||
|
|
||||||
|
- stack (id, id_min, id_max et nom) regrouppant les switches
|
||||||
|
- switch : nom, nombre de port, et interface
|
||||||
|
machine correspondante (mac, ip, etc) (voir machines.models.interface)
|
||||||
|
- Port: relié à un switch parent par foreign_key, numero du port,
|
||||||
|
relié de façon exclusive à un autre port, une machine
|
||||||
|
(serveur ou borne) ou une prise murale
|
||||||
|
- room : liste des prises murales, nom et commentaire de l'état de
|
||||||
|
la prise
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.signals import post_delete
|
from django.db.models.signals import post_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.forms import ModelForm, Form
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
import reversion
|
|
||||||
|
|
||||||
from machines.models import Vlan
|
|
||||||
|
|
||||||
|
|
||||||
class Stack(models.Model):
|
class Stack(models.Model):
|
||||||
|
@ -59,7 +67,9 @@ class Stack(models.Model):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" Verification que l'id_max < id_min"""
|
""" Verification que l'id_max < id_min"""
|
||||||
if self.member_id_max < self.member_id_min:
|
if self.member_id_max < self.member_id_min:
|
||||||
raise ValidationError({'member_id_max':"L'id maximale est inférieure à l'id minimale"})
|
raise ValidationError({'member_id_max': "L'id maximale est\
|
||||||
|
inférieure à l'id minimale"})
|
||||||
|
|
||||||
|
|
||||||
class Switch(models.Model):
|
class Switch(models.Model):
|
||||||
""" Definition d'un switch. Contient un nombre de ports (number),
|
""" Definition d'un switch. Contient un nombre de ports (number),
|
||||||
|
@ -69,14 +79,25 @@ class Switch(models.Model):
|
||||||
Pourquoi ne pas avoir fait hériter switch de interface ?
|
Pourquoi ne pas avoir fait hériter switch de interface ?
|
||||||
Principalement par méconnaissance de la puissance de cette façon de faire.
|
Principalement par méconnaissance de la puissance de cette façon de faire.
|
||||||
Ceci étant entendu, django crée en interne un onetoone, ce qui a un
|
Ceci étant entendu, django crée en interne un onetoone, ce qui a un
|
||||||
effet identique avec ce que l'on fait ici"""
|
effet identique avec ce que l'on fait ici
|
||||||
|
|
||||||
|
Validation au save que l'id du stack est bien dans le range id_min
|
||||||
|
id_max de la stack parente"""
|
||||||
PRETTY_NAME = "Switch / Commutateur"
|
PRETTY_NAME = "Switch / Commutateur"
|
||||||
|
|
||||||
switch_interface = models.OneToOneField('machines.Interface', on_delete=models.CASCADE)
|
switch_interface = models.OneToOneField(
|
||||||
|
'machines.Interface',
|
||||||
|
on_delete=models.CASCADE
|
||||||
|
)
|
||||||
location = models.CharField(max_length=255)
|
location = models.CharField(max_length=255)
|
||||||
number = models.IntegerField()
|
number = models.IntegerField()
|
||||||
details = models.CharField(max_length=255, blank=True)
|
details = models.CharField(max_length=255, blank=True)
|
||||||
stack = models.ForeignKey(Stack, blank=True, null=True, on_delete=models.SET_NULL)
|
stack = models.ForeignKey(
|
||||||
|
Stack,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET_NULL
|
||||||
|
)
|
||||||
stack_member_id = models.IntegerField(blank=True, null=True)
|
stack_member_id = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -89,10 +110,16 @@ class Switch(models.Model):
|
||||||
""" Verifie que l'id stack est dans le bon range"""
|
""" Verifie que l'id stack est dans le bon range"""
|
||||||
if self.stack is not None:
|
if self.stack is not None:
|
||||||
if self.stack_member_id is not None:
|
if self.stack_member_id is not None:
|
||||||
if (self.stack_member_id > self.stack.member_id_max) or (self.stack_member_id < self.stack.member_id_min):
|
if (self.stack_member_id > self.stack.member_id_max) or\
|
||||||
raise ValidationError({'stack_member_id': "L'id de ce switch est en dehors des bornes permises pas la stack"})
|
(self.stack_member_id < self.stack.member_id_min):
|
||||||
|
raise ValidationError(
|
||||||
|
{'stack_member_id': "L'id de ce switch est en\
|
||||||
|
dehors des bornes permises pas la stack"}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise ValidationError({'stack_member_id': "L'id dans la stack ne peut être nul"})
|
raise ValidationError({'stack_member_id': "L'id dans la stack\
|
||||||
|
ne peut être nul"})
|
||||||
|
|
||||||
|
|
||||||
class Port(models.Model):
|
class Port(models.Model):
|
||||||
""" Definition d'un port. Relié à un switch(foreign_key),
|
""" Definition d'un port. Relié à un switch(foreign_key),
|
||||||
|
@ -102,7 +129,8 @@ class Port(models.Model):
|
||||||
- un autre port (uplink) (related)
|
- un autre port (uplink) (related)
|
||||||
Champs supplémentaires :
|
Champs supplémentaires :
|
||||||
- RADIUS (mode STRICT : connexion sur port uniquement si machine
|
- RADIUS (mode STRICT : connexion sur port uniquement si machine
|
||||||
d'un adhérent à jour de cotisation et que la chambre est également à jour de cotisation
|
d'un adhérent à jour de cotisation et que la chambre est également à
|
||||||
|
jour de cotisation
|
||||||
mode COMMON : vérification uniquement du statut de la machine
|
mode COMMON : vérification uniquement du statut de la machine
|
||||||
mode NO : accepte toute demande venant du port et place sur le vlan normal
|
mode NO : accepte toute demande venant du port et place sur le vlan normal
|
||||||
mode BLOQ : rejet de toute authentification
|
mode BLOQ : rejet de toute authentification
|
||||||
|
@ -119,11 +147,31 @@ class Port(models.Model):
|
||||||
|
|
||||||
switch = models.ForeignKey('Switch', related_name="ports")
|
switch = models.ForeignKey('Switch', related_name="ports")
|
||||||
port = models.IntegerField()
|
port = models.IntegerField()
|
||||||
room = models.ForeignKey('Room', on_delete=models.PROTECT, blank=True, null=True)
|
room = models.ForeignKey(
|
||||||
machine_interface = models.ForeignKey('machines.Interface', on_delete=models.SET_NULL, blank=True, null=True)
|
'Room',
|
||||||
related = models.OneToOneField('self', null=True, blank=True, related_name='related_port')
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
machine_interface = models.ForeignKey(
|
||||||
|
'machines.Interface',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
related = models.OneToOneField(
|
||||||
|
'self',
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name='related_port'
|
||||||
|
)
|
||||||
radius = models.CharField(max_length=32, choices=STATES, default='NO')
|
radius = models.CharField(max_length=32, choices=STATES, default='NO')
|
||||||
vlan_force = models.ForeignKey('machines.Vlan', on_delete=models.SET_NULL, blank=True, null=True)
|
vlan_force = models.ForeignKey(
|
||||||
|
'machines.Vlan',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
details = models.CharField(max_length=255, blank=True)
|
details = models.CharField(max_length=255, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -142,23 +190,28 @@ class Port(models.Model):
|
||||||
related_port.save()
|
related_port.save()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" Verifie que un seul de chambre, interface_parent et related_port est rempli.
|
""" Verifie que un seul de chambre, interface_parent et related_port
|
||||||
Verifie que le related n'est pas le port lui-même....
|
est rempli. Verifie que le related n'est pas le port lui-même....
|
||||||
Verifie que le related n'est pas déjà occupé par une machine ou une chambre. Si
|
Verifie que le related n'est pas déjà occupé par une machine ou une
|
||||||
ce n'est pas le cas, applique la relation related
|
chambre. Si ce n'est pas le cas, applique la relation related
|
||||||
Si un port related point vers self, on nettoie la relation
|
Si un port related point vers self, on nettoie la relation
|
||||||
A priori pas d'autre solution que de faire ça à la main. A priori tout cela est dans
|
A priori pas d'autre solution que de faire ça à la main. A priori
|
||||||
un bloc transaction, donc pas de problème de cohérence"""
|
tout cela est dans un bloc transaction, donc pas de problème de
|
||||||
|
cohérence"""
|
||||||
if hasattr(self, 'switch'):
|
if hasattr(self, 'switch'):
|
||||||
if self.port > self.switch.number:
|
if self.port > self.switch.number:
|
||||||
raise ValidationError("Ce port ne peut exister, numero trop élevé")
|
raise ValidationError("Ce port ne peut exister,\
|
||||||
if self.room and self.machine_interface or self.room and self.related or self.machine_interface and self.related:
|
numero trop élevé")
|
||||||
raise ValidationError("Chambre, interface et related_port sont mutuellement exclusifs")
|
if self.room and self.machine_interface or self.room and\
|
||||||
|
self.related or self.machine_interface and self.related:
|
||||||
|
raise ValidationError("Chambre, interface et related_port sont\
|
||||||
|
mutuellement exclusifs")
|
||||||
if self.related == self:
|
if self.related == self:
|
||||||
raise ValidationError("On ne peut relier un port à lui même")
|
raise ValidationError("On ne peut relier un port à lui même")
|
||||||
if self.related and not self.related.related:
|
if self.related and not self.related.related:
|
||||||
if self.related.machine_interface or self.related.room:
|
if self.related.machine_interface or self.related.room:
|
||||||
raise ValidationError("Le port relié est déjà occupé, veuillez le libérer avant de créer une relation")
|
raise ValidationError("Le port relié est déjà occupé, veuillez\
|
||||||
|
le libérer avant de créer une relation")
|
||||||
else:
|
else:
|
||||||
self.make_port_related()
|
self.make_port_related()
|
||||||
elif hasattr(self, 'related_port'):
|
elif hasattr(self, 'related_port'):
|
||||||
|
@ -167,6 +220,7 @@ class Port(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.switch) + " - " + str(self.port)
|
return str(self.switch) + " - " + str(self.port)
|
||||||
|
|
||||||
|
|
||||||
class Room(models.Model):
|
class Room(models.Model):
|
||||||
"""Une chambre/local contenant une prise murale"""
|
"""Une chambre/local contenant une prise murale"""
|
||||||
PRETTY_NAME = "Chambre/ Prise murale"
|
PRETTY_NAME = "Chambre/ Prise murale"
|
||||||
|
@ -180,6 +234,8 @@ class Room(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.name)
|
return str(self.name)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Stack)
|
@receiver(post_delete, sender=Stack)
|
||||||
def stack_post_delete(sender, **kwargs):
|
def stack_post_delete(sender, **kwargs):
|
||||||
|
"""Vide les id des switches membres d'une stack supprimée"""
|
||||||
Switch.objects.filter(stack=None).update(stack_member_id=None)
|
Switch.objects.filter(stack=None).update(stack_member_id=None)
|
||||||
|
|
|
@ -19,6 +19,12 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des urls de l'application topologie.
|
||||||
|
Inclu dans urls de re2o.
|
||||||
|
|
||||||
|
Fait référence aux fonctions du views
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -33,18 +39,33 @@ urlpatterns = [
|
||||||
url(r'^new_room/$', views.new_room, name='new-room'),
|
url(r'^new_room/$', views.new_room, name='new-room'),
|
||||||
url(r'^edit_room/(?P<room_id>[0-9]+)$', views.edit_room, name='edit-room'),
|
url(r'^edit_room/(?P<room_id>[0-9]+)$', views.edit_room, name='edit-room'),
|
||||||
url(r'^del_room/(?P<room_id>[0-9]+)$', views.del_room, name='del-room'),
|
url(r'^del_room/(?P<room_id>[0-9]+)$', views.del_room, name='del-room'),
|
||||||
url(r'^switch/(?P<switch_id>[0-9]+)$', views.index_port, name='index-port'),
|
url(r'^switch/(?P<switch_id>[0-9]+)$',
|
||||||
url(r'^history/(?P<object>switch)/(?P<id>[0-9]+)$', views.history, name='history'),
|
views.index_port,
|
||||||
url(r'^history/(?P<object>port)/(?P<id>[0-9]+)$', views.history, name='history'),
|
name='index-port'),
|
||||||
url(r'^history/(?P<object>room)/(?P<id>[0-9]+)$', views.history, name='history'),
|
url(r'^history/(?P<object>switch)/(?P<id>[0-9]+)$',
|
||||||
url(r'^history/(?P<object>stack)/(?P<id>[0-9]+)$', views.history, name='history'),
|
views.history,
|
||||||
|
name='history'),
|
||||||
|
url(r'^history/(?P<object>port)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'),
|
||||||
|
url(r'^history/(?P<object>room)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'),
|
||||||
|
url(r'^history/(?P<object>stack)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'),
|
||||||
url(r'^edit_port/(?P<port_id>[0-9]+)$', views.edit_port, name='edit-port'),
|
url(r'^edit_port/(?P<port_id>[0-9]+)$', views.edit_port, name='edit-port'),
|
||||||
url(r'^new_port/(?P<switch_id>[0-9]+)$', views.new_port, name='new-port'),
|
url(r'^new_port/(?P<switch_id>[0-9]+)$', views.new_port, name='new-port'),
|
||||||
url(r'^del_port/(?P<port_id>[0-9]+)$', views.del_port, name='del-port'),
|
url(r'^del_port/(?P<port_id>[0-9]+)$', views.del_port, name='del-port'),
|
||||||
url(r'^edit_switch/(?P<switch_id>[0-9]+)$', views.edit_switch, name='edit-switch'),
|
url(r'^edit_switch/(?P<switch_id>[0-9]+)$',
|
||||||
|
views.edit_switch,
|
||||||
|
name='edit-switch'),
|
||||||
url(r'^new_stack/$', views.new_stack, name='new-stack'),
|
url(r'^new_stack/$', views.new_stack, name='new-stack'),
|
||||||
url(r'^index_stack/$', views.index_stack, name='index-stack'),
|
url(r'^index_stack/$', views.index_stack, name='index-stack'),
|
||||||
url(r'^edit_stack/(?P<stack_id>[0-9]+)$', views.edit_stack, name='edit-stack'),
|
url(r'^edit_stack/(?P<stack_id>[0-9]+)$',
|
||||||
url(r'^del_stack/(?P<stack_id>[0-9]+)$', views.del_stack, name='del-stack'),
|
views.edit_stack,
|
||||||
|
name='edit-stack'),
|
||||||
|
url(r'^del_stack/(?P<stack_id>[0-9]+)$',
|
||||||
|
views.del_stack,
|
||||||
|
name='del-stack'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,20 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# 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.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Page des vues de l'application topologie
|
||||||
|
|
||||||
|
Permet de créer, modifier et supprimer :
|
||||||
|
- un port (add_port, edit_port, del_port)
|
||||||
|
- un switch : les vues d'ajout et d'édition font appel aux forms de creation
|
||||||
|
de switch, mais aussi aux forms de machines.forms (domain, interface et
|
||||||
|
machine). Le views les envoie et les save en même temps. TODO : rationaliser
|
||||||
|
et faire que la creation de machines (interfaces, domain etc) soit gérée
|
||||||
|
coté models et forms de topologie
|
||||||
|
- une chambre (new_room, edit_room, del_room)
|
||||||
|
- une stack
|
||||||
|
- l'historique de tous les objets cités
|
||||||
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
@ -33,9 +46,9 @@ from reversion import revisions as reversion
|
||||||
from reversion.models import Version
|
from reversion.models import Version
|
||||||
|
|
||||||
from topologie.models import Switch, Port, Room, Stack
|
from topologie.models import Switch, Port, Room, Stack
|
||||||
from topologie.forms import EditPortForm, NewSwitchForm, EditSwitchForm, AddPortForm, EditRoomForm, StackForm
|
from topologie.forms import EditPortForm, NewSwitchForm, EditSwitchForm
|
||||||
|
from topologie.forms import AddPortForm, EditRoomForm, StackForm
|
||||||
from users.views import form
|
from users.views import form
|
||||||
from users.models import User
|
|
||||||
|
|
||||||
from machines.forms import AliasForm, NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm
|
from machines.forms import AliasForm, NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm
|
||||||
from machines.views import generate_ipv4_bft_param
|
from machines.views import generate_ipv4_bft_param
|
||||||
|
@ -46,41 +59,52 @@ from preferences.models import AssoOption, GeneralOption
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index(request):
|
def index(request):
|
||||||
""" Vue d'affichage de tous les swicthes"""
|
""" Vue d'affichage de tous les swicthes"""
|
||||||
switch_list = Switch.objects.order_by('stack','stack_member_id','location').select_related('switch_interface__domain__extension').select_related('switch_interface__ipv4').select_related('switch_interface__domain').select_related('stack')
|
switch_list = Switch.objects.order_by(
|
||||||
return render(request, 'topologie/index.html', {'switch_list': switch_list})
|
'stack',
|
||||||
|
'stack_member_id',
|
||||||
|
'location'
|
||||||
|
)\
|
||||||
|
.select_related('switch_interface__domain__extension')\
|
||||||
|
.select_related('switch_interface__ipv4')\
|
||||||
|
.select_related('switch_interface__domain')\
|
||||||
|
.select_related('stack')
|
||||||
|
return render(request, 'topologie/index.html', {
|
||||||
|
'switch_list': switch_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def history(request, object, id):
|
def history(request, object_name, object_id):
|
||||||
""" Vue générique pour afficher l'historique complet d'un objet"""
|
""" Vue générique pour afficher l'historique complet d'un objet"""
|
||||||
if object == 'switch':
|
if object_name == 'switch':
|
||||||
try:
|
try:
|
||||||
object_instance = Switch.objects.get(pk=id)
|
object_instance = Switch.objects.get(pk=object_id)
|
||||||
except Switch.DoesNotExist:
|
except Switch.DoesNotExist:
|
||||||
messages.error(request, "Switch inexistant")
|
messages.error(request, "Switch inexistant")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
elif object == 'port':
|
elif object_name == 'port':
|
||||||
try:
|
try:
|
||||||
object_instance = Port.objects.get(pk=id)
|
object_instance = Port.objects.get(pk=object_id)
|
||||||
except Port.DoesNotExist:
|
except Port.DoesNotExist:
|
||||||
messages.error(request, "Port inexistant")
|
messages.error(request, "Port inexistant")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
elif object == 'room':
|
elif object_name == 'room':
|
||||||
try:
|
try:
|
||||||
object_instance = Room.objects.get(pk=id)
|
object_instance = Room.objects.get(pk=object_id)
|
||||||
except Room.DoesNotExist:
|
except Room.DoesNotExist:
|
||||||
messages.error(request, "Chambre inexistante")
|
messages.error(request, "Chambre inexistante")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
elif object == 'stack':
|
elif object_name == 'stack':
|
||||||
try:
|
try:
|
||||||
object_instance = Stack.objects.get(pk=id)
|
object_instance = Stack.objects.get(pk=object_id)
|
||||||
except Room.DoesNotExist:
|
except Room.DoesNotExist:
|
||||||
messages.error(request, "Stack inexistante")
|
messages.error(request, "Stack inexistante")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Objet inconnu")
|
messages.error(request, "Objet inconnu")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
reversions = Version.objects.get_for_object(object_instance)
|
reversions = Version.objects.get_for_object(object_instance)
|
||||||
paginator = Paginator(reversions, pagination_number)
|
paginator = Paginator(reversions, pagination_number)
|
||||||
|
@ -93,7 +117,11 @@ def history(request, object, id):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
reversions = paginator.page(paginator.num_pages)
|
reversions = paginator.page(paginator.num_pages)
|
||||||
return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance})
|
return render(request, 're2o/history.html', {
|
||||||
|
'reversions': reversions,
|
||||||
|
'object': object_instance
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
|
@ -104,15 +132,25 @@ def index_port(request, switch_id):
|
||||||
except Switch.DoesNotExist:
|
except Switch.DoesNotExist:
|
||||||
messages.error(request, u"Switch inexistant")
|
messages.error(request, u"Switch inexistant")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
port_list = Port.objects.filter(switch = switch).select_related('room').select_related('machine_interface__domain__extension').select_related('related').select_related('switch').order_by('port')
|
port_list = Port.objects.filter(switch=switch)\
|
||||||
return render(request, 'topologie/index_p.html', {'port_list':port_list, 'id_switch':switch_id, 'nom_switch':switch})
|
.select_related('room')\
|
||||||
|
.select_related('machine_interface__domain__extension')\
|
||||||
|
.select_related('related')\
|
||||||
|
.select_related('switch')\
|
||||||
|
.order_by('port')
|
||||||
|
return render(request, 'topologie/index_p.html', {
|
||||||
|
'port_list': port_list,
|
||||||
|
'id_switch': switch_id,
|
||||||
|
'nom_switch': switch
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_room(request):
|
def index_room(request):
|
||||||
""" Affichage de l'ensemble des chambres"""
|
""" Affichage de l'ensemble des chambres"""
|
||||||
room_list = Room.objects.order_by('name')
|
room_list = Room.objects.order_by('name')
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
paginator = Paginator(room_list, pagination_number)
|
paginator = Paginator(room_list, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
|
@ -124,13 +162,20 @@ def index_room(request):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
room_list = paginator.page(paginator.num_pages)
|
room_list = paginator.page(paginator.num_pages)
|
||||||
return render(request, 'topologie/index_room.html', {'room_list': room_list})
|
return render(request, 'topologie/index_room.html', {
|
||||||
|
'room_list': room_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def index_stack(request):
|
def index_stack(request):
|
||||||
stack_list = Stack.objects.order_by('name').prefetch_related('switch_set__switch_interface__domain__extension')
|
"""Affichage de la liste des stacks (affiche l'ensemble des switches)"""
|
||||||
return render(request, 'topologie/index_stack.html', {'stack_list': stack_list})
|
stack_list = Stack.objects.order_by('name')\
|
||||||
|
.prefetch_related('switch_set__switch_interface__domain__extension')
|
||||||
|
return render(request, 'topologie/index_stack.html', {
|
||||||
|
'stack_list': stack_list
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -157,12 +202,20 @@ def new_port(request, switch_id):
|
||||||
return redirect("/topologie/switch/" + switch_id)
|
return redirect("/topologie/switch/" + switch_id)
|
||||||
return form({'topoform': port}, 'topologie/topo.html', request)
|
return form({'topoform': port}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_port(request, port_id):
|
def edit_port(request, port_id):
|
||||||
""" Edition d'un port. Permet de changer le switch parent et l'affectation du port"""
|
""" Edition d'un port. Permet de changer le switch parent et
|
||||||
|
l'affectation du port"""
|
||||||
try:
|
try:
|
||||||
port_object = Port.objects.select_related('switch__switch_interface__domain__extension').select_related('machine_interface__domain__extension').select_related('machine_interface__switch').select_related('room').select_related('related').get(pk=port_id)
|
port_object = Port.objects\
|
||||||
|
.select_related('switch__switch_interface__domain__extension')\
|
||||||
|
.select_related('machine_interface__domain__extension')\
|
||||||
|
.select_related('machine_interface__switch')\
|
||||||
|
.select_related('room')\
|
||||||
|
.select_related('related')\
|
||||||
|
.get(pk=port_id)
|
||||||
except Port.DoesNotExist:
|
except Port.DoesNotExist:
|
||||||
messages.error(request, u"Port inexistant")
|
messages.error(request, u"Port inexistant")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
|
@ -171,11 +224,14 @@ def edit_port(request, port_id):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
port.save()
|
port.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in port.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in port.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "Le port a bien été modifié")
|
messages.success(request, "Le port a bien été modifié")
|
||||||
return redirect("/topologie/switch/" + str(port_object.switch.id))
|
return redirect("/topologie/switch/" + str(port_object.switch.id))
|
||||||
return form({'topoform': port}, 'topologie/topo.html', request)
|
return form({'topoform': port}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def del_port(request, port_id):
|
def del_port(request, port_id):
|
||||||
|
@ -193,32 +249,30 @@ def del_port(request,port_id):
|
||||||
reversion.set_comment("Destruction")
|
reversion.set_comment("Destruction")
|
||||||
messages.success(request, "Le port a eté détruit")
|
messages.success(request, "Le port a eté détruit")
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "Le port %s est affecté à un autre objet, impossible de le supprimer" % port)
|
messages.error(request, "Le port %s est affecté à un autre objet,\
|
||||||
|
impossible de le supprimer" % port)
|
||||||
return redirect('/topologie/switch/' + str(port.switch.id))
|
return redirect('/topologie/switch/' + str(port.switch.id))
|
||||||
return form({'objet': port}, 'topologie/delete.html', request)
|
return form({'objet': port}, 'topologie/delete.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def new_stack(request):
|
def new_stack(request):
|
||||||
|
"""Ajoute un nouveau stack : stack_id_min, max, et nombre de switches"""
|
||||||
stack = StackForm(request.POST or None)
|
stack = StackForm(request.POST or None)
|
||||||
#if stack.is_valid():
|
if stack.is_valid():
|
||||||
if request.POST:
|
|
||||||
try:
|
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
stack.save()
|
stack.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "Stack crée")
|
messages.success(request, "Stack crée")
|
||||||
except:
|
|
||||||
messages.error(request, "Cette stack existe déjà")
|
|
||||||
else:
|
|
||||||
return redirect('/topologie/index_stack')
|
|
||||||
return form({'topoform': stack}, 'topologie/topo.html', request)
|
return form({'topoform': stack}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_stack(request, stack_id):
|
def edit_stack(request, stack_id):
|
||||||
|
"""Edition d'un stack (nombre de switches, nom...)"""
|
||||||
try:
|
try:
|
||||||
stack = Stack.objects.get(pk=stack_id)
|
stack = Stack.objects.get(pk=stack_id)
|
||||||
except Stack.DoesNotExist:
|
except Stack.DoesNotExist:
|
||||||
|
@ -229,13 +283,19 @@ def edit_stack(request,stack_id):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
stack.save()
|
stack.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in stack.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in stack.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
return redirect('/topologie/index_stack')
|
return redirect('/topologie/index_stack')
|
||||||
return form({'topoform': stack}, 'topologie/topo.html', request)
|
return form({'topoform': stack}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def del_stack(request, stack_id):
|
def del_stack(request, stack_id):
|
||||||
|
"""Supprime un stack"""
|
||||||
try:
|
try:
|
||||||
stack = Stack.objects.get(pk=stack_id)
|
stack = Stack.objects.get(pk=stack_id)
|
||||||
except Stack.DoesNotExist:
|
except Stack.DoesNotExist:
|
||||||
|
@ -249,13 +309,16 @@ def del_stack(request,stack_id):
|
||||||
reversion.set_comment("Destruction")
|
reversion.set_comment("Destruction")
|
||||||
messages.success(request, "La stack a eté détruite")
|
messages.success(request, "La stack a eté détruite")
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "La stack %s est affectée à un autre objet, impossible de la supprimer" % stack)
|
messages.error(request, "La stack %s est affectée à un autre\
|
||||||
|
objet, impossible de la supprimer" % stack)
|
||||||
return redirect('/topologie/index_stack')
|
return redirect('/topologie/index_stack')
|
||||||
return form({'objet': stack}, 'topologie/delete.html', request)
|
return form({'objet': stack}, 'topologie/delete.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_switchs_stack(request, stack_id):
|
def edit_switchs_stack(request, stack_id):
|
||||||
|
"""Permet d'éditer la liste des switches dans une stack et l'ajouter"""
|
||||||
try:
|
try:
|
||||||
stack = Stack.objects.get(pk=stack_id)
|
stack = Stack.objects.get(pk=stack_id)
|
||||||
except Stack.DoesNotExist:
|
except Stack.DoesNotExist:
|
||||||
|
@ -267,30 +330,36 @@ def edit_switchs_stack(request,stack_id):
|
||||||
context = {'stack': stack}
|
context = {'stack': stack}
|
||||||
context['switchs_stack'] = stack.switchs_set.all()
|
context['switchs_stack'] = stack.switchs_set.all()
|
||||||
context['switchs_autres'] = Switch.object.filter(stack=None)
|
context['switchs_autres'] = Switch.object.filter(stack=None)
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def new_switch(request):
|
def new_switch(request):
|
||||||
""" Creation d'un switch. Cree en meme temps l'interface et la machine associée.
|
""" Creation d'un switch. Cree en meme temps l'interface et la machine
|
||||||
Vue complexe. Appelle successivement les 4 models forms adaptés : machine,
|
associée. Vue complexe. Appelle successivement les 4 models forms
|
||||||
interface, domain et switch"""
|
adaptés : machine, interface, domain et switch"""
|
||||||
switch = NewSwitchForm(request.POST or None)
|
switch = NewSwitchForm(request.POST or None)
|
||||||
machine = NewMachineForm(request.POST or None)
|
machine = NewMachineForm(request.POST or None)
|
||||||
interface = AddInterfaceForm(request.POST or None, infra=request.user.has_perms(('infra',)))
|
interface = AddInterfaceForm(
|
||||||
domain = AliasForm(request.POST or None, infra=request.user.has_perms(('infra',)))
|
request.POST or None,
|
||||||
|
infra=request.user.has_perms(('infra',))
|
||||||
|
)
|
||||||
|
domain = AliasForm(
|
||||||
|
request.POST or None,
|
||||||
|
infra=request.user.has_perms(('infra',))
|
||||||
|
)
|
||||||
if switch.is_valid() and machine.is_valid() and interface.is_valid():
|
if switch.is_valid() and machine.is_valid() and interface.is_valid():
|
||||||
options, created = AssoOption.objects.get_or_create()
|
options, _created = AssoOption.objects.get_or_create()
|
||||||
user = options.utilisateur_asso
|
user = options.utilisateur_asso
|
||||||
if not user:
|
if not user:
|
||||||
messages.error(request, "L'user association n'existe pas encore, veuillez le créer ou le linker dans preferences")
|
messages.error(request, "L'user association n'existe pas encore,\
|
||||||
|
veuillez le créer ou le linker dans preferences")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
new_machine = machine.save(commit=False)
|
new_machine = machine.save(commit=False)
|
||||||
new_machine.user = user
|
new_machine.user = user
|
||||||
new_interface = interface.save(commit=False)
|
new_interface = interface.save(commit=False)
|
||||||
new_switch = switch.save(commit=False)
|
new_switch_instance = switch.save(commit=False)
|
||||||
new_domain = domain.save(commit=False)
|
new_domain_instance = domain.save(commit=False)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_machine.save()
|
new_machine.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
|
@ -300,14 +369,14 @@ def new_switch(request):
|
||||||
new_interface.save()
|
new_interface.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
new_domain.interface_parent = new_interface
|
new_domain_instance.interface_parent = new_interface
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_domain.save()
|
new_domain_instance.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
new_switch.switch_interface = new_interface
|
new_switch_instance.switch_interface = new_interface
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_switch.save()
|
new_switch_instance.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "Le switch a été créé")
|
messages.success(request, "Le switch a été créé")
|
||||||
|
@ -318,38 +387,59 @@ def new_switch(request):
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_switch(request, switch_id):
|
def edit_switch(request, switch_id):
|
||||||
""" Edition d'un switch. Permet de chambre nombre de ports, place dans le stack,
|
""" Edition d'un switch. Permet de chambre nombre de ports,
|
||||||
interface et machine associée"""
|
place dans le stack, interface et machine associée"""
|
||||||
try:
|
try:
|
||||||
switch = Switch.objects.get(pk=switch_id)
|
switch = Switch.objects.get(pk=switch_id)
|
||||||
except Switch.DoesNotExist:
|
except Switch.DoesNotExist:
|
||||||
messages.error(request, u"Switch inexistant")
|
messages.error(request, u"Switch inexistant")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
switch_form = EditSwitchForm(request.POST or None, instance=switch)
|
switch_form = EditSwitchForm(request.POST or None, instance=switch)
|
||||||
machine_form = EditMachineForm(request.POST or None, instance=switch.switch_interface.machine)
|
machine_form = EditMachineForm(
|
||||||
interface_form = EditInterfaceForm(request.POST or None, instance=switch.switch_interface)
|
request.POST or None,
|
||||||
domain_form = AliasForm(request.POST or None, infra=request.user.has_perms(('infra',)), instance=switch.switch_interface.domain)
|
instance=switch.switch_interface.machine
|
||||||
if switch_form.is_valid() and machine_form.is_valid() and interface_form.is_valid():
|
)
|
||||||
|
interface_form = EditInterfaceForm(
|
||||||
|
request.POST or None,
|
||||||
|
instance=switch.switch_interface
|
||||||
|
)
|
||||||
|
domain_form = AliasForm(
|
||||||
|
request.POST or None,
|
||||||
|
infra=request.user.has_perms(('infra',)),
|
||||||
|
instance=switch.switch_interface.domain
|
||||||
|
)
|
||||||
|
if switch_form.is_valid() and machine_form.is_valid()\
|
||||||
|
and interface_form.is_valid():
|
||||||
new_interface = interface_form.save(commit=False)
|
new_interface = interface_form.save(commit=False)
|
||||||
new_machine = machine_form.save(commit=False)
|
new_machine = machine_form.save(commit=False)
|
||||||
new_switch = switch_form.save(commit=False)
|
new_switch_instance = switch_form.save(commit=False)
|
||||||
new_domain = domain_form.save(commit=False)
|
new_domain = domain_form.save(commit=False)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_machine.save()
|
new_machine.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in machine_form.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in machine_form.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_interface.save()
|
new_interface.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in interface_form.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in interface_form.changed_data)
|
||||||
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_domain.save()
|
new_domain.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in domain_form.changed_data)
|
||||||
|
)
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
new_switch.save()
|
new_switch_instance.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in switch_form.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in switch_form.changed_data)
|
||||||
|
)
|
||||||
messages.success(request, "Le switch a bien été modifié")
|
messages.success(request, "Le switch a bien été modifié")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
i_bft_param = generate_ipv4_bft_param( interface_form, False )
|
i_bft_param = generate_ipv4_bft_param( interface_form, False )
|
||||||
|
@ -369,6 +459,7 @@ def new_room(request):
|
||||||
return redirect("/topologie/index_room/")
|
return redirect("/topologie/index_room/")
|
||||||
return form({'topoform': room}, 'topologie/topo.html', request)
|
return form({'topoform': room}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_room(request, room_id):
|
def edit_room(request, room_id):
|
||||||
|
@ -383,11 +474,14 @@ def edit_room(request, room_id):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
room.save()
|
room.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in room.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in room.changed_data)
|
||||||
|
)
|
||||||
messages.success(request, "La chambre a bien été modifiée")
|
messages.success(request, "La chambre a bien été modifiée")
|
||||||
return redirect("/topologie/index_room/")
|
return redirect("/topologie/index_room/")
|
||||||
return form({'topoform': room}, 'topologie/topo.html', request)
|
return form({'topoform': room}, 'topologie/topo.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def del_room(request, room_id):
|
def del_room(request, room_id):
|
||||||
|
@ -405,6 +499,10 @@ def del_room(request, room_id):
|
||||||
reversion.set_comment("Destruction")
|
reversion.set_comment("Destruction")
|
||||||
messages.success(request, "La chambre/prise a été détruite")
|
messages.success(request, "La chambre/prise a été détruite")
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "La chambre %s est affectée à un autre objet, impossible de la supprimer (switch ou user)" % room)
|
messages.error(request, "La chambre %s est affectée à un autre objet,\
|
||||||
|
impossible de la supprimer (switch ou user)" % room)
|
||||||
return redirect("/topologie/index_room/")
|
return redirect("/topologie/index_room/")
|
||||||
return form({'objet': room, 'objet_name': 'Chambre'}, 'topologie/delete.html', request)
|
return form({
|
||||||
|
'objet': room,
|
||||||
|
'objet_name': 'Chambre'
|
||||||
|
}, 'topologie/delete.html', request)
|
||||||
|
|
|
@ -651,10 +651,10 @@ def profil(request, userid):
|
||||||
if not request.user.has_perms(('cableur',)) and users != request.user:
|
if not request.user.has_perms(('cableur',)) and users != request.user:
|
||||||
messages.error(request, "Vous ne pouvez pas afficher un autre user que vous sans droit cableur")
|
messages.error(request, "Vous ne pouvez pas afficher un autre user que vous sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
machines = Machine.objects.filter(user__pseudo=users).select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type__extension').prefetch_related('interface_set__type').prefetch_related('interface_set__domain__related_domain__extension')
|
machines = Machine.objects.filter(user=users).select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type__extension').prefetch_related('interface_set__type').prefetch_related('interface_set__domain__related_domain__extension')
|
||||||
factures = Facture.objects.filter(user__pseudo=users)
|
factures = Facture.objects.filter(user=users)
|
||||||
bans = Ban.objects.filter(user__pseudo=users)
|
bans = Ban.objects.filter(user=users)
|
||||||
whitelists = Whitelist.objects.filter(user__pseudo=users)
|
whitelists = Whitelist.objects.filter(user=users)
|
||||||
list_droits = Right.objects.filter(user=users)
|
list_droits = Right.objects.filter(user=users)
|
||||||
options, created = OptionalUser.objects.get_or_create()
|
options, created = OptionalUser.objects.get_or_create()
|
||||||
user_solde = options.user_solde
|
user_solde = options.user_solde
|
||||||
|
|
Loading…
Reference in a new issue