mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-02-11 09:41:17 +00:00
Merge branch 'beta' into 'master'
Corrections diverses See merge request bde/nk20!123
This commit is contained in:
commit
5c702187e5
@ -7,7 +7,7 @@ from threading import Thread
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -123,6 +123,7 @@ class Activity(models.Model):
|
|||||||
verbose_name=_('open'),
|
verbose_name=_('open'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Update the activity wiki page each time the activity is updated (validation, change description, ...)
|
Update the activity wiki page each time the activity is updated (validation, change description, ...)
|
||||||
@ -194,8 +195,8 @@ class Entry(models.Model):
|
|||||||
else _("Entry for {note} to the activity {activity}").format(
|
else _("Entry for {note} to the activity {activity}").format(
|
||||||
guest=str(self.guest), note=str(self.note), activity=str(self.activity))
|
guest=str(self.guest), note=str(self.note), activity=str(self.activity))
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest)
|
qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest)
|
||||||
if qs.exists():
|
if qs.exists():
|
||||||
raise ValidationError(_("Already entered on ") + _("{:%Y-%m-%d %H:%M:%S}").format(qs.get().time, ))
|
raise ValidationError(_("Already entered on ") + _("{:%Y-%m-%d %H:%M:%S}").format(qs.get().time, ))
|
||||||
@ -260,6 +261,7 @@ class Guest(models.Model):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||||
one_year = timedelta(days=365)
|
one_year = timedelta(days=365)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from django.conf import settings
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import F, Q
|
from django.db.models import F, Q
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
@ -44,6 +45,7 @@ class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
date_end=timezone.now(),
|
date_end=timezone.now(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.creater = self.request.user
|
form.instance.creater = self.request.user
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
@ -145,6 +147,7 @@ class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
form.fields["inviter"].initial = self.request.user.note
|
form.fields["inviter"].initial = self.request.user.note
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.activity = Activity.objects\
|
form.instance.activity = Activity.objects\
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"])
|
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"])
|
||||||
|
@ -8,6 +8,7 @@ from django import forms
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import transaction
|
||||||
from django.forms import CheckboxSelectMultiple
|
from django.forms import CheckboxSelectMultiple
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -57,6 +58,7 @@ class ProfileForm(forms.ModelForm):
|
|||||||
self.fields['address'].widget.attrs.update({"placeholder": "4 avenue des Sciences, 91190 GIF-SUR-YVETTE"})
|
self.fields['address'].widget.attrs.update({"placeholder": "4 avenue des Sciences, 91190 GIF-SUR-YVETTE"})
|
||||||
self.fields['promotion'].widget.attrs.update({"max": timezone.now().year})
|
self.fields['promotion'].widget.attrs.update({"max": timezone.now().year})
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
if not self.instance.section or (("department" in self.changed_data
|
if not self.instance.section or (("department" in self.changed_data
|
||||||
or "promotion" in self.changed_data) and "section" not in self.changed_data):
|
or "promotion" in self.changed_data) and "section" not in self.changed_data):
|
||||||
@ -161,7 +163,7 @@ class MembershipForm(forms.ModelForm):
|
|||||||
soge = forms.BooleanField(
|
soge = forms.BooleanField(
|
||||||
label=_("Inscription paid by Société Générale"),
|
label=_("Inscription paid by Société Générale"),
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_("Check this case is the Société Générale paid the inscription."),
|
help_text=_("Check this case if the Société Générale paid the inscription."),
|
||||||
)
|
)
|
||||||
|
|
||||||
credit_type = forms.ModelChoiceField(
|
credit_type = forms.ModelChoiceField(
|
||||||
|
@ -7,7 +7,7 @@ import os
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
@ -271,6 +271,7 @@ class Club(models.Model):
|
|||||||
self._force_save = True
|
self._force_save = True
|
||||||
self.save(force_update=True)
|
self.save(force_update=True)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, force_insert=False, force_update=False, using=None,
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
update_fields=None):
|
update_fields=None):
|
||||||
if not self.require_memberships:
|
if not self.require_memberships:
|
||||||
@ -406,6 +407,7 @@ class Membership(models.Model):
|
|||||||
parent_membership.roles.set(Role.objects.filter(name="Membre de club").all())
|
parent_membership.roles.set(Role.objects.filter(name="Membre de club").all())
|
||||||
parent_membership.save()
|
parent_membership.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Calculate fee and end date before saving the membership and creating the transaction if needed.
|
Calculate fee and end date before saving the membership and creating the transaction if needed.
|
||||||
@ -475,8 +477,13 @@ class Membership(models.Model):
|
|||||||
# to treasurers.
|
# to treasurers.
|
||||||
transaction.valid = False
|
transaction.valid = False
|
||||||
from treasury.models import SogeCredit
|
from treasury.models import SogeCredit
|
||||||
soge_credit = SogeCredit.objects.get_or_create(user=self.user)[0]
|
if SogeCredit.objects.filter(user=self.user).exists():
|
||||||
soge_credit.refresh_from_db()
|
soge_credit = SogeCredit.objects.get(user=self.user)
|
||||||
|
else:
|
||||||
|
soge_credit = SogeCredit(user=self.user)
|
||||||
|
soge_credit._force_save = True
|
||||||
|
soge_credit.save(force_insert=True)
|
||||||
|
soge_credit.refresh_from_db()
|
||||||
transaction.save(force_insert=True)
|
transaction.save(force_insert=True)
|
||||||
transaction.refresh_from_db()
|
transaction.refresh_from_db()
|
||||||
soge_credit.transactions.add(transaction)
|
soge_credit.transactions.add(transaction)
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
|
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
|
||||||
<dd class="col-xl-6">{{ user_object.profile.address }}</dd>
|
<dd class="col-xl-6">{{ user_object.profile.address }}</dd>
|
||||||
|
|
||||||
{% if "note.view_note"|has_perm:user_object.note %}
|
{% if user_object.note and "note.view_note"|has_perm:user_object.note %}
|
||||||
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
|
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
|
||||||
<dd class="col-xl-6">{{ user_object.note.balance | pretty_money }}</dd>
|
<dd class="col-xl-6">{{ user_object.note.balance | pretty_money }}</dd>
|
||||||
|
|
||||||
@ -47,7 +47,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
{% if user_object.pk == user_object.pk %}
|
{% if user_object.pk == user.pk %}
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
|
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
|
||||||
<i class="fa fa-cogs"></i>{% trans 'API token' %}
|
<i class="fa fa-cogs"></i>{% trans 'API token' %}
|
||||||
|
@ -38,6 +38,7 @@ class CustomLoginView(LoginView):
|
|||||||
"""
|
"""
|
||||||
form_class = CustomAuthenticationForm
|
form_class = CustomAuthenticationForm
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
logout(self.request)
|
logout(self.request)
|
||||||
_set_current_user_and_ip(form.get_user(), self.request.session, None)
|
_set_current_user_and_ip(form.get_user(), self.request.session, None)
|
||||||
@ -76,6 +77,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
|||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
Check if ProfileForm is correct
|
Check if ProfileForm is correct
|
||||||
@ -269,6 +271,7 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det
|
|||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
return self.form_valid(form) if form.is_valid() else self.form_invalid(form)
|
return self.form_valid(form) if form.is_valid() else self.form_invalid(form)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""Save image to note"""
|
"""Save image to note"""
|
||||||
image = form.cleaned_data['image']
|
image = form.cleaned_data['image']
|
||||||
@ -650,6 +653,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
|
|
||||||
return not error
|
return not error
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
Create membership, check that all is good, make transactions
|
Create membership, check that all is good, make transactions
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@ -56,8 +57,9 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Alias.objects.all()
|
queryset = Alias.objects.all()
|
||||||
serializer_class = AliasSerializer
|
serializer_class = AliasSerializer
|
||||||
filter_backends = [SearchFilter, OrderingFilter]
|
filter_backends = [SearchFilter, DjangoFilterBackend, OrderingFilter]
|
||||||
search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
|
search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
|
||||||
|
filterset_fields = ['note']
|
||||||
ordering_fields = ['name', 'normalized_name']
|
ordering_fields = ['name', 'normalized_name']
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
@ -106,8 +108,9 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
|||||||
class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
|
class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
|
||||||
queryset = Alias.objects.all()
|
queryset = Alias.objects.all()
|
||||||
serializer_class = ConsumerSerializer
|
serializer_class = ConsumerSerializer
|
||||||
filter_backends = [SearchFilter, OrderingFilter]
|
filter_backends = [SearchFilter, OrderingFilter, DjangoFilterBackend]
|
||||||
search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
|
search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
|
||||||
|
filterset_fields = ['note']
|
||||||
ordering_fields = ['name', 'normalized_name']
|
ordering_fields = ['name', 'normalized_name']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@ -116,29 +119,31 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
|
|||||||
:return: The filtered set of requested aliases
|
:return: The filtered set of requested aliases
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset().distinct()
|
||||||
# Sqlite doesn't support ORDER BY in subqueries
|
# Sqlite doesn't support ORDER BY in subqueries
|
||||||
queryset = queryset.order_by("name") \
|
queryset = queryset.order_by("name") \
|
||||||
if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' else queryset
|
if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' else queryset
|
||||||
|
|
||||||
alias = self.request.query_params.get("alias", ".*")
|
alias = self.request.query_params.get("alias", None)
|
||||||
queryset = queryset.prefetch_related('note')
|
queryset = queryset.prefetch_related('note')
|
||||||
# We match first an alias if it is matched without normalization,
|
|
||||||
# then if the normalized pattern matches a normalized alias.
|
if alias:
|
||||||
queryset = queryset.filter(
|
# We match first an alias if it is matched without normalization,
|
||||||
name__iregex="^" + alias
|
# then if the normalized pattern matches a normalized alias.
|
||||||
).union(
|
queryset = queryset.filter(
|
||||||
queryset.filter(
|
name__iregex="^" + alias
|
||||||
Q(normalized_name__iregex="^" + Alias.normalize(alias))
|
).union(
|
||||||
& ~Q(name__iregex="^" + alias)
|
queryset.filter(
|
||||||
),
|
Q(normalized_name__iregex="^" + Alias.normalize(alias))
|
||||||
all=True).union(
|
& ~Q(name__iregex="^" + alias)
|
||||||
queryset.filter(
|
),
|
||||||
Q(normalized_name__iregex="^" + alias.lower())
|
all=True).union(
|
||||||
& ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
|
queryset.filter(
|
||||||
& ~Q(name__iregex="^" + alias)
|
Q(normalized_name__iregex="^" + alias.lower())
|
||||||
),
|
& ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
|
||||||
all=True)
|
& ~Q(name__iregex="^" + alias)
|
||||||
|
),
|
||||||
|
all=True)
|
||||||
|
|
||||||
queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \
|
queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \
|
||||||
else queryset.order_by("name")
|
else queryset.order_by("name")
|
||||||
@ -179,8 +184,11 @@ class TransactionViewSet(ReadProtectedModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Transaction.objects.order_by("-created_at").all()
|
queryset = Transaction.objects.order_by("-created_at").all()
|
||||||
serializer_class = TransactionPolymorphicSerializer
|
serializer_class = TransactionPolymorphicSerializer
|
||||||
filter_backends = [SearchFilter]
|
filter_backends = [SearchFilter, DjangoFilterBackend, OrderingFilter]
|
||||||
|
filterset_fields = ["source", "source_alias", "destination", "destination_alias", "quantity",
|
||||||
|
"polymorphic_ctype", "amount", "created_at", ]
|
||||||
search_fields = ['$reason', ]
|
search_fields = ['$reason', ]
|
||||||
|
ordering_fields = ['created_at', 'amount']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
|
@ -8,7 +8,7 @@ from django.conf.global_settings import DEFAULT_FROM_EMAIL
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -93,6 +93,7 @@ class Note(PolymorphicModel):
|
|||||||
delta = timezone.now() - self.last_negative
|
delta = timezone.now() - self.last_negative
|
||||||
return "{:d} jours".format(delta.days)
|
return "{:d} jours".format(delta.days)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Save note with it's alias (called in polymorphic children)
|
Save note with it's alias (called in polymorphic children)
|
||||||
@ -108,12 +109,16 @@ class Note(PolymorphicModel):
|
|||||||
|
|
||||||
# Save alias
|
# Save alias
|
||||||
a.note = self
|
a.note = self
|
||||||
|
# Consider that if the name of the note could be changed, then the alias can be created.
|
||||||
|
# It does not mean that any alias can be created.
|
||||||
|
a._force_save = True
|
||||||
a.save(force_insert=True)
|
a.save(force_insert=True)
|
||||||
else:
|
else:
|
||||||
# Check if the name of the note changed without changing the normalized form of the alias
|
# Check if the name of the note changed without changing the normalized form of the alias
|
||||||
alias = Alias.objects.get(normalized_name=Alias.normalize(str(self)))
|
alias = Alias.objects.get(normalized_name=Alias.normalize(str(self)))
|
||||||
if alias.name != str(self):
|
if alias.name != str(self):
|
||||||
alias.name = str(self)
|
alias.name = str(self)
|
||||||
|
alias._force_save = True
|
||||||
alias.save()
|
alias.save()
|
||||||
|
|
||||||
def clean(self, *args, **kwargs):
|
def clean(self, *args, **kwargs):
|
||||||
@ -154,6 +159,7 @@ class NoteUser(Note):
|
|||||||
def pretty(self):
|
def pretty(self):
|
||||||
return _("%(user)s's note") % {'user': str(self.user)}
|
return _("%(user)s's note") % {'user': str(self.user)}
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.pk and self.balance < 0:
|
if self.pk and self.balance < 0:
|
||||||
old_note = NoteUser.objects.get(pk=self.pk)
|
old_note = NoteUser.objects.get(pk=self.pk)
|
||||||
@ -195,6 +201,7 @@ class NoteClub(Note):
|
|||||||
def pretty(self):
|
def pretty(self):
|
||||||
return _("Note of %(club)s club") % {'club': str(self.club)}
|
return _("Note of %(club)s club") % {'club': str(self.club)}
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.pk and self.balance < 0:
|
if self.pk and self.balance < 0:
|
||||||
old_note = NoteClub.objects.get(pk=self.pk)
|
old_note = NoteClub.objects.get(pk=self.pk)
|
||||||
@ -310,6 +317,7 @@ class Alias(models.Model):
|
|||||||
pass
|
pass
|
||||||
self.normalized_name = normalized_name
|
self.normalized_name = normalized_name
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.clean()
|
self.clean()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
@ -170,19 +170,21 @@ class Transaction(PolymorphicModel):
|
|||||||
previous_source_balance = self.source.balance
|
previous_source_balance = self.source.balance
|
||||||
previous_dest_balance = self.destination.balance
|
previous_dest_balance = self.destination.balance
|
||||||
|
|
||||||
source_balance = self.source.balance
|
source_balance = previous_source_balance
|
||||||
dest_balance = self.destination.balance
|
dest_balance = previous_dest_balance
|
||||||
|
|
||||||
created = self.pk is None
|
created = self.pk is None
|
||||||
to_transfer = self.amount * self.quantity
|
to_transfer = self.total
|
||||||
if not created and not self.valid and not hasattr(self, "_force_save"):
|
if not created:
|
||||||
# Revert old transaction
|
# Revert old transaction
|
||||||
old_transaction = Transaction.objects.get(pk=self.pk)
|
# We make a select for update to avoid concurrency issues
|
||||||
|
old_transaction = Transaction.objects.select_for_update().get(pk=self.pk)
|
||||||
# Check that nothing important changed
|
# Check that nothing important changed
|
||||||
for field_name in ["source_id", "destination_id", "quantity", "amount"]:
|
if not hasattr(self, "_force_save"):
|
||||||
if getattr(self, field_name) != getattr(old_transaction, field_name):
|
for field_name in ["source_id", "destination_id", "quantity", "amount"]:
|
||||||
raise ValidationError(_("You can't update the {field} on a Transaction. "
|
if getattr(self, field_name) != getattr(old_transaction, field_name):
|
||||||
"Please invalidate it and create one other.").format(field=field_name))
|
raise ValidationError(_("You can't update the {field} on a Transaction. "
|
||||||
|
"Please invalidate it and create one other.").format(field=field_name))
|
||||||
|
|
||||||
if old_transaction.valid == self.valid:
|
if old_transaction.valid == self.valid:
|
||||||
# Don't change anything
|
# Don't change anything
|
||||||
@ -215,10 +217,6 @@ class Transaction(PolymorphicModel):
|
|||||||
# When source == destination, no money is transferred and no transaction is created
|
# When source == destination, no money is transferred and no transaction is created
|
||||||
return
|
return
|
||||||
|
|
||||||
# We refresh the notes with the "select for update" tag to avoid concurrency issues
|
|
||||||
self.source = Note.objects.filter(pk=self.source_id).select_for_update().get()
|
|
||||||
self.destination = Note.objects.filter(pk=self.destination_id).select_for_update().get()
|
|
||||||
|
|
||||||
# Check that the amounts stay between big integer bounds
|
# Check that the amounts stay between big integer bounds
|
||||||
diff_source, diff_dest = self.validate()
|
diff_source, diff_dest = self.validate()
|
||||||
|
|
||||||
@ -237,9 +235,11 @@ class Transaction(PolymorphicModel):
|
|||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
# Save notes
|
# Save notes
|
||||||
|
self.source.refresh_from_db()
|
||||||
self.source.balance += diff_source
|
self.source.balance += diff_source
|
||||||
self.source._force_save = True
|
self.source._force_save = True
|
||||||
self.source.save()
|
self.source.save()
|
||||||
|
self.destination.refresh_from_db()
|
||||||
self.destination.balance += diff_dest
|
self.destination.balance += diff_dest
|
||||||
self.destination._force_save = True
|
self.destination._force_save = True
|
||||||
self.destination.save()
|
self.destination.save()
|
||||||
@ -273,6 +273,7 @@ class RecurrentTransaction(Transaction):
|
|||||||
_("The destination of this transaction must equal to the destination of the template."))
|
_("The destination of this transaction must equal to the destination of the template."))
|
||||||
return super().clean()
|
return super().clean()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.clean()
|
self.clean()
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
@ -323,6 +324,7 @@ class SpecialTransaction(Transaction):
|
|||||||
raise(ValidationError(_("A special transaction is only possible between a"
|
raise(ValidationError(_("A special transaction is only possible between a"
|
||||||
" Note associated to a payment method and a User or a Club")))
|
" Note associated to a payment method and a User or a Club")))
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.clean()
|
self.clean()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
@ -29,7 +29,6 @@ $(document).ready(function () {
|
|||||||
// Switching in double consumptions mode should update the layout
|
// Switching in double consumptions mode should update the layout
|
||||||
$('#double_conso').change(function () {
|
$('#double_conso').change(function () {
|
||||||
$('#consos_list_div').removeClass('d-none')
|
$('#consos_list_div').removeClass('d-none')
|
||||||
$('#user_select_div').attr('class', 'col-xl-4')
|
|
||||||
$('#infos_div').attr('class', 'col-sm-5 col-xl-6')
|
$('#infos_div').attr('class', 'col-sm-5 col-xl-6')
|
||||||
|
|
||||||
const note_list_obj = $('#note_list')
|
const note_list_obj = $('#note_list')
|
||||||
@ -48,7 +47,6 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$('#single_conso').change(function () {
|
$('#single_conso').change(function () {
|
||||||
$('#consos_list_div').addClass('d-none')
|
$('#consos_list_div').addClass('d-none')
|
||||||
$('#user_select_div').attr('class', 'col-xl-7')
|
|
||||||
$('#infos_div').attr('class', 'col-sm-5 col-md-4')
|
$('#infos_div').attr('class', 'col-sm-5 col-md-4')
|
||||||
|
|
||||||
const consos_list_obj = $('#consos_list')
|
const consos_list_obj = $('#consos_list')
|
@ -10,22 +10,22 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-sm-5 col-md-4" id="infos_div">
|
<div class="col-sm-5 col-md-4" id="infos_div">
|
||||||
<div class="row">
|
<div class="row justify-content-center justify-content-md-end">
|
||||||
{# User details column #}
|
{# User details column #}
|
||||||
<div class="col">
|
<div class="col picture-col">
|
||||||
<div class="card bg-light border-success mb-4 text-center">
|
<div class="card bg-light mb-4 text-center">
|
||||||
<a id="profile_pic_link" href="#">
|
<a id="profile_pic_link" href="#">
|
||||||
<img src="{% static "member/img/default_picture.png" %}"
|
<img src="{% static "member/img/default_picture.png" %}"
|
||||||
id="profile_pic" alt="" class="card-img-top">
|
id="profile_pic" alt="" class="card-img-top d-none d-sm-block">
|
||||||
</a>
|
</a>
|
||||||
<div class="card-body text-center text-break">
|
<div class="card-body text-center text-break p-2">
|
||||||
<span id="user_note"></span>
|
<span id="user_note"><i class="small">{% trans "Please select a note" %}</i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# User selection column #}
|
{# User selection column #}
|
||||||
<div class="col-xl-7" id="user_select_div">
|
<div class="col-xl" id="user_select_div">
|
||||||
<div class="card bg-light border-success mb-4">
|
<div class="card bg-light border-success mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-text font-weight-bold">
|
<p class="card-text font-weight-bold">
|
||||||
@ -44,6 +44,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Summary of consumption and consume button #}
|
{# Summary of consumption and consume button #}
|
||||||
<div class="col-xl-5 d-none" id="consos_list_div">
|
<div class="col-xl-5 d-none" id="consos_list_div">
|
||||||
<div class="card bg-light border-info mb-4">
|
<div class="card bg-light border-info mb-4">
|
||||||
@ -65,7 +66,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{# Show last used buttons #}
|
{# Show last used buttons #}
|
||||||
<div class="card bg-light mb-4">
|
<div class="card bg-light mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@ -159,7 +159,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extrajavascript %}
|
{% block extrajavascript %}
|
||||||
<script type="text/javascript" src="{% static "js/consos.js" %}"></script>
|
<script type="text/javascript" src="{% static "note/js/consos.js" %}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
{% for button in highlighted %}
|
{% for button in highlighted %}
|
||||||
{% if button.display %}
|
{% if button.display %}
|
||||||
|
@ -34,21 +34,21 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="row">
|
<div class="row justify-content-center">
|
||||||
{# Preview note profile (picture, username and balance) #}
|
{# Preview note profile (picture, username and balance) #}
|
||||||
<div class="col-md-3" id="note_infos_div">
|
<div class="col-md picture-col" id="note_infos_div">
|
||||||
<div class="card bg-light border-success shadow mb-4 pt-4 text-center">
|
<div class="card bg-light mb-4 text-center">
|
||||||
<a id="profile_pic_link" href="#"><img src="{% static "member/img/default_picture.png" %}"
|
<a id="profile_pic_link" href="#"><img src="{% static "member/img/default_picture.png" %}"
|
||||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto"></a>
|
id="profile_pic" alt="" class="img-fluid rounded mx-auto"></a>
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center p-2">
|
||||||
<span id="user_note"></span>
|
<span id="user_note"><i class="small">{% trans "Please select a note" %}</i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# list of emitters #}
|
{# list of emitters #}
|
||||||
<div class="col-md-3" id="emitters_div">
|
<div class="col-md-3" id="emitters_div">
|
||||||
<div class="card bg-light border-success shadow mb-4">
|
<div class="card bg-light mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-text font-weight-bold">
|
<p class="card-text font-weight-bold">
|
||||||
<label for="source_note" id="source_note_label">{% trans "Select emitters" %}</label>
|
<label for="source_note" id="source_note_label">{% trans "Select emitters" %}</label>
|
||||||
@ -75,7 +75,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
{# list of receiver #}
|
{# list of receiver #}
|
||||||
<div class="col-md-3" id="dests_div">
|
<div class="col-md-3" id="dests_div">
|
||||||
<div class="card bg-light border-info shadow mb-4">
|
<div class="card bg-light mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-text font-weight-bold" id="dest_title">
|
<p class="card-text font-weight-bold" id="dest_title">
|
||||||
<label for="dest_note" id="dest_note_label">{% trans "Select receivers" %}</label>
|
<label for="dest_note" id="dest_note_label">{% trans "Select receivers" %}</label>
|
||||||
@ -97,8 +97,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Information on transaction (amount, reason, name,...) #}
|
{# Information on transaction (amount, reason, name,...) #}
|
||||||
<div class="col-md-3" id="external_div">
|
<div class="col-md" id="external_div">
|
||||||
<div class="card bg-light border-warning shadow mb-4">
|
<div class="card bg-light mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-text font-weight-bold">
|
<p class="card-text font-weight-bold">
|
||||||
{% trans "Action" %}
|
{% trans "Action" %}
|
||||||
@ -153,7 +153,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# transaction history #}
|
{# transaction history #}
|
||||||
<div class="card shadow mb-4" id="history">
|
<div class="card mb-4" id="history">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-text font-weight-bold">
|
<p class="card-text font-weight-bold">
|
||||||
{% trans "Recent transactions history" %}
|
{% trans "Recent transactions history" %}
|
||||||
@ -176,5 +176,5 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
select_receveirs_label = "{% trans "Select receivers" %}";
|
select_receveirs_label = "{% trans "Select receivers" %}";
|
||||||
transfer_type_label = "{% trans "Transfer type" %}";
|
transfer_type_label = "{% trans "Transfer type" %}";
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/js/transfer.js"></script>
|
<script src="{% static "note/js/transfer.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -144,7 +144,7 @@ class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, Up
|
|||||||
class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
"""
|
"""
|
||||||
The Magic View that make people pay their beer and burgers.
|
The Magic View that make people pay their beer and burgers.
|
||||||
(Most of the magic happens in the dark world of Javascript see `note_kfet/static/js/consos.js`)
|
(Most of the magic happens in the dark world of Javascript see `static/note/js/consos.js`)
|
||||||
"""
|
"""
|
||||||
model = Transaction
|
model = Transaction
|
||||||
template_name = "note/conso_form.html"
|
template_name = "note/conso_form.html"
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.sessions.models import Session
|
from django.contrib.sessions.models import Session
|
||||||
from note_kfet.middlewares import get_current_session
|
from note_kfet.middlewares import get_current_session
|
||||||
|
|
||||||
@ -33,9 +32,9 @@ def memoize(f):
|
|||||||
sess_funs = new_sess_funs
|
sess_funs = new_sess_funs
|
||||||
|
|
||||||
def func(*args, **kwargs):
|
def func(*args, **kwargs):
|
||||||
if settings.DEBUG:
|
# if settings.DEBUG:
|
||||||
# Don't memoize in DEBUG mode
|
# # Don't memoize in DEBUG mode
|
||||||
return f(*args, **kwargs)
|
# return f(*args, **kwargs)
|
||||||
|
|
||||||
nonlocal last_collect
|
nonlocal last_collect
|
||||||
|
|
||||||
|
@ -2679,6 +2679,102 @@
|
|||||||
"description": "Supprimer n'importe quel alias à une note non bloquée"
|
"description": "Supprimer n'importe quel alias à une note non bloquée"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 172,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"treasury",
|
||||||
|
"remittance"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Voir toutes les remises"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 173,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"treasury",
|
||||||
|
"remittance"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "add",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Ajouter une remise"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 174,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"treasury",
|
||||||
|
"remittance"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Modifier une remise"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 175,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"treasury",
|
||||||
|
"remittance"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "delete",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Supprimer une remise"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 176,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"auth",
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"query": "{\"profile__registration_valid\": false}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Modifier n'importe quel utilisateur non encore inscrit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 177,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"member",
|
||||||
|
"profile"
|
||||||
|
],
|
||||||
|
"query": "{\"registration_valid\": false}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"permanent": false,
|
||||||
|
"description": "Modifier n'importe quel profil non encore inscrit"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "permission.role",
|
"model": "permission.role",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
@ -2884,7 +2980,13 @@
|
|||||||
163,
|
163,
|
||||||
164,
|
164,
|
||||||
170,
|
170,
|
||||||
171
|
171,
|
||||||
|
172,
|
||||||
|
173,
|
||||||
|
174,
|
||||||
|
175,
|
||||||
|
176,
|
||||||
|
177
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3060,7 +3162,13 @@
|
|||||||
168,
|
168,
|
||||||
169,
|
169,
|
||||||
170,
|
170,
|
||||||
171
|
171,
|
||||||
|
172,
|
||||||
|
173,
|
||||||
|
174,
|
||||||
|
175,
|
||||||
|
176,
|
||||||
|
177
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3092,7 +3200,9 @@
|
|||||||
167,
|
167,
|
||||||
168,
|
168,
|
||||||
170,
|
170,
|
||||||
171
|
171,
|
||||||
|
176,
|
||||||
|
177
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3258,10 +3368,13 @@
|
|||||||
138,
|
138,
|
||||||
139,
|
139,
|
||||||
140,
|
140,
|
||||||
|
143,
|
||||||
145,
|
145,
|
||||||
146,
|
146,
|
||||||
147,
|
147,
|
||||||
150
|
150,
|
||||||
|
176,
|
||||||
|
177
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -199,6 +199,7 @@ class Permission(models.Model):
|
|||||||
if self.field and self.type not in {'view', 'change'}:
|
if self.field and self.type not in {'view', 'change'}:
|
||||||
raise ValidationError(_("Specifying field applies only to view and change permission types."))
|
raise ValidationError(_("Specifying field applies only to view and change permission types."))
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
super().save()
|
super().save()
|
||||||
|
@ -14,6 +14,7 @@ class StrongDjangoObjectPermissions(DjangoObjectPermissions):
|
|||||||
This is a simple patch of this class that controls view access.
|
This is a simple patch of this class that controls view access.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# The queryset is filtered, and permissions are more powerful than a simple check than just "can view this model"
|
||||||
perms_map = {
|
perms_map = {
|
||||||
'GET': ['%(app_label)s.view_%(model_name)s'],
|
'GET': ['%(app_label)s.view_%(model_name)s'],
|
||||||
'OPTIONS': [],
|
'OPTIONS': [],
|
||||||
|
@ -6,6 +6,7 @@ from datetime import date
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.forms import HiddenInput
|
from django.forms import HiddenInput
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
@ -56,6 +57,7 @@ class ProtectQuerysetMixin:
|
|||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
Submit the form, if the page is a FormView.
|
Submit the form, if the page is a FormView.
|
||||||
|
@ -60,7 +60,7 @@ class ValidationForm(forms.Form):
|
|||||||
soge = forms.BooleanField(
|
soge = forms.BooleanField(
|
||||||
label=_("Inscription paid by Société Générale"),
|
label=_("Inscription paid by Société Générale"),
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_("Check this case is the Société Générale paid the inscription."),
|
help_text=_("Check this case if the Société Générale paid the inscription."),
|
||||||
)
|
)
|
||||||
|
|
||||||
credit_type = forms.ModelChoiceField(
|
credit_type = forms.ModelChoiceField(
|
||||||
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-md-3 mb-4">
|
<div class="col-xl-5 mb-4">
|
||||||
<div class="card bg-light shadow">
|
<div class="card bg-light shadow">
|
||||||
<div class="card-header text-center" >
|
<div class="card-header text-center" >
|
||||||
<h4> {% trans "Account #" %} {{ object.pk }}</h4>
|
<h4> {% trans "Account #" %} {{ object.pk }}</h4>
|
||||||
@ -50,7 +50,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-7">
|
||||||
<div class="card bg-light shadow">
|
<div class="card bg-light shadow">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="card-header text-center" >
|
<div class="card-header text-center" >
|
||||||
|
@ -5,6 +5,7 @@ from django.conf import settings
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import resolve_url, redirect
|
from django.shortcuts import resolve_url, redirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
@ -47,6 +48,7 @@ class UserCreateView(CreateView):
|
|||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
If the form is valid, then the user is created with is_active set to False
|
If the form is valid, then the user is created with is_active set to False
|
||||||
@ -234,6 +236,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
|
|||||||
form.fields["first_name"].initial = user.first_name
|
form.fields["first_name"].initial = user.first_name
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = self.get_object()
|
user = self.get_object()
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit e5b76b7c35592aba4225115f933f2a7ed3a66df3
|
Subproject commit 7e27c3b71b04af0867d5fbe4916e2d1278637599
|
@ -4,6 +4,7 @@
|
|||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from crispy_forms.layout import Submit
|
from crispy_forms.layout import Submit
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.db import transaction
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from note_kfet.inputs import AmountInput
|
from note_kfet.inputs import AmountInput
|
||||||
|
|
||||||
@ -149,6 +150,7 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
|
|||||||
self.instance.transaction.bank = cleaned_data["bank"]
|
self.instance.transaction.bank = cleaned_data["bank"]
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
"""
|
"""
|
||||||
Save the transaction and the remittance.
|
Save the transaction and the remittance.
|
||||||
|
@ -5,7 +5,7 @@ from datetime import date
|
|||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@ -76,6 +76,7 @@ class Invoice(models.Model):
|
|||||||
verbose_name=_("tex source"),
|
verbose_name=_("tex source"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
When an invoice is generated, we store the tex source.
|
When an invoice is generated, we store the tex source.
|
||||||
@ -228,6 +229,7 @@ class Remittance(models.Model):
|
|||||||
"""
|
"""
|
||||||
return sum(transaction.total for transaction in self.transactions.all())
|
return sum(transaction.total for transaction in self.transactions.all())
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||||
# Check if all transactions have the right type.
|
# Check if all transactions have the right type.
|
||||||
if self.transactions.exists() and self.transactions.filter(~Q(source=self.remittance_type.note)).exists():
|
if self.transactions.exists() and self.transactions.filter(~Q(source=self.remittance_type.note)).exists():
|
||||||
@ -291,11 +293,12 @@ class SogeCredit(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def valid(self):
|
def valid(self):
|
||||||
return self.credit_transaction.valid
|
return self.credit_transaction and self.credit_transaction.valid
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def amount(self):
|
def amount(self):
|
||||||
return sum(transaction.total for transaction in self.transactions.all()) + 8000
|
return self.credit_transaction.total if self.valid \
|
||||||
|
else sum(transaction.total for transaction in self.transactions.all()) + 8000
|
||||||
|
|
||||||
def invalidate(self):
|
def invalidate(self):
|
||||||
"""
|
"""
|
||||||
@ -305,10 +308,10 @@ class SogeCredit(models.Model):
|
|||||||
if self.valid:
|
if self.valid:
|
||||||
self.credit_transaction.valid = False
|
self.credit_transaction.valid = False
|
||||||
self.credit_transaction.save()
|
self.credit_transaction.save()
|
||||||
for transaction in self.transactions.all():
|
for tr in self.transactions.all():
|
||||||
transaction.valid = False
|
tr.valid = False
|
||||||
transaction._force_save = True
|
tr._force_save = True
|
||||||
transaction.save()
|
tr.save()
|
||||||
|
|
||||||
def validate(self, force=False):
|
def validate(self, force=False):
|
||||||
if self.valid and not force:
|
if self.valid and not force:
|
||||||
@ -320,18 +323,20 @@ class SogeCredit(models.Model):
|
|||||||
# Refresh credit amount
|
# Refresh credit amount
|
||||||
self.save()
|
self.save()
|
||||||
self.credit_transaction.valid = True
|
self.credit_transaction.valid = True
|
||||||
|
self.credit_transaction._force_save = True
|
||||||
self.credit_transaction.save()
|
self.credit_transaction.save()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
for transaction in self.transactions.all():
|
for tr in self.transactions.all():
|
||||||
transaction.valid = True
|
tr.valid = True
|
||||||
transaction._force_save = True
|
tr._force_save = True
|
||||||
transaction.created_at = timezone.now()
|
tr.created_at = timezone.now()
|
||||||
transaction.save()
|
tr.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.credit_transaction:
|
if not self.credit_transaction:
|
||||||
self.credit_transaction = SpecialTransaction.objects.create(
|
credit_transaction = SpecialTransaction(
|
||||||
source=NoteSpecial.objects.get(special_type="Virement bancaire"),
|
source=NoteSpecial.objects.get(special_type="Virement bancaire"),
|
||||||
destination=self.user.note,
|
destination=self.user.note,
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@ -342,6 +347,10 @@ class SogeCredit(models.Model):
|
|||||||
bank="Société générale",
|
bank="Société générale",
|
||||||
valid=False,
|
valid=False,
|
||||||
)
|
)
|
||||||
|
credit_transaction._force_save = True
|
||||||
|
credit_transaction.save()
|
||||||
|
credit_transaction.refresh_from_db()
|
||||||
|
self.credit_transaction = credit_transaction
|
||||||
elif not self.valid:
|
elif not self.valid:
|
||||||
self.credit_transaction.amount = self.amount
|
self.credit_transaction.amount = self.amount
|
||||||
self.credit_transaction._force_save = True
|
self.credit_transaction._force_save = True
|
||||||
@ -361,11 +370,11 @@ class SogeCredit(models.Model):
|
|||||||
"Please ask her/him to credit the note before invalidating this credit."))
|
"Please ask her/him to credit the note before invalidating this credit."))
|
||||||
|
|
||||||
self.invalidate()
|
self.invalidate()
|
||||||
for transaction in self.transactions.all():
|
for tr in self.transactions.all():
|
||||||
transaction._force_save = True
|
tr._force_save = True
|
||||||
transaction.valid = True
|
tr.valid = True
|
||||||
transaction.created_at = timezone.now()
|
tr.created_at = timezone.now()
|
||||||
transaction.save()
|
tr.save()
|
||||||
self.credit_transaction.valid = False
|
self.credit_transaction.valid = False
|
||||||
self.credit_transaction.reason += " (invalide)"
|
self.credit_transaction.reason += " (invalide)"
|
||||||
self.credit_transaction.save()
|
self.credit_transaction.save()
|
||||||
|
@ -9,6 +9,7 @@ from tempfile import mkdtemp
|
|||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core.exceptions import ValidationError, PermissionDenied
|
from django.core.exceptions import ValidationError, PermissionDenied
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.forms import Form
|
from django.forms import Form
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
@ -65,6 +66,7 @@ class InvoiceCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
del form.fields["locked"]
|
del form.fields["locked"]
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
ret = super().form_valid(form)
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
@ -144,6 +146,7 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
|||||||
del form.fields["id"]
|
del form.fields["id"]
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
ret = super().form_valid(form)
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
@ -439,6 +442,7 @@ class SogeCreditManageView(LoginRequiredMixin, ProtectQuerysetMixin, BaseFormVie
|
|||||||
form_class = Form
|
form_class = Form
|
||||||
extra_context = {"title": _("Manage credits from the Société générale")}
|
extra_context = {"title": _("Manage credits from the Société générale")}
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
if "validate" in form.data:
|
if "validate" in form.data:
|
||||||
self.get_object().validate(True)
|
self.get_object().validate(True)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
from random import choice
|
from random import choice
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.db import transaction
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
|
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
|
||||||
@ -88,6 +89,7 @@ class WEISurvey2020(WEISurvey):
|
|||||||
"""
|
"""
|
||||||
form.set_registration(self.registration)
|
form.set_registration(self.registration)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
word = form.cleaned_data["word"]
|
word = form.cleaned_data["word"]
|
||||||
self.information.step += 1
|
self.information.step += 1
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from django.core.management import BaseCommand
|
|
||||||
from django.db.models import Q
|
|
||||||
from member.models import Membership, Club
|
|
||||||
from wei.models import WEIClub
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = "Get mailing list registrations from the last wei. " \
|
|
||||||
"Usage: manage.py extract_ml_registrations -t {events,art,sport}. " \
|
|
||||||
"You can write this into a file with a pipe, then paste the document into your mail manager."
|
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
|
||||||
parser.add_argument('--type', '-t', choices=["members", "clubs", "events", "art", "sport"], default="members",
|
|
||||||
help='Select the type of the mailing list (default members)')
|
|
||||||
parser.add_argument('--year', '-y', type=int, default=None,
|
|
||||||
help='Select the year of the concerned WEI. Default: last year')
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
###########################################################
|
|
||||||
# WARNING #
|
|
||||||
###########################################################
|
|
||||||
#
|
|
||||||
# This code is obsolete.
|
|
||||||
# TODO: Improve the mailing list extraction system, and link it automatically with Mailman.
|
|
||||||
|
|
||||||
if options["type"] == "members":
|
|
||||||
for membership in Membership.objects.filter(
|
|
||||||
club__name="BDE",
|
|
||||||
date_start__lte=date.today(),
|
|
||||||
date_end__gte=date.today(),
|
|
||||||
).all():
|
|
||||||
self.stdout.write(membership.user.email)
|
|
||||||
return
|
|
||||||
|
|
||||||
if options["type"] == "clubs":
|
|
||||||
for club in Club.objects.all():
|
|
||||||
self.stdout.write(club.email)
|
|
||||||
return
|
|
||||||
|
|
||||||
if options["year"] is None:
|
|
||||||
wei = WEIClub.objects.order_by('-year').first()
|
|
||||||
else:
|
|
||||||
wei = WEIClub.objects.filter(year=options["year"])
|
|
||||||
if wei.exists():
|
|
||||||
wei = wei.get()
|
|
||||||
else:
|
|
||||||
wei = WEIClub.objects.order_by('-year').first()
|
|
||||||
self.stderr.write(self.style.WARNING("Warning: there was no WEI in year " + str(options["year"]) + ". "
|
|
||||||
+ "Assuming the last WEI (year " + str(wei.year) + ")"))
|
|
||||||
q = Q(ml_events_registration=True) if options["type"] == "events" else Q(ml_art_registration=True)\
|
|
||||||
if options["type"] == "art" else Q(ml_sport_registration=True)
|
|
||||||
registrations = wei.users.filter(q)
|
|
||||||
for registration in registrations.all():
|
|
||||||
self.stdout.write(registration.user.email)
|
|
@ -238,7 +238,7 @@ class WEIRegistration(models.Model):
|
|||||||
information_json = models.TextField(
|
information_json = models.TextField(
|
||||||
default="{}",
|
default="{}",
|
||||||
verbose_name=_("registration information"),
|
verbose_name=_("registration information"),
|
||||||
help_text=_("Information about the registration (buses for old members, survey fot the new members), "
|
help_text=_("Information about the registration (buses for old members, survey for the new members), "
|
||||||
"encoded in JSON"),
|
"encoded in JSON"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from tempfile import mkdtemp
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import Q, Count
|
from django.db.models import Q, Count
|
||||||
from django.db.models.functions.text import Lower
|
from django.db.models.functions.text import Lower
|
||||||
from django.forms import HiddenInput
|
from django.forms import HiddenInput
|
||||||
@ -84,6 +85,7 @@ class WEICreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
date_end=date.today(),
|
date_end=date.today(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.requires_membership = True
|
form.instance.requires_membership = True
|
||||||
form.instance.parent_club = Club.objects.get(name="Kfet")
|
form.instance.parent_club = Club.objects.get(name="Kfet")
|
||||||
@ -517,6 +519,7 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
del form.fields["information_json"]
|
del form.fields["information_json"]
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
|
form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
|
||||||
form.instance.first_year = True
|
form.instance.first_year = True
|
||||||
@ -597,6 +600,7 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
|
form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
|
||||||
form.instance.first_year = False
|
form.instance.first_year = False
|
||||||
@ -688,6 +692,7 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
|
|||||||
del form.fields["information_json"]
|
del form.fields["information_json"]
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
# If the membership is already validated, then we update the bus and the team (and the roles)
|
# If the membership is already validated, then we update the bus and the team (and the roles)
|
||||||
if form.instance.is_validated:
|
if form.instance.is_validated:
|
||||||
@ -866,6 +871,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
).all()
|
).all()
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
Create membership, check that all is good, make transactions
|
Create membership, check that all is good, make transactions
|
||||||
@ -1016,6 +1022,7 @@ class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView):
|
|||||||
context["club"] = self.object.wei
|
context["club"] = self.object.wei
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
Update the survey with the data of the form.
|
Update the survey with the data of the form.
|
||||||
|
@ -7,9 +7,9 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-09-07 19:43+0200\n"
|
"POT-Creation-Date: 2020-09-13 12:35+0200\n"
|
||||||
"PO-Revision-Date: 2020-09-03 23:47+0200\n"
|
"PO-Revision-Date: 2020-09-13 12:39+0200\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -524,7 +524,7 @@ msgid "This image cannot be loaded."
|
|||||||
msgstr "Dieses Bild kann nicht geladen werden."
|
msgstr "Dieses Bild kann nicht geladen werden."
|
||||||
|
|
||||||
#: apps/member/forms.py:139 apps/member/views.py:98
|
#: apps/member/forms.py:139 apps/member/views.py:98
|
||||||
#: apps/registration/forms.py:33 apps/registration/views.py:237
|
#: apps/registration/forms.py:33 apps/registration/views.py:241
|
||||||
msgid "An alias with a similar name already exists."
|
msgid "An alias with a similar name already exists."
|
||||||
msgstr "Ein ähnliches Alias ist schon benutzt."
|
msgstr "Ein ähnliches Alias ist schon benutzt."
|
||||||
|
|
||||||
@ -533,7 +533,7 @@ msgid "Inscription paid by Société Générale"
|
|||||||
msgstr "Mitgliedschaft von der Société Générale bezahlt"
|
msgstr "Mitgliedschaft von der Société Générale bezahlt"
|
||||||
|
|
||||||
#: apps/member/forms.py:164 apps/registration/forms.py:63
|
#: apps/member/forms.py:164 apps/registration/forms.py:63
|
||||||
msgid "Check this case is the Société Générale paid the inscription."
|
msgid "Check this case if the Société Générale paid the inscription."
|
||||||
msgstr "Die Société Générale die Mitgliedschaft bezahlt."
|
msgstr "Die Société Générale die Mitgliedschaft bezahlt."
|
||||||
|
|
||||||
#: apps/member/forms.py:169 apps/registration/forms.py:68
|
#: apps/member/forms.py:169 apps/registration/forms.py:68
|
||||||
@ -1118,8 +1118,8 @@ msgid "The membership must begin before {:%m-%d-%Y}."
|
|||||||
msgstr "Die Mitgliedschaft muss vor {:%m-%d-Y} anfängen."
|
msgstr "Die Mitgliedschaft muss vor {:%m-%d-Y} anfängen."
|
||||||
|
|
||||||
#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648
|
#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648
|
||||||
#: apps/registration/views.py:287 apps/registration/views.py:289
|
#: apps/registration/views.py:291 apps/registration/views.py:293
|
||||||
#: apps/registration/views.py:291 apps/wei/views.py:927 apps/wei/views.py:931
|
#: apps/registration/views.py:295 apps/wei/views.py:927 apps/wei/views.py:931
|
||||||
msgid "This field is required."
|
msgid "This field is required."
|
||||||
msgstr "Dies ist ein Pflichtfeld."
|
msgstr "Dies ist ein Pflichtfeld."
|
||||||
|
|
||||||
@ -1454,6 +1454,11 @@ msgstr "Löschen"
|
|||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Bearbeiten"
|
msgstr "Bearbeiten"
|
||||||
|
|
||||||
|
#: apps/note/templates/note/conso_form.html:22
|
||||||
|
#: apps/note/templates/note/transaction_form.html:44
|
||||||
|
msgid "Please select a note"
|
||||||
|
msgstr "Wählen Sie eine Note"
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:32
|
#: apps/note/templates/note/conso_form.html:32
|
||||||
msgid "Consum"
|
msgid "Consum"
|
||||||
msgstr "Konsumieren"
|
msgstr "Konsumieren"
|
||||||
@ -1464,11 +1469,11 @@ msgstr "Konsumieren"
|
|||||||
msgid "Name or alias..."
|
msgid "Name or alias..."
|
||||||
msgstr "Name oder Alias..."
|
msgstr "Name oder Alias..."
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:52
|
#: apps/note/templates/note/conso_form.html:53
|
||||||
msgid "Select consumptions"
|
msgid "Select consumptions"
|
||||||
msgstr "Verbrauchswerte auswählen"
|
msgstr "Verbrauchswerte auswählen"
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:61
|
#: apps/note/templates/note/conso_form.html:62
|
||||||
msgid "Consume!"
|
msgid "Consume!"
|
||||||
msgstr "Konsumieren!"
|
msgstr "Konsumieren!"
|
||||||
|
|
||||||
@ -1694,7 +1699,7 @@ msgstr ""
|
|||||||
"Sie haben nicht die Berechtigung, das Feld {field} in dieser Instanz von "
|
"Sie haben nicht die Berechtigung, das Feld {field} in dieser Instanz von "
|
||||||
"Modell {app_label} zu ändern. {model_name}"
|
"Modell {app_label} zu ändern. {model_name}"
|
||||||
|
|
||||||
#: apps/permission/signals.py:73 apps/permission/views.py:89
|
#: apps/permission/signals.py:73 apps/permission/views.py:101
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to add an instance of model {app_label}."
|
"You don't have the permission to add an instance of model {app_label}."
|
||||||
@ -1752,7 +1757,7 @@ msgstr "Abfrage:"
|
|||||||
msgid "No associated permission"
|
msgid "No associated permission"
|
||||||
msgstr "Keine zugehörige Berechtigung"
|
msgstr "Keine zugehörige Berechtigung"
|
||||||
|
|
||||||
#: apps/permission/views.py:56
|
#: apps/permission/views.py:68
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to update this instance of the model "
|
"You don't have the permission to update this instance of the model "
|
||||||
@ -1762,7 +1767,7 @@ msgstr ""
|
|||||||
"diesen Parametern zu aktualisieren. Bitte korrigieren Sie Ihre Daten und "
|
"diesen Parametern zu aktualisieren. Bitte korrigieren Sie Ihre Daten und "
|
||||||
"versuchen Sie es erneut."
|
"versuchen Sie es erneut."
|
||||||
|
|
||||||
#: apps/permission/views.py:60
|
#: apps/permission/views.py:72
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to create an instance of the model \"{model}\" "
|
"You don't have the permission to create an instance of the model \"{model}\" "
|
||||||
@ -1772,11 +1777,11 @@ msgstr ""
|
|||||||
"diesen Parametern zu erstellen. Bitte korrigieren Sie Ihre Daten und "
|
"diesen Parametern zu erstellen. Bitte korrigieren Sie Ihre Daten und "
|
||||||
"versuchen Sie es erneut."
|
"versuchen Sie es erneut."
|
||||||
|
|
||||||
#: apps/permission/views.py:96 note_kfet/templates/base.html:106
|
#: apps/permission/views.py:108 note_kfet/templates/base.html:106
|
||||||
msgid "Rights"
|
msgid "Rights"
|
||||||
msgstr "Rechten"
|
msgstr "Rechten"
|
||||||
|
|
||||||
#: apps/permission/views.py:101
|
#: apps/permission/views.py:113
|
||||||
msgid "All rights"
|
msgid "All rights"
|
||||||
msgstr "Alle Rechten"
|
msgstr "Alle Rechten"
|
||||||
|
|
||||||
@ -1909,54 +1914,54 @@ msgstr "Danke"
|
|||||||
msgid "The Note Kfet team."
|
msgid "The Note Kfet team."
|
||||||
msgstr "Die NoteKfet Team."
|
msgstr "Die NoteKfet Team."
|
||||||
|
|
||||||
#: apps/registration/views.py:38
|
#: apps/registration/views.py:39
|
||||||
msgid "Register new user"
|
msgid "Register new user"
|
||||||
msgstr "Neuen User registrieren"
|
msgstr "Neuen User registrieren"
|
||||||
|
|
||||||
#: apps/registration/views.py:82
|
#: apps/registration/views.py:83
|
||||||
msgid "Email validation"
|
msgid "Email validation"
|
||||||
msgstr "Email validierung"
|
msgstr "Email validierung"
|
||||||
|
|
||||||
#: apps/registration/views.py:84
|
#: apps/registration/views.py:85
|
||||||
msgid "Validate email"
|
msgid "Validate email"
|
||||||
msgstr "Email validieren"
|
msgstr "Email validieren"
|
||||||
|
|
||||||
#: apps/registration/views.py:126
|
#: apps/registration/views.py:127
|
||||||
msgid "Email validation unsuccessful"
|
msgid "Email validation unsuccessful"
|
||||||
msgstr "Email validierung unerfolgreich"
|
msgstr "Email validierung unerfolgreich"
|
||||||
|
|
||||||
#: apps/registration/views.py:137
|
#: apps/registration/views.py:138
|
||||||
msgid "Email validation email sent"
|
msgid "Email validation email sent"
|
||||||
msgstr "Validierungsemail wurde gesendet"
|
msgstr "Validierungsemail wurde gesendet"
|
||||||
|
|
||||||
#: apps/registration/views.py:145
|
#: apps/registration/views.py:146
|
||||||
msgid "Resend email validation link"
|
msgid "Resend email validation link"
|
||||||
msgstr "E-Mail-Validierungslink erneut senden"
|
msgstr "E-Mail-Validierungslink erneut senden"
|
||||||
|
|
||||||
#: apps/registration/views.py:163
|
#: apps/registration/views.py:164
|
||||||
msgid "Pre-registered users list"
|
msgid "Pre-registered users list"
|
||||||
msgstr "Vorregistrierte Userliste"
|
msgstr "Vorregistrierte Userliste"
|
||||||
|
|
||||||
#: apps/registration/views.py:187
|
#: apps/registration/views.py:188
|
||||||
msgid "Unregistered users"
|
msgid "Unregistered users"
|
||||||
msgstr "Unregistrierte Users"
|
msgstr "Unregistrierte Users"
|
||||||
|
|
||||||
#: apps/registration/views.py:200
|
#: apps/registration/views.py:201
|
||||||
msgid "Registration detail"
|
msgid "Registration detail"
|
||||||
msgstr "Registrierung Detailen"
|
msgstr "Registrierung Detailen"
|
||||||
|
|
||||||
#: apps/registration/views.py:256
|
#: apps/registration/views.py:260
|
||||||
msgid "You must join the BDE."
|
msgid "You must join the BDE."
|
||||||
msgstr "Sie müssen die BDE beitreten."
|
msgstr "Sie müssen die BDE beitreten."
|
||||||
|
|
||||||
#: apps/registration/views.py:280
|
#: apps/registration/views.py:284
|
||||||
msgid ""
|
msgid ""
|
||||||
"The entered amount is not enough for the memberships, should be at least {}"
|
"The entered amount is not enough for the memberships, should be at least {}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Der eingegebene Betrag reicht für die Mitgliedschaft nicht aus, sollte "
|
"Der eingegebene Betrag reicht für die Mitgliedschaft nicht aus, sollte "
|
||||||
"mindestens {} betragen"
|
"mindestens {} betragen"
|
||||||
|
|
||||||
#: apps/registration/views.py:355
|
#: apps/registration/views.py:364
|
||||||
msgid "Invalidate pre-registration"
|
msgid "Invalidate pre-registration"
|
||||||
msgstr "Ungültige Vorregistrierung"
|
msgstr "Ungültige Vorregistrierung"
|
||||||
|
|
||||||
@ -2102,7 +2107,7 @@ msgstr "spezielle Transaktion Proxies"
|
|||||||
msgid "credit transaction"
|
msgid "credit transaction"
|
||||||
msgstr "Kredit Transaktion"
|
msgstr "Kredit Transaktion"
|
||||||
|
|
||||||
#: apps/treasury/models.py:352
|
#: apps/treasury/models.py:361
|
||||||
msgid ""
|
msgid ""
|
||||||
"This user doesn't have enough money to pay the memberships with its note. "
|
"This user doesn't have enough money to pay the memberships with its note. "
|
||||||
"Please ask her/him to credit the note before invalidating this credit."
|
"Please ask her/him to credit the note before invalidating this credit."
|
||||||
@ -2110,16 +2115,16 @@ msgstr ""
|
|||||||
"Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner "
|
"Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner "
|
||||||
"Note zu bezahlen."
|
"Note zu bezahlen."
|
||||||
|
|
||||||
#: apps/treasury/models.py:364
|
#: apps/treasury/models.py:376
|
||||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||||
msgid "Credit from the Société générale"
|
msgid "Credit from the Société générale"
|
||||||
msgstr "Kredit von der Société générale"
|
msgstr "Kredit von der Société générale"
|
||||||
|
|
||||||
#: apps/treasury/models.py:365
|
#: apps/treasury/models.py:377
|
||||||
msgid "Credits from the Société générale"
|
msgid "Credits from the Société générale"
|
||||||
msgstr "Krediten von der Société générale"
|
msgstr "Krediten von der Société générale"
|
||||||
|
|
||||||
#: apps/treasury/models.py:368
|
#: apps/treasury/models.py:380
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Soge credit for {user}"
|
msgid "Soge credit for {user}"
|
||||||
msgstr "Kredit von der Société générale für {user}"
|
msgstr "Kredit von der Société générale für {user}"
|
||||||
@ -2356,7 +2361,7 @@ msgstr "Fügen Sie einer Überweisung eine Transaktion hinzu"
|
|||||||
msgid "List of credits from the Société générale"
|
msgid "List of credits from the Société générale"
|
||||||
msgstr "Kreditliste von Société générale"
|
msgstr "Kreditliste von Société générale"
|
||||||
|
|
||||||
#: apps/treasury/views.py:443
|
#: apps/treasury/views.py:440
|
||||||
msgid "Manage credits from the Société générale"
|
msgid "Manage credits from the Société générale"
|
||||||
msgstr "Krediten von der Société générale handeln"
|
msgstr "Krediten von der Société générale handeln"
|
||||||
|
|
||||||
@ -2519,7 +2524,7 @@ msgstr "Registrierung Detailen"
|
|||||||
|
|
||||||
#: apps/wei/models.py:241
|
#: apps/wei/models.py:241
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about the registration (buses for old members, survey fot the "
|
"Information about the registration (buses for old members, survey for the "
|
||||||
"new members), encoded in JSON"
|
"new members), encoded in JSON"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Informationen zur Registrierung (Busse für alte Mitglieder, Umfrage für neue "
|
"Informationen zur Registrierung (Busse für alte Mitglieder, Umfrage für neue "
|
||||||
@ -2907,6 +2912,10 @@ msgid "English"
|
|||||||
msgstr "English"
|
msgstr "English"
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:157
|
#: note_kfet/settings/base.py:157
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr "Spanisch"
|
||||||
|
|
||||||
|
#: note_kfet/settings/base.py:158
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Französich"
|
msgstr "Französich"
|
||||||
|
|
||||||
@ -3152,3 +3161,6 @@ msgstr ""
|
|||||||
"können. Sie müssen zum Kfet gehen und die Registrierungbeitrag bezahlen. Sie "
|
"können. Sie müssen zum Kfet gehen und die Registrierungbeitrag bezahlen. Sie "
|
||||||
"müssen Ihre E-Mail-Adresse auch überprüfen, indem Sie dem Link folgen, den "
|
"müssen Ihre E-Mail-Adresse auch überprüfen, indem Sie dem Link folgen, den "
|
||||||
"Sie erhalten haben."
|
"Sie erhalten haben."
|
||||||
|
|
||||||
|
#~ msgid "Check this case is the Société Générale paid the inscription."
|
||||||
|
#~ msgstr "Die Société Générale die Mitgliedschaft bezahlt."
|
||||||
|
3148
locale/es/LC_MESSAGES/django.po
Normal file
3148
locale/es/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,9 +7,9 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-09-07 19:43+0200\n"
|
"POT-Creation-Date: 2020-09-13 12:35+0200\n"
|
||||||
"PO-Revision-Date: 2020-09-02 23:18+0200\n"
|
"PO-Revision-Date: 2020-09-13 12:36+0200\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -438,7 +438,7 @@ msgstr "données précédentes"
|
|||||||
|
|
||||||
#: apps/logs/models.py:55
|
#: apps/logs/models.py:55
|
||||||
msgid "new data"
|
msgid "new data"
|
||||||
msgstr "ouvelles données"
|
msgstr "nouvelles données"
|
||||||
|
|
||||||
#: apps/logs/models.py:63
|
#: apps/logs/models.py:63
|
||||||
msgid "create"
|
msgid "create"
|
||||||
@ -526,7 +526,7 @@ msgid "This image cannot be loaded."
|
|||||||
msgstr "Cette image ne peut pas être chargée."
|
msgstr "Cette image ne peut pas être chargée."
|
||||||
|
|
||||||
#: apps/member/forms.py:139 apps/member/views.py:98
|
#: apps/member/forms.py:139 apps/member/views.py:98
|
||||||
#: apps/registration/forms.py:33 apps/registration/views.py:237
|
#: apps/registration/forms.py:33 apps/registration/views.py:241
|
||||||
msgid "An alias with a similar name already exists."
|
msgid "An alias with a similar name already exists."
|
||||||
msgstr "Un alias avec un nom similaire existe déjà."
|
msgstr "Un alias avec un nom similaire existe déjà."
|
||||||
|
|
||||||
@ -535,7 +535,7 @@ msgid "Inscription paid by Société Générale"
|
|||||||
msgstr "Inscription payée par la Société générale"
|
msgstr "Inscription payée par la Société générale"
|
||||||
|
|
||||||
#: apps/member/forms.py:164 apps/registration/forms.py:63
|
#: apps/member/forms.py:164 apps/registration/forms.py:63
|
||||||
msgid "Check this case is the Société Générale paid the inscription."
|
msgid "Check this case if the Société Générale paid the inscription."
|
||||||
msgstr "Cochez cette case si la Société Générale a payé l'inscription."
|
msgstr "Cochez cette case si la Société Générale a payé l'inscription."
|
||||||
|
|
||||||
#: apps/member/forms.py:169 apps/registration/forms.py:68
|
#: apps/member/forms.py:169 apps/registration/forms.py:68
|
||||||
@ -550,7 +550,7 @@ msgstr "Pas de rechargement"
|
|||||||
|
|
||||||
#: apps/member/forms.py:172
|
#: apps/member/forms.py:172
|
||||||
msgid "You can credit the note of the user."
|
msgid "You can credit the note of the user."
|
||||||
msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion."
|
msgstr "Vous pouvez créditer la note de l'utilisateur avant l'adhésion."
|
||||||
|
|
||||||
#: apps/member/forms.py:176 apps/registration/forms.py:74
|
#: apps/member/forms.py:176 apps/registration/forms.py:74
|
||||||
#: apps/wei/forms/registration.py:89
|
#: apps/wei/forms/registration.py:89
|
||||||
@ -1017,7 +1017,7 @@ msgstr "Changer le mot de passe"
|
|||||||
|
|
||||||
#: apps/member/templates/member/includes/profile_info.html:53
|
#: apps/member/templates/member/includes/profile_info.html:53
|
||||||
msgid "API token"
|
msgid "API token"
|
||||||
msgstr "Acces API"
|
msgstr "Accès API"
|
||||||
|
|
||||||
#: apps/member/templates/member/manage_auth_tokens.html:19
|
#: apps/member/templates/member/manage_auth_tokens.html:19
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
@ -1120,8 +1120,8 @@ msgid "The membership must begin before {:%m-%d-%Y}."
|
|||||||
msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}."
|
msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}."
|
||||||
|
|
||||||
#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648
|
#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648
|
||||||
#: apps/registration/views.py:287 apps/registration/views.py:289
|
#: apps/registration/views.py:291 apps/registration/views.py:293
|
||||||
#: apps/registration/views.py:291 apps/wei/views.py:927 apps/wei/views.py:931
|
#: apps/registration/views.py:295 apps/wei/views.py:927 apps/wei/views.py:931
|
||||||
msgid "This field is required."
|
msgid "This field is required."
|
||||||
msgstr "Ce champ est requis."
|
msgstr "Ce champ est requis."
|
||||||
|
|
||||||
@ -1459,6 +1459,11 @@ msgstr "Supprimer"
|
|||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Éditer"
|
msgstr "Éditer"
|
||||||
|
|
||||||
|
#: apps/note/templates/note/conso_form.html:22
|
||||||
|
#: apps/note/templates/note/transaction_form.html:44
|
||||||
|
msgid "Please select a note"
|
||||||
|
msgstr "Sélectionnez une note"
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:32
|
#: apps/note/templates/note/conso_form.html:32
|
||||||
msgid "Consum"
|
msgid "Consum"
|
||||||
msgstr "Consommer"
|
msgstr "Consommer"
|
||||||
@ -1469,11 +1474,11 @@ msgstr "Consommer"
|
|||||||
msgid "Name or alias..."
|
msgid "Name or alias..."
|
||||||
msgstr "Pseudo ou alias ..."
|
msgstr "Pseudo ou alias ..."
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:52
|
#: apps/note/templates/note/conso_form.html:53
|
||||||
msgid "Select consumptions"
|
msgid "Select consumptions"
|
||||||
msgstr "Sélection des consommations"
|
msgstr "Sélection des consommations"
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:61
|
#: apps/note/templates/note/conso_form.html:62
|
||||||
msgid "Consume!"
|
msgid "Consume!"
|
||||||
msgstr "Consommer !"
|
msgstr "Consommer !"
|
||||||
|
|
||||||
@ -1701,7 +1706,7 @@ msgstr ""
|
|||||||
"Vous n'avez pas la permission de modifier le champ {field} sur l'instance du "
|
"Vous n'avez pas la permission de modifier le champ {field} sur l'instance du "
|
||||||
"modèle {app_label}.{model_name}."
|
"modèle {app_label}.{model_name}."
|
||||||
|
|
||||||
#: apps/permission/signals.py:73 apps/permission/views.py:89
|
#: apps/permission/signals.py:73 apps/permission/views.py:101
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to add an instance of model {app_label}."
|
"You don't have the permission to add an instance of model {app_label}."
|
||||||
@ -1760,7 +1765,7 @@ msgstr "Requête :"
|
|||||||
msgid "No associated permission"
|
msgid "No associated permission"
|
||||||
msgstr "Pas de permission associée"
|
msgstr "Pas de permission associée"
|
||||||
|
|
||||||
#: apps/permission/views.py:56
|
#: apps/permission/views.py:68
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to update this instance of the model "
|
"You don't have the permission to update this instance of the model "
|
||||||
@ -1769,7 +1774,7 @@ msgstr ""
|
|||||||
"Vous n'avez pas la permission de modifier cette instance du modèle « {model} "
|
"Vous n'avez pas la permission de modifier cette instance du modèle « {model} "
|
||||||
"» avec ces paramètres. Merci de les corriger et de réessayer."
|
"» avec ces paramètres. Merci de les corriger et de réessayer."
|
||||||
|
|
||||||
#: apps/permission/views.py:60
|
#: apps/permission/views.py:72
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You don't have the permission to create an instance of the model \"{model}\" "
|
"You don't have the permission to create an instance of the model \"{model}\" "
|
||||||
@ -1778,11 +1783,11 @@ msgstr ""
|
|||||||
"Vous n'avez pas la permission d'ajouter une instance du modèle « {model} » "
|
"Vous n'avez pas la permission d'ajouter une instance du modèle « {model} » "
|
||||||
"avec ces paramètres. Merci de les corriger et de réessayer."
|
"avec ces paramètres. Merci de les corriger et de réessayer."
|
||||||
|
|
||||||
#: apps/permission/views.py:96 note_kfet/templates/base.html:106
|
#: apps/permission/views.py:108 note_kfet/templates/base.html:106
|
||||||
msgid "Rights"
|
msgid "Rights"
|
||||||
msgstr "Droits"
|
msgstr "Droits"
|
||||||
|
|
||||||
#: apps/permission/views.py:101
|
#: apps/permission/views.py:113
|
||||||
msgid "All rights"
|
msgid "All rights"
|
||||||
msgstr "Tous les droits"
|
msgstr "Tous les droits"
|
||||||
|
|
||||||
@ -1913,54 +1918,54 @@ msgstr "Merci"
|
|||||||
msgid "The Note Kfet team."
|
msgid "The Note Kfet team."
|
||||||
msgstr "L'équipe de la Note Kfet."
|
msgstr "L'équipe de la Note Kfet."
|
||||||
|
|
||||||
#: apps/registration/views.py:38
|
#: apps/registration/views.py:39
|
||||||
msgid "Register new user"
|
msgid "Register new user"
|
||||||
msgstr "Enregistrer un nouvel utilisateur"
|
msgstr "Enregistrer un nouvel utilisateur"
|
||||||
|
|
||||||
#: apps/registration/views.py:82
|
#: apps/registration/views.py:83
|
||||||
msgid "Email validation"
|
msgid "Email validation"
|
||||||
msgstr "Validation de l'adresse mail"
|
msgstr "Validation de l'adresse mail"
|
||||||
|
|
||||||
#: apps/registration/views.py:84
|
#: apps/registration/views.py:85
|
||||||
msgid "Validate email"
|
msgid "Validate email"
|
||||||
msgstr "Valider l'adresse e-mail"
|
msgstr "Valider l'adresse e-mail"
|
||||||
|
|
||||||
#: apps/registration/views.py:126
|
#: apps/registration/views.py:127
|
||||||
msgid "Email validation unsuccessful"
|
msgid "Email validation unsuccessful"
|
||||||
msgstr "La validation de l'adresse mail a échoué"
|
msgstr "La validation de l'adresse mail a échoué"
|
||||||
|
|
||||||
#: apps/registration/views.py:137
|
#: apps/registration/views.py:138
|
||||||
msgid "Email validation email sent"
|
msgid "Email validation email sent"
|
||||||
msgstr "L'email de vérification de l'adresse email a bien été envoyé"
|
msgstr "L'email de vérification de l'adresse email a bien été envoyé"
|
||||||
|
|
||||||
#: apps/registration/views.py:145
|
#: apps/registration/views.py:146
|
||||||
msgid "Resend email validation link"
|
msgid "Resend email validation link"
|
||||||
msgstr "Renvoyer le lien de validation"
|
msgstr "Renvoyer le lien de validation"
|
||||||
|
|
||||||
#: apps/registration/views.py:163
|
#: apps/registration/views.py:164
|
||||||
msgid "Pre-registered users list"
|
msgid "Pre-registered users list"
|
||||||
msgstr "Liste des utilisateurs en attente d'inscription"
|
msgstr "Liste des utilisateurs en attente d'inscription"
|
||||||
|
|
||||||
#: apps/registration/views.py:187
|
#: apps/registration/views.py:188
|
||||||
msgid "Unregistered users"
|
msgid "Unregistered users"
|
||||||
msgstr "Utilisateurs en attente d'inscription"
|
msgstr "Utilisateurs en attente d'inscription"
|
||||||
|
|
||||||
#: apps/registration/views.py:200
|
#: apps/registration/views.py:201
|
||||||
msgid "Registration detail"
|
msgid "Registration detail"
|
||||||
msgstr "Détails de l'inscription"
|
msgstr "Détails de l'inscription"
|
||||||
|
|
||||||
#: apps/registration/views.py:256
|
#: apps/registration/views.py:260
|
||||||
msgid "You must join the BDE."
|
msgid "You must join the BDE."
|
||||||
msgstr "Vous devez adhérer au BDE."
|
msgstr "Vous devez adhérer au BDE."
|
||||||
|
|
||||||
#: apps/registration/views.py:280
|
#: apps/registration/views.py:284
|
||||||
msgid ""
|
msgid ""
|
||||||
"The entered amount is not enough for the memberships, should be at least {}"
|
"The entered amount is not enough for the memberships, should be at least {}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Le montant crédité est trop faible pour adhérer, il doit être au minimum de "
|
"Le montant crédité est trop faible pour adhérer, il doit être au minimum de "
|
||||||
"{}"
|
"{}"
|
||||||
|
|
||||||
#: apps/registration/views.py:355
|
#: apps/registration/views.py:364
|
||||||
msgid "Invalidate pre-registration"
|
msgid "Invalidate pre-registration"
|
||||||
msgstr "Invalider l'inscription"
|
msgstr "Invalider l'inscription"
|
||||||
|
|
||||||
@ -2106,7 +2111,7 @@ msgstr "proxys de transactions spéciales"
|
|||||||
msgid "credit transaction"
|
msgid "credit transaction"
|
||||||
msgstr "transaction de crédit"
|
msgstr "transaction de crédit"
|
||||||
|
|
||||||
#: apps/treasury/models.py:352
|
#: apps/treasury/models.py:361
|
||||||
msgid ""
|
msgid ""
|
||||||
"This user doesn't have enough money to pay the memberships with its note. "
|
"This user doesn't have enough money to pay the memberships with its note. "
|
||||||
"Please ask her/him to credit the note before invalidating this credit."
|
"Please ask her/him to credit the note before invalidating this credit."
|
||||||
@ -2114,16 +2119,16 @@ msgstr ""
|
|||||||
"Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa "
|
"Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa "
|
||||||
"note. Merci de lui demander de recharger sa note avant d'invalider ce crédit."
|
"note. Merci de lui demander de recharger sa note avant d'invalider ce crédit."
|
||||||
|
|
||||||
#: apps/treasury/models.py:364
|
#: apps/treasury/models.py:376
|
||||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||||
msgid "Credit from the Société générale"
|
msgid "Credit from the Société générale"
|
||||||
msgstr "Crédit de la Société générale"
|
msgstr "Crédit de la Société générale"
|
||||||
|
|
||||||
#: apps/treasury/models.py:365
|
#: apps/treasury/models.py:377
|
||||||
msgid "Credits from the Société générale"
|
msgid "Credits from the Société générale"
|
||||||
msgstr "Crédits de la Société générale"
|
msgstr "Crédits de la Société générale"
|
||||||
|
|
||||||
#: apps/treasury/models.py:368
|
#: apps/treasury/models.py:380
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Soge credit for {user}"
|
msgid "Soge credit for {user}"
|
||||||
msgstr "Crédit de la société générale pour l'utilisateur {user}"
|
msgstr "Crédit de la société générale pour l'utilisateur {user}"
|
||||||
@ -2358,7 +2363,7 @@ msgstr "Joindre une transaction à une remise"
|
|||||||
msgid "List of credits from the Société générale"
|
msgid "List of credits from the Société générale"
|
||||||
msgstr "Liste des crédits de la Société générale"
|
msgstr "Liste des crédits de la Société générale"
|
||||||
|
|
||||||
#: apps/treasury/views.py:443
|
#: apps/treasury/views.py:440
|
||||||
msgid "Manage credits from the Société générale"
|
msgid "Manage credits from the Société générale"
|
||||||
msgstr "Gérer les crédits de la Société générale"
|
msgstr "Gérer les crédits de la Société générale"
|
||||||
|
|
||||||
@ -2523,7 +2528,7 @@ msgstr "informations sur l'inscription"
|
|||||||
|
|
||||||
#: apps/wei/models.py:241
|
#: apps/wei/models.py:241
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about the registration (buses for old members, survey fot the "
|
"Information about the registration (buses for old members, survey for the "
|
||||||
"new members), encoded in JSON"
|
"new members), encoded in JSON"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Informations sur l'inscription (bus pour les 2A+, questionnaire pour les "
|
"Informations sur l'inscription (bus pour les 2A+, questionnaire pour les "
|
||||||
@ -2868,7 +2873,7 @@ msgid ""
|
|||||||
"This user can't be in her/his first year since he/she has already "
|
"This user can't be in her/his first year since he/she has already "
|
||||||
"participated to a WEI."
|
"participated to a WEI."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Cet utilisateur ne peut pas être en première année puisqu'iel a déjà "
|
"Cet utilisateur ne peut pas être en première année puisqu'il a déjà "
|
||||||
"participé à un WEI."
|
"participé à un WEI."
|
||||||
|
|
||||||
#: apps/wei/views.py:549
|
#: apps/wei/views.py:549
|
||||||
@ -2908,6 +2913,10 @@ msgid "English"
|
|||||||
msgstr "Anglais"
|
msgstr "Anglais"
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:157
|
#: note_kfet/settings/base.py:157
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr "Espagnol"
|
||||||
|
|
||||||
|
#: note_kfet/settings/base.py:158
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Français"
|
msgstr "Français"
|
||||||
|
|
||||||
@ -3083,7 +3092,7 @@ msgid ""
|
|||||||
"password twice so we can verify you typed it in correctly."
|
"password twice so we can verify you typed it in correctly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Veuillez entrer votre ancien mot de passe pour des raisons de sécurité, puis "
|
"Veuillez entrer votre ancien mot de passe pour des raisons de sécurité, puis "
|
||||||
"renseigné votre nouveau mot de passe à deux reprises, pour être sur de "
|
"renseigner votre nouveau mot de passe à deux reprises, pour être sûr de "
|
||||||
"l'avoir tapé correctement."
|
"l'avoir tapé correctement."
|
||||||
|
|
||||||
#: note_kfet/templates/registration/password_change_form.html:16
|
#: note_kfet/templates/registration/password_change_form.html:16
|
||||||
@ -3153,3 +3162,6 @@ msgstr ""
|
|||||||
"vous connecter. Vous devez vous rendre à la Kfet et payer les frais "
|
"vous connecter. Vous devez vous rendre à la Kfet et payer les frais "
|
||||||
"d'adhésion. Vous devez également valider votre adresse email en suivant le "
|
"d'adhésion. Vous devez également valider votre adresse email en suivant le "
|
||||||
"lien que vous avez reçu."
|
"lien que vous avez reçu."
|
||||||
|
|
||||||
|
#~ msgid "Check this case is the Société Générale paid the inscription."
|
||||||
|
#~ msgstr "Cochez cette case si la Société Générale a payé l'inscription."
|
||||||
|
@ -50,6 +50,20 @@ class SessionMiddleware(object):
|
|||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
user = request.user
|
user = request.user
|
||||||
|
|
||||||
|
# If we authenticate through a token to connect to the API, then we query the good user
|
||||||
|
if 'HTTP_AUTHORIZATION' in request.META and request.path.startswith("/api"):
|
||||||
|
token = request.META.get('HTTP_AUTHORIZATION')
|
||||||
|
if token.startswith("Token "):
|
||||||
|
token = token[6:]
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
if Token.objects.filter(key=token).exists():
|
||||||
|
token_obj = Token.objects.get(key=token)
|
||||||
|
user = token_obj.user
|
||||||
|
session = request.session
|
||||||
|
session["permission_mask"] = 42
|
||||||
|
session.save()
|
||||||
|
|
||||||
if 'HTTP_X_REAL_IP' in request.META:
|
if 'HTTP_X_REAL_IP' in request.META:
|
||||||
ip = request.META.get('HTTP_X_REAL_IP')
|
ip = request.META.get('HTTP_X_REAL_IP')
|
||||||
elif 'HTTP_X_FORWARDED_FOR' in request.META:
|
elif 'HTTP_X_FORWARDED_FOR' in request.META:
|
||||||
|
@ -154,6 +154,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
LANGUAGES = [
|
LANGUAGES = [
|
||||||
('de', _('German')),
|
('de', _('German')),
|
||||||
('en', _('English')),
|
('en', _('English')),
|
||||||
|
('es', _('Spanish')),
|
||||||
('fr', _('French')),
|
('fr', _('French')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
border-bottom-color: rgba(0, 0, 0, .250);
|
border-bottom-color: rgba(0, 0, 0, .250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fixed width picture column */
|
||||||
|
.picture-col {
|
||||||
|
max-width: 202px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Limit fluid container to a max size */
|
/* Limit fluid container to a max size */
|
||||||
.container-fluid {
|
.container-fluid {
|
||||||
max-width: 1600px;
|
max-width: 1600px;
|
||||||
|
@ -177,12 +177,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
onchange="this.form.submit()">
|
onchange="this.form.submit()">
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
{% get_available_languages as LANGUAGES %}
|
{% get_available_languages as LANGUAGES %}
|
||||||
{% get_language_info_list for LANGUAGES as languages %}
|
{% for lang_code, lang_name in LANGUAGES %}
|
||||||
{% for language in languages %}
|
<option value="{{ lang_code }}"
|
||||||
<option value="{{ language.code }}"
|
{% if lang_code == LANGUAGE_CODE %}
|
||||||
{% if language.code == LANGUAGE_CODE %}
|
|
||||||
selected{% endif %}>
|
selected{% endif %}>
|
||||||
{{ language.name_local }} ({{ language.code }})
|
{{ lang_name }} ({{ lang_code }})
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
@ -36,8 +36,9 @@ urlpatterns = [
|
|||||||
path('coffee/', include('django_htcpcp_tea.urls')),
|
path('coffee/', include('django_htcpcp_tea.urls')),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
# During development, serve media files
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
if settings.DEBUG:
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
if "cas_server" in settings.INSTALLED_APPS:
|
if "cas_server" in settings.INSTALLED_APPS:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user