From c8b72cf1ff9387639cd254229a6bf3b084fbb3b5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Mar 2020 16:52:58 +0100 Subject: [PATCH] Guests can pay with CB or coins, lot of other improvements --- apps/activity/api/serializers.py | 13 +- apps/activity/models.py | 4 +- apps/activity/tables.py | 24 +++- apps/activity/views.py | 14 ++- apps/note/api/serializers.py | 8 ++ locale/de/LC_MESSAGES/django.po | 124 ++++++++++++------ locale/fr/LC_MESSAGES/django.po | 159 ++++++++++++++---------- templates/activity/activity_detail.html | 2 +- templates/activity/activity_entry.html | 74 +++++++++-- templates/activity/activity_list.html | 15 ++- 10 files changed, 304 insertions(+), 133 deletions(-) diff --git a/apps/activity/api/serializers.py b/apps/activity/api/serializers.py index 19b52a47..2f257de0 100644 --- a/apps/activity/api/serializers.py +++ b/apps/activity/api/serializers.py @@ -3,7 +3,7 @@ from rest_framework import serializers -from ..models import ActivityType, Activity, Guest, Entry +from ..models import ActivityType, Activity, Guest, Entry, GuestTransaction class ActivityTypeSerializer(serializers.ModelSerializer): @@ -48,3 +48,14 @@ class EntrySerializer(serializers.ModelSerializer): class Meta: model = Entry fields = '__all__' + + +class GuestTransactionSerializer(serializers.ModelSerializer): + """ + REST API Serializer for Special transactions. + The djangorestframework plugin will analyse the model `GuestTransaction` and parse all fields in the API. + """ + + class Meta: + model = GuestTransaction + fields = '__all__' diff --git a/apps/activity/models.py b/apps/activity/models.py index 9e3ea296..1645d9ae 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -69,8 +69,6 @@ class Activity(models.Model): 'note.Note', on_delete=models.PROTECT, related_name='+', - null=True, - blank=True, verbose_name=_('note'), ) @@ -152,7 +150,7 @@ class Entry(models.Model): GuestTransaction.objects.create( source=self.note, source_alias=self.note.user.username, - destination=self.activity.organizer.note, + destination=self.note, destination_alias=self.activity.organizer.name, quantity=1, amount=self.activity.activity_type.guest_entry_fee, diff --git a/apps/activity/tables.py b/apps/activity/tables.py index 449ee321..d6e566d3 100644 --- a/apps/activity/tables.py +++ b/apps/activity/tables.py @@ -7,7 +7,7 @@ import django_tables2 as tables from django_tables2 import A from note.templatetags.pretty_money import pretty_money -from .models import Activity, Guest +from .models import Activity, Guest, Entry class ActivityTable(tables.Table): @@ -55,6 +55,22 @@ class GuestTable(tables.Table): return _("remove").capitalize() +def get_row_class(record): + c = "table-row" + if isinstance(record, Guest): + if record.has_entry: + c += " table-success" + else: + c += " table-warning" + else: + qs = Entry.objects.filter(note=record.note, activity=record.activity, guest=None) + if qs.exists(): + c += " table-success" + elif record.note.balance < 0: + c += " table-danger" + return c + + class EntryTable(tables.Table): type = tables.Column(verbose_name=_("Type")) @@ -82,9 +98,11 @@ class EntryTable(tables.Table): } template_name = 'django_tables2/bootstrap4.html' row_attrs = { - 'class': 'table-row', + 'class': lambda record: get_row_class(record), 'id': lambda record: "row-" + ("guest-" if isinstance(record, Guest) else "membership-") + str(record.pk), 'data-type': lambda record: "guest" if isinstance(record, Guest) else "membership", - 'data-id': lambda record: record.pk, + 'data-id': lambda record: record.pk if isinstance(record, Guest) else record.note.pk, 'data-inviter': lambda record: record.inviter.pk if isinstance(record, Guest) else "", + 'data-last-name': lambda record: record.last_name, + 'data-first-name': lambda record: record.first_name, } diff --git a/apps/activity/views.py b/apps/activity/views.py index bb97c2c3..af871d99 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -1,5 +1,6 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from datetime import datetime from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.contenttypes.models import ContentType @@ -8,11 +9,11 @@ from django.urls import reverse_lazy from django.views.generic import CreateView, DetailView, UpdateView, TemplateView from django.utils.translation import gettext_lazy as _ from django_tables2.views import SingleTableView -from note.models import NoteUser, Alias +from note.models import NoteUser, Alias, NoteSpecial from permission.backends import PermissionBackend from .forms import ActivityForm, GuestForm -from .models import Activity, Guest +from .models import Activity, Guest, Entry from .tables import ActivityTable, GuestTable, EntryTable @@ -31,7 +32,10 @@ class ActivityListView(LoginRequiredMixin, SingleTableView): def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) - ctx['title'] = _("Upcoming activities") + ctx['title'] = _("Activities") + + upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now()) + ctx['upcoming'] = ActivityTable(data=upcoming_activities) return ctx @@ -115,12 +119,16 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): .distinct("username")[:20] for note in note_qs: note.type = "Adhérent" + note.activity = activity matched.append(note) table = EntryTable(data=matched) ctx["table"] = table + ctx["entries"] = Entry.objects.filter(activity=activity) + ctx["title"] = _('Entry for activity "{}"').format(activity.name) ctx["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk + ctx["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk return ctx diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index 05c35aa5..fbd12038 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -163,6 +163,7 @@ class SpecialTransactionSerializer(serializers.ModelSerializer): fields = '__all__' +# noinspection PyUnresolvedReferences class TransactionPolymorphicSerializer(PolymorphicSerializer): model_serializer_mapping = { Transaction: TransactionSerializer, @@ -171,5 +172,12 @@ class TransactionPolymorphicSerializer(PolymorphicSerializer): SpecialTransaction: SpecialTransactionSerializer, } + try: + from activity.models import GuestTransaction + from activity.api.serializers import GuestTransactionSerializer + model_serializer_mapping[GuestTransaction] = GuestTransactionSerializer + except ImportError: # Activity app is not loaded + pass + class Meta: model = Transaction diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 70c85682..f92240d3 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-03-28 01:54+0100\n" +"POT-Creation-Date: 2020-03-28 16:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,10 +19,11 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: apps/activity/apps.py:10 apps/activity/models.py:101 +#: apps/activity/models.py:109 msgid "activity" msgstr "" -#: apps/activity/models.py:19 apps/activity/models.py:44 +#: apps/activity/models.py:21 apps/activity/models.py:46 #: apps/member/models.py:64 apps/member/models.py:122 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 #: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231 @@ -30,38 +31,38 @@ msgstr "" msgid "name" msgstr "" -#: apps/activity/models.py:23 templates/activity/activity_detail.html:34 +#: apps/activity/models.py:25 templates/activity/activity_detail.html:34 msgid "can invite" msgstr "" -#: apps/activity/models.py:26 templates/activity/activity_detail.html:38 +#: apps/activity/models.py:28 templates/activity/activity_detail.html:38 msgid "guest entry fee" msgstr "" -#: apps/activity/models.py:30 +#: apps/activity/models.py:32 msgid "activity type" msgstr "" -#: apps/activity/models.py:31 +#: apps/activity/models.py:33 msgid "activity types" msgstr "" -#: apps/activity/models.py:49 apps/note/models/transactions.py:69 +#: apps/activity/models.py:51 apps/note/models/transactions.py:69 #: apps/permission/models.py:90 templates/activity/activity_detail.html:16 msgid "description" msgstr "" -#: apps/activity/models.py:56 apps/note/models/notes.py:164 +#: apps/activity/models.py:58 apps/note/models/notes.py:164 #: apps/note/models/transactions.py:62 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "" -#: apps/activity/models.py:63 templates/activity/activity_detail.html:28 +#: apps/activity/models.py:65 templates/activity/activity_detail.html:28 msgid "organizer" msgstr "" -#: apps/activity/models.py:72 apps/activity/models.py:113 apps/note/apps.py:14 +#: apps/activity/models.py:72 apps/activity/models.py:120 apps/note/apps.py:14 #: apps/note/models/notes.py:58 msgid "note" msgstr "" @@ -91,43 +92,80 @@ msgstr "" msgid "activities" msgstr "" -#: apps/activity/models.py:107 +#: apps/activity/models.py:114 msgid "entry time" msgstr "" -#: apps/activity/models.py:129 +#: apps/activity/models.py:137 +msgid "Already entered on " +msgstr "" + +#: apps/activity/models.py:137 apps/activity/tables.py:54 +msgid "{:%Y-%m-%d %H:%M:%S}" +msgstr "" + +#: apps/activity/models.py:145 +msgid "The balance is negative." +msgstr "" + +#: apps/activity/models.py:177 msgid "last name" msgstr "" -#: apps/activity/models.py:134 templates/member/profile_info.html:14 +#: apps/activity/models.py:182 templates/member/profile_info.html:14 msgid "first name" msgstr "" -#: apps/activity/models.py:141 +#: apps/activity/models.py:189 msgid "inviter" msgstr "" -#: apps/activity/models.py:151 +#: apps/activity/models.py:202 msgid "guest" msgstr "" -#: apps/activity/models.py:152 +#: apps/activity/models.py:203 msgid "guests" msgstr "" -#: apps/activity/models.py:163 +#: apps/activity/models.py:214 msgid "Invitation" msgstr "" #: apps/activity/tables.py:54 +msgid "Entered on " +msgstr "" + +#: apps/activity/tables.py:55 msgid "remove" msgstr "" -#: apps/activity/views.py:34 -msgid "Upcoming activities" +#: apps/activity/tables.py:75 apps/treasury/models.py:126 +msgid "Type" msgstr "" -#: apps/activity/views.py:119 +#: apps/activity/tables.py:77 apps/treasury/forms.py:120 +msgid "Last name" +msgstr "" + +#: apps/activity/tables.py:79 apps/treasury/forms.py:122 +#: templates/note/transaction_form.html:92 +msgid "First name" +msgstr "" + +#: apps/activity/tables.py:81 apps/note/models/notes.py:67 +msgid "Note" +msgstr "" + +#: apps/activity/tables.py:83 +msgid "Balance" +msgstr "" + +#: apps/activity/views.py:35 templates/base.html:94 +msgid "Activities" +msgstr "" + +#: apps/activity/views.py:130 msgid "Entry for activity \"{}\"" msgstr "" @@ -357,10 +395,6 @@ msgstr "" msgid "notes" msgstr "" -#: apps/note/models/notes.py:67 -msgid "Note" -msgstr "" - #: apps/note/models/notes.py:77 apps/note/models/notes.py:101 msgid "This alias is already taken." msgstr "" @@ -573,14 +607,6 @@ msgstr "" msgid "You can't change the type of the remittance." msgstr "" -#: apps/treasury/forms.py:120 -msgid "Last name" -msgstr "" - -#: apps/treasury/forms.py:122 templates/note/transaction_form.html:92 -msgid "First name" -msgstr "" - #: apps/treasury/forms.py:124 templates/note/transaction_form.html:98 msgid "Bank" msgstr "" @@ -639,10 +665,6 @@ msgstr "" msgid "Date" msgstr "" -#: apps/treasury/models.py:126 -msgid "Type" -msgstr "" - #: apps/treasury/models.py:131 msgid "Comment" msgstr "" @@ -733,10 +755,34 @@ msgstr "" msgid "Guests list" msgstr "" -#: templates/activity/activity_list.html:7 +#: templates/activity/activity_entry.html:10 +msgid "Return to activity page" +msgstr "" + +#: templates/activity/activity_entry.html:18 +msgid "entries" +msgstr "" + +#: templates/activity/activity_entry.html:18 +msgid "entry" +msgstr "" + +#: templates/activity/activity_list.html:5 +msgid "Upcoming activities" +msgstr "" + +#: templates/activity/activity_list.html:10 +msgid "There is no planned activity." +msgstr "" + +#: templates/activity/activity_list.html:14 msgid "New activity" msgstr "" +#: templates/activity/activity_list.html:18 +msgid "All activities" +msgstr "" + #: templates/base.html:13 msgid "The ENS Paris-Saclay BDE note." msgstr "" @@ -745,10 +791,6 @@ msgstr "" msgid "Clubs" msgstr "" -#: templates/base.html:94 -msgid "Activities" -msgstr "" - #: templates/cas_server/base.html:7 msgid "Central Authentication Service" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 9c4272c3..4a900f35 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-03-28 01:54+0100\n" +"POT-Creation-Date: 2020-03-28 16:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -14,10 +14,11 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: apps/activity/apps.py:10 apps/activity/models.py:101 +#: apps/activity/models.py:109 msgid "activity" msgstr "activité" -#: apps/activity/models.py:19 apps/activity/models.py:44 +#: apps/activity/models.py:21 apps/activity/models.py:46 #: apps/member/models.py:64 apps/member/models.py:122 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 #: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231 @@ -25,45 +26,45 @@ msgstr "activité" msgid "name" msgstr "nom" -#: apps/activity/models.py:23 templates/activity/activity_detail.html:34 +#: apps/activity/models.py:25 templates/activity/activity_detail.html:34 msgid "can invite" msgstr "peut inviter" -#: apps/activity/models.py:26 templates/activity/activity_detail.html:38 +#: apps/activity/models.py:28 templates/activity/activity_detail.html:38 msgid "guest entry fee" msgstr "cotisation de l'entrée invité" -#: apps/activity/models.py:30 +#: apps/activity/models.py:32 msgid "activity type" msgstr "type d'activité" -#: apps/activity/models.py:31 +#: apps/activity/models.py:33 msgid "activity types" msgstr "types d'activité" -#: apps/activity/models.py:49 apps/note/models/transactions.py:69 +#: apps/activity/models.py:51 apps/note/models/transactions.py:69 #: apps/permission/models.py:90 templates/activity/activity_detail.html:16 msgid "description" msgstr "description" -#: apps/activity/models.py:56 apps/note/models/notes.py:164 +#: apps/activity/models.py:58 apps/note/models/notes.py:164 #: apps/note/models/transactions.py:62 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "type" -#: apps/activity/models.py:63 templates/activity/activity_detail.html:28 +#: apps/activity/models.py:65 templates/activity/activity_detail.html:28 msgid "organizer" msgstr "organisateur" -#: apps/activity/models.py:72 apps/activity/models.py:113 apps/note/apps.py:14 +#: apps/activity/models.py:72 apps/activity/models.py:120 apps/note/apps.py:14 #: apps/note/models/notes.py:58 msgid "note" msgstr "note" #: apps/activity/models.py:79 templates/activity/activity_detail.html:31 msgid "attendees club" -msgstr "" +msgstr "club attendu" #: apps/activity/models.py:83 templates/activity/activity_detail.html:22 msgid "start date" @@ -80,59 +81,96 @@ msgstr "valide" #: apps/activity/models.py:97 templates/activity/activity_detail.html:56 msgid "open" -msgstr "" +msgstr "ouvrir" #: apps/activity/models.py:102 msgid "activities" msgstr "activités" -#: apps/activity/models.py:107 +#: apps/activity/models.py:114 msgid "entry time" -msgstr "" +msgstr "heure d'entrée" -#: apps/activity/models.py:129 +#: apps/activity/models.py:137 +msgid "Already entered on " +msgstr "Déjà rentré le " + +#: apps/activity/models.py:137 apps/activity/tables.py:54 +msgid "{:%Y-%m-%d %H:%M:%S}" +msgstr "{:%d/%m/%Y %H:%M:%S}" + +#: apps/activity/models.py:145 +msgid "The balance is negative." +msgstr "La note est en négatif." + +#: apps/activity/models.py:177 msgid "last name" msgstr "nom de famille" -#: apps/activity/models.py:134 templates/member/profile_info.html:14 +#: apps/activity/models.py:182 templates/member/profile_info.html:14 msgid "first name" msgstr "prénom" -#: apps/activity/models.py:141 +#: apps/activity/models.py:189 msgid "inviter" msgstr "hôte" -#: apps/activity/models.py:151 +#: apps/activity/models.py:202 msgid "guest" msgstr "invité" -#: apps/activity/models.py:152 +#: apps/activity/models.py:203 msgid "guests" msgstr "invités" -#: apps/activity/models.py:163 +#: apps/activity/models.py:214 msgid "Invitation" msgstr "Invitation" #: apps/activity/tables.py:54 +msgid "Entered on " +msgstr "Entré le " + +#: apps/activity/tables.py:55 msgid "remove" msgstr "supprimer" -#: apps/activity/views.py:34 -msgid "Upcoming activities" -msgstr "Activités à venir" +#: apps/activity/tables.py:75 apps/treasury/models.py:126 +msgid "Type" +msgstr "Type" -#: apps/activity/views.py:119 +#: apps/activity/tables.py:77 apps/treasury/forms.py:120 +msgid "Last name" +msgstr "Nom de famille" + +#: apps/activity/tables.py:79 apps/treasury/forms.py:122 +#: templates/note/transaction_form.html:92 +msgid "First name" +msgstr "Prénom" + +#: apps/activity/tables.py:81 apps/note/models/notes.py:67 +msgid "Note" +msgstr "Note" + +#: apps/activity/tables.py:83 +msgid "Balance" +msgstr "Solde du compte" + +#: apps/activity/views.py:35 templates/base.html:94 +msgid "Activities" +msgstr "Activités" + +#: apps/activity/views.py:130 msgid "Entry for activity \"{}\"" msgstr "Entrées pour l'activité « {} »" #: apps/api/apps.py:10 msgid "API" -msgstr "" +msgstr "API" #: apps/logs/apps.py:11 msgid "Logs" -msgstr "" +msgstr "Logs" #: apps/logs/models.py:21 apps/note/models/notes.py:117 msgid "user" @@ -283,7 +321,7 @@ msgstr "cotisation" #: apps/member/models.py:172 msgid "User is not a member of the parent club" -msgstr "" +msgstr "L'utilisateur n'est pas membre du club parent" #: apps/member/models.py:176 msgid "membership" @@ -357,10 +395,6 @@ msgstr "créée le" msgid "notes" msgstr "notes" -#: apps/note/models/notes.py:67 -msgid "Note" -msgstr "Note" - #: apps/note/models/notes.py:77 apps/note/models/notes.py:101 msgid "This alias is already taken." msgstr "Cet alias est déjà pris." @@ -573,14 +607,6 @@ msgstr "La remise est déjà fermée." msgid "You can't change the type of the remittance." msgstr "Vous ne pouvez pas changer le type de la remise." -#: apps/treasury/forms.py:120 -msgid "Last name" -msgstr "Nom de famille" - -#: apps/treasury/forms.py:122 templates/note/transaction_form.html:92 -msgid "First name" -msgstr "Prénom" - #: apps/treasury/forms.py:124 templates/note/transaction_form.html:98 msgid "Bank" msgstr "Banque" @@ -639,10 +665,6 @@ msgstr "Prix unitaire" msgid "Date" msgstr "Date" -#: apps/treasury/models.py:126 -msgid "Type" -msgstr "Type" - #: apps/treasury/models.py:131 msgid "Comment" msgstr "Commentaire" @@ -733,10 +755,34 @@ msgstr "Inviter" msgid "Guests list" msgstr "Liste des invités" -#: templates/activity/activity_list.html:7 +#: templates/activity/activity_entry.html:10 +msgid "Return to activity page" +msgstr "Retour à la page de l'activité" + +#: templates/activity/activity_entry.html:18 +msgid "entries" +msgstr "entrées" + +#: templates/activity/activity_entry.html:18 +msgid "entry" +msgstr "entrée" + +#: templates/activity/activity_list.html:5 +msgid "Upcoming activities" +msgstr "Activités à venir" + +#: templates/activity/activity_list.html:10 +msgid "There is no planned activity." +msgstr "Il n'y a pas d'activité prévue." + +#: templates/activity/activity_list.html:14 msgid "New activity" msgstr "Nouvelle activité" +#: templates/activity/activity_list.html:18 +msgid "All activities" +msgstr "Toutes les activités" + #: templates/base.html:13 msgid "The ENS Paris-Saclay BDE note." msgstr "La note du BDE de l'ENS Paris-Saclay." @@ -745,10 +791,6 @@ msgstr "La note du BDE de l'ENS Paris-Saclay." msgid "Clubs" msgstr "Clubs" -#: templates/base.html:94 -msgid "Activities" -msgstr "Activités" - #: templates/cas_server/base.html:7 msgid "Central Authentication Service" msgstr "" @@ -882,9 +924,6 @@ msgstr "Changer le mot de passe" msgid "balance" msgstr "solde du compte" -msgid "Balance" -msgstr "Solde du compte" - #: templates/member/profile_info.html:41 msgid "Manage auth token" msgstr "Gérer les jetons d'authentification" @@ -1138,21 +1177,3 @@ msgstr "Il n'y a pas de transaction associée à une remise ouverte." #: templates/treasury/remittance_list.html:54 msgid "Closed remittances" msgstr "Remises fermées" - -#~ msgid "Account #%(id)s: %(username)s" -#~ msgstr "Compte n°%(id)s : %(username)s" - -#~ msgid "Alias successfully deleted" -#~ msgstr "L'alias a bien été supprimé" - -#~ msgid "New Alias" -#~ msgstr "Nouvel alias" - -#~ msgid "Membership starts on" -#~ msgstr "L'adhésion commence le" - -#~ msgid "Membership ends on" -#~ msgstr "L'adhésion finie le" - -#~ msgid "Membership duration" -#~ msgstr "Durée de l'adhésion" diff --git a/templates/activity/activity_detail.html b/templates/activity/activity_detail.html index b663e52d..ccd64803 100644 --- a/templates/activity/activity_detail.html +++ b/templates/activity/activity_detail.html @@ -48,7 +48,7 @@