From b81f18686601c575200ff80f17a29f515de5c6d5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 23 Apr 2020 18:28:16 +0200 Subject: [PATCH] Add PDF member lists --- apps/member/models.py | 1 + apps/permission/backends.py | 24 ++-- apps/permission/fixtures/initial.json | 52 +++++++- apps/registration/views.py | 1 + apps/treasury/views.py | 2 +- apps/wei/models.py | 1 + apps/wei/tables.py | 25 +++- apps/wei/urls.py | 7 +- apps/wei/views.py | 92 +++++++++++++- locale/de/LC_MESSAGES/django.po | 165 +++++++++++++------------ locale/fr/LC_MESSAGES/django.po | 168 ++++++++++++++------------ templates/wei/bus_tables.html | 6 + templates/wei/busteam_tables.html | 6 + templates/wei/weilist_sample.tex | 37 ++++++ templates/wei/weimembership_list.html | 6 + 15 files changed, 427 insertions(+), 166 deletions(-) create mode 100644 templates/wei/weilist_sample.tex diff --git a/apps/member/models.py b/apps/member/models.py index d2435fed..016542b3 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -273,6 +273,7 @@ class Membership(models.Model): user = models.ForeignKey( User, on_delete=models.PROTECT, + related_name="memberships", verbose_name=_("user"), ) diff --git a/apps/permission/backends.py b/apps/permission/backends.py index d3397d2a..3dd47fa7 100644 --- a/apps/permission/backends.py +++ b/apps/permission/backends.py @@ -36,13 +36,15 @@ class PermissionBackend(ModelBackend): # Unauthenticated users have no permissions return Permission.objects.none() - return Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \ - .filter( - rolepermissions__role__membership__user=user, - rolepermissions__role__membership__date_start__lte=datetime.date.today(), - rolepermissions__role__membership__date_end__gte=datetime.date.today(), - type=t, - mask__rank__lte=get_current_session().get("permission_mask", 0), + return Permission.objects.annotate( + club=F("rolepermissions__role__membership__club"), + membership=F("rolepermissions__role__membership"), + ).filter( + rolepermissions__role__membership__user=user, + rolepermissions__role__membership__date_start__lte=datetime.date.today(), + rolepermissions__role__membership__date_end__gte=datetime.date.today(), + type=t, + mask__rank__lte=get_current_session().get("permission_mask", 0), ).distinct() @staticmethod @@ -55,6 +57,7 @@ class PermissionBackend(ModelBackend): :return: A generator of the requested permissions """ clubs = {} + memberships = {} for permission in PermissionBackend.get_raw_permissions(user, type): if not isinstance(model.model_class()(), permission.model.model_class()) or not permission.club: @@ -64,9 +67,16 @@ class PermissionBackend(ModelBackend): clubs[permission.club] = club = Club.objects.get(pk=permission.club) else: club = clubs[permission.club] + + if permission.membership not in memberships: + memberships[permission.membership] = membership = Membership.objects.get(pk=permission.membership) + else: + membership = memberships[permission.membership] + permission = permission.about( user=user, club=club, + membership=membership, User=User, Club=Club, Membership=Membership, diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index a0a24b8a..7e7709e3 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -1470,7 +1470,7 @@ "wei", "weiregistration" ], - "query": "{\"user\": [\"user\"], \"wei\": [\"club\"], \"wei__membership_start__lte\": [\"today\"], \"wei__year\": [\"today\", \"year\"]}", + "query": "{\"user\": [\"user\"], \"wei\": [\"club\"], \"wei__membership_start__lte\": [\"today\"]}", "type": "view", "mask": 1, "field": "", @@ -1882,6 +1882,36 @@ "description": "View my own WEI membership if I am an old member or if the WEI is past" } }, + { + "model": "permission.permission", + "pk": 115, + "fields": { + "model": [ + "wei", + "weimembership" + ], + "query": "{\"wei\": [\"club\"], \"bus\": [\"membership\", \"weimembership\", \"bus\"]}", + "type": "view", + "mask": 1, + "field": "", + "description": "View the members of the bus" + } + }, + { + "model": "permission.permission", + "pk": 116, + "fields": { + "model": [ + "wei", + "weimembership" + ], + "query": "{\"wei\": [\"club\"], \"team\": [\"membership\", \"weimembership\", \"team\"]}", + "type": "view", + "mask": 1, + "field": "", + "description": "View the members of the team" + } + }, { "model": "permission.rolepermissions", "pk": 1, @@ -2230,5 +2260,25 @@ 113 ] } + }, + { + "model": "permission.rolepermissions", + "pk": 13, + "fields": { + "role": 13, + "permissions": [ + 115 + ] + } + }, + { + "model": "permission.rolepermissions", + "pk": 14, + "fields": { + "role": 14, + "permissions": [ + 116 + ] + } } ] \ No newline at end of file diff --git a/apps/registration/views.py b/apps/registration/views.py index 86fb9d82..2c91a604 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -38,6 +38,7 @@ class UserCreateView(CreateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["profile_form"] = self.second_form() + del context["profile_form"].fields["section"] return context diff --git a/apps/treasury/views.py b/apps/treasury/views.py index badcb6cc..f42e5e77 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -182,7 +182,7 @@ class InvoiceRenderView(LoginRequiredMixin, View): # Display the generated pdf as a HTTP Response pdf = open("{}/invoice-{}.pdf".format(tmp_dir, pk), 'rb').read() response = HttpResponse(pdf, content_type="application/pdf") - response['Content-Disposition'] = "inline;filename=invoice-{:d}.pdf".format(pk) + response['Content-Disposition'] = "inline;filename=Facture%20n°{:d}.pdf".format(pk) except IOError as e: raise e finally: diff --git a/apps/wei/models.py b/apps/wei/models.py index 9481fb09..3b41fdd0 100644 --- a/apps/wei/models.py +++ b/apps/wei/models.py @@ -265,6 +265,7 @@ class WEIMembership(Membership): bus = models.ForeignKey( Bus, on_delete=models.PROTECT, + related_name="memberships", null=True, default=None, verbose_name=_("bus"), diff --git a/apps/wei/tables.py b/apps/wei/tables.py index 17f16ea1..36d09342 100644 --- a/apps/wei/tables.py +++ b/apps/wei/tables.py @@ -91,6 +91,11 @@ class WEIMembershipTable(tables.Table): args=[A('registration.pk')], ) + year = tables.Column( + accessor=A("pk"), + verbose_name=_("Year"), + ) + bus = tables.LinkColumn( 'wei:manage_bus', args=[A('bus.pk')], @@ -101,13 +106,17 @@ class WEIMembershipTable(tables.Table): args=[A('bus.pk')], ) + def render_year(self, record): + return str(record.user.profile.ens_year) + "A" + class Meta: attrs = { 'class': 'table table-condensed table-striped table-hover' } model = WEIMembership template_name = 'django_tables2/bootstrap4.html' - fields = ('user', 'user.first_name', 'user.last_name', 'bus', 'team', ) + fields = ('user', 'user.last_name', 'user.first_name', 'registration.gender', 'user.profile.department', + 'year', 'bus', 'team', ) row_attrs = { 'class': 'table-row', 'id': lambda record: "row-" + str(record.pk), @@ -130,9 +139,16 @@ class BusTable(tables.Table): } ) + count = tables.Column( + verbose_name=_("Members count"), + ) + def render_teams(self, value): return ", ".join(team.name for team in value.all()) + def render_count(self, value): + return str(value) + " " + (str(_("members")) if value > 0 else str(_("member"))) + class Meta: attrs = { 'class': 'table table-condensed table-striped table-hover' @@ -161,6 +177,13 @@ class BusTeamTable(tables.Table): } ) + def render_count(self, value): + return str(value) + " " + (str(_("members")) if value > 0 else str(_("member"))) + + count = tables.Column( + verbose_name=_("Members count"), + ) + def render_color(self, value): return "#{:06X}".format(value) diff --git a/apps/wei/urls.py b/apps/wei/urls.py index 39af30e0..7cf91a60 100644 --- a/apps/wei/urls.py +++ b/apps/wei/urls.py @@ -4,7 +4,7 @@ from django.urls import path from .views import CurrentWEIDetailView, WEIListView, WEICreateView, WEIDetailView, WEIUpdateView,\ - WEIRegistrationsView, WEIMembershipsView,\ + WEIRegistrationsView, WEIMembershipsView, MemberListRenderView,\ BusCreateView, BusManageView, BusUpdateView, BusTeamCreateView, BusTeamManageView, BusTeamUpdateView,\ WEIRegister1AView, WEIRegister2AView, WEIUpdateRegistrationView, WEIDeleteRegistrationView,\ WEIValidateRegistrationView, WEISurveyView, WEISurveyEndView, WEIClosedView @@ -19,6 +19,11 @@ urlpatterns = [ path('update//', WEIUpdateView.as_view(), name="wei_update"), path('detail//registrations/', WEIRegistrationsView.as_view(), name="wei_registrations"), path('detail//memberships/', WEIMembershipsView.as_view(), name="wei_memberships"), + path('detail//memberships/pdf/', MemberListRenderView.as_view(), name="wei_memberships_pdf"), + path('detail//memberships/pdf//', MemberListRenderView.as_view(), + name="wei_memberships_bus_pdf"), + path('detail//memberships/pdf///', MemberListRenderView.as_view(), + name="wei_memberships_team_pdf"), path('add-bus//', BusCreateView.as_view(), name="add_bus"), path('manage-bus//', BusManageView.as_view(), name="manage_bus"), path('update-bus//', BusUpdateView.as_view(), name="update_bus"), diff --git a/apps/wei/views.py b/apps/wei/views.py index d9753004..93edb491 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -1,15 +1,23 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +import os +import shutil +import subprocess from datetime import datetime, date +from tempfile import mkdtemp from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied -from django.db.models import Q +from django.db.models import Q, Count +from django.db.models.functions import Lower from django.forms import HiddenInput +from django.http import HttpResponse from django.shortcuts import redirect +from django.template.loader import render_to_string from django.urls import reverse_lazy +from django.views import View from django.views.generic import DetailView, UpdateView, CreateView, RedirectView, TemplateView from django.utils.translation import gettext_lazy as _ from django.views.generic.edit import BaseFormView, DeleteView @@ -17,6 +25,7 @@ from django_tables2 import SingleTableView from member.models import Membership, Club from note.models import Transaction, NoteClub, Alias from note.tables import HistoryTable +from note_kfet.settings import BASE_DIR from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin @@ -108,7 +117,7 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): context["my_registration"] = my_registration buses = Bus.objects.filter(PermissionBackend.filter_queryset(self.request.user, Bus, "view"))\ - .filter(wei=self.object) + .filter(wei=self.object).annotate(count=Count("memberships")) bus_table = BusTable(data=buses, prefix="bus-") context['buses'] = bus_table @@ -299,7 +308,7 @@ class BusManageView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): bus = self.object teams = BusTeam.objects.filter(PermissionBackend.filter_queryset(self.request.user, BusTeam, "view"))\ - .filter(bus=bus) + .filter(bus=bus).annotate(count=Count("memberships")) teams_table = BusTeamTable(data=teams, prefix="team-") context["teams"] = teams_table @@ -824,3 +833,80 @@ class WEIClosedView(LoginRequiredMixin, TemplateView): context["club"] = WEIClub.objects.get(pk=self.kwargs["pk"]) context["title"] = _("Survey WEI") return context + + +class MemberListRenderView(LoginRequiredMixin, View): + """ + Render Invoice as a generated PDF with the given information and a LaTeX template + """ + + def get_queryset(self, **kwargs): + qs = WEIMembership.objects.filter(PermissionBackend.filter_queryset(self.request.user, WEIMembership, "view")) + qs = qs.filter(club__pk=self.kwargs["wei_pk"]).order_by( + Lower('bus__name'), + Lower('team__name'), + 'roles', + Lower('user__last_name'), + Lower('user__first_name'), + ).distinct() + + if "bus_pk" in self.kwargs: + qs = qs.filter(bus__pk=self.kwargs["bus_pk"]) + + if "team_pk" in self.kwargs: + qs = qs.filter(team__pk=self.kwargs["team_pk"] if self.kwargs["team_pk"] else None) + + return qs + + def get(self, request, **kwargs): + qs = self.get_queryset() + + wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"]) + bus = team = None + if "bus_pk" in self.kwargs: + bus = Bus.objects.get(pk=self.kwargs["bus_pk"]) + if "team_pk" in self.kwargs: + team = BusTeam.objects.filter(pk=self.kwargs["team_pk"] if self.kwargs["team_pk"] else None) + if team.exists(): + team = team.get() + bus = team.bus + else: + team = dict(name="Staff") + + # Fill the template with the information + tex = render_to_string("wei/weilist_sample.tex", dict(memberships=qs.all(), wei=wei, bus=bus, team=team)) + + try: + os.mkdir(BASE_DIR + "/tmp") + except FileExistsError: + pass + # We render the file in a temporary directory + tmp_dir = mkdtemp(prefix=BASE_DIR + "/tmp/") + + try: + with open("{}/wei-list.tex".format(tmp_dir), "wb") as f: + f.write(tex.encode("UTF-8")) + del tex + + error = subprocess.Popen( + ["pdflatex", "{}/wei-list.tex".format(tmp_dir)], + cwd=tmp_dir, + stdin=open(os.devnull, "r"), + stderr=open(os.devnull, "wb"), + stdout=open(os.devnull, "wb"), + ).wait() + + if error: + raise IOError("An error attempted while generating a WEI list (code=" + str(error) + ")") + + # Display the generated pdf as a HTTP Response + pdf = open("{}/wei-list.pdf".format(tmp_dir), 'rb').read() + response = HttpResponse(pdf, content_type="application/pdf") + response['Content-Disposition'] = "inline;filename=Liste%20des%20participants%20au%20WEI.pdf" + except IOError as e: + raise e + finally: + # Delete all temporary files + shutil.rmtree(tmp_dir) + + return response diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index a588f1ec..5e7ae0c0 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-22 17:25+0200\n" +"POT-Creation-Date: 2020-04-23 18:21+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,7 +44,7 @@ msgid "You can't invite more than 3 people to this activity." msgstr "" #: apps/activity/models.py:23 apps/activity/models.py:48 -#: apps/member/models.py:152 apps/member/models.py:256 +#: apps/member/models.py:151 apps/member/models.py:255 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:25 #: apps/note/models/transactions.py:45 apps/note/models/transactions.py:250 #: apps/wei/models.py:62 templates/member/club_info.html:13 @@ -308,192 +308,192 @@ msgstr "" msgid "Bank" msgstr "" -#: apps/member/models.py:35 +#: apps/member/models.py:34 #: templates/registration/future_profile_detail.html:47 #: templates/wei/weimembership_form.html:48 msgid "phone number" msgstr "" -#: apps/member/models.py:42 templates/member/profile_info.html:27 +#: apps/member/models.py:41 templates/member/profile_info.html:27 #: templates/registration/future_profile_detail.html:41 #: templates/wei/weimembership_form.html:42 msgid "section" msgstr "" -#: apps/member/models.py:43 +#: apps/member/models.py:42 msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" msgstr "" -#: apps/member/models.py:51 templates/wei/weimembership_form.html:36 +#: apps/member/models.py:50 templates/wei/weimembership_form.html:36 msgid "department" msgstr "" -#: apps/member/models.py:53 +#: apps/member/models.py:52 msgid "Informatics (A0)" msgstr "" -#: apps/member/models.py:54 +#: apps/member/models.py:53 msgid "Mathematics (A1)" msgstr "" -#: apps/member/models.py:55 +#: apps/member/models.py:54 msgid "Physics (A2)" msgstr "" -#: apps/member/models.py:56 +#: apps/member/models.py:55 msgid "Applied physics (A'2)" msgstr "" -#: apps/member/models.py:57 +#: apps/member/models.py:56 msgid "Chemistry (A''2)" msgstr "" -#: apps/member/models.py:58 +#: apps/member/models.py:57 msgid "Biology (A3)" msgstr "" -#: apps/member/models.py:59 +#: apps/member/models.py:58 msgid "SAPHIRE (B1234)" msgstr "" -#: apps/member/models.py:60 +#: apps/member/models.py:59 msgid "Mechanics (B1)" msgstr "" -#: apps/member/models.py:61 +#: apps/member/models.py:60 msgid "Civil engineering (B2)" msgstr "" -#: apps/member/models.py:62 +#: apps/member/models.py:61 msgid "Mechanical engineering (B3)" msgstr "" -#: apps/member/models.py:63 +#: apps/member/models.py:62 msgid "EEA (B4)" msgstr "" -#: apps/member/models.py:64 +#: apps/member/models.py:63 msgid "Design (C)" msgstr "" -#: apps/member/models.py:65 +#: apps/member/models.py:64 msgid "Economy-management (D2)" msgstr "" -#: apps/member/models.py:66 +#: apps/member/models.py:65 msgid "Social sciences (D3)" msgstr "" -#: apps/member/models.py:67 +#: apps/member/models.py:66 msgid "English (E)" msgstr "" -#: apps/member/models.py:68 +#: apps/member/models.py:67 msgid "External (EXT)" msgstr "" -#: apps/member/models.py:75 +#: apps/member/models.py:74 msgid "promotion" msgstr "" -#: apps/member/models.py:76 +#: apps/member/models.py:75 msgid "Year of entry to the school (None if not ENS student)" msgstr "" -#: apps/member/models.py:80 templates/member/profile_info.html:30 +#: apps/member/models.py:79 templates/member/profile_info.html:30 #: templates/registration/future_profile_detail.html:44 #: templates/wei/weimembership_form.html:45 msgid "address" msgstr "" -#: apps/member/models.py:87 +#: apps/member/models.py:86 #: templates/registration/future_profile_detail.html:50 #: templates/wei/weimembership_form.html:51 msgid "paid" msgstr "" -#: apps/member/models.py:88 +#: apps/member/models.py:87 msgid "Tells if the user receive a salary." msgstr "" -#: apps/member/models.py:93 +#: apps/member/models.py:92 msgid "email confirmed" msgstr "" -#: apps/member/models.py:98 +#: apps/member/models.py:97 msgid "registration valid" msgstr "" -#: apps/member/models.py:127 apps/member/models.py:128 +#: apps/member/models.py:126 apps/member/models.py:127 msgid "user profile" msgstr "" -#: apps/member/models.py:157 templates/member/club_info.html:57 +#: apps/member/models.py:156 templates/member/club_info.html:57 #: templates/registration/future_profile_detail.html:22 #: templates/wei/weiclub_info.html:52 templates/wei/weimembership_form.html:24 msgid "email" msgstr "" -#: apps/member/models.py:164 +#: apps/member/models.py:163 msgid "parent club" msgstr "" -#: apps/member/models.py:173 +#: apps/member/models.py:172 msgid "require memberships" msgstr "" -#: apps/member/models.py:174 +#: apps/member/models.py:173 msgid "Uncheck if this club don't require memberships." msgstr "" -#: apps/member/models.py:179 templates/member/club_info.html:41 +#: apps/member/models.py:178 templates/member/club_info.html:41 msgid "membership fee (paid students)" msgstr "" -#: apps/member/models.py:184 templates/member/club_info.html:44 +#: apps/member/models.py:183 templates/member/club_info.html:44 msgid "membership fee (unpaid students)" msgstr "" -#: apps/member/models.py:190 templates/member/club_info.html:33 +#: apps/member/models.py:189 templates/member/club_info.html:33 msgid "membership duration" msgstr "" -#: apps/member/models.py:191 +#: apps/member/models.py:190 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "" -#: apps/member/models.py:198 templates/member/club_info.html:23 +#: apps/member/models.py:197 templates/member/club_info.html:23 msgid "membership start" msgstr "" -#: apps/member/models.py:199 +#: apps/member/models.py:198 msgid "How long after January 1st the members can renew their membership." msgstr "" -#: apps/member/models.py:206 templates/member/club_info.html:28 +#: apps/member/models.py:205 templates/member/club_info.html:28 msgid "membership end" msgstr "" -#: apps/member/models.py:207 +#: apps/member/models.py:206 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." msgstr "" -#: apps/member/models.py:241 apps/member/models.py:283 +#: apps/member/models.py:240 apps/member/models.py:283 #: apps/note/models/notes.py:139 msgid "club" msgstr "" -#: apps/member/models.py:242 +#: apps/member/models.py:241 msgid "clubs" msgstr "" -#: apps/member/models.py:262 apps/permission/models.py:312 +#: apps/member/models.py:261 apps/permission/models.py:312 msgid "role" msgstr "" -#: apps/member/models.py:263 apps/member/models.py:288 +#: apps/member/models.py:262 apps/member/models.py:288 msgid "roles" msgstr "" @@ -509,7 +509,7 @@ msgstr "" msgid "fee" msgstr "" -#: apps/member/models.py:320 apps/member/views.py:505 apps/wei/views.py:731 +#: apps/member/models.py:320 apps/member/views.py:505 apps/wei/views.py:738 msgid "User is not a member of the parent club" msgstr "" @@ -552,7 +552,7 @@ msgstr "" msgid "Search user" msgstr "" -#: apps/member/views.py:500 apps/wei/views.py:722 +#: apps/member/views.py:500 apps/wei/views.py:729 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -567,8 +567,8 @@ msgid "The membership must begin before {:%m-%d-%Y}." msgstr "" #: apps/member/views.py:540 apps/member/views.py:542 apps/member/views.py:544 -#: apps/registration/views.py:288 apps/registration/views.py:290 -#: apps/registration/views.py:292 +#: apps/registration/views.py:289 apps/registration/views.py:291 +#: apps/registration/views.py:293 msgid "This field is required." msgstr "" @@ -890,31 +890,31 @@ msgstr "" msgid "Join Kfet Club" msgstr "" -#: apps/registration/views.py:77 +#: apps/registration/views.py:78 msgid "Email validation" msgstr "" -#: apps/registration/views.py:123 +#: apps/registration/views.py:124 msgid "Email validation unsuccessful" msgstr "" -#: apps/registration/views.py:134 +#: apps/registration/views.py:135 msgid "Email validation email sent" msgstr "" -#: apps/registration/views.py:187 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "" -#: apps/registration/views.py:254 +#: apps/registration/views.py:255 msgid "You must join the BDE." msgstr "" -#: apps/registration/views.py:276 +#: apps/registration/views.py:277 msgid "You must join BDE club before joining Kfet club." msgstr "" -#: apps/registration/views.py:281 +#: apps/registration/views.py:282 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" @@ -1121,7 +1121,7 @@ msgid "WEI" msgstr "" #: apps/wei/forms/registration.py:47 apps/wei/models.py:109 -#: apps/wei/models.py:270 +#: apps/wei/models.py:271 msgid "bus" msgstr "" @@ -1154,10 +1154,6 @@ msgstr "" msgid "This team doesn't belong to the given bus." msgstr "" -#: apps/wei/management/commands/wei_algorithm.py:11 -msgid "Attribute to each first year member a bus for the WEI" -msgstr "" - #: apps/wei/models.py:20 templates/wei/weiclub_info.html:23 msgid "year" msgstr "" @@ -1290,19 +1286,19 @@ msgstr "" msgid "WEI Users" msgstr "" -#: apps/wei/models.py:280 +#: apps/wei/models.py:281 msgid "team" msgstr "" -#: apps/wei/models.py:290 +#: apps/wei/models.py:291 msgid "WEI registration" msgstr "" -#: apps/wei/models.py:294 +#: apps/wei/models.py:295 msgid "WEI membership" msgstr "" -#: apps/wei/models.py:295 +#: apps/wei/models.py:296 msgid "WEI memberships" msgstr "" @@ -1311,46 +1307,58 @@ msgstr "" msgid "Validate" msgstr "" -#: apps/wei/tables.py:125 templates/wei/bus_tables.html:26 +#: apps/wei/tables.py:96 +msgid "Year" +msgstr "" + +#: apps/wei/tables.py:134 templates/wei/bus_tables.html:26 #: templates/wei/busteam_tables.html:43 msgid "Teams" msgstr "" -#: apps/wei/views.py:170 +#: apps/wei/tables.py:143 apps/wei/tables.py:185 +msgid "Members count" +msgstr "" + +#: apps/wei/tables.py:150 apps/wei/tables.py:151 apps/wei/tables.py:182 +msgid "members" +msgstr "" + +#: apps/wei/views.py:177 msgid "Find WEI Membership" msgstr "" -#: apps/wei/views.py:205 +#: apps/wei/views.py:212 msgid "Find WEI Registration" msgstr "" -#: apps/wei/views.py:414 templates/wei/weiclub_info.html:62 +#: apps/wei/views.py:421 templates/wei/weiclub_info.html:62 msgid "Register 1A" msgstr "" -#: apps/wei/views.py:435 apps/wei/views.py:503 +#: apps/wei/views.py:442 apps/wei/views.py:510 msgid "This user is already registered to this WEI." msgstr "" -#: apps/wei/views.py:440 +#: apps/wei/views.py:447 msgid "" "This user can't be in her/his first year since he/she has already participed " "to a WEI." msgstr "" -#: apps/wei/views.py:468 templates/wei/weiclub_info.html:63 +#: apps/wei/views.py:475 templates/wei/weiclub_info.html:63 msgid "Register 2A+" msgstr "" -#: apps/wei/views.py:486 apps/wei/views.py:569 +#: apps/wei/views.py:493 apps/wei/views.py:576 msgid "You already opened an account in the Société générale." msgstr "" -#: apps/wei/views.py:726 +#: apps/wei/views.py:733 msgid "This user didn't give her/his caution check." msgstr "" -#: apps/wei/views.py:795 apps/wei/views.py:815 apps/wei/views.py:825 +#: apps/wei/views.py:802 apps/wei/views.py:822 apps/wei/views.py:832 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -2010,6 +2018,11 @@ msgstr "" msgid "Members" msgstr "" +#: templates/wei/bus_tables.html:48 templates/wei/busteam_tables.html:52 +#: templates/wei/weimembership_list.html:30 +msgid "View as PDF" +msgstr "" + #: templates/wei/survey.html:24 msgid "Next" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 8e3e2ec4..68d05045 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-22 17:25+0200\n" +"POT-Creation-Date: 2020-04-23 18:21+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -40,7 +40,7 @@ msgid "You can't invite more than 3 people to this activity." msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." #: apps/activity/models.py:23 apps/activity/models.py:48 -#: apps/member/models.py:152 apps/member/models.py:256 +#: apps/member/models.py:151 apps/member/models.py:255 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:25 #: apps/note/models/transactions.py:45 apps/note/models/transactions.py:250 #: apps/wei/models.py:62 templates/member/club_info.html:13 @@ -304,175 +304,175 @@ msgstr "Montant à créditer" msgid "Bank" msgstr "Banque" -#: apps/member/models.py:35 +#: apps/member/models.py:34 #: templates/registration/future_profile_detail.html:47 #: templates/wei/weimembership_form.html:48 msgid "phone number" msgstr "numéro de téléphone" -#: apps/member/models.py:42 templates/member/profile_info.html:27 +#: apps/member/models.py:41 templates/member/profile_info.html:27 #: templates/registration/future_profile_detail.html:41 #: templates/wei/weimembership_form.html:42 msgid "section" msgstr "section" -#: apps/member/models.py:43 +#: apps/member/models.py:42 msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" -#: apps/member/models.py:51 templates/wei/weimembership_form.html:36 +#: apps/member/models.py:50 templates/wei/weimembership_form.html:36 msgid "department" msgstr "département" -#: apps/member/models.py:53 +#: apps/member/models.py:52 msgid "Informatics (A0)" msgstr "Informatique (A0)" -#: apps/member/models.py:54 +#: apps/member/models.py:53 msgid "Mathematics (A1)" msgstr "Mathématiques (A1)" -#: apps/member/models.py:55 +#: apps/member/models.py:54 msgid "Physics (A2)" msgstr "Physique (A2)" -#: apps/member/models.py:56 +#: apps/member/models.py:55 msgid "Applied physics (A'2)" msgstr "Physique appliquée (A'2)" -#: apps/member/models.py:57 +#: apps/member/models.py:56 msgid "Chemistry (A''2)" msgstr "Chimie (A''2)" -#: apps/member/models.py:58 +#: apps/member/models.py:57 msgid "Biology (A3)" msgstr "Biologie (A3)" -#: apps/member/models.py:59 +#: apps/member/models.py:58 msgid "SAPHIRE (B1234)" msgstr "SAPHIRE (B1234)" -#: apps/member/models.py:60 +#: apps/member/models.py:59 msgid "Mechanics (B1)" msgstr "Mécanique (B1)" -#: apps/member/models.py:61 +#: apps/member/models.py:60 msgid "Civil engineering (B2)" msgstr "Génie civil (B2)" -#: apps/member/models.py:62 +#: apps/member/models.py:61 msgid "Mechanical engineering (B3)" msgstr "Génie mécanique (B3)" -#: apps/member/models.py:63 +#: apps/member/models.py:62 msgid "EEA (B4)" msgstr "EEA (B4)" -#: apps/member/models.py:64 +#: apps/member/models.py:63 msgid "Design (C)" msgstr "Design (C)" -#: apps/member/models.py:65 +#: apps/member/models.py:64 msgid "Economy-management (D2)" msgstr "Économie-gestion (D2)" -#: apps/member/models.py:66 +#: apps/member/models.py:65 msgid "Social sciences (D3)" msgstr "Sciences sociales (D3)" -#: apps/member/models.py:67 +#: apps/member/models.py:66 msgid "English (E)" msgstr "Anglais (E)" -#: apps/member/models.py:68 +#: apps/member/models.py:67 msgid "External (EXT)" msgstr "Externe (EXT)" -#: apps/member/models.py:75 +#: apps/member/models.py:74 msgid "promotion" msgstr "promotion" -#: apps/member/models.py:76 +#: apps/member/models.py:75 msgid "Year of entry to the school (None if not ENS student)" msgstr "Année d'entrée dans l'école (None si non-étudiant·e de l'ENS)" -#: apps/member/models.py:80 templates/member/profile_info.html:30 +#: apps/member/models.py:79 templates/member/profile_info.html:30 #: templates/registration/future_profile_detail.html:44 #: templates/wei/weimembership_form.html:45 msgid "address" msgstr "adresse" -#: apps/member/models.py:87 +#: apps/member/models.py:86 #: templates/registration/future_profile_detail.html:50 #: templates/wei/weimembership_form.html:51 msgid "paid" msgstr "payé" -#: apps/member/models.py:88 +#: apps/member/models.py:87 msgid "Tells if the user receive a salary." msgstr "Indique si l'utilisateur perçoit un salaire." -#: apps/member/models.py:93 +#: apps/member/models.py:92 msgid "email confirmed" msgstr "adresse email confirmée" -#: apps/member/models.py:98 +#: apps/member/models.py:97 msgid "registration valid" msgstr "inscription valid" -#: apps/member/models.py:127 apps/member/models.py:128 +#: apps/member/models.py:126 apps/member/models.py:127 msgid "user profile" msgstr "profil utilisateur" -#: apps/member/models.py:157 templates/member/club_info.html:57 +#: apps/member/models.py:156 templates/member/club_info.html:57 #: templates/registration/future_profile_detail.html:22 #: templates/wei/weiclub_info.html:52 templates/wei/weimembership_form.html:24 msgid "email" msgstr "courriel" -#: apps/member/models.py:164 +#: apps/member/models.py:163 msgid "parent club" msgstr "club parent" -#: apps/member/models.py:173 +#: apps/member/models.py:172 msgid "require memberships" msgstr "nécessite des adhésions" -#: apps/member/models.py:174 +#: apps/member/models.py:173 msgid "Uncheck if this club don't require memberships." msgstr "Décochez si ce club n'utilise pas d'adhésions." -#: apps/member/models.py:179 templates/member/club_info.html:41 +#: apps/member/models.py:178 templates/member/club_info.html:41 msgid "membership fee (paid students)" msgstr "cotisation pour adhérer (normalien élève)" -#: apps/member/models.py:184 templates/member/club_info.html:44 +#: apps/member/models.py:183 templates/member/club_info.html:44 msgid "membership fee (unpaid students)" msgstr "cotisation pour adhérer (normalien étudiant)" -#: apps/member/models.py:190 templates/member/club_info.html:33 +#: apps/member/models.py:189 templates/member/club_info.html:33 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:191 +#: apps/member/models.py:190 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "La durée maximale (en jours) d'une adhésion (NULL = infinie)." -#: apps/member/models.py:198 templates/member/club_info.html:23 +#: apps/member/models.py:197 templates/member/club_info.html:23 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:199 +#: apps/member/models.py:198 msgid "How long after January 1st the members can renew their membership." msgstr "" "Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur " "adhésion." -#: apps/member/models.py:206 templates/member/club_info.html:28 +#: apps/member/models.py:205 templates/member/club_info.html:28 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:207 +#: apps/member/models.py:206 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." @@ -480,20 +480,20 @@ msgstr "" "Combien de temps l'adhésion peut durer après le 1er Janvier de l'année " "suivante avant que les adhérents peuvent renouveler leur adhésion." -#: apps/member/models.py:241 apps/member/models.py:283 +#: apps/member/models.py:240 apps/member/models.py:283 #: apps/note/models/notes.py:139 msgid "club" msgstr "club" -#: apps/member/models.py:242 +#: apps/member/models.py:241 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:262 apps/permission/models.py:312 +#: apps/member/models.py:261 apps/permission/models.py:312 msgid "role" msgstr "rôle" -#: apps/member/models.py:263 apps/member/models.py:288 +#: apps/member/models.py:262 apps/member/models.py:288 msgid "roles" msgstr "rôles" @@ -509,7 +509,7 @@ msgstr "l'adhésion finit le" msgid "fee" msgstr "cotisation" -#: apps/member/models.py:320 apps/member/views.py:505 apps/wei/views.py:731 +#: apps/member/models.py:320 apps/member/views.py:505 apps/wei/views.py:738 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" @@ -552,7 +552,7 @@ msgstr "Un alias avec un nom similaire existe déjà." msgid "Search user" msgstr "Chercher un utilisateur" -#: apps/member/views.py:500 apps/wei/views.py:722 +#: apps/member/views.py:500 apps/wei/views.py:729 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -569,8 +569,8 @@ msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." #: apps/member/views.py:540 apps/member/views.py:542 apps/member/views.py:544 -#: apps/registration/views.py:288 apps/registration/views.py:290 -#: apps/registration/views.py:292 +#: apps/registration/views.py:289 apps/registration/views.py:291 +#: apps/registration/views.py:293 msgid "This field is required." msgstr "Ce champ est requis." @@ -896,31 +896,31 @@ msgstr "Adhérer au club BDE" msgid "Join Kfet Club" msgstr "Adhérer au club Kfet" -#: apps/registration/views.py:77 +#: apps/registration/views.py:78 msgid "Email validation" msgstr "Validation de l'adresse mail" -#: apps/registration/views.py:123 +#: apps/registration/views.py:124 msgid "Email validation unsuccessful" msgstr " La validation de l'adresse mail a échoué" -#: apps/registration/views.py:134 +#: apps/registration/views.py:135 msgid "Email validation email sent" msgstr "L'email de vérification de l'adresse email a bien été envoyé." -#: apps/registration/views.py:187 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "Utilisateurs en attente d'inscription" -#: apps/registration/views.py:254 +#: apps/registration/views.py:255 msgid "You must join the BDE." msgstr "Vous devez adhérer au BDE." -#: apps/registration/views.py:276 +#: apps/registration/views.py:277 msgid "You must join BDE club before joining Kfet club." msgstr "Vous devez adhérer au club BDE avant d'adhérer au club Kfet." -#: apps/registration/views.py:281 +#: apps/registration/views.py:282 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" @@ -1131,7 +1131,7 @@ msgid "WEI" msgstr "WEI" #: apps/wei/forms/registration.py:47 apps/wei/models.py:109 -#: apps/wei/models.py:270 +#: apps/wei/models.py:271 msgid "bus" msgstr "Bus" @@ -1169,10 +1169,6 @@ msgstr "Sélectionnez les rôles qui vous intéressent." msgid "This team doesn't belong to the given bus." msgstr "Cette équipe n'appartient pas à ce bus." -#: apps/wei/management/commands/wei_algorithm.py:11 -msgid "Attribute to each first year member a bus for the WEI" -msgstr "Attribuer à chaque première année un bus pour le WEI" - #: apps/wei/models.py:20 templates/wei/weiclub_info.html:23 msgid "year" msgstr "année" @@ -1315,19 +1311,19 @@ msgstr "Participant au WEI" msgid "WEI Users" msgstr "Participants au WEI" -#: apps/wei/models.py:280 +#: apps/wei/models.py:281 msgid "team" msgstr "équipe" -#: apps/wei/models.py:290 +#: apps/wei/models.py:291 msgid "WEI registration" msgstr "inscription au WEI" -#: apps/wei/models.py:294 +#: apps/wei/models.py:295 msgid "WEI membership" msgstr "adhésion au WEI" -#: apps/wei/models.py:295 +#: apps/wei/models.py:296 msgid "WEI memberships" msgstr "adhésions au WEI" @@ -1336,28 +1332,40 @@ msgstr "adhésions au WEI" msgid "Validate" msgstr "Valider" -#: apps/wei/tables.py:125 templates/wei/bus_tables.html:26 +#: apps/wei/tables.py:96 +msgid "Year" +msgstr "" + +#: apps/wei/tables.py:134 templates/wei/bus_tables.html:26 #: templates/wei/busteam_tables.html:43 msgid "Teams" msgstr "Équipes" -#: apps/wei/views.py:170 +#: apps/wei/tables.py:143 apps/wei/tables.py:185 +msgid "Members count" +msgstr "Nombre de membres" + +#: apps/wei/tables.py:150 apps/wei/tables.py:151 apps/wei/tables.py:182 +msgid "members" +msgstr "adhérents" + +#: apps/wei/views.py:177 msgid "Find WEI Membership" msgstr "Trouver une adhésion au WEI" -#: apps/wei/views.py:205 +#: apps/wei/views.py:212 msgid "Find WEI Registration" msgstr "Trouver une inscription au WEI" -#: apps/wei/views.py:414 templates/wei/weiclub_info.html:62 +#: apps/wei/views.py:421 templates/wei/weiclub_info.html:62 msgid "Register 1A" msgstr "Inscrire un 1A" -#: apps/wei/views.py:435 apps/wei/views.py:503 +#: apps/wei/views.py:442 apps/wei/views.py:510 msgid "This user is already registered to this WEI." msgstr "Cette personne est déjà inscrite au WEI." -#: apps/wei/views.py:440 +#: apps/wei/views.py:447 msgid "" "This user can't be in her/his first year since he/she has already participed " "to a WEI." @@ -1365,19 +1373,19 @@ msgstr "" "Cet utilisateur ne peut pas être en première année puisqu'iel a déjà " "participé à un WEI." -#: apps/wei/views.py:468 templates/wei/weiclub_info.html:63 +#: apps/wei/views.py:475 templates/wei/weiclub_info.html:63 msgid "Register 2A+" msgstr "Inscrire un 2A+" -#: apps/wei/views.py:486 apps/wei/views.py:569 +#: apps/wei/views.py:493 apps/wei/views.py:576 msgid "You already opened an account in the Société générale." msgstr "Vous avez déjà ouvert un compte auprès de la société générale." -#: apps/wei/views.py:726 +#: apps/wei/views.py:733 msgid "This user didn't give her/his caution check." msgstr "Cet utilisateur n'a pas donné son chèque de caution." -#: apps/wei/views.py:795 apps/wei/views.py:815 apps/wei/views.py:825 +#: apps/wei/views.py:802 apps/wei/views.py:822 apps/wei/views.py:832 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -2069,6 +2077,11 @@ msgstr "Ajouter une équipe" msgid "Members" msgstr "Membres" +#: templates/wei/bus_tables.html:48 templates/wei/busteam_tables.html:52 +#: templates/wei/weimembership_list.html:30 +msgid "View as PDF" +msgstr "Télécharger au format PDF" + #: templates/wei/survey.html:24 msgid "Next" msgstr "Suivant" @@ -2292,3 +2305,6 @@ msgstr "Il n'y a pas de pré-inscription en attente avec cette entrée." #: templates/wei/weiregistration_list.html:24 msgid "View validated memberships..." msgstr "Voir les adhésions validées ..." + +#~ msgid "Attribute to each first year member a bus for the WEI" +#~ msgstr "Attribuer à chaque première année un bus pour le WEI" diff --git a/templates/wei/bus_tables.html b/templates/wei/bus_tables.html index 63f8b56e..50eccf6a 100644 --- a/templates/wei/bus_tables.html +++ b/templates/wei/bus_tables.html @@ -41,4 +41,10 @@ {% render_table memberships %} + +
+ + + + {% endif %} diff --git a/templates/wei/busteam_tables.html b/templates/wei/busteam_tables.html index 2b4deacb..3135158f 100644 --- a/templates/wei/busteam_tables.html +++ b/templates/wei/busteam_tables.html @@ -45,4 +45,10 @@ {% render_table memberships %} + +
+ + + + {% endif %} diff --git a/templates/wei/weilist_sample.tex b/templates/wei/weilist_sample.tex new file mode 100644 index 00000000..f22659a4 --- /dev/null +++ b/templates/wei/weilist_sample.tex @@ -0,0 +1,37 @@ +\documentclass{article} + +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} + +\usepackage[margin=2cm]{geometry} +\usepackage{tabularx} + +\begin{document} +\begin{center} +\huge{Liste des inscrits \og {{ wei.name }} \fg{}} + +{% if bus %} +\LARGE{Bus {{ bus.name }}} + + +{% if team %} +\Large{Équipe {{ team.name }}} +{% endif %} +{% endif %} +\end{center} + +\begin{center} +\begin{tabularx}{\textwidth}{|c|c|c|c|c|c|c|X|} +\hline +\textbf{Nom} & \textbf{Prénom} & \textbf{Genre} & \textbf{Département} & \textbf{Année} & \textbf{Bus} & \textbf{Équipe} & \textbf{Rôles} \\ +\hline +{% for membership in memberships %} +{{ membership.user.last_name|safe }} & {{ membership.user.first_name|safe }} & {{ membership.registration.get_gender_display|safe }} +& {{ membership.user.profile.get_department_display|safe }} & {{ membership.user.profile.ens_year|safe }}A & {{ membership.bus.name|safe }} +& {% if membership.team %}{{ membership.team.name|safe }}{% else %}--{% endif %} & {{ membership.roles.all|join:", "|safe }} \\ +\hline +{% endfor %} +\end{tabularx} +\end{center} +\end{document} diff --git a/templates/wei/weimembership_list.html b/templates/wei/weimembership_list.html index 461c988f..d058211f 100644 --- a/templates/wei/weimembership_list.html +++ b/templates/wei/weimembership_list.html @@ -23,6 +23,12 @@ + +
+ + + + {% endblock %} {% block extrajavascript %}