From 75bb3658ac2a24e4644b5af005893ccbae9501c2 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sat, 21 Sep 2019 23:10:28 +0200 Subject: [PATCH] Add Mandate model --- preferences/forms.py | 14 ++++- preferences/migrations/0063_mandate.py | 54 +++++++++++++++++ preferences/models.py | 35 +++++++++++ .../templates/preferences/aff_mandate.html | 52 ++++++++++++++++ .../preferences/display_preferences.html | 7 +++ preferences/urls.py | 15 +++++ preferences/views.py | 59 ++++++++++++++++++- 7 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 preferences/migrations/0063_mandate.py create mode 100644 preferences/templates/preferences/aff_mandate.html diff --git a/preferences/forms.py b/preferences/forms.py index c3d6376f..981bf5e2 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -45,7 +45,8 @@ from .models import ( RadiusOption, CotisationsOption, DocumentTemplate, - RadiusAttribute + RadiusAttribute, + Mandate ) from topologie.models import Switch @@ -261,6 +262,17 @@ class EditCotisationsOptionForm(ModelForm): fields = '__all__' +class MandateForm(ModelForm): + """Edit Mandates""" + class Meta: + model = Mandate + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(MandateForm, self).__init__(*args, prefix=prefix, **kwargs) + + class ServiceForm(ModelForm): """Edition, ajout de services sur la page d'accueil""" class Meta: diff --git a/preferences/migrations/0063_mandate.py b/preferences/migrations/0063_mandate.py new file mode 100644 index 00000000..f28acee4 --- /dev/null +++ b/preferences/migrations/0063_mandate.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-09-21 18:23 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +from django.utils import timezone +import re2o.mixins + + +def create_current_mandate(apps, schema_editor): + AssoOption = apps.get_model('preferences', 'AssoOption') + Mandate = apps.get_model('preferences', 'Mandate') + Adherent = apps.get_model('users', 'Adherent') + pres_name = AssoOption.objects.get_or_create()[0].pres_name + l = pres_name.split(' ') + try: + name, surname = l[0], l[1] + president = Adherent.objects.get(name__icontains=name, surname__icontains=surname) + Mandate.objects.create( + president=president, + start_date=timezone.now(), + ) + except Exception as e: + print("Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward." % pres_name) + + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('preferences', '0062_auto_20190910_1909'), + ] + + operations = [ + migrations.CreateModel( + name='Mandate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_date', models.DateTimeField(verbose_name='start date')), + ('end_date', models.DateTimeField(blank=True, null=True, verbose_name='end date')), + ('president', models.ForeignKey(blank=True, help_text='Displayed on subscription vouchers', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='President of the association')), + ], + options={ + 'verbose_name': 'Mandate', + 'verbose_name_plural': 'Mandates', + 'permissions': (('view_mandate', 'Can view a mandate'),), + }, + bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), + ), + migrations.RunPython(create_current_mandate), + ] diff --git a/preferences/models.py b/preferences/models.py index 39eb814e..90655d48 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -501,6 +501,41 @@ class MailContact(AclMixin, models.Model): def __str__(self): return(self.address) +class Mandate(RevMixin, AclMixin, models.Model): + class Meta: + verbose_name = _("Mandate") + verbose_name_plural = _("Mandates") + permissions = ( + ("view_mandate", _("Can view a mandate")), + ) + + president = models.ForeignKey( + 'users.User', + on_delete=models.SET_NULL, + null=True, + blank=True, + verbose_name=_("President of the association"), + help_text=_("Displayed on subscription vouchers") + ) + start_date = models.DateTimeField( + verbose_name=_("start date") + ) + end_date = models.DateTimeField( + verbose_name=_("end date"), + blank=True, + null=True + ) + + @classmethod + def get_mandate(cls, date=timezone.now): + if callable(date): + date = date() + return cls.objects.get( + start_date__gte=date, end_date__lte=date + ) + + def is_over(self): + return self.end_date is None class AssoOption(AclMixin, PreferencesModel): """Options générales de l'asso : siret, addresse, nom, etc""" diff --git a/preferences/templates/preferences/aff_mandate.html b/preferences/templates/preferences/aff_mandate.html new file mode 100644 index 00000000..38017985 --- /dev/null +++ b/preferences/templates/preferences/aff_mandate.html @@ -0,0 +1,52 @@ +{% comment %} +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 © 2018 Hugo Levy-Falk + +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. +{% endcomment %} +{% load i18n %} +{% load acl %} +{% load logs_extra %} + + + + + + + + + + + {% for mandate in mandate_list %} + + + + + + + {% endfor %} +
{% trans "Start date" %}{% trans "End date" %}{% trans "President" %}
{{mandate.start_date|date:"d/m/Y"}}{% if mandate.end_date %}{{mandate.end_date|date:"d/m/Y"}}{% else %}{% trans "In progress." %}{% endif %}{{mandate.president.name}} {{mandate.president.surname}} + {% can_edit mandate%} + {% include 'buttons/edit.html' with href='preferences:edit-mandate' id=mandate.id %} + {% acl_end %} + {% can_delete mandate %} + {% include 'buttons/suppr.html' with href='preferences:del-mandate' id=mandate.id %} + {% acl_end %} + {% history_button mandate %} +
+ diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 0d2b3a6e..a94c2c11 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -330,6 +330,13 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ assooptions.pres_name }} +
{% trans "Mandates" %}
+ {% can_create Mandate %} + + {% trans "Add a mandate" %} + + {% acl_end %} + {% include 'preferences/aff_mandate.html' with mandate_list=mandate_list %}
diff --git a/preferences/urls.py b/preferences/urls.py index 656689ba..a03d7412 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -126,6 +126,21 @@ urlpatterns = [ views.del_document_template, name='del-document-template' ), + url( + r'^add_mandate/$', + views.add_mandate, + name='add-mandate' + ), + url( + r'^edit_mandate/(?P[0-9]+)$', + views.edit_mandate, + name='edit-mandate' + ), + url( + r'^del_mandate/(?P[0-9]+)$', + views.del_mandate, + name='del-mandate' + ), url(r'^add_radiusattribute/$', views.add_radiusattribute, name='add-radiusattribute'), url( r'^edit_radiusattribute/(?P[0-9]+)$', diff --git a/preferences/views.py b/preferences/views.py index 065ea6cf..9a5da84d 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -54,7 +54,8 @@ from .forms import ( DocumentTemplateForm, DelDocumentTemplateForm, RadiusAttributeForm, - DelRadiusAttributeForm + DelRadiusAttributeForm, + MandateForm ) from .models import ( Service, @@ -72,7 +73,8 @@ from .models import ( RadiusOption, CotisationsOption, DocumentTemplate, - RadiusAttribute + RadiusAttribute, + Mandate ) from . import models from . import forms @@ -89,6 +91,7 @@ def display_options(request): topologieoptions, _created = OptionalTopologie.objects.get_or_create() generaloptions, _created = GeneralOption.objects.get_or_create() assooptions, _created = AssoOption.objects.get_or_create() + mandate_list = Mandate.objects.order_by('start_date') homeoptions, _created = HomeOption.objects.get_or_create() mailmessageoptions, _created = MailMessageOption.objects.get_or_create() service_list = Service.objects.all() @@ -110,6 +113,7 @@ def display_options(request): 'topologieoptions': topologieoptions, 'generaloptions': generaloptions, 'assooptions': assooptions, + 'mandate_list': mandate_list, 'homeoptions': homeoptions, 'mailmessageoptions': mailmessageoptions, 'service_list': service_list, @@ -558,3 +562,54 @@ def del_radiusattribute(request, radiusattribute_instance, **_kwargs): ) +@login_required +@can_create(Mandate) +def add_mandate(request): + """Create a mandate.""" + mandate = MandateForm(request.POST or None) + if mandate.is_valid(): + mandate.save() + messages.success(request, _("The mandate was added.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': mandate, 'action_name': _("Add a mandate")}, + 'preferences/preferences.html', + request + ) + + +@login_required +@can_edit(Mandate) +def edit_mandate(request, mandate_instance, **_kwargs): + """Edit a mandate.""" + mandate = MandateForm( + request.POST or None, + instance=mandate_instance + ) + if mandate.is_valid(): + mandate.save() + messages.success(request, _("The mandate was edited.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': mandate, 'action_name': _("Edit")}, + 'preferences/preferences.html', + request + ) + +@login_required +@can_delete(Mandate) +def del_mandate(request, mandate_instance, **_kwargs): + """Delete a mandate.""" + if request.method == "POST": + mandate_instance.delete() + messages.success(request, _("The mandate was deleted.")) + return redirect(reverse('preferences:display-options')) + return form( + {'objet': mandate_instance, 'objet_name': 'attribute'}, + 'preferences/delete.html', + request + ) + + + +