diff --git a/cotisations/migrations/0021_auto_20170819_0104.py b/cotisations/migrations/0021_auto_20170819_0104.py new file mode 100644 index 00000000..1f165a44 --- /dev/null +++ b/cotisations/migrations/0021_auto_20170819_0104.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-18 23:04 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0020_auto_20170819_0057'), + ] + + operations = [ + migrations.AlterField( + model_name='paiement', + name='type_paiement', + field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0), + ), + ] diff --git a/cotisations/migrations/0022_auto_20170824_0128.py b/cotisations/migrations/0022_auto_20170824_0128.py new file mode 100644 index 00000000..bd605aee --- /dev/null +++ b/cotisations/migrations/0022_auto_20170824_0128.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-23 23:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0021_auto_20170819_0104'), + ] + + operations = [ + migrations.AlterField( + model_name='paiement', + name='type_paiement', + field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), + ), + ] diff --git a/cotisations/views.py b/cotisations/views.py index 89dea5da..07dd6f68 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -41,9 +41,9 @@ 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 .tex import render_tex -from re2o.settings import ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH +from re2o.settings import LOGO_PATH from re2o import settings -from preferences.models import OptionalUser, GeneralOption +from preferences.models import OptionalUser, AssoOption, GeneralOption from dateutil.relativedelta import relativedelta from django.utils import timezone @@ -111,6 +111,7 @@ def new_facture(request, userid): def new_facture_pdf(request): facture_form = NewFactureFormPdf(request.POST or None) if facture_form.is_valid(): + options, created = AssoOption.objects.get_or_create() tbl = [] article = facture_form.cleaned_data['article'] quantite = facture_form.cleaned_data['number'] @@ -122,7 +123,7 @@ def new_facture_pdf(request): tbl.append([a, quantite, a.prix * quantite]) prix_total = sum(a[2] for a in tbl) 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':ASSO_NAME, 'line1':ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)}) + 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 form({'factureform': facture_form}, 'cotisations/facture.html', request) @login_required @@ -140,9 +141,10 @@ def facture_pdf(request, factureid): return redirect("/users/profil/" + str(request.user.id)) vente = Vente.objects.all().filter(facture=facture) ventes = [] + options, created = AssoOption.objects.get_or_create() for v in vente: ventes.append([v, v.number, v.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':ASSO_NAME, 'line1': ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, '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 @permission_required('cableur') diff --git a/machines/models.py b/machines/models.py index bd4426c3..9da62f5e 100644 --- a/machines/models.py +++ b/machines/models.py @@ -334,6 +334,7 @@ def machine_post_save(sender, **kwargs): user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) regen('dhcp') regen('dns') + regen('mac_ip_list') @receiver(post_delete, sender=Machine) def machine_post_delete(sender, **kwargs): @@ -348,6 +349,7 @@ def interface_post_save(sender, **kwargs): user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) regen('dhcp') regen('dns') + regen('mac_ip_list') @receiver(post_delete, sender=Interface) def interface_post_delete(sender, **kwargs): diff --git a/preferences/admin.py b/preferences/admin.py index 8c38f3f3..e1806c5a 100644 --- a/preferences/admin.py +++ b/preferences/admin.py @@ -1,3 +1,47 @@ -from django.contrib import admin +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# Register your models here. +from django.contrib import admin +from reversion.admin import VersionAdmin + +from .models import OptionalUser, OptionalMachine, GeneralOption, Service, AssoOption + +class OptionalUserAdmin(VersionAdmin): + pass + +class OptionalMachineAdmin(VersionAdmin): + pass + +class GeneralOptionAdmin(VersionAdmin): + pass + +class ServiceAdmin(VersionAdmin): + pass + +class AssoOptionAdmin(VersionAdmin): + pass + +admin.site.register(OptionalUser, OptionalUserAdmin) +admin.site.register(OptionalMachine, OptionalMachineAdmin) +admin.site.register(GeneralOption, GeneralOptionAdmin) +admin.site.register(Service, ServiceAdmin) +admin.site.register(AssoOption, AssoOptionAdmin) diff --git a/preferences/forms.py b/preferences/forms.py index ec1de82b..0bdee00c 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -22,38 +22,48 @@ from django.forms import ModelForm, Form, ValidationError from django import forms -from .models import OptionalUser, OptionalMachine, GeneralOption +from .models import OptionalUser, OptionalMachine, GeneralOption, AssoOption, Service from django.db.models import Q -class EditUserOptionsForm(ModelForm): +class EditOptionalUserForm(ModelForm): class Meta: model = OptionalUser fields = '__all__' def __init__(self, *args, **kwargs): - super(EditUserOptionsForm, self).__init__(*args, **kwargs) + super(EditOptionalUserForm, self).__init__(*args, **kwargs) self.fields['is_tel_mandatory'].label = 'Exiger un numéro de téléphone' self.fields['user_solde'].label = 'Activation du solde pour les utilisateurs' -class EditMachineOptionsForm(ModelForm): +class EditOptionalMachineForm(ModelForm): class Meta: model = OptionalMachine fields = '__all__' def __init__(self, *args, **kwargs): - super(EditMachineOptionsForm, self).__init__(*args, **kwargs) + super(EditOptionalMachineForm, self).__init__(*args, **kwargs) self.fields['password_machine'].label = "Possibilité d'attribuer un mot de passe par interface" self.fields['max_lambdauser_interfaces'].label = "Maximum d'interfaces autorisées pour un user normal" self.fields['max_lambdauser_aliases'].label = "Maximum d'alias dns autorisés pour un user normal" -class EditGeneralOptionsForm(ModelForm): +class EditGeneralOptionForm(ModelForm): class Meta: model = GeneralOption fields = '__all__' def __init__(self, *args, **kwargs): - super(EditGeneralOptionsForm, self).__init__(*args, **kwargs) + super(EditGeneralOptionForm, self).__init__(*args, **kwargs) self.fields['search_display_page'].label = 'Resultats affichés dans une recherche' self.fields['pagination_number'].label = 'Items par page, taille normale (ex users)' self.fields['pagination_large_number'].label = 'Items par page, taille élevée (machines)' + +class EditAssoOptionForm(ModelForm): + class Meta: + model = AssoOption + fields = '__all__' + +class Service(ModelForm): + class Meta: + model = Service + fields = '__all__' diff --git a/preferences/migrations/0004_assooption_services.py b/preferences/migrations/0004_assooption_services.py new file mode 100644 index 00000000..b8601a7f --- /dev/null +++ b/preferences/migrations/0004_assooption_services.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-23 23:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0003_optionaluser_solde_negatif'), + ] + + operations = [ + migrations.CreateModel( + name='AssoOption', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default="Association réseau de l'école machin", max_length=32)), + ('siret', models.CharField(default='00000000000000', max_length=32)), + ('adresse', models.CharField(default="1 Rue de l'exemple, 94230 Cachan", max_length=128)), + ('contact', models.EmailField(default='contact@example.org', max_length=254)), + ('telephone', models.CharField(default='0000000000', max_length=15)), + ('pseudo', models.CharField(default='Asso', max_length=32)), + ], + ), + migrations.CreateModel( + name='Services', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ('url', models.URLField()), + ('description', models.TextField()), + ('image', models.ImageField(upload_to='logo')), + ], + ), + ] diff --git a/preferences/migrations/0005_auto_20170824_0139.py b/preferences/migrations/0005_auto_20170824_0139.py new file mode 100644 index 00000000..c1fb68c7 --- /dev/null +++ b/preferences/migrations/0005_auto_20170824_0139.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-23 23:39 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0004_assooption_services'), + ] + + operations = [ + migrations.RenameModel( + old_name='Services', + new_name='Service', + ), + ] diff --git a/preferences/migrations/0006_auto_20170824_0143.py b/preferences/migrations/0006_auto_20170824_0143.py new file mode 100644 index 00000000..782bbbdc --- /dev/null +++ b/preferences/migrations/0006_auto_20170824_0143.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-23 23:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0005_auto_20170824_0139'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='image', + field=models.ImageField(blank=True, upload_to='logo'), + ), + ] diff --git a/preferences/migrations/0007_auto_20170824_2056.py b/preferences/migrations/0007_auto_20170824_2056.py new file mode 100644 index 00000000..55a74e08 --- /dev/null +++ b/preferences/migrations/0007_auto_20170824_2056.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-24 18:56 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0006_auto_20170824_0143'), + ] + + operations = [ + migrations.AlterField( + model_name='assooption', + name='name', + field=models.CharField(default="Association réseau de l'école machin", max_length=256), + ), + ] diff --git a/preferences/migrations/0008_auto_20170824_2122.py b/preferences/migrations/0008_auto_20170824_2122.py new file mode 100644 index 00000000..183607aa --- /dev/null +++ b/preferences/migrations/0008_auto_20170824_2122.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-24 19:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0007_auto_20170824_2056'), + ] + + operations = [ + migrations.RemoveField( + model_name='assooption', + name='adresse', + ), + migrations.AddField( + model_name='assooption', + name='adresse1', + field=models.CharField(default='1 Rue de exemple', max_length=128), + ), + migrations.AddField( + model_name='assooption', + name='adresse2', + field=models.CharField(default='94230 Cachan', max_length=128), + ), + migrations.AlterField( + model_name='assooption', + name='name', + field=models.CharField(default='Association réseau école machin', max_length=256), + ), + ] diff --git a/preferences/migrations/0009_assooption_utilisateur_asso.py b/preferences/migrations/0009_assooption_utilisateur_asso.py new file mode 100644 index 00000000..68bcc382 --- /dev/null +++ b/preferences/migrations/0009_assooption_utilisateur_asso.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-08-24 19:35 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('preferences', '0008_auto_20170824_2122'), + ] + + operations = [ + migrations.AddField( + model_name='assooption', + name='utilisateur_asso', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 13106e05..47ab7381 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -25,6 +25,8 @@ from django.db import models from cotisations.models import Paiement class OptionalUser(models.Model): + PRETTY_NAME = "Options utilisateur" + is_tel_mandatory = models.BooleanField(default=True) user_solde = models.BooleanField(default=False) solde_negatif = models.DecimalField(max_digits=5, decimal_places=2, default=0) @@ -35,6 +37,8 @@ class OptionalUser(models.Model): Paiement.objects.get_or_create(moyen="Solde") class OptionalMachine(models.Model): + PRETTY_NAME = "Options machines" + password_machine = models.BooleanField(default=False) max_lambdauser_interfaces = models.IntegerField(default=10) max_lambdauser_aliases = models.IntegerField(default=10) @@ -43,7 +47,26 @@ class OptionalMachine(models.Model): class GeneralOption(models.Model): + PRETTY_NAME = "Options générales" + search_display_page = models.IntegerField(default=15) pagination_number = models.IntegerField(default=25) pagination_large_number = models.IntegerField(default=8) +class Service(models.Model): + name = models.CharField(max_length=32) + url = models.URLField() + description = models.TextField() + image = models.ImageField(upload_to='logo', blank=True) + +class AssoOption(models.Model): + PRETTY_NAME = "Options de l'association" + + name = models.CharField(default="Association réseau école machin", max_length=256) + siret = models.CharField(default="00000000000000", max_length=32) + adresse1 = models.CharField(default="1 Rue de exemple", max_length=128) + adresse2 = models.CharField(default="94230 Cachan", max_length=128) + contact = models.EmailField(default="contact@example.org") + telephone = models.CharField(max_length=15, default="0000000000") + pseudo = models.CharField(default="Asso", max_length=32) + utilisateur_asso = models.OneToOneField('users.User', on_delete=models.PROTECT, blank=True, null=True) diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index a4d6c583..ffb0091e 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -28,13 +28,15 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block title %}Création et modification des préférences{% endblock %} {% block content %} +
+
Téléphone obligatoirement requis | @@ -48,6 +50,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
---|
+
Mot de passe par machine | @@ -61,6 +71,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
---|
+
Affichage de résultats dans le champ de recherche | @@ -73,6 +91,39 @@ with this program; if not, write to the Free Software Foundation, Inc.,{{ generaloptions.pagination_large_number }} |
---|
+
+Nom | +{{ assooptions.name }} | +SIRET | +{{ assooptions.siret }} | +
---|---|---|---|
Adresse | +{{ assooptions.adresse1 }} {{ assooptions.adresse2 }} | +Contact mail | +{{ assooptions.contact }} | +
Telephone | +{{ assooptions.telephone }} | +Pseudo d'usage | +{{ assooptions.pseudo }} | +
Objet utilisateur de l'association | +{{ assooptions.utilisateur_asso }} | +