diff --git a/.gitignore b/.gitignore index 91e55e22..40e0824d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ map.json backups/ /static/ /media/ +/tmp/ # Virtualenv env/ diff --git a/apps/activity/fixtures/initial.json b/apps/activity/fixtures/initial.json index 63c5009e..7961c17f 100644 --- a/apps/activity/fixtures/initial.json +++ b/apps/activity/fixtures/initial.json @@ -6,7 +6,7 @@ "name": "Pot", "manage_entries": true, "can_invite": true, - "guest_entry_fee": 500 + "guest_entry_fee": 1000 } }, { @@ -28,5 +28,25 @@ "can_invite": false, "guest_entry_fee": 0 } + }, + { + "model": "activity.activitytype", + "pk": 5, + "fields": { + "name": "Soir\u00e9e avec entrées", + "manage_entries": true, + "can_invite": false, + "guest_entry_fee": 0 + } + }, + { + "model": "activity.activitytype", + "pk": 7, + "fields": { + "name": "Soir\u00e9e avec invitations", + "manage_entries": true, + "can_invite": true, + "guest_entry_fee": 0 + } } ] diff --git a/apps/api/pagination.py b/apps/api/pagination.py index d897b583..1c6b1a1f 100644 --- a/apps/api/pagination.py +++ b/apps/api/pagination.py @@ -1,5 +1,5 @@ from rest_framework.pagination import PageNumberPagination + class CustomPagination(PageNumberPagination): page_size_query_param = 'page_size' - diff --git a/apps/member/forms.py b/apps/member/forms.py index ab24ded6..527816cb 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -47,6 +47,13 @@ class ProfileForm(forms.ModelForm): last_report = forms.DateTimeField(required=False, disabled=True, label=_("Last report date")) + VSS_charter_read = forms.BooleanField( + required=True, + label=_("Anti-VSS (Violences Sexistes et Sexuelles) charter read and approved"), + help_text=_("Tick after having read and accepted the anti-VSS charter \ + available here in pdf") + ) + def clean_promotion(self): promotion = self.cleaned_data["promotion"] if promotion > timezone.now().year: diff --git a/apps/member/migrations/0009_auto_20220904_2325.py b/apps/member/migrations/0009_auto_20220904_2325.py new file mode 100644 index 00000000..e259dacf --- /dev/null +++ b/apps/member/migrations/0009_auto_20220904_2325.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.26 on 2022-09-04 21:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('member', '0008_auto_20211005_1544'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='promotion', + field=models.PositiveSmallIntegerField(default=2022, help_text='Year of entry to the school (None if not ENS student)', null=True, verbose_name='promotion'), + ), + ] diff --git a/apps/member/migrations/0010_new_default_year.py b/apps/member/migrations/0010_new_default_year.py new file mode 100644 index 00000000..90740c57 --- /dev/null +++ b/apps/member/migrations/0010_new_default_year.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-08-23 21:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('member', '0009_auto_20220904_2325'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='promotion', + field=models.PositiveSmallIntegerField(default=2023, help_text='Year of entry to the school (None if not ENS student)', null=True, verbose_name='promotion'), + ), + ] diff --git a/apps/member/migrations/0011_profile_vss_charter_read.py b/apps/member/migrations/0011_profile_vss_charter_read.py new file mode 100644 index 00000000..502cc6e0 --- /dev/null +++ b/apps/member/migrations/0011_profile_vss_charter_read.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-08-31 09:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('member', '0010_new_default_year'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='VSS_charter_read', + field=models.BooleanField(default=False, verbose_name='VSS charter read'), + ), + ] diff --git a/apps/member/models.py b/apps/member/models.py index 0b471f12..5e0da5bc 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -134,6 +134,11 @@ class Profile(models.Model): default=False, ) + VSS_charter_read = models.BooleanField( + verbose_name=_("VSS charter read"), + default=False + ) + @property def ens_year(self): """ @@ -263,7 +268,7 @@ class Club(models.Model): today = datetime.date.today() - if (today - self.membership_start).days >= 365: + while (today - self.membership_start).days >= 365: if self.membership_start: self.membership_start = datetime.date(self.membership_start.year + 1, self.membership_start.month, self.membership_start.day) diff --git a/apps/member/static/member/js/trust.js b/apps/member/static/member/js/trust.js index a16bed08..15b5359f 100644 --- a/apps/member/static/member/js/trust.js +++ b/apps/member/static/member/js/trust.js @@ -1,7 +1,7 @@ /** * On form submit, create a new friendship */ -function create_trust (e) { +function form_create_trust (e) { // Do not submit HTML form e.preventDefault() @@ -14,25 +14,35 @@ function create_trust (e) { addMsg(gettext("You can't add yourself as a friend"), "danger") return } - $.post('/api/note/trust/', { - csrfmiddlewaretoken: formData.get('csrfmiddlewaretoken'), - trusting: formData.get('trusting'), - trusted: trusted_alias.note - }).done(function () { - // Reload table - $('#trust_table').load(location.pathname + ' #trust_table') - addMsg(gettext('Friendship successfully added'), 'success') - }).fail(function (xhr, _textStatus, _error) { - errMsg(xhr.responseJSON) - }) + create_trust(formData.get('trusting'), trusted_alias.note) }).fail(function (xhr, _textStatus, _error) { errMsg(xhr.responseJSON) }) } /** - * On click of "delete", delete the alias - * @param button_id:Integer Alias id to remove + * Create a trust between users + * @param trusting:Integer trusting note id + * @param trusted:Integer trusted note id + */ +function create_trust(trusting, trusted) { + $.post('/api/note/trust/', { + trusting: trusting, + trusted: trusted, + csrfmiddlewaretoken: CSRF_TOKEN + }).done(function () { + // Reload tables + $('#trust_table').load(location.pathname + ' #trust_table') + $('#trusted_table').load(location.pathname + ' #trusted_table') + addMsg(gettext('Friendship successfully added'), 'success') + }).fail(function (xhr, _textStatus, _error) { + errMsg(xhr.responseJSON) + }) +} + +/** + * On click of "delete", delete the trust + * @param button_id:Integer Trust id to remove */ function delete_button (button_id) { $.ajax({ @@ -42,6 +52,7 @@ function delete_button (button_id) { }).done(function () { addMsg(gettext('Friendship successfully deleted'), 'success') $('#trust_table').load(location.pathname + ' #trust_table') + $('#trusted_table').load(location.pathname + ' #trusted_table') }).fail(function (xhr, _textStatus, _error) { errMsg(xhr.responseJSON) }) @@ -49,5 +60,5 @@ function delete_button (button_id) { $(document).ready(function () { // Attach event - document.getElementById('form_trust').addEventListener('submit', create_trust) + document.getElementById('form_trust').addEventListener('submit', form_create_trust) }) diff --git a/apps/member/templates/member/profile_trust.html b/apps/member/templates/member/profile_trust.html index bd8d6b50..b89f05f6 100644 --- a/apps/member/templates/member/profile_trust.html +++ b/apps/member/templates/member/profile_trust.html @@ -7,7 +7,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block profile_content %}

- {% trans "Note friendships" %} + {% trans "Add friends" %}

{% if can_create %} @@ -24,7 +24,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% render_table trusting %}
-
+
{% blocktrans trimmed %} Adding someone as a friend enables them to initiate transactions coming from your account (while keeping your balance positive). This is @@ -33,6 +33,13 @@ SPDX-License-Identifier: GPL-3.0-or-later friends without needing additional rights among them. {% endblocktrans %}
+ +
+

+ {% trans "People having you as a friend" %} +

+ {% render_table trusted_by %} +
{% endblock %} {% block extrajavascript %} diff --git a/apps/member/tests/test_memberships.py b/apps/member/tests/test_memberships.py index 2dc6dd41..de9f3d3d 100644 --- a/apps/member/tests/test_memberships.py +++ b/apps/member/tests/test_memberships.py @@ -183,7 +183,7 @@ class TestMemberships(TestCase): club = Club.objects.get(name="Kfet") else: club = Club.objects.create( - name="Second club " + ("with BDE" if bde_parent else "without BDE"), + name="Second club without BDE", parent_club=None, email="newclub@example.com", require_memberships=True, @@ -335,6 +335,7 @@ class TestMemberships(TestCase): ml_sports_registration=True, ml_art_registration=True, report_frequency=7, + VSS_charter_read=True )) self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200) self.assertTrue(User.objects.filter(username="toto changed").exists()) diff --git a/apps/member/views.py b/apps/member/views.py index 2f6348a6..066a7ef3 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -8,7 +8,6 @@ from django.contrib.auth import logout from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.contrib.auth.views import LoginView -from django.contrib.contenttypes.models import ContentType from django.db import transaction from django.db.models import Q, F from django.shortcuts import redirect @@ -21,7 +20,7 @@ from django_tables2.views import SingleTableView from rest_framework.authtoken.models import Token from note.models import Alias, NoteClub, NoteUser, Trust from note.models.transactions import Transaction, SpecialTransaction -from note.tables import HistoryTable, AliasTable, TrustTable +from note.tables import HistoryTable, AliasTable, TrustTable, TrustedTable from note_kfet.middlewares import _set_current_request from permission.backends import PermissionBackend from permission.models import Role @@ -258,17 +257,18 @@ class ProfileTrustView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): note = context['object'].note context["trusting"] = TrustTable( note.trusting.filter(PermissionBackend.filter_queryset(self.request, Trust, "view")).distinct().all()) + context["trusted_by"] = TrustedTable( + note.trusted.filter(PermissionBackend.filter_queryset(self.request, Trust, "view")).distinct().all()) context["can_create"] = PermissionBackend.check_perm(self.request, "note.add_trust", Trust( trusting=context["object"].note, trusted=context["object"].note )) context["widget"] = { "name": "trusted", + "resetable": True, "attrs": { - "model_pk": ContentType.objects.get_for_model(Alias).pk, "class": "autocomplete form-control", "id": "trusted", - "resetable": True, "api_url": "/api/note/alias/?note__polymorphic_ctype__model=noteuser", "name_field": "name", "placeholder": "" @@ -753,6 +753,10 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView): club = old_membership.club user = old_membership.user + # Update club membership date + if PermissionBackend.check_perm(self.request, "member.change_club_membership_start", club): + club.update_membership_dates() + form.instance.club = club # Get form data diff --git a/apps/note/admin.py b/apps/note/admin.py index eb0f0f3c..8d081d90 100644 --- a/apps/note/admin.py +++ b/apps/note/admin.py @@ -7,7 +7,7 @@ from polymorphic.admin import PolymorphicChildModelAdmin, \ PolymorphicChildModelFilter, PolymorphicParentModelAdmin from note_kfet.admin import admin_site -from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser +from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser, Trust from .models.transactions import Transaction, TemplateCategory, TransactionTemplate, \ RecurrentTransaction, MembershipTransaction, SpecialTransaction from .templatetags.pretty_money import pretty_money @@ -21,6 +21,16 @@ class AliasInlines(admin.TabularInline): model = Alias +class TrustInlines(admin.TabularInline): + """ + Define trusts when editing the trusting note + """ + model = Trust + fk_name = "trusting" + extra = 0 + readonly_fields = ("trusted",) + + @admin.register(Note, site=admin_site) class NoteAdmin(PolymorphicParentModelAdmin): """ @@ -92,7 +102,7 @@ class NoteUserAdmin(PolymorphicChildModelAdmin): """ Child for an user note, see NoteAdmin """ - inlines = (AliasInlines,) + inlines = (AliasInlines, TrustInlines) # We can't change user after creation or the balance readonly_fields = ('user', 'balance') diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index 33bf75ba..a374fc33 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -11,6 +11,7 @@ from member.models import Membership from note_kfet.middlewares import get_current_request from permission.backends import PermissionBackend from rest_framework.utils import model_meta +from rest_framework.validators import UniqueTogetherValidator from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias, Trust from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \ @@ -86,11 +87,9 @@ class TrustSerializer(serializers.ModelSerializer): class Meta: model = Trust fields = '__all__' - - def validate(self, attrs): - instance = Trust(**attrs) - instance.clean() - return attrs + validators = [UniqueTogetherValidator( + queryset=Trust.objects.all(), fields=('trusting', 'trusted'), + message=_("This friendship already exists"))] class AliasSerializer(serializers.ModelSerializer): diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 3c6b4c7d..8ec7bf0a 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -325,8 +325,8 @@ class SpecialTransaction(Transaction): def clean(self): # SpecialTransaction are only possible with NoteSpecial object if self.is_credit() == self.is_debit(): - raise(ValidationError(_("A special transaction is only possible between a" - " Note associated to a payment method and a User or a Club"))) + 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): diff --git a/apps/note/static/note/js/consos.js b/apps/note/static/note/js/consos.js index 5999ffc3..9ee543f7 100644 --- a/apps/note/static/note/js/consos.js +++ b/apps/note/static/note/js/consos.js @@ -221,7 +221,7 @@ function consume (source, source_alias, dest, quantity, amount, reason, type, ca .done(function () { if (!isNaN(source.balance)) { const newBalance = source.balance - quantity * amount - if (newBalance <= -5000) { + if (newBalance <= -2000) { addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' + 'but the emitter note %s is very negative.'), [source_alias, source_alias]), 'danger', 30000) } else if (newBalance < 0) { @@ -258,3 +258,39 @@ function consume (source, source_alias, dest, quantity, amount, reason, type, ca }) }) } + +var searchbar = document.getElementById("search-input") +var search_results = document.getElementById("search-results") + +var old_pattern = null; +var firstMatch = null; +/** + * Updates the button search tab + * @param force Forces the update even if the pattern didn't change + */ +function updateSearch(force = false) { + let pattern = searchbar.value + if (pattern === "") + firstMatch = null; + if ((pattern === old_pattern || pattern === "") && !force) + return; + firstMatch = null; + const re = new RegExp(pattern, "i"); + Array.from(search_results.children).forEach(function(b) { + if (re.test(b.innerText)) { + b.hidden = false; + if (firstMatch === null) { + firstMatch = b; + } + } else + b.hidden = true; + }); +} + +searchbar.addEventListener("input", function (e) { + debounce(updateSearch)() +}); +searchbar.addEventListener("keyup", function (e) { + if (firstMatch && e.key === "Enter") + firstMatch.click() +}); diff --git a/apps/note/static/note/js/transfer.js b/apps/note/static/note/js/transfer.js index 6c1656ef..509d9b48 100644 --- a/apps/note/static/note/js/transfer.js +++ b/apps/note/static/note/js/transfer.js @@ -314,7 +314,7 @@ $('#btn_transfer').click(function () { if (!isNaN(source.note.balance)) { const newBalance = source.note.balance - source.quantity * dest.quantity * amount - if (newBalance <= -5000) { + if (newBalance <= -2000) { addMsg(interpolate(gettext('Warning, the transaction of %s from the note %s to the note %s succeed, but the emitter note %s is very negative.'), [pretty_money(source.quantity * dest.quantity * amount), source.name, dest.name, source.name]), 'danger', 10000) reset() diff --git a/apps/note/tables.py b/apps/note/tables.py index 1e94a39f..243a8da6 100644 --- a/apps/note/tables.py +++ b/apps/note/tables.py @@ -159,11 +159,11 @@ class TrustTable(tables.Table): template_name = 'django_tables2/bootstrap4.html' show_header = False - trusted = tables.Column(attrs={'td': {'class': 'text_center'}}) + trusted = tables.Column(attrs={'td': {'class': 'text-center'}}) delete_col = tables.TemplateColumn( template_code=DELETE_TEMPLATE, - extra_context={"delete_trans": _('delete')}, + extra_context={"delete_trans": _('Delete')}, attrs={ 'td': { 'class': lambda record: 'col-sm-1' @@ -173,6 +173,46 @@ class TrustTable(tables.Table): verbose_name=_("Delete"),) +class TrustedTable(tables.Table): + class Meta: + attrs = { + 'class': 'table table condensed table-striped', + 'id': 'trusted_table' + } + Model = Trust + fields = ("trusting",) + template_name = "django_tables2/bootstrap4.html" + + show_header = False + trusting = tables.Column(attrs={ + 'td': {'class': 'text-center', 'width': '100%'}}) + + trust_back = tables.Column( + verbose_name=_("Trust back"), + accessor="pk", + attrs={ + 'td': { + 'class': '', + 'id': lambda record: "trust_back_" + str(record.pk), + } + }, + ) + + def render_trust_back(self, record): + user_note = record.trusted + trusting_note = record.trusting + if Trust.objects.filter(trusted=trusting_note, trusting=user_note): + return "" + val = '' + return mark_safe(val) + + class AliasTable(tables.Table): class Meta: attrs = { diff --git a/apps/note/templates/note/conso_form.html b/apps/note/templates/note/conso_form.html index d6044b87..25015c90 100644 --- a/apps/note/templates/note/conso_form.html +++ b/apps/note/templates/note/conso_form.html @@ -103,6 +103,11 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endfor %} +
@@ -123,6 +128,20 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endfor %} + @@ -163,7 +182,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endblock %} diff --git a/apps/note/views.py b/apps/note/views.py index 1224f2f8..0cdfe370 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -10,12 +10,12 @@ from django.core.exceptions import PermissionDenied from django.db.models import Q, F from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, UpdateView, DetailView -from django_tables2 import SingleTableView from django.urls import reverse_lazy +from django_tables2 import SingleTableView from activity.models import Entry -from note_kfet.inputs import AmountInput from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin +from note_kfet.inputs import AmountInput from .forms import TransactionTemplateForm, SearchTransactionForm from .models import TemplateCategory, Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial, Note @@ -190,6 +190,10 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): ).order_by('name').all() context['polymorphic_ctype'] = ContentType.objects.get_for_model(RecurrentTransaction).pk + context['all_buttons'] = TransactionTemplate.objects.filter( + PermissionBackend.filter_queryset(self.request, TransactionTemplate, "view") + ).filter(display=True).order_by('name').all() + return context diff --git a/apps/permission/backends.py b/apps/permission/backends.py index f9c90d56..4d7ffbf1 100644 --- a/apps/permission/backends.py +++ b/apps/permission/backends.py @@ -198,6 +198,41 @@ class PermissionBackend(ModelBackend): def has_module_perms(self, user_obj, app_label): return False + @staticmethod + @memoize + def has_model_perm(request, model, type): + """ + Check is the given user has the permission over a given model for a given action. + The result is then memoized. + :param request: The current request + :param model: The model that the permissions shoud apply + :param type: The type of the permissions: view, change, add or delete + For view action, it is consider possible if user can view or change the model + """ + # Requested by a shell + if request is None: + return False + + user_obj = request.user + sess = request.session + + if hasattr(request, 'auth') and request.auth is not None and hasattr(request.auth, 'scope'): + # OAuth2 Authentication + user_obj = request.auth.user + + if user_obj is None or user_obj.is_anonymous: + return False + + if user_obj.is_superuser and sess.get("permission_mask", -1) >= 42: + return True + + ct = ContentType.objects.get_for_model(model) + if any(PermissionBackend.permissions(request, ct, type)): + return True + if type == "view" and any(PermissionBackend.permissions(request, ct, "change")): + return True + return False + def get_all_permissions(self, user_obj, obj=None): ct = ContentType.objects.get_for_model(obj) return list(self.permissions(get_current_request(), ct, "view")) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 35b0a1e5..6e004e09 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -243,7 +243,7 @@ "type": "delete", "mask": 1, "field": "", - "permanent": false, + "permanent": true, "description": "Supprimer un alias à sa note" } }, @@ -319,7 +319,7 @@ "note", "transaction" ], - "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}}, {\"valid\": false}]]", + "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}}, {\"valid\": false}]]", "type": "add", "mask": 2, "field": "", @@ -335,7 +335,7 @@ "note", "recurrenttransaction" ], - "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}}, {\"valid\": false}]]", + "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}}, {\"valid\": false}]]", "type": "add", "mask": 2, "field": "", @@ -369,7 +369,7 @@ ], "query": "{}", "type": "change", - "mask": 1, + "mask": 2, "field": "valid", "permanent": false, "description": "Mettre à jour le statut de validation d'une transaction" @@ -705,7 +705,7 @@ ], "query": "{}", "type": "view", - "mask": 1, + "mask": 2, "field": "", "permanent": false, "description": "Voir toutes les transactions d'invitation" @@ -737,7 +737,7 @@ ], "query": "{\"pk\": [\"club\", \"pk\"]}", "type": "change", - "mask": 1, + "mask": 2, "field": "", "permanent": false, "description": "Modifier un club" @@ -865,7 +865,7 @@ ], "query": "{}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter un utilisateur" @@ -881,7 +881,7 @@ ], "query": "{\"email_confirmed\": false, \"registration_valid\": false}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter un profil" @@ -961,7 +961,7 @@ ], "query": "{\"destination\": [\"club\", \"note\"]}", "type": "change", - "mask": 2, + "mask": 3, "field": "", "permanent": false, "description": "Modifier le bouton d'un club" @@ -1105,7 +1105,7 @@ ], "query": "{}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter un crédit de la Soci\u00e9t\u00e9 g\u00e9n\u00e9rale" @@ -1137,7 +1137,7 @@ ], "query": "{}", "type": "change", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Modifier un crédit de la Soci\u00e9t\u00e9 g\u00e9n\u00e9rale" @@ -1281,7 +1281,7 @@ ], "query": "{\"wei\": [\"club\"], \"first_year\": true, \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"], \"membership\": null}", "type": "add", - "mask": 1, + "mask": 2, "field": "", "permanent": false, "description": "Inscrire un 1A au WEI" @@ -1297,7 +1297,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"], \"membership\": null}", "type": "add", - "mask": 1, + "mask": 2, "field": "", "permanent": false, "description": "Inscrire n'importe qui au WEI" @@ -1313,7 +1313,7 @@ ], "query": "{\"wei\": [\"club\"]}", "type": "delete", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Supprimer une inscription WEI" @@ -1345,9 +1345,9 @@ ], "query": "{\"wei\": [\"club\"]}", "type": "view", - "mask": 1, + "mask": 2, "field": "", - "permanent": true, + "permanent": false, "description": "Voir toutes les inscriptions WEI" } }, @@ -1361,7 +1361,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "soge_credit", "permanent": false, "description": "Indiquer si une inscription WEI est payée par la Société générale" @@ -1393,7 +1393,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 2, "field": "caution_check", "permanent": false, "description": "Dire si un chèque de caution est donné pour une inscription WEI" @@ -1409,7 +1409,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "birth_date", "permanent": false, "description": "Modifier la date de naissance d'une inscription WEI" @@ -1441,7 +1441,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "gender", "permanent": false, "description": "Modifier le genre de toute inscription WEI" @@ -1473,7 +1473,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "health_issues", "permanent": false, "description": "Modifier les problèmes de santé de toutes les inscriptions WEI" @@ -1505,7 +1505,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "emergency_contact_name", "permanent": false, "description": "Modifier le nom du contact en cas d'urgence de toute inscription WEI" @@ -1537,7 +1537,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "emergency_contact_phone", "permanent": false, "description": "Modifier le téléphone du contact en cas d'urgence de toute inscription WEI" @@ -1569,7 +1569,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "information_json", "permanent": false, "description": "Modifier les informations (sondage 1A, ...) d'une inscription WEI" @@ -1697,9 +1697,9 @@ ], "query": "[\"AND\", {\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}, [\"OR\", {\"registration__soge_credit\": true}, {\"user__note__balance__gte\": {\"F\": [\"F\", \"fee\"]}}]]", "type": "add", - "mask": 3, + "mask": 2, "field": "", - "permanent": true, + "permanent": false, "description": "Créer une adhésion WEI pour le dernier WEI" } }, @@ -1713,7 +1713,7 @@ ], "query": "{\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 2, "field": "bus", "permanent": false, "description": "Modifier le bus d'une adhésion WEI" @@ -1729,7 +1729,7 @@ ], "query": "{\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 2, "field": "team", "permanent": false, "description": "Modifier l'équipe d'une adhésion WEI" @@ -1745,9 +1745,9 @@ ], "query": "{\"club\": [\"club\"]}", "type": "view", - "mask": 1, + "mask": 2, "field": "", - "permanent": true, + "permanent": false, "description": "Voir toutes les adhésions au WEI" } }, @@ -1777,9 +1777,9 @@ ], "query": "{\"club\": [\"club\"], \"bus\": [\"membership\", \"weimembership\", \"bus\"]}", "type": "view", - "mask": 1, + "mask": 2, "field": "", - "permanent": true, + "permanent": false, "description": "Voir les membres du bus" } }, @@ -1793,9 +1793,9 @@ ], "query": "{\"club\": [\"club\"], \"team\": [\"membership\", \"weimembership\", \"team\"]}", "type": "view", - "mask": 1, + "mask": 2, "field": "", - "permanent": true, + "permanent": false, "description": "Voir les membres de l'équipe" } }, @@ -1809,7 +1809,7 @@ ], "query": "{\"pk\": [\"membership\", \"weimembership\", \"bus\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "name", "permanent": false, "description": "Modifier le nom du bus" @@ -1825,7 +1825,7 @@ ], "query": "{\"pk\": [\"membership\", \"weimembership\", \"bus\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "description", "permanent": false, "description": "Modifier la description du bus" @@ -1841,7 +1841,7 @@ ], "query": "{\"bus\": [\"membership\", \"weimembership\", \"bus\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter une équipe à mon bus" @@ -1857,7 +1857,7 @@ ], "query": "{\"bus\": [\"membership\", \"weimembership\", \"bus\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "name", "permanent": false, "description": "Modifier le nom d'une équipe de mon bus" @@ -1873,7 +1873,7 @@ ], "query": "{\"bus\": [\"membership\", \"weimembership\", \"bus\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "color", "permanent": false, "description": "Modifier la couleur d'une équipe de mon bus" @@ -1889,7 +1889,7 @@ ], "query": "{\"bus\": [\"membership\", \"weimembership\", \"bus\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "description", "permanent": false, "description": "Modifier la description d'une équipe de mon bus" @@ -1905,7 +1905,7 @@ ], "query": "{\"pk\": [\"membership\", \"weimembership\", \"team\", \"pk\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "name", "permanent": false, "description": "Modifier le nom de mon équipe" @@ -1921,7 +1921,7 @@ ], "query": "{\"pk\": [\"membership\", \"weimembership\", \"team\", \"pk\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "color", "permanent": false, "description": "Modifier la couleur de mon équipe" @@ -1937,7 +1937,7 @@ ], "query": "{\"pk\": [\"membership\", \"weimembership\", \"team\", \"pk\"], \"bus__wei__date_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "description", "permanent": false, "description": "Modifier la description de mon équipe" @@ -1967,7 +1967,7 @@ "note", "transaction" ], - "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]]", + "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": true}]]", "type": "change", "mask": 2, "field": "valid", @@ -1985,7 +1985,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "clothing_cut", "permanent": false, "description": "Modifier la coupe de vêtements d'une inscription WEI" @@ -2017,7 +2017,7 @@ ], "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}", "type": "change", - "mask": 1, + "mask": 3, "field": "clothing_size", "permanent": false, "description": "Modifier la taille de vêtements d'une inscription WEI" @@ -2063,7 +2063,7 @@ "note", "transaction" ], - "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]]", + "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": false}]]", "type": "change", "mask": 2, "field": "invalidity_reason", @@ -2225,7 +2225,7 @@ ], "query": "{}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Créer une note d'utilisateur" @@ -2257,7 +2257,7 @@ ], "query": "{}", "type": "view", - "mask": 1, + "mask": 2, "field": "", "permanent": false, "description": "Voir toutes les notes de club" @@ -2276,7 +2276,7 @@ "mask": 3, "field": "", "permanent": false, - "description": "Voir tous les adhérents du club" + "description": "Voir tous les adhérents de tous les clubs" } }, { @@ -2564,7 +2564,7 @@ "mask": 3, "field": "inactivity_reason", "permanent": false, - "description": "(Dé)bloquer sa propre note et modifier la raison" + "description": "(Dé)bloquer n'importe quelle note et indiquer la raison" } }, { @@ -2591,12 +2591,12 @@ "note", "transaction" ], - "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}}, {\"valid\": false}]", + "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}}, {\"valid\": false}]", "type": "add", "mask": 2, "field": "", "permanent": false, - "description": "Créer une transaction quelconque tant que la source reste au-dessus de -50 €" + "description": "Créer une transaction quelconque tant que la source reste au-dessus de -20 €" } }, { @@ -2607,12 +2607,12 @@ "note", "transaction" ], - "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]", + "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": true}]", "type": "change", "mask": 2, "field": "valid", "permanent": false, - "description": "Modifier le statut de validation d'une transaction si c'est possible" + "description": "Modifier le statut de validation d'une transaction si tout le monde reste au dessus de -20 €" } }, { @@ -2623,12 +2623,12 @@ "note", "transaction" ], - "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]", + "query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 2000]}, \"valid\": true}]", "type": "change", "mask": 2, "field": "invalidity_reason", "permanent": false, - "description": "Modifier la raison d'invalidité d'une transaction si c'est possible" + "description": "Modifier la raison d'invalidité d'une transaction si tout le monde reste au dessus de -20 €" } }, { @@ -2641,7 +2641,7 @@ ], "query": "{\"club\": [\"club\"]}", "type": "change", - "mask": 1, + "mask": 2, "field": "display_image", "permanent": false, "description": "Changer l'image de la note de son club" @@ -2657,7 +2657,7 @@ ], "query": "{\"note__is_active\": true}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter n'importe quel alias à une note non bloquée" @@ -2753,7 +2753,7 @@ ], "query": "{\"profile__registration_valid\": false}", "type": "change", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Modifier n'importe quel utilisateur non encore inscrit" @@ -2769,7 +2769,7 @@ ], "query": "{\"registration_valid\": false}", "type": "change", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Modifier n'importe quel profil non encore inscrit" @@ -2865,7 +2865,7 @@ ], "query": "{}", "type": "change", - "mask": 1, + "mask": 3, "field": "display_image", "permanent": false, "description": "Changer l'image de n'importe quelle note" @@ -2883,7 +2883,7 @@ "type": "change", "mask": 3, "field": "is_active", - "permanent": true, + "permanent": false, "description": "(Dé)bloquer la note de son club manuellement" } }, @@ -2899,7 +2899,7 @@ "type": "change", "mask": 3, "field": "inactivity_reason", - "permanent": true, + "permanent": false, "description": "(Dé)bloquer la note de son club et indiquer que cela a été fait manuellement" } }, @@ -2928,7 +2928,7 @@ "application" ], "query": "{\"user\": [\"user\"]}", - "type": "create", + "type": "add", "mask": 1, "field": "", "permanent": true, @@ -2979,7 +2979,7 @@ "type": "delete", "mask": 1, "field": "", - "permanent": false, + "permanent": true, "description": "Supprimer une amitié à sa note" } }, @@ -3009,7 +3009,7 @@ ], "query": "{\"trusting__is_active\": true}", "type": "add", - "mask": 1, + "mask": 3, "field": "", "permanent": false, "description": "Ajouter une amitié à une note non bloquée" @@ -3079,6 +3079,38 @@ "description": "Transférer de l'argent depuis une note amie en restant positif" } }, + { + "model": "permission.permission", + "pk": 197, + "fields": { + "model": [ + "note", + "specialtransaction" + ], + "query": "{\"source__notespecial__gte\":0}", + "type": "add", + "mask": 2, + "field": "", + "permanent": false, + "description": "Créer un crédit quelconque" + } + }, + { + "model": "permission.permission", + "pk": 198, + "fields": { + "model": [ + "note", + "trust" + ], + "query": "{\"trusted__noteuser__user\": [\"user\"]}", + "type": "view", + "mask": 1, + "field": "", + "permanent": true, + "description": "Voir ceux nous ayant pour ami, pour toujours" + } + }, { "model": "permission.role", "pk": 1, @@ -3104,12 +3136,14 @@ 16, 17, 22, + 34, 48, 52, 126, 161, 162, 165, + 179, 186, 187, 188, @@ -3117,7 +3151,8 @@ 190, 191, 195, - 196 + 196, + 198 ] } }, @@ -3129,11 +3164,9 @@ "name": "Adh\u00e9rent Kfet", "permissions": [ 22, - 34, 36, 39, 40, - 70, 78, 79, 83, @@ -3157,10 +3190,7 @@ 157, 158, 159, - 160, - 179, - 189, - 190 + 160 ] } }, @@ -3197,9 +3227,7 @@ "for_club": null, "name": "Pr\u00e9sident\u00b7e de club", "permissions": [ - 50, 62, - 141, 142 ] } @@ -3211,23 +3239,17 @@ "for_club": null, "name": "Tr\u00e9sorier\u00b7\u00e8re de club", "permissions": [ - 59, 19, 20, 21, 27, + 59, 60, 61, 62, 127, 133, - 136, - 141, 142, - 150, - 166, - 167, - 168, 182, 184, 185 @@ -3246,7 +3268,20 @@ 26, 27, 30, - 33 + 41, + 42, + 63, + 66, + 135, + 136, + 137, + 150, + 163, + 164, + 166, + 167, + 168, + 172 ] } }, @@ -3268,6 +3303,10 @@ 31, 32, 33, + 37, + 38, + 41, + 42, 43, 51, 53, @@ -3283,6 +3322,7 @@ 67, 68, 69, + 70, 71, 72, 73, @@ -3297,12 +3337,12 @@ 143, 146, 147, + 148, + 149, 150, 151, 163, 164, - 170, - 171, 172, 173, 174, @@ -3310,10 +3350,7 @@ 176, 177, 178, - 188, - 183, - 186, - 187 + 183 ] } }, @@ -3323,199 +3360,7 @@ "fields": { "for_club": 1, "name": "Respo info", - "permissions": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 123, - 124, - 125, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 145, - 146, - 147, - 148, - 149, - 150, - 151, - 152, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196 - ] + "permissions": [] } }, { @@ -3525,12 +3370,6 @@ "for_club": 2, "name": "GC Kfet", "permissions": [ - 32, - 56, - 58, - 55, - 57, - 52, 23, 24, 25, @@ -3540,20 +3379,16 @@ 29, 30, 31, - 70, - 72, - 143, + 32, + 37, + 38, + 41, + 43, + 148, + 149, 166, 167, 168, - 170, - 171, - 176, - 177, - 178, - 179, - 180, - 181, 182 ] } @@ -3565,6 +3400,9 @@ "for_club": 2, "name": "Res[pot]", "permissions": [ + 19, + 25, + 26, 37, 38, 41, @@ -3587,6 +3425,8 @@ "name": "GC WEI", "permissions": [ 22, + 70, + 72, 76, 85, 86, @@ -3608,8 +3448,8 @@ 111, 112, 113, - 130, - 131 + 128, + 130 ] } }, @@ -3622,12 +3462,13 @@ "permissions": [ 22, 84, + 115, 117, 118, + 119, 120, 121, - 122, - 115 + 122 ] } }, @@ -3688,18 +3529,7 @@ "name": "Adhérent WEI", "permissions": [ 77, - 87, - 90, - 93, - 95, - 97, - 99, - 101, - 108, - 109, - 114, - 128, - 130 + 114 ] } }, @@ -3710,6 +3540,9 @@ "for_club": 1, "name": "Secrétaire BDE", "permissions": [ + 37, + 41, + 53, 54, 55, 56, @@ -3718,15 +3551,21 @@ 135, 136, 137, + 138, 139, 140, 143, 145, 146, 147, + 148, + 149, 150, 176, - 177 + 177, + 180, + 181, + 183 ] } }, @@ -3738,23 +3577,15 @@ "name": "PC Kfet", "permissions": [ 6, - 22, 24, 25, - 26, 27, 30, + 34, 49, 50, - 55, - 56, - 57, - 58, - 70, - 72, 135, 137, - 143, 147, 150, 166, @@ -3762,8 +3593,21 @@ 168, 176, 177, - 180, - 181 + 197 + ] + } + }, + { + "model": "permission.role", + "pk": 21, + "fields": { + "for_club": 1, + "name": "GC anti-VSS", + "permissions": [ + 150, + 163, + 164, + 182 ] } }, diff --git a/apps/permission/migrations/0002_club_not_required.py b/apps/permission/migrations/0002_club_not_required.py new file mode 100644 index 00000000..ead242aa --- /dev/null +++ b/apps/permission/migrations/0002_club_not_required.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2023-07-24 10:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('permission', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='role', + name='for_club', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='member.Club', verbose_name='for club'), + ), + ] diff --git a/apps/permission/models.py b/apps/permission/models.py index 7ca309ca..c05dcc4b 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -339,6 +339,7 @@ class Role(models.Model): "member.Club", verbose_name=_("for club"), on_delete=models.PROTECT, + blank=True, null=True, default=None, ) diff --git a/apps/registration/forms.py b/apps/registration/forms.py index 64e79d52..6761da43 100644 --- a/apps/registration/forms.py +++ b/apps/registration/forms.py @@ -5,6 +5,7 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.utils.translation import gettext_lazy as _ +from member.models import Club from note.models import NoteSpecial, Alias from note_kfet.inputs import AmountInput @@ -44,14 +45,14 @@ class SignUpForm(UserCreationForm): fields = ('first_name', 'last_name', 'username', 'email', ) -class DeclareSogeAccountOpenedForm(forms.Form): - soge_account = forms.BooleanField( - label=_("I declare that I opened or I will open soon a bank account in the Société générale with the BDE " - "partnership."), - help_text=_("Warning: this engages you to open your bank account. If you finally decides to don't open your " - "account, you will have to pay the BDE membership."), - required=False, - ) +# class DeclareSogeAccountOpenedForm(forms.Form): +# soge_account = forms.BooleanField( +# label=_("I declare that I opened or I will open soon a bank account in the Société générale with the BDE " +# "partnership."), +# help_text=_("Warning: this engages you to open your bank account. If you finally decides to don't open your " +# "account, you will have to pay the BDE membership."), +# required=False, +# ) class WEISignupForm(forms.Form): @@ -67,11 +68,11 @@ class ValidationForm(forms.Form): """ Validate the inscription of the new users and pay memberships. """ - soge = forms.BooleanField( - label=_("Inscription paid by Société Générale"), - required=False, - help_text=_("Check this case if the Société Générale paid the inscription."), - ) +# soge = forms.BooleanField( +# label=_("Inscription paid by Société Générale"), +# required=False, +# help_text=_("Check this case if the Société Générale paid the inscription."), +# ) credit_type = forms.ModelChoiceField( queryset=NoteSpecial.objects, @@ -114,3 +115,12 @@ class ValidationForm(forms.Form): required=False, initial=True, ) + + # If the bda exists + if Club.objects.filter(name__iexact="bda").exists(): + # The user can join the bda club at the inscription + join_bda = forms.BooleanField( + label=_("Join BDA Club"), + required=False, + initial=True, + ) diff --git a/apps/registration/templates/registration/future_profile_detail.html b/apps/registration/templates/registration/future_profile_detail.html index 577ad219..be0c084f 100644 --- a/apps/registration/templates/registration/future_profile_detail.html +++ b/apps/registration/templates/registration/future_profile_detail.html @@ -57,11 +57,13 @@ SPDX-License-Identifier: GPL-3.0-or-later

{% trans "Validate account" %}

+ {% comment "Soge not for membership (only WEI)" %} {% if declare_soge_account %}
{% trans "The user declared that he/she opened a bank account in the Société générale." %}
{% endif %} + {% endcomment %}
{% csrf_token %} @@ -76,6 +78,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endblock %} +{% comment "Soge not for membership (only WEI)" %} {% block extrajavascript %} {% endblock %} +{% endcomment %} diff --git a/apps/registration/tests/test_registration.py b/apps/registration/tests/test_registration.py index 18cf16db..69ab52d5 100644 --- a/apps/registration/tests/test_registration.py +++ b/apps/registration/tests/test_registration.py @@ -48,6 +48,7 @@ class TestSignup(TestCase): ml_events_registration="en", ml_sport_registration=True, ml_art_registration=True, + VSS_charter_read=True )) self.assertRedirects(response, reverse("registration:email_validation_sent"), 302, 200) self.assertTrue(User.objects.filter(username="toto").exists()) @@ -105,6 +106,7 @@ class TestSignup(TestCase): ml_events_registration="en", ml_sport_registration=True, ml_art_registration=True, + VSS_charter_read=True )) self.assertTrue(response.status_code, 200) @@ -124,6 +126,7 @@ class TestSignup(TestCase): ml_events_registration="en", ml_sport_registration=True, ml_art_registration=True, + VSS_charter_read=True )) self.assertTrue(response.status_code, 200) @@ -143,6 +146,27 @@ class TestSignup(TestCase): ml_events_registration="en", ml_sport_registration=True, ml_art_registration=True, + VSS_charter_read=True + )) + self.assertTrue(response.status_code, 200) + + # The VSS charter is not read + response = self.client.post(reverse("registration:signup"), dict( + first_name="Toto", + last_name="TOTO", + username="Ihaveanotherusername", + email="othertoto@example.com", + password1="toto1234", + password2="toto1234", + phone_number="+33123456789", + department="EXT", + promotion=Club.objects.get(name="BDE").membership_start.year, + address="Earth", + paid=False, + ml_events_registration="en", + ml_sport_registration=True, + ml_art_registration=True, + VSS_charter_read=False )) self.assertTrue(response.status_code, 200) @@ -190,7 +214,7 @@ class TestValidateRegistration(TestCase): # BDE Membership is mandatory response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Chèque").id, credit_amount=4200, last_name="TOTO", @@ -204,7 +228,7 @@ class TestValidateRegistration(TestCase): # Same response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type="", credit_amount=0, last_name="TOTO", @@ -218,7 +242,7 @@ class TestValidateRegistration(TestCase): # The BDE membership is not free response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Espèces").id, credit_amount=0, last_name="TOTO", @@ -232,7 +256,7 @@ class TestValidateRegistration(TestCase): # Last and first names are required for a credit response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Chèque").id, credit_amount=4000, last_name="", @@ -249,7 +273,7 @@ class TestValidateRegistration(TestCase): self.user.username = "admïntoto" self.user.save() response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Chèque").id, credit_amount=500, last_name="TOTO", @@ -275,7 +299,7 @@ class TestValidateRegistration(TestCase): self.user.profile.save() response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Chèque").id, credit_amount=500, last_name="TOTO", @@ -290,6 +314,7 @@ class TestValidateRegistration(TestCase): self.assertTrue(NoteUser.objects.filter(user=self.user).exists()) self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists()) self.assertFalse(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) + self.assertFalse(Membership.objects.filter(club__name__iexact="BDA", user=self.user).exists()) self.assertFalse(SogeCredit.objects.filter(user=self.user).exists()) self.assertEqual(Transaction.objects.filter( Q(source=self.user.note) | Q(destination=self.user.note)).count(), 2) @@ -311,7 +336,7 @@ class TestValidateRegistration(TestCase): self.user.profile.save() response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=False, + # soge=False, credit_type=NoteSpecial.objects.get(special_type="Espèces").id, credit_amount=4000, last_name="TOTO", @@ -326,6 +351,7 @@ class TestValidateRegistration(TestCase): self.assertTrue(NoteUser.objects.filter(user=self.user).exists()) self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists()) self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) + self.assertFalse(Membership.objects.filter(club__name__iexact="BDA", user=self.user).exists()) self.assertFalse(SogeCredit.objects.filter(user=self.user).exists()) self.assertEqual(Transaction.objects.filter( Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) @@ -333,42 +359,43 @@ class TestValidateRegistration(TestCase): response = self.client.get(self.user.profile.get_absolute_url()) self.assertEqual(response.status_code, 200) - def test_validate_kfet_registration_with_soge(self): - """ - The user joins the BDE and the Kfet, but the membership is paid by the Société générale. - """ - response = self.client.get(reverse("registration:future_user_detail", args=(self.user.pk,))) - self.assertEqual(response.status_code, 200) - - response = self.client.get(self.user.profile.get_absolute_url()) - self.assertEqual(response.status_code, 404) - - self.user.profile.email_confirmed = True - self.user.profile.save() - - response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( - soge=True, - credit_type=NoteSpecial.objects.get(special_type="Espèces").id, - credit_amount=4000, - last_name="TOTO", - first_name="Toto", - bank="Société générale", - join_bde=True, - join_kfet=True, - )) - self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200) - self.user.profile.refresh_from_db() - self.assertTrue(self.user.profile.registration_valid) - self.assertTrue(NoteUser.objects.filter(user=self.user).exists()) - self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists()) - self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) - self.assertTrue(SogeCredit.objects.filter(user=self.user).exists()) - self.assertEqual(Transaction.objects.filter( - Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) - self.assertFalse(Transaction.objects.filter(valid=True).exists()) - - response = self.client.get(self.user.profile.get_absolute_url()) - self.assertEqual(response.status_code, 200) +# def test_validate_kfet_registration_with_soge(self): +# """ +# The user joins the BDE and the Kfet, but the membership is paid by the Société générale. +# """ +# response = self.client.get(reverse("registration:future_user_detail", args=(self.user.pk,))) +# self.assertEqual(response.status_code, 200) +# +# response = self.client.get(self.user.profile.get_absolute_url()) +# self.assertEqual(response.status_code, 404) +# +# self.user.profile.email_confirmed = True +# self.user.profile.save() +# +# response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict( +# soge=True, +# credit_type=NoteSpecial.objects.get(special_type="Espèces").id, +# credit_amount=4000, +# last_name="TOTO", +# first_name="Toto", +# bank="Société générale", +# join_bde=True, +# join_kfet=True, +# )) +# self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200) +# self.user.profile.refresh_from_db() +# self.assertTrue(self.user.profile.registration_valid) +# self.assertTrue(NoteUser.objects.filter(user=self.user).exists()) +# self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists()) +# self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) +# self.assertFalse(Membership.objects.filter(club__name__iexact="BDA", user=self.user).exists()) +# self.assertTrue(SogeCredit.objects.filter(user=self.user).exists()) +# self.assertEqual(Transaction.objects.filter( +# Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) +# self.assertFalse(Transaction.objects.filter(valid=True).exists()) +# +# response = self.client.get(self.user.profile.get_absolute_url()) +# self.assertEqual(response.status_code, 200) def test_invalidate_registration(self): """ diff --git a/apps/registration/views.py b/apps/registration/views.py index b256f591..eb415bdd 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -24,7 +24,8 @@ from permission.models import Role from permission.views import ProtectQuerysetMixin from treasury.models import SogeCredit -from .forms import SignUpForm, ValidationForm, DeclareSogeAccountOpenedForm +# from .forms import SignUpForm, ValidationForm, DeclareSogeAccountOpenedForm +from .forms import SignUpForm, ValidationForm from .tables import FutureUserTable from .tokens import email_validation_token @@ -42,7 +43,7 @@ class UserCreateView(CreateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["profile_form"] = self.second_form(self.request.POST if self.request.POST else None) - context["soge_form"] = DeclareSogeAccountOpenedForm(self.request.POST if self.request.POST else None) +# context["soge_form"] = DeclareSogeAccountOpenedForm(self.request.POST if self.request.POST else None) del context["profile_form"].fields["section"] del context["profile_form"].fields["report_frequency"] del context["profile_form"].fields["last_report"] @@ -75,12 +76,12 @@ class UserCreateView(CreateView): user.profile.send_email_validation_link() - soge_form = DeclareSogeAccountOpenedForm(self.request.POST) - if "soge_account" in soge_form.data and soge_form.data["soge_account"]: - # If the user declares that a bank account got opened, prepare the soge credit to warn treasurers - soge_credit = SogeCredit(user=user) - soge_credit._force_save = True - soge_credit.save() +# soge_form = DeclareSogeAccountOpenedForm(self.request.POST) +# if "soge_account" in soge_form.data and soge_form.data["soge_account"]: +# # If the user declares that a bank account got opened, prepare the soge credit to warn treasurers +# soge_credit = SogeCredit(user=user) +# soge_credit._force_save = True +# soge_credit.save() return super().form_valid(form) @@ -237,9 +238,12 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid kfet = Club.objects.get(name="Kfet") fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid + if Club.objects.filter(name__iexact="BDA").exists(): + bda = Club.objects.get(name__iexact="BDA") + fee += bda.membership_fee_paid if user.profile.paid else bda.membership_fee_unpaid ctx["total_fee"] = "{:.02f}".format(fee / 100, ) - ctx["declare_soge_account"] = SogeCredit.objects.filter(user=user).exists() +# ctx["declare_soge_account"] = SogeCredit.objects.filter(user=user).exists() return ctx @@ -262,8 +266,13 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, form.add_error(None, _("An alias with a similar name already exists.")) return self.form_invalid(form) + # Check if BDA exist to propose membership at regisration + bda_exists = False + if Club.objects.filter(name__iexact="BDA").exists(): + bda_exists = True + # Get form data - soge = form.cleaned_data["soge"] +# soge = form.cleaned_data["soge"] credit_type = form.cleaned_data["credit_type"] credit_amount = form.cleaned_data["credit_amount"] last_name = form.cleaned_data["last_name"] @@ -271,11 +280,13 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, bank = form.cleaned_data["bank"] join_bde = form.cleaned_data["join_bde"] join_kfet = form.cleaned_data["join_kfet"] + if bda_exists: + join_bda = form.cleaned_data["join_bda"] - if soge: - # If Société Générale pays the inscription, the user automatically joins the two clubs. - join_bde = True - join_kfet = True +# if soge: +# # If Société Générale pays the inscription, the user automatically joins the two clubs. +# join_bde = True +# join_kfet = True if not join_bde: # This software belongs to the BDE. @@ -292,15 +303,21 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, kfet_fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid # Add extra fee for the full membership fee += kfet_fee if join_kfet else 0 + if bda_exists: + bda = Club.objects.get(name__iexact="BDA") + bda_fee = bda.membership_fee_paid if user.profile.paid else bda.membership_fee_unpaid + # Add extra fee for the bda membership + fee += bda_fee if join_bda else 0 - # If the bank pays, then we don't credit now. Treasurers will validate the transaction - # and credit the note later. - credit_type = None if soge else credit_type +# # If the bank pays, then we don't credit now. Treasurers will validate the transaction +# # and credit the note later. +# credit_type = None if soge else credit_type # If the user does not select any payment method, then no credit will be performed. credit_amount = 0 if credit_type is None else credit_amount - if fee > credit_amount and not soge: +# if fee > credit_amount and not soge: + if fee > credit_amount: # Check if the user credits enough money form.add_error('credit_type', _("The entered amount is not enough for the memberships, should be at least {}") @@ -320,12 +337,12 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, user.profile.save() user.refresh_from_db() - if not soge and SogeCredit.objects.filter(user=user).exists(): - # If the user declared that a bank account was opened but in the validation form the SoGé case was - # unchecked, delete the associated credit - soge_credit = SogeCredit.objects.get(user=user) - soge_credit._force_delete = True - soge_credit.delete() +# if not soge and SogeCredit.objects.filter(user=user).exists(): +# # If the user declared that a bank account was opened but in the validation form the SoGé case was +# # unchecked, delete the associated credit +# soge_credit = SogeCredit.objects.get(user=user) +# soge_credit._force_delete = True +# soge_credit.delete() if credit_type is not None and credit_amount > 0: # Credit the note @@ -334,7 +351,8 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, destination=user.note, quantity=1, amount=credit_amount, - reason="Crédit " + ("Société générale" if soge else credit_type.special_type) + " (Inscription)", + reason="Crédit " + credit_type.special_type + " (Inscription)", + # reason="Crédit " + ("Société générale" if soge else credit_type.special_type) + " (Inscription)", last_name=last_name, first_name=first_name, bank=bank, @@ -348,8 +366,8 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, user=user, fee=bde_fee, ) - if soge: - membership._soge = True +# if soge: +# membership._soge = True membership.save() membership.refresh_from_db() membership.roles.add(Role.objects.get(name="Adhérent BDE")) @@ -362,17 +380,29 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, user=user, fee=kfet_fee, ) - if soge: - membership._soge = True +# if soge: +# membership._soge = True membership.save() membership.refresh_from_db() membership.roles.add(Role.objects.get(name="Adhérent Kfet")) membership.save() - if soge: - soge_credit = SogeCredit.objects.get(user=user) - # Update the credit transaction amount - soge_credit.save() + if bda_exists and join_bda: + # Create membership for the user to the BDA starting today + membership = Membership( + club=bda, + user=user, + fee=bda_fee, + ) + membership.save() + membership.refresh_from_db() + membership.roles.add(Role.objects.get(name="Membre de club")) + membership.save() + +# if soge: +# soge_credit = SogeCredit.objects.get(user=user) +# # Update the credit transaction amount +# soge_credit.save() return ret diff --git a/apps/treasury/migrations/0005_auto_20230129_2348.py b/apps/treasury/migrations/0005_auto_20230129_2348.py new file mode 100644 index 00000000..bd8a607a --- /dev/null +++ b/apps/treasury/migrations/0005_auto_20230129_2348.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-01-29 22:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('treasury', '0004_auto_20211005_1544'), + ] + + operations = [ + migrations.AlterField( + model_name='invoice', + name='bde', + field=models.CharField(choices=[('TotalistSpies', 'Tota[list]Spies'), ('Saperlistpopette', 'Saper[list]popette'), ('Finalist', 'Fina[list]'), ('Listorique', '[List]orique'), ('Satellist', 'Satel[list]'), ('Monopolist', 'Monopo[list]'), ('Kataclist', 'Katac[list]')], default='TotalistSpies', max_length=32, verbose_name='BDE'), + ), + ] diff --git a/apps/treasury/migrations/0006_auto_20230414_1651.py b/apps/treasury/migrations/0006_auto_20230414_1651.py new file mode 100644 index 00000000..98df4316 --- /dev/null +++ b/apps/treasury/migrations/0006_auto_20230414_1651.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-04-14 14:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('treasury', '0005_auto_20230129_2348'), + ] + + operations = [ + migrations.AlterField( + model_name='invoice', + name='bde', + field=models.CharField(choices=[('SecretStorlist', 'SecretStor[list]'), ('TotalistSpies', 'Tota[list]Spies'), ('Saperlistpopette', 'Saper[list]popette'), ('Finalist', 'Fina[list]'), ('Listorique', '[List]orique'), ('Satellist', 'Satel[list]'), ('Monopolist', 'Monopo[list]'), ('Kataclist', 'Katac[list]')], default='SecretStorlist', max_length=32, verbose_name='BDE'), + ), + ] diff --git a/apps/treasury/models.py b/apps/treasury/models.py index 51e2b885..e788e479 100644 --- a/apps/treasury/models.py +++ b/apps/treasury/models.py @@ -1,6 +1,5 @@ -# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -import datetime from datetime import date from django.conf import settings @@ -12,7 +11,8 @@ from django.db.models import Q from django.template.loader import render_to_string from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from member.models import Club, Membership +# from member.models import Club, Membership # Club unused because of disabled soge +from member.models import Membership from note.models import NoteSpecial, SpecialTransaction, MembershipTransaction, NoteUser @@ -28,8 +28,10 @@ class Invoice(models.Model): bde = models.CharField( max_length=32, - default='Saperlistpopette', + default='SecretStorlist', choices=( + ('SecretStorlist', 'SecretStor[list]'), + ('TotalistSpies', 'Tota[list]Spies'), ('Saperlistpopette', 'Saper[list]popette'), ('Finalist', 'Fina[list]'), ('Listorique', '[List]orique'), @@ -95,7 +97,7 @@ class Invoice(models.Model): products = self.products.all() self.place = "Gif-sur-Yvette" - self.my_name = "BDE ENS Cachan" + self.my_name = "BDE ENS Paris Saclay" self.my_address_street = "4 avenue des Sciences" self.my_city = "91190 Gif-sur-Yvette" self.bank_code = 30003 @@ -324,23 +326,23 @@ class SogeCredit(models.Model): if self.valid or not self.pk: return - bde = Club.objects.get(name="BDE") - kfet = Club.objects.get(name="Kfet") - bde_qs = Membership.objects.filter(user=self.user, club=bde, date_start__gte=bde.membership_start) - kfet_qs = Membership.objects.filter(user=self.user, club=kfet, date_start__gte=kfet.membership_start) +# Soge do not pay BDE and kfet memberships since 2022 +# bde = Club.objects.get(name="BDE") +# kfet = Club.objects.get(name="Kfet") +# bde_qs = Membership.objects.filter(user=self.user, club=bde, date_start__gte=bde.membership_start) +# kfet_qs = Membership.objects.filter(user=self.user, club=kfet, date_start__gte=kfet.membership_start) -## Soge do not pay BDE and kfet memberships this year (2022-2023) # if bde_qs.exists(): # m = bde_qs.get() # if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership # if m.transaction not in self.transactions.all(): # self.transactions.add(m.transaction) # -# if kfet_qs.exists(): -# m = kfet_qs.get() -# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership -# if m.transaction not in self.transactions.all(): -# self.transactions.add(m.transaction) +# if kfet_qs.exists(): +# m = kfet_qs.get() +# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership +# if m.transaction not in self.transactions.all(): +# self.transactions.add(m.transaction) if 'wei' in settings.INSTALLED_APPS: from wei.models import WEIClub @@ -386,7 +388,6 @@ class SogeCredit(models.Model): for tr in self.transactions.all(): tr.valid = True tr._force_save = True - tr.created_at = timezone.now() tr.save() @transaction.atomic @@ -435,12 +436,11 @@ class SogeCredit(models.Model): for tr in self.transactions.all(): tr._force_save = True tr.valid = True - tr.created_at = timezone.now() tr.save() if self.credit_transaction: # If the soge credit is deleted while the user is not validated yet, # there is not credit transaction. - # There is a credit transaction iff the user declares that no bank account + # There is a credit transaction if the user declares that no bank account # was opened after the validation of the account. self.credit_transaction.valid = False self.credit_transaction.reason += " (invalide)" diff --git a/apps/treasury/static/img/SecretStorlist.png b/apps/treasury/static/img/SecretStorlist.png new file mode 100644 index 00000000..5b7766fd Binary files /dev/null and b/apps/treasury/static/img/SecretStorlist.png differ diff --git a/apps/treasury/static/img/SecretStorlist_bg.jpg b/apps/treasury/static/img/SecretStorlist_bg.jpg new file mode 100644 index 00000000..8c5b0d26 Binary files /dev/null and b/apps/treasury/static/img/SecretStorlist_bg.jpg differ diff --git a/apps/treasury/static/img/TotalistSpies.png b/apps/treasury/static/img/TotalistSpies.png new file mode 100644 index 00000000..196b4bc0 Binary files /dev/null and b/apps/treasury/static/img/TotalistSpies.png differ diff --git a/apps/treasury/static/img/TotalistSpies_bg.jpg b/apps/treasury/static/img/TotalistSpies_bg.jpg new file mode 100644 index 00000000..829ee2fa Binary files /dev/null and b/apps/treasury/static/img/TotalistSpies_bg.jpg differ diff --git a/apps/treasury/templates/treasury/invoice_sample.tex b/apps/treasury/templates/treasury/invoice_sample.tex index f07f00f5..f34b7ad3 100644 --- a/apps/treasury/templates/treasury/invoice_sample.tex +++ b/apps/treasury/templates/treasury/invoice_sample.tex @@ -105,8 +105,8 @@ \renewcommand{\headrulewidth}{0pt} \cfoot{ - \small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)6 89 88 56 50\newline - Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011 + \small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)7 78 17 22 34\newline + Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00029 } } diff --git a/apps/treasury/tests/test_treasury.py b/apps/treasury/tests/test_treasury.py index 798a960f..bc0eddc3 100644 --- a/apps/treasury/tests/test_treasury.py +++ b/apps/treasury/tests/test_treasury.py @@ -385,8 +385,7 @@ class TestSogeCredits(TestCase): response = self.client.post(reverse("treasury:manage_soge_credit", args=(soge_credit.pk,)), data=dict(delete=True)) - # 403 because no SogeCredit exists anymore, then a PermissionDenied is raised - self.assertRedirects(response, reverse("treasury:soge_credits"), 302, 403) + self.assertRedirects(response, reverse("treasury:soge_credits"), 302, 200) self.assertFalse(SogeCredit.objects.filter(pk=soge_credit.pk)) self.user.note.refresh_from_db() self.assertEqual(self.user.note.balance, 0) diff --git a/apps/treasury/views.py b/apps/treasury/views.py index aee6ea04..fef684cc 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -101,14 +101,7 @@ class InvoiceListView(LoginRequiredMixin, SingleTableView): if not request.user.is_authenticated: return self.handle_no_permission() - sample_invoice = Invoice( - id=0, - object="", - description="", - name="", - address="", - ) - if not PermissionBackend.check_perm(self.request, "treasury.add_invoice", sample_invoice): + if not PermissionBackend.has_model_perm(self.request, Invoice(), "view"): raise PermissionDenied(_("You are not able to see the treasury interface.")) return super().dispatch(request, *args, **kwargs) @@ -278,11 +271,7 @@ class RemittanceListView(LoginRequiredMixin, TemplateView): if not request.user.is_authenticated: return self.handle_no_permission() - sample_remittance = Remittance( - remittance_type_id=1, - comment="", - ) - if not PermissionBackend.check_perm(self.request, "treasury.add_remittance", sample_remittance): + if not PermissionBackend.has_model_perm(self.request, Remittance(), "view"): raise PermissionDenied(_("You are not able to see the treasury interface.")) return super().dispatch(request, *args, **kwargs) @@ -408,7 +397,7 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi if not request.user.is_authenticated: return self.handle_no_permission() - if not super().get_queryset().exists(): + if not PermissionBackend.has_model_perm(self.request, SogeCredit(), "view"): raise PermissionDenied(_("You are not able to see the treasury interface.")) return super().dispatch(request, *args, **kwargs) diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py index e934fb50..408071f4 100644 --- a/apps/wei/forms/registration.py +++ b/apps/wei/forms/registration.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later from django import forms @@ -38,7 +38,7 @@ class WEIRegistrationForm(forms.ModelForm): class Meta: model = WEIRegistration - exclude = ('wei', ) + exclude = ('wei', 'clothing_cut') widgets = { "user": Autocomplete( User, diff --git a/apps/wei/forms/surveys/__init__.py b/apps/wei/forms/surveys/__init__.py index 06fcfae5..0b1c583f 100644 --- a/apps/wei/forms/surveys/__init__.py +++ b/apps/wei/forms/surveys/__init__.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: GPL-3.0-or-later from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm -from .wei2022 import WEISurvey2022 +from .wei2023 import WEISurvey2023 __all__ = [ 'WEISurvey', 'WEISurveyInformation', 'WEISurveyAlgorithm', 'CurrentSurvey', ] -CurrentSurvey = WEISurvey2022 +CurrentSurvey = WEISurvey2023 diff --git a/apps/wei/forms/surveys/wei2022.py b/apps/wei/forms/surveys/wei2022.py index cb2b4adb..6a6aecd5 100644 --- a/apps/wei/forms/surveys/wei2022.py +++ b/apps/wei/forms/surveys/wei2022.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2022 by BDE ENS Paris-Saclay +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import time @@ -14,17 +14,17 @@ from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInf from ...models import WEIMembership WORDS = [ - 'ABBA', 'After', 'Alcoolique anonyme', 'Ambiance festive', 'Années 2000', 'Apéro', 'Art', - 'Baby foot billard biere pong', 'BBQ', 'Before', 'Bière pong', 'Bon enfant', 'Calme', 'Canapé', - 'Chanson paillarde', 'Chanson populaire', 'Chartreuse', 'Cheerleader', 'Chill', 'Choré', - 'Cinéma', 'Cocktail', 'Comédie musicle', 'Commercial', 'Copaing', 'Danse', 'Dancefloor', - 'Electro', 'Fanfare', 'Gin tonic', 'Inclusif', 'Jazz', "Jeux d'alcool", 'Jeux de carte', - 'Jeux de rôle', 'Jeux de société', 'JUL', 'Jus de fruit', 'Kfet', 'Kleptomanie assurée', - 'LGBTQ+', 'Livre', 'Morning beer', 'Musique', 'NAPS', 'Paillettes', 'Pastis', 'Paté Hénaff', - 'Peluche', 'Pena baiona', "Peu d'alcool", 'Pilier de bar', 'PMU', 'Poulpe', 'Punch', 'Rap', - 'Réveil', 'Rock', 'Rugby', 'Sandwich', 'Serge', 'Shot', 'Sociable', 'Spectacle', 'Techno', - 'Techno house', 'Thérapie Taxi', 'Tradition kchanaises', 'Troisième mi-temps', 'Turn up', - 'Vodka', 'Vodka pomme', 'Volley', 'Vomi stratégique' + 'ABBA', 'After', 'Alcoolique anonyme', 'Ambiance festive', 'Années 2000', 'Apéro', 'Art', + 'Baby foot billard biere pong', 'BBQ', 'Before', 'Bière pong', 'Bon enfant', 'Calme', 'Canapé', + 'Chanson paillarde', 'Chanson populaire', 'Chartreuse', 'Cheerleader', 'Chill', 'Choré', + 'Cinéma', 'Cocktail', 'Comédie musicle', 'Commercial', 'Copaing', 'Danse', 'Dancefloor', + 'Electro', 'Fanfare', 'Gin tonic', 'Inclusif', 'Jazz', "Jeux d'alcool", 'Jeux de carte', + 'Jeux de rôle', 'Jeux de société', 'JUL', 'Jus de fruit', 'Kfet', 'Kleptomanie assurée', + 'LGBTQ+', 'Livre', 'Morning beer', 'Musique', 'NAPS', 'Paillettes', 'Pastis', 'Paté Hénaff', + 'Peluche', 'Pena baiona', "Peu d'alcool", 'Pilier de bar', 'PMU', 'Poulpe', 'Punch', 'Rap', + 'Réveil', 'Rock', 'Rugby', 'Sandwich', 'Serge', 'Shot', 'Sociable', 'Spectacle', 'Techno', + 'Techno house', 'Thérapie Taxi', 'Tradition kchanaises', 'Troisième mi-temps', 'Turn up', + 'Vodka', 'Vodka pomme', 'Volley', 'Vomi stratégique' ] diff --git a/apps/wei/forms/surveys/wei2023.py b/apps/wei/forms/surveys/wei2023.py new file mode 100644 index 00000000..70bd814e --- /dev/null +++ b/apps/wei/forms/surveys/wei2023.py @@ -0,0 +1,391 @@ +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from functools import lru_cache + +from django import forms +from django.db import transaction +from django.db.models import Q + +from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation +from ...models import WEIMembership + +WORDS = { + "ambiance": ["Ambiance de bus :", { + 1: "Ambiance calme et posée", + 2: "Ambiance rigolage entre copaing", + 3: "Ambiance danse de camping autour d'une piscine inexistante", + 4: "Grosse soirée avec de la musique qui fait bouger", + 5: "On retourne le camping et le bus (dans le respect et le savoir vivre)" + }], + "musique": ["Musique :", { + 1: "Musique tranquille", + 2: "Musique commerciale", + 3: "Chansons paillardes", + 4: "Musique de Colonie de vacances", + 5: "Grosse techno" + }], + "boisson": ["Boissons :", { + 1: "Boisson soft", + 2: "Des cocktails de temps en temps", + 3: "Des coktails fancy de pétasse (parce que c'est les meilleurs)", + 4: "Bière !", + 5: "L'alcool c'est dans les céréales" + }], + "beauferie": ["Échelle de la beauferie :", { + 1: "Je suis toujours classe", + 2: "Je rote de temps en temps", + 3: "Claquette chaussette, c'est confortable", + 4: "L'aviron bayonnais est dans ma plyaylist", + 5: "Je suis champion⋅ne de concours de rots et d'éclatage de gobelet sur mon front" + }], + "sommeil": ["Échelle de ton sommeil pendant le WEI :", { + 1: "Dormir, c'est pour les faibles", + 2: "5h maximum", + 3: "10h", + 4: "15h", + 5: "Deux bonnes nuits de sommeil, c'est important pour être en forme pour les activités proposées par nos supers GC WEI" + }], + "vacances": ["Tes vacances de rêve :", { + 1: "Dans ma chambre", + 2: "Retourner chez popa et moman pour pouvoir enfin arrêter de manger des pasta box", + 3: "Être une grosse larve sous le soleil des troopiiiiiiiiques", + 4: "Faire un road trip camping sauvage, manger des racines et boire son pipi", + 5: "Le crime ne prend pas de vacances" + }], + "activite": ["T'as une heure de trou pendant ton WEI, que fais-tu ?", { + 1: "Je cherche des copaines pour faire un petit jeu de société", + 2: "Je cherche un moyen de me dépenser, n'importe quel ballon ferait l'affaire", + 3: "Je cherche un endroit où il y a de la musique pour bouger sur le dancefloor", + 4: "Petit apéro, petite pétanque avec les collègues autour d'un bon pastaga", + 5: "Je cherche une connerie à faire (mais pas trop méchante, pour ne pas embêter mes GC WEI préférés)" + }], + "hygiene": ["Échelle de ton hygiène :", { + 1: "La douche, c'eest tous les jours", + 2: "La règle des 2 jours, c'est un droit et un devoir", + 3: "Je ne me lave qu'après le sport", + 4: "« Ne vous inquiétez pas, je pue pas »", + 5: "Y a que les sales qui se lavent" + }], + "animal": ["Tu décrirais ton animal totem plutôt comme :", { + 1: "Un dragon qui raserait des villes entières d'un seul souffle", + 2: "Une mouette qui pique des frites aux dunkerquois", + 3: "Un poulpe tout meunion", + 4: "Un pitbull qui au fond cache un petit cœur en sucre", + 5: "Un canard en plastique au bord d'une baignoire qui n'a pas servi depuis 10 ans" + }], + "fensfoire": ["Quel est ton rapport à la F[ENS]foire ?", { + 1: "Je réveille les autres à 6h avec mon instrument", + 2: "Je la suis partout", + 3: "J'aime bien l'écouter de temps en temps", + 4: "Je mets des bouchons d'oreilles pour ne pas l'entendre", + 5: "La quoi ?" + }], + "kokarde": ["Qu'est-ce que le mot Kokarde t'évoque ?", { + 1: "Vraiment pas mon truc les soirées…", + 2: "Bof, je viens pour manger et je repars aussitôt", + 3: "Je kiffe, good vibes", + 4: "Perso, je ne m'arrêterai pas de danser sur la piste !", + 5: "J'resterai jusqu'à 3h ou rien" + }], + "copain": ["Qu'est-ce que tu fais avec un⋅e «copain⋅ine» ?", { + 1: "Je l'insulte de sale merde", + 2: "J'lui fais faire des trucs cons et je l'affiche !", + 3: "On parlerait ensemble et on se marrerait", + 4: "On aurait des vrais gros délires", + 5: "Je meurs pour lui/elle" + }], + "vie": ["Selon toi, qu'est-ce que la vie ?", { + 1: "La vie, cette sale race !", + 2: "Un moment paisible avant la mort", + 3: "C'est difficile à définir...", + 4: "En vrai, c'est cool !", + 5: "Une gigantestque tranche de kiff ! Et tous les jours, j'en mange un morceau" + }], + "jeux": ["Quel est ton rapport avec les jeux de société ?", { + 1: "éloigné", + 2: "nonchalant", + 3: "timide", + 4: "assumé", + 5: "sexuel" + }], + "calin": ["Qu'est-ce que tu penses des câlins ?", { + 1: "Jamais je n'en fais et jamais je n'en ferai !", + 2: "J'en fais mais ça ne me plaît pas", + 3: "J'en fais rarement mais c'est toujours cool", + 4: "J'en fais tous les jours avec mes ami⋅es !", + 5: "Je pourrais en faire à n'importe qui. Pourquoi ne pas créer le club Câl[ENS] ?" + }], + "vomi": ["Quel est ton rapport au vomi ?", { + 1: "C'est compliqué…", + 2: "Jamais je ne vomis mais je nettoie quand mes potes vomissent", + 3: "Jamais je ne vomis et jamais je ne nettoie celui de quelqu'un d'autre", + 4: "Je vomis quelquefois, ça arrive, faites pas cette tête, mais je fins toujours par nettoyer !", + 5: "Je vomis à chaque soirée et ce n'est jamais moi qui nettoie" + }], + "kfet": ["Qu'est ce que la Kfet t'évoque ?", { + 1: "La Kfet, quel lieu de dépravé⋅es sérieux…", + 2: "C'est un endroit à l'hygiène plus que douteuse…", + 3: "Téma les prix des boissons et des snacks, c'est aberrant !", + 4: "En vrai, c'est cool, petit billard, petit canapé, chill !", + 5: "Banger, j'y reste jusqu'à la fin de mes jours" + }], + "fatigue": ["Comment combattre la fatigue lors de ton WEI ?", { + 1: "Le sport en journée, ça réveille", + 2: "Le sucre du coca, ça réveille", + 3: "La taurine du Red Bull, ça réveille", + 4: "L'alcool dans le sang, ça réveille", + 5: "L'écocup sur le front, ça réveille" + }], + "duree trajet": ["Quelle serait ta durée de trajet préférée ?", { + 1: "Trajet instantané, pas le temps de niaiser", + 2: "1h, histoire de faire connaissance avec quelques personnes avant de se jeter sur les boissons", + 3: "3h, on peut vraiment parler et apprendre à connaître nos voisin⋅es", + 4: "6h, histoire d'avoir le temps de faire des conneries dans le bus pour bien se marrer !", + 5: "12h, il faut bien trouver un moment pour dormir, ce seront deux gros dodos dans un bus" + }], + "scolarite": ["Comment tu vois ton cursus à l'ENS ?", { + 1: "La tranquillité et le travail", + 2: "On va s'amuser tout en bossant", + 3: "Ça va profiter et réviser au dernier moment pour les exams…", + 4: "Nous festoierons sans songer aux conséquences", + 5: "Je ne vois qu'une seule issue : la débauche" + }] +} + + +class WEISurveyForm2023(forms.Form): + """ + Survey form for the year 2023. + Members answer 20 questions, from which we calculate the best associated bus. + """ + def set_registration(self, registration): + """ + Filter the bus selector with the buses of the current WEI. + """ + information = WEISurveyInformation2023(registration) + + question = information.questions[information.step] + self.fields[question] = forms.ChoiceField( + label=WORDS[question][0], + widget=forms.RadioSelect(), + ) + answers = [(answer, WORDS[question][1][answer]) for answer in WORDS[question][1]] + self.fields[question].choices = answers + + +class WEIBusInformation2023(WEIBusInformation): + """ + For each question, the bus has ordered answers + """ + scores: dict + + def __init__(self, bus): + self.scores = {} + for question in WORDS: + self.scores[question] = [] + super().__init__(bus) + + +class WEISurveyInformation2023(WEISurveyInformation): + """ + We store the id of the selected bus. We store only the name, but is not used in the selection: + that's only for humans that try to read data. + """ + + step = 0 + questions = list(WORDS.keys()) + + def __init__(self, registration): + for question in WORDS: + setattr(self, str(question), None) + super().__init__(registration) + + +class WEISurvey2023(WEISurvey): + """ + Survey for the year 2023. + """ + + @classmethod + def get_year(cls): + return 2023 + + @classmethod + def get_survey_information_class(cls): + return WEISurveyInformation2023 + + def get_form_class(self): + return WEISurveyForm2023 + + def update_form(self, form): + """ + Filter the bus selector with the buses of the WEI. + """ + form.set_registration(self.registration) + + @transaction.atomic + def form_valid(self, form): + self.information.step += 1 + for question in WORDS: + if question in form.cleaned_data: + answer = form.cleaned_data[question] + setattr(self.information, question, answer) + self.save() + + @classmethod + def get_algorithm_class(cls): + return WEISurveyAlgorithm2023 + + def is_complete(self) -> bool: + """ + The survey is complete once the bus is chosen. + """ + for question in WORDS: + if not getattr(self.information, question): + return False + return True + + @lru_cache() + def score(self, bus): + if not self.is_complete(): + raise ValueError("Survey is not ended, can't calculate score") + + bus_info = self.get_algorithm_class().get_bus_information(bus) + # Score is the given score by the bus subtracted to the mid-score of the buses. + s = 0 + for question in WORDS: + s += bus_info.scores[question][str(getattr(self.information, question))] + return s + + @lru_cache() + def scores_per_bus(self): + return {bus: self.score(bus) for bus in self.get_algorithm_class().get_buses()} + + @lru_cache() + def ordered_buses(self): + values = list(self.scores_per_bus().items()) + values.sort(key=lambda item: -item[1]) + return values + + @classmethod + def clear_cache(cls): + return super().clear_cache() + + +class WEISurveyAlgorithm2023(WEISurveyAlgorithm): + """ + The algorithm class for the year 2023. + We use Gale-Shapley algorithm to attribute 1y students into buses. + """ + + @classmethod + def get_survey_class(cls): + return WEISurvey2023 + + @classmethod + def get_bus_information_class(cls): + return WEIBusInformation2023 + + def run_algorithm(self, display_tqdm=False): + """ + Gale-Shapley algorithm implementation. + We modify it to allow buses to have multiple "weddings". + """ + surveys = list(self.get_survey_class()(r) for r in self.get_registrations()) # All surveys + surveys = [s for s in surveys if s.is_complete()] # Don't consider invalid surveys + # Don't manage hardcoded people + surveys = [s for s in surveys if not hasattr(s.information, 'hardcoded') or not s.information.hardcoded] + + # Reset previous algorithm run + for survey in surveys: + survey.free() + survey.save() + + non_men = [s for s in surveys if s.registration.gender != 'male'] + men = [s for s in surveys if s.registration.gender == 'male'] + + quotas = {} + registrations = self.get_registrations() + non_men_total = registrations.filter(~Q(gender='male')).count() + for bus in self.get_buses(): + free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count() + # Remove hardcoded people + free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True, + registration__information_json__icontains="hardcoded").count() + quotas[bus] = 4 + int(non_men_total / registrations.count() * free_seats) + + tqdm_obj = None + if display_tqdm: + from tqdm import tqdm + tqdm_obj = tqdm(total=len(non_men), desc="Non-hommes") + + # Repartition for non men people first + self.make_repartition(non_men, quotas, tqdm_obj=tqdm_obj) + + quotas = {} + for bus in self.get_buses(): + free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count() + free_seats -= sum(1 for s in non_men if s.information.selected_bus_pk == bus.pk) + # Remove hardcoded people + free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True, + registration__information_json__icontains="hardcoded").count() + quotas[bus] = free_seats + + if display_tqdm: + tqdm_obj.close() + + from tqdm import tqdm + tqdm_obj = tqdm(total=len(men), desc="Hommes") + + self.make_repartition(men, quotas, tqdm_obj=tqdm_obj) + + if display_tqdm: + tqdm_obj.close() + + # Clear cache information after running algorithm + WEISurvey2023.clear_cache() + + def make_repartition(self, surveys, quotas=None, tqdm_obj=None): + free_surveys = surveys.copy() # Remaining surveys + while free_surveys: # Some students are not affected + survey = free_surveys[0] + buses = survey.ordered_buses() # Preferences of the student + for bus, current_score in buses: + if self.get_bus_information(bus).has_free_seats(surveys, quotas): + # Selected bus has free places. Put student in the bus + survey.select_bus(bus) + survey.save() + free_surveys.remove(survey) + break + else: + # Current bus has not enough places. Remove the least preferred student from the bus if existing + least_preferred_survey = None + least_score = -1 + # Find the least student in the bus that has a lower score than the current student + for survey2 in surveys: + if not survey2.information.valid or survey2.information.get_selected_bus() != bus: + continue + score2 = survey2.score(bus) + if current_score <= score2: # Ignore better students + continue + if least_preferred_survey is None or score2 < least_score: + least_preferred_survey = survey2 + least_score = score2 + + if least_preferred_survey is not None: + # Remove the least student from the bus and put the current student in. + # If it does not exist, choose the next bus. + least_preferred_survey.free() + least_preferred_survey.save() + free_surveys.append(least_preferred_survey) + survey.select_bus(bus) + survey.save() + free_surveys.remove(survey) + break + else: + raise ValueError(f"User {survey.registration.user} has no free seat") + + if tqdm_obj is not None: + tqdm_obj.n = len(surveys) - len(free_surveys) + tqdm_obj.refresh() diff --git a/apps/wei/migrations/0004_auto_20220904_2325.py b/apps/wei/migrations/0004_auto_20220904_2325.py new file mode 100644 index 00000000..fb41c2bd --- /dev/null +++ b/apps/wei/migrations/0004_auto_20220904_2325.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.26 on 2022-09-04 21:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wei', '0003_bus_size'), + ] + + operations = [ + migrations.AlterField( + model_name='weiclub', + name='year', + field=models.PositiveIntegerField(default=2022, unique=True, verbose_name='year'), + ), + ] diff --git a/apps/wei/migrations/0005_auto_20230128_1850.py b/apps/wei/migrations/0005_auto_20230128_1850.py new file mode 100644 index 00000000..a8c432aa --- /dev/null +++ b/apps/wei/migrations/0005_auto_20230128_1850.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-01-28 17:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wei', '0004_auto_20220904_2325'), + ] + + operations = [ + migrations.AlterField( + model_name='weiclub', + name='year', + field=models.PositiveIntegerField(default=2023, unique=True, verbose_name='year'), + ), + ] diff --git a/apps/wei/migrations/0006_unisex_clothing_cut.py b/apps/wei/migrations/0006_unisex_clothing_cut.py new file mode 100644 index 00000000..c2ed7c97 --- /dev/null +++ b/apps/wei/migrations/0006_unisex_clothing_cut.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-07-09 09:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wei', '0005_auto_20230128_1850'), + ] + + operations = [ + migrations.AlterField( + model_name='weiregistration', + name='clothing_cut', + field=models.CharField(choices=[('male', 'Male'), ('female', 'Female'), ('unisex', 'Unisex')], default='unisex', max_length=16, verbose_name='clothing cut'), + ), + ] diff --git a/apps/wei/migrations/0007_help_text_emergency_contact.py b/apps/wei/migrations/0007_help_text_emergency_contact.py new file mode 100644 index 00000000..4437db7d --- /dev/null +++ b/apps/wei/migrations/0007_help_text_emergency_contact.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2023-07-09 12:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wei', '0006_unisex_clothing_cut'), + ] + + operations = [ + migrations.AlterField( + model_name='weiregistration', + name='emergency_contact_name', + field=models.CharField(help_text='The emergency contact must not be a WEI participant', max_length=255, verbose_name='emergency contact name'), + ), + ] diff --git a/apps/wei/models.py b/apps/wei/models.py index 6b7272b4..6b05609f 100644 --- a/apps/wei/models.py +++ b/apps/wei/models.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import json @@ -209,7 +209,9 @@ class WEIRegistration(models.Model): choices=( ('male', _("Male")), ('female', _("Female")), + ('unisex', _("Unisex")), ), + default='unisex', verbose_name=_("clothing cut"), ) @@ -235,6 +237,7 @@ class WEIRegistration(models.Model): emergency_contact_name = models.CharField( max_length=255, verbose_name=_("emergency contact name"), + help_text=_("The emergency contact must not be a WEI participant") ) emergency_contact_phone = PhoneNumberField( diff --git a/apps/wei/templates/wei/weimembership_form.html b/apps/wei/templates/wei/weimembership_form.html index 7d1059b7..017b0dd7 100644 --- a/apps/wei/templates/wei/weimembership_form.html +++ b/apps/wei/templates/wei/weimembership_form.html @@ -56,7 +56,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{{ registration.get_gender_display }}
{% trans 'clothing cut'|capfirst %}
-
{{ registration.clothing_cut }}
+
{{ registration.get_clothing_cut_display }}
{% trans 'clothing size'|capfirst %}
{{ registration.clothing_size }}
diff --git a/apps/wei/tests/test_wei_algorithm_2023.py b/apps/wei/tests/test_wei_algorithm_2023.py new file mode 100644 index 00000000..ae982d3c --- /dev/null +++ b/apps/wei/tests/test_wei_algorithm_2023.py @@ -0,0 +1,170 @@ +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +import random +from datetime import date, timedelta + +from django.contrib.auth.models import User +from django.test import TestCase +from django.urls import reverse +from note.models import NoteUser + +from ..forms.surveys.wei2023 import WEIBusInformation2023, WEISurvey2023, WORDS, WEISurveyInformation2023 +from ..models import Bus, WEIClub, WEIRegistration + + +class TestWEIAlgorithm(TestCase): + """ + Run some tests to ensure that the WEI algorithm is working well. + """ + fixtures = ('initial',) + + def setUp(self): + """ + Create some test data, with one WEI and 10 buses with random score attributions. + """ + self.user = User.objects.create_superuser( + username="weiadmin", + password="admin", + email="admin@example.com", + ) + self.user.save() + self.client.force_login(self.user) + sess = self.client.session + sess["permission_mask"] = 42 + sess.save() + + self.wei = WEIClub.objects.create( + name="WEI 2023", + email="wei2023@example.com", + parent_club_id=2, + membership_fee_paid=12500, + membership_fee_unpaid=5500, + membership_start='2023-01-01', + membership_end='2023-12-31', + date_start=date.today() + timedelta(days=2), + date_end='2023-12-31', + year=2023, + ) + + self.buses = [] + for i in range(10): + bus = Bus.objects.create(wei=self.wei, name=f"Bus {i}", size=10) + self.buses.append(bus) + information = WEIBusInformation2023(bus) + for question in WORDS: + information.scores[question] = {answer: random.randint(1, 5) for answer in WORDS[question][1]} + information.save() + bus.save() + + def test_survey_algorithm_small(self): + """ + There are only a few people in each bus, ensure that each person has its best bus + """ + # Add a few users + for i in range(10): + user = User.objects.create(username=f"user{i}") + registration = WEIRegistration.objects.create( + user=user, + wei=self.wei, + first_year=True, + birth_date='2000-01-01', + ) + information = WEISurveyInformation2023(registration) + for question in WORDS: + setattr(information, question, random.randint(1, 5)) + information.step = 20 + information.save(registration) + registration.save() + + # Run algorithm + WEISurvey2023.get_algorithm_class()().run_algorithm() + + # Ensure that everyone has its first choice + for r in WEIRegistration.objects.filter(wei=self.wei).all(): + survey = WEISurvey2023(r) + preferred_bus = survey.ordered_buses()[0][0] + chosen_bus = survey.information.get_selected_bus() + self.assertEqual(preferred_bus, chosen_bus) + + def test_survey_algorithm_full(self): + """ + Buses are full of first year people, ensure that they are happy + """ + # Add a lot of users + for i in range(95): + user = User.objects.create(username=f"user{i}") + registration = WEIRegistration.objects.create( + user=user, + wei=self.wei, + first_year=True, + birth_date='2000-01-01', + ) + information = WEISurveyInformation2023(registration) + for question in WORDS: + setattr(information, question, random.randint(1, 5)) + information.step = 20 + information.save(registration) + registration.save() + + # Run algorithm + WEISurvey2023.get_algorithm_class()().run_algorithm() + + penalty = 0 + # Ensure that everyone seems to be happy + # We attribute a penalty for each user that didn't have its first choice + # The penalty is the square of the distance between the score of the preferred bus + # and the score of the attributed bus + # We consider it acceptable if the mean of this distance is lower than 5 % + for r in WEIRegistration.objects.filter(wei=self.wei).all(): + survey = WEISurvey2023(r) + chosen_bus = survey.information.get_selected_bus() + buses = survey.ordered_buses() + score = min(v for bus, v in buses if bus == chosen_bus) + max_score = buses[0][1] + penalty += (max_score - score) ** 2 + + self.assertLessEqual(max_score - score, 25) # Always less than 25 % of tolerance + + self.assertLessEqual(penalty / 100, 25) # Tolerance of 5 % + + def test_register_1a(self): + """ + Test register a first year member to the WEI and complete the survey + """ + response = self.client.get(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk))) + self.assertEqual(response.status_code, 200) + + user = User.objects.create(username="toto", email="toto@example.com") + NoteUser.objects.create(user=user) + response = self.client.post(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)), dict( + user=user.id, + soge_credit=True, + birth_date=date(2000, 1, 1), + gender='nonbinary', + clothing_cut='female', + clothing_size='XS', + health_issues='I am a bot', + emergency_contact_name='NoteKfet2020', + emergency_contact_phone='+33123456789', + )) + qs = WEIRegistration.objects.filter(user_id=user.id) + self.assertTrue(qs.exists()) + registration = qs.get() + self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302, 200) + for question in WORDS: + # Fill 1A Survey, 20 pages + # be careful if questionnary form change (number of page, type of answer...) + response = self.client.post(reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), { + question: "1" + }) + registration.refresh_from_db() + survey = WEISurvey2023(registration) + self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302, + 302 if survey.is_complete() else 200) + self.assertIsNotNone(getattr(survey.information, question), "Survey page " + question + " failed") + survey = WEISurvey2023(registration) + self.assertTrue(survey.is_complete()) + survey.select_bus(self.buses[0]) + survey.save() + self.assertIsNotNone(survey.information.get_selected_bus()) diff --git a/apps/wei/tests/test_wei_registration.py b/apps/wei/tests/test_wei_registration.py index ef285f4f..86dd4cfd 100644 --- a/apps/wei/tests/test_wei_registration.py +++ b/apps/wei/tests/test_wei_registration.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay +# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import subprocess @@ -380,7 +380,7 @@ class TestWEIRegistration(TestCase): def test_register_1a(self): """ - Test register a first year member to the WEI and complete the survey. + Test register a first year member to the WEI. """ response = self.client.get(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk))) self.assertEqual(response.status_code, 200) @@ -402,21 +402,6 @@ class TestWEIRegistration(TestCase): self.assertTrue(qs.exists()) registration = qs.get() self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302, 200) - for i in range(1, 21): - # Fill 1A Survey, 20 pages - response = self.client.post(reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), dict( - word="Jus de fruit", - )) - registration.refresh_from_db() - survey = CurrentSurvey(registration) - self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302, - 302 if survey.is_complete() else 200) - self.assertIsNotNone(getattr(survey.information, "word" + str(i)), "Survey page #" + str(i) + " failed") - survey = CurrentSurvey(registration) - self.assertTrue(survey.is_complete()) - survey.select_bus(self.bus) - survey.save() - self.assertIsNotNone(survey.information.get_selected_bus()) # Check that the user can't be registered twice response = self.client.post(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)), dict( @@ -662,7 +647,7 @@ class TestWEIRegistration(TestCase): first_name="admin", bank="Société générale", )) - self.assertRedirects(response, reverse("wei:wei_detail", kwargs=dict(pk=self.registration.wei.pk)), 302, 200) + self.assertRedirects(response, reverse("wei:wei_registrations", kwargs=dict(pk=self.registration.wei.pk)), 302, 200) # Check if the membership is successfully created membership = WEIMembership.objects.filter(user_id=self.user.id, club=self.wei) self.assertTrue(membership.exists()) @@ -782,7 +767,7 @@ class TestDefaultWEISurvey(TestCase): WEISurvey.update_form(None, None) self.assertEqual(CurrentSurvey.get_algorithm_class().get_survey_class(), CurrentSurvey) - self.assertEqual(CurrentSurvey.get_year(), 2022) + self.assertEqual(CurrentSurvey.get_year(), 2023) class TestWeiAPI(TestAPI): diff --git a/apps/wei/views.py b/apps/wei/views.py index 80ff770e..4f2b7b65 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -969,7 +969,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): if not registration.soge_credit and user.note.balance + credit_amount < fee: # Users must have money before registering to the WEI. - form.add_error('bus', + form.add_error('credit_type', _("This user don't have enough money to join this club, and can't have a negative balance.")) return super().form_invalid(form) @@ -1014,7 +1014,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): def get_success_url(self): self.object.refresh_from_db() - return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.club.pk}) + return reverse_lazy("wei:wei_registrations", kwargs={"pk": self.object.club.pk}) class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView): @@ -1084,7 +1084,44 @@ class WEISurveyEndView(LoginRequiredMixin, TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["club"] = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei + club = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei + context["club"] = club + + random_user = User.objects.filter(~Q(wei__wei__in=[club])).first() + + if random_user is None: + # This case occurs when all users are registered to the WEI. + # Don't worry, Pikachu never went to the WEI. + # This bug can arrive only in dev mode. + context["can_add_first_year_member"] = True + context["can_add_any_member"] = True + else: + # Check if the user has the right to create a registration of a random first year member. + empty_fy_registration = WEIRegistration( + wei=club, + user=random_user, + first_year=True, + birth_date="1970-01-01", + gender="No", + emergency_contact_name="No", + emergency_contact_phone="No", + ) + context["can_add_first_year_member"] = PermissionBackend \ + .check_perm(self.request, "wei.add_weiregistration", empty_fy_registration) + + # Check if the user has the right to create a registration of a random old member. + empty_old_registration = WEIRegistration( + wei=club, + user=User.objects.filter(~Q(wei__wei__in=[club])).first(), + first_year=False, + birth_date="1970-01-01", + gender="No", + emergency_contact_name="No", + emergency_contact_phone="No", + ) + context["can_add_any_member"] = PermissionBackend \ + .check_perm(self.request, "wei.add_weiregistration", empty_old_registration) + return context diff --git a/docs/api/wei.rst b/docs/api/wei.rst index 8c92c026..125ac9b4 100644 --- a/docs/api/wei.rst +++ b/docs/api/wei.rst @@ -448,6 +448,10 @@ Options "value": "female", "display_name": "Femme" } + { + "value": "unisex", + "display_name": "Unisexe" + }, ] }, "clothing_size": { diff --git a/docs/apps/permission.rst b/docs/apps/permission.rst index 0ba46430..ac859151 100644 --- a/docs/apps/permission.rst +++ b/docs/apps/permission.rst @@ -118,13 +118,13 @@ Exemples {"F": [ "ADD", ["F", "source__balance"], - 5000] + 2000] } } ] - | si la destination est la note du club dont on est membre et si le montant est inférieur au solde de la source + 50 €, - autrement dit le solde final est au-dessus de -50 €. + | si la destination est la note du club dont on est membre et si le montant est inférieur au solde de la source + 20 €, + autrement dit le solde final est au-dessus de -20 €. Masques de permissions diff --git a/docs/faq.rst b/docs/faq.rst index d7971971..18b8a4be 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -83,13 +83,6 @@ Je suis trésorier d'un club, qu'ai-je le droit de faire ? bien sûr permis pour faciliter des transferts. Tout abus de droits constaté pourra mener à des sanctions prises par le bureau du BDE. -.. warning:: - Une fonctionnalité pour permettre de gérer plus proprement les remboursements - entre amis est en cours de développement. Temporairement et pour des raisons - de confort, les trésoriers de clubs ont le droit de prélever n'importe quelle - adhérente vers n'importe quelle autre note adhérente, tant que la source ne - descend pas sous ``- 50 €``. Ces droits seront retirés d'ici quelques semaines. - Je suis trésorier d'un club, je n'arrive pas à voir le solde du club / faire des transactions --------------------------------------------------------------------------------------------------- diff --git a/docs/install.rst b/docs/install.rst index 15ce27df..b625bfae 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -615,7 +615,7 @@ pas déjà fait par créer un utilisateur sur les deux serveurs : .. code:: bash - ynerant@bde-note:~$ sudo -u postgres createuser -l ynerant + ynerant@bde-note:~$ sudo -u postgres createuser -s ynerant On réinitialise **sur le serveur de développement** la base de données présente, en éteignant tout d'abord le serveur Web : diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 215a09a7..4fa2bdac 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: 2022-04-10 22:34+0200\n" +"POT-Creation-Date: 2023-10-25 19:12+0200\n" "PO-Revision-Date: 2020-11-16 20:02+0000\n" -"Last-Translator: Yohann D'ANELLO \n" +"Last-Translator: bleizi \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" @@ -53,7 +53,7 @@ msgid "You can't invite more than 3 people to this activity." msgstr "Sie dürfen höchstens 3 Leute zu dieser Veranstaltung einladen." #: apps/activity/models.py:28 apps/activity/models.py:63 -#: apps/member/models.py:199 +#: apps/member/models.py:204 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -114,8 +114,8 @@ msgstr "Wo findet die Veranstaltung statt ? (z.B Kfet)." msgid "type" msgstr "Type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307 -#: apps/note/models/notes.py:148 apps/treasury/models.py:285 +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:312 +#: apps/note/models/notes.py:148 apps/treasury/models.py:287 #: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" @@ -258,19 +258,19 @@ msgstr "Eingetreten um " msgid "remove" msgstr "entfernen" -#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199 +#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:201 msgid "Type" msgstr "Type" -#: apps/activity/tables.py:84 apps/member/forms.py:186 -#: apps/registration/forms.py:91 apps/treasury/forms.py:131 +#: apps/activity/tables.py:84 apps/member/forms.py:193 +#: apps/registration/forms.py:92 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Nachname" -#: apps/activity/tables.py:86 apps/member/forms.py:191 +#: apps/activity/tables.py:86 apps/member/forms.py:198 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:96 apps/treasury/forms.py:133 +#: apps/registration/forms.py:97 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Vorname" @@ -391,7 +391,7 @@ msgid "validate" msgstr "" #: apps/activity/templates/activity/includes/activity_info.html:71 -#: apps/logs/models.py:64 apps/note/tables.py:220 +#: apps/logs/models.py:64 apps/note/tables.py:260 msgid "edit" msgstr "bearbeiten" @@ -467,9 +467,9 @@ msgstr "neue Daten" msgid "create" msgstr "schaffen" -#: apps/logs/models.py:65 apps/note/tables.py:166 apps/note/tables.py:190 -#: apps/note/tables.py:237 apps/permission/models.py:127 -#: apps/treasury/tables.py:38 apps/wei/tables.py:74 +#: apps/logs/models.py:65 apps/note/tables.py:230 apps/note/tables.py:277 +#: apps/permission/models.py:127 apps/treasury/tables.py:38 +#: apps/wei/tables.py:74 msgid "delete" msgstr "entfernen" @@ -498,21 +498,21 @@ msgstr "Changelogs" msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" msgstr "Changelog \"{action}\" für Model {model} an {timestamp}" -#: apps/member/admin.py:50 apps/member/models.py:226 +#: apps/member/admin.py:50 apps/member/models.py:231 #: apps/member/templates/member/includes/club_info.html:34 msgid "membership fee (paid students)" msgstr "Mitgliedschaftpreis (bezahlte Studenten)" -#: apps/member/admin.py:51 apps/member/models.py:231 +#: apps/member/admin.py:51 apps/member/models.py:236 #: apps/member/templates/member/includes/club_info.html:37 msgid "membership fee (unpaid students)" msgstr "Mitgliedschaftpreis (unbezahlte Studenten)" -#: apps/member/admin.py:65 apps/member/models.py:319 +#: apps/member/admin.py:65 apps/member/models.py:324 msgid "roles" msgstr "Rollen" -#: apps/member/admin.py:66 apps/member/models.py:333 +#: apps/member/admin.py:66 apps/member/models.py:338 msgid "fee" msgstr "Preis" @@ -532,65 +532,82 @@ msgstr "Bericht Frequenz" msgid "Last report date" msgstr "Letzen Bericht Datum" +#: apps/member/forms.py:52 +msgid "" +"Anti-VSS (Violences Sexistes et Sexuelles) charter read and approved" +msgstr "" +"Anti-VSS (Violences Sexistes et Sexuelles) Charta gelesen und " +"angenommen" + #: apps/member/forms.py:53 +msgid "" +"Tick after having read and accepted the anti-VSS charter " +"available here in pdf" +msgstr "" +"Kreuzen Sie an, nachdem Sie die Anti-VSS-Charta gelesen und akzeptiert " +"haben, die hier als pdf-Datei verfügbar ist" + +#: apps/member/forms.py:60 msgid "You can't register to the note if you come from the future." msgstr "Sie dürfen nicht einloggen wenn sie aus der Zukunft kommen." -#: apps/member/forms.py:79 +#: apps/member/forms.py:86 msgid "select an image" msgstr "Wählen sie ein Bild aus" -#: apps/member/forms.py:80 +#: apps/member/forms.py:87 msgid "Maximal size: 2MB" msgstr "Maximal Größe: 2MB" -#: apps/member/forms.py:105 +#: apps/member/forms.py:112 msgid "This image cannot be loaded." msgstr "Dieses Bild kann nicht geladen werden." -#: apps/member/forms.py:141 apps/member/views.py:103 -#: apps/registration/forms.py:33 apps/registration/views.py:262 +#: apps/member/forms.py:148 apps/member/views.py:102 +#: apps/registration/forms.py:34 apps/registration/views.py:266 msgid "An alias with a similar name already exists." msgstr "Ein ähnliches Alias ist schon benutzt." -#: apps/member/forms.py:165 apps/registration/forms.py:71 +#: apps/member/forms.py:172 msgid "Inscription paid by Société Générale" msgstr "Mitgliedschaft von der Société Générale bezahlt" -#: apps/member/forms.py:167 apps/registration/forms.py:73 +#: apps/member/forms.py:174 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:172 apps/registration/forms.py:78 +#: apps/member/forms.py:179 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Kredittype" -#: apps/member/forms.py:173 apps/registration/forms.py:79 +#: apps/member/forms.py:180 apps/registration/forms.py:80 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "Kein Kredit" -#: apps/member/forms.py:175 +#: apps/member/forms.py:182 msgid "You can credit the note of the user." msgstr "Sie dûrfen diese Note kreditieren." -#: apps/member/forms.py:179 apps/registration/forms.py:84 +#: apps/member/forms.py:186 apps/registration/forms.py:85 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Kreditanzahl" -#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:101 apps/treasury/forms.py:135 +#: apps/member/forms.py:203 apps/note/templates/note/transaction_form.html:144 +#: apps/registration/forms.py:102 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Bank" -#: apps/member/forms.py:223 +#: apps/member/forms.py:230 msgid "User" msgstr "User" -#: apps/member/forms.py:237 +#: apps/member/forms.py:244 msgid "Roles" msgstr "Rollen" @@ -777,15 +794,19 @@ msgstr "email bestätigt" msgid "registration valid" msgstr "Anmeldung gültig" -#: apps/member/models.py:162 apps/member/models.py:163 +#: apps/member/models.py:138 +msgid "VSS charter read" +msgstr "VSS-Charta gelesen" + +#: apps/member/models.py:167 apps/member/models.py:168 msgid "user profile" msgstr "Userprofile" -#: apps/member/models.py:173 +#: apps/member/models.py:178 msgid "Activate your Note Kfet account" msgstr "Ihre Note Kfet Konto bestätigen" -#: apps/member/models.py:204 +#: apps/member/models.py:209 #: apps/member/templates/member/includes/club_info.html:55 #: apps/member/templates/member/includes/profile_info.html:40 #: apps/registration/templates/registration/future_profile_detail.html:22 @@ -794,88 +815,88 @@ msgstr "Ihre Note Kfet Konto bestätigen" msgid "email" msgstr "Email" -#: apps/member/models.py:211 +#: apps/member/models.py:216 msgid "parent club" msgstr "Urclub" -#: apps/member/models.py:220 +#: apps/member/models.py:225 msgid "require memberships" msgstr "erfordern Mitgliedschaft" -#: apps/member/models.py:221 +#: apps/member/models.py:226 msgid "Uncheck if this club don't require memberships." msgstr "" "Deaktivieren Sie diese Option, wenn für diesen Club keine Mitgliedschaft " "erforderlich ist." -#: apps/member/models.py:237 +#: apps/member/models.py:242 #: apps/member/templates/member/includes/club_info.html:26 msgid "membership duration" msgstr "Mitgliedscahftzeit" -#: apps/member/models.py:238 +#: apps/member/models.py:243 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "Wie lang am höchsten eine Mitgliedschaft dauern kann." -#: apps/member/models.py:245 +#: apps/member/models.py:250 #: apps/member/templates/member/includes/club_info.html:16 msgid "membership start" msgstr "Mitgliedschaftanfangsdatum" -#: apps/member/models.py:246 +#: apps/member/models.py:251 msgid "Date from which the members can renew their membership." msgstr "Ab wann kann man sein Mitgliedschaft erneuern." -#: apps/member/models.py:252 +#: apps/member/models.py:257 #: apps/member/templates/member/includes/club_info.html:21 msgid "membership end" msgstr "Mitgliedschaftenddatum" -#: apps/member/models.py:253 +#: apps/member/models.py:258 msgid "Maximal date of a membership, after which members must renew it." msgstr "" "Maximales Datum einer Mitgliedschaft, nach dem Mitglieder es erneuern müssen." -#: apps/member/models.py:288 apps/member/models.py:313 +#: apps/member/models.py:293 apps/member/models.py:318 #: apps/note/models/notes.py:176 msgid "club" msgstr "Club" -#: apps/member/models.py:289 +#: apps/member/models.py:294 msgid "clubs" msgstr "Clubs" -#: apps/member/models.py:324 +#: apps/member/models.py:329 msgid "membership starts on" msgstr "Mitgliedschaft fängt an" -#: apps/member/models.py:328 +#: apps/member/models.py:333 msgid "membership ends on" msgstr "Mitgliedschaft endet am" -#: apps/member/models.py:430 +#: apps/member/models.py:435 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "Die Rolle {role} ist nicht erlaubt für das Club {club}." -#: apps/member/models.py:439 apps/member/views.py:712 +#: apps/member/models.py:444 apps/member/views.py:712 msgid "User is already a member of the club" msgstr "User ist schon ein Mitglied dieser club" -#: apps/member/models.py:451 apps/member/views.py:721 +#: apps/member/models.py:456 apps/member/views.py:721 msgid "User is not a member of the parent club" msgstr "User ist noch nicht Mitglied des Urclubs" -#: apps/member/models.py:504 +#: apps/member/models.py:509 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Mitgliedschaft von {user} für das Club {club}" -#: apps/member/models.py:507 apps/note/models/transactions.py:389 +#: apps/member/models.py:512 apps/note/models/transactions.py:389 msgid "membership" msgstr "Mitgliedschaft" -#: apps/member/models.py:508 +#: apps/member/models.py:513 msgid "memberships" msgstr "Mitgliedschaften" @@ -930,7 +951,7 @@ msgid "Account #" msgstr "Konto #" #: apps/member/templates/member/base.html:48 -#: apps/member/templates/member/base.html:62 apps/member/views.py:60 +#: apps/member/templates/member/base.html:62 apps/member/views.py:59 #: apps/registration/templates/registration/future_profile_detail.html:48 #: apps/wei/templates/wei/weimembership_form.html:117 msgid "Update Profile" @@ -1172,8 +1193,8 @@ msgstr "Click hier um eine Bestätigunglinke zu schicken." msgid "View my memberships" msgstr "Meine Mitgliedschaften schauen" -#: apps/member/templates/member/profile_trust.html:10 apps/member/views.py:254 -msgid "Note friendships" +#: apps/member/templates/member/profile_trust.html:10 +msgid "Add friends" msgstr "" #: apps/member/templates/member/profile_trust.html:28 @@ -1185,6 +1206,10 @@ msgid "" "without needing additional rights among them." msgstr "" +#: apps/member/templates/member/profile_trust.html:39 +msgid "People having you as a friend" +msgstr "" + #: apps/member/templates/member/profile_update.html:18 msgid "Save Changes" msgstr "Speichern" @@ -1193,18 +1218,22 @@ msgstr "Speichern" msgid "Registrations" msgstr "Anmeldung" -#: apps/member/views.py:73 apps/registration/forms.py:23 +#: apps/member/views.py:72 apps/registration/forms.py:24 msgid "This address must be valid." msgstr "Diese Adresse muss gültig sein." -#: apps/member/views.py:140 +#: apps/member/views.py:139 msgid "Profile detail" msgstr "Profile detail" -#: apps/member/views.py:206 +#: apps/member/views.py:205 msgid "Search user" msgstr "User finden" +#: apps/member/views.py:253 +msgid "Note friendships" +msgstr "" + #: apps/member/views.py:308 msgid "Update note picture" msgstr "Notebild ändern" @@ -1249,29 +1278,35 @@ msgstr "Die Mitgliedschaft muss nach {:%m-%d-Y} anfängen." msgid "The membership must begin before {:%m-%d-%Y}." msgstr "Die Mitgliedschaft muss vor {:%m-%d-Y} anfängen." -#: apps/member/views.py:876 +#: apps/member/views.py:880 msgid "Manage roles of an user in the club" msgstr "Rollen in diesen Club bearbeiten" -#: apps/member/views.py:901 +#: apps/member/views.py:905 msgid "Members of the club" msgstr "Mitlglieder dieses Club" -#: apps/note/admin.py:129 apps/note/models/transactions.py:109 +#: apps/note/admin.py:139 apps/note/models/transactions.py:109 msgid "source" msgstr "Sender" -#: apps/note/admin.py:137 apps/note/admin.py:205 +#: apps/note/admin.py:147 apps/note/admin.py:215 #: apps/note/models/transactions.py:56 apps/note/models/transactions.py:122 msgid "destination" msgstr "Empfänger" -#: apps/note/admin.py:210 apps/note/models/transactions.py:60 +#: apps/note/admin.py:220 apps/note/models/transactions.py:60 #: apps/note/models/transactions.py:140 msgid "amount" msgstr "Anzahl" -#: apps/note/api/serializers.py:199 apps/note/api/serializers.py:205 +#: apps/note/api/serializers.py:92 +#, fuzzy +#| msgid "This credit is already validated." +msgid "This friendship already exists" +msgstr "Dieser Kredit ist bereits validiert." + +#: apps/note/api/serializers.py:198 apps/note/api/serializers.py:204 #: apps/note/models/transactions.py:228 msgid "" "The transaction can't be saved since the source note or the destination note " @@ -1570,7 +1605,7 @@ msgstr "Sondertranskationen" msgid "membership transaction" msgstr "Mitgliedschafttransaktion" -#: apps/note/models/transactions.py:385 apps/treasury/models.py:292 +#: apps/note/models/transactions.py:385 apps/treasury/models.py:294 msgid "membership transactions" msgstr "Mitgliedschaftttransaktionen" @@ -1586,8 +1621,8 @@ msgstr "Klicken Sie zum gültigmachen" msgid "No reason specified" msgstr "Kein Grund gegeben" -#: apps/note/tables.py:173 apps/note/tables.py:194 apps/note/tables.py:239 -#: apps/treasury/tables.py:39 +#: apps/note/tables.py:166 apps/note/tables.py:173 apps/note/tables.py:234 +#: apps/note/tables.py:279 apps/treasury/tables.py:39 #: apps/treasury/templates/treasury/invoice_confirm_delete.html:30 #: apps/treasury/templates/treasury/sogecredit_detail.html:65 #: apps/wei/tables.py:75 apps/wei/tables.py:118 @@ -1598,7 +1633,17 @@ msgstr "Kein Grund gegeben" msgid "Delete" msgstr "Löschen" -#: apps/note/tables.py:222 apps/note/templates/note/conso_form.html:132 +#: apps/note/tables.py:191 +msgid "Trust back" +msgstr "" + +#: apps/note/tables.py:211 +#, fuzzy +#| msgid "Add bus" +msgid "Add back" +msgstr "Neue Bus" + +#: apps/note/tables.py:262 apps/note/templates/note/conso_form.html:151 #: apps/wei/tables.py:49 apps/wei/tables.py:50 #: apps/wei/templates/wei/base.html:89 #: apps/wei/templates/wei/bus_detail.html:20 @@ -1608,7 +1653,7 @@ msgstr "Löschen" msgid "Edit" msgstr "Bearbeiten" -#: apps/note/tables.py:226 apps/note/tables.py:253 +#: apps/note/tables.py:266 apps/note/tables.py:293 msgid "Hide/Show" msgstr "" @@ -1639,15 +1684,27 @@ msgstr "Konsumieren!" msgid "Highlighted buttons" msgstr "Hervorgehobene Tasten" -#: apps/note/templates/note/conso_form.html:138 +#: apps/note/templates/note/conso_form.html:108 +#, fuzzy +#| msgid "Search WEI" +msgid "Search" +msgstr "WEI finden" + +#: apps/note/templates/note/conso_form.html:133 +#, fuzzy +#| msgid "Search button" +msgid "Search button..." +msgstr "Tatsen finden" + +#: apps/note/templates/note/conso_form.html:157 msgid "Single consumptions" msgstr "Solo Modus" -#: apps/note/templates/note/conso_form.html:143 +#: apps/note/templates/note/conso_form.html:162 msgid "Double consumptions" msgstr "Doppelte Modus" -#: apps/note/templates/note/conso_form.html:154 +#: apps/note/templates/note/conso_form.html:173 #: apps/note/templates/note/transaction_form.html:163 msgid "Recent transactions history" msgstr "Verlauf der letzten Transaktionen" @@ -1689,7 +1746,7 @@ msgid "Amount" msgstr "Anzahl" #: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:54 +#: apps/treasury/models.py:56 msgid "Name" msgstr "Name" @@ -1781,7 +1838,7 @@ msgstr "Verbräuche" msgid "You can't see any button." msgstr "Sie können keine Taste sehen." -#: apps/note/views.py:200 +#: apps/note/views.py:208 msgid "Search transactions" msgstr "Transaktion finden" @@ -1860,7 +1917,7 @@ msgstr "Angabefeld gilt nur zum Anzeigen und Ändern von Berechtigungstypen." msgid "for club" msgstr "Für Club" -#: apps/permission/models.py:350 apps/permission/models.py:351 +#: apps/permission/models.py:351 apps/permission/models.py:352 msgid "role permissions" msgstr "Berechtigung Rollen" @@ -1982,29 +2039,15 @@ msgstr "Alle Rechten" msgid "registration" msgstr "Anmeldung" -#: apps/registration/forms.py:39 +#: apps/registration/forms.py:40 msgid "This email address is already used." msgstr "Diese email adresse ist schon benutzt." -#: apps/registration/forms.py:49 -#, fuzzy -#| msgid "You already opened an account in the Société générale." -msgid "" -"I declare that I opened or I will open soon a bank account in the Société " -"générale with the BDE partnership." -msgstr "Sie haben bereits ein Konto in der Société générale eröffnet." - -#: apps/registration/forms.py:51 -msgid "" -"Warning: this engages you to open your bank account. If you finally decides " -"to don't open your account, you will have to pay the BDE membership." -msgstr "" - -#: apps/registration/forms.py:59 +#: apps/registration/forms.py:60 msgid "Register to the WEI" msgstr "Zu WEI anmelden" -#: apps/registration/forms.py:61 +#: apps/registration/forms.py:62 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." @@ -2013,14 +2056,18 @@ msgstr "" "falls Zweifel, können Sie sich später nach Bestätigung Ihres Kontos im Kfet " "registrieren." -#: apps/registration/forms.py:106 +#: apps/registration/forms.py:107 msgid "Join BDE Club" msgstr "BDE Mitglieder werden" -#: apps/registration/forms.py:113 +#: apps/registration/forms.py:114 msgid "Join Kfet Club" msgstr "Kfet Mitglieder werden" +#: apps/registration/forms.py:123 +msgid "Join BDA Club" +msgstr "BDA Mitglieder werden" + #: apps/registration/templates/registration/email_validation_complete.html:15 msgid "Your email have successfully been validated." msgstr "Ihre E-Mail wurde erfolgreich validiert." @@ -2069,14 +2116,14 @@ msgstr "Registrierung löschen" msgid "Validate account" msgstr "Konto validieren" -#: apps/registration/templates/registration/future_profile_detail.html:62 +#: apps/registration/templates/registration/future_profile_detail.html:63 #, fuzzy #| msgid "You already opened an account in the Société générale." msgid "" "The user declared that he/she opened a bank account in the Société générale." msgstr "Sie haben bereits ein Konto in der Société générale eröffnet." -#: apps/registration/templates/registration/future_profile_detail.html:71 +#: apps/registration/templates/registration/future_profile_detail.html:73 #: apps/wei/templates/wei/weimembership_form.html:127 #: apps/wei/templates/wei/weimembership_form.html:186 msgid "Validate registration" @@ -2128,54 +2175,54 @@ msgstr "Danke" msgid "The Note Kfet team." msgstr "Die NoteKfet Team." -#: apps/registration/views.py:40 +#: apps/registration/views.py:41 msgid "Register new user" msgstr "Neuen User registrieren" -#: apps/registration/views.py:98 +#: apps/registration/views.py:99 msgid "Email validation" msgstr "Email validierung" -#: apps/registration/views.py:100 +#: apps/registration/views.py:101 msgid "Validate email" msgstr "Email validieren" -#: apps/registration/views.py:144 +#: apps/registration/views.py:145 msgid "Email validation unsuccessful" msgstr "Email validierung unerfolgreich" -#: apps/registration/views.py:155 +#: apps/registration/views.py:156 msgid "Email validation email sent" msgstr "Validierungsemail wurde gesendet" -#: apps/registration/views.py:163 +#: apps/registration/views.py:164 msgid "Resend email validation link" msgstr "E-Mail-Validierungslink erneut senden" -#: apps/registration/views.py:181 +#: apps/registration/views.py:182 msgid "Pre-registered users list" msgstr "Vorregistrierte Userliste" -#: apps/registration/views.py:205 +#: apps/registration/views.py:206 msgid "Unregistered users" msgstr "Unregistrierte Users" -#: apps/registration/views.py:218 +#: apps/registration/views.py:219 msgid "Registration detail" msgstr "Registrierung Detailen" -#: apps/registration/views.py:282 +#: apps/registration/views.py:293 msgid "You must join the BDE." msgstr "Sie müssen die BDE beitreten." -#: apps/registration/views.py:306 +#: apps/registration/views.py:323 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:387 +#: apps/registration/views.py:417 msgid "Invalidate pre-registration" msgstr "Ungültige Vorregistrierung" @@ -2183,7 +2230,7 @@ msgstr "Ungültige Vorregistrierung" msgid "Treasury" msgstr "Quaestor" -#: apps/treasury/forms.py:26 apps/treasury/models.py:93 +#: apps/treasury/forms.py:26 apps/treasury/models.py:95 #: apps/treasury/templates/treasury/invoice_form.html:22 msgid "This invoice is locked and can no longer be edited." msgstr "Diese Rechnung ist gesperrt und kann nicht mehr bearbeitet werden." @@ -2196,7 +2243,7 @@ msgstr "Überweisung ist bereits geschlossen." msgid "You can't change the type of the remittance." msgstr "Sie können die Art der Überweisung nicht ändern." -#: apps/treasury/forms.py:125 apps/treasury/models.py:267 +#: apps/treasury/forms.py:125 apps/treasury/models.py:269 #: 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 @@ -2212,116 +2259,116 @@ msgstr "Keine beigefügte Überweisung" msgid "Invoice identifier" msgstr "Rechnungskennung" -#: apps/treasury/models.py:40 +#: apps/treasury/models.py:42 msgid "BDE" msgstr "BDE" -#: apps/treasury/models.py:45 +#: apps/treasury/models.py:47 msgid "Object" msgstr "Objekt" -#: apps/treasury/models.py:49 +#: apps/treasury/models.py:51 msgid "Description" msgstr "Beschreibung" -#: apps/treasury/models.py:58 +#: apps/treasury/models.py:60 msgid "Address" msgstr "Adresse" -#: apps/treasury/models.py:63 apps/treasury/models.py:193 +#: apps/treasury/models.py:65 apps/treasury/models.py:195 msgid "Date" msgstr "Datum" -#: apps/treasury/models.py:67 +#: apps/treasury/models.py:69 msgid "Acquitted" msgstr "Bezahlt" -#: apps/treasury/models.py:72 +#: apps/treasury/models.py:74 msgid "Locked" msgstr "Gesperrt" -#: apps/treasury/models.py:73 +#: apps/treasury/models.py:75 msgid "An invoice can't be edited when it is locked." msgstr "Eine Rechnung kann nicht bearbeitet werden, wenn sie gesperrt ist." -#: apps/treasury/models.py:79 +#: apps/treasury/models.py:81 msgid "tex source" msgstr "Tex Quelle" -#: apps/treasury/models.py:113 apps/treasury/models.py:129 +#: apps/treasury/models.py:115 apps/treasury/models.py:131 msgid "invoice" msgstr "Rechnung" -#: apps/treasury/models.py:114 +#: apps/treasury/models.py:116 msgid "invoices" msgstr "Rechnungen" -#: apps/treasury/models.py:117 +#: apps/treasury/models.py:119 #, python-brace-format msgid "Invoice #{id}" msgstr "Rechnung #{id}" -#: apps/treasury/models.py:134 +#: apps/treasury/models.py:136 msgid "Designation" msgstr "Bezeichnung" -#: apps/treasury/models.py:140 +#: apps/treasury/models.py:142 msgid "Quantity" msgstr "Qualität" -#: apps/treasury/models.py:145 +#: apps/treasury/models.py:147 msgid "Unit price" msgstr "Einzelpreis" -#: apps/treasury/models.py:161 +#: apps/treasury/models.py:163 msgid "product" msgstr "Produkt" -#: apps/treasury/models.py:162 +#: apps/treasury/models.py:164 msgid "products" msgstr "Produkten" -#: apps/treasury/models.py:182 +#: apps/treasury/models.py:184 msgid "remittance type" msgstr "Überweisungstyp" -#: apps/treasury/models.py:183 +#: apps/treasury/models.py:185 msgid "remittance types" msgstr "Überweisungstypen" -#: apps/treasury/models.py:204 +#: apps/treasury/models.py:206 msgid "Comment" msgstr "Kommentar" -#: apps/treasury/models.py:209 +#: apps/treasury/models.py:211 msgid "Closed" msgstr "Geschlossen" -#: apps/treasury/models.py:213 +#: apps/treasury/models.py:215 msgid "remittance" msgstr "Überweisung" -#: apps/treasury/models.py:214 +#: apps/treasury/models.py:216 msgid "remittances" msgstr "Überweisungen" -#: apps/treasury/models.py:247 +#: apps/treasury/models.py:249 msgid "Remittance #{:d}: {}" msgstr "Überweisung #{:d}:{}" -#: apps/treasury/models.py:271 +#: apps/treasury/models.py:273 msgid "special transaction proxy" msgstr "spezielle Transaktion Proxy" -#: apps/treasury/models.py:272 +#: apps/treasury/models.py:274 msgid "special transaction proxies" msgstr "spezielle Transaktion Proxies" -#: apps/treasury/models.py:298 +#: apps/treasury/models.py:300 msgid "credit transaction" msgstr "Kredit Transaktion" -#: apps/treasury/models.py:430 +#: apps/treasury/models.py:432 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." @@ -2329,16 +2376,16 @@ msgstr "" "Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner " "Note zu bezahlen." -#: apps/treasury/models.py:451 +#: apps/treasury/models.py:452 #: 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:452 +#: apps/treasury/models.py:453 msgid "Credits from the Société générale" msgstr "Krediten von der Société générale" -#: apps/treasury/models.py:455 +#: apps/treasury/models.py:456 #, python-brace-format msgid "Soge credit for {user}" msgstr "Kredit von der Société générale für {user}" @@ -2367,12 +2414,12 @@ msgid "Yes" msgstr "Ja" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:10 -#: apps/treasury/views.py:180 +#: apps/treasury/views.py:173 msgid "Delete invoice" msgstr "Rechnung löschen" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:15 -#: apps/treasury/views.py:184 +#: apps/treasury/views.py:177 msgid "This invoice is locked and can't be deleted." msgstr "Eine Rechnung kann nicht gelöscht werden, wenn sie gesperrt ist." @@ -2558,36 +2605,36 @@ msgstr "Neue Rechnung" msgid "Invoices list" msgstr "Rechnunglist" -#: apps/treasury/views.py:112 apps/treasury/views.py:286 -#: apps/treasury/views.py:412 +#: apps/treasury/views.py:105 apps/treasury/views.py:275 +#: apps/treasury/views.py:401 msgid "You are not able to see the treasury interface." msgstr "Sie können die Quaestor-App nicht sehen." -#: apps/treasury/views.py:122 +#: apps/treasury/views.py:115 msgid "Update an invoice" msgstr "Rechnung bearbeiten" -#: apps/treasury/views.py:247 +#: apps/treasury/views.py:240 msgid "Create a new remittance" msgstr "Neue Überweisung" -#: apps/treasury/views.py:274 +#: apps/treasury/views.py:267 msgid "Remittances list" msgstr "Überweisungliste" -#: apps/treasury/views.py:337 +#: apps/treasury/views.py:326 msgid "Update a remittance" msgstr "Überweisung bearbeiten" -#: apps/treasury/views.py:360 +#: apps/treasury/views.py:349 msgid "Attach a transaction to a remittance" msgstr "Fügen Sie einer Überweisung eine Transaktion hinzu" -#: apps/treasury/views.py:404 +#: apps/treasury/views.py:393 msgid "List of credits from the Société générale" msgstr "Kreditliste von Société générale" -#: apps/treasury/views.py:449 +#: apps/treasury/views.py:438 msgid "Manage credits from the Société générale" msgstr "Krediten von der Société générale handeln" @@ -2602,7 +2649,7 @@ msgid "The selected user is not validated. Please validate its account first" msgstr "" #: apps/wei/forms/registration.py:59 apps/wei/models.py:126 -#: apps/wei/models.py:323 +#: apps/wei/models.py:326 msgid "bus" msgstr "Bus" @@ -2640,7 +2687,7 @@ msgstr "Wählen Sie die Rollen aus, an denen Sie interessiert sind." msgid "This team doesn't belong to the given bus." msgstr "Dieses Team gehört nicht zum angegebenen Bus." -#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35 +#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38 msgid "Choose a word:" msgstr "Wählen Sie ein Wort:" @@ -2727,40 +2774,48 @@ msgstr "Nicht binär" msgid "gender" msgstr "Geschlecht" -#: apps/wei/models.py:213 apps/wei/templates/wei/weimembership_form.html:58 +#: apps/wei/models.py:212 +msgid "Unisex" +msgstr "Unisex" + +#: apps/wei/models.py:215 apps/wei/templates/wei/weimembership_form.html:58 msgid "clothing cut" msgstr "Kleidung Schnitt" -#: apps/wei/models.py:226 apps/wei/templates/wei/weimembership_form.html:61 +#: apps/wei/models.py:228 apps/wei/templates/wei/weimembership_form.html:61 msgid "clothing size" msgstr "Kleidergröße" -#: apps/wei/models.py:232 apps/wei/templates/wei/attribute_bus_1A.html:28 +#: apps/wei/models.py:234 apps/wei/templates/wei/attribute_bus_1A.html:28 #: apps/wei/templates/wei/weimembership_form.html:67 msgid "health issues" msgstr "Gesundheitsprobleme" -#: apps/wei/models.py:237 apps/wei/templates/wei/weimembership_form.html:70 +#: apps/wei/models.py:239 apps/wei/templates/wei/weimembership_form.html:70 msgid "emergency contact name" msgstr "Notfall-Kontakt" -#: apps/wei/models.py:242 apps/wei/templates/wei/weimembership_form.html:73 +#: apps/wei/models.py:240 +msgid "The emergency contact must not be a WEI participant" +msgstr "Der Notfallkontakt darf kein WEI-Teilnehmer sein" + +#: apps/wei/models.py:245 apps/wei/templates/wei/weimembership_form.html:73 msgid "emergency contact phone" msgstr "Notfallkontakttelefon" -#: apps/wei/models.py:247 apps/wei/templates/wei/weimembership_form.html:52 +#: apps/wei/models.py:250 apps/wei/templates/wei/weimembership_form.html:52 msgid "first year" msgstr "Erste Jahr" -#: apps/wei/models.py:248 +#: apps/wei/models.py:251 msgid "Tells if the user is new in the school." msgstr "Gibt an, ob der USer neu in der Schule ist." -#: apps/wei/models.py:253 +#: apps/wei/models.py:256 msgid "registration information" msgstr "Registrierung Detailen" -#: apps/wei/models.py:254 +#: apps/wei/models.py:257 msgid "" "Information about the registration (buses for old members, survey for the " "new members), encoded in JSON" @@ -2768,27 +2823,27 @@ msgstr "" "Informationen zur Registrierung (Busse für alte Mitglieder, Umfrage für neue " "Mitglieder), verschlüsselt in JSON" -#: apps/wei/models.py:312 +#: apps/wei/models.py:315 msgid "WEI User" msgstr "WEI User" -#: apps/wei/models.py:313 +#: apps/wei/models.py:316 msgid "WEI Users" msgstr "WEI Users" -#: apps/wei/models.py:333 +#: apps/wei/models.py:336 msgid "team" msgstr "Team" -#: apps/wei/models.py:343 +#: apps/wei/models.py:346 msgid "WEI registration" msgstr "WEI Registrierung" -#: apps/wei/models.py:347 +#: apps/wei/models.py:350 msgid "WEI membership" msgstr "WEI Mitgliedschaft" -#: apps/wei/models.py:348 +#: apps/wei/models.py:351 msgid "WEI memberships" msgstr "WEI Mitgliedschaften" @@ -2933,7 +2988,7 @@ msgstr "Als PDF schauen" #: 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:1028 -#: apps/wei/views.py:1083 apps/wei/views.py:1093 +#: apps/wei/views.py:1083 apps/wei/views.py:1130 msgid "Survey WEI" msgstr "WEI Umfrage" @@ -3211,11 +3266,11 @@ msgstr "Sie haben nicht das Recht, diese WEI-Registrierung zu löschen." msgid "Validate WEI registration" msgstr "Überprüfen Sie die WEI-Registrierung" -#: apps/wei/views.py:1186 +#: apps/wei/views.py:1223 msgid "Attribute buses to first year members" msgstr "" -#: apps/wei/views.py:1211 +#: apps/wei/views.py:1248 msgid "Attribute bus" msgstr "" @@ -3361,6 +3416,10 @@ msgstr "Kontakt" msgid "Technical Support" msgstr "" +#: note_kfet/templates/base.html:198 +msgid "FAQ (FR)" +msgstr "FAQ (FR)" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Suche nach Attributen wie Name…" @@ -3608,10 +3667,16 @@ msgstr "" "müssen Ihre E-Mail-Adresse auch überprüfen, indem Sie dem Link folgen, den " "Sie erhalten haben." +#, fuzzy +#~| msgid "You already opened an account in the Société générale." +#~ msgid "" +#~ "I declare that I opened or I will open soon a bank account in the Société " +#~ "générale with the BDE partnership." +#~ msgstr "Sie haben bereits ein Konto in der Société générale eröffnet." + #~ msgid "This user didn't give her/his caution check." #~ msgstr "Dieser User hat seine / ihre Vorsicht nicht überprüft." -#, 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 " diff --git a/locale/de/LC_MESSAGES/djangojs.po b/locale/de/LC_MESSAGES/djangojs.po index f4f51515..35648a6e 100644 --- a/locale/de/LC_MESSAGES/djangojs.po +++ b/locale/de/LC_MESSAGES/djangojs.po @@ -7,11 +7,11 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-15 23:21+0100\n" +"POT-Creation-Date: 2022-10-07 09:07+0200\n" "PO-Revision-Date: 2020-11-16 20:21+0000\n" "Last-Translator: Yohann D'ANELLO \n" -"Language-Team: German " -"\n" +"Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -27,6 +27,22 @@ msgstr "Alias erfolgreich hinzugefügt" msgid "Alias successfully deleted" msgstr "Alias erfolgreich gelöscht" +#: apps/member/static/member/js/trust.js:14 +msgid "You can't add yourself as a friend" +msgstr "" + +#: apps/member/static/member/js/trust.js:37 +#, fuzzy +#| msgid "Alias successfully added" +msgid "Friendship successfully added" +msgstr "Alias erfolgreich hinzugefügt" + +#: apps/member/static/member/js/trust.js:53 +#, fuzzy +#| msgid "Alias successfully deleted" +msgid "Friendship successfully deleted" +msgstr "Alias erfolgreich gelöscht" + #: apps/note/static/note/js/consos.js:225 #, javascript-format msgid "" @@ -46,32 +62,32 @@ msgstr "" "ist negativ." #: apps/note/static/note/js/consos.js:232 -#: apps/note/static/note/js/transfer.js:298 -#: apps/note/static/note/js/transfer.js:401 +#: apps/note/static/note/js/transfer.js:309 +#: apps/note/static/note/js/transfer.js:412 #, javascript-format msgid "Warning, the emitter note %s is no more a BDE member." msgstr "Warnung, der Emittent Hinweis %s ist kein BDE-Mitglied mehr." -#: apps/note/static/note/js/consos.js:253 +#: apps/note/static/note/js/consos.js:254 msgid "The transaction couldn't be validated because of insufficient balance." msgstr "" "Die Transaktion konnte aufgrund eines unzureichenden Saldos nicht validiert " "werden." -#: apps/note/static/note/js/transfer.js:238 +#: apps/note/static/note/js/transfer.js:249 msgid "This field is required and must contain a decimal positive number." msgstr "" "Dieses Feld ist erforderlich und muss eine positive Dezimalzahl enthalten." -#: apps/note/static/note/js/transfer.js:245 +#: apps/note/static/note/js/transfer.js:256 msgid "The amount must stay under 21,474,836.47 €." msgstr "Der Betrag muss unter 21.474.836,47 € bleiben." -#: apps/note/static/note/js/transfer.js:251 +#: apps/note/static/note/js/transfer.js:262 msgid "This field is required." msgstr "Dies ist ein Pflichtfeld." -#: apps/note/static/note/js/transfer.js:277 +#: apps/note/static/note/js/transfer.js:288 #, javascript-format msgid "" "Warning: the transaction of %s from %s to %s was not made because it is the " @@ -80,12 +96,12 @@ msgstr "" "Warnung: Die Transaktion von %s von %s nach %s wurde nicht durchgeführt, da " "es sich um die gleiche Quell- und Zielnotiz handelt." -#: apps/note/static/note/js/transfer.js:301 +#: apps/note/static/note/js/transfer.js:312 #, javascript-format msgid "Warning, the destination note %s is no more a BDE member." msgstr "Warnung, der Bestimmungsvermerk %s ist kein BDE-Mitglied mehr." -#: apps/note/static/note/js/transfer.js:307 +#: apps/note/static/note/js/transfer.js:318 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -94,7 +110,7 @@ msgstr "" "Warnung, die Transaktion von %s von der Note %s zur Note %s gelingt, aber " "die Emitternote %s ist sehr negativ." -#: apps/note/static/note/js/transfer.js:312 +#: apps/note/static/note/js/transfer.js:323 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -103,31 +119,32 @@ msgstr "" "Warnung, die Transaktion von %s von der Note %s zur Note %s gelingt, aber " "die Emitternote %s ist negativ." -#: apps/note/static/note/js/transfer.js:318 +#: apps/note/static/note/js/transfer.js:329 #, javascript-format msgid "Transfer of %s from %s to %s succeed!" msgstr "Übertragung von %s von %s auf %s gelingt!" -#: apps/note/static/note/js/transfer.js:325 -#: apps/note/static/note/js/transfer.js:346 -#: apps/note/static/note/js/transfer.js:353 +#: apps/note/static/note/js/transfer.js:336 +#: apps/note/static/note/js/transfer.js:357 +#: apps/note/static/note/js/transfer.js:364 #, javascript-format msgid "Transfer of %s from %s to %s failed: %s" msgstr "Übertragung von %s von %s auf %s fehlgeschlagen: %s" -#: apps/note/static/note/js/transfer.js:347 +#: apps/note/static/note/js/transfer.js:358 msgid "insufficient funds" msgstr "unzureichende Geldmittel" -#: apps/note/static/note/js/transfer.js:400 +#: apps/note/static/note/js/transfer.js:411 msgid "Credit/debit succeed!" msgstr "Kredit/Debit erfolgreich!" -#: apps/note/static/note/js/transfer.js:407 +#: apps/note/static/note/js/transfer.js:418 #, javascript-format msgid "Credit/debit failed: %s" msgstr "Kredit/Debit fehlgeschlagen: %s" -#: note_kfet/static/js/base.js:366 +#: note_kfet/static/js/base.js:370 msgid "An error occured while (in)validating this transaction:" -msgstr "Bei der (Un-)Validierung dieser Transaktion ist ein Fehler aufgetreten:" +msgstr "" +"Bei der (Un-)Validierung dieser Transaktion ist ein Fehler aufgetreten:" diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 4f03a2ca..fe8e4950 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-10 22:34+0200\n" +"POT-Creation-Date: 2023-10-25 19:12+0200\n" "PO-Revision-Date: 2022-04-11 23:12+0200\n" -"Last-Translator: elkmaennchen \n" +"Last-Translator: bleizi \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 3.0\n" +"X-Generator: Poedit 3.0.1\n" #: apps/activity/apps.py:10 apps/activity/models.py:151 #: apps/activity/models.py:167 @@ -52,7 +52,7 @@ 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/models.py:204 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -113,8 +113,8 @@ msgstr "Lugar donde se organiza la actividad, por ejemplo la Kfet." msgid "type" msgstr "tipo" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307 -#: apps/note/models/notes.py:148 apps/treasury/models.py:285 +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:312 +#: apps/note/models/notes.py:148 apps/treasury/models.py:287 #: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" @@ -257,19 +257,19 @@ msgstr "Entrado el " msgid "remove" msgstr "quitar" -#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199 +#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:201 msgid "Type" msgstr "Tipo" -#: apps/activity/tables.py:84 apps/member/forms.py:186 -#: apps/registration/forms.py:91 apps/treasury/forms.py:131 +#: apps/activity/tables.py:84 apps/member/forms.py:193 +#: apps/registration/forms.py:92 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Apellido" -#: apps/activity/tables.py:86 apps/member/forms.py:191 +#: apps/activity/tables.py:86 apps/member/forms.py:198 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:96 apps/treasury/forms.py:133 +#: apps/registration/forms.py:97 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Nombre" @@ -386,7 +386,7 @@ msgid "validate" msgstr "validar" #: apps/activity/templates/activity/includes/activity_info.html:71 -#: apps/logs/models.py:64 apps/note/tables.py:220 +#: apps/logs/models.py:64 apps/note/tables.py:260 msgid "edit" msgstr "modificar" @@ -464,9 +464,9 @@ msgstr "nuevos datos" msgid "create" msgstr "crear" -#: apps/logs/models.py:65 apps/note/tables.py:166 apps/note/tables.py:190 -#: apps/note/tables.py:237 apps/permission/models.py:127 -#: apps/treasury/tables.py:38 apps/wei/tables.py:74 +#: apps/logs/models.py:65 apps/note/tables.py:230 apps/note/tables.py:277 +#: apps/permission/models.py:127 apps/treasury/tables.py:38 +#: apps/wei/tables.py:74 msgid "delete" msgstr "suprimir" @@ -495,21 +495,21 @@ msgstr "diario de cambios" msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" msgstr "" -#: apps/member/admin.py:50 apps/member/models.py:226 +#: apps/member/admin.py:50 apps/member/models.py:231 #: 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/admin.py:51 apps/member/models.py:236 #: 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:319 +#: apps/member/admin.py:65 apps/member/models.py:324 msgid "roles" msgstr "papel" -#: apps/member/admin.py:66 apps/member/models.py:333 +#: apps/member/admin.py:66 apps/member/models.py:338 msgid "fee" msgstr "pago" @@ -529,65 +529,81 @@ msgstr "Frecuencia de los informes (en días)" msgid "Last report date" msgstr "Fecha del último informe" +#: apps/member/forms.py:52 +msgid "" +"Anti-VSS (Violences Sexistes et Sexuelles) charter read and approved" +msgstr "" +"Carta Anti-VSS (Violences Sexistes et Sexuelles) leída y aprobada" + #: apps/member/forms.py:53 +msgid "" +"Tick after having read and accepted the anti-VSS charter " +"available here in pdf" +msgstr "" +"Marque después de leer y aceptar la carta anti-VVS disponible en " +"pdf aquí" + +#: apps/member/forms.py:60 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:79 +#: apps/member/forms.py:86 msgid "select an image" msgstr "elegir una imagen" -#: apps/member/forms.py:80 +#: apps/member/forms.py:87 msgid "Maximal size: 2MB" msgstr "Tamaño máximo : 2Mo" -#: apps/member/forms.py:105 +#: apps/member/forms.py:112 msgid "This image cannot be loaded." msgstr "Esta imagen no puede ser cargada." -#: apps/member/forms.py:141 apps/member/views.py:103 -#: apps/registration/forms.py:33 apps/registration/views.py:262 +#: apps/member/forms.py:148 apps/member/views.py:102 +#: apps/registration/forms.py:34 apps/registration/views.py:266 msgid "An alias with a similar name already exists." msgstr "Un alias similar ya existe." -#: apps/member/forms.py:165 apps/registration/forms.py:71 +#: apps/member/forms.py:172 msgid "Inscription paid by Société Générale" msgstr "Registración pagadas por Société Générale" -#: apps/member/forms.py:167 apps/registration/forms.py:73 +#: apps/member/forms.py:174 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:172 apps/registration/forms.py:78 +#: apps/member/forms.py:179 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Tipo de crédito" -#: apps/member/forms.py:173 apps/registration/forms.py:79 +#: apps/member/forms.py:180 apps/registration/forms.py:80 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "No crédito" -#: apps/member/forms.py:175 +#: apps/member/forms.py:182 msgid "You can credit the note of the user." msgstr "Usted puede acreditar la note del usuario." -#: apps/member/forms.py:179 apps/registration/forms.py:84 +#: apps/member/forms.py:186 apps/registration/forms.py:85 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Valor del crédito" -#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:101 apps/treasury/forms.py:135 +#: apps/member/forms.py:203 apps/note/templates/note/transaction_form.html:144 +#: apps/registration/forms.py:102 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Banco" -#: apps/member/forms.py:223 +#: apps/member/forms.py:230 msgid "User" msgstr "Usuario" -#: apps/member/forms.py:237 +#: apps/member/forms.py:244 msgid "Roles" msgstr "Papeles" @@ -772,15 +788,19 @@ msgstr "correo electrónico confirmado" msgid "registration valid" msgstr "registración valida" -#: apps/member/models.py:162 apps/member/models.py:163 +#: apps/member/models.py:138 +msgid "VSS charter read" +msgstr "Carta VSS leída" + +#: apps/member/models.py:167 apps/member/models.py:168 msgid "user profile" msgstr "perfil usuario" -#: apps/member/models.py:173 +#: apps/member/models.py:178 msgid "Activate your Note Kfet account" msgstr "Active su cuenta Note Kfet" -#: apps/member/models.py:204 +#: apps/member/models.py:209 #: apps/member/templates/member/includes/club_info.html:55 #: apps/member/templates/member/includes/profile_info.html:40 #: apps/registration/templates/registration/future_profile_detail.html:22 @@ -789,87 +809,87 @@ msgstr "Active su cuenta Note Kfet" msgid "email" msgstr "correo electrónico" -#: apps/member/models.py:211 +#: apps/member/models.py:216 msgid "parent club" msgstr "club pariente" -#: apps/member/models.py:220 +#: apps/member/models.py:225 msgid "require memberships" msgstr "necesita afiliaciones" -#: apps/member/models.py:221 +#: apps/member/models.py:226 msgid "Uncheck if this club don't require memberships." msgstr "Desmarcar si este club no usa afiliaciones." -#: apps/member/models.py:237 +#: apps/member/models.py:242 #: apps/member/templates/member/includes/club_info.html:26 msgid "membership duration" msgstr "duración de la afiliación" -#: apps/member/models.py:238 +#: apps/member/models.py:243 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/models.py:250 #: apps/member/templates/member/includes/club_info.html:16 msgid "membership start" msgstr "inicio de la afiliación" -#: apps/member/models.py:246 +#: apps/member/models.py:251 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/models.py:257 #: apps/member/templates/member/includes/club_info.html:21 msgid "membership end" msgstr "fin de la afiliación" -#: apps/member/models.py:253 +#: apps/member/models.py:258 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:288 apps/member/models.py:313 +#: apps/member/models.py:293 apps/member/models.py:318 #: apps/note/models/notes.py:176 msgid "club" msgstr "club" -#: apps/member/models.py:289 +#: apps/member/models.py:294 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:324 +#: apps/member/models.py:329 msgid "membership starts on" msgstr "afiliación empezá el" -#: apps/member/models.py:328 +#: apps/member/models.py:333 msgid "membership ends on" msgstr "afiliación termina el" -#: apps/member/models.py:430 +#: apps/member/models.py:435 #, 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:439 apps/member/views.py:712 +#: apps/member/models.py:444 apps/member/views.py:712 msgid "User is already a member of the club" msgstr "Usuario ya esta un miembro del club" -#: apps/member/models.py:451 apps/member/views.py:721 +#: apps/member/models.py:456 apps/member/views.py:721 msgid "User is not a member of the parent club" msgstr "Usuario no es un miembro del club pariente" -#: apps/member/models.py:504 +#: apps/member/models.py:509 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Afiliación of {user} for the club {club}" -#: apps/member/models.py:507 apps/note/models/transactions.py:389 +#: apps/member/models.py:512 apps/note/models/transactions.py:389 msgid "membership" msgstr "afiliación" -#: apps/member/models.py:508 +#: apps/member/models.py:513 msgid "memberships" msgstr "afiliaciones" @@ -921,7 +941,7 @@ msgid "Account #" msgstr "Cuenta n°" #: apps/member/templates/member/base.html:48 -#: apps/member/templates/member/base.html:62 apps/member/views.py:60 +#: apps/member/templates/member/base.html:62 apps/member/views.py:59 #: apps/registration/templates/registration/future_profile_detail.html:48 #: apps/wei/templates/wei/weimembership_form.html:117 msgid "Update Profile" @@ -1155,9 +1175,9 @@ msgstr "Hacer clic aquí para reenviar un enlace de validación." msgid "View my memberships" msgstr "Ver mis afiliaciones" -#: apps/member/templates/member/profile_trust.html:10 apps/member/views.py:254 -msgid "Note friendships" -msgstr "Amistades de note" +#: apps/member/templates/member/profile_trust.html:10 +msgid "Add friends" +msgstr "Añadir amig@s" #: apps/member/templates/member/profile_trust.html:28 msgid "" @@ -1172,6 +1192,10 @@ msgstr "" "simplificar el reembolso entre amig@s por Note Kfet. Pues una persona puede " "crear todas la transacciones sin tener derechos particulares." +#: apps/member/templates/member/profile_trust.html:39 +msgid "People having you as a friend" +msgstr "Personas que tienen usted como amig@" + #: apps/member/templates/member/profile_update.html:18 msgid "Save Changes" msgstr "Guardar cambios" @@ -1180,18 +1204,22 @@ msgstr "Guardar cambios" msgid "Registrations" msgstr "Registraciones" -#: apps/member/views.py:73 apps/registration/forms.py:23 +#: apps/member/views.py:72 apps/registration/forms.py:24 msgid "This address must be valid." msgstr "Este correo tiene que ser valido." -#: apps/member/views.py:140 +#: apps/member/views.py:139 msgid "Profile detail" msgstr "Detalles del usuario" -#: apps/member/views.py:206 +#: apps/member/views.py:205 msgid "Search user" msgstr "Buscar un usuario" +#: apps/member/views.py:253 +msgid "Note friendships" +msgstr "Amistades de note" + #: apps/member/views.py:308 msgid "Update note picture" msgstr "Modificar la imagen de la note" @@ -1236,29 +1264,35 @@ msgstr "La afiliación tiene que empezar después del {:%d-%m-%Y}." 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:876 +#: apps/member/views.py:880 msgid "Manage roles of an user in the club" msgstr "Gestionar los papeles de un usuario en el club" -#: apps/member/views.py:901 +#: apps/member/views.py:905 msgid "Members of the club" msgstr "Miembros del club" -#: apps/note/admin.py:129 apps/note/models/transactions.py:109 +#: apps/note/admin.py:139 apps/note/models/transactions.py:109 msgid "source" msgstr "fuente" -#: apps/note/admin.py:137 apps/note/admin.py:205 +#: apps/note/admin.py:147 apps/note/admin.py:215 #: 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/admin.py:220 apps/note/models/transactions.py:60 #: apps/note/models/transactions.py:140 msgid "amount" msgstr "monto" -#: apps/note/api/serializers.py:199 apps/note/api/serializers.py:205 +#: apps/note/api/serializers.py:92 +#, fuzzy +#| msgid "This credit is already validated." +msgid "This friendship already exists" +msgstr "Este crédito ya fue validado." + +#: apps/note/api/serializers.py:198 apps/note/api/serializers.py:204 #: apps/note/models/transactions.py:228 msgid "" "The transaction can't be saved since the source note or the destination note " @@ -1557,7 +1591,7 @@ msgstr "Transacciones especiales" msgid "membership transaction" msgstr "transacción de afiliación" -#: apps/note/models/transactions.py:385 apps/treasury/models.py:292 +#: apps/note/models/transactions.py:385 apps/treasury/models.py:294 msgid "membership transactions" msgstr "transacciones de afiliación" @@ -1573,8 +1607,8 @@ msgstr "Hacer clic para validar" msgid "No reason specified" msgstr "Ningún motivo dado" -#: apps/note/tables.py:173 apps/note/tables.py:194 apps/note/tables.py:239 -#: apps/treasury/tables.py:39 +#: apps/note/tables.py:166 apps/note/tables.py:173 apps/note/tables.py:234 +#: apps/note/tables.py:279 apps/treasury/tables.py:39 #: apps/treasury/templates/treasury/invoice_confirm_delete.html:30 #: apps/treasury/templates/treasury/sogecredit_detail.html:65 #: apps/wei/tables.py:75 apps/wei/tables.py:118 @@ -1585,7 +1619,15 @@ msgstr "Ningún motivo dado" msgid "Delete" msgstr "Suprimir" -#: apps/note/tables.py:222 apps/note/templates/note/conso_form.html:132 +#: apps/note/tables.py:191 +msgid "Trust back" +msgstr "Añadir como amig@" + +#: apps/note/tables.py:211 +msgid "Add back" +msgstr "Añadir en retorno" + +#: apps/note/tables.py:262 apps/note/templates/note/conso_form.html:151 #: apps/wei/tables.py:49 apps/wei/tables.py:50 #: apps/wei/templates/wei/base.html:89 #: apps/wei/templates/wei/bus_detail.html:20 @@ -1595,7 +1637,7 @@ msgstr "Suprimir" msgid "Edit" msgstr "Editar" -#: apps/note/tables.py:226 apps/note/tables.py:253 +#: apps/note/tables.py:266 apps/note/tables.py:293 msgid "Hide/Show" msgstr "Ocultar/Mostrar" @@ -1626,15 +1668,27 @@ msgstr "¡ Consumir !" msgid "Highlighted buttons" msgstr "Botones resaltados" -#: apps/note/templates/note/conso_form.html:138 +#: apps/note/templates/note/conso_form.html:108 +#, fuzzy +#| msgid "Search WEI" +msgid "Search" +msgstr "Buscar un WEI" + +#: apps/note/templates/note/conso_form.html:133 +#, fuzzy +#| msgid "Search button" +msgid "Search button..." +msgstr "Buscar un botón" + +#: apps/note/templates/note/conso_form.html:157 msgid "Single consumptions" msgstr "Consumiciones simples" -#: apps/note/templates/note/conso_form.html:143 +#: apps/note/templates/note/conso_form.html:162 msgid "Double consumptions" msgstr "Consumiciones dobles" -#: apps/note/templates/note/conso_form.html:154 +#: apps/note/templates/note/conso_form.html:173 #: apps/note/templates/note/transaction_form.html:163 msgid "Recent transactions history" msgstr "Historial de las transacciones recientes" @@ -1676,7 +1730,7 @@ msgid "Amount" msgstr "Monto" #: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:54 +#: apps/treasury/models.py:56 msgid "Name" msgstr "Nombre" @@ -1764,7 +1818,7 @@ msgstr "Consumiciones" msgid "You can't see any button." msgstr "Usted no puede ver ningún botón." -#: apps/note/views.py:200 +#: apps/note/views.py:208 msgid "Search transactions" msgstr "Buscar transacciones" @@ -1845,7 +1899,7 @@ msgstr "" msgid "for club" msgstr "interesa el club" -#: apps/permission/models.py:350 apps/permission/models.py:351 +#: apps/permission/models.py:351 apps/permission/models.py:352 msgid "role permissions" msgstr "permisos por papeles" @@ -1963,31 +2017,15 @@ msgstr "Todos los permisos" msgid "registration" msgstr "afiliación" -#: apps/registration/forms.py:39 +#: apps/registration/forms.py:40 msgid "This email address is already used." msgstr "Este correo electrónico ya esta utilizado." -#: apps/registration/forms.py:49 -msgid "" -"I declare that I opened or I will open soon a bank account in the Société " -"générale with the BDE partnership." -msgstr "" -"Declaro que ya abrió una cuenta a la Société Générale en colaboración con el " -"BDE." - -#: apps/registration/forms.py:51 -msgid "" -"Warning: this engages you to open your bank account. If you finally decides " -"to don't open your account, you will have to pay the BDE membership." -msgstr "" -"Cuidado : esto le obliga abrir su cuenta bancaria. Si cambia de idea y no " -"abre su cuenta bancaria, tendrá que pagar su afiliación al BDE." - -#: apps/registration/forms.py:59 +#: apps/registration/forms.py:60 msgid "Register to the WEI" msgstr "Registrarse en el WEI" -#: apps/registration/forms.py:61 +#: apps/registration/forms.py:62 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." @@ -1995,14 +2033,18 @@ 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:106 +#: apps/registration/forms.py:107 msgid "Join BDE Club" msgstr "Afiliarse al club BDE" -#: apps/registration/forms.py:113 +#: apps/registration/forms.py:114 msgid "Join Kfet Club" msgstr "Afiliarse al club Kfet" +#: apps/registration/forms.py:123 +msgid "Join BDA Club" +msgstr "Afiliarse al club BDA" + #: 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." @@ -2051,12 +2093,12 @@ msgstr "Suprimir afiliación" msgid "Validate account" msgstr "Validar la cuenta" -#: apps/registration/templates/registration/future_profile_detail.html:62 +#: apps/registration/templates/registration/future_profile_detail.html:63 msgid "" "The user declared that he/she opened a bank account in the Société générale." msgstr "El usuario declara que ya abrió una cuenta a la Société Générale." -#: apps/registration/templates/registration/future_profile_detail.html:71 +#: apps/registration/templates/registration/future_profile_detail.html:73 #: apps/wei/templates/wei/weimembership_form.html:127 #: apps/wei/templates/wei/weimembership_form.html:186 msgid "Validate registration" @@ -2108,54 +2150,54 @@ msgstr "Gracias" msgid "The Note Kfet team." msgstr "El equipo Note Kfet." -#: apps/registration/views.py:40 +#: apps/registration/views.py:41 msgid "Register new user" msgstr "Registrar un nuevo usuario" -#: apps/registration/views.py:98 +#: apps/registration/views.py:99 msgid "Email validation" msgstr "Validación del correo electrónico" -#: apps/registration/views.py:100 +#: apps/registration/views.py:101 msgid "Validate email" msgstr "Validar el correo electrónico" -#: apps/registration/views.py:144 +#: apps/registration/views.py:145 msgid "Email validation unsuccessful" msgstr "La validación del correo electrónico fracasó" -#: apps/registration/views.py:155 +#: apps/registration/views.py:156 msgid "Email validation email sent" msgstr "Correo de validación enviado" -#: apps/registration/views.py:163 +#: apps/registration/views.py:164 msgid "Resend email validation link" msgstr "Reenviar el enlace de validación" -#: apps/registration/views.py:181 +#: apps/registration/views.py:182 msgid "Pre-registered users list" msgstr "Lista de los usuarios con afiliación pendiente" -#: apps/registration/views.py:205 +#: apps/registration/views.py:206 msgid "Unregistered users" msgstr "Usuarios con afiliación pendiente" -#: apps/registration/views.py:218 +#: apps/registration/views.py:219 msgid "Registration detail" msgstr "Detalles de la afiliación" -#: apps/registration/views.py:282 +#: apps/registration/views.py:293 msgid "You must join the BDE." msgstr "Usted tiene que afiliarse al BDE." -#: apps/registration/views.py:306 +#: apps/registration/views.py:323 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:387 +#: apps/registration/views.py:417 msgid "Invalidate pre-registration" msgstr "Invalidar la afiliación" @@ -2163,7 +2205,7 @@ msgstr "Invalidar la afiliación" msgid "Treasury" msgstr "Tesorería" -#: apps/treasury/forms.py:26 apps/treasury/models.py:93 +#: apps/treasury/forms.py:26 apps/treasury/models.py:95 #: 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." @@ -2176,7 +2218,7 @@ msgstr "El descuento ya esta cerrado." msgid "You can't change the type of the remittance." msgstr "No puede cambiar el tipo de descuento." -#: apps/treasury/forms.py:125 apps/treasury/models.py:267 +#: apps/treasury/forms.py:125 apps/treasury/models.py:269 #: 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 @@ -2192,116 +2234,116 @@ msgstr "No hay descuento relacionado" msgid "Invoice identifier" msgstr "Numero de factura" -#: apps/treasury/models.py:40 +#: apps/treasury/models.py:42 msgid "BDE" msgstr "BDE" -#: apps/treasury/models.py:45 +#: apps/treasury/models.py:47 msgid "Object" msgstr "Asunto" -#: apps/treasury/models.py:49 +#: apps/treasury/models.py:51 msgid "Description" msgstr "Descripción" -#: apps/treasury/models.py:58 +#: apps/treasury/models.py:60 msgid "Address" msgstr "Dirección" -#: apps/treasury/models.py:63 apps/treasury/models.py:193 +#: apps/treasury/models.py:65 apps/treasury/models.py:195 msgid "Date" msgstr "Fecha" -#: apps/treasury/models.py:67 +#: apps/treasury/models.py:69 msgid "Acquitted" msgstr "Pagada" -#: apps/treasury/models.py:72 +#: apps/treasury/models.py:74 msgid "Locked" msgstr "Bloqueada" -#: apps/treasury/models.py:73 +#: apps/treasury/models.py:75 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:79 +#: apps/treasury/models.py:81 msgid "tex source" msgstr "código fuente TeX" -#: apps/treasury/models.py:113 apps/treasury/models.py:129 +#: apps/treasury/models.py:115 apps/treasury/models.py:131 msgid "invoice" msgstr "factura" -#: apps/treasury/models.py:114 +#: apps/treasury/models.py:116 msgid "invoices" msgstr "facturas" -#: apps/treasury/models.py:117 +#: apps/treasury/models.py:119 #, python-brace-format msgid "Invoice #{id}" msgstr "Factura n°{id}" -#: apps/treasury/models.py:134 +#: apps/treasury/models.py:136 msgid "Designation" msgstr "Designación" -#: apps/treasury/models.py:140 +#: apps/treasury/models.py:142 msgid "Quantity" msgstr "Cantidad" -#: apps/treasury/models.py:145 +#: apps/treasury/models.py:147 msgid "Unit price" msgstr "Precio unitario" -#: apps/treasury/models.py:161 +#: apps/treasury/models.py:163 msgid "product" msgstr "producto" -#: apps/treasury/models.py:162 +#: apps/treasury/models.py:164 msgid "products" msgstr "productos" -#: apps/treasury/models.py:182 +#: apps/treasury/models.py:184 msgid "remittance type" msgstr "tipo de descuento" -#: apps/treasury/models.py:183 +#: apps/treasury/models.py:185 msgid "remittance types" msgstr "tipos de descuentos" -#: apps/treasury/models.py:204 +#: apps/treasury/models.py:206 msgid "Comment" msgstr "Comentario" -#: apps/treasury/models.py:209 +#: apps/treasury/models.py:211 msgid "Closed" msgstr "Cerrada" -#: apps/treasury/models.py:213 +#: apps/treasury/models.py:215 msgid "remittance" msgstr "descuento" -#: apps/treasury/models.py:214 +#: apps/treasury/models.py:216 msgid "remittances" msgstr "descuentos" -#: apps/treasury/models.py:247 +#: apps/treasury/models.py:249 msgid "Remittance #{:d}: {}" msgstr "Descuento n°{:d} : {}" -#: apps/treasury/models.py:271 +#: apps/treasury/models.py:273 msgid "special transaction proxy" msgstr "proxy de transacción especial" -#: apps/treasury/models.py:272 +#: apps/treasury/models.py:274 msgid "special transaction proxies" msgstr "proxys de transacciones especiales" -#: apps/treasury/models.py:298 +#: apps/treasury/models.py:300 msgid "credit transaction" msgstr "transacción de crédito" -#: apps/treasury/models.py:430 +#: apps/treasury/models.py:432 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." @@ -2310,16 +2352,16 @@ msgstr "" "afiliaciones. Por favor pídelo acreditar su note antes de invalidar este " "crédito." -#: apps/treasury/models.py:451 +#: apps/treasury/models.py:452 #: 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:452 +#: apps/treasury/models.py:453 msgid "Credits from the Société générale" msgstr "Créditos de la Société Générale" -#: apps/treasury/models.py:455 +#: apps/treasury/models.py:456 #, python-brace-format msgid "Soge credit for {user}" msgstr "Crédito de la Société Générale para {user}" @@ -2348,12 +2390,12 @@ msgid "Yes" msgstr "Sí" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:10 -#: apps/treasury/views.py:180 +#: apps/treasury/views.py:173 msgid "Delete invoice" msgstr "Suprimir la factura" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:15 -#: apps/treasury/views.py:184 +#: apps/treasury/views.py:177 msgid "This invoice is locked and can't be deleted." msgstr "Esta factura esta bloqueada y no puede ser suprimida." @@ -2529,36 +2571,36 @@ msgstr "Crear una nueva factura" msgid "Invoices list" msgstr "Lista de las facturas" -#: apps/treasury/views.py:112 apps/treasury/views.py:286 -#: apps/treasury/views.py:412 +#: apps/treasury/views.py:105 apps/treasury/views.py:275 +#: apps/treasury/views.py:401 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:122 +#: apps/treasury/views.py:115 msgid "Update an invoice" msgstr "Modificar una factura" -#: apps/treasury/views.py:247 +#: apps/treasury/views.py:240 msgid "Create a new remittance" msgstr "Crear un nuevo descuento" -#: apps/treasury/views.py:274 +#: apps/treasury/views.py:267 msgid "Remittances list" msgstr "Lista de los descuentos" -#: apps/treasury/views.py:337 +#: apps/treasury/views.py:326 msgid "Update a remittance" msgstr "Modificar un descuento" -#: apps/treasury/views.py:360 +#: apps/treasury/views.py:349 msgid "Attach a transaction to a remittance" msgstr "Unir una transacción con un descuento" -#: apps/treasury/views.py:404 +#: apps/treasury/views.py:393 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:449 +#: apps/treasury/views.py:438 msgid "Manage credits from the Société générale" msgstr "Gestionar los créditos de la Société Générale" @@ -2574,7 +2616,7 @@ msgstr "" "El usuario seleccionado no ha sido validado. Validar esta cuenta primero" #: apps/wei/forms/registration.py:59 apps/wei/models.py:126 -#: apps/wei/models.py:323 +#: apps/wei/models.py:326 msgid "bus" msgstr "bus" @@ -2612,7 +2654,7 @@ msgstr "Elegir los papeles que le interesa." msgid "This team doesn't belong to the given bus." msgstr "Este equipo no pertenece al bus dado." -#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35 +#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38 msgid "Choose a word:" msgstr "Elegir una palabra :" @@ -2699,40 +2741,48 @@ msgstr "No binari@" msgid "gender" msgstr "género" -#: apps/wei/models.py:213 apps/wei/templates/wei/weimembership_form.html:58 +#: apps/wei/models.py:212 +msgid "Unisex" +msgstr "Unisex" + +#: apps/wei/models.py:215 apps/wei/templates/wei/weimembership_form.html:58 msgid "clothing cut" msgstr "forma de ropa" -#: apps/wei/models.py:226 apps/wei/templates/wei/weimembership_form.html:61 +#: apps/wei/models.py:228 apps/wei/templates/wei/weimembership_form.html:61 msgid "clothing size" msgstr "medida de ropa" -#: apps/wei/models.py:232 apps/wei/templates/wei/attribute_bus_1A.html:28 +#: apps/wei/models.py:234 apps/wei/templates/wei/attribute_bus_1A.html:28 #: apps/wei/templates/wei/weimembership_form.html:67 msgid "health issues" msgstr "problemas de salud" -#: apps/wei/models.py:237 apps/wei/templates/wei/weimembership_form.html:70 +#: apps/wei/models.py:239 apps/wei/templates/wei/weimembership_form.html:70 msgid "emergency contact name" msgstr "nombre del contacto de emergencia" -#: apps/wei/models.py:242 apps/wei/templates/wei/weimembership_form.html:73 +#: apps/wei/models.py:240 +msgid "The emergency contact must not be a WEI participant" +msgstr "El contacto de emergencia no debe ser un participante de WEI" + +#: apps/wei/models.py:245 apps/wei/templates/wei/weimembership_form.html:73 msgid "emergency contact phone" msgstr "teléfono del contacto de emergencia" -#: apps/wei/models.py:247 apps/wei/templates/wei/weimembership_form.html:52 +#: apps/wei/models.py:250 apps/wei/templates/wei/weimembership_form.html:52 msgid "first year" msgstr "primer año" -#: apps/wei/models.py:248 +#: apps/wei/models.py:251 msgid "Tells if the user is new in the school." msgstr "Indica si el usuario es nuevo en la escuela." -#: apps/wei/models.py:253 +#: apps/wei/models.py:256 msgid "registration information" msgstr "informaciones sobre la afiliación" -#: apps/wei/models.py:254 +#: apps/wei/models.py:257 msgid "" "Information about the registration (buses for old members, survey for the " "new members), encoded in JSON" @@ -2740,27 +2790,27 @@ msgstr "" "Informaciones sobre la afiliacion (bus para miembros ancianos, cuestionario " "para los nuevos miembros), registrado en JSON" -#: apps/wei/models.py:312 +#: apps/wei/models.py:315 msgid "WEI User" msgstr "Participante WEI" -#: apps/wei/models.py:313 +#: apps/wei/models.py:316 msgid "WEI Users" msgstr "Participantes WEI" -#: apps/wei/models.py:333 +#: apps/wei/models.py:336 msgid "team" msgstr "equipo" -#: apps/wei/models.py:343 +#: apps/wei/models.py:346 msgid "WEI registration" msgstr "Apuntación al WEI" -#: apps/wei/models.py:347 +#: apps/wei/models.py:350 msgid "WEI membership" msgstr "Afiliación al WEI" -#: apps/wei/models.py:348 +#: apps/wei/models.py:351 msgid "WEI memberships" msgstr "Afiliaciones al WEI" @@ -2891,7 +2941,7 @@ 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:1028 -#: apps/wei/views.py:1083 apps/wei/views.py:1093 +#: apps/wei/views.py:1083 apps/wei/views.py:1130 msgid "Survey WEI" msgstr "Cuestionario WEI" @@ -3162,11 +3212,11 @@ msgstr "Usted no tiene derecho a suprimir esta inscripción WEI." msgid "Validate WEI registration" msgstr "Validar la inscripción WEI" -#: apps/wei/views.py:1186 +#: apps/wei/views.py:1223 msgid "Attribute buses to first year members" msgstr "Repartir los primer años en los buses" -#: apps/wei/views.py:1211 +#: apps/wei/views.py:1248 msgid "Attribute bus" msgstr "Repartir en un bus" @@ -3316,6 +3366,10 @@ msgstr "Contactarnos" msgid "Technical Support" msgstr "Soporte técnico" +#: note_kfet/templates/base.html:198 +msgid "FAQ (FR)" +msgstr "FAQ (FR)" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Buscar con atributo, como el nombre…" @@ -3537,6 +3591,26 @@ msgstr "" "pagar su afiliación. Tambien tiene que validar su correo electronico con el " "enlace que recibió." +#, fuzzy +#~| msgid "People having you as a friend" +#~ msgid "You already have that person as a friend" +#~ msgstr "Personas que tienen usted como amig@" + +#~ msgid "" +#~ "I declare that I opened or I will open soon a bank account in the Société " +#~ "générale with the BDE partnership." +#~ msgstr "" +#~ "Declaro que ya abrió una cuenta a la Société Générale en colaboración con " +#~ "el BDE." + +#~ msgid "" +#~ "Warning: this engages you to open your bank account. If you finally " +#~ "decides to don't open your account, you will have to pay the BDE " +#~ "membership." +#~ msgstr "" +#~ "Cuidado : esto le obliga abrir su cuenta bancaria. Si cambia de idea y no " +#~ "abre su cuenta bancaria, tendrá que pagar su afiliación al BDE." + #~ msgid "You are not a Kfet member, so you can't use your note account." #~ msgstr "Usted no es un miembro de la Kfet, no puede usar su cuenta note." diff --git a/locale/es/LC_MESSAGES/djangojs.po b/locale/es/LC_MESSAGES/djangojs.po index 50782bb8..e4ebb3e3 100644 --- a/locale/es/LC_MESSAGES/djangojs.po +++ b/locale/es/LC_MESSAGES/djangojs.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-15 23:21+0100\n" -"PO-Revision-Date: 2020-11-21 12:23+0100\n" +"POT-Creation-Date: 2022-10-07 09:07+0200\n" +"PO-Revision-Date: 2022-10-07 13:20+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" -"Last-Translator: elkmaennchen \n" -"Language-Team: \n" -"X-Generator: Poedit 2.3\n" +"X-Generator: Poedit 3.0.1\n" #: apps/member/static/member/js/alias.js:17 msgid "Alias successfully added" @@ -26,6 +26,18 @@ msgstr "Alias añadido con éxito" msgid "Alias successfully deleted" msgstr "Alias suprimido con éxito" +#: apps/member/static/member/js/trust.js:14 +msgid "You can't add yourself as a friend" +msgstr "No puede añadir asimismo como amig@" + +#: apps/member/static/member/js/trust.js:37 +msgid "Friendship successfully added" +msgstr "Amig@ añadido con éxito" + +#: apps/member/static/member/js/trust.js:53 +msgid "Friendship successfully deleted" +msgstr "Amig@ suprimido con éxito" + #: apps/note/static/note/js/consos.js:225 #, javascript-format msgid "" @@ -44,30 +56,29 @@ msgstr "" "Cuidado, la transacción de %s fue un éxito, pero la note %s está negativa." #: apps/note/static/note/js/consos.js:232 -#: apps/note/static/note/js/transfer.js:298 -#: apps/note/static/note/js/transfer.js:401 +#: apps/note/static/note/js/transfer.js:309 +#: apps/note/static/note/js/transfer.js:412 #, javascript-format msgid "Warning, the emitter note %s is no more a BDE member." msgstr "Cuidado, la note remitente %s no está más miembro del BDE." -#: apps/note/static/note/js/consos.js:253 +#: apps/note/static/note/js/consos.js:254 msgid "The transaction couldn't be validated because of insufficient balance." -msgstr "" -"La transacción no pudo ser validada por culpa de saldo demasiado bajo." +msgstr "La transacción no pudo ser validada por culpa de saldo demasiado bajo." -#: apps/note/static/note/js/transfer.js:238 +#: apps/note/static/note/js/transfer.js:249 msgid "This field is required and must contain a decimal positive number." msgstr "Este campo obligatorio requiere un número decimal positivo." -#: apps/note/static/note/js/transfer.js:245 +#: apps/note/static/note/js/transfer.js:256 msgid "The amount must stay under 21,474,836.47 €." msgstr "El monto no puede superar los 21 474 836,47 €." -#: apps/note/static/note/js/transfer.js:251 +#: apps/note/static/note/js/transfer.js:262 msgid "This field is required." msgstr "Este campo es obligatorio." -#: apps/note/static/note/js/transfer.js:277 +#: apps/note/static/note/js/transfer.js:288 #, javascript-format msgid "" "Warning: the transaction of %s from %s to %s was not made because it is the " @@ -76,12 +87,12 @@ msgstr "" "Cuidado : la transacción de %s de %s a %s no fue echa porque la fuente y el " "destino son iguales." -#: apps/note/static/note/js/transfer.js:301 +#: apps/note/static/note/js/transfer.js:312 #, javascript-format msgid "Warning, the destination note %s is no more a BDE member." msgstr "Cuidado, la note destino %s no está más miembro del BDE." -#: apps/note/static/note/js/transfer.js:307 +#: apps/note/static/note/js/transfer.js:318 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -90,7 +101,7 @@ msgstr "" "Cuidado, la transacción de %s de la note %s a la note %s fue un éxito, pero " "la note fuente %s está muy negativa." -#: apps/note/static/note/js/transfer.js:312 +#: apps/note/static/note/js/transfer.js:323 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -99,31 +110,31 @@ msgstr "" "Cuidado, la transacción de %s de la note %s a la note %s fue un éxito, pero " "la note fuente %s está negativa." -#: apps/note/static/note/js/transfer.js:318 +#: apps/note/static/note/js/transfer.js:329 #, javascript-format msgid "Transfer of %s from %s to %s succeed!" msgstr "¡ La transacción de %s de %s a %s fue un éxito !" -#: apps/note/static/note/js/transfer.js:325 -#: apps/note/static/note/js/transfer.js:346 -#: apps/note/static/note/js/transfer.js:353 +#: apps/note/static/note/js/transfer.js:336 +#: apps/note/static/note/js/transfer.js:357 +#: apps/note/static/note/js/transfer.js:364 #, javascript-format msgid "Transfer of %s from %s to %s failed: %s" msgstr "La transacción de %s de %s a %s fue un fracaso : %s" -#: apps/note/static/note/js/transfer.js:347 +#: apps/note/static/note/js/transfer.js:358 msgid "insufficient funds" msgstr "fundos insuficientes" -#: apps/note/static/note/js/transfer.js:400 +#: apps/note/static/note/js/transfer.js:411 msgid "Credit/debit succeed!" msgstr "¡ Crédito/débito tubo éxito !" -#: apps/note/static/note/js/transfer.js:407 +#: apps/note/static/note/js/transfer.js:418 #, javascript-format msgid "Credit/debit failed: %s" msgstr "Crédito/débito falló : %s" -#: note_kfet/static/js/base.js:366 +#: note_kfet/static/js/base.js:370 msgid "An error occured while (in)validating this transaction:" msgstr "Un error ocurrió durante la (in)validación de esta transacción :" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 65fd6062..36bfd028 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: 2022-04-10 22:34+0200\n" +"POT-Creation-Date: 2023-10-25 19:12+0200\n" "PO-Revision-Date: 2022-04-11 22:05+0200\n" -"Last-Translator: elkmaennchen \n" +"Last-Translator: bleizi \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" @@ -53,7 +53,7 @@ msgid "You can't invite more than 3 people to this activity." msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." #: apps/activity/models.py:28 apps/activity/models.py:63 -#: apps/member/models.py:199 +#: apps/member/models.py:204 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -114,8 +114,8 @@ msgstr "Lieu où l'activité est organisée, par exemple la Kfet." msgid "type" msgstr "type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307 -#: apps/note/models/notes.py:148 apps/treasury/models.py:285 +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:312 +#: apps/note/models/notes.py:148 apps/treasury/models.py:287 #: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" @@ -258,19 +258,19 @@ msgstr "Entré le " msgid "remove" msgstr "supprimer" -#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199 +#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:201 msgid "Type" msgstr "Type" -#: apps/activity/tables.py:84 apps/member/forms.py:186 -#: apps/registration/forms.py:91 apps/treasury/forms.py:131 +#: apps/activity/tables.py:84 apps/member/forms.py:193 +#: apps/registration/forms.py:92 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Nom de famille" -#: apps/activity/tables.py:86 apps/member/forms.py:191 +#: apps/activity/tables.py:86 apps/member/forms.py:198 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:96 apps/treasury/forms.py:133 +#: apps/registration/forms.py:97 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Prénom" @@ -388,7 +388,7 @@ msgid "validate" msgstr "valider" #: apps/activity/templates/activity/includes/activity_info.html:71 -#: apps/logs/models.py:64 apps/note/tables.py:220 +#: apps/logs/models.py:64 apps/note/tables.py:260 msgid "edit" msgstr "modifier" @@ -466,9 +466,9 @@ msgstr "nouvelles données" msgid "create" msgstr "créer" -#: apps/logs/models.py:65 apps/note/tables.py:166 apps/note/tables.py:190 -#: apps/note/tables.py:237 apps/permission/models.py:127 -#: apps/treasury/tables.py:38 apps/wei/tables.py:74 +#: apps/logs/models.py:65 apps/note/tables.py:230 apps/note/tables.py:277 +#: apps/permission/models.py:127 apps/treasury/tables.py:38 +#: apps/wei/tables.py:74 msgid "delete" msgstr "supprimer" @@ -497,21 +497,21 @@ msgstr "journaux de modifications" msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" msgstr "Changelog de type « {action} » pour le modèle {model} à {timestamp}" -#: apps/member/admin.py:50 apps/member/models.py:226 +#: apps/member/admin.py:50 apps/member/models.py:231 #: apps/member/templates/member/includes/club_info.html:34 msgid "membership fee (paid students)" msgstr "cotisation pour adhérer (normalien élève)" -#: apps/member/admin.py:51 apps/member/models.py:231 +#: apps/member/admin.py:51 apps/member/models.py:236 #: apps/member/templates/member/includes/club_info.html:37 msgid "membership fee (unpaid students)" msgstr "cotisation pour adhérer (normalien étudiant)" -#: apps/member/admin.py:65 apps/member/models.py:319 +#: apps/member/admin.py:65 apps/member/models.py:324 msgid "roles" msgstr "rôles" -#: apps/member/admin.py:66 apps/member/models.py:333 +#: apps/member/admin.py:66 apps/member/models.py:338 msgid "fee" msgstr "cotisation" @@ -531,65 +531,80 @@ msgstr "Fréquence des rapports (en jours)" msgid "Last report date" msgstr "Date de dernier rapport" +#: apps/member/forms.py:52 +msgid "" +"Anti-VSS (Violences Sexistes et Sexuelles) charter read and approved" +msgstr "Charte Anti-VSS (Violences Sexistes et Sexuelles) lue et approuvée" + #: apps/member/forms.py:53 +msgid "" +"Tick after having read and accepted the anti-VSS charter " +"available here in pdf" +msgstr "" +"Cochez après avoir lu la chartre anti-VSS disponible en pdf ici" + +#: apps/member/forms.py:60 msgid "You can't register to the note if you come from the future." msgstr "Vous ne pouvez pas vous inscrire à la note si vous venez du futur." -#: apps/member/forms.py:79 +#: apps/member/forms.py:86 msgid "select an image" msgstr "choisissez une image" -#: apps/member/forms.py:80 +#: apps/member/forms.py:87 msgid "Maximal size: 2MB" msgstr "Taille maximale : 2 Mo" -#: apps/member/forms.py:105 +#: apps/member/forms.py:112 msgid "This image cannot be loaded." msgstr "Cette image ne peut pas être chargée." -#: apps/member/forms.py:141 apps/member/views.py:103 -#: apps/registration/forms.py:33 apps/registration/views.py:262 +#: apps/member/forms.py:148 apps/member/views.py:102 +#: apps/registration/forms.py:34 apps/registration/views.py:266 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." -#: apps/member/forms.py:165 apps/registration/forms.py:71 +#: apps/member/forms.py:172 msgid "Inscription paid by Société Générale" msgstr "Inscription payée par la Société générale" -#: apps/member/forms.py:167 apps/registration/forms.py:73 +#: apps/member/forms.py:174 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:172 apps/registration/forms.py:78 +#: apps/member/forms.py:179 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Type de rechargement" -#: apps/member/forms.py:173 apps/registration/forms.py:79 +#: apps/member/forms.py:180 apps/registration/forms.py:80 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "Pas de rechargement" -#: apps/member/forms.py:175 +#: apps/member/forms.py:182 msgid "You can credit the note of the user." msgstr "Vous pouvez créditer la note de l'utilisateur avant l'adhésion." -#: apps/member/forms.py:179 apps/registration/forms.py:84 +#: apps/member/forms.py:186 apps/registration/forms.py:85 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Montant à créditer" -#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:101 apps/treasury/forms.py:135 +#: apps/member/forms.py:203 apps/note/templates/note/transaction_form.html:144 +#: apps/registration/forms.py:102 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Banque" -#: apps/member/forms.py:223 +#: apps/member/forms.py:230 msgid "User" msgstr "Utilisateur" -#: apps/member/forms.py:237 +#: apps/member/forms.py:244 msgid "Roles" msgstr "Rôles" @@ -774,15 +789,19 @@ msgstr "adresse email confirmée" msgid "registration valid" msgstr "inscription valide" -#: apps/member/models.py:162 apps/member/models.py:163 +#: apps/member/models.py:138 +msgid "VSS charter read" +msgstr "Charte VSS lue" + +#: apps/member/models.py:167 apps/member/models.py:168 msgid "user profile" msgstr "profil utilisateur" -#: apps/member/models.py:173 +#: apps/member/models.py:178 msgid "Activate your Note Kfet account" msgstr "Activez votre compte Note Kfet" -#: apps/member/models.py:204 +#: apps/member/models.py:209 #: apps/member/templates/member/includes/club_info.html:55 #: apps/member/templates/member/includes/profile_info.html:40 #: apps/registration/templates/registration/future_profile_detail.html:22 @@ -791,88 +810,88 @@ msgstr "Activez votre compte Note Kfet" msgid "email" msgstr "courriel" -#: apps/member/models.py:211 +#: apps/member/models.py:216 msgid "parent club" msgstr "club parent" -#: apps/member/models.py:220 +#: apps/member/models.py:225 msgid "require memberships" msgstr "nécessite des adhésions" -#: apps/member/models.py:221 +#: apps/member/models.py:226 msgid "Uncheck if this club don't require memberships." msgstr "Décochez si ce club n'utilise pas d'adhésions." -#: apps/member/models.py:237 +#: apps/member/models.py:242 #: apps/member/templates/member/includes/club_info.html:26 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:238 +#: apps/member/models.py:243 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "La durée maximale (en jours) d'une adhésion (NULL = infinie)." -#: apps/member/models.py:245 +#: apps/member/models.py:250 #: apps/member/templates/member/includes/club_info.html:16 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:246 +#: apps/member/models.py:251 msgid "Date from which the members can renew their membership." msgstr "" "Date à partir de laquelle les adhérents peuvent renouveler leur adhésion." -#: apps/member/models.py:252 +#: apps/member/models.py:257 #: apps/member/templates/member/includes/club_info.html:21 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:253 +#: apps/member/models.py:258 msgid "Maximal date of a membership, after which members must renew it." msgstr "" "Date maximale d'une fin d'adhésion, après laquelle les adhérents doivent la " "renouveler." -#: apps/member/models.py:288 apps/member/models.py:313 +#: apps/member/models.py:293 apps/member/models.py:318 #: apps/note/models/notes.py:176 msgid "club" msgstr "club" -#: apps/member/models.py:289 +#: apps/member/models.py:294 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:324 +#: apps/member/models.py:329 msgid "membership starts on" msgstr "l'adhésion commence le" -#: apps/member/models.py:328 +#: apps/member/models.py:333 msgid "membership ends on" msgstr "l'adhésion finit le" -#: apps/member/models.py:430 +#: apps/member/models.py:435 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "Le rôle {role} ne s'applique pas au club {club}." -#: apps/member/models.py:439 apps/member/views.py:712 +#: apps/member/models.py:444 apps/member/views.py:712 msgid "User is already a member of the club" msgstr "L'utilisateur est déjà membre du club" -#: apps/member/models.py:451 apps/member/views.py:721 +#: apps/member/models.py:456 apps/member/views.py:721 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" -#: apps/member/models.py:504 +#: apps/member/models.py:509 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Adhésion de {user} pour le club {club}" -#: apps/member/models.py:507 apps/note/models/transactions.py:389 +#: apps/member/models.py:512 apps/note/models/transactions.py:389 msgid "membership" msgstr "adhésion" -#: apps/member/models.py:508 +#: apps/member/models.py:513 msgid "memberships" msgstr "adhésions" @@ -924,7 +943,7 @@ msgid "Account #" msgstr "Compte n°" #: apps/member/templates/member/base.html:48 -#: apps/member/templates/member/base.html:62 apps/member/views.py:60 +#: apps/member/templates/member/base.html:62 apps/member/views.py:59 #: apps/registration/templates/registration/future_profile_detail.html:48 #: apps/wei/templates/wei/weimembership_form.html:117 msgid "Update Profile" @@ -1158,9 +1177,9 @@ msgstr "Cliquez ici pour renvoyer un lien de validation." msgid "View my memberships" msgstr "Voir mes adhésions" -#: apps/member/templates/member/profile_trust.html:10 apps/member/views.py:254 -msgid "Note friendships" -msgstr "Amitiés note" +#: apps/member/templates/member/profile_trust.html:10 +msgid "Add friends" +msgstr "Ajouter des amis" #: apps/member/templates/member/profile_trust.html:28 msgid "" @@ -1175,6 +1194,10 @@ msgstr "" "ami⋅es via note. En effet, une personne peut effectuer tous les transferts " "sans posséder de droits supplémentaires." +#: apps/member/templates/member/profile_trust.html:39 +msgid "People having you as a friend" +msgstr "Personnes vous ayant ajouté" + #: apps/member/templates/member/profile_update.html:18 msgid "Save Changes" msgstr "Sauvegarder les changements" @@ -1183,18 +1206,22 @@ msgstr "Sauvegarder les changements" msgid "Registrations" msgstr "Inscriptions" -#: apps/member/views.py:73 apps/registration/forms.py:23 +#: apps/member/views.py:72 apps/registration/forms.py:24 msgid "This address must be valid." msgstr "Cette adresse doit être valide." -#: apps/member/views.py:140 +#: apps/member/views.py:139 msgid "Profile detail" msgstr "Détails de l'utilisateur" -#: apps/member/views.py:206 +#: apps/member/views.py:205 msgid "Search user" msgstr "Chercher un utilisateur" +#: apps/member/views.py:253 +msgid "Note friendships" +msgstr "Amitiés note" + #: apps/member/views.py:308 msgid "Update note picture" msgstr "Modifier la photo de la note" @@ -1239,29 +1266,33 @@ msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}." msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." -#: apps/member/views.py:876 +#: apps/member/views.py:880 msgid "Manage roles of an user in the club" msgstr "Gérer les rôles d'un utilisateur dans le club" -#: apps/member/views.py:901 +#: apps/member/views.py:905 msgid "Members of the club" msgstr "Membres du club" -#: apps/note/admin.py:129 apps/note/models/transactions.py:109 +#: apps/note/admin.py:139 apps/note/models/transactions.py:109 msgid "source" msgstr "source" -#: apps/note/admin.py:137 apps/note/admin.py:205 +#: apps/note/admin.py:147 apps/note/admin.py:215 #: apps/note/models/transactions.py:56 apps/note/models/transactions.py:122 msgid "destination" msgstr "destination" -#: apps/note/admin.py:210 apps/note/models/transactions.py:60 +#: apps/note/admin.py:220 apps/note/models/transactions.py:60 #: apps/note/models/transactions.py:140 msgid "amount" msgstr "montant" -#: apps/note/api/serializers.py:199 apps/note/api/serializers.py:205 +#: apps/note/api/serializers.py:92 +msgid "This friendship already exists" +msgstr "Cette amitié existe déjà" + +#: apps/note/api/serializers.py:198 apps/note/api/serializers.py:204 #: apps/note/models/transactions.py:228 msgid "" "The transaction can't be saved since the source note or the destination note " @@ -1563,7 +1594,7 @@ msgstr "Transactions de crédit/retrait" msgid "membership transaction" msgstr "transaction d'adhésion" -#: apps/note/models/transactions.py:385 apps/treasury/models.py:292 +#: apps/note/models/transactions.py:385 apps/treasury/models.py:294 msgid "membership transactions" msgstr "transactions d'adhésion" @@ -1579,8 +1610,8 @@ msgstr "Cliquez pour valider" msgid "No reason specified" msgstr "Pas de motif spécifié" -#: apps/note/tables.py:173 apps/note/tables.py:194 apps/note/tables.py:239 -#: apps/treasury/tables.py:39 +#: apps/note/tables.py:166 apps/note/tables.py:173 apps/note/tables.py:234 +#: apps/note/tables.py:279 apps/treasury/tables.py:39 #: apps/treasury/templates/treasury/invoice_confirm_delete.html:30 #: apps/treasury/templates/treasury/sogecredit_detail.html:65 #: apps/wei/tables.py:75 apps/wei/tables.py:118 @@ -1591,7 +1622,15 @@ msgstr "Pas de motif spécifié" msgid "Delete" msgstr "Supprimer" -#: apps/note/tables.py:222 apps/note/templates/note/conso_form.html:132 +#: apps/note/tables.py:191 +msgid "Trust back" +msgstr "Ajouter en ami" + +#: apps/note/tables.py:211 +msgid "Add back" +msgstr "Ajouter" + +#: apps/note/tables.py:262 apps/note/templates/note/conso_form.html:151 #: apps/wei/tables.py:49 apps/wei/tables.py:50 #: apps/wei/templates/wei/base.html:89 #: apps/wei/templates/wei/bus_detail.html:20 @@ -1601,7 +1640,7 @@ msgstr "Supprimer" msgid "Edit" msgstr "Éditer" -#: apps/note/tables.py:226 apps/note/tables.py:253 +#: apps/note/tables.py:266 apps/note/tables.py:293 msgid "Hide/Show" msgstr "Afficher/Masquer" @@ -1632,15 +1671,23 @@ msgstr "Consommer !" msgid "Highlighted buttons" msgstr "Boutons mis en avant" -#: apps/note/templates/note/conso_form.html:138 +#: apps/note/templates/note/conso_form.html:108 +msgid "Search" +msgstr "Recherche" + +#: apps/note/templates/note/conso_form.html:133 +msgid "Search button..." +msgstr "Chercher un bouton..." + +#: apps/note/templates/note/conso_form.html:157 msgid "Single consumptions" msgstr "Consommations simples" -#: apps/note/templates/note/conso_form.html:143 +#: apps/note/templates/note/conso_form.html:162 msgid "Double consumptions" msgstr "Consommations doubles" -#: apps/note/templates/note/conso_form.html:154 +#: apps/note/templates/note/conso_form.html:173 #: apps/note/templates/note/transaction_form.html:163 msgid "Recent transactions history" msgstr "Historique des transactions récentes" @@ -1682,7 +1729,7 @@ msgid "Amount" msgstr "Montant" #: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:54 +#: apps/treasury/models.py:56 msgid "Name" msgstr "Nom" @@ -1770,7 +1817,7 @@ msgstr "Consommations" msgid "You can't see any button." msgstr "Vous ne pouvez pas voir le moindre bouton." -#: apps/note/views.py:200 +#: apps/note/views.py:208 msgid "Search transactions" msgstr "Rechercher des transactions" @@ -1851,7 +1898,7 @@ msgstr "" msgid "for club" msgstr "s'applique au club" -#: apps/permission/models.py:350 apps/permission/models.py:351 +#: apps/permission/models.py:351 apps/permission/models.py:352 msgid "role permissions" msgstr "permissions par rôles" @@ -1972,31 +2019,15 @@ msgstr "Tous les droits" msgid "registration" msgstr "inscription" -#: apps/registration/forms.py:39 +#: apps/registration/forms.py:40 msgid "This email address is already used." msgstr "Cet email est déjà pris." -#: apps/registration/forms.py:49 -msgid "" -"I declare that I opened or I will open soon a bank account in the Société " -"générale with the BDE partnership." -msgstr "" -"Je déclare avoir ouvert ou ouvrir prochainement un compte à la société " -"générale avec le partenariat du BDE." - -#: apps/registration/forms.py:51 -msgid "" -"Warning: this engages you to open your bank account. If you finally decides " -"to don't open your account, you will have to pay the BDE membership." -msgstr "" -"Attention : cocher cette case vous engage à ouvrir votre compte. Si vous " -"décidez de ne pas le faire, vous devrez payer l'adhésion au BDE." - -#: apps/registration/forms.py:59 +#: apps/registration/forms.py:60 msgid "Register to the WEI" msgstr "S'inscrire au WEI" -#: apps/registration/forms.py:61 +#: apps/registration/forms.py:62 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." @@ -2005,14 +2036,18 @@ msgstr "" "pourrez toujours vous inscrire plus tard, après avoir validé votre compte à " "la Kfet." -#: apps/registration/forms.py:106 +#: apps/registration/forms.py:107 msgid "Join BDE Club" msgstr "Adhérer au club BDE" -#: apps/registration/forms.py:113 +#: apps/registration/forms.py:114 msgid "Join Kfet Club" msgstr "Adhérer au club Kfet" +#: apps/registration/forms.py:123 +msgid "Join BDA Club" +msgstr "Adhérer au club BDA" + #: apps/registration/templates/registration/email_validation_complete.html:15 msgid "Your email have successfully been validated." msgstr "Votre adresse e-mail a bien été validée." @@ -2061,12 +2096,12 @@ msgstr "Supprimer l'inscription" msgid "Validate account" msgstr "Valider le compte" -#: apps/registration/templates/registration/future_profile_detail.html:62 +#: apps/registration/templates/registration/future_profile_detail.html:63 msgid "" "The user declared that he/she opened a bank account in the Société générale." msgstr "L'utilisateur a déclaré avoir ouvert un compte à la société générale." -#: apps/registration/templates/registration/future_profile_detail.html:71 +#: apps/registration/templates/registration/future_profile_detail.html:73 #: apps/wei/templates/wei/weimembership_form.html:127 #: apps/wei/templates/wei/weimembership_form.html:186 msgid "Validate registration" @@ -2116,54 +2151,54 @@ msgstr "Merci" msgid "The Note Kfet team." msgstr "L'équipe de la Note Kfet." -#: apps/registration/views.py:40 +#: apps/registration/views.py:41 msgid "Register new user" msgstr "Enregistrer un nouvel utilisateur" -#: apps/registration/views.py:98 +#: apps/registration/views.py:99 msgid "Email validation" msgstr "Validation de l'adresse mail" -#: apps/registration/views.py:100 +#: apps/registration/views.py:101 msgid "Validate email" msgstr "Valider l'adresse e-mail" -#: apps/registration/views.py:144 +#: apps/registration/views.py:145 msgid "Email validation unsuccessful" msgstr "La validation de l'adresse mail a échoué" -#: apps/registration/views.py:155 +#: apps/registration/views.py:156 msgid "Email validation email sent" msgstr "L'email de vérification de l'adresse email a bien été envoyé" -#: apps/registration/views.py:163 +#: apps/registration/views.py:164 msgid "Resend email validation link" msgstr "Renvoyer le lien de validation" -#: apps/registration/views.py:181 +#: apps/registration/views.py:182 msgid "Pre-registered users list" msgstr "Liste des utilisateurs en attente d'inscription" -#: apps/registration/views.py:205 +#: apps/registration/views.py:206 msgid "Unregistered users" msgstr "Utilisateurs en attente d'inscription" -#: apps/registration/views.py:218 +#: apps/registration/views.py:219 msgid "Registration detail" msgstr "Détails de l'inscription" -#: apps/registration/views.py:282 +#: apps/registration/views.py:293 msgid "You must join the BDE." msgstr "Vous devez adhérer au BDE." -#: apps/registration/views.py:306 +#: apps/registration/views.py:323 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:387 +#: apps/registration/views.py:417 msgid "Invalidate pre-registration" msgstr "Invalider l'inscription" @@ -2171,7 +2206,7 @@ msgstr "Invalider l'inscription" msgid "Treasury" msgstr "Trésorerie" -#: apps/treasury/forms.py:26 apps/treasury/models.py:93 +#: apps/treasury/forms.py:26 apps/treasury/models.py:95 #: apps/treasury/templates/treasury/invoice_form.html:22 msgid "This invoice is locked and can no longer be edited." msgstr "Cette facture est verrouillée et ne peut plus être éditée." @@ -2184,7 +2219,7 @@ msgstr "La remise est déjà fermée." msgid "You can't change the type of the remittance." msgstr "Vous ne pouvez pas changer le type de la remise." -#: apps/treasury/forms.py:125 apps/treasury/models.py:267 +#: apps/treasury/forms.py:125 apps/treasury/models.py:269 #: 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 @@ -2200,116 +2235,116 @@ msgstr "Pas de remise associée" msgid "Invoice identifier" msgstr "Numéro de facture" -#: apps/treasury/models.py:40 +#: apps/treasury/models.py:42 msgid "BDE" msgstr "BDE" -#: apps/treasury/models.py:45 +#: apps/treasury/models.py:47 msgid "Object" msgstr "Objet" -#: apps/treasury/models.py:49 +#: apps/treasury/models.py:51 msgid "Description" msgstr "Description" -#: apps/treasury/models.py:58 +#: apps/treasury/models.py:60 msgid "Address" msgstr "Adresse" -#: apps/treasury/models.py:63 apps/treasury/models.py:193 +#: apps/treasury/models.py:65 apps/treasury/models.py:195 msgid "Date" msgstr "Date" -#: apps/treasury/models.py:67 +#: apps/treasury/models.py:69 msgid "Acquitted" msgstr "Acquittée" -#: apps/treasury/models.py:72 +#: apps/treasury/models.py:74 msgid "Locked" msgstr "Verrouillée" -#: apps/treasury/models.py:73 +#: apps/treasury/models.py:75 msgid "An invoice can't be edited when it is locked." msgstr "Une facture ne peut plus être modifiée si elle est verrouillée." -#: apps/treasury/models.py:79 +#: apps/treasury/models.py:81 msgid "tex source" msgstr "fichier TeX source" -#: apps/treasury/models.py:113 apps/treasury/models.py:129 +#: apps/treasury/models.py:115 apps/treasury/models.py:131 msgid "invoice" msgstr "facture" -#: apps/treasury/models.py:114 +#: apps/treasury/models.py:116 msgid "invoices" msgstr "factures" -#: apps/treasury/models.py:117 +#: apps/treasury/models.py:119 #, python-brace-format msgid "Invoice #{id}" msgstr "Facture n°{id}" -#: apps/treasury/models.py:134 +#: apps/treasury/models.py:136 msgid "Designation" msgstr "Désignation" -#: apps/treasury/models.py:140 +#: apps/treasury/models.py:142 msgid "Quantity" msgstr "Quantité" -#: apps/treasury/models.py:145 +#: apps/treasury/models.py:147 msgid "Unit price" msgstr "Prix unitaire" -#: apps/treasury/models.py:161 +#: apps/treasury/models.py:163 msgid "product" msgstr "produit" -#: apps/treasury/models.py:162 +#: apps/treasury/models.py:164 msgid "products" msgstr "produits" -#: apps/treasury/models.py:182 +#: apps/treasury/models.py:184 msgid "remittance type" msgstr "type de remise" -#: apps/treasury/models.py:183 +#: apps/treasury/models.py:185 msgid "remittance types" msgstr "types de remises" -#: apps/treasury/models.py:204 +#: apps/treasury/models.py:206 msgid "Comment" msgstr "Commentaire" -#: apps/treasury/models.py:209 +#: apps/treasury/models.py:211 msgid "Closed" msgstr "Fermée" -#: apps/treasury/models.py:213 +#: apps/treasury/models.py:215 msgid "remittance" msgstr "remise" -#: apps/treasury/models.py:214 +#: apps/treasury/models.py:216 msgid "remittances" msgstr "remises" -#: apps/treasury/models.py:247 +#: apps/treasury/models.py:249 msgid "Remittance #{:d}: {}" msgstr "Remise n°{:d} : {}" -#: apps/treasury/models.py:271 +#: apps/treasury/models.py:273 msgid "special transaction proxy" msgstr "proxy de transaction spéciale" -#: apps/treasury/models.py:272 +#: apps/treasury/models.py:274 msgid "special transaction proxies" msgstr "proxys de transactions spéciales" -#: apps/treasury/models.py:298 +#: apps/treasury/models.py:300 msgid "credit transaction" msgstr "transaction de crédit" -#: apps/treasury/models.py:430 +#: apps/treasury/models.py:432 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." @@ -2317,16 +2352,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:451 +#: apps/treasury/models.py:452 #: 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:452 +#: apps/treasury/models.py:453 msgid "Credits from the Société générale" msgstr "Crédits de la Société générale" -#: apps/treasury/models.py:455 +#: apps/treasury/models.py:456 #, python-brace-format msgid "Soge credit for {user}" msgstr "Crédit de la société générale pour l'utilisateur {user}" @@ -2355,12 +2390,12 @@ msgid "Yes" msgstr "Oui" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:10 -#: apps/treasury/views.py:180 +#: apps/treasury/views.py:173 msgid "Delete invoice" msgstr "Supprimer la facture" #: apps/treasury/templates/treasury/invoice_confirm_delete.html:15 -#: apps/treasury/views.py:184 +#: apps/treasury/views.py:177 msgid "This invoice is locked and can't be deleted." msgstr "Cette facture est verrouillée et ne peut pas être supprimée." @@ -2540,36 +2575,36 @@ msgstr "Créer une nouvelle facture" msgid "Invoices list" msgstr "Liste des factures" -#: apps/treasury/views.py:112 apps/treasury/views.py:286 -#: apps/treasury/views.py:412 +#: apps/treasury/views.py:105 apps/treasury/views.py:275 +#: apps/treasury/views.py:401 msgid "You are not able to see the treasury interface." msgstr "Vous n'êtes pas autorisé à voir l'interface de trésorerie." -#: apps/treasury/views.py:122 +#: apps/treasury/views.py:115 msgid "Update an invoice" msgstr "Modifier la facture" -#: apps/treasury/views.py:247 +#: apps/treasury/views.py:240 msgid "Create a new remittance" msgstr "Créer une nouvelle remise" -#: apps/treasury/views.py:274 +#: apps/treasury/views.py:267 msgid "Remittances list" msgstr "Liste des remises" -#: apps/treasury/views.py:337 +#: apps/treasury/views.py:326 msgid "Update a remittance" msgstr "Modifier la remise" -#: apps/treasury/views.py:360 +#: apps/treasury/views.py:349 msgid "Attach a transaction to a remittance" msgstr "Joindre une transaction à une remise" -#: apps/treasury/views.py:404 +#: apps/treasury/views.py:393 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:449 +#: apps/treasury/views.py:438 msgid "Manage credits from the Société générale" msgstr "Gérer les crédits de la Société générale" @@ -2586,7 +2621,7 @@ msgstr "" "compte" #: apps/wei/forms/registration.py:59 apps/wei/models.py:126 -#: apps/wei/models.py:323 +#: apps/wei/models.py:326 msgid "bus" msgstr "bus" @@ -2624,7 +2659,7 @@ msgstr "Sélectionnez les rôles qui vous intéressent." msgid "This team doesn't belong to the given bus." msgstr "Cette équipe n'appartient pas à ce bus." -#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35 +#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38 msgid "Choose a word:" msgstr "Choisissez un mot :" @@ -2711,40 +2746,50 @@ msgstr "Non-binaire" msgid "gender" msgstr "genre" -#: apps/wei/models.py:213 apps/wei/templates/wei/weimembership_form.html:58 +#: apps/wei/models.py:212 +msgid "Unisex" +msgstr "Unisexe" + +#: apps/wei/models.py:215 apps/wei/templates/wei/weimembership_form.html:58 msgid "clothing cut" msgstr "coupe de vêtement" -#: apps/wei/models.py:226 apps/wei/templates/wei/weimembership_form.html:61 +#: apps/wei/models.py:228 apps/wei/templates/wei/weimembership_form.html:61 msgid "clothing size" msgstr "taille de vêtement" -#: apps/wei/models.py:232 apps/wei/templates/wei/attribute_bus_1A.html:28 +#: apps/wei/models.py:234 apps/wei/templates/wei/attribute_bus_1A.html:28 #: apps/wei/templates/wei/weimembership_form.html:67 msgid "health issues" msgstr "problèmes de santé" -#: apps/wei/models.py:237 apps/wei/templates/wei/weimembership_form.html:70 +#: apps/wei/models.py:239 apps/wei/templates/wei/weimembership_form.html:70 msgid "emergency contact name" msgstr "nom du contact en cas d'urgence" -#: apps/wei/models.py:242 apps/wei/templates/wei/weimembership_form.html:73 +#: apps/wei/models.py:240 +msgid "The emergency contact must not be a WEI participant" +msgstr "" +"Le contact en cas d'urgence ne doit pas être une personne qui participe au " +"WEI" + +#: apps/wei/models.py:245 apps/wei/templates/wei/weimembership_form.html:73 msgid "emergency contact phone" msgstr "téléphone du contact en cas d'urgence" -#: apps/wei/models.py:247 apps/wei/templates/wei/weimembership_form.html:52 +#: apps/wei/models.py:250 apps/wei/templates/wei/weimembership_form.html:52 msgid "first year" msgstr "première année" -#: apps/wei/models.py:248 +#: apps/wei/models.py:251 msgid "Tells if the user is new in the school." msgstr "Indique si l'utilisateur est nouveau dans l'école." -#: apps/wei/models.py:253 +#: apps/wei/models.py:256 msgid "registration information" msgstr "informations sur l'inscription" -#: apps/wei/models.py:254 +#: apps/wei/models.py:257 msgid "" "Information about the registration (buses for old members, survey for the " "new members), encoded in JSON" @@ -2752,27 +2797,27 @@ msgstr "" "Informations sur l'inscription (bus pour les 2A+, questionnaire pour les " "1A), encodées en JSON" -#: apps/wei/models.py:312 +#: apps/wei/models.py:315 msgid "WEI User" msgstr "Participant au WEI" -#: apps/wei/models.py:313 +#: apps/wei/models.py:316 msgid "WEI Users" msgstr "Participants au WEI" -#: apps/wei/models.py:333 +#: apps/wei/models.py:336 msgid "team" msgstr "équipe" -#: apps/wei/models.py:343 +#: apps/wei/models.py:346 msgid "WEI registration" msgstr "Inscription au WEI" -#: apps/wei/models.py:347 +#: apps/wei/models.py:350 msgid "WEI membership" msgstr "Adhésion au WEI" -#: apps/wei/models.py:348 +#: apps/wei/models.py:351 msgid "WEI memberships" msgstr "Adhésions au WEI" @@ -2903,7 +2948,7 @@ msgstr "Télécharger au format 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:1028 -#: apps/wei/views.py:1083 apps/wei/views.py:1093 +#: apps/wei/views.py:1083 apps/wei/views.py:1130 msgid "Survey WEI" msgstr "Questionnaire WEI" @@ -3177,11 +3222,11 @@ msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI." msgid "Validate WEI registration" msgstr "Valider l'inscription WEI" -#: apps/wei/views.py:1186 +#: apps/wei/views.py:1223 msgid "Attribute buses to first year members" msgstr "Répartir les 1A dans les bus" -#: apps/wei/views.py:1211 +#: apps/wei/views.py:1248 msgid "Attribute bus" msgstr "Attribuer un bus" @@ -3335,6 +3380,10 @@ msgstr "Nous contacter" msgid "Technical Support" msgstr "Support technique" +#: note_kfet/templates/base.html:198 +msgid "FAQ (FR)" +msgstr "FAQ (FR)" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Chercher par un attribut tel que le nom …" @@ -3562,3 +3611,23 @@ 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." + +#, fuzzy +#~| msgid "People having you as a friend" +#~ msgid "You already have that person as a friend" +#~ msgstr "Personnes vous ayant ajouté" + +#~ msgid "" +#~ "I declare that I opened or I will open soon a bank account in the Société " +#~ "générale with the BDE partnership." +#~ msgstr "" +#~ "Je déclare avoir ouvert ou ouvrir prochainement un compte à la société " +#~ "générale avec le partenariat du BDE." + +#~ msgid "" +#~ "Warning: this engages you to open your bank account. If you finally " +#~ "decides to don't open your account, you will have to pay the BDE " +#~ "membership." +#~ msgstr "" +#~ "Attention : cocher cette case vous engage à ouvrir votre compte. Si vous " +#~ "décidez de ne pas le faire, vous devrez payer l'adhésion au BDE." diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index 7d5fd8ce..93be9947 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -3,12 +3,11 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-15 23:21+0100\n" +"POT-Creation-Date: 2022-10-07 09:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,6 +25,18 @@ msgstr "Alias ajouté avec succès" msgid "Alias successfully deleted" msgstr "Alias supprimé avec succès" +#: apps/member/static/member/js/trust.js:14 +msgid "You can't add yourself as a friend" +msgstr "Vous ne pouvez pas vous ajouter vous-même en ami" + +#: apps/member/static/member/js/trust.js:37 +msgid "Friendship successfully added" +msgstr "Amitié ajoutée avec succès" + +#: apps/member/static/member/js/trust.js:53 +msgid "Friendship successfully deleted" +msgstr "Amitié supprimée avec succès" + #: apps/note/static/note/js/consos.js:225 #, javascript-format msgid "" @@ -45,31 +56,31 @@ msgstr "" "la note émettrice %s est en négatif." #: apps/note/static/note/js/consos.js:232 -#: apps/note/static/note/js/transfer.js:298 -#: apps/note/static/note/js/transfer.js:401 +#: apps/note/static/note/js/transfer.js:309 +#: apps/note/static/note/js/transfer.js:412 #, javascript-format msgid "Warning, the emitter note %s is no more a BDE member." msgstr "Attention, la note émettrice %s n'est plus adhérente." -#: apps/note/static/note/js/consos.js:253 +#: apps/note/static/note/js/consos.js:254 msgid "The transaction couldn't be validated because of insufficient balance." msgstr "" "La transaction n'a pas pu être validée pour cause de solde insuffisant." -#: apps/note/static/note/js/transfer.js:238 +#: apps/note/static/note/js/transfer.js:249 msgid "This field is required and must contain a decimal positive number." msgstr "" "Ce champ est requis et doit comporter un nombre décimal strictement positif." -#: apps/note/static/note/js/transfer.js:245 +#: apps/note/static/note/js/transfer.js:256 msgid "The amount must stay under 21,474,836.47 €." msgstr "Le montant ne doit pas excéder 21 474 836.47 €." -#: apps/note/static/note/js/transfer.js:251 +#: apps/note/static/note/js/transfer.js:262 msgid "This field is required." msgstr "Ce champ est requis." -#: apps/note/static/note/js/transfer.js:277 +#: apps/note/static/note/js/transfer.js:288 #, javascript-format msgid "" "Warning: the transaction of %s from %s to %s was not made because it is the " @@ -78,12 +89,12 @@ msgstr "" "Attention : la transaction de %s de la note %s vers la note %s n'a pas été " "faite car il s'agit de la même note au départ et à l'arrivée." -#: apps/note/static/note/js/transfer.js:301 +#: apps/note/static/note/js/transfer.js:312 #, javascript-format msgid "Warning, the destination note %s is no more a BDE member." msgstr "Attention, la note de destination %s n'est plus adhérente." -#: apps/note/static/note/js/transfer.js:307 +#: apps/note/static/note/js/transfer.js:318 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -92,7 +103,7 @@ msgstr "" "Attention, La transaction de %s depuis la note %s vers la note %s a été " "réalisée avec succès, mais la note émettrice %s est en négatif sévère." -#: apps/note/static/note/js/transfer.js:312 +#: apps/note/static/note/js/transfer.js:323 #, javascript-format msgid "" "Warning, the transaction of %s from the note %s to the note %s succeed, but " @@ -101,33 +112,33 @@ msgstr "" "Attention, La transaction de %s depuis la note %s vers la note %s a été " "réalisée avec succès, mais la note émettrice %s est en négatif." -#: apps/note/static/note/js/transfer.js:318 +#: apps/note/static/note/js/transfer.js:329 #, javascript-format msgid "Transfer of %s from %s to %s succeed!" msgstr "" "Le transfert de %s de la note %s vers la note %s a été fait avec succès !" -#: apps/note/static/note/js/transfer.js:325 -#: apps/note/static/note/js/transfer.js:346 -#: apps/note/static/note/js/transfer.js:353 +#: apps/note/static/note/js/transfer.js:336 +#: apps/note/static/note/js/transfer.js:357 +#: apps/note/static/note/js/transfer.js:364 #, javascript-format msgid "Transfer of %s from %s to %s failed: %s" msgstr "Le transfert de %s de la note %s vers la note %s a échoué : %s" -#: apps/note/static/note/js/transfer.js:347 +#: apps/note/static/note/js/transfer.js:358 msgid "insufficient funds" msgstr "solde insuffisant" -#: apps/note/static/note/js/transfer.js:400 +#: apps/note/static/note/js/transfer.js:411 msgid "Credit/debit succeed!" msgstr "Le crédit/retrait a bien été effectué !" -#: apps/note/static/note/js/transfer.js:407 +#: apps/note/static/note/js/transfer.js:418 #, javascript-format msgid "Credit/debit failed: %s" msgstr "Le crédit/retrait a échoué : %s" -#: note_kfet/static/js/base.js:366 +#: note_kfet/static/js/base.js:370 msgid "An error occured while (in)validating this transaction:" msgstr "" "Une erreur est survenue lors de la validation/dévalidation de cette " diff --git a/note.cron b/note.cron index dd20c183..a54ad031 100644 --- a/note.cron +++ b/note.cron @@ -18,7 +18,7 @@ MAILTO=notekfet2020@lists.crans.org # Spammer les gens en négatif 00 5 * * 2 root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --spam --negative-amount 1 -v 0 # Envoyer le rapport mensuel aux trésoriers et respos info - 00 8 6 * * root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report --add-years 1 -v 0 + 00 8 * * 5 root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report --add-years 1 -v 0 # Envoyer les rapports aux gens 55 6 * * * root cd /var/www/note_kfet && env/bin/python manage.py send_reports -v 0 # Mettre à jour les boutons mis en avant diff --git a/note_kfet/static/css/custom.css b/note_kfet/static/css/custom.css old mode 100644 new mode 100755 index b97dc8e7..3b7a977a --- a/note_kfet/static/css/custom.css +++ b/note_kfet/static/css/custom.css @@ -67,7 +67,8 @@ mark { .bg-primary { /* background-color: rgb(18, 67, 4) !important; */ /* MODE VIEUXCON=ON */ - background-color: rgb(0, 119, 139) !important; +/* background-color: rgb(166, 0, 2) !important; */ + background-color: rgb(0, 0, 0) !important; } html { @@ -82,15 +83,15 @@ body { .btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active { - color: #fff; - background-color: rgb(0, 119, 139); - border-color: rgb(0, 119, 139); + color: rgb(241, 229, 52); + background-color: rgb(228, 35, 132); + border-color: rgb(228, 35, 132); } .btn-outline-primary { - color: rgb(0, 119, 139); - background-color: rgba(248, 249, 250, 0.9); - border-color: rgb(0, 119, 139); + color: #fff; + background-color: #000; + border-color: #464647; } .turbolinks-progress-bar { @@ -100,36 +101,63 @@ body { .btn-primary:hover, .btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active { - color: #fff; - background-color: rgb(0, 119, 139); - border-color: rgb(0, 119, 139); + color: rgb(241, 229, 52); + background-color: rgb(228, 35, 132); + border-color: rgb(228, 35, 132); } .btn-primary { - color: rgba(248, 249, 250, 0.9); - background-color: rgb(0, 119, 139); - border-color: rgb(0, 119, 139); + color: #fff; + background-color: #000; + border-color: #adb5bd; } .border-primary { - border-color: rgb(0,85, 102) !important; + border-color: rgb(228, 35, 132) !important; } +.btn-secondary { + color: #fff; + background-color: #000; + border-color: #adb5bd; +} + +.btn-secondary:hover, +.btn-secondary:not(:disabled):not(.disabled).active, +.btn-secondary:not(:disabled):not(.disabled):active { + color: rgb(241, 229, 52); + background-color: rgb(228, 35, 132); + border-color: rgb(228, 35, 132); +} + + +.btn-outline-dark { + color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:hover, +.btn-outline-dark:not(:disabled):not(.disabled).active, +.btn-outline-dark:not(:disabled):not(.disabled):active { + color: rgb(241, 229, 52); + background-color: rgb(228, 35, 132); + border-color: rgb(228, 35, 132); +} + + a { - color: rgb(0, 119, 139); + color: rgb(228, 35, 132); } a:hover { - color: rgb(0, 171, 205); + color: rgb(228, 35, 132); } .form-control:focus { - box-shadow: 0 0 0 0.25rem rgba(0, 171, 205, 0.25); - border-color: rgb(0, 171, 205); + box-shadow: 0 0 0 0.25rem rgb(228 35 132 / 50%); + border-color: rgb(228, 35, 132); } .btn-outline-primary.focus { - box-shadow: 0 0 0 0.25rem rgba(0, 171, 205, 0.5); + box-shadow: 0 0 0 0.25rem rgb(228 35 132 / 10%); } - - diff --git a/note_kfet/static/js/autocomplete_model.js b/note_kfet/static/js/autocomplete_model.js index 2a2677d4..a8b2461c 100644 --- a/note_kfet/static/js/autocomplete_model.js +++ b/note_kfet/static/js/autocomplete_model.js @@ -1,3 +1,5 @@ +const keycodes = [32, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 106, 107, 109, 110, 111, 186, 187, 188, 189, 190, 191, 219, 220, 221, 222] + $(document).ready(function () { $('.autocomplete').keyup(function (e) { const target = $('#' + e.target.id) @@ -10,7 +12,6 @@ $(document).ready(function () { const input = target.val() target.addClass('is-invalid') target.removeClass('is-valid') - $('#' + prefix + '_reset').removeClass('d-none') $.getJSON(api_url + (api_url.includes('?') ? '&' : '?') + 'format=json&search=^' + input + api_url_suffix, function (objects) { let html = '