diff --git a/apps/activity/models.py b/apps/activity/models.py index fe2cfb20..67b16466 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -7,7 +7,7 @@ from threading import Thread from django.conf import settings 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.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -123,6 +123,7 @@ class Activity(models.Model): verbose_name=_('open'), ) + @transaction.atomic def save(self, *args, **kwargs): """ 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( guest=str(self.guest), note=str(self.note), activity=str(self.activity)) + @transaction.atomic def save(self, *args, **kwargs): - qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest) if qs.exists(): 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: return False + @transaction.atomic def save(self, force_insert=False, force_update=False, using=None, update_fields=None): one_year = timedelta(days=365) diff --git a/apps/activity/views.py b/apps/activity/views.py index 7de31b0c..2f5c7e0b 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -7,6 +7,7 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied +from django.db import transaction from django.db.models import F, Q from django.http import HttpResponse from django.urls import reverse_lazy @@ -44,6 +45,7 @@ class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView): date_end=timezone.now(), ) + @transaction.atomic def form_valid(self, form): form.instance.creater = self.request.user return super().form_valid(form) @@ -145,6 +147,7 @@ class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView): form.fields["inviter"].initial = self.request.user.note return form + @transaction.atomic def form_valid(self, form): form.instance.activity = Activity.objects\ .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"]) diff --git a/apps/member/forms.py b/apps/member/forms.py index 20de91b7..5081a12e 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -8,6 +8,7 @@ from django import forms from django.conf import settings from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User +from django.db import transaction from django.forms import CheckboxSelectMultiple from django.utils import timezone 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['promotion'].widget.attrs.update({"max": timezone.now().year}) + @transaction.atomic def save(self, commit=True): if not self.instance.section or (("department" 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( label=_("Inscription paid by Société Générale"), 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( diff --git a/apps/member/models.py b/apps/member/models.py index c7467120..ff8f2b88 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -7,7 +7,7 @@ import os from django.conf import settings from django.contrib.auth.models import User 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.template import loader from django.urls import reverse, reverse_lazy @@ -271,6 +271,7 @@ class Club(models.Model): self._force_save = True self.save(force_update=True) + @transaction.atomic def save(self, force_insert=False, force_update=False, using=None, update_fields=None): 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.save() + @transaction.atomic def save(self, *args, **kwargs): """ 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. transaction.valid = False from treasury.models import SogeCredit - soge_credit = SogeCredit.objects.get_or_create(user=self.user)[0] - soge_credit.refresh_from_db() + if SogeCredit.objects.filter(user=self.user).exists(): + 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.refresh_from_db() soge_credit.transactions.add(transaction) diff --git a/apps/member/templates/member/includes/profile_info.html b/apps/member/templates/member/includes/profile_info.html index 372592d5..b7f2fe70 100644 --- a/apps/member/templates/member/includes/profile_info.html +++ b/apps/member/templates/member/includes/profile_info.html @@ -38,7 +38,7 @@
{% trans 'address'|capfirst %}
{{ user_object.profile.address }}
- {% if "note.view_note"|has_perm:user_object.note %} + {% if user_object.note and "note.view_note"|has_perm:user_object.note %}
{% trans 'balance'|capfirst %}
{{ user_object.note.balance | pretty_money }}
@@ -47,7 +47,7 @@ {% endif %} -{% if user_object.pk == user_object.pk %} +{% if user_object.pk == user.pk %}
{% trans 'API token' %} diff --git a/apps/member/views.py b/apps/member/views.py index 033533ff..3000562c 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -38,6 +38,7 @@ class CustomLoginView(LoginView): """ form_class = CustomAuthenticationForm + @transaction.atomic def form_valid(self, form): logout(self.request) _set_current_user_and_ip(form.get_user(), self.request.session, None) @@ -76,6 +77,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): return context + @transaction.atomic def form_valid(self, form): """ Check if ProfileForm is correct @@ -269,6 +271,7 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det self.object = self.get_object() return self.form_valid(form) if form.is_valid() else self.form_invalid(form) + @transaction.atomic def form_valid(self, form): """Save image to note""" image = form.cleaned_data['image'] @@ -650,6 +653,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView): return not error + @transaction.atomic def form_valid(self, form): """ Create membership, check that all is good, make transactions diff --git a/apps/note/api/views.py b/apps/note/api/views.py index a478e7ff..ae8bc94e 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -1,5 +1,6 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later + from django.conf import settings from django.db.models import Q from django.core.exceptions import ValidationError @@ -56,8 +57,9 @@ class AliasViewSet(ReadProtectedModelViewSet): """ queryset = Alias.objects.all() serializer_class = AliasSerializer - filter_backends = [SearchFilter, OrderingFilter] + filter_backends = [SearchFilter, DjangoFilterBackend, OrderingFilter] search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ] + filterset_fields = ['note'] ordering_fields = ['name', 'normalized_name'] def get_serializer_class(self): @@ -106,8 +108,9 @@ class AliasViewSet(ReadProtectedModelViewSet): class ConsumerViewSet(ReadOnlyProtectedModelViewSet): queryset = Alias.objects.all() serializer_class = ConsumerSerializer - filter_backends = [SearchFilter, OrderingFilter] + filter_backends = [SearchFilter, OrderingFilter, DjangoFilterBackend] search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ] + filterset_fields = ['note'] ordering_fields = ['name', 'normalized_name'] def get_queryset(self): @@ -116,29 +119,31 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet): :return: The filtered set of requested aliases """ - queryset = super().get_queryset() + queryset = super().get_queryset().distinct() # Sqlite doesn't support ORDER BY in subqueries queryset = queryset.order_by("name") \ 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') - # We match first an alias if it is matched without normalization, - # then if the normalized pattern matches a normalized alias. - queryset = queryset.filter( - name__iregex="^" + alias - ).union( - queryset.filter( - Q(normalized_name__iregex="^" + Alias.normalize(alias)) - & ~Q(name__iregex="^" + alias) - ), - all=True).union( - queryset.filter( - Q(normalized_name__iregex="^" + alias.lower()) - & ~Q(normalized_name__iregex="^" + Alias.normalize(alias)) - & ~Q(name__iregex="^" + alias) - ), - all=True) + + if alias: + # We match first an alias if it is matched without normalization, + # then if the normalized pattern matches a normalized alias. + queryset = queryset.filter( + name__iregex="^" + alias + ).union( + queryset.filter( + Q(normalized_name__iregex="^" + Alias.normalize(alias)) + & ~Q(name__iregex="^" + alias) + ), + all=True).union( + queryset.filter( + Q(normalized_name__iregex="^" + alias.lower()) + & ~Q(normalized_name__iregex="^" + Alias.normalize(alias)) + & ~Q(name__iregex="^" + alias) + ), + all=True) queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \ else queryset.order_by("name") @@ -179,8 +184,11 @@ class TransactionViewSet(ReadProtectedModelViewSet): """ queryset = Transaction.objects.order_by("-created_at").all() 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', ] + ordering_fields = ['created_at', 'amount'] def get_queryset(self): user = self.request.user diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py index 9efdd1d0..49b9fd58 100644 --- a/apps/note/models/notes.py +++ b/apps/note/models/notes.py @@ -8,7 +8,7 @@ from django.conf.global_settings import DEFAULT_FROM_EMAIL from django.core.exceptions import ValidationError from django.core.mail import send_mail 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.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -93,6 +93,7 @@ class Note(PolymorphicModel): delta = timezone.now() - self.last_negative return "{:d} jours".format(delta.days) + @transaction.atomic def save(self, *args, **kwargs): """ Save note with it's alias (called in polymorphic children) @@ -108,12 +109,16 @@ class Note(PolymorphicModel): # Save alias 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) else: # 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))) if alias.name != str(self): alias.name = str(self) + alias._force_save = True alias.save() def clean(self, *args, **kwargs): @@ -154,6 +159,7 @@ class NoteUser(Note): def pretty(self): return _("%(user)s's note") % {'user': str(self.user)} + @transaction.atomic def save(self, *args, **kwargs): if self.pk and self.balance < 0: old_note = NoteUser.objects.get(pk=self.pk) @@ -195,6 +201,7 @@ class NoteClub(Note): def pretty(self): return _("Note of %(club)s club") % {'club': str(self.club)} + @transaction.atomic def save(self, *args, **kwargs): if self.pk and self.balance < 0: old_note = NoteClub.objects.get(pk=self.pk) @@ -310,6 +317,7 @@ class Alias(models.Model): pass self.normalized_name = normalized_name + @transaction.atomic def save(self, *args, **kwargs): self.clean() super().save(*args, **kwargs) diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index c28d66da..bfe39a42 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -170,19 +170,21 @@ class Transaction(PolymorphicModel): previous_source_balance = self.source.balance previous_dest_balance = self.destination.balance - source_balance = self.source.balance - dest_balance = self.destination.balance + source_balance = previous_source_balance + dest_balance = previous_dest_balance created = self.pk is None - to_transfer = self.amount * self.quantity - if not created and not self.valid and not hasattr(self, "_force_save"): + to_transfer = self.total + if not created: # 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 - for field_name in ["source_id", "destination_id", "quantity", "amount"]: - if getattr(self, field_name) != getattr(old_transaction, 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 not hasattr(self, "_force_save"): + for field_name in ["source_id", "destination_id", "quantity", "amount"]: + if getattr(self, field_name) != getattr(old_transaction, 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: # Don't change anything @@ -215,10 +217,6 @@ class Transaction(PolymorphicModel): # When source == destination, no money is transferred and no transaction is created 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 diff_source, diff_dest = self.validate() @@ -237,9 +235,11 @@ class Transaction(PolymorphicModel): super().save(*args, **kwargs) # Save notes + self.source.refresh_from_db() self.source.balance += diff_source self.source._force_save = True self.source.save() + self.destination.refresh_from_db() self.destination.balance += diff_dest self.destination._force_save = True self.destination.save() @@ -273,6 +273,7 @@ class RecurrentTransaction(Transaction): _("The destination of this transaction must equal to the destination of the template.")) return super().clean() + @transaction.atomic def save(self, *args, **kwargs): self.clean() return super().save(*args, **kwargs) @@ -323,6 +324,7 @@ class SpecialTransaction(Transaction): raise(ValidationError(_("A special transaction is only possible between a" " Note associated to a payment method and a User or a Club"))) + @transaction.atomic def save(self, *args, **kwargs): self.clean() super().save(*args, **kwargs) diff --git a/note_kfet/static/js/consos.js b/apps/note/static/note/js/consos.js similarity index 98% rename from note_kfet/static/js/consos.js rename to apps/note/static/note/js/consos.js index 5a7e6144..78909600 100644 --- a/note_kfet/static/js/consos.js +++ b/apps/note/static/note/js/consos.js @@ -29,7 +29,6 @@ $(document).ready(function () { // Switching in double consumptions mode should update the layout $('#double_conso').change(function () { $('#consos_list_div').removeClass('d-none') - $('#user_select_div').attr('class', 'col-xl-4') $('#infos_div').attr('class', 'col-sm-5 col-xl-6') const note_list_obj = $('#note_list') @@ -48,7 +47,6 @@ $(document).ready(function () { $('#single_conso').change(function () { $('#consos_list_div').addClass('d-none') - $('#user_select_div').attr('class', 'col-xl-7') $('#infos_div').attr('class', 'col-sm-5 col-md-4') const consos_list_obj = $('#consos_list') diff --git a/note_kfet/static/js/transfer.js b/apps/note/static/note/js/transfer.js similarity index 100% rename from note_kfet/static/js/transfer.js rename to apps/note/static/note/js/transfer.js diff --git a/apps/note/templates/note/conso_form.html b/apps/note/templates/note/conso_form.html index d5914055..d6044b87 100644 --- a/apps/note/templates/note/conso_form.html +++ b/apps/note/templates/note/conso_form.html @@ -10,22 +10,22 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block content %}
-
+
{# User details column #} -
-
+
+ {# User selection column #} -
+

@@ -44,6 +44,7 @@ SPDX-License-Identifier: GPL-3.0-or-later

+ {# Summary of consumption and consume button #}
@@ -65,7 +66,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
- {# Show last used buttons #}
@@ -159,7 +159,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endblock %} {% block extrajavascript %} - + - + {% endblock %} diff --git a/apps/note/views.py b/apps/note/views.py index f5e18290..50fcd78d 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -144,7 +144,7 @@ class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, Up class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): """ 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 template_name = "note/conso_form.html" diff --git a/apps/permission/decorators.py b/apps/permission/decorators.py index 8963cb0b..8ab35697 100644 --- a/apps/permission/decorators.py +++ b/apps/permission/decorators.py @@ -4,7 +4,6 @@ from functools import lru_cache from time import time -from django.conf import settings from django.contrib.sessions.models import Session from note_kfet.middlewares import get_current_session @@ -33,9 +32,9 @@ def memoize(f): sess_funs = new_sess_funs def func(*args, **kwargs): - if settings.DEBUG: - # Don't memoize in DEBUG mode - return f(*args, **kwargs) + # if settings.DEBUG: + # # Don't memoize in DEBUG mode + # return f(*args, **kwargs) nonlocal last_collect diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index c419f9a5..64c7db5a 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2679,6 +2679,102 @@ "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", "pk": 1, @@ -2884,7 +2980,13 @@ 163, 164, 170, - 171 + 171, + 172, + 173, + 174, + 175, + 176, + 177 ] } }, @@ -3060,7 +3162,13 @@ 168, 169, 170, - 171 + 171, + 172, + 173, + 174, + 175, + 176, + 177 ] } }, @@ -3092,7 +3200,9 @@ 167, 168, 170, - 171 + 171, + 176, + 177 ] } }, @@ -3258,10 +3368,13 @@ 138, 139, 140, + 143, 145, 146, 147, - 150 + 150, + 176, + 177 ] } }, diff --git a/apps/permission/models.py b/apps/permission/models.py index ff348404..48d1b19a 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -199,6 +199,7 @@ class Permission(models.Model): if self.field and self.type not in {'view', 'change'}: raise ValidationError(_("Specifying field applies only to view and change permission types.")) + @transaction.atomic def save(self, **kwargs): self.full_clean() super().save() diff --git a/apps/permission/permissions.py b/apps/permission/permissions.py index 03f07992..f2ca28f0 100644 --- a/apps/permission/permissions.py +++ b/apps/permission/permissions.py @@ -14,6 +14,7 @@ class StrongDjangoObjectPermissions(DjangoObjectPermissions): 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 = { 'GET': ['%(app_label)s.view_%(model_name)s'], 'OPTIONS': [], diff --git a/apps/permission/views.py b/apps/permission/views.py index 343152f5..d76a2351 100644 --- a/apps/permission/views.py +++ b/apps/permission/views.py @@ -6,6 +6,7 @@ from datetime import date from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from django.db import transaction from django.db.models import Q from django.forms import HiddenInput from django.http import Http404 @@ -56,6 +57,7 @@ class ProtectQuerysetMixin: return form + @transaction.atomic def form_valid(self, form): """ Submit the form, if the page is a FormView. diff --git a/apps/registration/forms.py b/apps/registration/forms.py index ad258cb1..c164fdfa 100644 --- a/apps/registration/forms.py +++ b/apps/registration/forms.py @@ -60,7 +60,7 @@ class ValidationForm(forms.Form): soge = forms.BooleanField( label=_("Inscription paid by Société Générale"), 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( diff --git a/apps/registration/templates/registration/future_profile_detail.html b/apps/registration/templates/registration/future_profile_detail.html index 914b4224..2c0e4f04 100644 --- a/apps/registration/templates/registration/future_profile_detail.html +++ b/apps/registration/templates/registration/future_profile_detail.html @@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block content %}
-
+

{% trans "Account #" %} {{ object.pk }}

@@ -50,7 +50,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
-
+
diff --git a/apps/registration/views.py b/apps/registration/views.py index 1f71931e..a2109045 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -5,6 +5,7 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.core.exceptions import ValidationError +from django.db import transaction from django.db.models import Q from django.shortcuts import resolve_url, redirect from django.urls import reverse_lazy @@ -47,6 +48,7 @@ class UserCreateView(CreateView): return context + @transaction.atomic def form_valid(self, form): """ 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 return form + @transaction.atomic def form_valid(self, form): user = self.get_object() diff --git a/apps/scripts b/apps/scripts index e5b76b7c..7e27c3b7 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit e5b76b7c35592aba4225115f933f2a7ed3a66df3 +Subproject commit 7e27c3b71b04af0867d5fbe4916e2d1278637599 diff --git a/apps/treasury/forms.py b/apps/treasury/forms.py index c2461f76..b24dfa48 100644 --- a/apps/treasury/forms.py +++ b/apps/treasury/forms.py @@ -4,6 +4,7 @@ from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit from django import forms +from django.db import transaction from django.utils.translation import gettext_lazy as _ from note_kfet.inputs import AmountInput @@ -149,6 +150,7 @@ class LinkTransactionToRemittanceForm(forms.ModelForm): self.instance.transaction.bank = cleaned_data["bank"] return cleaned_data + @transaction.atomic def save(self, commit=True): """ Save the transaction and the remittance. diff --git a/apps/treasury/models.py b/apps/treasury/models.py index d611650f..cabec830 100644 --- a/apps/treasury/models.py +++ b/apps/treasury/models.py @@ -5,7 +5,7 @@ from datetime import date from django.contrib.auth.models import User 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.template.loader import render_to_string from django.utils import timezone @@ -76,6 +76,7 @@ class Invoice(models.Model): verbose_name=_("tex source"), ) + @transaction.atomic def save(self, *args, **kwargs): """ 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()) + @transaction.atomic def save(self, force_insert=False, force_update=False, using=None, update_fields=None): # Check if all transactions have the right type. if self.transactions.exists() and self.transactions.filter(~Q(source=self.remittance_type.note)).exists(): @@ -291,11 +293,12 @@ class SogeCredit(models.Model): @property def valid(self): - return self.credit_transaction.valid + return self.credit_transaction and self.credit_transaction.valid @property 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): """ @@ -305,10 +308,10 @@ class SogeCredit(models.Model): if self.valid: self.credit_transaction.valid = False self.credit_transaction.save() - for transaction in self.transactions.all(): - transaction.valid = False - transaction._force_save = True - transaction.save() + for tr in self.transactions.all(): + tr.valid = False + tr._force_save = True + tr.save() def validate(self, force=False): if self.valid and not force: @@ -320,18 +323,20 @@ class SogeCredit(models.Model): # Refresh credit amount self.save() self.credit_transaction.valid = True + self.credit_transaction._force_save = True self.credit_transaction.save() self.save() - for transaction in self.transactions.all(): - transaction.valid = True - transaction._force_save = True - transaction.created_at = timezone.now() - transaction.save() + for tr in self.transactions.all(): + tr.valid = True + tr._force_save = True + tr.created_at = timezone.now() + tr.save() + @transaction.atomic def save(self, *args, **kwargs): if not self.credit_transaction: - self.credit_transaction = SpecialTransaction.objects.create( + credit_transaction = SpecialTransaction( source=NoteSpecial.objects.get(special_type="Virement bancaire"), destination=self.user.note, quantity=1, @@ -342,6 +347,10 @@ class SogeCredit(models.Model): bank="Société générale", valid=False, ) + credit_transaction._force_save = True + credit_transaction.save() + credit_transaction.refresh_from_db() + self.credit_transaction = credit_transaction elif not self.valid: self.credit_transaction.amount = self.amount 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.")) self.invalidate() - for transaction in self.transactions.all(): - transaction._force_save = True - transaction.valid = True - transaction.created_at = timezone.now() - transaction.save() + for tr in self.transactions.all(): + tr._force_save = True + tr.valid = True + tr.created_at = timezone.now() + tr.save() self.credit_transaction.valid = False self.credit_transaction.reason += " (invalide)" self.credit_transaction.save() diff --git a/apps/treasury/views.py b/apps/treasury/views.py index ecefc5cf..1b6dc127 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -9,6 +9,7 @@ from tempfile import mkdtemp from crispy_forms.helper import FormHelper from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import ValidationError, PermissionDenied +from django.db import transaction from django.db.models import Q from django.forms import Form from django.http import HttpResponse @@ -65,6 +66,7 @@ class InvoiceCreateView(ProtectQuerysetMixin, ProtectedCreateView): del form.fields["locked"] return form + @transaction.atomic def form_valid(self, form): ret = super().form_valid(form) @@ -144,6 +146,7 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): del form.fields["id"] return form + @transaction.atomic def form_valid(self, form): ret = super().form_valid(form) @@ -439,6 +442,7 @@ class SogeCreditManageView(LoginRequiredMixin, ProtectQuerysetMixin, BaseFormVie form_class = Form extra_context = {"title": _("Manage credits from the Société générale")} + @transaction.atomic def form_valid(self, form): if "validate" in form.data: self.get_object().validate(True) diff --git a/apps/wei/forms/surveys/wei2020.py b/apps/wei/forms/surveys/wei2020.py index df528e1b..48203fdf 100644 --- a/apps/wei/forms/surveys/wei2020.py +++ b/apps/wei/forms/surveys/wei2020.py @@ -4,6 +4,7 @@ from random import choice from django import forms +from django.db import transaction from django.utils.translation import gettext_lazy as _ from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation @@ -88,6 +89,7 @@ class WEISurvey2020(WEISurvey): """ form.set_registration(self.registration) + @transaction.atomic def form_valid(self, form): word = form.cleaned_data["word"] self.information.step += 1 diff --git a/apps/wei/management/commands/extract_ml_registrations.py b/apps/wei/management/commands/extract_ml_registrations.py deleted file mode 100644 index 9bc82418..00000000 --- a/apps/wei/management/commands/extract_ml_registrations.py +++ /dev/null @@ -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) diff --git a/apps/wei/models.py b/apps/wei/models.py index 46d9383f..0798fa40 100644 --- a/apps/wei/models.py +++ b/apps/wei/models.py @@ -238,7 +238,7 @@ class WEIRegistration(models.Model): information_json = models.TextField( default="{}", 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"), ) diff --git a/apps/wei/views.py b/apps/wei/views.py index 8246bebf..bd7b3d49 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -10,6 +10,7 @@ from tempfile import mkdtemp from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from django.db import transaction from django.db.models import Q, Count from django.db.models.functions.text import Lower from django.forms import HiddenInput @@ -84,6 +85,7 @@ class WEICreateView(ProtectQuerysetMixin, ProtectedCreateView): date_end=date.today(), ) + @transaction.atomic def form_valid(self, form): form.instance.requires_membership = True form.instance.parent_club = Club.objects.get(name="Kfet") @@ -517,6 +519,7 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView): del form.fields["information_json"] return form + @transaction.atomic def form_valid(self, form): form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"]) form.instance.first_year = True @@ -597,6 +600,7 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView): return form + @transaction.atomic def form_valid(self, form): form.instance.wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"]) form.instance.first_year = False @@ -688,6 +692,7 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update del form.fields["information_json"] return form + @transaction.atomic def form_valid(self, form): # If the membership is already validated, then we update the bus and the team (and the roles) if form.instance.is_validated: @@ -866,6 +871,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): ).all() return form + @transaction.atomic def form_valid(self, form): """ Create membership, check that all is good, make transactions @@ -1016,6 +1022,7 @@ class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView): context["club"] = self.object.wei return context + @transaction.atomic def form_valid(self, form): """ Update the survey with the data of the form. diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 3891a934..4a12dbed 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-07 19:43+0200\n" -"PO-Revision-Date: 2020-09-03 23:47+0200\n" -"Last-Translator: \n" +"POT-Creation-Date: 2020-09-13 12:35+0200\n" +"PO-Revision-Date: 2020-09-13 12:39+0200\n" +"Last-Translator: elkmaennchen \n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" @@ -524,7 +524,7 @@ msgid "This image cannot be loaded." msgstr "Dieses Bild kann nicht geladen werden." #: 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." 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" #: 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." #: 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." #: 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/wei/views.py:927 apps/wei/views.py:931 +#: apps/registration/views.py:291 apps/registration/views.py:293 +#: apps/registration/views.py:295 apps/wei/views.py:927 apps/wei/views.py:931 msgid "This field is required." msgstr "Dies ist ein Pflichtfeld." @@ -1454,6 +1454,11 @@ msgstr "Löschen" msgid "Edit" 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 msgid "Consum" msgstr "Konsumieren" @@ -1464,11 +1469,11 @@ msgstr "Konsumieren" msgid "Name or alias..." msgstr "Name oder Alias..." -#: apps/note/templates/note/conso_form.html:52 +#: apps/note/templates/note/conso_form.html:53 msgid "Select consumptions" msgstr "Verbrauchswerte auswählen" -#: apps/note/templates/note/conso_form.html:61 +#: apps/note/templates/note/conso_form.html:62 msgid "Consume!" msgstr "Konsumieren!" @@ -1694,7 +1699,7 @@ msgstr "" "Sie haben nicht die Berechtigung, das Feld {field} in dieser Instanz von " "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 msgid "" "You don't have the permission to add an instance of model {app_label}." @@ -1752,7 +1757,7 @@ msgstr "Abfrage:" msgid "No associated permission" msgstr "Keine zugehörige Berechtigung" -#: apps/permission/views.py:56 +#: apps/permission/views.py:68 #, python-brace-format msgid "" "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 " "versuchen Sie es erneut." -#: apps/permission/views.py:60 +#: apps/permission/views.py:72 #, python-brace-format msgid "" "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 " "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" msgstr "Rechten" -#: apps/permission/views.py:101 +#: apps/permission/views.py:113 msgid "All rights" msgstr "Alle Rechten" @@ -1909,54 +1914,54 @@ msgstr "Danke" msgid "The Note Kfet team." msgstr "Die NoteKfet Team." -#: apps/registration/views.py:38 +#: apps/registration/views.py:39 msgid "Register new user" msgstr "Neuen User registrieren" -#: apps/registration/views.py:82 +#: apps/registration/views.py:83 msgid "Email validation" msgstr "Email validierung" -#: apps/registration/views.py:84 +#: apps/registration/views.py:85 msgid "Validate email" msgstr "Email validieren" -#: apps/registration/views.py:126 +#: apps/registration/views.py:127 msgid "Email validation unsuccessful" msgstr "Email validierung unerfolgreich" -#: apps/registration/views.py:137 +#: apps/registration/views.py:138 msgid "Email validation email sent" msgstr "Validierungsemail wurde gesendet" -#: apps/registration/views.py:145 +#: apps/registration/views.py:146 msgid "Resend email validation link" msgstr "E-Mail-Validierungslink erneut senden" -#: apps/registration/views.py:163 +#: apps/registration/views.py:164 msgid "Pre-registered users list" msgstr "Vorregistrierte Userliste" -#: apps/registration/views.py:187 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "Unregistrierte Users" -#: apps/registration/views.py:200 +#: apps/registration/views.py:201 msgid "Registration detail" msgstr "Registrierung Detailen" -#: apps/registration/views.py:256 +#: apps/registration/views.py:260 msgid "You must join the BDE." msgstr "Sie müssen die BDE beitreten." -#: apps/registration/views.py:280 +#: apps/registration/views.py:284 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" "Der eingegebene Betrag reicht für die Mitgliedschaft nicht aus, sollte " "mindestens {} betragen" -#: apps/registration/views.py:355 +#: apps/registration/views.py:364 msgid "Invalidate pre-registration" msgstr "Ungültige Vorregistrierung" @@ -2102,7 +2107,7 @@ msgstr "spezielle Transaktion Proxies" msgid "credit transaction" msgstr "Kredit Transaktion" -#: apps/treasury/models.py:352 +#: apps/treasury/models.py:361 msgid "" "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." @@ -2110,16 +2115,16 @@ msgstr "" "Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner " "Note zu bezahlen." -#: apps/treasury/models.py:364 +#: apps/treasury/models.py:376 #: apps/treasury/templates/treasury/sogecredit_detail.html:10 msgid "Credit from the 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" msgstr "Krediten von der Société générale" -#: apps/treasury/models.py:368 +#: apps/treasury/models.py:380 #, python-brace-format msgid "Soge credit for {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" 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" msgstr "Krediten von der Société générale handeln" @@ -2519,7 +2524,7 @@ msgstr "Registrierung Detailen" #: apps/wei/models.py:241 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" msgstr "" "Informationen zur Registrierung (Busse für alte Mitglieder, Umfrage für neue " @@ -2907,6 +2912,10 @@ msgid "English" msgstr "English" #: note_kfet/settings/base.py:157 +msgid "Spanish" +msgstr "Spanisch" + +#: note_kfet/settings/base.py:158 msgid "French" msgstr "Französich" @@ -3152,3 +3161,6 @@ msgstr "" "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 " "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." diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po new file mode 100644 index 00000000..27c4f7c1 --- /dev/null +++ b/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,3148 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-09-13 12:35+0200\n" +"PO-Revision-Date: 2020-09-13 12:38+0200\n" +"Last-Translator: elkmaennchen \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.3\n" + +#: apps/activity/apps.py:10 apps/activity/models.py:150 +#: apps/activity/models.py:166 +msgid "activity" +msgstr "actividad" + +#: apps/activity/forms.py:35 apps/activity/models.py:131 +msgid "The end date must be after the start date." +msgstr "La fecha final tiene que ser después de la fecha de inicio." + +#: apps/activity/forms.py:76 apps/activity/models.py:268 +msgid "You can't invite someone once the activity is started." +msgstr "No se puede invitar a alguien una vez que arrancó la actividad." + +#: apps/activity/forms.py:79 apps/activity/models.py:271 +msgid "This activity is not validated yet." +msgstr "Esta actividad no fue validada por ahora." + +#: apps/activity/forms.py:89 apps/activity/models.py:279 +msgid "This person has been already invited 5 times this year." +msgstr "Esta persona ya fue invitada 5 veces este año." + +#: apps/activity/forms.py:93 apps/activity/models.py:283 +msgid "This person is already invited." +msgstr "Esta persona ya está invitada." + +#: apps/activity/forms.py:97 apps/activity/models.py:287 +msgid "You can't invite more than 3 people to this activity." +msgstr "Usted no puede invitar más de 3 persona a esta actividad." + +#: apps/activity/models.py:28 apps/activity/models.py:63 +#: apps/member/models.py:199 +#: apps/member/templates/member/includes/club_info.html:4 +#: apps/member/templates/member/includes/profile_info.html:4 +#: apps/note/models/notes.py:253 apps/note/models/transactions.py:26 +#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:296 +#: apps/permission/models.py:329 +#: apps/registration/templates/registration/future_profile_detail.html:16 +#: apps/wei/models.py:66 apps/wei/models.py:118 +#: apps/wei/templates/wei/base.html:26 +#: apps/wei/templates/wei/weimembership_form.html:14 +msgid "name" +msgstr "nombre" + +#: apps/activity/models.py:33 +msgid "manage entries" +msgstr "gestionar las entradas" + +#: apps/activity/models.py:34 +msgid "Enable the support of entries for this activity." +msgstr "Activar el soporte de las entradas por esta actividad." + +#: apps/activity/models.py:39 +#: apps/activity/templates/activity/includes/activity_info.html:42 +msgid "can invite" +msgstr "puede invitar" + +#: apps/activity/models.py:44 +#: apps/activity/templates/activity/includes/activity_info.html:46 +msgid "guest entry fee" +msgstr "pago de entrada invitado" + +#: apps/activity/models.py:49 +msgid "activity type" +msgstr "tipo de actividad" + +#: apps/activity/models.py:50 +msgid "activity types" +msgstr "tipos de actividad" + +#: apps/activity/models.py:68 +#: apps/activity/templates/activity/includes/activity_info.html:19 +#: apps/note/models/transactions.py:81 apps/permission/models.py:110 +#: apps/permission/models.py:189 apps/wei/models.py:72 apps/wei/models.py:129 +msgid "description" +msgstr "descripción" + +#: apps/activity/models.py:72 +msgid "location" +msgstr "ubicación" + +#: apps/activity/models.py:76 +msgid "Place where the activity is organized, eg. Kfet." +msgstr "Lugar donde se organiza la actividad, por ejemplo la Kfet." + +#: apps/activity/models.py:83 +#: apps/activity/templates/activity/includes/activity_info.html:22 +#: apps/note/models/notes.py:229 apps/note/models/transactions.py:66 +#: apps/permission/models.py:164 +msgid "type" +msgstr "tipo" + +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:304 +#: apps/note/models/notes.py:144 apps/treasury/models.py:276 +#: apps/treasury/templates/treasury/sogecredit_detail.html:14 +#: apps/wei/models.py:160 apps/wei/templates/wei/survey.html:15 +msgid "user" +msgstr "usuario" + +#: apps/activity/models.py:96 +#: apps/activity/templates/activity/includes/activity_info.html:36 +msgid "organizer" +msgstr "organizador" + +#: apps/activity/models.py:97 +msgid "Club that organizes the activity. The entry fees will go to this club." +msgstr "" +"El club que organiza la actividad. Los pagos de entrada serán dados a este " +"club." + +#: apps/activity/models.py:104 +#: apps/activity/templates/activity/includes/activity_info.html:39 +msgid "attendees club" +msgstr "club esperado" + +#: apps/activity/models.py:105 +msgid "Club that is authorized to join the activity. Mostly the Kfet club." +msgstr "Club permitido unirse a la actividad. Generalmente el club Kfet." + +#: apps/activity/models.py:109 +#: apps/activity/templates/activity/includes/activity_info.html:25 +msgid "start date" +msgstr "fecha de inicio" + +#: apps/activity/models.py:113 +#: apps/activity/templates/activity/includes/activity_info.html:28 +msgid "end date" +msgstr "fecha de fin" + +#: apps/activity/models.py:118 +#: apps/activity/templates/activity/includes/activity_info.html:50 +#: apps/note/models/transactions.py:149 +msgid "valid" +msgstr "válido" + +#: apps/activity/models.py:123 +#: apps/activity/templates/activity/includes/activity_info.html:65 +msgid "open" +msgstr "abierto" + +#: apps/activity/models.py:151 +msgid "activities" +msgstr "actividades" + +#: apps/activity/models.py:171 +msgid "entry time" +msgstr "hora de entrada" + +#: apps/activity/models.py:177 apps/note/apps.py:14 +#: apps/note/models/notes.py:78 +msgid "note" +msgstr "note" + +#: apps/activity/models.py:188 +#: apps/activity/templates/activity/activity_entry.html:46 +msgid "entry" +msgstr "entrada" + +#: apps/activity/models.py:189 +#: apps/activity/templates/activity/activity_entry.html:46 +msgid "entries" +msgstr "entradas" + +#: apps/activity/models.py:192 +#, python-brace-format +msgid "Entry for {guest}, invited by {note} to the activity {activity}" +msgstr "Entrada para {guest}, invitado por {note} en la actividad {activity}" + +#: apps/activity/models.py:194 +#, python-brace-format +msgid "Entry for {note} to the activity {activity}" +msgstr "Entrada para {note} en la actividad {activity}" + +#: apps/activity/models.py:201 +msgid "Already entered on " +msgstr "Entrado ya el " + +#: apps/activity/models.py:201 apps/activity/tables.py:54 +msgid "{:%Y-%m-%d %H:%M:%S}" +msgstr "{:%d/%m/%Y %H:%M:%S}" + +#: apps/activity/models.py:209 +msgid "The balance is negative." +msgstr "El saldo es negativo." + +#: apps/activity/models.py:239 +msgid "last name" +msgstr "apellido" + +#: apps/activity/models.py:244 +#: apps/member/templates/member/includes/profile_info.html:4 +#: apps/registration/templates/registration/future_profile_detail.html:16 +#: apps/wei/templates/wei/weimembership_form.html:14 +msgid "first name" +msgstr "nombre" + +#: apps/activity/models.py:251 +msgid "inviter" +msgstr "huésped" + +#: apps/activity/models.py:295 +msgid "guest" +msgstr "invitado" + +#: apps/activity/models.py:296 +msgid "guests" +msgstr "invitados" + +#: apps/activity/models.py:308 +msgid "Invitation" +msgstr "Invitación" + +#: apps/activity/tables.py:25 +msgid "The activity is currently open." +msgstr "La actividad está actualmente abierta." + +#: apps/activity/tables.py:26 +msgid "The validation of the activity is pending." +msgstr "La validación de esta actividad es pendiente." + +#: apps/activity/tables.py:41 apps/treasury/tables.py:107 +msgid "Remove" +msgstr "Quitar" + +#: apps/activity/tables.py:54 +msgid "Entered on " +msgstr "Entrado el " + +#: apps/activity/tables.py:56 +msgid "remove" +msgstr "quitar" + +#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:192 +msgid "Type" +msgstr "Tipo" + +#: apps/activity/tables.py:82 apps/member/forms.py:183 +#: apps/registration/forms.py:81 apps/treasury/forms.py:129 +#: apps/wei/forms/registration.py:96 +msgid "Last name" +msgstr "Apellido" + +#: apps/activity/tables.py:84 apps/member/forms.py:188 +#: apps/note/templates/note/transaction_form.html:134 +#: apps/registration/forms.py:86 apps/treasury/forms.py:131 +#: apps/wei/forms/registration.py:101 +msgid "First name" +msgstr "Nombre" + +#: apps/activity/tables.py:86 apps/note/models/notes.py:87 +msgid "Note" +msgstr "Note" + +#: apps/activity/tables.py:88 apps/member/tables.py:46 +msgid "Balance" +msgstr "Saldo de la cuenta" + +#: apps/activity/templates/activity/activity_detail.html:15 +msgid "Guests list" +msgstr "Lista de los invitados" + +#: apps/activity/templates/activity/activity_entry.html:14 +#: apps/note/models/transactions.py:253 +#: apps/note/templates/note/transaction_form.html:16 +#: apps/note/templates/note/transaction_form.html:148 +#: note_kfet/templates/base.html:70 +msgid "Transfer" +msgstr "Transferencia" + +#: apps/activity/templates/activity/activity_entry.html:18 +#: apps/note/models/transactions.py:312 +#: apps/note/templates/note/transaction_form.html:21 +msgid "Credit" +msgstr "Crédito" + +#: apps/activity/templates/activity/activity_entry.html:21 +#: apps/note/models/transactions.py:312 +#: apps/note/templates/note/transaction_form.html:25 +msgid "Debit" +msgstr "Débito" + +#: apps/activity/templates/activity/activity_entry.html:27 +#: apps/note/templates/note/transaction_form.html:30 +msgid "Entries" +msgstr "Entradas" + +#: apps/activity/templates/activity/activity_entry.html:37 +msgid "Return to activity page" +msgstr "Regresar a la página de la actividad" + +#: apps/activity/templates/activity/activity_form.html:16 +#: apps/member/templates/member/add_members.html:32 +#: apps/member/templates/member/club_form.html:16 +#: apps/note/templates/note/transactiontemplate_form.html:18 +#: apps/treasury/forms.py:87 apps/treasury/forms.py:141 +#: apps/treasury/templates/treasury/invoice_form.html:74 +#: apps/wei/templates/wei/bus_form.html:17 +#: apps/wei/templates/wei/busteam_form.html:17 +#: apps/wei/templates/wei/weiclub_form.html:17 +#: apps/wei/templates/wei/weiregistration_form.html:18 +msgid "Submit" +msgstr "Enviar" + +#: apps/activity/templates/activity/activity_list.html:12 +msgid "Current activity" +msgstr "Actividad actual" + +#: apps/activity/templates/activity/activity_list.html:24 +msgid "Upcoming activities" +msgstr "Próximas actividades" + +#: apps/activity/templates/activity/activity_list.html:31 +msgid "There is no planned activity." +msgstr "No hay actividad planeada." + +#: apps/activity/templates/activity/activity_list.html:38 +msgid "New activity" +msgstr "Nueva actividad" + +#: apps/activity/templates/activity/activity_list.html:45 +msgid "All activities" +msgstr "Todas las actividades" + +#: apps/activity/templates/activity/includes/activity_info.html:32 +msgid "creater" +msgstr "creador" + +#: apps/activity/templates/activity/includes/activity_info.html:53 +msgid "opened" +msgstr "abierto" + +#: apps/activity/templates/activity/includes/activity_info.html:60 +msgid "Entry page" +msgstr "Página de las entradas" + +#: apps/activity/templates/activity/includes/activity_info.html:65 +msgid "close" +msgstr "cerrado" + +#: apps/activity/templates/activity/includes/activity_info.html:68 +msgid "invalidate" +msgstr "invalidar" + +#: apps/activity/templates/activity/includes/activity_info.html:68 +msgid "validate" +msgstr "validar" + +#: apps/activity/templates/activity/includes/activity_info.html:71 +#: apps/logs/models.py:64 apps/note/tables.py:195 +msgid "edit" +msgstr "modificar" + +#: apps/activity/templates/activity/includes/activity_info.html:74 +msgid "Invite" +msgstr "Invitar" + +#: apps/activity/views.py:33 +msgid "Create new activity" +msgstr "Crear una nueva actividad" + +#: apps/activity/views.py:63 note_kfet/templates/base.html:88 +msgid "Activities" +msgstr "Actividades" + +#: apps/activity/views.py:91 +msgid "Activity detail" +msgstr "Detalles de la actividad" + +#: apps/activity/views.py:111 +msgid "Update activity" +msgstr "Modificar la actividad" + +#: apps/activity/views.py:138 +msgid "Invite guest to the activity \"{}\"" +msgstr "Invitar alguien para la actividad \"{}\"" + +#: apps/activity/views.py:172 +msgid "You are not allowed to display the entry interface for this activity." +msgstr "" +"Usted no tiene derecho a mostrar la interfaz de las entradas para esta " +"actividad." + +#: apps/activity/views.py:175 +msgid "This activity does not support activity entries." +msgstr "Esta actividad no necesita entradas." + +#: apps/activity/views.py:178 +msgid "This activity is closed." +msgstr "Esta actividad esta cerrada." + +#: apps/activity/views.py:274 +msgid "Entry for activity \"{}\"" +msgstr "Entradas para la actividad \"{}\"" + +#: apps/api/apps.py:10 +msgid "API" +msgstr "API" + +#: apps/logs/apps.py:11 +msgid "Logs" +msgstr "Logs" + +#: apps/logs/models.py:28 +msgid "IP Address" +msgstr "Dirección IP" + +#: apps/logs/models.py:36 apps/permission/models.py:134 +msgid "model" +msgstr "modelo" + +#: apps/logs/models.py:43 +msgid "identifier" +msgstr "nombre de usuario" + +#: apps/logs/models.py:49 +msgid "previous data" +msgstr "datos anteriores" + +#: apps/logs/models.py:55 +msgid "new data" +msgstr "nuevos datos" + +#: apps/logs/models.py:63 +msgid "create" +msgstr "crear" + +#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:201 +#: apps/permission/models.py:127 apps/treasury/tables.py:38 +#: apps/wei/tables.py:75 +msgid "delete" +msgstr "suprimir" + +#: apps/logs/models.py:68 +msgid "action" +msgstr "acción" + +#: apps/logs/models.py:76 +msgid "timestamp" +msgstr "fecha" + +#: apps/logs/models.py:80 +msgid "Logs cannot be destroyed." +msgstr "No se puede suprimir los logs." + +#: apps/logs/models.py:83 +msgid "changelog" +msgstr "diario de cambio" + +#: apps/logs/models.py:84 +msgid "changelogs" +msgstr "diario de cambios" + +#: apps/logs/models.py:87 +#, python-brace-format +msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" +msgstr "" + +#: apps/member/admin.py:50 apps/member/models.py:226 +#: apps/member/templates/member/includes/club_info.html:34 +msgid "membership fee (paid students)" +msgstr "pago de afiliación (estudiantes pagados)" + +#: apps/member/admin.py:51 apps/member/models.py:231 +#: apps/member/templates/member/includes/club_info.html:37 +msgid "membership fee (unpaid students)" +msgstr "pago de afiliación (estudiantes no pagados)" + +#: apps/member/admin.py:65 apps/member/models.py:315 +msgid "roles" +msgstr "papel" + +#: apps/member/admin.py:66 apps/member/models.py:329 +msgid "fee" +msgstr "pago" + +#: apps/member/apps.py:14 apps/wei/tables.py:181 apps/wei/tables.py:212 +msgid "member" +msgstr "miembro" + +#: apps/member/forms.py:23 +msgid "Permission mask" +msgstr "Antifaz de permisos" + +#: apps/member/forms.py:45 +msgid "Report frequency" +msgstr "Frecuencia de los informes (en días)" + +#: apps/member/forms.py:47 +msgid "Last report date" +msgstr "Fecha del último informe" + +#: apps/member/forms.py:52 +msgid "You can't register to the note if you come from the future." +msgstr "Usted no puede registrar si viene del futuro." + +#: apps/member/forms.py:77 +msgid "select an image" +msgstr "elegir una imagen" + +#: apps/member/forms.py:78 +msgid "Maximal size: 2MB" +msgstr "Tamaño máximo : 2Mo" + +#: apps/member/forms.py:103 +msgid "This image cannot be loaded." +msgstr "Esta imagen no puede ser cargada." + +#: apps/member/forms.py:139 apps/member/views.py:98 +#: apps/registration/forms.py:33 apps/registration/views.py:241 +msgid "An alias with a similar name already exists." +msgstr "Un alias similar ya existe." + +#: apps/member/forms.py:162 apps/registration/forms.py:61 +msgid "Inscription paid by Société Générale" +msgstr "Registración pagadas por Société Générale" + +#: apps/member/forms.py:164 apps/registration/forms.py:63 +msgid "Check this case if the Société Générale paid the inscription." +msgstr "Marcar esta casilla si Société Générale pagó la registración." + +#: apps/member/forms.py:169 apps/registration/forms.py:68 +#: apps/wei/forms/registration.py:83 +msgid "Credit type" +msgstr "Tipo de crédito" + +#: apps/member/forms.py:170 apps/registration/forms.py:69 +#: apps/wei/forms/registration.py:84 +msgid "No credit" +msgstr "No crédito" + +#: apps/member/forms.py:172 +msgid "You can credit the note of the user." +msgstr "Usted puede acreditar la note del usuario." + +#: apps/member/forms.py:176 apps/registration/forms.py:74 +#: apps/wei/forms/registration.py:89 +msgid "Credit amount" +msgstr "Valor del crédito" + +#: apps/member/forms.py:193 apps/note/templates/note/transaction_form.html:140 +#: apps/registration/forms.py:91 apps/treasury/forms.py:133 +#: apps/wei/forms/registration.py:106 +msgid "Bank" +msgstr "Banco" + +#: apps/member/forms.py:220 +msgid "User" +msgstr "Usuario" + +#: apps/member/forms.py:234 +msgid "Roles" +msgstr "Papeles" + +#: apps/member/models.py:38 +#: apps/member/templates/member/includes/profile_info.html:34 +#: apps/registration/templates/registration/future_profile_detail.html:40 +#: apps/wei/templates/wei/weimembership_form.html:44 +msgid "phone number" +msgstr "número de teléfono" + +#: apps/member/models.py:45 +#: apps/member/templates/member/includes/profile_info.html:28 +#: apps/registration/templates/registration/future_profile_detail.html:34 +#: apps/wei/templates/wei/weimembership_form.html:38 +msgid "section" +msgstr "sección" + +#: apps/member/models.py:46 +msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" +msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" + +#: apps/member/models.py:54 apps/wei/templates/wei/weimembership_form.html:32 +msgid "department" +msgstr "departamento" + +#: apps/member/models.py:56 +msgid "Informatics (A0)" +msgstr "Informática (A0)" + +#: apps/member/models.py:57 +msgid "Mathematics (A1)" +msgstr "Matemáticas (A1)" + +#: apps/member/models.py:58 +msgid "Physics (A2)" +msgstr "Física (A2)" + +#: apps/member/models.py:59 +msgid "Applied physics (A'2)" +msgstr "Física aplicada (A'2)" + +#: apps/member/models.py:60 +msgid "Chemistry (A''2)" +msgstr "Química (A''2)" + +#: apps/member/models.py:61 +msgid "Biology (A3)" +msgstr "Biología (A3)" + +#: apps/member/models.py:62 +msgid "SAPHIRE (B1234)" +msgstr "SAPHIRE (B1234)" + +#: apps/member/models.py:63 +msgid "Mechanics (B1)" +msgstr "Mecánica (B1)" + +#: apps/member/models.py:64 +msgid "Civil engineering (B2)" +msgstr "Ingeniería civil (B2)" + +#: apps/member/models.py:65 +msgid "Mechanical engineering (B3)" +msgstr "Ingeniería mecánica (B3)" + +#: apps/member/models.py:66 +msgid "EEA (B4)" +msgstr "EEA (B4)" + +#: apps/member/models.py:67 +msgid "Design (C)" +msgstr "Design (C)" + +#: apps/member/models.py:68 +msgid "Economy-management (D2)" +msgstr "Economía-gestión (D2)" + +#: apps/member/models.py:69 +msgid "Social sciences (D3)" +msgstr "Ciencias sociales (D3)" + +#: apps/member/models.py:70 +msgid "English (E)" +msgstr "Inglés (E)" + +#: apps/member/models.py:71 +msgid "External (EXT)" +msgstr "Extern@ (EXT)" + +#: apps/member/models.py:78 +msgid "promotion" +msgstr "promoción" + +#: apps/member/models.py:79 +msgid "Year of entry to the school (None if not ENS student)" +msgstr "Año de ingreso en la escuela (None si no un alumn@ ENS)" + +#: apps/member/models.py:83 +#: apps/member/templates/member/includes/profile_info.html:38 +#: apps/registration/templates/registration/future_profile_detail.html:37 +#: apps/wei/templates/wei/weimembership_form.html:41 +msgid "address" +msgstr "dirección" + +#: apps/member/models.py:90 +#: apps/member/templates/member/includes/profile_info.html:45 +#: apps/registration/templates/registration/future_profile_detail.html:43 +#: apps/wei/templates/wei/weimembership_form.html:47 +msgid "paid" +msgstr "pagado" + +#: apps/member/models.py:91 +msgid "Tells if the user receive a salary." +msgstr "Indica si el usuario percibe un salario." + +#: apps/member/models.py:100 apps/treasury/tables.py:146 +msgid "No" +msgstr "No" + +#: apps/member/models.py:101 +msgid "Yes (receive them in french)" +msgstr "Si (recibirles en francés)" + +#: apps/member/models.py:102 +msgid "Yes (receive them in english)" +msgstr "Si (recibirles en inglés)" + +#: apps/member/models.py:104 +msgid "" +"Register on the mailing list to stay informed of the events of the campus (1 " +"mail/week)" +msgstr "" +"Registrar el la lista de difusión de correo electrónico para quedarse " +"informado de los eventos del campus (1 correo por semana)" + +#: apps/member/models.py:109 +msgid "" +"Register on the mailing list to stay informed of the sport events of the " +"campus (1 mail/week)" +msgstr "" +"Registrar el la lista de difusión de correo electrónico para quedarse " +"informado de los eventos deportivos del campus (1 correo por semana)" + +#: apps/member/models.py:114 +msgid "" +"Register on the mailing list to stay informed of the art events of the " +"campus (1 mail/week)" +msgstr "" +"Registrar el la lista de difusión de correo electrónico para quedarse " +"informado de los eventos artísticos del campus (1 correo por semana)" + +#: apps/member/models.py:118 +msgid "report frequency (in days)" +msgstr "frecuencia de los informes (en días)" + +#: apps/member/models.py:123 +msgid "last report date" +msgstr "fecha del último informe" + +#: apps/member/models.py:128 +msgid "email confirmed" +msgstr "correo electrónico confirmado" + +#: apps/member/models.py:133 +msgid "registration valid" +msgstr "registración valida" + +#: apps/member/models.py:162 apps/member/models.py:163 +msgid "user profile" +msgstr "perfil usuario" + +#: apps/member/models.py:173 +msgid "Activate your Note Kfet account" +msgstr "Active su cuenta Note Kfet" + +#: apps/member/models.py:204 +#: apps/member/templates/member/includes/club_info.html:55 +#: apps/member/templates/member/includes/profile_info.html:31 +#: apps/registration/templates/registration/future_profile_detail.html:22 +#: apps/wei/templates/wei/base.html:70 +#: apps/wei/templates/wei/weimembership_form.html:20 +msgid "email" +msgstr "correo electrónico" + +#: apps/member/models.py:211 +msgid "parent club" +msgstr "club pariente" + +#: apps/member/models.py:220 +msgid "require memberships" +msgstr "necesita afiliaciones" + +#: apps/member/models.py:221 +msgid "Uncheck if this club don't require memberships." +msgstr "Desmarcar si este club no usa afiliaciones." + +#: apps/member/models.py:237 +#: apps/member/templates/member/includes/club_info.html:26 +msgid "membership duration" +msgstr "duración de la afiliación" + +#: apps/member/models.py:238 +msgid "The longest time (in days) a membership can last (NULL = infinite)." +msgstr "La duración máxima (en días) de una afiliación (NULL = infinito)." + +#: apps/member/models.py:245 +#: apps/member/templates/member/includes/club_info.html:16 +msgid "membership start" +msgstr "inicio de la afiliación" + +#: apps/member/models.py:246 +msgid "Date from which the members can renew their membership." +msgstr "Fecha a partir de la cual los miembros pueden prorrogar su afiliación." + +#: apps/member/models.py:252 +#: apps/member/templates/member/includes/club_info.html:21 +msgid "membership end" +msgstr "fin de la afiliación" + +#: apps/member/models.py:253 +msgid "Maximal date of a membership, after which members must renew it." +msgstr "" +"Ultima fecha de una afiliación, después de la cual los miembros tienen que " +"prorrogarla." + +#: apps/member/models.py:285 apps/member/models.py:310 +#: apps/note/models/notes.py:185 +msgid "club" +msgstr "club" + +#: apps/member/models.py:286 +msgid "clubs" +msgstr "clubs" + +#: apps/member/models.py:320 +msgid "membership starts on" +msgstr "afiliación empezá el" + +#: apps/member/models.py:324 +msgid "membership ends on" +msgstr "afiliación termina el" + +#: apps/member/models.py:419 +#, python-brace-format +msgid "The role {role} does not apply to the club {club}." +msgstr "El papel {role} no se encuentra en el club {club}." + +#: apps/member/models.py:428 apps/member/views.py:628 +msgid "User is already a member of the club" +msgstr "Usuario ya esta un miembro del club" + +#: apps/member/models.py:440 +msgid "User is not a member of the parent club" +msgstr "Usuario no es un miembro del club pariente" + +#: apps/member/models.py:488 +#, python-brace-format +msgid "Membership of {user} for the club {club}" +msgstr "Afiliación of {user} for the club {club}" + +#: apps/member/models.py:491 apps/note/models/transactions.py:353 +msgid "membership" +msgstr "afiliación" + +#: apps/member/models.py:492 +msgid "memberships" +msgstr "afiliaciones" + +#: apps/member/tables.py:121 +msgid "Renew" +msgstr "Prorrogar" + +#: apps/member/templates/member/add_members.html:16 +#, python-format +msgid "" +"The user is not a member of the club·s %(clubs)s. An additional fee of " +"%(pretty_fee)s will be charged to renew automatically the membership in this/" +"these club·s." +msgstr "" +"El usuario no esta miembro del/de los club·s parientes %(clubs)s. Un pago " +"adicional de %(pretty_fee)s sera cargado para prorrogar automáticamente la " +"afiliación a este/os club·s." + +#: apps/member/templates/member/add_members.html:21 +#, python-format +msgid "" +"This club has parents %(clubs)s. An additional fee of %(pretty_fee)s will be " +"charged to adhere automatically to this/these club·s." +msgstr "" +"Este club tiene come pariente %(clubs)s. Un pago adicional de %(pretty_fee)s " +"sera cargado para registrar automáticamente a este/os club·s." + +#: apps/member/templates/member/base.html:17 +#: apps/registration/templates/registration/future_profile_detail.html:12 +msgid "Account #" +msgstr "Cuenta n°" + +#: apps/member/templates/member/base.html:48 +#: apps/member/templates/member/base.html:62 apps/member/views.py:57 +#: apps/registration/templates/registration/future_profile_detail.html:48 +#: apps/wei/templates/wei/weimembership_form.html:117 +msgid "Update Profile" +msgstr "Modificar el perfil" + +#: apps/member/templates/member/base.html:52 +#: apps/member/templates/member/base.html:67 +msgid "View Profile" +msgstr "Ver perfil" + +#: apps/member/templates/member/base.html:57 +msgid "Add member" +msgstr "Añadir un miembro" + +#: apps/member/templates/member/base.html:72 +#: apps/member/templates/member/base.html:93 +#: apps/member/templates/member/base.html:114 +msgid "Lock note" +msgstr "Bloquear la note" + +#: apps/member/templates/member/base.html:76 +#: apps/member/templates/member/base.html:126 +#: apps/member/templates/member/base.html:138 +msgid "Unlock note" +msgstr "Desbloquear la note" + +#: apps/member/templates/member/base.html:99 +msgid "" +"Are you sure you want to lock this note? This will prevent any transaction " +"that would be performed, until the note is unlocked." +msgstr "" +"Es usted seguro de querer bloquear esta note ? Impedirá todas las " +"transacciones hasta que se desbloquea la note." + +#: apps/member/templates/member/base.html:104 +msgid "" +"If you use the force mode, the user won't be able to unlock the note by " +"itself." +msgstr "" +"Si usted bloquea la nota con el modo fuerza, el usuario no será capaz de " +"desbloquearla si mismo." + +#: apps/member/templates/member/base.html:110 +#: apps/member/templates/member/base.html:137 apps/treasury/forms.py:89 +msgid "Close" +msgstr "Cerrar" + +#: apps/member/templates/member/base.html:112 +msgid "Force mode" +msgstr "Bloquear en modo fuerza" + +#: apps/member/templates/member/base.html:132 +msgid "" +"Are you sure you want to unlock this note? Transactions will be re-enabled." +msgstr "" +"Es usted seguro de querer desbloquear esta note ? Las transacciones serán de " +"nuevo posibles." + +#: apps/member/templates/member/club_alias.html:10 +#: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:236 +#: apps/member/views.py:433 +msgid "Note aliases" +msgstr "Alias de la note" + +#: apps/member/templates/member/club_alias.html:20 +#: apps/member/templates/member/profile_alias.html:19 +#: apps/treasury/tables.py:99 +msgid "Add" +msgstr "Añadir" + +#: apps/member/templates/member/club_detail.html:13 +#: apps/permission/templates/permission/all_rights.html:32 +msgid "Club managers" +msgstr "Gerentes del club" + +#: apps/member/templates/member/club_detail.html:26 +msgid "Club members" +msgstr "Miembros del club" + +#: apps/member/templates/member/club_detail.html:40 +#: apps/member/templates/member/profile_detail.html:32 +#: apps/wei/templates/wei/weiclub_detail.html:75 +msgid "Transaction history" +msgstr "Historial de las transacciones" + +#: apps/member/templates/member/club_list.html:10 +msgid "Create club" +msgstr "Crear un club" + +#: apps/member/templates/member/club_members.html:19 +msgid "Display only active memberships" +msgstr "Mostrar unicamente las afiliaciones validas" + +#: apps/member/templates/member/club_members.html:23 +msgid "Filter roles:" +msgstr "Filtrar los papeles :" + +#: apps/member/templates/member/club_members.html:36 +#: apps/wei/templates/wei/weimembership_list.html:17 +msgid "There is no membership found with this pattern." +msgstr "No hay afiliación encontrada con esta entrada." + +#: apps/member/templates/member/includes/club_info.html:9 +msgid "Club Parent" +msgstr "Club pariente" + +#: apps/member/templates/member/includes/club_info.html:27 +msgid "days" +msgstr "días" + +#: apps/member/templates/member/includes/club_info.html:31 +#: apps/wei/templates/wei/base.html:40 +msgid "membership fee" +msgstr "pago de afiliación" + +#: apps/member/templates/member/includes/club_info.html:43 +#: apps/member/templates/member/includes/profile_info.html:42 +#: apps/treasury/templates/treasury/sogecredit_detail.html:18 +#: apps/wei/templates/wei/base.html:60 +msgid "balance" +msgstr "saldo de la cuenta" + +#: apps/member/templates/member/includes/club_info.html:47 +#: apps/member/templates/member/includes/profile_info.html:20 +#: apps/note/models/notes.py:276 apps/wei/templates/wei/base.html:66 +msgid "aliases" +msgstr "alias" + +#: apps/member/templates/member/includes/club_info.html:51 +#: apps/member/templates/member/includes/profile_info.html:24 +msgid "Manage aliases" +msgstr "Gestionar los alias" + +#: apps/member/templates/member/includes/profile_info.html:7 +#: apps/registration/templates/registration/future_profile_detail.html:19 +#: apps/wei/templates/wei/weimembership_form.html:17 +msgid "username" +msgstr "nombre de usuario" + +#: apps/member/templates/member/includes/profile_info.html:11 +msgid "password" +msgstr "contraseña" + +#: apps/member/templates/member/includes/profile_info.html:15 +msgid "Change password" +msgstr "Cambiar la contraseña" + +#: apps/member/templates/member/includes/profile_info.html:53 +msgid "API token" +msgstr "Acceso API" + +#: apps/member/templates/member/manage_auth_tokens.html:19 +msgid "Token" +msgstr "Token" + +#: apps/member/templates/member/manage_auth_tokens.html:26 +msgid "Created" +msgstr "Creado el" + +#: apps/member/templates/member/manage_auth_tokens.html:34 +msgid "Regenerate token" +msgstr "Regenerar token" + +#: apps/member/templates/member/picture_update.html:35 +msgid "Nevermind" +msgstr "No importa" + +#: apps/member/templates/member/picture_update.html:36 +msgid "Crop and upload" +msgstr "Podar y subir" + +#: apps/member/templates/member/profile_detail.html:11 +#: apps/registration/templates/registration/future_profile_detail.html:28 +#: apps/wei/templates/wei/weimembership_form.html:26 +msgid "This user doesn't have confirmed his/her e-mail address." +msgstr "Este usuario no confirmó su correo electrónico." + +#: apps/member/templates/member/profile_detail.html:13 +#: apps/registration/templates/registration/future_profile_detail.html:29 +#: apps/wei/templates/wei/weimembership_form.html:27 +msgid "Click here to resend a validation link." +msgstr "Hacer clic aquí para reenviar un enlace de validación." + +#: apps/member/templates/member/profile_detail.html:21 +msgid "View my memberships" +msgstr "Ver mis afiliaciones" + +#: apps/member/templates/member/profile_update.html:18 +msgid "Save Changes" +msgstr "Guardar cambios" + +#: apps/member/templates/member/user_list.html:10 +msgid "Registrations" +msgstr "Registraciones" + +#: apps/member/views.py:70 apps/registration/forms.py:23 +msgid "This address must be valid." +msgstr "Este correo tiene que ser valido." + +#: apps/member/views.py:135 +msgid "Profile detail" +msgstr "Detalles del usuario" + +#: apps/member/views.py:195 +msgid "Search user" +msgstr "Buscar un usuario" + +#: apps/member/views.py:256 +msgid "Update note picture" +msgstr "Modificar la imagen de la note" + +#: apps/member/views.py:301 +msgid "Manage auth token" +msgstr "Gestionar los token de autentificación" + +#: apps/member/views.py:328 +msgid "Create new club" +msgstr "Crear un nuevo club" + +#: apps/member/views.py:347 +msgid "Search club" +msgstr "Buscar un club" + +#: apps/member/views.py:380 +msgid "Club detail" +msgstr "Detalles del club" + +#: apps/member/views.py:456 +msgid "Update club" +msgstr "Modificar el club" + +#: apps/member/views.py:490 +msgid "Add new member to the club" +msgstr "Añadir un nuevo miembro al club" + +#: apps/member/views.py:619 apps/wei/views.py:922 +msgid "" +"This user don't have enough money to join this club, and can't have a " +"negative balance." +msgstr "" +"Este usuario no tiene suficiente dinero para unirse a este club, y no puede " +"tener un saldo negativo." + +#: apps/member/views.py:632 +msgid "The membership must start after {:%m-%d-%Y}." +msgstr "La afiliación tiene que empezar después del {:%d-%m-%Y}." + +#: apps/member/views.py:637 +msgid "The membership must begin before {:%m-%d-%Y}." +msgstr "La afiliación tiene que empezar antes del {:%d-%m-%Y}." + +#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648 +#: apps/registration/views.py:291 apps/registration/views.py:293 +#: apps/registration/views.py:295 apps/wei/views.py:927 apps/wei/views.py:931 +msgid "This field is required." +msgstr "Este campo es obligatorio." + +#: apps/member/views.py:783 +msgid "Manage roles of an user in the club" +msgstr "Gestionar los papeles de un usuario en el club" + +#: apps/member/views.py:808 +msgid "Members of the club" +msgstr "Miembros del club" + +#: apps/note/admin.py:129 apps/note/models/transactions.py:109 +msgid "source" +msgstr "fuente" + +#: apps/note/admin.py:137 apps/note/admin.py:205 +#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:122 +msgid "destination" +msgstr "destino" + +#: apps/note/admin.py:210 apps/note/models/transactions.py:60 +#: apps/note/models/transactions.py:140 +msgid "amount" +msgstr "monto" + +#: apps/note/api/serializers.py:183 apps/note/api/serializers.py:189 +#: apps/note/models/transactions.py:226 +msgid "" +"The transaction can't be saved since the source note or the destination note " +"is not active." +msgstr "" +"La transacción no puede ser guardada puesto que la note fuente o la note " +"destino no esta activa." + +#: apps/note/forms.py:39 +msgid "Source" +msgstr "Fuente" + +#: apps/note/forms.py:53 +msgid "Destination" +msgstr "Destino" + +#: apps/note/forms.py:74 apps/note/templates/note/transaction_form.html:119 +msgid "Reason" +msgstr "Motivo" + +#: apps/note/forms.py:79 apps/treasury/tables.py:139 +msgid "Valid" +msgstr "Valido" + +#: apps/note/forms.py:85 +msgid "Total amount greater than" +msgstr "Monto total mayor que" + +#: apps/note/forms.py:93 +msgid "Total amount less than" +msgstr "Monto total menor que" + +#: apps/note/forms.py:99 +msgid "Created after" +msgstr "Creado después" + +#: apps/note/forms.py:106 +msgid "Created before" +msgstr "Creado antes" + +#: apps/note/models/notes.py:32 +msgid "account balance" +msgstr "saldo de la cuenta" + +#: apps/note/models/notes.py:33 +msgid "in centimes, money credited for this instance" +msgstr "en céntimos, dinero acreditado por este instancia" + +#: apps/note/models/notes.py:38 +msgid "last negative date" +msgstr "última fecha en negativo" + +#: apps/note/models/notes.py:39 +msgid "last time the balance was negative" +msgstr "último momento en el cual el saldo estaba negativo" + +#: apps/note/models/notes.py:45 +msgid "display image" +msgstr "imagen mostrada" + +#: apps/note/models/notes.py:54 apps/note/models/transactions.py:132 +msgid "created at" +msgstr "creada el" + +#: apps/note/models/notes.py:59 +msgid "active" +msgstr "activo" + +#: apps/note/models/notes.py:62 +msgid "" +"Designates whether this note should be treated as active. Unselect this " +"instead of deleting notes." +msgstr "" +"Indica si la note tiene que ser considerada como activa. Desmarcar en vez de " +"suprimir la note." + +#: apps/note/models/notes.py:69 +msgid "" +"The user blocked his/her note manually, eg. when he/she left the school for " +"holidays. It can be reactivated at any time." +msgstr "" +"El usuario bloqueó su note, por ejemplo cuando se fue de vacaciones. Puede " +"ser desbloqueada en cualquier momento." + +#: apps/note/models/notes.py:71 +msgid "The note is blocked by the the BDE and can't be manually reactivated." +msgstr "" +"La note esta bloqueada por el BDE y no puede ser desbloqueada por el usuario." + +#: apps/note/models/notes.py:79 +msgid "notes" +msgstr "notes" + +#: apps/note/models/notes.py:128 +msgid "This alias is already taken." +msgstr "Este alias ya esta utilizado." + +#: apps/note/models/notes.py:148 +msgid "one's note" +msgstr "note de un usuario" + +#: apps/note/models/notes.py:149 +msgid "users note" +msgstr "notes de los usuarios" + +#: apps/note/models/notes.py:155 +#, python-format +msgid "%(user)s's note" +msgstr "Note de %(user)s" + +#: apps/note/models/notes.py:189 +msgid "club note" +msgstr "note de un club" + +#: apps/note/models/notes.py:190 +msgid "clubs notes" +msgstr "notes de los clubs" + +#: apps/note/models/notes.py:196 +#, python-format +msgid "Note of %(club)s club" +msgstr "Note del club %(club)s" + +#: apps/note/models/notes.py:235 +msgid "special note" +msgstr "note especial" + +#: apps/note/models/notes.py:236 +msgid "special notes" +msgstr "notes especiales" + +#: apps/note/models/notes.py:259 +msgid "Invalid alias" +msgstr "Alias inválido" + +#: apps/note/models/notes.py:275 +msgid "alias" +msgstr "alias" + +#: apps/note/models/notes.py:299 +msgid "Alias is too long." +msgstr "El alias es demasiado largo." + +#: apps/note/models/notes.py:302 +msgid "" +"This alias contains only complex character. Please use a more simple alias." +msgstr "" +"Este alias solo contiene caracteres complejos. Por favor usa un alias más " +"sencillo." + +#: apps/note/models/notes.py:306 +msgid "An alias with a similar name already exists: {} " +msgstr "Un alias parecido ya existe : {} " + +#: apps/note/models/notes.py:319 +msgid "You can't delete your main alias." +msgstr "No puede suprimir su alias principal." + +#: apps/note/models/transactions.py:32 +msgid "transaction category" +msgstr "tipo de transacción" + +#: apps/note/models/transactions.py:33 +msgid "transaction categories" +msgstr "tipos de transacción" + +#: apps/note/models/transactions.py:49 +msgid "A template with this name already exist" +msgstr "Un plantilla de transacción con un nombre similar ya existe" + +#: apps/note/models/transactions.py:72 +msgid "display" +msgstr "mostrar" + +#: apps/note/models/transactions.py:77 +msgid "highlighted" +msgstr "resaltar" + +#: apps/note/models/transactions.py:87 +msgid "transaction template" +msgstr "plantilla de transacción" + +#: apps/note/models/transactions.py:88 +msgid "transaction templates" +msgstr "plantillas de transacción" + +#: apps/note/models/transactions.py:115 apps/note/models/transactions.py:128 +#: apps/note/tables.py:34 apps/note/tables.py:44 +msgid "used alias" +msgstr "alias usado" + +#: apps/note/models/transactions.py:136 +msgid "quantity" +msgstr "cantidad" + +#: apps/note/models/transactions.py:144 +msgid "reason" +msgstr "motivo" + +#: apps/note/models/transactions.py:154 apps/note/tables.py:140 +msgid "invalidity reason" +msgstr "motivo de invalidación" + +#: apps/note/models/transactions.py:161 +msgid "transaction" +msgstr "transacción" + +#: apps/note/models/transactions.py:162 +#: apps/treasury/templates/treasury/sogecredit_detail.html:22 +msgid "transactions" +msgstr "transacciones" + +#: apps/note/models/transactions.py:184 +#, python-brace-format +msgid "" +"You can't update the {field} on a Transaction. Please invalidate it and " +"create one other." +msgstr "" +"No se puede cambiar el {field} de una transacción. Por favor invalide esta y " +"cree una nueva." + +#: apps/note/models/transactions.py:204 +msgid "" +"The note balances must be between - 92 233 720 368 547 758.08 € and 92 233 " +"720 368 547 758.07 €." +msgstr "" +"El saldo de la note tiene que ser entre - 92 233 720 368 547 758.08 € y 92 " +"233 720 368 547 758.07 €." + +#: apps/note/models/transactions.py:273 +msgid "" +"The destination of this transaction must equal to the destination of the " +"template." +msgstr "" + +#: apps/note/models/transactions.py:282 +msgid "Template" +msgstr "" + +#: apps/note/models/transactions.py:285 +msgid "recurrent transaction" +msgstr "" + +#: apps/note/models/transactions.py:286 +msgid "recurrent transactions" +msgstr "" + +#: apps/note/models/transactions.py:301 +msgid "first_name" +msgstr "nombre" + +#: apps/note/models/transactions.py:306 +msgid "bank" +msgstr "banco" + +#: apps/note/models/transactions.py:323 +msgid "" +"A special transaction is only possible between a Note associated to a " +"payment method and a User or a Club" +msgstr "" +"Una transacción especial solo esta disponible entre una note de un modo de " +"pago y un usuario o un club" + +#: apps/note/models/transactions.py:331 +msgid "Special transaction" +msgstr "Transacción especial" + +#: apps/note/models/transactions.py:332 +msgid "Special transactions" +msgstr "Transacciones especiales" + +#: apps/note/models/transactions.py:348 +msgid "membership transaction" +msgstr "transacción de afiliación" + +#: apps/note/models/transactions.py:349 apps/treasury/models.py:282 +msgid "membership transactions" +msgstr "transacciones de afiliación" + +#: apps/note/tables.py:94 +msgid "Click to invalidate" +msgstr "Hacer clic para invalidar" + +#: apps/note/tables.py:94 +msgid "Click to validate" +msgstr "Hacer clic para validar" + +#: apps/note/tables.py:138 +msgid "No reason specified" +msgstr "Ningún motivo dado" + +#: apps/note/tables.py:169 apps/note/tables.py:203 apps/treasury/tables.py:39 +#: apps/treasury/templates/treasury/invoice_confirm_delete.html:30 +#: apps/treasury/templates/treasury/sogecredit_detail.html:59 +#: apps/wei/tables.py:76 apps/wei/tables.py:103 +#: apps/wei/templates/wei/weiregistration_confirm_delete.html:31 +msgid "Delete" +msgstr "Suprimir" + +#: apps/note/tables.py:197 apps/note/templates/note/conso_form.html:132 +#: apps/wei/tables.py:47 apps/wei/tables.py:48 +#: apps/wei/templates/wei/base.html:89 +#: apps/wei/templates/wei/bus_detail.html:20 +#: apps/wei/templates/wei/busteam_detail.html:20 +#: apps/wei/templates/wei/busteam_detail.html:40 +msgid "Edit" +msgstr "Editar" + +#: apps/note/templates/note/conso_form.html:22 +#: apps/note/templates/note/transaction_form.html:44 +msgid "Please select a note" +msgstr "Por favor elige una note" + +#: apps/note/templates/note/conso_form.html:32 +msgid "Consum" +msgstr "Consumir" + +#: apps/note/templates/note/conso_form.html:43 +#: apps/note/templates/note/transaction_form.html:65 +#: apps/note/templates/note/transaction_form.html:92 +msgid "Name or alias..." +msgstr "Nombre o alias..." + +#: apps/note/templates/note/conso_form.html:53 +msgid "Select consumptions" +msgstr "Escoger consumiciones" + +#: apps/note/templates/note/conso_form.html:62 +msgid "Consume!" +msgstr "¡ Consumir !" + +#: apps/note/templates/note/conso_form.html:73 +msgid "Highlighted buttons" +msgstr "Botones resaltados" + +#: apps/note/templates/note/conso_form.html:138 +msgid "Single consumptions" +msgstr "Consumiciones simples" + +#: apps/note/templates/note/conso_form.html:143 +msgid "Double consumptions" +msgstr "Consumiciones dobles" + +#: apps/note/templates/note/conso_form.html:154 +#: apps/note/templates/note/transaction_form.html:159 +msgid "Recent transactions history" +msgstr "Historial de las transacciones recientes" + +#: apps/note/templates/note/mails/negative_balance.html:43 +#: apps/note/templates/note/mails/negative_balance.txt:25 +#: apps/note/templates/note/mails/negative_notes_report.html:46 +#: apps/note/templates/note/mails/negative_notes_report.txt:13 +#: apps/note/templates/note/mails/weekly_report.html:51 +#: apps/note/templates/note/mails/weekly_report.txt:32 +#: apps/registration/templates/registration/mails/email_validation_email.html:40 +#: apps/registration/templates/registration/mails/email_validation_email.txt:16 +msgid "Mail generated by the Note Kfet on the" +msgstr "Correo electrónico enviado por la Note Kfet el" + +#: apps/note/templates/note/transaction_form.html:54 +#: apps/note/templates/note/transaction_form.html:174 +msgid "Select emitters" +msgstr "Elegir les remitentes" + +#: apps/note/templates/note/transaction_form.html:69 +msgid "I am the emitter" +msgstr "Estoy la fuente" + +#: apps/note/templates/note/transaction_form.html:81 +#: apps/note/templates/note/transaction_form.html:176 +msgid "Select receivers" +msgstr "Elegir destinatarios" + +#: apps/note/templates/note/transaction_form.html:104 +msgid "Action" +msgstr "Acción" + +#: apps/note/templates/note/transaction_form.html:112 +#: apps/treasury/forms.py:135 apps/treasury/tables.py:67 +#: apps/treasury/tables.py:135 +#: apps/treasury/templates/treasury/remittance_form.html:23 +msgid "Amount" +msgstr "Monto" + +#: apps/note/templates/note/transaction_form.html:128 +#: apps/treasury/models.py:51 +msgid "Name" +msgstr "Nombre" + +#: apps/note/templates/note/transaction_form.html:173 +msgid "Select emitter" +msgstr "Elegir el remitente" + +#: apps/note/templates/note/transaction_form.html:175 +msgid "Select receiver" +msgstr "Elegir destinatario" + +#: apps/note/templates/note/transaction_form.html:177 +msgid "Transfer type" +msgstr "Tipo de transferencia" + +#: apps/note/templates/note/transactiontemplate_form.html:8 +msgid "Buttons list" +msgstr "Lista de los botones" + +#: apps/note/templates/note/transactiontemplate_form.html:24 +msgid "Price history" +msgstr "Historial de los precios" + +#: apps/note/templates/note/transactiontemplate_form.html:27 +msgid "Obsolete since" +msgstr "Obsoleto desde" + +#: apps/note/templates/note/transactiontemplate_form.html:27 +msgid "Current price" +msgstr "Precio actual" + +#: apps/note/templates/note/transactiontemplate_list.html:13 +msgid "Name of the button..." +msgstr "Nombre del botón..." + +#: apps/note/templates/note/transactiontemplate_list.html:15 +msgid "New button" +msgstr "Nuevo botón" + +#: apps/note/templates/note/transactiontemplate_list.html:22 +msgid "buttons listing " +msgstr "lista de los botones " + +#: apps/note/templates/note/transactiontemplate_list.html:73 +msgid "button successfully deleted " +msgstr "botón suprimido con éxito " + +#: apps/note/templates/note/transactiontemplate_list.html:77 +msgid "Unable to delete button " +msgstr "Imposible de suprimir el botón " + +#: apps/note/views.py:36 +msgid "Transfer money" +msgstr "Transferir dinero" + +#: apps/note/views.py:74 +msgid "Create new button" +msgstr "Crear un nuevo botón" + +#: apps/note/views.py:83 +msgid "Search button" +msgstr "Buscar un botón" + +#: apps/note/views.py:111 +msgid "Update button" +msgstr "Modificar el botón" + +#: apps/note/views.py:151 note_kfet/templates/base.html:64 +msgid "Consumptions" +msgstr "Consumiciones" + +#: apps/note/views.py:165 +msgid "You can't see any button." +msgstr "Usted no puede ver ningún botón." + +#: apps/note/views.py:200 +msgid "Search transactions" +msgstr "Buscar transacciones" + +#: apps/permission/models.py:89 +#, python-brace-format +msgid "Can {type} {model}.{field} in {query}" +msgstr "" + +#: apps/permission/models.py:91 +#, python-brace-format +msgid "Can {type} {model} in {query}" +msgstr "" + +#: apps/permission/models.py:104 +msgid "rank" +msgstr "posición" + +#: apps/permission/models.py:117 +msgid "permission mask" +msgstr "antifaz de permisos" + +#: apps/permission/models.py:118 +msgid "permission masks" +msgstr "antifaces de permisos" + +#: apps/permission/models.py:124 +msgid "add" +msgstr "añadir" + +#: apps/permission/models.py:125 +msgid "view" +msgstr "ver" + +#: apps/permission/models.py:126 +msgid "change" +msgstr "cambiar" + +#: apps/permission/models.py:158 +msgid "query" +msgstr "consulta" + +#: apps/permission/models.py:171 +msgid "mask" +msgstr "antifaz" + +#: apps/permission/models.py:177 +msgid "field" +msgstr "campo" + +#: apps/permission/models.py:182 +msgid "" +"Tells if the permission should be granted even if the membership of the user " +"is expired." +msgstr "" +"Indica si el permiso tiene que ser dado aunque la afiliación del usuario " +"terminó." + +#: apps/permission/models.py:183 +#: apps/permission/templates/permission/all_rights.html:89 +msgid "permanent" +msgstr "permanente" + +#: apps/permission/models.py:194 +msgid "permission" +msgstr "permiso" + +#: apps/permission/models.py:195 apps/permission/models.py:334 +msgid "permissions" +msgstr "permisos" + +#: apps/permission/models.py:200 +msgid "Specifying field applies only to view and change permission types." +msgstr "" +"Especifica el campo interesado, solo funciona para los permisos view y " +"change." + +#: apps/permission/models.py:339 +msgid "for club" +msgstr "interesa el club" + +#: apps/permission/models.py:349 apps/permission/models.py:350 +msgid "role permissions" +msgstr "permisos por papeles" + +#: apps/permission/signals.py:63 +#, python-brace-format +msgid "" +"You don't have the permission to change the field {field} on this instance " +"of model {app_label}.{model_name}." +msgstr "" +"Usted no tiene permiso a cambiar el campo {field} on this instance of model " +"{app_label}.{model_name}." + +#: apps/permission/signals.py:73 apps/permission/views.py:101 +#, python-brace-format +msgid "" +"You don't have the permission to add an instance of model {app_label}." +"{model_name}." +msgstr "" +"Usted no tiene permiso a añadir an instance of model {app_label}." +"{model_name}." + +#: apps/permission/signals.py:102 +#, python-brace-format +msgid "" +"You don't have the permission to delete this instance of model {app_label}." +"{model_name}." +msgstr "" +"Usted no tiene permiso a suprimir este instance of model {app_label}." +"{model_name}." + +#: apps/permission/templates/permission/all_rights.html:12 +msgid "Users that have surnormal rights" +msgstr "Lista de los usuarios poseyendo permisos majores" + +#: apps/permission/templates/permission/all_rights.html:16 +msgid "Superusers have all rights on everything, to manage the website." +msgstr "" +"Super-usuarios tienen todos los permisos sobre todo para gestionar el " +"sistema." + +#: apps/permission/templates/permission/all_rights.html:21 +msgid "Superusers" +msgstr "Super-usuarios" + +#: apps/permission/templates/permission/all_rights.html:45 +msgid "Roles description" +msgstr "Descripción de todos los papeles" + +#: apps/permission/templates/permission/all_rights.html:52 +msgid "Filter with roles that I have in at least one club" +msgstr "Filtrar los papeles que tengo en al menos un club" + +#: apps/permission/templates/permission/all_rights.html:69 +msgid "Owned" +msgstr "Tenido" + +#: apps/permission/templates/permission/all_rights.html:80 +msgid "Own this role in the clubs" +msgstr "Tiene este papel en los clubs" + +#: apps/permission/templates/permission/all_rights.html:86 +msgid "Mask:" +msgstr "Antifaz :" + +#: apps/permission/templates/permission/all_rights.html:86 +msgid "Query:" +msgstr "Consulta :" + +#: apps/permission/templates/permission/all_rights.html:92 +msgid "No associated permission" +msgstr "No hay permiso relacionado" + +#: apps/permission/views.py:68 +#, python-brace-format +msgid "" +"You don't have the permission to update this instance of the model " +"\"{model}\" with these parameters. Please correct your data and retry." +msgstr "" + +#: apps/permission/views.py:72 +#, python-brace-format +msgid "" +"You don't have the permission to create an instance of the model \"{model}\" " +"with these parameters. Please correct your data and retry." +msgstr "" + +#: apps/permission/views.py:108 note_kfet/templates/base.html:106 +msgid "Rights" +msgstr "Permisos" + +#: apps/permission/views.py:113 +msgid "All rights" +msgstr "Todos los permisos" + +#: apps/registration/apps.py:10 +msgid "registration" +msgstr "afiliación" + +#: apps/registration/forms.py:39 +msgid "This email address is already used." +msgstr "Este correo electrónico ya esta utilizado." + +#: apps/registration/forms.py:49 +msgid "Register to the WEI" +msgstr "Registrarse en el WEI" + +#: apps/registration/forms.py:51 +msgid "" +"Check this case if you want to register to the WEI. If you hesitate, you " +"will be able to register later, after validating your account in the Kfet." +msgstr "" +"Marcar esta casilla si usted quiere registrarse en el WEI. Si duda, podrá " +"registrarse más tarde, después de validar su cuenta Note Kfet." + +#: apps/registration/forms.py:96 +msgid "Join BDE Club" +msgstr "Afiliarse al club BDE" + +#: apps/registration/forms.py:103 +msgid "Join Kfet Club" +msgstr "Afiliarse al club Kfet" + +#: apps/registration/templates/registration/email_validation_complete.html:15 +msgid "Your email have successfully been validated." +msgstr "Su correo electrónico fue validado con éxito." + +#: apps/registration/templates/registration/email_validation_complete.html:19 +#, python-format +msgid "You can now log in." +msgstr "Puede desde ahora conectarse." + +#: apps/registration/templates/registration/email_validation_complete.html:23 +msgid "" +"You must pay now your membership in the Kfet to complete your registration." +msgstr "Tiene que pagar su afiliación a la Kfet para acabar con su afiliación." + +#: apps/registration/templates/registration/email_validation_complete.html:28 +msgid "" +"The link was invalid. The token may have expired. Please send us an email to " +"activate your account." +msgstr "" +"El enlace era invalido. El token quizá expiró. Por favor envíenos un correo " +"electrónico para activar su cuenta." + +#: apps/registration/templates/registration/email_validation_email_sent.html:10 +msgid "Account activation" +msgstr "Activación de la cuenta" + +#: apps/registration/templates/registration/email_validation_email_sent.html:14 +msgid "" +"An email has been sent. Please click on the link to activate your account." +msgstr "" +"Un correo electrónico le fue enviado. Por favor haga clic en el enlace para " +"activar su cuenta." + +#: apps/registration/templates/registration/email_validation_email_sent.html:17 +msgid "You must also go to the Kfet to pay your membership." +msgstr "" +"También tendrá que ir en la Kfet para pagar su afiliación. La afiliación al " +"WEI incluye una afiliación al BDE." + +#: apps/registration/templates/registration/future_profile_detail.html:49 +#: apps/wei/templates/wei/weiregistration_confirm_delete.html:11 +msgid "Delete registration" +msgstr "Suprimir afiliación" + +#: apps/registration/templates/registration/future_profile_detail.html:57 +msgid "Validate account" +msgstr "Validar la cuenta" + +#: apps/registration/templates/registration/future_profile_detail.html:64 +#: apps/wei/templates/wei/weimembership_form.html:127 +#: apps/wei/templates/wei/weimembership_form.html:186 +msgid "Validate registration" +msgstr "Validar la afiliación" + +#: apps/registration/templates/registration/future_user_list.html:9 +msgid "New user" +msgstr "Nuevo usuario" + +#: apps/registration/templates/registration/mails/email_validation_email.html:12 +#: apps/registration/templates/registration/mails/email_validation_email.txt:3 +msgid "Hi" +msgstr "Hola" + +#: apps/registration/templates/registration/mails/email_validation_email.html:16 +#: apps/registration/templates/registration/mails/email_validation_email.txt:5 +msgid "" +"You recently registered on the Note Kfet. Please click on the link below to " +"confirm your registration." +msgstr "" +"Usted registró recientemente a la Note Kfet. Por favor haga clic en el " +"enlace más abajo para validar sur afiliación." + +#: apps/registration/templates/registration/mails/email_validation_email.html:26 +#: apps/registration/templates/registration/mails/email_validation_email.txt:9 +msgid "" +"This link is only valid for a couple of days, after that you will need to " +"contact us to validate your email." +msgstr "" +"El enlace queda valido solamente unos días, después tendrá que contactarnos." + +#: apps/registration/templates/registration/mails/email_validation_email.html:30 +#: apps/registration/templates/registration/mails/email_validation_email.txt:11 +msgid "" +"After that, you'll have to wait that someone validates your account before " +"you can log in. You will need to pay your membership in the Kfet." +msgstr "" +"Después de esto, tendrá que esperar que alguien validará su cuenta antes que " +"usted pueda conectarse. Tendrá que pagar su afiliación en la Kfet. La " +"afiliación al WEI incluye una afiliación a la Kfet." + +#: apps/registration/templates/registration/mails/email_validation_email.html:34 +#: apps/registration/templates/registration/mails/email_validation_email.txt:13 +msgid "Thanks" +msgstr "Gracias" + +#: apps/registration/templates/registration/mails/email_validation_email.html:39 +#: apps/registration/templates/registration/mails/email_validation_email.txt:15 +msgid "The Note Kfet team." +msgstr "El equipo Note Kfet." + +#: apps/registration/views.py:39 +msgid "Register new user" +msgstr "Registrar un nuevo usuario" + +#: apps/registration/views.py:83 +msgid "Email validation" +msgstr "Validación del correo electrónico" + +#: apps/registration/views.py:85 +msgid "Validate email" +msgstr "Validar el correo electrónico" + +#: apps/registration/views.py:127 +msgid "Email validation unsuccessful" +msgstr "La validación del correo electrónico fracasó" + +#: apps/registration/views.py:138 +msgid "Email validation email sent" +msgstr "Correo de validación enviado" + +#: apps/registration/views.py:146 +msgid "Resend email validation link" +msgstr "Reenviar el enlace de validación" + +#: apps/registration/views.py:164 +msgid "Pre-registered users list" +msgstr "Lista de los usuarios con afiliación pendiente" + +#: apps/registration/views.py:188 +msgid "Unregistered users" +msgstr "Usuarios con afiliación pendiente" + +#: apps/registration/views.py:201 +msgid "Registration detail" +msgstr "Detalles de la afiliación" + +#: apps/registration/views.py:260 +msgid "You must join the BDE." +msgstr "Usted tiene que afiliarse al BDE." + +#: apps/registration/views.py:284 +msgid "" +"The entered amount is not enough for the memberships, should be at least {}" +msgstr "" +"El monto dado no es suficiente para las afiliaciones, tiene que ser al menos " +"{}" + +#: apps/registration/views.py:364 +msgid "Invalidate pre-registration" +msgstr "Invalidar la afiliación" + +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:94 +msgid "Treasury" +msgstr "Tesorería" + +#: apps/treasury/forms.py:24 apps/treasury/models.py:89 +#: apps/treasury/templates/treasury/invoice_form.html:22 +msgid "This invoice is locked and can no longer be edited." +msgstr "Esta factura esta bloqueada y no puede ser modificada." + +#: apps/treasury/forms.py:98 +msgid "Remittance is already closed." +msgstr "El descuento ya esta cerrado." + +#: apps/treasury/forms.py:103 +msgid "You can't change the type of the remittance." +msgstr "No puede cambiar el tipo de descuento." + +#: apps/treasury/forms.py:123 apps/treasury/models.py:258 +#: apps/treasury/tables.py:97 apps/treasury/tables.py:105 +#: apps/treasury/templates/treasury/invoice_list.html:16 +#: apps/treasury/templates/treasury/remittance_list.html:16 +#: apps/treasury/templates/treasury/sogecredit_list.html:16 +msgid "Remittance" +msgstr "Descuento" + +#: apps/treasury/forms.py:124 +msgid "No attached remittance" +msgstr "No hay descuento relacionado" + +#: apps/treasury/models.py:23 +msgid "Invoice identifier" +msgstr "Numero de factura" + +#: apps/treasury/models.py:37 +msgid "BDE" +msgstr "BDE" + +#: apps/treasury/models.py:42 +msgid "Object" +msgstr "Asunto" + +#: apps/treasury/models.py:46 +msgid "Description" +msgstr "Descripción" + +#: apps/treasury/models.py:55 +msgid "Address" +msgstr "Dirección" + +#: apps/treasury/models.py:60 apps/treasury/models.py:186 +msgid "Date" +msgstr "Fecha" + +#: apps/treasury/models.py:64 +msgid "Acquitted" +msgstr "Pagada" + +#: apps/treasury/models.py:69 +msgid "Locked" +msgstr "Bloqueada" + +#: apps/treasury/models.py:70 +msgid "An invoice can't be edited when it is locked." +msgstr "Une factura no puede ser modificada cuando esta bloqueada." + +#: apps/treasury/models.py:76 +msgid "tex source" +msgstr "código fuente TeX" + +#: apps/treasury/models.py:109 apps/treasury/models.py:125 +msgid "invoice" +msgstr "factura" + +#: apps/treasury/models.py:110 +msgid "invoices" +msgstr "facturas" + +#: apps/treasury/models.py:113 +#, python-brace-format +msgid "Invoice #{id}" +msgstr "Factura n°{id}" + +#: apps/treasury/models.py:130 +msgid "Designation" +msgstr "Designación" + +#: apps/treasury/models.py:134 +msgid "Quantity" +msgstr "Cantidad" + +#: apps/treasury/models.py:138 +msgid "Unit price" +msgstr "Precio unitario" + +#: apps/treasury/models.py:154 +msgid "product" +msgstr "producto" + +#: apps/treasury/models.py:155 +msgid "products" +msgstr "productos" + +#: apps/treasury/models.py:175 +msgid "remittance type" +msgstr "tipo de descuento" + +#: apps/treasury/models.py:176 +msgid "remittance types" +msgstr "tipos de descuentos" + +#: apps/treasury/models.py:197 +msgid "Comment" +msgstr "Comentario" + +#: apps/treasury/models.py:202 +msgid "Closed" +msgstr "Cerrada" + +#: apps/treasury/models.py:206 +msgid "remittance" +msgstr "descuento" + +#: apps/treasury/models.py:207 +msgid "remittances" +msgstr "descuentos" + +#: apps/treasury/models.py:239 +msgid "Remittance #{:d}: {}" +msgstr "Descuento n°{:d} : {}" + +#: apps/treasury/models.py:262 +msgid "special transaction proxy" +msgstr "proxy de transacción especial" + +#: apps/treasury/models.py:263 +msgid "special transaction proxies" +msgstr "proxys de transacciones especiales" + +#: apps/treasury/models.py:288 +msgid "credit transaction" +msgstr "transacción de crédito" + +#: apps/treasury/models.py:361 +msgid "" +"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." +msgstr "" +"Este usuario no tiene suficiente dinero en su note para pagar las " +"afiliaciones. Por favor pídelo acreditar su note antes de invalidar este " +"crédito." + +#: apps/treasury/models.py:376 +#: apps/treasury/templates/treasury/sogecredit_detail.html:10 +msgid "Credit from the Société générale" +msgstr "Crédito de la Société Générale" + +#: apps/treasury/models.py:377 +msgid "Credits from the Société générale" +msgstr "Créditos de la Société Générale" + +#: apps/treasury/models.py:380 +#, python-brace-format +msgid "Soge credit for {user}" +msgstr "Crédito de la Société Générale para {user}" + +#: apps/treasury/tables.py:20 +msgid "Invoice #{:d}" +msgstr "Factura n°{:d}" + +#: apps/treasury/tables.py:25 +#: apps/treasury/templates/treasury/invoice_list.html:13 +#: apps/treasury/templates/treasury/remittance_list.html:13 +#: apps/treasury/templates/treasury/sogecredit_list.html:13 +msgid "Invoice" +msgstr "Factura" + +#: apps/treasury/tables.py:65 +msgid "Transaction count" +msgstr "Cantidad de transacciones" + +#: apps/treasury/tables.py:70 apps/treasury/tables.py:72 +msgid "View" +msgstr "Ver" + +#: apps/treasury/tables.py:146 +msgid "Yes" +msgstr "Sí" + +#: apps/treasury/templates/treasury/invoice_confirm_delete.html:10 +#: apps/treasury/views.py:176 +msgid "Delete invoice" +msgstr "Suprimir la factura" + +#: apps/treasury/templates/treasury/invoice_confirm_delete.html:15 +#: apps/treasury/views.py:180 +msgid "This invoice is locked and can't be deleted." +msgstr "Esta factura esta bloqueada y no puede ser suprimida." + +#: apps/treasury/templates/treasury/invoice_confirm_delete.html:21 +msgid "" +"Are you sure you want to delete this invoice? This action can't be undone." +msgstr "" +"¿ Usted está seguro de querer suprimir esta factura ? Este acto es " +"definitivo." + +#: apps/treasury/templates/treasury/invoice_confirm_delete.html:28 +msgid "Return to invoices list" +msgstr "Regresar a la lista de las facturas" + +#: apps/treasury/templates/treasury/invoice_form.html:15 +msgid "" +"Warning: the LaTeX template is saved with this object. Updating the invoice " +"implies regenerate it. Be careful if you manipulate old invoices." +msgstr "" +"Cuidado : la plantilla LaTeX es guardada con este objeto. Modificar la " +"factura supone regenerarla. Tenga cuidado si trata con facturas antiguas." + +#: apps/treasury/templates/treasury/invoice_form.html:69 +msgid "Add product" +msgstr "Añadir un producto" + +#: apps/treasury/templates/treasury/invoice_form.html:70 +msgid "Remove product" +msgstr "Quitar un producto" + +#: apps/treasury/templates/treasury/invoice_list.html:19 +#: apps/treasury/templates/treasury/remittance_list.html:19 +#: apps/treasury/templates/treasury/sogecredit_list.html:19 +msgid "Société générale credits" +msgstr "Créditos de la Société Générale" + +#: apps/treasury/templates/treasury/invoice_list.html:31 +msgid "New invoice" +msgstr "Nueva factura" + +#: apps/treasury/templates/treasury/remittance_form.html:12 +msgid "Remittance #" +msgstr "Descuento n°" + +#: apps/treasury/templates/treasury/remittance_form.html:17 +msgid "Count" +msgstr "Número" + +#: apps/treasury/templates/treasury/remittance_form.html:35 +msgid "Linked transactions" +msgstr "Transacciones vinculadas" + +#: apps/treasury/templates/treasury/remittance_form.html:42 +msgid "There is no transaction linked with this remittance." +msgstr "No hay transacción vinculada con este descuento." + +#: apps/treasury/templates/treasury/remittance_list.html:27 +msgid "Opened remittances" +msgstr "Descuentos abiertos" + +#: apps/treasury/templates/treasury/remittance_list.html:34 +msgid "There is no opened remittance." +msgstr "No hay descuento abierto." + +#: apps/treasury/templates/treasury/remittance_list.html:39 +msgid "New remittance" +msgstr "Nuevo descuento" + +#: apps/treasury/templates/treasury/remittance_list.html:45 +msgid "Transfers without remittances" +msgstr "Transacciones sin descuento" + +#: apps/treasury/templates/treasury/remittance_list.html:52 +msgid "There is no transaction without any linked remittance." +msgstr "No hay transacción sin descuento vinculado." + +#: apps/treasury/templates/treasury/remittance_list.html:60 +msgid "Transfers with opened remittances" +msgstr "Transacciones con un descuento abierto" + +#: apps/treasury/templates/treasury/remittance_list.html:67 +msgid "There is no transaction with an opened linked remittance." +msgstr "No hay transacción con un descuento abierto." + +#: apps/treasury/templates/treasury/remittance_list.html:75 +msgid "Closed remittances" +msgstr "Descuentos cerrados" + +#: apps/treasury/templates/treasury/remittance_list.html:82 +msgid "There is no closed remittance yet." +msgstr "Por ahora no hay descuentos cerrados." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:29 +msgid "total amount" +msgstr "monto total" + +#: apps/treasury/templates/treasury/sogecredit_detail.html:35 +msgid "" +"Warning: Validating this credit implies that all membership transactions " +"will be validated." +msgstr "" +"Cuidado : Validar este crédito implica que las transacciones de afiliación " +"serán validadas." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:36 +msgid "" +"If you delete this credit, there all membership transactions will be also " +"validated, but no credit will be operated." +msgstr "" +"Si suprime este crédito, todas las transacciones de afiliación serán " +"validadas, pero ningún crédito tendrá lugar." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:37 +msgid "" +"If this credit is validated, then the user won't be able to ask for a credit " +"from the Société générale." +msgstr "" +"Si este crédito es validado, pues el usuario no podrá pedir más crédito de " +"la Société Générale." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:38 +msgid "If you think there is an error, please contact the \"respos info\"." +msgstr "Si usted cree que hay un error, por favor contacte un \"respo info\"." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:44 +msgid "This credit is already validated." +msgstr "Este crédito ya fue validado." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:49 +msgid "" +"Warning: if you don't validate this credit, the note of the user doesn't " +"have enough money to pay its memberships." +msgstr "" +"Cuidado : si no valida este crédito, la note del usuario no tiene suficiente " +"dinero para pagar sus afiliaciones." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:50 +msgid "Please ask the user to credit its note before deleting this credit." +msgstr "" +"Por favor pide al usuario acreditar su note antes de suprimir este crédito." + +#: apps/treasury/templates/treasury/sogecredit_detail.html:57 +#: apps/wei/tables.py:59 apps/wei/tables.py:60 apps/wei/tables.py:99 +msgid "Validate" +msgstr "Validar" + +#: apps/treasury/templates/treasury/sogecredit_detail.html:65 +msgid "Return to credit list" +msgstr "Regresar a la lista de los créditos" + +#: apps/treasury/templates/treasury/sogecredit_list.html:34 +msgid "Filter with unvalidated credits only" +msgstr "Filtrar con créditos invalidados unicamente" + +#: apps/treasury/templates/treasury/sogecredit_list.html:44 +msgid "There is no matched user that have asked for a Société générale credit." +msgstr "" +"No hay usuario encontrado cual pidió un crédito de la Société Générale." + +#: apps/treasury/views.py:38 +msgid "Create new invoice" +msgstr "Crear una nueva factura" + +#: apps/treasury/views.py:94 +msgid "Invoices list" +msgstr "Lista de las facturas" + +#: apps/treasury/views.py:109 apps/treasury/views.py:282 +#: apps/treasury/views.py:408 +msgid "You are not able to see the treasury interface." +msgstr "Usted no tiene derecho a ver la interfaz de tesorería." + +#: apps/treasury/views.py:119 +msgid "Update an invoice" +msgstr "Modificar una factura" + +#: apps/treasury/views.py:243 +msgid "Create a new remittance" +msgstr "Crear un nuevo descuento" + +#: apps/treasury/views.py:270 +msgid "Remittances list" +msgstr "Lista de los descuentos" + +#: apps/treasury/views.py:333 +msgid "Update a remittance" +msgstr "Modificar un descuento" + +#: apps/treasury/views.py:356 +msgid "Attach a transaction to a remittance" +msgstr "Unir una transacción con un descuento" + +#: apps/treasury/views.py:400 +msgid "List of credits from the Société générale" +msgstr "Lista de los créditos de la Société Générale" + +#: apps/treasury/views.py:440 +msgid "Manage credits from the Société générale" +msgstr "Gestionar los créditos de la Société Générale" + +#: apps/wei/apps.py:10 apps/wei/models.py:49 apps/wei/models.py:50 +#: apps/wei/models.py:61 apps/wei/models.py:167 +#: note_kfet/templates/base.html:100 +msgid "WEI" +msgstr "WEI" + +#: apps/wei/forms/registration.py:51 apps/wei/models.py:113 +#: apps/wei/models.py:283 +msgid "bus" +msgstr "bus" + +#: apps/wei/forms/registration.py:52 +msgid "" +"This choice is not definitive. The WEI organizers are free to attribute for " +"you a bus and a team, in particular if you are a free eletron." +msgstr "" +"Esta elección no es definitiva. Los organizadores del WEI se quedan con el " +"derecho de imponer su bus y su equipo, en particular para los electrones " +"libres." + +#: apps/wei/forms/registration.py:59 +msgid "Team" +msgstr "Equipo" + +#: apps/wei/forms/registration.py:61 +msgid "" +"Leave this field empty if you won't be in a team (staff, bus chief, free " +"electron)" +msgstr "" +"Deje este campo vacío si no quiere estar en un equipo (staff, jefe de bus, " +"electrón libre)" + +#: apps/wei/forms/registration.py:67 apps/wei/forms/registration.py:77 +#: apps/wei/models.py:148 +msgid "WEI Roles" +msgstr "Papeles en el WEI" + +#: apps/wei/forms/registration.py:68 +msgid "Select the roles that you are interested in." +msgstr "Elegir los papeles que le interesa." + +#: apps/wei/forms/registration.py:113 +msgid "This team doesn't belong to the given bus." +msgstr "Este equipo no pertenece al bus dado." + +#: apps/wei/forms/surveys/wei2020.py:29 +msgid "Choose a word:" +msgstr "Elegir una palabra :" + +#: apps/wei/models.py:24 apps/wei/templates/wei/base.html:36 +msgid "year" +msgstr "año" + +#: apps/wei/models.py:28 apps/wei/templates/wei/base.html:30 +msgid "date start" +msgstr "fecha de inicio" + +#: apps/wei/models.py:32 apps/wei/templates/wei/base.html:33 +msgid "date end" +msgstr "fecha de fin" + +#: apps/wei/models.py:77 +msgid "survey information" +msgstr "informaciones sobre el cuestionario" + +#: apps/wei/models.py:78 +msgid "Information about the survey for new members, encoded in JSON" +msgstr "" +"Informaciones sobre el cuestionario para los nuevos miembros, registrado en " +"JSON" + +#: apps/wei/models.py:100 +msgid "Bus" +msgstr "Bus" + +#: apps/wei/models.py:101 apps/wei/templates/wei/weiclub_detail.html:51 +msgid "Buses" +msgstr "Bus" + +#: apps/wei/models.py:122 +msgid "color" +msgstr "color" + +#: apps/wei/models.py:123 +msgid "The color of the T-Shirt, stored with its number equivalent" +msgstr "El color de la camiseta, registrado con su número equivalente" + +#: apps/wei/models.py:137 +msgid "Bus team" +msgstr "Equipo de bus" + +#: apps/wei/models.py:138 +msgid "Bus teams" +msgstr "Equipos de bus" + +#: apps/wei/models.py:147 +msgid "WEI Role" +msgstr "Papeles en el WEI" + +#: apps/wei/models.py:172 +msgid "Credit from Société générale" +msgstr "Crédito de la Société Générale" + +#: apps/wei/models.py:177 +msgid "Caution check given" +msgstr "Cheque de garantía dado" + +#: apps/wei/models.py:181 apps/wei/templates/wei/weimembership_form.html:64 +msgid "birth date" +msgstr "fecha de nacimiento" + +#: apps/wei/models.py:187 apps/wei/models.py:197 +msgid "Male" +msgstr "Hombre" + +#: apps/wei/models.py:188 apps/wei/models.py:198 +msgid "Female" +msgstr "Mujer" + +#: apps/wei/models.py:189 +msgid "Non binary" +msgstr "No binari@" + +#: apps/wei/models.py:191 apps/wei/templates/wei/weimembership_form.html:55 +msgid "gender" +msgstr "género" + +#: apps/wei/models.py:200 apps/wei/templates/wei/weimembership_form.html:58 +msgid "clothing cut" +msgstr "forma de ropa" + +#: apps/wei/models.py:213 apps/wei/templates/wei/weimembership_form.html:61 +msgid "clothing size" +msgstr "medida de ropa" + +#: apps/wei/models.py:219 apps/wei/templates/wei/weimembership_form.html:67 +msgid "health issues" +msgstr "problemas de salud" + +#: apps/wei/models.py:224 apps/wei/templates/wei/weimembership_form.html:70 +msgid "emergency contact name" +msgstr "nombre del contacto de emergencia" + +#: apps/wei/models.py:229 apps/wei/templates/wei/weimembership_form.html:73 +msgid "emergency contact phone" +msgstr "teléfono del contacto de emergencia" + +#: apps/wei/models.py:234 apps/wei/templates/wei/weimembership_form.html:52 +msgid "first year" +msgstr "primer año" + +#: apps/wei/models.py:235 +msgid "Tells if the user is new in the school." +msgstr "Indica si el usuario es nuevo en la escuela." + +#: apps/wei/models.py:240 +msgid "registration information" +msgstr "informaciones sobre la afiliación" + +#: apps/wei/models.py:241 +msgid "" +"Information about the registration (buses for old members, survey for the " +"new members), encoded in JSON" +msgstr "" +"Informaciones sobre la afiliacion (bus para miembros ancianos, cuestionario " +"para los nuevos miembros), registrado en JSON" + +#: apps/wei/models.py:272 +msgid "WEI User" +msgstr "Participante WEI" + +#: apps/wei/models.py:273 +msgid "WEI Users" +msgstr "Participantes WEI" + +#: apps/wei/models.py:293 +msgid "team" +msgstr "equipo" + +#: apps/wei/models.py:303 +msgid "WEI registration" +msgstr "Apuntación al WEI" + +#: apps/wei/models.py:307 +msgid "WEI membership" +msgstr "Afiliación al WEI" + +#: apps/wei/models.py:308 +msgid "WEI memberships" +msgstr "Afiliaciones al WEI" + +#: apps/wei/tables.py:127 +msgid "Year" +msgstr "Año" + +#: apps/wei/tables.py:165 apps/wei/templates/wei/bus_detail.html:32 +#: apps/wei/templates/wei/busteam_detail.html:50 +msgid "Teams" +msgstr "Equipos" + +#: apps/wei/tables.py:174 apps/wei/tables.py:215 +msgid "Members count" +msgstr "Número de miembros" + +#: apps/wei/tables.py:181 apps/wei/tables.py:212 +msgid "members" +msgstr "miembros" + +#: apps/wei/templates/wei/base.html:44 +msgid "WEI fee (paid students)" +msgstr "Pago de entrada del WEI (estudiantes pagados)" + +#: apps/wei/templates/wei/base.html:47 apps/wei/templates/wei/base.html:54 +msgid "The BDE membership is included in the WEI registration." +msgstr "La afiliación al BDE esta incluida en la afiliación WEI." + +#: apps/wei/templates/wei/base.html:51 +msgid "WEI fee (unpaid students)" +msgstr "Pago de entrada del WEI (estudiantes no pagados)" + +#: apps/wei/templates/wei/base.html:76 +msgid "WEI list" +msgstr "Lista de los WEI" + +#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:506 +msgid "Register 1A" +msgstr "Apuntar un 1A" + +#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:573 +msgid "Register 2A+" +msgstr "Apuntar un 2A+" + +#: apps/wei/templates/wei/base.html:93 +msgid "Add bus" +msgstr "Añadir un bus" + +#: apps/wei/templates/wei/base.html:97 +msgid "View WEI" +msgstr "Ver un WEI" + +#: apps/wei/templates/wei/bus_detail.html:22 +#: apps/wei/templates/wei/busteam_detail.html:22 +msgid "Add team" +msgstr "Añadir un equipo" + +#: apps/wei/templates/wei/bus_detail.html:45 +msgid "Members" +msgstr "Miembros" + +#: apps/wei/templates/wei/bus_detail.html:54 +#: apps/wei/templates/wei/busteam_detail.html:60 +#: apps/wei/templates/wei/weimembership_list.html:29 +msgid "View as PDF" +msgstr "Descargar un PDF" + +#: apps/wei/templates/wei/survey.html:11 +#: apps/wei/templates/wei/survey_closed.html:11 +#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:978 +#: apps/wei/views.py:1032 apps/wei/views.py:1042 +msgid "Survey WEI" +msgstr "Cuestionario WEI" + +#: apps/wei/templates/wei/survey.html:23 +msgid "Next" +msgstr "Siguiente" + +#: apps/wei/templates/wei/survey_closed.html:15 +msgid "The inscription for this WEI are now closed." +msgstr "La inscripción a este WEI esta cerrada por el momento." + +#: apps/wei/templates/wei/survey_closed.html:19 +msgid "Return to WEI detail" +msgstr "Regresar a los detalles del WEI" + +#: apps/wei/templates/wei/survey_end.html:15 +msgid "The survey is now ended. Your answers have been saved." +msgstr "El cuestionario se acabó. Sus repuestas fueron guardadas." + +#: apps/wei/templates/wei/weiclub_detail.html:32 +msgid "Register to the WEI! – 1A" +msgstr "¡ Apuntar al WEI ! – 1A" + +#: apps/wei/templates/wei/weiclub_detail.html:36 +msgid "Register to the WEI! – 2A+" +msgstr "¡ Apuntar al WEI ! – 2A+" + +#: apps/wei/templates/wei/weiclub_detail.html:40 +msgid "Update my registration" +msgstr "Modificar mi inscripción" + +#: apps/wei/templates/wei/weiclub_detail.html:63 +msgid "Members of the WEI" +msgstr "Miembros del WEI" + +#: apps/wei/templates/wei/weiclub_detail.html:89 +msgid "Unvalidated registrations" +msgstr "Inscripciones sin validación" + +#: apps/wei/templates/wei/weiclub_list.html:14 apps/wei/views.py:76 +msgid "Create WEI" +msgstr "Crear un WEI" + +#: apps/wei/templates/wei/weiclub_list.html:22 +msgid "WEI listing" +msgstr "Lista de los WEI" + +#: apps/wei/templates/wei/weimembership_form.html:10 +msgid "Review registration" +msgstr "Revisar la inscripción" + +#: apps/wei/templates/wei/weimembership_form.html:35 +msgid "ENS year" +msgstr "Año en la ENS" + +#: apps/wei/templates/wei/weimembership_form.html:76 +msgid "Payment from Société générale" +msgstr "Pago de la Société Générale" + +#: apps/wei/templates/wei/weimembership_form.html:80 +msgid "Suggested bus from the survey:" +msgstr "Bus sugerido por el cuestionario :" + +#: apps/wei/templates/wei/weimembership_form.html:85 +msgid "Raw survey information" +msgstr "Informaciones crudas del cuestionario" + +#: apps/wei/templates/wei/weimembership_form.html:95 +msgid "The algorithm didn't run." +msgstr "El algoritmo no funcionó." + +#: apps/wei/templates/wei/weimembership_form.html:98 +msgid "caution check given" +msgstr "cheque de garantía dado" + +#: apps/wei/templates/wei/weimembership_form.html:102 +msgid "preferred bus" +msgstr "bus preferido" + +#: apps/wei/templates/wei/weimembership_form.html:105 +msgid "preferred team" +msgstr "equipo preferido" + +#: apps/wei/templates/wei/weimembership_form.html:108 +msgid "preferred roles" +msgstr "papales preferidos" + +#: apps/wei/templates/wei/weimembership_form.html:115 +#: apps/wei/templates/wei/weiregistration_confirm_delete.html:30 +msgid "Update registration" +msgstr "Modificar la inscripción" + +#: apps/wei/templates/wei/weimembership_form.html:131 +msgid "The registration is already validated and can't be unvalidated." +msgstr "La inscripción ya fue validada y no puede ser invalidada." + +#: apps/wei/templates/wei/weimembership_form.html:132 +msgid "The user joined the bus" +msgstr "El usuario se queda con el bus" + +#: apps/wei/templates/wei/weimembership_form.html:133 +msgid "in the team" +msgstr "en el equipo" + +#: apps/wei/templates/wei/weimembership_form.html:134 +msgid "in no team (staff)" +msgstr "en ningún equipo (staff)" + +#: apps/wei/templates/wei/weimembership_form.html:134 +msgid "with the following roles:" +msgstr "con los papeles :" + +#: apps/wei/templates/wei/weimembership_form.html:139 +msgid "" +"The WEI will be paid by Société générale. The membership will be created " +"even if the bank didn't pay the BDE yet. The membership transaction will be " +"created but will be invalid. You will have to validate it once the bank " +"validated the creation of the account, or to change the payment method." +msgstr "" +"El WEI será pagado por la Société Générale. La afiliación será creada aunque " +"el banco no pago el BDE ya. La transacción de afiliación será creada pero " +"resultará invalida. Tendrá que validarla una vez que el banco confirmará la " +"creación de la cuenta, o cambiará el método de pago." + +#: apps/wei/templates/wei/weimembership_form.html:149 +#, python-format +msgid "" +"The note don't have enough money (%(balance)s, %(pretty_fee)s required). The " +"registration may fail if you don't credit the note now." +msgstr "" +"La note no tiene suficiente dinero (%(balance)s, %(pretty_fee)s pedidos). La " +"afiliación puede fallar si usted no acredita la note ahora." + +#: apps/wei/templates/wei/weimembership_form.html:157 +#, python-format +msgid "" +"The note has enough money (%(pretty_fee)s required), the registration is " +"possible." +msgstr "" +"La note tiene suficiente dinero (%(pretty_fee)s pedidos), la afiliación es " +"posible." + +#: apps/wei/templates/wei/weimembership_form.html:166 +msgid "The user didn't give her/his caution check." +msgstr "El usuario no dio su cheque de garantía." + +#: apps/wei/templates/wei/weimembership_form.html:174 +msgid "" +"This user is not a member of the Kfet club for the coming year. The " +"membership will be processed automatically, the WEI registration includes " +"the membership fee." +msgstr "" +"Este usuario no es miembro del club Kfet por el año que viene. La afiliación " +"será hecha automáticamente, la afiliación al WEI incluye el pago de los dos." + +#: apps/wei/templates/wei/weimembership_list.html:23 +msgid "View unvalidated registrations..." +msgstr "Ver las inscripciones no validadas..." + +#: apps/wei/templates/wei/weiregistration_confirm_delete.html:16 +msgid "This registration is already validated and can't be deleted." +msgstr "La inscripción ya fue validada y no puede ser suprimida." + +#: apps/wei/templates/wei/weiregistration_confirm_delete.html:23 +#, python-format +msgid "" +"Are you sure you want to delete the registration of %(user)s for the WEI " +"%(wei_name)s? This action can't be undone." +msgstr "" +"¿ Usted está seguro que quiere suprimir la inscripción de %(user)s para el " +"WEI %(wei_name)s ? Este acto es definitivo." + +#: apps/wei/templates/wei/weiregistration_list.html:17 +msgid "There is no pre-registration found with this pattern." +msgstr "No hay pre-inscripción encontrada con esta entrada." + +#: apps/wei/templates/wei/weiregistration_list.html:23 +msgid "View validated memberships..." +msgstr "Ver las inscripciones validadas..." + +#: apps/wei/views.py:55 +msgid "Search WEI" +msgstr "Buscar un WEI" + +#: apps/wei/views.py:105 +msgid "WEI Detail" +msgstr "Detalles del WEI" + +#: apps/wei/views.py:200 +msgid "View members of the WEI" +msgstr "Ver los miembros del WEI" + +#: apps/wei/views.py:228 +msgid "Find WEI Membership" +msgstr "Buscar una afiliación al WEI" + +#: apps/wei/views.py:238 +msgid "View registrations to the WEI" +msgstr "Ver las inscripciones al WEI" + +#: apps/wei/views.py:262 +msgid "Find WEI Registration" +msgstr "Buscar una inscripción al WEI" + +#: apps/wei/views.py:273 +msgid "Update the WEI" +msgstr "Modificar el WEI" + +#: apps/wei/views.py:294 +msgid "Create new bus" +msgstr "Añadir un bus" + +#: apps/wei/views.py:332 +msgid "Update bus" +msgstr "Modificar el bus" + +#: apps/wei/views.py:362 +msgid "Manage bus" +msgstr "Gestionar el bus" + +#: apps/wei/views.py:389 +msgid "Create new team" +msgstr "Añadir un equipo" + +#: apps/wei/views.py:429 +msgid "Update team" +msgstr "Modificar el equipo" + +#: apps/wei/views.py:460 +msgid "Manage WEI team" +msgstr "Gestionar el equipo" + +#: apps/wei/views.py:482 +msgid "Register first year student to the WEI" +msgstr "Registrar un 1A al WEI" + +#: apps/wei/views.py:527 apps/wei/views.py:607 +msgid "This user is already registered to this WEI." +msgstr "Este usuario ya afilió a este WEI." + +#: apps/wei/views.py:532 +msgid "" +"This user can't be in her/his first year since he/she has already " +"participated to a WEI." +msgstr "Este usuario no puede ser un 1A porque ya participó en un WEI." + +#: apps/wei/views.py:549 +msgid "Register old student to the WEI" +msgstr "Registrar un 2A+ al WEI" + +#: apps/wei/views.py:592 apps/wei/views.py:680 +msgid "You already opened an account in the Société générale." +msgstr "Usted ya abrió una cuenta a la Société Générale." + +#: apps/wei/views.py:637 +msgid "Update WEI Registration" +msgstr "Modificar la inscripción WEI" + +#: apps/wei/views.py:739 +msgid "Delete WEI registration" +msgstr "Suprimir la inscripción WEI" + +#: apps/wei/views.py:750 +msgid "You don't have the right to delete this WEI registration." +msgstr "Usted no tiene derecho a suprimir esta inscripción WEI." + +#: apps/wei/views.py:769 +msgid "Validate WEI registration" +msgstr "Validar la inscripción WEI" + +#: apps/wei/views.py:916 +msgid "This user didn't give her/his caution check." +msgstr "Este usuario no dio su cheque de garantía." + +#: note_kfet/settings/base.py:155 +msgid "German" +msgstr "Alemán" + +#: note_kfet/settings/base.py:156 +msgid "English" +msgstr "Ingles" + +#: note_kfet/settings/base.py:157 +msgid "Spanish" +msgstr "Español" + +#: note_kfet/settings/base.py:158 +msgid "French" +msgstr "Francés" + +#: note_kfet/templates/400.html:10 +msgid "Bad request" +msgstr "" + +#: note_kfet/templates/400.html:14 +msgid "" +"Sorry, your request was bad. Don't know what could be wrong. An email has " +"been sent to webmasters with the details of the error. You can now drink a " +"coke." +msgstr "" +"Un error ocurrió con lo que pidió. ¡ Pero ni idea de lo que falló ! Un " +"correo electrónico fue enviado a los responsables técnicos de la página. " +"Mientras usted puede relajarse." + +#: note_kfet/templates/403.html:10 +msgid "Permission denied" +msgstr "Falta de permiso" + +#: note_kfet/templates/403.html:13 +msgid "You don't have the right to perform this request." +msgstr "Usted no tiene los permisos para pedir esto." + +#: note_kfet/templates/403.html:15 note_kfet/templates/404.html:19 +msgid "Exception message:" +msgstr "Detalles del error :" + +#: note_kfet/templates/404.html:10 +msgid "Page not found" +msgstr "Página no encontrada" + +#: note_kfet/templates/404.html:14 +#, python-format +msgid "" +"The requested path %(request_path)s was not found on the server." +msgstr "" + +#: note_kfet/templates/500.html:10 +msgid "Server error" +msgstr "" + +#: note_kfet/templates/500.html:14 +msgid "" +"Sorry, an error occurred when processing your request. An email has been " +"sent to webmasters with the detail of the error, and this will be fixed " +"soon. You can now drink a beer." +msgstr "" +"Lo siento, un error ocurrió mientras procesaba lo que pidió. Un correo " +"electrónico con los detalles fue enviado a los responsables técnicos de la " +"página. Mientras usted puede relajarse." + +#: note_kfet/templates/autocomplete_model.html:14 +msgid "Reset" +msgstr "" + +#: note_kfet/templates/base.html:14 +msgid "The ENS Paris-Saclay BDE note." +msgstr "La note del BDE de la ENS Paris-Saclay." + +#: note_kfet/templates/base.html:76 +msgid "Users" +msgstr "Usuarios" + +#: note_kfet/templates/base.html:82 +msgid "Clubs" +msgstr "Clubs" + +#: note_kfet/templates/base.html:111 +msgid "Admin" +msgstr "" + +#: note_kfet/templates/base.html:125 +msgid "My account" +msgstr "Mi cuenta" + +#: note_kfet/templates/base.html:128 +msgid "Log out" +msgstr "Desconectarse" + +#: note_kfet/templates/base.html:136 +#: note_kfet/templates/registration/signup.html:6 +#: note_kfet/templates/registration/signup.html:11 +#: note_kfet/templates/registration/signup.html:27 +msgid "Sign up" +msgstr "Registrar" + +#: note_kfet/templates/base.html:143 +#: note_kfet/templates/registration/login.html:6 +#: note_kfet/templates/registration/login.html:15 +#: note_kfet/templates/registration/login.html:38 +#: note_kfet/templates/registration/password_reset_complete.html:15 +msgid "Log in" +msgstr "Conectarse" + +#: note_kfet/templates/base.html:155 +msgid "" +"Your e-mail address is not validated. Please check your mail inbox and click " +"on the validation link." +msgstr "" +"Su correo electrónico no fue validado. Por favor mire en sus correos y haga " +"clic en el enlace de validación." + +#: note_kfet/templates/base.html:172 +msgid "Contact us" +msgstr "Contactarnos" + +#: note_kfet/templates/base_search.html:15 +msgid "Search by attribute such as name…" +msgstr "Buscar con atributo, como el nombre…" + +#: note_kfet/templates/base_search.html:23 +msgid "There is no results." +msgstr "No hay resultado." + +#: note_kfet/templates/cas_server/base.html:7 +msgid "Central Authentication Service" +msgstr "Servicio Central de Autentificación" + +#: note_kfet/templates/cas_server/base.html:43 +#, python-format +msgid "" +"A new version of the application is available. This instance runs " +"%(VERSION)s and the last version is %(LAST_VERSION)s. Please consider " +"upgrading." +msgstr "" +"Una nueva versión es disponible. Se está usando %(VERSION)s y la ultima " +"versión está %(LAST_VERSION)s. Piensa en actualizar." + +#: note_kfet/templates/registration/logged_out.html:13 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Gracias por usar la Note Kfet." + +#: note_kfet/templates/registration/logged_out.html:14 +msgid "Log in again" +msgstr "Conectarse de nuevo" + +#: note_kfet/templates/registration/login.html:20 +#, python-format +msgid "" +"You are authenticated as %(username)s, but are not authorized to access this " +"page. Would you like to login to a different account, or with a higher " +"permission mask?" +msgstr "" +"Está conectado como %(username)s, y no se permite que vea este página. " +"Quiere conectarse con otra cuenta, o con más permisos (antifaz de permisos " +"más largo) ?" + +#: note_kfet/templates/registration/login.html:30 +msgid "" +"You must be logged with a staff account with the higher mask to access " +"Django Admin." +msgstr "" +"Tiene que conectarse con un antifaz de permisos más largo para acceder " +"Djando Admin." + +#: note_kfet/templates/registration/login.html:40 +msgid "Forgotten your password or username?" +msgstr "¿ Contraseña o nombre de usuario olvidado ?" + +#: note_kfet/templates/registration/password_change_done.html:13 +msgid "Your password was changed." +msgstr "Su contraseña fue cambiada con éxito." + +#: note_kfet/templates/registration/password_change_form.html:14 +msgid "" +"Please enter your old password, for security's sake, and then enter your new " +"password twice so we can verify you typed it in correctly." +msgstr "" +"Por favor entre su antigua contraseña por seguridad, y su nueva contraseña " +"dos veces para evitar los errores de tecleo." + +#: note_kfet/templates/registration/password_change_form.html:16 +#: note_kfet/templates/registration/password_reset_confirm.html:17 +msgid "Change my password" +msgstr "Cambiar mi contraseña" + +#: note_kfet/templates/registration/password_reset_complete.html:13 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Su contraseña fue guardada con éxito. Puede conectarse desde ahora." + +#: note_kfet/templates/registration/password_reset_confirm.html:14 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Por favor entra su nueva contraseña dos veces para evitar los errores de " +"tecleo." + +#: note_kfet/templates/registration/password_reset_confirm.html:21 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"El enlace para reiniciar su contraseña está invalido, quizás ya fue " +"utilizado. Por favor pide un nuevo enlace." + +#: note_kfet/templates/registration/password_reset_done.html:13 +msgid "" +"We've emailed you instructions for setting your password, if an account " +"exists with the email you entered. You should receive them shortly." +msgstr "" +"Le enviamos un correo con el método para reiniciar su contraseña (si una " +"cuenta existe con el correo dado). Beba recibirle muy pronto." + +#: note_kfet/templates/registration/password_reset_done.html:14 +msgid "" +"If you don't receive an email, please make sure you've entered the address " +"you registered with, and check your spam folder." +msgstr "" +"Si no recibe el correo, compruebe que entró el correo que usó para " +"registrar, y mire en su carpeta spam." + +#: note_kfet/templates/registration/password_reset_form.html:13 +msgid "" +"Forgotten your password? Enter your email address below, and we'll email " +"instructions for setting a new one." +msgstr "" +"¿ Contraseña olvidada ? Entre su correo electrónico más abajo, le enviaremos " +"un correo con el método para reiniciar su contraseña." + +#: note_kfet/templates/registration/password_reset_form.html:18 +msgid "Reset my password" +msgstr "Reiniciar mi contraseña" + +#: note_kfet/templates/registration/signup.html:15 +msgid "" +"If you already signed up, your registration is taken into account. The BDE " +"must validate your account before your can log in. You have to go to the " +"Kfet and pay the registration fee. You must also validate your email address " +"by following the link you received." +msgstr "" +"Si ya registró, se procesa su inscripción. El BDE tiene que validar su " +"cuenta antes que usted pueda conectarse. Usted tiene que ir en la Kfet para " +"pagar su afiliación. Tambien tiene que validar su correo electronico con el " +"enlace que recibió." + +#~ msgid "Check this case is the Société Générale paid the inscription." +#~ msgstr "Marcar esta casilla si Société Générale pagó la registración." + +#~ msgid "You must join BDE club before joining Kfet club." +#~ msgstr "Tiene que afiliarse al club BDE antes de afiliarse al club Kfet." diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 5e6e2740..a391c4f6 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-07 19:43+0200\n" -"PO-Revision-Date: 2020-09-02 23:18+0200\n" -"Last-Translator: \n" +"POT-Creation-Date: 2020-09-13 12:35+0200\n" +"PO-Revision-Date: 2020-09-13 12:36+0200\n" +"Last-Translator: elkmaennchen \n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" @@ -438,7 +438,7 @@ msgstr "données précédentes" #: apps/logs/models.py:55 msgid "new data" -msgstr "ouvelles données" +msgstr "nouvelles données" #: apps/logs/models.py:63 msgid "create" @@ -526,7 +526,7 @@ msgid "This image cannot be loaded." msgstr "Cette image ne peut pas être chargée." #: 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." 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" #: 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." #: apps/member/forms.py:169 apps/registration/forms.py:68 @@ -550,7 +550,7 @@ msgstr "Pas de rechargement" #: apps/member/forms.py:172 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/wei/forms/registration.py:89 @@ -1017,7 +1017,7 @@ msgstr "Changer le mot de passe" #: apps/member/templates/member/includes/profile_info.html:53 msgid "API token" -msgstr "Acces API" +msgstr "Accès API" #: apps/member/templates/member/manage_auth_tokens.html:19 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}." #: 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/wei/views.py:927 apps/wei/views.py:931 +#: apps/registration/views.py:291 apps/registration/views.py:293 +#: apps/registration/views.py:295 apps/wei/views.py:927 apps/wei/views.py:931 msgid "This field is required." msgstr "Ce champ est requis." @@ -1459,6 +1459,11 @@ msgstr "Supprimer" msgid "Edit" 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 msgid "Consum" msgstr "Consommer" @@ -1469,11 +1474,11 @@ msgstr "Consommer" msgid "Name or alias..." msgstr "Pseudo ou alias ..." -#: apps/note/templates/note/conso_form.html:52 +#: apps/note/templates/note/conso_form.html:53 msgid "Select consumptions" msgstr "Sélection des consommations" -#: apps/note/templates/note/conso_form.html:61 +#: apps/note/templates/note/conso_form.html:62 msgid "Consume!" msgstr "Consommer !" @@ -1701,7 +1706,7 @@ msgstr "" "Vous n'avez pas la permission de modifier le champ {field} sur l'instance du " "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 msgid "" "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" msgstr "Pas de permission associée" -#: apps/permission/views.py:56 +#: apps/permission/views.py:68 #, python-brace-format msgid "" "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} " "» 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 msgid "" "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} » " "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" msgstr "Droits" -#: apps/permission/views.py:101 +#: apps/permission/views.py:113 msgid "All rights" msgstr "Tous les droits" @@ -1913,54 +1918,54 @@ msgstr "Merci" msgid "The Note Kfet team." msgstr "L'équipe de la Note Kfet." -#: apps/registration/views.py:38 +#: apps/registration/views.py:39 msgid "Register new user" msgstr "Enregistrer un nouvel utilisateur" -#: apps/registration/views.py:82 +#: apps/registration/views.py:83 msgid "Email validation" msgstr "Validation de l'adresse mail" -#: apps/registration/views.py:84 +#: apps/registration/views.py:85 msgid "Validate email" msgstr "Valider l'adresse e-mail" -#: apps/registration/views.py:126 +#: apps/registration/views.py:127 msgid "Email validation unsuccessful" msgstr "La validation de l'adresse mail a échoué" -#: apps/registration/views.py:137 +#: apps/registration/views.py:138 msgid "Email validation email sent" 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" msgstr "Renvoyer le lien de validation" -#: apps/registration/views.py:163 +#: apps/registration/views.py:164 msgid "Pre-registered users list" msgstr "Liste des utilisateurs en attente d'inscription" -#: apps/registration/views.py:187 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "Utilisateurs en attente d'inscription" -#: apps/registration/views.py:200 +#: apps/registration/views.py:201 msgid "Registration detail" msgstr "Détails de l'inscription" -#: apps/registration/views.py:256 +#: apps/registration/views.py:260 msgid "You must join the BDE." msgstr "Vous devez adhérer au BDE." -#: apps/registration/views.py:280 +#: apps/registration/views.py:284 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" "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" msgstr "Invalider l'inscription" @@ -2106,7 +2111,7 @@ msgstr "proxys de transactions spéciales" msgid "credit transaction" msgstr "transaction de crédit" -#: apps/treasury/models.py:352 +#: apps/treasury/models.py:361 msgid "" "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." @@ -2114,16 +2119,16 @@ msgstr "" "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." -#: apps/treasury/models.py:364 +#: apps/treasury/models.py:376 #: apps/treasury/templates/treasury/sogecredit_detail.html:10 msgid "Credit from the 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" msgstr "Crédits de la Société générale" -#: apps/treasury/models.py:368 +#: apps/treasury/models.py:380 #, python-brace-format msgid "Soge credit for {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" 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" 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 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" msgstr "" "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 " "participated to a WEI." 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." #: apps/wei/views.py:549 @@ -2908,6 +2913,10 @@ msgid "English" msgstr "Anglais" #: note_kfet/settings/base.py:157 +msgid "Spanish" +msgstr "Espagnol" + +#: note_kfet/settings/base.py:158 msgid "French" msgstr "Français" @@ -3083,7 +3092,7 @@ msgid "" "password twice so we can verify you typed it in correctly." msgstr "" "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." #: 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 " "d'adhésion. Vous devez également valider votre adresse email en suivant le " "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." diff --git a/note_kfet/middlewares.py b/note_kfet/middlewares.py index 8987816d..22f3e264 100644 --- a/note_kfet/middlewares.py +++ b/note_kfet/middlewares.py @@ -50,6 +50,20 @@ class SessionMiddleware(object): def __call__(self, request): 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: ip = request.META.get('HTTP_X_REAL_IP') elif 'HTTP_X_FORWARDED_FOR' in request.META: diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index 230bf441..27010fef 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -154,6 +154,7 @@ from django.utils.translation import gettext_lazy as _ LANGUAGES = [ ('de', _('German')), ('en', _('English')), + ('es', _('Spanish')), ('fr', _('French')), ] diff --git a/note_kfet/static/css/custom.css b/note_kfet/static/css/custom.css index 5d901c9d..1f7cf763 100644 --- a/note_kfet/static/css/custom.css +++ b/note_kfet/static/css/custom.css @@ -22,6 +22,11 @@ border-bottom-color: rgba(0, 0, 0, .250); } +/* Fixed width picture column */ +.picture-col { + max-width: 202px; +} + /* Limit fluid container to a max size */ .container-fluid { max-width: 1600px; diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html index f65fe87c..79ea6ea9 100644 --- a/note_kfet/templates/base.html +++ b/note_kfet/templates/base.html @@ -177,12 +177,11 @@ SPDX-License-Identifier: GPL-3.0-or-later onchange="this.form.submit()"> {% get_current_language as LANGUAGE_CODE %} {% get_available_languages as LANGUAGES %} - {% get_language_info_list for LANGUAGES as languages %} - {% for language in languages %} - {% endfor %} diff --git a/note_kfet/urls.py b/note_kfet/urls.py index 62943e4d..ae6bf3db 100644 --- a/note_kfet/urls.py +++ b/note_kfet/urls.py @@ -36,8 +36,9 @@ urlpatterns = [ path('coffee/', include('django_htcpcp_tea.urls')), ] -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +# During development, serve media files +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) if "cas_server" in settings.INSTALLED_APPS: