mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
Merge branch 'activity' into 'master'
Activity management See merge request bde/nk20!32
This commit is contained in:
commit
c8854cf45d
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from ..models import ActivityType, Activity, Guest
|
from ..models import ActivityType, Activity, Guest, Entry, GuestTransaction
|
||||||
|
|
||||||
|
|
||||||
class ActivityTypeSerializer(serializers.ModelSerializer):
|
class ActivityTypeSerializer(serializers.ModelSerializer):
|
||||||
@ -37,3 +37,25 @@ class GuestSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Guest
|
model = Guest
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class EntrySerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
REST API Serializer for Entries.
|
||||||
|
The djangorestframework plugin will analyse the model `Entry` and parse all fields in the API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Entry
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class GuestTransactionSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
REST API Serializer for Special transactions.
|
||||||
|
The djangorestframework plugin will analyse the model `GuestTransaction` and parse all fields in the API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = GuestTransaction
|
||||||
|
fields = '__all__'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from .views import ActivityTypeViewSet, ActivityViewSet, GuestViewSet
|
from .views import ActivityTypeViewSet, ActivityViewSet, GuestViewSet, EntryViewSet
|
||||||
|
|
||||||
|
|
||||||
def register_activity_urls(router, path):
|
def register_activity_urls(router, path):
|
||||||
@ -11,3 +11,4 @@ def register_activity_urls(router, path):
|
|||||||
router.register(path + '/activity', ActivityViewSet)
|
router.register(path + '/activity', ActivityViewSet)
|
||||||
router.register(path + '/type', ActivityTypeViewSet)
|
router.register(path + '/type', ActivityTypeViewSet)
|
||||||
router.register(path + '/guest', GuestViewSet)
|
router.register(path + '/guest', GuestViewSet)
|
||||||
|
router.register(path + '/entry', EntryViewSet)
|
||||||
|
@ -5,8 +5,8 @@ from django_filters.rest_framework import DjangoFilterBackend
|
|||||||
from rest_framework.filters import SearchFilter
|
from rest_framework.filters import SearchFilter
|
||||||
from api.viewsets import ReadProtectedModelViewSet
|
from api.viewsets import ReadProtectedModelViewSet
|
||||||
|
|
||||||
from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer
|
from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer, EntrySerializer
|
||||||
from ..models import ActivityType, Activity, Guest
|
from ..models import ActivityType, Activity, Guest, Entry
|
||||||
|
|
||||||
|
|
||||||
class ActivityTypeViewSet(ReadProtectedModelViewSet):
|
class ActivityTypeViewSet(ReadProtectedModelViewSet):
|
||||||
@ -42,4 +42,16 @@ class GuestViewSet(ReadProtectedModelViewSet):
|
|||||||
queryset = Guest.objects.all()
|
queryset = Guest.objects.all()
|
||||||
serializer_class = GuestSerializer
|
serializer_class = GuestSerializer
|
||||||
filter_backends = [SearchFilter]
|
filter_backends = [SearchFilter]
|
||||||
search_fields = ['$name', ]
|
search_fields = ['$last_name', '$first_name', '$inviter__alias__name', '$inviter__alias__normalized_name', ]
|
||||||
|
|
||||||
|
|
||||||
|
class EntryViewSet(ReadProtectedModelViewSet):
|
||||||
|
"""
|
||||||
|
REST API View set.
|
||||||
|
The djangorestframework plugin will get all `Entry` objects, serialize it to JSON with the given serializer,
|
||||||
|
then render it on /api/activity/entry/
|
||||||
|
"""
|
||||||
|
queryset = Entry.objects.all()
|
||||||
|
serializer_class = EntrySerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$last_name', '$first_name', '$inviter__alias__name', '$inviter__alias__normalized_name', ]
|
||||||
|
84
apps/activity/forms.py
Normal file
84
apps/activity/forms.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from member.models import Club
|
||||||
|
from note.models import NoteUser, Note
|
||||||
|
from note_kfet.inputs import DateTimePickerInput, Autocomplete
|
||||||
|
|
||||||
|
from .models import Activity, Guest
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Activity
|
||||||
|
exclude = ('creater', 'valid', 'open', )
|
||||||
|
widgets = {
|
||||||
|
"organizer": Autocomplete(
|
||||||
|
model=Club,
|
||||||
|
attrs={"api_url": "/api/members/club/"},
|
||||||
|
),
|
||||||
|
"note": Autocomplete(
|
||||||
|
model=Note,
|
||||||
|
attrs={
|
||||||
|
"api_url": "/api/note/note/",
|
||||||
|
'placeholder': 'Note de l\'événement sur laquelle envoyer les crédits d\'invitation ...'
|
||||||
|
},
|
||||||
|
),
|
||||||
|
"attendees_club": Autocomplete(
|
||||||
|
model=Club,
|
||||||
|
attrs={"api_url": "/api/members/club/"},
|
||||||
|
),
|
||||||
|
"date_start": DateTimePickerInput(),
|
||||||
|
"date_end": DateTimePickerInput(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GuestForm(forms.ModelForm):
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
|
||||||
|
if self.activity.date_start > datetime.now():
|
||||||
|
self.add_error("inviter", _("You can't invite someone once the activity is started."))
|
||||||
|
|
||||||
|
if not self.activity.valid:
|
||||||
|
self.add_error("inviter", _("This activity is not validated yet."))
|
||||||
|
|
||||||
|
one_year = timedelta(days=365)
|
||||||
|
|
||||||
|
qs = Guest.objects.filter(
|
||||||
|
first_name=cleaned_data["first_name"],
|
||||||
|
last_name=cleaned_data["last_name"],
|
||||||
|
activity__date_start__gte=self.activity.date_start - one_year,
|
||||||
|
)
|
||||||
|
if len(qs) >= 5:
|
||||||
|
self.add_error("last_name", _("This person has been already invited 5 times this year."))
|
||||||
|
|
||||||
|
qs = qs.filter(activity=self.activity)
|
||||||
|
if qs.exists():
|
||||||
|
self.add_error("last_name", _("This person is already invited."))
|
||||||
|
|
||||||
|
qs = Guest.objects.filter(inviter=cleaned_data["inviter"], activity=self.activity)
|
||||||
|
if len(qs) >= 3:
|
||||||
|
self.add_error("inviter", _("You can't invite more than 3 people to this activity."))
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Guest
|
||||||
|
fields = ('last_name', 'first_name', 'inviter', )
|
||||||
|
widgets = {
|
||||||
|
"inviter": Autocomplete(
|
||||||
|
NoteUser,
|
||||||
|
attrs={
|
||||||
|
'api_url': '/api/note/note/',
|
||||||
|
# We don't evaluate the content type at launch because the DB might be not initialized
|
||||||
|
'api_url_suffix':
|
||||||
|
lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteUser).pk),
|
||||||
|
'placeholder': 'Note ...',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
@ -1,9 +1,13 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
from django.conf import settings
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
from note.models import NoteUser, Transaction
|
||||||
|
|
||||||
|
|
||||||
class ActivityType(models.Model):
|
class ActivityType(models.Model):
|
||||||
@ -44,39 +48,131 @@ class Activity(models.Model):
|
|||||||
verbose_name=_('name'),
|
verbose_name=_('name'),
|
||||||
max_length=255,
|
max_length=255,
|
||||||
)
|
)
|
||||||
|
|
||||||
description = models.TextField(
|
description = models.TextField(
|
||||||
verbose_name=_('description'),
|
verbose_name=_('description'),
|
||||||
)
|
)
|
||||||
|
|
||||||
activity_type = models.ForeignKey(
|
activity_type = models.ForeignKey(
|
||||||
ActivityType,
|
ActivityType,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='+',
|
||||||
verbose_name=_('type'),
|
verbose_name=_('type'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
creater = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("user"),
|
||||||
|
)
|
||||||
|
|
||||||
organizer = models.ForeignKey(
|
organizer = models.ForeignKey(
|
||||||
'member.Club',
|
'member.Club',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='+',
|
||||||
verbose_name=_('organizer'),
|
verbose_name=_('organizer'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
note = models.ForeignKey(
|
||||||
|
'note.Note',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name='+',
|
||||||
|
verbose_name=_('note'),
|
||||||
|
)
|
||||||
|
|
||||||
attendees_club = models.ForeignKey(
|
attendees_club = models.ForeignKey(
|
||||||
'member.Club',
|
'member.Club',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='+',
|
||||||
verbose_name=_('attendees club'),
|
verbose_name=_('attendees club'),
|
||||||
)
|
)
|
||||||
|
|
||||||
date_start = models.DateTimeField(
|
date_start = models.DateTimeField(
|
||||||
verbose_name=_('start date'),
|
verbose_name=_('start date'),
|
||||||
)
|
)
|
||||||
|
|
||||||
date_end = models.DateTimeField(
|
date_end = models.DateTimeField(
|
||||||
verbose_name=_('end date'),
|
verbose_name=_('end date'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
valid = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name=_('valid'),
|
||||||
|
)
|
||||||
|
|
||||||
|
open = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name=_('open'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("activity")
|
verbose_name = _("activity")
|
||||||
verbose_name_plural = _("activities")
|
verbose_name_plural = _("activities")
|
||||||
|
|
||||||
|
|
||||||
|
class Entry(models.Model):
|
||||||
|
activity = models.ForeignKey(
|
||||||
|
Activity,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name="entries",
|
||||||
|
verbose_name=_("activity"),
|
||||||
|
)
|
||||||
|
|
||||||
|
time = models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
verbose_name=_("entry time"),
|
||||||
|
)
|
||||||
|
|
||||||
|
note = models.ForeignKey(
|
||||||
|
NoteUser,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("note"),
|
||||||
|
)
|
||||||
|
|
||||||
|
guest = models.OneToOneField(
|
||||||
|
'activity.Guest',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('activity', 'note', 'guest', ), )
|
||||||
|
|
||||||
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
|
update_fields=None):
|
||||||
|
|
||||||
|
qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest)
|
||||||
|
if qs.exists():
|
||||||
|
raise ValidationError(_("Already entered on ") + _("{:%Y-%m-%d %H:%M:%S}").format(qs.get().time, ))
|
||||||
|
|
||||||
|
if self.guest:
|
||||||
|
self.note = self.guest.inviter
|
||||||
|
|
||||||
|
insert = not self.pk
|
||||||
|
if insert:
|
||||||
|
if self.note.balance < 0:
|
||||||
|
raise ValidationError(_("The balance is negative."))
|
||||||
|
|
||||||
|
ret = super().save(force_insert, force_update, using, update_fields)
|
||||||
|
|
||||||
|
if insert and self.guest:
|
||||||
|
GuestTransaction.objects.create(
|
||||||
|
source=self.note,
|
||||||
|
source_alias=self.note.user.username,
|
||||||
|
destination=self.note,
|
||||||
|
destination_alias=self.activity.organizer.name,
|
||||||
|
quantity=1,
|
||||||
|
amount=self.activity.activity_type.guest_entry_fee,
|
||||||
|
reason="Invitation " + self.activity.name + " " + self.guest.first_name + " " + self.guest.last_name,
|
||||||
|
valid=True,
|
||||||
|
guest=self.guest,
|
||||||
|
).save()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class Guest(models.Model):
|
class Guest(models.Model):
|
||||||
"""
|
"""
|
||||||
People who are not current members of any clubs, and are invited by someone who is a current member.
|
People who are not current members of any clubs, and are invited by someone who is a current member.
|
||||||
@ -86,24 +182,73 @@ class Guest(models.Model):
|
|||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='+',
|
||||||
)
|
)
|
||||||
name = models.CharField(
|
|
||||||
|
last_name = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
|
verbose_name=_("last name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
first_name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("first name"),
|
||||||
|
)
|
||||||
|
|
||||||
inviter = models.ForeignKey(
|
inviter = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
NoteUser,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='guests',
|
||||||
|
verbose_name=_("inviter"),
|
||||||
)
|
)
|
||||||
entry = models.DateTimeField(
|
|
||||||
null=True,
|
@property
|
||||||
)
|
def has_entry(self):
|
||||||
entry_transaction = models.ForeignKey(
|
try:
|
||||||
'note.Transaction',
|
if self.entry:
|
||||||
on_delete=models.PROTECT,
|
return True
|
||||||
blank=True,
|
return False
|
||||||
null=True,
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||||
|
one_year = timedelta(days=365)
|
||||||
|
|
||||||
|
if not force_insert:
|
||||||
|
if self.activity.date_start > datetime.now():
|
||||||
|
raise ValidationError(_("You can't invite someone once the activity is started."))
|
||||||
|
|
||||||
|
if not self.activity.valid:
|
||||||
|
raise ValidationError(_("This activity is not validated yet."))
|
||||||
|
|
||||||
|
qs = Guest.objects.filter(
|
||||||
|
first_name=self.first_name,
|
||||||
|
last_name=self.last_name,
|
||||||
|
activity__date_start__gte=self.activity.date_start - one_year,
|
||||||
)
|
)
|
||||||
|
if len(qs) >= 5:
|
||||||
|
raise ValidationError(_("This person has been already invited 5 times this year."))
|
||||||
|
|
||||||
|
qs = qs.filter(activity=self.activity)
|
||||||
|
if qs.exists():
|
||||||
|
raise ValidationError(_("This person is already invited."))
|
||||||
|
|
||||||
|
qs = Guest.objects.filter(inviter=self.inviter, activity=self.activity)
|
||||||
|
if len(qs) >= 3:
|
||||||
|
raise ValidationError(_("You can't invite more than 3 people to this activity."))
|
||||||
|
|
||||||
|
return super().save(force_insert, force_update, using, update_fields)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("guest")
|
verbose_name = _("guest")
|
||||||
verbose_name_plural = _("guests")
|
verbose_name_plural = _("guests")
|
||||||
|
unique_together = ("activity", "last_name", "first_name", )
|
||||||
|
|
||||||
|
|
||||||
|
class GuestTransaction(Transaction):
|
||||||
|
guest = models.OneToOneField(
|
||||||
|
Guest,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return _('Invitation')
|
||||||
|
108
apps/activity/tables.py
Normal file
108
apps/activity/tables.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from django.utils.html import format_html
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
import django_tables2 as tables
|
||||||
|
from django_tables2 import A
|
||||||
|
from note.templatetags.pretty_money import pretty_money
|
||||||
|
|
||||||
|
from .models import Activity, Guest, Entry
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityTable(tables.Table):
|
||||||
|
name = tables.LinkColumn(
|
||||||
|
'activity:activity_detail',
|
||||||
|
args=[A('pk'), ],
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
attrs = {
|
||||||
|
'class': 'table table-condensed table-striped table-hover'
|
||||||
|
}
|
||||||
|
model = Activity
|
||||||
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
|
fields = ('name', 'activity_type', 'organizer', 'attendees_club', 'date_start', 'date_end', )
|
||||||
|
|
||||||
|
|
||||||
|
class GuestTable(tables.Table):
|
||||||
|
inviter = tables.LinkColumn(
|
||||||
|
'member:user_detail',
|
||||||
|
args=[A('inviter.user.pk'), ],
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = tables.Column(
|
||||||
|
empty_values=(),
|
||||||
|
attrs={
|
||||||
|
"td": {
|
||||||
|
"class": lambda record: "" if record.has_entry else "validate btn btn-danger",
|
||||||
|
"onclick": lambda record: "" if record.has_entry else "remove_guest(" + str(record.pk) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
attrs = {
|
||||||
|
'class': 'table table-condensed table-striped table-hover'
|
||||||
|
}
|
||||||
|
model = Guest
|
||||||
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
|
fields = ("last_name", "first_name", "inviter", )
|
||||||
|
|
||||||
|
def render_entry(self, record):
|
||||||
|
if record.has_entry:
|
||||||
|
return str(_("Entered on ") + str(_("{:%Y-%m-%d %H:%M:%S}").format(record.entry.time, )))
|
||||||
|
return _("remove").capitalize()
|
||||||
|
|
||||||
|
|
||||||
|
def get_row_class(record):
|
||||||
|
c = "table-row"
|
||||||
|
if isinstance(record, Guest):
|
||||||
|
if record.has_entry:
|
||||||
|
c += " table-success"
|
||||||
|
else:
|
||||||
|
c += " table-warning"
|
||||||
|
else:
|
||||||
|
qs = Entry.objects.filter(note=record.note, activity=record.activity, guest=None)
|
||||||
|
if qs.exists():
|
||||||
|
c += " table-success"
|
||||||
|
elif record.note.balance < 0:
|
||||||
|
c += " table-danger"
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
class EntryTable(tables.Table):
|
||||||
|
type = tables.Column(verbose_name=_("Type"))
|
||||||
|
|
||||||
|
last_name = tables.Column(verbose_name=_("Last name"))
|
||||||
|
|
||||||
|
first_name = tables.Column(verbose_name=_("First name"))
|
||||||
|
|
||||||
|
note_name = tables.Column(verbose_name=_("Note"))
|
||||||
|
|
||||||
|
balance = tables.Column(verbose_name=_("Balance"))
|
||||||
|
|
||||||
|
def render_note_name(self, value, record):
|
||||||
|
if hasattr(record, 'username'):
|
||||||
|
username = record.username
|
||||||
|
if username != value:
|
||||||
|
return format_html(value + " <em>aka.</em> " + username)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def render_balance(self, value):
|
||||||
|
return pretty_money(value)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
attrs = {
|
||||||
|
'class': 'table table-condensed table-striped table-hover'
|
||||||
|
}
|
||||||
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
|
row_attrs = {
|
||||||
|
'class': lambda record: get_row_class(record),
|
||||||
|
'id': lambda record: "row-" + ("guest-" if isinstance(record, Guest) else "membership-") + str(record.pk),
|
||||||
|
'data-type': lambda record: "guest" if isinstance(record, Guest) else "membership",
|
||||||
|
'data-id': lambda record: record.pk if isinstance(record, Guest) else record.note.pk,
|
||||||
|
'data-inviter': lambda record: record.inviter.pk if isinstance(record, Guest) else "",
|
||||||
|
'data-last-name': lambda record: record.last_name,
|
||||||
|
'data-first-name': lambda record: record.first_name,
|
||||||
|
}
|
17
apps/activity/urls.py
Normal file
17
apps/activity/urls.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'activity'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.ActivityListView.as_view(), name='activity_list'),
|
||||||
|
path('<int:pk>/', views.ActivityDetailView.as_view(), name='activity_detail'),
|
||||||
|
path('<int:pk>/invite/', views.ActivityInviteView.as_view(), name='activity_invite'),
|
||||||
|
path('<int:pk>/entry/', views.ActivityEntryView.as_view(), name='activity_entry'),
|
||||||
|
path('<int:pk>/update/', views.ActivityUpdateView.as_view(), name='activity_update'),
|
||||||
|
path('new/', views.ActivityCreateView.as_view(), name='activity_create'),
|
||||||
|
]
|
153
apps/activity/views.py
Normal file
153
apps/activity/views.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db.models import F, Q
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django_tables2.views import SingleTableView
|
||||||
|
from note.models import NoteUser, Alias, NoteSpecial
|
||||||
|
from permission.backends import PermissionBackend
|
||||||
|
|
||||||
|
from .forms import ActivityForm, GuestForm
|
||||||
|
from .models import Activity, Guest, Entry
|
||||||
|
from .tables import ActivityTable, GuestTable, EntryTable
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityCreateView(LoginRequiredMixin, CreateView):
|
||||||
|
model = Activity
|
||||||
|
form_class = ActivityForm
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.creater = self.request.user
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
|
self.object.refresh_from_db()
|
||||||
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityListView(LoginRequiredMixin, SingleTableView):
|
||||||
|
model = Activity
|
||||||
|
table_class = ActivityTable
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return super().get_queryset()\
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).reverse()
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
ctx['title'] = _("Activities")
|
||||||
|
|
||||||
|
upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now())
|
||||||
|
ctx['upcoming'] = ActivityTable(data=upcoming_activities
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")))
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = Activity
|
||||||
|
context_object_name = "activity"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data()
|
||||||
|
|
||||||
|
table = GuestTable(data=Guest.objects.filter(activity=self.object)
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view")))
|
||||||
|
ctx["guests"] = table
|
||||||
|
|
||||||
|
ctx["activity_started"] = datetime.now(timezone.utc) > self.object.date_start
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
|
model = Activity
|
||||||
|
form_class = ActivityForm
|
||||||
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityInviteView(LoginRequiredMixin, CreateView):
|
||||||
|
model = Guest
|
||||||
|
form_class = GuestForm
|
||||||
|
template_name = "activity/activity_invite.html"
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
form.activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
|
return form
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||||
|
template_name = "activity/activity_entry.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
|
ctx["activity"] = activity
|
||||||
|
|
||||||
|
matched = []
|
||||||
|
|
||||||
|
pattern = "^$"
|
||||||
|
if "search" in self.request.GET:
|
||||||
|
pattern = self.request.GET["search"]
|
||||||
|
|
||||||
|
if not pattern:
|
||||||
|
pattern = "^$"
|
||||||
|
|
||||||
|
if pattern[0] != "^":
|
||||||
|
pattern = "^" + pattern
|
||||||
|
|
||||||
|
guest_qs = Guest.objects\
|
||||||
|
.annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\
|
||||||
|
.filter(Q(first_name__regex=pattern) | Q(last_name__regex=pattern)
|
||||||
|
| Q(inviter__alias__name__regex=pattern)
|
||||||
|
| Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern))) \
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\
|
||||||
|
.distinct()[:20]
|
||||||
|
for guest in guest_qs:
|
||||||
|
guest.type = "Invité"
|
||||||
|
matched.append(guest)
|
||||||
|
|
||||||
|
note_qs = Alias.objects.annotate(last_name=F("note__noteuser__user__last_name"),
|
||||||
|
first_name=F("note__noteuser__user__first_name"),
|
||||||
|
username=F("note__noteuser__user__username"),
|
||||||
|
note_name=F("name"),
|
||||||
|
balance=F("note__balance"))\
|
||||||
|
.filter(Q(note__polymorphic_ctype__model="noteuser")
|
||||||
|
& (Q(note__noteuser__user__first_name__regex=pattern)
|
||||||
|
| Q(note__noteuser__user__last_name__regex=pattern)
|
||||||
|
| Q(name__regex=pattern)
|
||||||
|
| Q(normalized_name__regex=Alias.normalize(pattern)))) \
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))\
|
||||||
|
.distinct("username")[:20]
|
||||||
|
for note in note_qs:
|
||||||
|
note.type = "Adhérent"
|
||||||
|
note.activity = activity
|
||||||
|
matched.append(note)
|
||||||
|
|
||||||
|
table = EntryTable(data=matched)
|
||||||
|
ctx["table"] = table
|
||||||
|
|
||||||
|
ctx["entries"] = Entry.objects.filter(activity=activity)
|
||||||
|
|
||||||
|
ctx["title"] = _('Entry for activity "{}"').format(activity.name)
|
||||||
|
ctx["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk
|
||||||
|
ctx["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk
|
||||||
|
|
||||||
|
return ctx
|
@ -4,10 +4,10 @@
|
|||||||
from crispy_forms.bootstrap import Div
|
from crispy_forms.bootstrap import Div
|
||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from crispy_forms.layout import Layout
|
from crispy_forms.layout import Layout
|
||||||
from dal import autocomplete
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from note_kfet.inputs import Autocomplete
|
||||||
from permission.models import PermissionMask
|
from permission.models import PermissionMask
|
||||||
|
|
||||||
from .models import Profile, Club, Membership
|
from .models import Profile, Club, Membership
|
||||||
@ -63,11 +63,12 @@ class MembershipForm(forms.ModelForm):
|
|||||||
# et récupère les noms d'utilisateur valides
|
# et récupère les noms d'utilisateur valides
|
||||||
widgets = {
|
widgets = {
|
||||||
'user':
|
'user':
|
||||||
autocomplete.ModelSelect2(
|
Autocomplete(
|
||||||
url='member:user_autocomplete',
|
User,
|
||||||
attrs={
|
attrs={
|
||||||
'data-placeholder': 'Nom ...',
|
'api_url': '/api/user/',
|
||||||
'data-minimum-input-length': 1,
|
'name_field': 'username',
|
||||||
|
'placeholder': 'Nom ...',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,4 @@ urlpatterns = [
|
|||||||
path('user/<int:pk>/update_pic', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
|
path('user/<int:pk>/update_pic', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
|
||||||
path('user/<int:pk>/aliases', views.ProfileAliasView.as_view(), name="user_alias"),
|
path('user/<int:pk>/aliases', views.ProfileAliasView.as_view(), name="user_alias"),
|
||||||
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
||||||
# API for the user autocompleter
|
|
||||||
path('user/user-autocomplete', views.UserAutocomplete.as_view(), name="user_autocomplete"),
|
|
||||||
]
|
]
|
||||||
|
@ -4,24 +4,19 @@
|
|||||||
import io
|
import io
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from dal import autocomplete
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.views import LoginView
|
from django.contrib.auth.views import LoginView
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView, DeleteView
|
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from django_tables2.views import SingleTableView
|
from django_tables2.views import SingleTableView
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from note.forms import ImageForm
|
from note.forms import ImageForm
|
||||||
#from note.forms import AliasForm, ImageForm
|
|
||||||
from note.models import Alias, NoteUser
|
from note.models import Alias, NoteUser
|
||||||
from note.models.transactions import Transaction
|
from note.models.transactions import Transaction
|
||||||
from note.tables import HistoryTable, AliasTable
|
from note.tables import HistoryTable, AliasTable
|
||||||
@ -257,28 +252,6 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class UserAutocomplete(autocomplete.Select2QuerySetView):
|
|
||||||
"""
|
|
||||||
Auto complete users by usernames
|
|
||||||
"""
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""
|
|
||||||
Quand une personne cherche un utilisateur par pseudo, une requête est envoyée sur l'API dédiée à l'auto-complétion.
|
|
||||||
Cette fonction récupère la requête, et renvoie la liste filtrée des utilisateurs par pseudos.
|
|
||||||
"""
|
|
||||||
# Un utilisateur non connecté n'a accès à aucune information
|
|
||||||
if not self.request.user.is_authenticated:
|
|
||||||
return User.objects.none()
|
|
||||||
|
|
||||||
qs = User.objects.filter(PermissionBackend.filter_queryset(self.request.user, User, "view")).all()
|
|
||||||
|
|
||||||
if self.q:
|
|
||||||
qs = qs.filter(username__regex="^" + self.q)
|
|
||||||
|
|
||||||
return qs
|
|
||||||
|
|
||||||
|
|
||||||
# ******************************* #
|
# ******************************* #
|
||||||
# CLUB #
|
# CLUB #
|
||||||
# ******************************* #
|
# ******************************* #
|
||||||
@ -326,6 +299,7 @@ class ClubDetailView(LoginRequiredMixin, DetailView):
|
|||||||
context['member_list'] = club_member
|
context['member_list'] = club_member
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ClubAliasView(LoginRequiredMixin, DetailView):
|
class ClubAliasView(LoginRequiredMixin, DetailView):
|
||||||
model = Club
|
model = Club
|
||||||
template_name = 'member/club_alias.html'
|
template_name = 'member/club_alias.html'
|
||||||
@ -364,6 +338,7 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
|
|||||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")
|
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")
|
||||||
| PermissionBackend.filter_queryset(self.request.user, Membership,
|
| PermissionBackend.filter_queryset(self.request.user, Membership,
|
||||||
"change"))
|
"change"))
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
club = Club.objects.get(pk=self.kwargs["pk"])
|
club = Club.objects.get(pk=self.kwargs["pk"])
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
@ -163,6 +163,7 @@ class SpecialTransactionSerializer(serializers.ModelSerializer):
|
|||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
class TransactionPolymorphicSerializer(PolymorphicSerializer):
|
class TransactionPolymorphicSerializer(PolymorphicSerializer):
|
||||||
model_serializer_mapping = {
|
model_serializer_mapping = {
|
||||||
Transaction: TransactionSerializer,
|
Transaction: TransactionSerializer,
|
||||||
@ -171,5 +172,12 @@ class TransactionPolymorphicSerializer(PolymorphicSerializer):
|
|||||||
SpecialTransaction: SpecialTransactionSerializer,
|
SpecialTransaction: SpecialTransactionSerializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
from activity.models import GuestTransaction
|
||||||
|
from activity.api.serializers import GuestTransactionSerializer
|
||||||
|
model_serializer_mapping[GuestTransaction] = GuestTransactionSerializer
|
||||||
|
except ImportError: # Activity app is not loaded
|
||||||
|
pass
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Transaction
|
model = Transaction
|
||||||
|
@ -8,7 +8,6 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
|||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
||||||
|
|
||||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
|
from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
|
||||||
@ -25,7 +24,8 @@ class NotePolymorphicViewSet(ReadOnlyProtectedModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Note.objects.all()
|
queryset = Note.objects.all()
|
||||||
serializer_class = NotePolymorphicSerializer
|
serializer_class = NotePolymorphicSerializer
|
||||||
filter_backends = [SearchFilter, OrderingFilter]
|
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||||
|
filterset_fields = ['polymorphic_ctype', 'is_active', ]
|
||||||
search_fields = ['$alias__normalized_name', '$alias__name', '$polymorphic_ctype__model', ]
|
search_fields = ['$alias__normalized_name', '$alias__name', '$polymorphic_ctype__model', ]
|
||||||
ordering_fields = ['alias__name', 'alias__normalized_name']
|
ordering_fields = ['alias__name', 'alias__normalized_name']
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
|||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
serializer_class = self.serializer_class
|
serializer_class = self.serializer_class
|
||||||
if self.request.method in ['PUT', 'PATCH']:
|
if self.request.method in ['PUT', 'PATCH']:
|
||||||
#alias owner cannot be change once establish
|
# alias owner cannot be change once establish
|
||||||
setattr(serializer_class.Meta, 'read_only_fields', ('note',))
|
setattr(serializer_class.Meta, 'read_only_fields', ('note',))
|
||||||
return serializer_class
|
return serializer_class
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
|||||||
self.perform_destroy(instance)
|
self.perform_destroy(instance)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
print(e)
|
print(e)
|
||||||
return Response({e.code:e.message},status.HTTP_400_BAD_REQUEST)
|
return Response({e.code: e.message}, status.HTTP_400_BAD_REQUEST)
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from dal import autocomplete
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from note_kfet.inputs import Autocomplete
|
||||||
|
|
||||||
from .models import Alias
|
from .models import TransactionTemplate, NoteClub
|
||||||
from .models import TransactionTemplate
|
|
||||||
|
|
||||||
|
|
||||||
class ImageForm(forms.Form):
|
class ImageForm(forms.Form):
|
||||||
@ -31,11 +31,14 @@ class TransactionTemplateForm(forms.ModelForm):
|
|||||||
# forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special}
|
# forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special}
|
||||||
widgets = {
|
widgets = {
|
||||||
'destination':
|
'destination':
|
||||||
autocomplete.ModelSelect2(
|
Autocomplete(
|
||||||
url='note:note_autocomplete',
|
NoteClub,
|
||||||
attrs={
|
attrs={
|
||||||
'data-placeholder': 'Note ...',
|
'api_url': '/api/note/note/',
|
||||||
'data-minimum-input-length': 1,
|
# We don't evaluate the content type at launch because the DB might be not initialized
|
||||||
|
'api_url_suffix':
|
||||||
|
lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteClub).pk),
|
||||||
|
'placeholder': 'Note ...',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -242,9 +242,9 @@ class Alias(models.Model):
|
|||||||
pass
|
pass
|
||||||
self.normalized_name = normalized_name
|
self.normalized_name = normalized_name
|
||||||
|
|
||||||
def save(self,*args,**kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.normalized_name = self.normalize(self.name)
|
self.normalized_name = self.normalize(self.name)
|
||||||
super().save(*args,**kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def delete(self, using=None, keep_parents=False):
|
def delete(self, using=None, keep_parents=False):
|
||||||
if self.name == str(self.note):
|
if self.name == str(self.note):
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import F
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -106,9 +106,8 @@ DELETE_TEMPLATE = """
|
|||||||
class AliasTable(tables.Table):
|
class AliasTable(tables.Table):
|
||||||
class Meta:
|
class Meta:
|
||||||
attrs = {
|
attrs = {
|
||||||
'class':
|
'class': 'table table condensed table-striped table-hover',
|
||||||
'table table condensed table-striped table-hover',
|
'id': "alias_table"
|
||||||
'id':"alias_table"
|
|
||||||
}
|
}
|
||||||
model = Alias
|
model = Alias
|
||||||
fields = ('name',)
|
fields = ('name',)
|
||||||
@ -122,7 +121,6 @@ class AliasTable(tables.Table):
|
|||||||
attrs={'td': {'class': 'col-sm-1'}})
|
attrs={'td': {'class': 'col-sm-1'}})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ButtonTable(tables.Table):
|
class ButtonTable(tables.Table):
|
||||||
class Meta:
|
class Meta:
|
||||||
attrs = {
|
attrs = {
|
||||||
|
@ -18,10 +18,5 @@ def pretty_money(value):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def cents_to_euros(value):
|
|
||||||
return "{:.02f}".format(value / 100) if value else ""
|
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter('pretty_money', pretty_money)
|
register.filter('pretty_money', pretty_money)
|
||||||
register.filter('cents_to_euros', cents_to_euros)
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
from .models import Note
|
|
||||||
|
|
||||||
app_name = 'note'
|
app_name = 'note'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -13,7 +12,4 @@ urlpatterns = [
|
|||||||
path('buttons/update/<int:pk>/', views.TransactionTemplateUpdateView.as_view(), name='template_update'),
|
path('buttons/update/<int:pk>/', views.TransactionTemplateUpdateView.as_view(), name='template_update'),
|
||||||
path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'),
|
path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'),
|
||||||
path('consos/', views.ConsoView.as_view(), name='consos'),
|
path('consos/', views.ConsoView.as_view(), name='consos'),
|
||||||
|
|
||||||
# API for the note autocompleter
|
|
||||||
path('note-autocomplete/', views.NoteAutocomplete.as_view(model=Note), name='note_autocomplete'),
|
|
||||||
]
|
]
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from dal import autocomplete
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import CreateView, UpdateView
|
from django.views.generic import CreateView, UpdateView
|
||||||
from django_tables2 import SingleTableView
|
from django_tables2 import SingleTableView
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from note_kfet.inputs import AmountInput
|
||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
|
|
||||||
from .forms import TransactionTemplateForm
|
from .forms import TransactionTemplateForm
|
||||||
from .models import Transaction, TransactionTemplate, Alias, RecurrentTransaction, NoteSpecial
|
from .models import Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial
|
||||||
from .models.transactions import SpecialTransaction
|
from .models.transactions import SpecialTransaction
|
||||||
from .tables import HistoryTable, ButtonTable
|
from .tables import HistoryTable, ButtonTable
|
||||||
|
|
||||||
@ -40,6 +39,7 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
|
|||||||
"""
|
"""
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['title'] = _('Transfer money')
|
context['title'] = _('Transfer money')
|
||||||
|
context['amount_widget'] = AmountInput(attrs={"id": "amount"})
|
||||||
context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk
|
context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk
|
||||||
context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk
|
context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk
|
||||||
context['special_types'] = NoteSpecial.objects.order_by("special_type").all()
|
context['special_types'] = NoteSpecial.objects.order_by("special_type").all()
|
||||||
@ -47,62 +47,6 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class NoteAutocomplete(autocomplete.Select2QuerySetView):
|
|
||||||
"""
|
|
||||||
Auto complete note by aliases. Used in every search field for note
|
|
||||||
ex: :view:`ConsoView`, :view:`TransactionCreateView`
|
|
||||||
"""
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""
|
|
||||||
When someone look for an :models:`note.Alias`, a query is sent to the dedicated API.
|
|
||||||
This function handles the result and return a filtered list of aliases.
|
|
||||||
"""
|
|
||||||
# Un utilisateur non connecté n'a accès à aucune information
|
|
||||||
if not self.request.user.is_authenticated:
|
|
||||||
return Alias.objects.none()
|
|
||||||
|
|
||||||
qs = Alias.objects.all()
|
|
||||||
|
|
||||||
# self.q est le paramètre de la recherche
|
|
||||||
if self.q:
|
|
||||||
qs = qs.filter(Q(name__regex="^" + self.q) | Q(normalized_name__regex="^" + Alias.normalize(self.q))) \
|
|
||||||
.order_by('normalized_name').distinct()
|
|
||||||
|
|
||||||
# Filtrage par type de note (user, club, special)
|
|
||||||
note_type = self.forwarded.get("note_type", None)
|
|
||||||
if note_type:
|
|
||||||
types = str(note_type).lower()
|
|
||||||
if "user" in types:
|
|
||||||
qs = qs.filter(note__polymorphic_ctype__model="noteuser")
|
|
||||||
elif "club" in types:
|
|
||||||
qs = qs.filter(note__polymorphic_ctype__model="noteclub")
|
|
||||||
elif "special" in types:
|
|
||||||
qs = qs.filter(note__polymorphic_ctype__model="notespecial")
|
|
||||||
else:
|
|
||||||
qs = qs.none()
|
|
||||||
|
|
||||||
return qs
|
|
||||||
|
|
||||||
def get_result_label(self, result):
|
|
||||||
"""
|
|
||||||
Show the selected alias and the username associated
|
|
||||||
<Alias> (aka. <Username> )
|
|
||||||
"""
|
|
||||||
# Gère l'affichage de l'alias dans la recherche
|
|
||||||
res = result.name
|
|
||||||
note_name = str(result.note)
|
|
||||||
if res != note_name:
|
|
||||||
res += " (aka. " + note_name + ")"
|
|
||||||
return res
|
|
||||||
|
|
||||||
def get_result_value(self, result):
|
|
||||||
"""
|
|
||||||
The value used for the transactions will be the id of the Note.
|
|
||||||
"""
|
|
||||||
return str(result.note.pk)
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
|
class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create TransactionTemplate
|
Create TransactionTemplate
|
||||||
|
@ -55,6 +55,20 @@
|
|||||||
"name": "Tr\u00e9sorier\u00b7\u00e8re de club"
|
"name": "Tr\u00e9sorier\u00b7\u00e8re de club"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"model": "member.role",
|
||||||
|
"pk": 8,
|
||||||
|
"fields": {
|
||||||
|
"name": "Tr\u00e9sorier\u00b7\u00e8re de club"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "member.role",
|
||||||
|
"pk": 9,
|
||||||
|
"fields": {
|
||||||
|
"name": "Res[pot]"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "permission.permissionmask",
|
"model": "permission.permissionmask",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
@ -574,6 +588,201 @@
|
|||||||
"description": "Create any transaction"
|
"description": "Create any transaction"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 34,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "[\"OR\", {\"valid\": true}, {\"creater\": [\"user\"]}]",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "View valid activites"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 35,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "[\"AND\", {\"valid\": false}, {\"creater\": [\"user\"]}]",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "Change our activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 36,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "{\"creater\": [\"user\"], \"valid\": false}",
|
||||||
|
"type": "add",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "Add activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 37,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "valid",
|
||||||
|
"description": "Validate activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 38,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "open",
|
||||||
|
"description": "Open activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 39,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guest"
|
||||||
|
],
|
||||||
|
"query": "{\"inviter\": [\"user\", \"note\"], \"activity__activity_type__can_invite\": true}",
|
||||||
|
"type": "add",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "Invite people to activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 40,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guest"
|
||||||
|
],
|
||||||
|
"query": "{\"inviter\": [\"user\", \"note\"]}",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "View invited people"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 41,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"activity"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "",
|
||||||
|
"description": "View all activities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 42,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guest"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "",
|
||||||
|
"description": "View all invited people"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 43,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"entry"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "add",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "",
|
||||||
|
"description": "Manage entries"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 44,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guesttransaction"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "add",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "",
|
||||||
|
"description": "Add invitation transactions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 45,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guesttransaction"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "view",
|
||||||
|
"mask": 1,
|
||||||
|
"field": "",
|
||||||
|
"description": "View invitation transactions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 46,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"activity",
|
||||||
|
"guesttransaction"
|
||||||
|
],
|
||||||
|
"query": "{}",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 2,
|
||||||
|
"field": "valid",
|
||||||
|
"description": "Validate invitation transactions"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "permission.rolepermissions",
|
"model": "permission.rolepermissions",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
@ -613,7 +822,12 @@
|
|||||||
15,
|
15,
|
||||||
16,
|
16,
|
||||||
17,
|
17,
|
||||||
18
|
18,
|
||||||
|
34,
|
||||||
|
35,
|
||||||
|
36,
|
||||||
|
39,
|
||||||
|
40
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -649,5 +863,22 @@
|
|||||||
33
|
33
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.rolepermissions",
|
||||||
|
"pk": 5,
|
||||||
|
"fields": {
|
||||||
|
"role": 9,
|
||||||
|
"permissions": [
|
||||||
|
37,
|
||||||
|
38,
|
||||||
|
41,
|
||||||
|
42,
|
||||||
|
43,
|
||||||
|
44,
|
||||||
|
45,
|
||||||
|
46
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -48,6 +48,11 @@ def not_empty_model_change_list(model_name):
|
|||||||
return session.get("not_empty_model_change_list_" + model_name) == 1
|
return session.get("not_empty_model_change_list_" + model_name) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def has_perm(perm, obj):
|
||||||
|
return PermissionBackend().has_perm(get_current_authenticated_user(), perm, obj)
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter('not_empty_model_list', not_empty_model_list)
|
register.filter('not_empty_model_list', not_empty_model_list)
|
||||||
register.filter('not_empty_model_change_list', not_empty_model_change_list)
|
register.filter('not_empty_model_change_list', not_empty_model_change_list)
|
||||||
|
register.filter('has_perm', has_perm)
|
||||||
|
@ -7,6 +7,7 @@ from crispy_forms.helper import FormHelper
|
|||||||
from crispy_forms.layout import Submit
|
from crispy_forms.layout import Submit
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from note_kfet.inputs import DatePickerInput, AmountInput
|
||||||
|
|
||||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
|
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ class InvoiceForm(forms.ModelForm):
|
|||||||
# Django forms don't support date fields. We have to add it manually
|
# Django forms don't support date fields. We have to add it manually
|
||||||
date = forms.DateField(
|
date = forms.DateField(
|
||||||
initial=datetime.date.today,
|
initial=datetime.date.today,
|
||||||
widget=forms.TextInput(attrs={'type': 'date'})
|
widget=DatePickerInput()
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean_date(self):
|
def clean_date(self):
|
||||||
@ -30,12 +31,21 @@ class InvoiceForm(forms.ModelForm):
|
|||||||
exclude = ('bde', )
|
exclude = ('bde', )
|
||||||
|
|
||||||
|
|
||||||
|
class ProductForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Product
|
||||||
|
fields = '__all__'
|
||||||
|
widgets = {
|
||||||
|
"amount": AmountInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Add a subform per product in the invoice form, and manage correctly the link between the invoice and
|
# Add a subform per product in the invoice form, and manage correctly the link between the invoice and
|
||||||
# its products. The FormSet will search automatically the ForeignKey in the Product model.
|
# its products. The FormSet will search automatically the ForeignKey in the Product model.
|
||||||
ProductFormSet = forms.inlineformset_factory(
|
ProductFormSet = forms.inlineformset_factory(
|
||||||
Invoice,
|
Invoice,
|
||||||
Product,
|
Product,
|
||||||
fields='__all__',
|
form=ProductForm,
|
||||||
extra=1,
|
extra=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,18 +50,8 @@ class InvoiceCreateView(LoginRequiredMixin, CreateView):
|
|||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
ret = super().form_valid(form)
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
kwargs = {}
|
|
||||||
|
|
||||||
# The user type amounts in cents. We convert it in euros.
|
|
||||||
for key in self.request.POST:
|
|
||||||
value = self.request.POST[key]
|
|
||||||
if key.endswith("amount") and value:
|
|
||||||
kwargs[key] = str(int(100 * float(value)))
|
|
||||||
elif value:
|
|
||||||
kwargs[key] = value
|
|
||||||
|
|
||||||
# For each product, we save it
|
# For each product, we save it
|
||||||
formset = ProductFormSet(kwargs, instance=form.instance)
|
formset = ProductFormSet(self.request.POST, instance=form.instance)
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
for f in formset:
|
for f in formset:
|
||||||
# We don't save the product if the designation is not entered, ie. if the line is empty
|
# We don't save the product if the designation is not entered, ie. if the line is empty
|
||||||
@ -112,16 +102,7 @@ class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
|
|||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
ret = super().form_valid(form)
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
kwargs = {}
|
formset = ProductFormSet(self.request.POST, instance=form.instance)
|
||||||
# The user type amounts in cents. We convert it in euros.
|
|
||||||
for key in self.request.POST:
|
|
||||||
value = self.request.POST[key]
|
|
||||||
if key.endswith("amount") and value:
|
|
||||||
kwargs[key] = str(int(100 * float(value)))
|
|
||||||
elif value:
|
|
||||||
kwargs[key] = value
|
|
||||||
|
|
||||||
formset = ProductFormSet(kwargs, instance=form.instance)
|
|
||||||
saved = []
|
saved = []
|
||||||
# For each product, we save it
|
# For each product, we save it
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-03-26 14:40+0100\n"
|
"POT-Creation-Date: 2020-03-30 17:31+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -18,72 +18,182 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: apps/activity/apps.py:10 apps/activity/models.py:76
|
#: apps/activity/apps.py:10 apps/activity/models.py:111
|
||||||
|
#: apps/activity/models.py:120
|
||||||
msgid "activity"
|
msgid "activity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:19 apps/activity/models.py:44
|
#: apps/activity/forms.py:45 apps/activity/models.py:217
|
||||||
#: apps/member/models.py:63 apps/member/models.py:114
|
msgid "You can't invite someone once the activity is started."
|
||||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
|
msgstr ""
|
||||||
#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
|
|
||||||
#: templates/member/profile_detail.html:15
|
#: apps/activity/forms.py:48 apps/activity/models.py:220
|
||||||
|
msgid "This activity is not validated yet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:58 apps/activity/models.py:228
|
||||||
|
msgid "This person has been already invited 5 times this year."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:62 apps/activity/models.py:232
|
||||||
|
msgid "This person is already invited."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:66 apps/activity/models.py:236
|
||||||
|
msgid "You can't invite more than 3 people to this activity."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:23 apps/activity/models.py:48
|
||||||
|
#: apps/member/models.py:64 apps/member/models.py:122
|
||||||
|
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
|
||||||
|
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231
|
||||||
|
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:23
|
#: apps/activity/models.py:27 templates/activity/activity_detail.html:39
|
||||||
msgid "can invite"
|
msgid "can invite"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:26
|
#: apps/activity/models.py:30 templates/activity/activity_detail.html:43
|
||||||
msgid "guest entry fee"
|
msgid "guest entry fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:30
|
#: apps/activity/models.py:34
|
||||||
msgid "activity type"
|
msgid "activity type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:31
|
#: apps/activity/models.py:35
|
||||||
msgid "activity types"
|
msgid "activity types"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:70
|
#: apps/activity/models.py:53 apps/note/models/transactions.py:69
|
||||||
#: apps/permission/models.py:91
|
#: apps/permission/models.py:90 templates/activity/activity_detail.html:16
|
||||||
msgid "description"
|
msgid "description"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
|
#: apps/activity/models.py:60 apps/note/models/notes.py:164
|
||||||
#: apps/note/models/transactions.py:63
|
#: apps/note/models/transactions.py:62
|
||||||
|
#: templates/activity/activity_detail.html:19
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:60
|
#: apps/activity/models.py:66 apps/logs/models.py:21
|
||||||
|
#: apps/note/models/notes.py:117
|
||||||
|
msgid "user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:73 templates/activity/activity_detail.html:33
|
||||||
msgid "organizer"
|
msgid "organizer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:66
|
#: apps/activity/models.py:82 apps/activity/models.py:131 apps/note/apps.py:14
|
||||||
|
#: apps/note/models/notes.py:58
|
||||||
|
msgid "note"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:89 templates/activity/activity_detail.html:36
|
||||||
msgid "attendees club"
|
msgid "attendees club"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:69
|
#: apps/activity/models.py:93 templates/activity/activity_detail.html:22
|
||||||
msgid "start date"
|
msgid "start date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:72
|
#: apps/activity/models.py:97 templates/activity/activity_detail.html:25
|
||||||
msgid "end date"
|
msgid "end date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:77
|
#: apps/activity/models.py:102 apps/note/models/transactions.py:134
|
||||||
|
#: templates/activity/activity_detail.html:47
|
||||||
|
msgid "valid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:107 templates/activity/activity_detail.html:61
|
||||||
|
msgid "open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:112
|
||||||
msgid "activities"
|
msgid "activities"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:108
|
#: apps/activity/models.py:125
|
||||||
|
msgid "entry time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:148
|
||||||
|
msgid "Already entered on "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:148 apps/activity/tables.py:54
|
||||||
|
msgid "{:%Y-%m-%d %H:%M:%S}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:156
|
||||||
|
msgid "The balance is negative."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:188
|
||||||
|
msgid "last name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:193 templates/member/profile_info.html:14
|
||||||
|
msgid "first name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:200
|
||||||
|
msgid "inviter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:241
|
||||||
msgid "guest"
|
msgid "guest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/activity/models.py:109
|
#: apps/activity/models.py:242
|
||||||
msgid "guests"
|
msgid "guests"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/models.py:254
|
||||||
|
msgid "Invitation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:54
|
||||||
|
msgid "Entered on "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:55
|
||||||
|
msgid "remove"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:75 apps/treasury/models.py:126
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:77 apps/treasury/forms.py:120
|
||||||
|
msgid "Last name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:79 apps/treasury/forms.py:122
|
||||||
|
#: templates/note/transaction_form.html:92
|
||||||
|
msgid "First name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:81 apps/note/models/notes.py:67
|
||||||
|
msgid "Note"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:83
|
||||||
|
msgid "Balance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/views.py:44 templates/base.html:94
|
||||||
|
msgid "Activities"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/activity/views.py:149
|
||||||
|
msgid "Entry for activity \"{}\""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/api/apps.py:10
|
#: apps/api/apps.py:10
|
||||||
msgid "API"
|
msgid "API"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -92,10 +202,6 @@ msgstr ""
|
|||||||
msgid "Logs"
|
msgid "Logs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/logs/models.py:21 apps/note/models/notes.py:117
|
|
||||||
msgid "user"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/logs/models.py:27
|
#: apps/logs/models.py:27
|
||||||
msgid "IP Address"
|
msgid "IP Address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -120,11 +226,12 @@ msgstr ""
|
|||||||
msgid "create"
|
msgid "create"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/logs/models.py:61 apps/note/tables.py:147
|
#: apps/logs/models.py:61 apps/note/tables.py:142
|
||||||
|
#: templates/activity/activity_detail.html:67
|
||||||
msgid "edit"
|
msgid "edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/logs/models.py:62 apps/note/tables.py:151
|
#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:146
|
||||||
msgid "delete"
|
msgid "delete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -144,139 +251,130 @@ msgstr ""
|
|||||||
msgid "member"
|
msgid "member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:25
|
#: apps/member/models.py:26
|
||||||
msgid "phone number"
|
msgid "phone number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:31 templates/member/profile_detail.html:28
|
#: apps/member/models.py:32 templates/member/profile_info.html:27
|
||||||
msgid "section"
|
msgid "section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:32
|
#: apps/member/models.py:33
|
||||||
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:38 templates/member/profile_detail.html:31
|
#: apps/member/models.py:39 templates/member/profile_info.html:30
|
||||||
msgid "address"
|
msgid "address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:44
|
#: apps/member/models.py:45
|
||||||
msgid "paid"
|
msgid "paid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:49 apps/member/models.py:50
|
#: apps/member/models.py:50 apps/member/models.py:51
|
||||||
msgid "user profile"
|
msgid "user profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:68
|
#: apps/member/models.py:69 templates/member/club_info.html:36
|
||||||
msgid "email"
|
msgid "email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:73
|
#: apps/member/models.py:76
|
||||||
|
msgid "parent club"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/member/models.py:81 templates/member/club_info.html:30
|
||||||
msgid "membership fee"
|
msgid "membership fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:77
|
#: apps/member/models.py:85 templates/member/club_info.html:27
|
||||||
msgid "membership duration"
|
msgid "membership duration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:78
|
#: apps/member/models.py:86
|
||||||
msgid "The longest time a membership can last (NULL = infinite)."
|
msgid "The longest time a membership can last (NULL = infinite)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:83
|
#: apps/member/models.py:91 templates/member/club_info.html:21
|
||||||
msgid "membership start"
|
msgid "membership start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:84
|
#: apps/member/models.py:92
|
||||||
msgid "How long after January 1st the members can renew their membership."
|
msgid "How long after January 1st the members can renew their membership."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:89
|
#: apps/member/models.py:97 templates/member/club_info.html:24
|
||||||
msgid "membership end"
|
msgid "membership end"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:90
|
#: apps/member/models.py:98
|
||||||
msgid ""
|
msgid ""
|
||||||
"How long the membership can last after January 1st of the next year after "
|
"How long the membership can last after January 1st of the next year after "
|
||||||
"members can renew their membership."
|
"members can renew their membership."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:96 apps/note/models/notes.py:139
|
#: apps/member/models.py:104 apps/note/models/notes.py:139
|
||||||
msgid "club"
|
msgid "club"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:97
|
#: apps/member/models.py:105
|
||||||
msgid "clubs"
|
msgid "clubs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:120 apps/permission/models.py:276
|
#: apps/member/models.py:128 apps/permission/models.py:275
|
||||||
msgid "role"
|
msgid "role"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:121
|
#: apps/member/models.py:129
|
||||||
msgid "roles"
|
msgid "roles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:145
|
#: apps/member/models.py:153
|
||||||
msgid "membership starts on"
|
msgid "membership starts on"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:148
|
#: apps/member/models.py:156
|
||||||
msgid "membership ends on"
|
msgid "membership ends on"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:152
|
#: apps/member/models.py:160
|
||||||
msgid "fee"
|
msgid "fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:162
|
#: apps/member/models.py:172
|
||||||
|
msgid "User is not a member of the parent club"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/member/models.py:176
|
||||||
msgid "membership"
|
msgid "membership"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/models.py:163
|
#: apps/member/models.py:177
|
||||||
msgid "memberships"
|
msgid "memberships"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/views.py:80 templates/member/profile_detail.html:46
|
#: apps/member/views.py:76 templates/member/profile_info.html:45
|
||||||
msgid "Update Profile"
|
msgid "Update Profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/views.py:93
|
#: apps/member/views.py:89
|
||||||
msgid "An alias with a similar name already exists."
|
msgid "An alias with a similar name already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/member/views.py:146
|
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
|
||||||
#, python-format
|
|
||||||
msgid "Account #%(id)s: %(username)s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/member/views.py:216
|
|
||||||
msgid "Alias successfully deleted"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:95
|
|
||||||
msgid "source"
|
msgid "source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/admin.py:128 apps/note/admin.py:156
|
#: apps/note/admin.py:128 apps/note/admin.py:156
|
||||||
#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
|
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:107
|
||||||
msgid "destination"
|
msgid "destination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/apps.py:14 apps/note/models/notes.py:58
|
#: apps/note/forms.py:14
|
||||||
msgid "note"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/note/forms.py:20
|
|
||||||
msgid "New Alias"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/note/forms.py:25
|
|
||||||
msgid "select an image"
|
msgid "select an image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/forms.py:26
|
#: apps/note/forms.py:15
|
||||||
msgid "Maximal size: 2MB"
|
msgid "Maximal size: 2MB"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -310,7 +408,7 @@ msgstr ""
|
|||||||
msgid "display image"
|
msgid "display image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
|
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:117
|
||||||
msgid "created at"
|
msgid "created at"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -318,10 +416,6 @@ msgstr ""
|
|||||||
msgid "notes"
|
msgid "notes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/notes.py:67
|
|
||||||
msgid "Note"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
|
#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
|
||||||
msgid "This alias is already taken."
|
msgid "This alias is already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -368,7 +462,8 @@ msgstr ""
|
|||||||
msgid "alias"
|
msgid "alias"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/notes.py:211 templates/member/profile_detail.html:37
|
#: apps/note/models/notes.py:211 templates/member/club_info.html:33
|
||||||
|
#: templates/member/profile_info.html:36
|
||||||
msgid "aliases"
|
msgid "aliases"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -380,106 +475,114 @@ msgstr ""
|
|||||||
msgid "An alias with a similar name already exists: {} "
|
msgid "An alias with a similar name already exists: {} "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/notes.py:247
|
#: apps/note/models/notes.py:251
|
||||||
msgid "You can't delete your main alias."
|
msgid "You can't delete your main alias."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:31
|
#: apps/note/models/transactions.py:30
|
||||||
msgid "transaction category"
|
msgid "transaction category"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:32
|
#: apps/note/models/transactions.py:31
|
||||||
msgid "transaction categories"
|
msgid "transaction categories"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:48
|
#: apps/note/models/transactions.py:47
|
||||||
msgid "A template with this name already exist"
|
msgid "A template with this name already exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
|
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:125
|
||||||
msgid "amount"
|
msgid "amount"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:58
|
#: apps/note/models/transactions.py:57
|
||||||
msgid "in centimes"
|
msgid "in centimes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:76
|
#: apps/note/models/transactions.py:75
|
||||||
msgid "transaction template"
|
msgid "transaction template"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:77
|
#: apps/note/models/transactions.py:76
|
||||||
msgid "transaction templates"
|
msgid "transaction templates"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
|
#: apps/note/models/transactions.py:100 apps/note/models/transactions.py:113
|
||||||
#: apps/note/tables.py:33 apps/note/tables.py:42
|
#: apps/note/tables.py:33 apps/note/tables.py:42
|
||||||
msgid "used alias"
|
msgid "used alias"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:122
|
#: apps/note/models/transactions.py:121
|
||||||
msgid "quantity"
|
msgid "quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:130
|
#: apps/note/models/transactions.py:129
|
||||||
msgid "reason"
|
msgid "reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:135
|
#: apps/note/models/transactions.py:139 apps/note/tables.py:95
|
||||||
msgid "valid"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:140 apps/note/tables.py:95
|
|
||||||
msgid "invalidity reason"
|
msgid "invalidity reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:147
|
#: apps/note/models/transactions.py:146
|
||||||
msgid "transaction"
|
msgid "transaction"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:148
|
#: apps/note/models/transactions.py:147
|
||||||
msgid "transactions"
|
msgid "transactions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:202 templates/base.html:83
|
#: apps/note/models/transactions.py:201 templates/base.html:84
|
||||||
#: templates/note/transaction_form.html:19
|
#: templates/note/transaction_form.html:19
|
||||||
#: templates/note/transaction_form.html:145
|
#: templates/note/transaction_form.html:140
|
||||||
msgid "Transfer"
|
msgid "Transfer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:188
|
#: apps/note/models/transactions.py:221
|
||||||
msgid "Template"
|
msgid "Template"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:203
|
#: apps/note/models/transactions.py:236
|
||||||
msgid "first_name"
|
msgid "first_name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:208
|
#: apps/note/models/transactions.py:241
|
||||||
msgid "bank"
|
msgid "bank"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:24
|
#: apps/note/models/transactions.py:247 templates/note/transaction_form.html:24
|
||||||
msgid "Credit"
|
msgid "Credit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:28
|
#: apps/note/models/transactions.py:247 templates/note/transaction_form.html:28
|
||||||
msgid "Debit"
|
msgid "Debit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:230 apps/note/models/transactions.py:235
|
#: apps/note/models/transactions.py:263 apps/note/models/transactions.py:268
|
||||||
msgid "membership transaction"
|
msgid "membership transaction"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:231
|
#: apps/note/models/transactions.py:264
|
||||||
msgid "membership transactions"
|
msgid "membership transactions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/views.py:39
|
#: apps/note/tables.py:57
|
||||||
|
msgid "Click to invalidate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/note/tables.py:57
|
||||||
|
msgid "Click to validate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/note/tables.py:93
|
||||||
|
msgid "No reason specified"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/note/views.py:41
|
||||||
msgid "Transfer money"
|
msgid "Transfer money"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/note/views.py:145 templates/base.html:79
|
#: apps/note/views.py:102 templates/base.html:79
|
||||||
msgid "Consumptions"
|
msgid "Consumptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -501,41 +604,35 @@ msgstr ""
|
|||||||
msgid "Specifying field applies only to view and change permission types."
|
msgid "Specifying field applies only to view and change permission types."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/apps.py:11 templates/base.html:102
|
#: apps/treasury/apps.py:12 templates/base.html:99
|
||||||
msgid "Treasury"
|
msgid "Treasury"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:56 apps/treasury/forms.py:95
|
#: apps/treasury/forms.py:84 apps/treasury/forms.py:132
|
||||||
|
#: templates/activity/activity_form.html:9
|
||||||
|
#: templates/activity/activity_invite.html:8
|
||||||
#: templates/django_filters/rest_framework/form.html:5
|
#: templates/django_filters/rest_framework/form.html:5
|
||||||
#: templates/member/club_form.html:10 templates/treasury/invoice_form.html:47
|
#: templates/member/club_form.html:9 templates/treasury/invoice_form.html:46
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:58
|
#: apps/treasury/forms.py:86
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:65
|
#: apps/treasury/forms.py:95
|
||||||
msgid "Remittance is already closed."
|
msgid "Remittance is already closed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:70
|
#: apps/treasury/forms.py:100
|
||||||
msgid "You can't change the type of the remittance."
|
msgid "You can't change the type of the remittance."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:84
|
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:98
|
||||||
msgid "Last name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/treasury/forms.py:86 templates/note/transaction_form.html:92
|
|
||||||
msgid "First name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/treasury/forms.py:88 templates/note/transaction_form.html:98
|
|
||||||
msgid "Bank"
|
msgid "Bank"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/forms.py:90 apps/treasury/tables.py:40
|
#: apps/treasury/forms.py:126 apps/treasury/tables.py:47
|
||||||
#: templates/note/transaction_form.html:128
|
#: templates/note/transaction_form.html:128
|
||||||
#: templates/treasury/remittance_form.html:18
|
#: templates/treasury/remittance_form.html:18
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
@ -589,10 +686,6 @@ msgstr ""
|
|||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/models.py:126
|
|
||||||
msgid "Type"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/treasury/models.py:131
|
#: apps/treasury/models.py:131
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -601,38 +694,38 @@ msgstr ""
|
|||||||
msgid "Closed"
|
msgid "Closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/models.py:159
|
#: apps/treasury/models.py:169
|
||||||
msgid "Remittance #{:d}: {}"
|
msgid "Remittance #{:d}: {}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/models.py:178 apps/treasury/tables.py:64
|
#: apps/treasury/models.py:188 apps/treasury/tables.py:76
|
||||||
#: apps/treasury/tables.py:72 templates/treasury/invoice_list.html:13
|
#: apps/treasury/tables.py:84 templates/treasury/invoice_list.html:13
|
||||||
#: templates/treasury/remittance_list.html:13
|
#: templates/treasury/remittance_list.html:13
|
||||||
msgid "Remittance"
|
msgid "Remittance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:16
|
#: apps/treasury/tables.py:19
|
||||||
msgid "Invoice #{:d}"
|
msgid "Invoice #{:d}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10
|
#: apps/treasury/tables.py:22 templates/treasury/invoice_list.html:10
|
||||||
#: templates/treasury/remittance_list.html:10
|
#: templates/treasury/remittance_list.html:10
|
||||||
msgid "Invoice"
|
msgid "Invoice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:38
|
#: apps/treasury/tables.py:45
|
||||||
msgid "Transaction count"
|
msgid "Transaction count"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:43 apps/treasury/tables.py:45
|
#: apps/treasury/tables.py:50 apps/treasury/tables.py:52
|
||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:66
|
#: apps/treasury/tables.py:78
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/tables.py:74
|
#: apps/treasury/tables.py:86
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -643,30 +736,86 @@ msgid ""
|
|||||||
"again unless your session expires or you logout."
|
"again unless your session expires or you logout."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:151
|
#: note_kfet/settings/base.py:152
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:152
|
#: note_kfet/settings/base.py:153
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:153
|
#: note_kfet/settings/base.py:154
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:29
|
||||||
|
msgid "creater"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:50
|
||||||
|
msgid "opened"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:57
|
||||||
|
msgid "Entry page"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:61
|
||||||
|
msgid "close"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:64
|
||||||
|
msgid "invalidate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:64
|
||||||
|
msgid "validate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:70
|
||||||
|
msgid "Invite"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:77
|
||||||
|
msgid "Guests list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:10
|
||||||
|
msgid "Return to activity page"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:18
|
||||||
|
msgid "entries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:18
|
||||||
|
msgid "entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:5
|
||||||
|
msgid "Upcoming activities"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:10
|
||||||
|
msgid "There is no planned activity."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:14
|
||||||
|
msgid "New activity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:18
|
||||||
|
msgid "All activities"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:13
|
#: templates/base.html:13
|
||||||
msgid "The ENS Paris-Saclay BDE note."
|
msgid "The ENS Paris-Saclay BDE note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:87
|
#: templates/base.html:89
|
||||||
msgid "Clubs"
|
msgid "Clubs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:92
|
|
||||||
msgid "Activities"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/cas_server/base.html:7
|
#: templates/cas_server/base.html:7
|
||||||
msgid "Central Authentication Service"
|
msgid "Central Authentication Service"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -722,32 +871,48 @@ msgstr ""
|
|||||||
msgid "Field filters"
|
msgid "Field filters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:10
|
#: templates/member/alias_update.html:5
|
||||||
msgid "Membership starts on"
|
msgid "Add alias"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:12
|
#: templates/member/club_info.html:17
|
||||||
msgid "Membership ends on"
|
msgid "Club Parent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:14
|
#: templates/member/club_info.html:41
|
||||||
msgid "Membership duration"
|
msgid "Add member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:18 templates/member/profile_detail.html:34
|
#: templates/member/club_info.html:42 templates/note/conso_form.html:121
|
||||||
msgid "balance"
|
msgid "Edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:51 templates/member/profile_detail.html:75
|
#: templates/member/club_info.html:43
|
||||||
msgid "Transaction history"
|
msgid "Add roles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_form.html:6
|
#: templates/member/club_info.html:46 templates/member/profile_info.html:48
|
||||||
msgid "Clubs list"
|
msgid "View Profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_list.html:8
|
#: templates/member/club_list.html:8
|
||||||
msgid "New club"
|
msgid "search clubs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/club_list.html:12
|
||||||
|
msgid "Créer un club"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/club_list.html:19
|
||||||
|
msgid "club listing "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/club_tables.html:9
|
||||||
|
msgid "Member of the Club"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/club_tables.html:22 templates/member/profile_tables.html:22
|
||||||
|
msgid "Transaction history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/manage_auth_tokens.html:16
|
#: templates/member/manage_auth_tokens.html:16
|
||||||
@ -762,35 +927,31 @@ msgstr ""
|
|||||||
msgid "Regenerate token"
|
msgid "Regenerate token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_alias.html:10
|
#: templates/member/profile_info.html:5
|
||||||
msgid "Add alias"
|
msgid "Account #"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:15
|
#: templates/member/profile_info.html:17
|
||||||
msgid "first name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:18
|
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:21
|
#: templates/member/profile_info.html:20
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:24
|
#: templates/member/profile_info.html:23
|
||||||
msgid "Change password"
|
msgid "Change password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:42
|
#: templates/member/profile_info.html:33
|
||||||
|
msgid "balance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/profile_info.html:41
|
||||||
msgid "Manage auth token"
|
msgid "Manage auth token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:49
|
#: templates/member/profile_tables.html:9
|
||||||
msgid "View Profile"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:62
|
|
||||||
msgid "View my memberships"
|
msgid "View my memberships"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -819,10 +980,6 @@ msgstr ""
|
|||||||
msgid "Most used buttons"
|
msgid "Most used buttons"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/conso_form.html:121
|
|
||||||
msgid "Edit"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/note/conso_form.html:126
|
#: templates/note/conso_form.html:126
|
||||||
msgid "Single consumptions"
|
msgid "Single consumptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -831,7 +988,7 @@ msgstr ""
|
|||||||
msgid "Double consumptions"
|
msgid "Double consumptions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152
|
#: templates/note/conso_form.html:141 templates/note/transaction_form.html:147
|
||||||
msgid "Recent transactions history"
|
msgid "Recent transactions history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -847,37 +1004,21 @@ msgstr ""
|
|||||||
msgid "Transfer type"
|
msgid "Transfer type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:86
|
|
||||||
msgid "Name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:92
|
|
||||||
msgid "First name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:98
|
|
||||||
msgid "Bank"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:111
|
#: templates/note/transaction_form.html:111
|
||||||
#: templates/note/transaction_form.html:169
|
#: templates/note/transaction_form.html:164
|
||||||
#: templates/note/transaction_form.html:176
|
#: templates/note/transaction_form.html:171
|
||||||
msgid "Select receivers"
|
msgid "Select receivers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:128
|
#: templates/note/transaction_form.html:133
|
||||||
msgid "Amount"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:138
|
|
||||||
msgid "Reason"
|
msgid "Reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:183
|
#: templates/note/transaction_form.html:178
|
||||||
msgid "Credit note"
|
msgid "Credit note"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:190
|
#: templates/note/transaction_form.html:185
|
||||||
msgid "Debit note"
|
msgid "Debit note"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -889,6 +1030,10 @@ msgstr ""
|
|||||||
msgid "search button"
|
msgid "search button"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/note/transactiontemplate_list.html:13
|
||||||
|
msgid "New button"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/note/transactiontemplate_list.html:20
|
#: templates/note/transactiontemplate_list.html:20
|
||||||
msgid "buttons listing "
|
msgid "buttons listing "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -991,11 +1136,11 @@ msgstr ""
|
|||||||
msgid "Invoices list"
|
msgid "Invoices list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/treasury/invoice_form.html:42
|
#: templates/treasury/invoice_form.html:41
|
||||||
msgid "Add product"
|
msgid "Add product"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/treasury/invoice_form.html:43
|
#: templates/treasury/invoice_form.html:42
|
||||||
msgid "Remove product"
|
msgid "Remove product"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-03-26 14:40+0100\n"
|
"POT-Creation-Date: 2020-03-30 17:31+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -13,83 +13,189 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
#: apps/activity/apps.py:10 apps/activity/models.py:76
|
#: apps/activity/apps.py:10 apps/activity/models.py:111
|
||||||
|
#: apps/activity/models.py:120
|
||||||
msgid "activity"
|
msgid "activity"
|
||||||
msgstr "activité"
|
msgstr "activité"
|
||||||
|
|
||||||
#: apps/activity/models.py:19 apps/activity/models.py:44
|
#: apps/activity/forms.py:45 apps/activity/models.py:217
|
||||||
#: apps/member/models.py:63 apps/member/models.py:114
|
msgid "You can't invite someone once the activity is started."
|
||||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
|
msgstr "Vous ne pouvez pas inviter quelqu'un une fois que l'activité a démarré."
|
||||||
#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
|
|
||||||
#: templates/member/profile_detail.html:15
|
#: apps/activity/forms.py:48 apps/activity/models.py:220
|
||||||
|
msgid "This activity is not validated yet."
|
||||||
|
msgstr "Cette activité n'est pas encore validée."
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:58 apps/activity/models.py:228
|
||||||
|
msgid "This person has been already invited 5 times this year."
|
||||||
|
msgstr "Cette personne a déjà été invitée 5 fois cette année."
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:62 apps/activity/models.py:232
|
||||||
|
msgid "This person is already invited."
|
||||||
|
msgstr "Cette personne est déjà invitée."
|
||||||
|
|
||||||
|
#: apps/activity/forms.py:66 apps/activity/models.py:236
|
||||||
|
msgid "You can't invite more than 3 people to this activity."
|
||||||
|
msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité."
|
||||||
|
|
||||||
|
#: apps/activity/models.py:23 apps/activity/models.py:48
|
||||||
|
#: apps/member/models.py:64 apps/member/models.py:122
|
||||||
|
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
|
||||||
|
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231
|
||||||
|
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr "nom"
|
msgstr "nom"
|
||||||
|
|
||||||
#: apps/activity/models.py:23
|
#: apps/activity/models.py:27 templates/activity/activity_detail.html:39
|
||||||
msgid "can invite"
|
msgid "can invite"
|
||||||
msgstr "peut inviter"
|
msgstr "peut inviter"
|
||||||
|
|
||||||
#: apps/activity/models.py:26
|
#: apps/activity/models.py:30 templates/activity/activity_detail.html:43
|
||||||
msgid "guest entry fee"
|
msgid "guest entry fee"
|
||||||
msgstr "cotisation de l'entrée invité"
|
msgstr "cotisation de l'entrée invité"
|
||||||
|
|
||||||
#: apps/activity/models.py:30
|
#: apps/activity/models.py:34
|
||||||
msgid "activity type"
|
msgid "activity type"
|
||||||
msgstr "type d'activité"
|
msgstr "type d'activité"
|
||||||
|
|
||||||
#: apps/activity/models.py:31
|
#: apps/activity/models.py:35
|
||||||
msgid "activity types"
|
msgid "activity types"
|
||||||
msgstr "types d'activité"
|
msgstr "types d'activité"
|
||||||
|
|
||||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:70
|
#: apps/activity/models.py:53 apps/note/models/transactions.py:69
|
||||||
#: apps/permission/models.py:91
|
#: apps/permission/models.py:90 templates/activity/activity_detail.html:16
|
||||||
msgid "description"
|
msgid "description"
|
||||||
msgstr "description"
|
msgstr "description"
|
||||||
|
|
||||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
|
#: apps/activity/models.py:60 apps/note/models/notes.py:164
|
||||||
#: apps/note/models/transactions.py:63
|
#: apps/note/models/transactions.py:62
|
||||||
|
#: templates/activity/activity_detail.html:19
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr "type"
|
msgstr "type"
|
||||||
|
|
||||||
#: apps/activity/models.py:60
|
#: apps/activity/models.py:66 apps/logs/models.py:21
|
||||||
|
#: apps/note/models/notes.py:117
|
||||||
|
msgid "user"
|
||||||
|
msgstr "utilisateur"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:73 templates/activity/activity_detail.html:33
|
||||||
msgid "organizer"
|
msgid "organizer"
|
||||||
msgstr "organisateur"
|
msgstr "organisateur"
|
||||||
|
|
||||||
#: apps/activity/models.py:66
|
#: apps/activity/models.py:82 apps/activity/models.py:131 apps/note/apps.py:14
|
||||||
msgid "attendees club"
|
#: apps/note/models/notes.py:58
|
||||||
msgstr ""
|
msgid "note"
|
||||||
|
msgstr "note"
|
||||||
|
|
||||||
#: apps/activity/models.py:69
|
#: apps/activity/models.py:89 templates/activity/activity_detail.html:36
|
||||||
|
msgid "attendees club"
|
||||||
|
msgstr "club attendu"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:93 templates/activity/activity_detail.html:22
|
||||||
msgid "start date"
|
msgid "start date"
|
||||||
msgstr "date de début"
|
msgstr "date de début"
|
||||||
|
|
||||||
#: apps/activity/models.py:72
|
#: apps/activity/models.py:97 templates/activity/activity_detail.html:25
|
||||||
msgid "end date"
|
msgid "end date"
|
||||||
msgstr "date de fin"
|
msgstr "date de fin"
|
||||||
|
|
||||||
#: apps/activity/models.py:77
|
#: apps/activity/models.py:102 apps/note/models/transactions.py:134
|
||||||
|
#: templates/activity/activity_detail.html:47
|
||||||
|
msgid "valid"
|
||||||
|
msgstr "valide"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:107 templates/activity/activity_detail.html:61
|
||||||
|
msgid "open"
|
||||||
|
msgstr "ouvrir"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:112
|
||||||
msgid "activities"
|
msgid "activities"
|
||||||
msgstr "activités"
|
msgstr "activités"
|
||||||
|
|
||||||
#: apps/activity/models.py:108
|
#: apps/activity/models.py:125
|
||||||
|
msgid "entry time"
|
||||||
|
msgstr "heure d'entrée"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:148
|
||||||
|
msgid "Already entered on "
|
||||||
|
msgstr "Déjà rentré le "
|
||||||
|
|
||||||
|
#: apps/activity/models.py:148 apps/activity/tables.py:54
|
||||||
|
msgid "{:%Y-%m-%d %H:%M:%S}"
|
||||||
|
msgstr "{:%d/%m/%Y %H:%M:%S}"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:156
|
||||||
|
msgid "The balance is negative."
|
||||||
|
msgstr "La note est en négatif."
|
||||||
|
|
||||||
|
#: apps/activity/models.py:188
|
||||||
|
msgid "last name"
|
||||||
|
msgstr "nom de famille"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:193 templates/member/profile_info.html:14
|
||||||
|
msgid "first name"
|
||||||
|
msgstr "prénom"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:200
|
||||||
|
msgid "inviter"
|
||||||
|
msgstr "hôte"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:241
|
||||||
msgid "guest"
|
msgid "guest"
|
||||||
msgstr "invité"
|
msgstr "invité"
|
||||||
|
|
||||||
#: apps/activity/models.py:109
|
#: apps/activity/models.py:242
|
||||||
msgid "guests"
|
msgid "guests"
|
||||||
msgstr "invités"
|
msgstr "invités"
|
||||||
|
|
||||||
|
#: apps/activity/models.py:254
|
||||||
|
msgid "Invitation"
|
||||||
|
msgstr "Invitation"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:54
|
||||||
|
msgid "Entered on "
|
||||||
|
msgstr "Entré le "
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:55
|
||||||
|
msgid "remove"
|
||||||
|
msgstr "supprimer"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:75 apps/treasury/models.py:126
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Type"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:77 apps/treasury/forms.py:120
|
||||||
|
msgid "Last name"
|
||||||
|
msgstr "Nom de famille"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:79 apps/treasury/forms.py:122
|
||||||
|
#: templates/note/transaction_form.html:92
|
||||||
|
msgid "First name"
|
||||||
|
msgstr "Prénom"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:81 apps/note/models/notes.py:67
|
||||||
|
msgid "Note"
|
||||||
|
msgstr "Note"
|
||||||
|
|
||||||
|
#: apps/activity/tables.py:83
|
||||||
|
msgid "Balance"
|
||||||
|
msgstr "Solde du compte"
|
||||||
|
|
||||||
|
#: apps/activity/views.py:44 templates/base.html:94
|
||||||
|
msgid "Activities"
|
||||||
|
msgstr "Activités"
|
||||||
|
|
||||||
|
#: apps/activity/views.py:149
|
||||||
|
msgid "Entry for activity \"{}\""
|
||||||
|
msgstr "Entrées pour l'activité « {} »"
|
||||||
|
|
||||||
#: apps/api/apps.py:10
|
#: apps/api/apps.py:10
|
||||||
msgid "API"
|
msgid "API"
|
||||||
msgstr ""
|
msgstr "API"
|
||||||
|
|
||||||
#: apps/logs/apps.py:11
|
#: apps/logs/apps.py:11
|
||||||
msgid "Logs"
|
msgid "Logs"
|
||||||
msgstr ""
|
msgstr "Logs"
|
||||||
|
|
||||||
#: apps/logs/models.py:21 apps/note/models/notes.py:117
|
|
||||||
msgid "user"
|
|
||||||
msgstr "utilisateur"
|
|
||||||
|
|
||||||
#: apps/logs/models.py:27
|
#: apps/logs/models.py:27
|
||||||
msgid "IP Address"
|
msgid "IP Address"
|
||||||
@ -115,11 +221,12 @@ msgstr "Nouvelles données"
|
|||||||
msgid "create"
|
msgid "create"
|
||||||
msgstr "Créer"
|
msgstr "Créer"
|
||||||
|
|
||||||
#: apps/logs/models.py:61 apps/note/tables.py:147
|
#: apps/logs/models.py:61 apps/note/tables.py:142
|
||||||
|
#: templates/activity/activity_detail.html:67
|
||||||
msgid "edit"
|
msgid "edit"
|
||||||
msgstr "Modifier"
|
msgstr "Modifier"
|
||||||
|
|
||||||
#: apps/logs/models.py:62 apps/note/tables.py:151
|
#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:146
|
||||||
msgid "delete"
|
msgid "delete"
|
||||||
msgstr "Supprimer"
|
msgstr "Supprimer"
|
||||||
|
|
||||||
@ -139,61 +246,65 @@ msgstr "Les logs ne peuvent pas être détruits."
|
|||||||
msgid "member"
|
msgid "member"
|
||||||
msgstr "adhérent"
|
msgstr "adhérent"
|
||||||
|
|
||||||
#: apps/member/models.py:25
|
#: apps/member/models.py:26
|
||||||
msgid "phone number"
|
msgid "phone number"
|
||||||
msgstr "numéro de téléphone"
|
msgstr "numéro de téléphone"
|
||||||
|
|
||||||
#: apps/member/models.py:31 templates/member/profile_detail.html:28
|
#: apps/member/models.py:32 templates/member/profile_info.html:27
|
||||||
msgid "section"
|
msgid "section"
|
||||||
msgstr "section"
|
msgstr "section"
|
||||||
|
|
||||||
#: apps/member/models.py:32
|
#: apps/member/models.py:33
|
||||||
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
||||||
msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
|
||||||
|
|
||||||
#: apps/member/models.py:38 templates/member/profile_detail.html:31
|
#: apps/member/models.py:39 templates/member/profile_info.html:30
|
||||||
msgid "address"
|
msgid "address"
|
||||||
msgstr "adresse"
|
msgstr "adresse"
|
||||||
|
|
||||||
#: apps/member/models.py:44
|
#: apps/member/models.py:45
|
||||||
msgid "paid"
|
msgid "paid"
|
||||||
msgstr "payé"
|
msgstr "payé"
|
||||||
|
|
||||||
#: apps/member/models.py:49 apps/member/models.py:50
|
#: apps/member/models.py:50 apps/member/models.py:51
|
||||||
msgid "user profile"
|
msgid "user profile"
|
||||||
msgstr "profil utilisateur"
|
msgstr "profil utilisateur"
|
||||||
|
|
||||||
#: apps/member/models.py:68
|
#: apps/member/models.py:69 templates/member/club_info.html:36
|
||||||
msgid "email"
|
msgid "email"
|
||||||
msgstr "courriel"
|
msgstr "courriel"
|
||||||
|
|
||||||
#: apps/member/models.py:73
|
#: apps/member/models.py:76
|
||||||
|
msgid "parent club"
|
||||||
|
msgstr "club parent"
|
||||||
|
|
||||||
|
#: apps/member/models.py:81 templates/member/club_info.html:30
|
||||||
msgid "membership fee"
|
msgid "membership fee"
|
||||||
msgstr "cotisation pour adhérer"
|
msgstr "cotisation pour adhérer"
|
||||||
|
|
||||||
#: apps/member/models.py:77
|
#: apps/member/models.py:85 templates/member/club_info.html:27
|
||||||
msgid "membership duration"
|
msgid "membership duration"
|
||||||
msgstr "durée de l'adhésion"
|
msgstr "durée de l'adhésion"
|
||||||
|
|
||||||
#: apps/member/models.py:78
|
#: apps/member/models.py:86
|
||||||
msgid "The longest time a membership can last (NULL = infinite)."
|
msgid "The longest time a membership can last (NULL = infinite)."
|
||||||
msgstr "La durée maximale d'une adhésion (NULL = infinie)."
|
msgstr "La durée maximale d'une adhésion (NULL = infinie)."
|
||||||
|
|
||||||
#: apps/member/models.py:83
|
#: apps/member/models.py:91 templates/member/club_info.html:21
|
||||||
msgid "membership start"
|
msgid "membership start"
|
||||||
msgstr "début de l'adhésion"
|
msgstr "début de l'adhésion"
|
||||||
|
|
||||||
#: apps/member/models.py:84
|
#: apps/member/models.py:92
|
||||||
msgid "How long after January 1st the members can renew their membership."
|
msgid "How long after January 1st the members can renew their membership."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
|
"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
|
||||||
"adhésion."
|
"adhésion."
|
||||||
|
|
||||||
#: apps/member/models.py:89
|
#: apps/member/models.py:97 templates/member/club_info.html:24
|
||||||
msgid "membership end"
|
msgid "membership end"
|
||||||
msgstr "fin de l'adhésion"
|
msgstr "fin de l'adhésion"
|
||||||
|
|
||||||
#: apps/member/models.py:90
|
#: apps/member/models.py:98
|
||||||
msgid ""
|
msgid ""
|
||||||
"How long the membership can last after January 1st of the next year after "
|
"How long the membership can last after January 1st of the next year after "
|
||||||
"members can renew their membership."
|
"members can renew their membership."
|
||||||
@ -201,81 +312,68 @@ msgstr ""
|
|||||||
"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
|
"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
|
||||||
"suivante avant que les adhérents peuvent renouveler leur adhésion."
|
"suivante avant que les adhérents peuvent renouveler leur adhésion."
|
||||||
|
|
||||||
#: apps/member/models.py:96 apps/note/models/notes.py:139
|
#: apps/member/models.py:104 apps/note/models/notes.py:139
|
||||||
msgid "club"
|
msgid "club"
|
||||||
msgstr "club"
|
msgstr "club"
|
||||||
|
|
||||||
#: apps/member/models.py:97
|
#: apps/member/models.py:105
|
||||||
msgid "clubs"
|
msgid "clubs"
|
||||||
msgstr "clubs"
|
msgstr "clubs"
|
||||||
|
|
||||||
#: apps/member/models.py:120 apps/permission/models.py:276
|
#: apps/member/models.py:128 apps/permission/models.py:275
|
||||||
msgid "role"
|
msgid "role"
|
||||||
msgstr "rôle"
|
msgstr "rôle"
|
||||||
|
|
||||||
#: apps/member/models.py:121
|
#: apps/member/models.py:129
|
||||||
msgid "roles"
|
msgid "roles"
|
||||||
msgstr "rôles"
|
msgstr "rôles"
|
||||||
|
|
||||||
#: apps/member/models.py:145
|
#: apps/member/models.py:153
|
||||||
msgid "membership starts on"
|
msgid "membership starts on"
|
||||||
msgstr "l'adhésion commence le"
|
msgstr "l'adhésion commence le"
|
||||||
|
|
||||||
#: apps/member/models.py:148
|
#: apps/member/models.py:156
|
||||||
msgid "membership ends on"
|
msgid "membership ends on"
|
||||||
msgstr "l'adhésion finie le"
|
msgstr "l'adhésion finie le"
|
||||||
|
|
||||||
#: apps/member/models.py:152
|
#: apps/member/models.py:160
|
||||||
msgid "fee"
|
msgid "fee"
|
||||||
msgstr "cotisation"
|
msgstr "cotisation"
|
||||||
|
|
||||||
#: apps/member/models.py:162
|
#: apps/member/models.py:172
|
||||||
|
msgid "User is not a member of the parent club"
|
||||||
|
msgstr "L'utilisateur n'est pas membre du club parent"
|
||||||
|
|
||||||
|
#: apps/member/models.py:176
|
||||||
msgid "membership"
|
msgid "membership"
|
||||||
msgstr "adhésion"
|
msgstr "adhésion"
|
||||||
|
|
||||||
#: apps/member/models.py:163
|
#: apps/member/models.py:177
|
||||||
msgid "memberships"
|
msgid "memberships"
|
||||||
msgstr "adhésions"
|
msgstr "adhésions"
|
||||||
|
|
||||||
#: apps/member/views.py:80 templates/member/profile_detail.html:46
|
#: apps/member/views.py:76 templates/member/profile_info.html:45
|
||||||
msgid "Update Profile"
|
msgid "Update Profile"
|
||||||
msgstr "Modifier le profil"
|
msgstr "Modifier le profil"
|
||||||
|
|
||||||
#: apps/member/views.py:93
|
#: apps/member/views.py:89
|
||||||
msgid "An alias with a similar name already exists."
|
msgid "An alias with a similar name already exists."
|
||||||
msgstr "Un alias avec un nom similaire existe déjà."
|
msgstr "Un alias avec un nom similaire existe déjà."
|
||||||
|
|
||||||
#: apps/member/views.py:146
|
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
|
||||||
#, python-format
|
|
||||||
msgid "Account #%(id)s: %(username)s"
|
|
||||||
msgstr "Compte n°%(id)s : %(username)s"
|
|
||||||
|
|
||||||
#: apps/member/views.py:216
|
|
||||||
msgid "Alias successfully deleted"
|
|
||||||
msgstr "L'alias a bien été supprimé"
|
|
||||||
|
|
||||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:95
|
|
||||||
msgid "source"
|
msgid "source"
|
||||||
msgstr "source"
|
msgstr "source"
|
||||||
|
|
||||||
#: apps/note/admin.py:128 apps/note/admin.py:156
|
#: apps/note/admin.py:128 apps/note/admin.py:156
|
||||||
#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
|
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:107
|
||||||
msgid "destination"
|
msgid "destination"
|
||||||
msgstr "destination"
|
msgstr "destination"
|
||||||
|
|
||||||
#: apps/note/apps.py:14 apps/note/models/notes.py:58
|
#: apps/note/forms.py:14
|
||||||
msgid "note"
|
|
||||||
msgstr "note"
|
|
||||||
|
|
||||||
#: apps/note/forms.py:20
|
|
||||||
msgid "New Alias"
|
|
||||||
msgstr "Nouvel alias"
|
|
||||||
|
|
||||||
#: apps/note/forms.py:25
|
|
||||||
msgid "select an image"
|
msgid "select an image"
|
||||||
msgstr "Choisissez une image"
|
msgstr "Choisissez une image"
|
||||||
|
|
||||||
#: apps/note/forms.py:26
|
#: apps/note/forms.py:15
|
||||||
msgid "Maximal size: 2MB"
|
msgid "Maximal size: 2MB"
|
||||||
msgstr "Taille maximale : 2 Mo"
|
msgstr "Taille maximale : 2 Mo"
|
||||||
|
|
||||||
@ -310,7 +408,7 @@ msgstr ""
|
|||||||
msgid "display image"
|
msgid "display image"
|
||||||
msgstr "image affichée"
|
msgstr "image affichée"
|
||||||
|
|
||||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
|
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:117
|
||||||
msgid "created at"
|
msgid "created at"
|
||||||
msgstr "créée le"
|
msgstr "créée le"
|
||||||
|
|
||||||
@ -318,10 +416,6 @@ msgstr "créée le"
|
|||||||
msgid "notes"
|
msgid "notes"
|
||||||
msgstr "notes"
|
msgstr "notes"
|
||||||
|
|
||||||
#: apps/note/models/notes.py:67
|
|
||||||
msgid "Note"
|
|
||||||
msgstr "Note"
|
|
||||||
|
|
||||||
#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
|
#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
|
||||||
msgid "This alias is already taken."
|
msgid "This alias is already taken."
|
||||||
msgstr "Cet alias est déjà pris."
|
msgstr "Cet alias est déjà pris."
|
||||||
@ -368,7 +462,8 @@ msgstr "Alias invalide"
|
|||||||
msgid "alias"
|
msgid "alias"
|
||||||
msgstr "alias"
|
msgstr "alias"
|
||||||
|
|
||||||
#: apps/note/models/notes.py:211 templates/member/profile_detail.html:37
|
#: apps/note/models/notes.py:211 templates/member/club_info.html:33
|
||||||
|
#: templates/member/profile_info.html:36
|
||||||
msgid "aliases"
|
msgid "aliases"
|
||||||
msgstr "alias"
|
msgstr "alias"
|
||||||
|
|
||||||
@ -380,102 +475,114 @@ msgstr "L'alias est trop long."
|
|||||||
msgid "An alias with a similar name already exists: {} "
|
msgid "An alias with a similar name already exists: {} "
|
||||||
msgstr "Un alias avec un nom similaire existe déjà : {}"
|
msgstr "Un alias avec un nom similaire existe déjà : {}"
|
||||||
|
|
||||||
#: apps/note/models/notes.py:247
|
#: apps/note/models/notes.py:251
|
||||||
msgid "You can't delete your main alias."
|
msgid "You can't delete your main alias."
|
||||||
msgstr "Vous ne pouvez pas supprimer votre alias principal."
|
msgstr "Vous ne pouvez pas supprimer votre alias principal."
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:31
|
#: apps/note/models/transactions.py:30
|
||||||
msgid "transaction category"
|
msgid "transaction category"
|
||||||
msgstr "catégorie de transaction"
|
msgstr "catégorie de transaction"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:32
|
#: apps/note/models/transactions.py:31
|
||||||
msgid "transaction categories"
|
msgid "transaction categories"
|
||||||
msgstr "catégories de transaction"
|
msgstr "catégories de transaction"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:48
|
#: apps/note/models/transactions.py:47
|
||||||
msgid "A template with this name already exist"
|
msgid "A template with this name already exist"
|
||||||
msgstr "Un modèle de transaction avec un nom similaire existe déjà."
|
msgstr "Un modèle de transaction avec un nom similaire existe déjà."
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
|
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:125
|
||||||
msgid "amount"
|
msgid "amount"
|
||||||
msgstr "montant"
|
msgstr "montant"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:58
|
#: apps/note/models/transactions.py:57
|
||||||
msgid "in centimes"
|
msgid "in centimes"
|
||||||
msgstr "en centimes"
|
msgstr "en centimes"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:76
|
#: apps/note/models/transactions.py:75
|
||||||
msgid "transaction template"
|
msgid "transaction template"
|
||||||
msgstr "modèle de transaction"
|
msgstr "modèle de transaction"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:77
|
#: apps/note/models/transactions.py:76
|
||||||
msgid "transaction templates"
|
msgid "transaction templates"
|
||||||
msgstr "modèles de transaction"
|
msgstr "modèles de transaction"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
|
#: apps/note/models/transactions.py:100 apps/note/models/transactions.py:113
|
||||||
#: apps/note/tables.py:33 apps/note/tables.py:42
|
#: apps/note/tables.py:33 apps/note/tables.py:42
|
||||||
msgid "used alias"
|
msgid "used alias"
|
||||||
msgstr "alias utilisé"
|
msgstr "alias utilisé"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:122
|
#: apps/note/models/transactions.py:121
|
||||||
msgid "quantity"
|
msgid "quantity"
|
||||||
msgstr "quantité"
|
msgstr "quantité"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:115
|
#: apps/note/models/transactions.py:129
|
||||||
msgid "reason"
|
msgid "reason"
|
||||||
msgstr "raison"
|
msgstr "raison"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:119
|
#: apps/note/models/transactions.py:139 apps/note/tables.py:95
|
||||||
msgid "valid"
|
msgid "invalidity reason"
|
||||||
msgstr "valide"
|
msgstr "Motif d'invalidité"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:124
|
#: apps/note/models/transactions.py:146
|
||||||
msgid "transaction"
|
msgid "transaction"
|
||||||
msgstr "transaction"
|
msgstr "transaction"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:125
|
#: apps/note/models/transactions.py:147
|
||||||
msgid "transactions"
|
msgid "transactions"
|
||||||
msgstr "transactions"
|
msgstr "transactions"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:168 templates/base.html:98
|
#: apps/note/models/transactions.py:201 templates/base.html:84
|
||||||
#: templates/note/transaction_form.html:19
|
#: templates/note/transaction_form.html:19
|
||||||
#: templates/note/transaction_form.html:145
|
#: templates/note/transaction_form.html:140
|
||||||
msgid "Transfer"
|
msgid "Transfer"
|
||||||
msgstr "Virement"
|
msgstr "Virement"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:188
|
#: apps/note/models/transactions.py:221
|
||||||
msgid "Template"
|
msgid "Template"
|
||||||
msgstr "Bouton"
|
msgstr "Bouton"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:203
|
#: apps/note/models/transactions.py:236
|
||||||
msgid "first_name"
|
msgid "first_name"
|
||||||
msgstr "prénom"
|
msgstr "prénom"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:208
|
#: apps/note/models/transactions.py:241
|
||||||
msgid "bank"
|
msgid "bank"
|
||||||
msgstr "banque"
|
msgstr "banque"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:24
|
#: apps/note/models/transactions.py:247 templates/note/transaction_form.html:24
|
||||||
msgid "Credit"
|
msgid "Credit"
|
||||||
msgstr "Crédit"
|
msgstr "Crédit"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:28
|
#: apps/note/models/transactions.py:247 templates/note/transaction_form.html:28
|
||||||
msgid "Debit"
|
msgid "Debit"
|
||||||
msgstr "Débit"
|
msgstr "Débit"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:230 apps/note/models/transactions.py:235
|
#: apps/note/models/transactions.py:263 apps/note/models/transactions.py:268
|
||||||
msgid "membership transaction"
|
msgid "membership transaction"
|
||||||
msgstr "transaction d'adhésion"
|
msgstr "transaction d'adhésion"
|
||||||
|
|
||||||
#: apps/note/models/transactions.py:231
|
#: apps/note/models/transactions.py:264
|
||||||
msgid "membership transactions"
|
msgid "membership transactions"
|
||||||
msgstr "transactions d'adhésion"
|
msgstr "transactions d'adhésion"
|
||||||
|
|
||||||
#: apps/note/views.py:39
|
#: apps/note/tables.py:57
|
||||||
|
msgid "Click to invalidate"
|
||||||
|
msgstr "Cliquez pour dévalider"
|
||||||
|
|
||||||
|
#: apps/note/tables.py:57
|
||||||
|
msgid "Click to validate"
|
||||||
|
msgstr "Cliquez pour valider"
|
||||||
|
|
||||||
|
#: apps/note/tables.py:93
|
||||||
|
msgid "No reason specified"
|
||||||
|
msgstr "Pas de motif spécifié"
|
||||||
|
|
||||||
|
#: apps/note/views.py:41
|
||||||
msgid "Transfer money"
|
msgid "Transfer money"
|
||||||
msgstr "Transférer de l'argent"
|
msgstr "Transférer de l'argent"
|
||||||
|
|
||||||
#: apps/note/views.py:145 templates/base.html:79
|
#: apps/note/views.py:102 templates/base.html:79
|
||||||
msgid "Consumptions"
|
msgid "Consumptions"
|
||||||
msgstr "Consommations"
|
msgstr "Consommations"
|
||||||
|
|
||||||
@ -497,41 +604,35 @@ msgstr "Rang"
|
|||||||
msgid "Specifying field applies only to view and change permission types."
|
msgid "Specifying field applies only to view and change permission types."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/treasury/apps.py:11 templates/base.html:102
|
#: apps/treasury/apps.py:12 templates/base.html:99
|
||||||
msgid "Treasury"
|
msgid "Treasury"
|
||||||
msgstr "Trésorerie"
|
msgstr "Trésorerie"
|
||||||
|
|
||||||
#: apps/treasury/forms.py:56 apps/treasury/forms.py:95
|
#: apps/treasury/forms.py:84 apps/treasury/forms.py:132
|
||||||
|
#: templates/activity/activity_form.html:9
|
||||||
|
#: templates/activity/activity_invite.html:8
|
||||||
#: templates/django_filters/rest_framework/form.html:5
|
#: templates/django_filters/rest_framework/form.html:5
|
||||||
#: templates/member/club_form.html:10 templates/treasury/invoice_form.html:47
|
#: templates/member/club_form.html:9 templates/treasury/invoice_form.html:46
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr "Envoyer"
|
msgstr "Envoyer"
|
||||||
|
|
||||||
#: apps/treasury/forms.py:58
|
#: apps/treasury/forms.py:86
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Fermer"
|
msgstr "Fermer"
|
||||||
|
|
||||||
#: apps/treasury/forms.py:65
|
#: apps/treasury/forms.py:95
|
||||||
msgid "Remittance is already closed."
|
msgid "Remittance is already closed."
|
||||||
msgstr "La remise est déjà fermée."
|
msgstr "La remise est déjà fermée."
|
||||||
|
|
||||||
#: apps/treasury/forms.py:70
|
#: apps/treasury/forms.py:100
|
||||||
msgid "You can't change the type of the remittance."
|
msgid "You can't change the type of the remittance."
|
||||||
msgstr "Vous ne pouvez pas changer le type de la remise."
|
msgstr "Vous ne pouvez pas changer le type de la remise."
|
||||||
|
|
||||||
#: apps/treasury/forms.py:84
|
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:98
|
||||||
msgid "Last name"
|
|
||||||
msgstr "Nom de famille"
|
|
||||||
|
|
||||||
#: apps/treasury/forms.py:86 templates/note/transaction_form.html:92
|
|
||||||
msgid "First name"
|
|
||||||
msgstr "Prénom"
|
|
||||||
|
|
||||||
#: apps/treasury/forms.py:88 templates/note/transaction_form.html:98
|
|
||||||
msgid "Bank"
|
msgid "Bank"
|
||||||
msgstr "Banque"
|
msgstr "Banque"
|
||||||
|
|
||||||
#: apps/treasury/forms.py:90 apps/treasury/tables.py:40
|
#: apps/treasury/forms.py:126 apps/treasury/tables.py:47
|
||||||
#: templates/note/transaction_form.html:128
|
#: templates/note/transaction_form.html:128
|
||||||
#: templates/treasury/remittance_form.html:18
|
#: templates/treasury/remittance_form.html:18
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
@ -585,10 +686,6 @@ msgstr "Prix unitaire"
|
|||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Date"
|
msgstr "Date"
|
||||||
|
|
||||||
#: apps/treasury/models.py:126
|
|
||||||
msgid "Type"
|
|
||||||
msgstr "Type"
|
|
||||||
|
|
||||||
#: apps/treasury/models.py:131
|
#: apps/treasury/models.py:131
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Commentaire"
|
msgstr "Commentaire"
|
||||||
@ -597,38 +694,38 @@ msgstr "Commentaire"
|
|||||||
msgid "Closed"
|
msgid "Closed"
|
||||||
msgstr "Fermée"
|
msgstr "Fermée"
|
||||||
|
|
||||||
#: apps/treasury/models.py:159
|
#: apps/treasury/models.py:169
|
||||||
msgid "Remittance #{:d}: {}"
|
msgid "Remittance #{:d}: {}"
|
||||||
msgstr "Remise n°{:d} : {}"
|
msgstr "Remise n°{:d} : {}"
|
||||||
|
|
||||||
#: apps/treasury/models.py:178 apps/treasury/tables.py:64
|
#: apps/treasury/models.py:188 apps/treasury/tables.py:76
|
||||||
#: apps/treasury/tables.py:72 templates/treasury/invoice_list.html:13
|
#: apps/treasury/tables.py:84 templates/treasury/invoice_list.html:13
|
||||||
#: templates/treasury/remittance_list.html:13
|
#: templates/treasury/remittance_list.html:13
|
||||||
msgid "Remittance"
|
msgid "Remittance"
|
||||||
msgstr "Remise"
|
msgstr "Remise"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:16
|
#: apps/treasury/tables.py:19
|
||||||
msgid "Invoice #{:d}"
|
msgid "Invoice #{:d}"
|
||||||
msgstr "Facture n°{:d}"
|
msgstr "Facture n°{:d}"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10
|
#: apps/treasury/tables.py:22 templates/treasury/invoice_list.html:10
|
||||||
#: templates/treasury/remittance_list.html:10
|
#: templates/treasury/remittance_list.html:10
|
||||||
msgid "Invoice"
|
msgid "Invoice"
|
||||||
msgstr "Facture"
|
msgstr "Facture"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:38
|
#: apps/treasury/tables.py:45
|
||||||
msgid "Transaction count"
|
msgid "Transaction count"
|
||||||
msgstr "Nombre de transactions"
|
msgstr "Nombre de transactions"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:43 apps/treasury/tables.py:45
|
#: apps/treasury/tables.py:50 apps/treasury/tables.py:52
|
||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Voir"
|
msgstr "Voir"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:66
|
#: apps/treasury/tables.py:78
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr "Ajouter"
|
msgstr "Ajouter"
|
||||||
|
|
||||||
#: apps/treasury/tables.py:74
|
#: apps/treasury/tables.py:86
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "supprimer"
|
msgstr "supprimer"
|
||||||
|
|
||||||
@ -639,30 +736,86 @@ msgid ""
|
|||||||
"again unless your session expires or you logout."
|
"again unless your session expires or you logout."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:151
|
#: note_kfet/settings/base.py:152
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:152
|
#: note_kfet/settings/base.py:153
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: note_kfet/settings/base.py:153
|
#: note_kfet/settings/base.py:154
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:29
|
||||||
|
msgid "creater"
|
||||||
|
msgstr "Créateur"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:50
|
||||||
|
msgid "opened"
|
||||||
|
msgstr "ouvert"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:57
|
||||||
|
msgid "Entry page"
|
||||||
|
msgstr "Page des entrées"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:61
|
||||||
|
msgid "close"
|
||||||
|
msgstr "fermer"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:64
|
||||||
|
msgid "invalidate"
|
||||||
|
msgstr "dévalider"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:64
|
||||||
|
msgid "validate"
|
||||||
|
msgstr "valider"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:70
|
||||||
|
msgid "Invite"
|
||||||
|
msgstr "Inviter"
|
||||||
|
|
||||||
|
#: templates/activity/activity_detail.html:77
|
||||||
|
msgid "Guests list"
|
||||||
|
msgstr "Liste des invités"
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:10
|
||||||
|
msgid "Return to activity page"
|
||||||
|
msgstr "Retour à la page de l'activité"
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:18
|
||||||
|
msgid "entries"
|
||||||
|
msgstr "entrées"
|
||||||
|
|
||||||
|
#: templates/activity/activity_entry.html:18
|
||||||
|
msgid "entry"
|
||||||
|
msgstr "entrée"
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:5
|
||||||
|
msgid "Upcoming activities"
|
||||||
|
msgstr "Activités à venir"
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:10
|
||||||
|
msgid "There is no planned activity."
|
||||||
|
msgstr "Il n'y a pas d'activité prévue."
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:14
|
||||||
|
msgid "New activity"
|
||||||
|
msgstr "Nouvelle activité"
|
||||||
|
|
||||||
|
#: templates/activity/activity_list.html:18
|
||||||
|
msgid "All activities"
|
||||||
|
msgstr "Toutes les activités"
|
||||||
|
|
||||||
#: templates/base.html:13
|
#: templates/base.html:13
|
||||||
msgid "The ENS Paris-Saclay BDE note."
|
msgid "The ENS Paris-Saclay BDE note."
|
||||||
msgstr "La note du BDE de l'ENS Paris-Saclay."
|
msgstr "La note du BDE de l'ENS Paris-Saclay."
|
||||||
|
|
||||||
#: templates/base.html:87
|
#: templates/base.html:89
|
||||||
msgid "Clubs"
|
msgid "Clubs"
|
||||||
msgstr "Clubs"
|
msgstr "Clubs"
|
||||||
|
|
||||||
#: templates/base.html:92
|
|
||||||
msgid "Activities"
|
|
||||||
msgstr "Activités"
|
|
||||||
|
|
||||||
#: templates/cas_server/base.html:7
|
#: templates/cas_server/base.html:7
|
||||||
msgid "Central Authentication Service"
|
msgid "Central Authentication Service"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -720,33 +873,49 @@ msgstr ""
|
|||||||
msgid "Field filters"
|
msgid "Field filters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/member/club_detail.html:10
|
#: templates/member/alias_update.html:5
|
||||||
msgid "Membership starts on"
|
msgid "Add alias"
|
||||||
msgstr "L'adhésion commence le"
|
msgstr "Ajouter un alias"
|
||||||
|
|
||||||
#: templates/member/club_detail.html:12
|
#: templates/member/club_info.html:17
|
||||||
msgid "Membership ends on"
|
msgid "Club Parent"
|
||||||
msgstr "L'adhésion finie le"
|
msgstr "Club parent"
|
||||||
|
|
||||||
#: templates/member/club_detail.html:14
|
#: templates/member/club_info.html:41
|
||||||
msgid "Membership duration"
|
msgid "Add member"
|
||||||
msgstr "Durée de l'adhésion"
|
msgstr "Ajouter un membre"
|
||||||
|
|
||||||
#: templates/member/club_detail.html:18 templates/member/profile_detail.html:34
|
#: templates/member/club_info.html:42 templates/note/conso_form.html:121
|
||||||
msgid "balance"
|
msgid "Edit"
|
||||||
msgstr "solde du compte"
|
msgstr "Éditer"
|
||||||
|
|
||||||
#: templates/member/club_detail.html:51 templates/member/profile_detail.html:75
|
#: templates/member/club_info.html:43
|
||||||
msgid "Transaction history"
|
msgid "Add roles"
|
||||||
msgstr "Historique des transactions"
|
msgstr "Ajouter des rôles"
|
||||||
|
|
||||||
#: templates/member/club_form.html:6
|
#: templates/member/club_info.html:46 templates/member/profile_info.html:48
|
||||||
msgid "Clubs list"
|
msgid "View Profile"
|
||||||
msgstr "Liste des clubs"
|
msgstr "Voir le profil"
|
||||||
|
|
||||||
#: templates/member/club_list.html:8
|
#: templates/member/club_list.html:8
|
||||||
msgid "New club"
|
msgid "search clubs"
|
||||||
msgstr "Nouveau club"
|
msgstr "Chercher un club"
|
||||||
|
|
||||||
|
#: templates/member/club_list.html:12
|
||||||
|
msgid "Créer un club"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/member/club_list.html:19
|
||||||
|
msgid "club listing "
|
||||||
|
msgstr "Liste des clubs"
|
||||||
|
|
||||||
|
#: templates/member/club_tables.html:9
|
||||||
|
msgid "Member of the Club"
|
||||||
|
msgstr "Membre du club"
|
||||||
|
|
||||||
|
#: templates/member/club_tables.html:22 templates/member/profile_tables.html:22
|
||||||
|
msgid "Transaction history"
|
||||||
|
msgstr "Historique des transactions"
|
||||||
|
|
||||||
#: templates/member/manage_auth_tokens.html:16
|
#: templates/member/manage_auth_tokens.html:16
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
@ -760,35 +929,31 @@ msgstr "Créé le"
|
|||||||
msgid "Regenerate token"
|
msgid "Regenerate token"
|
||||||
msgstr "Regénérer le jeton"
|
msgstr "Regénérer le jeton"
|
||||||
|
|
||||||
#: templates/member/profile_alias.html:10
|
#: templates/member/profile_info.html:5
|
||||||
msgid "Add alias"
|
msgid "Account #"
|
||||||
msgstr "Ajouter un alias"
|
msgstr "Compte n°"
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:15
|
#: templates/member/profile_info.html:17
|
||||||
msgid "first name"
|
|
||||||
msgstr "prénom"
|
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:18
|
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr "pseudo"
|
msgstr "pseudo"
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:21
|
#: templates/member/profile_info.html:20
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr "mot de passe"
|
msgstr "mot de passe"
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:24
|
#: templates/member/profile_info.html:23
|
||||||
msgid "Change password"
|
msgid "Change password"
|
||||||
msgstr "Changer le mot de passe"
|
msgstr "Changer le mot de passe"
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:42
|
#: templates/member/profile_info.html:33
|
||||||
|
msgid "balance"
|
||||||
|
msgstr "solde du compte"
|
||||||
|
|
||||||
|
#: templates/member/profile_info.html:41
|
||||||
msgid "Manage auth token"
|
msgid "Manage auth token"
|
||||||
msgstr "Gérer les jetons d'authentification"
|
msgstr "Gérer les jetons d'authentification"
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:49
|
#: templates/member/profile_tables.html:9
|
||||||
msgid "View Profile"
|
|
||||||
msgstr "Voir le profil"
|
|
||||||
|
|
||||||
#: templates/member/profile_detail.html:62
|
|
||||||
msgid "View my memberships"
|
msgid "View my memberships"
|
||||||
msgstr "Voir mes adhésions"
|
msgstr "Voir mes adhésions"
|
||||||
|
|
||||||
@ -817,10 +982,6 @@ msgstr "Consommer !"
|
|||||||
msgid "Most used buttons"
|
msgid "Most used buttons"
|
||||||
msgstr "Boutons les plus utilisés"
|
msgstr "Boutons les plus utilisés"
|
||||||
|
|
||||||
#: templates/note/conso_form.html:121
|
|
||||||
msgid "Edit"
|
|
||||||
msgstr "Éditer"
|
|
||||||
|
|
||||||
#: templates/note/conso_form.html:126
|
#: templates/note/conso_form.html:126
|
||||||
msgid "Single consumptions"
|
msgid "Single consumptions"
|
||||||
msgstr "Consommations simples"
|
msgstr "Consommations simples"
|
||||||
@ -829,7 +990,7 @@ msgstr "Consommations simples"
|
|||||||
msgid "Double consumptions"
|
msgid "Double consumptions"
|
||||||
msgstr "Consommations doubles"
|
msgstr "Consommations doubles"
|
||||||
|
|
||||||
#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152
|
#: templates/note/conso_form.html:141 templates/note/transaction_form.html:147
|
||||||
msgid "Recent transactions history"
|
msgid "Recent transactions history"
|
||||||
msgstr "Historique des transactions récentes"
|
msgstr "Historique des transactions récentes"
|
||||||
|
|
||||||
@ -845,37 +1006,21 @@ msgstr "Paiement externe"
|
|||||||
msgid "Transfer type"
|
msgid "Transfer type"
|
||||||
msgstr "Type de transfert"
|
msgstr "Type de transfert"
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:86
|
|
||||||
msgid "Name"
|
|
||||||
msgstr "Nom"
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:92
|
|
||||||
msgid "First name"
|
|
||||||
msgstr "Prénom"
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:98
|
|
||||||
msgid "Bank"
|
|
||||||
msgstr "Banque"
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:111
|
#: templates/note/transaction_form.html:111
|
||||||
#: templates/note/transaction_form.html:169
|
#: templates/note/transaction_form.html:164
|
||||||
#: templates/note/transaction_form.html:176
|
#: templates/note/transaction_form.html:171
|
||||||
msgid "Select receivers"
|
msgid "Select receivers"
|
||||||
msgstr "Sélection des destinataires"
|
msgstr "Sélection des destinataires"
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:128
|
#: templates/note/transaction_form.html:133
|
||||||
msgid "Amount"
|
|
||||||
msgstr "Montant"
|
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:138
|
|
||||||
msgid "Reason"
|
msgid "Reason"
|
||||||
msgstr "Raison"
|
msgstr "Raison"
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:183
|
#: templates/note/transaction_form.html:178
|
||||||
msgid "Credit note"
|
msgid "Credit note"
|
||||||
msgstr "Note à recharger"
|
msgstr "Note à recharger"
|
||||||
|
|
||||||
#: templates/note/transaction_form.html:190
|
#: templates/note/transaction_form.html:185
|
||||||
msgid "Debit note"
|
msgid "Debit note"
|
||||||
msgstr "Note à débiter"
|
msgstr "Note à débiter"
|
||||||
|
|
||||||
@ -887,6 +1032,10 @@ msgstr "Liste des boutons"
|
|||||||
msgid "search button"
|
msgid "search button"
|
||||||
msgstr "Chercher un bouton"
|
msgstr "Chercher un bouton"
|
||||||
|
|
||||||
|
#: templates/note/transactiontemplate_list.html:13
|
||||||
|
msgid "New button"
|
||||||
|
msgstr "Nouveau bouton"
|
||||||
|
|
||||||
#: templates/note/transactiontemplate_list.html:20
|
#: templates/note/transactiontemplate_list.html:20
|
||||||
msgid "buttons listing "
|
msgid "buttons listing "
|
||||||
msgstr "Liste des boutons"
|
msgstr "Liste des boutons"
|
||||||
@ -989,11 +1138,11 @@ msgstr ""
|
|||||||
msgid "Invoices list"
|
msgid "Invoices list"
|
||||||
msgstr "Liste des factures"
|
msgstr "Liste des factures"
|
||||||
|
|
||||||
#: templates/treasury/invoice_form.html:42
|
#: templates/treasury/invoice_form.html:41
|
||||||
msgid "Add product"
|
msgid "Add product"
|
||||||
msgstr "Ajouter produit"
|
msgstr "Ajouter produit"
|
||||||
|
|
||||||
#: templates/treasury/invoice_form.html:43
|
#: templates/treasury/invoice_form.html:42
|
||||||
msgid "Remove product"
|
msgid "Remove product"
|
||||||
msgstr "Retirer produit"
|
msgstr "Retirer produit"
|
||||||
|
|
||||||
|
302
note_kfet/inputs.py
Normal file
302
note_kfet/inputs.py
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from json import dumps as json_dumps
|
||||||
|
|
||||||
|
from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput
|
||||||
|
|
||||||
|
|
||||||
|
class AmountInput(NumberInput):
|
||||||
|
"""
|
||||||
|
This input type lets the user type amounts in euros, but forms receive data in cents
|
||||||
|
"""
|
||||||
|
template_name = "note/amount_input.html"
|
||||||
|
|
||||||
|
def format_value(self, value):
|
||||||
|
return None if value is None or value == "" else "{:.02f}".format(value / 100, )
|
||||||
|
|
||||||
|
def value_from_datadict(self, data, files, name):
|
||||||
|
val = super().value_from_datadict(data, files, name)
|
||||||
|
return str(int(100 * float(val))) if val else val
|
||||||
|
|
||||||
|
|
||||||
|
class Autocomplete(TextInput):
|
||||||
|
template_name = "member/autocomplete_model.html"
|
||||||
|
|
||||||
|
def __init__(self, model, attrs=None):
|
||||||
|
super().__init__(attrs)
|
||||||
|
|
||||||
|
self.model = model
|
||||||
|
self.model_pk = None
|
||||||
|
|
||||||
|
class Media:
|
||||||
|
"""JS/CSS resources needed to render the date-picker calendar."""
|
||||||
|
|
||||||
|
js = ('js/autocomplete_model.js', )
|
||||||
|
|
||||||
|
def format_value(self, value):
|
||||||
|
if value:
|
||||||
|
self.attrs["model_pk"] = int(value)
|
||||||
|
return str(self.model.objects.get(pk=int(value)))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
The remaining of this file comes from the project `django-bootstrap-datepicker-plus` available on Github:
|
||||||
|
https://github.com/monim67/django-bootstrap-datepicker-plus
|
||||||
|
This is distributed under Apache License 2.0.
|
||||||
|
|
||||||
|
This adds datetime pickers with bootstrap.
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""Contains Base Date-Picker input class for widgets of this package."""
|
||||||
|
|
||||||
|
|
||||||
|
class DatePickerDictionary:
|
||||||
|
"""Keeps track of all date-picker input classes."""
|
||||||
|
|
||||||
|
_i = 0
|
||||||
|
items = dict()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_id(cls):
|
||||||
|
"""Return a unique ID for each date-picker input class."""
|
||||||
|
cls._i += 1
|
||||||
|
return 'dp_%s' % cls._i
|
||||||
|
|
||||||
|
|
||||||
|
class BasePickerInput(DateTimeBaseInput):
|
||||||
|
"""Base Date-Picker input class for widgets of this package."""
|
||||||
|
|
||||||
|
template_name = 'bootstrap_datepicker_plus/date_picker.html'
|
||||||
|
picker_type = 'DATE'
|
||||||
|
format = '%Y-%m-%d'
|
||||||
|
config = {}
|
||||||
|
_default_config = {
|
||||||
|
'id': None,
|
||||||
|
'picker_type': None,
|
||||||
|
'linked_to': None,
|
||||||
|
'options': {} # final merged options
|
||||||
|
}
|
||||||
|
options = {} # options extended by user
|
||||||
|
options_param = {} # options passed as parameter
|
||||||
|
_default_options = {
|
||||||
|
'showClose': True,
|
||||||
|
'showClear': True,
|
||||||
|
'showTodayButton': True,
|
||||||
|
"locale": "fr",
|
||||||
|
}
|
||||||
|
|
||||||
|
# source: https://github.com/tutorcruncher/django-bootstrap3-datetimepicker
|
||||||
|
# file: /blob/31fbb09/bootstrap3_datetime/widgets.py#L33
|
||||||
|
format_map = (
|
||||||
|
('DDD', r'%j'),
|
||||||
|
('DD', r'%d'),
|
||||||
|
('MMMM', r'%B'),
|
||||||
|
('MMM', r'%b'),
|
||||||
|
('MM', r'%m'),
|
||||||
|
('YYYY', r'%Y'),
|
||||||
|
('YY', r'%y'),
|
||||||
|
('HH', r'%H'),
|
||||||
|
('hh', r'%I'),
|
||||||
|
('mm', r'%M'),
|
||||||
|
('ss', r'%S'),
|
||||||
|
('a', r'%p'),
|
||||||
|
('ZZ', r'%z'),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Media:
|
||||||
|
"""JS/CSS resources needed to render the date-picker calendar."""
|
||||||
|
|
||||||
|
js = (
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/'
|
||||||
|
'moment-with-locales.min.js',
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/'
|
||||||
|
'4.17.47/js/bootstrap-datetimepicker.min.js',
|
||||||
|
'bootstrap_datepicker_plus/js/datepicker-widget.js'
|
||||||
|
)
|
||||||
|
css = {'all': (
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/'
|
||||||
|
'4.17.47/css/bootstrap-datetimepicker.css',
|
||||||
|
'bootstrap_datepicker_plus/css/datepicker-widget.css'
|
||||||
|
), }
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def format_py2js(cls, datetime_format):
|
||||||
|
"""Convert python datetime format to moment datetime format."""
|
||||||
|
for js_format, py_format in cls.format_map:
|
||||||
|
datetime_format = datetime_format.replace(py_format, js_format)
|
||||||
|
return datetime_format
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def format_js2py(cls, datetime_format):
|
||||||
|
"""Convert moment datetime format to python datetime format."""
|
||||||
|
for js_format, py_format in cls.format_map:
|
||||||
|
datetime_format = datetime_format.replace(js_format, py_format)
|
||||||
|
return datetime_format
|
||||||
|
|
||||||
|
def __init__(self, attrs=None, format=None, options=None):
|
||||||
|
"""Initialize the Date-picker widget."""
|
||||||
|
self.format_param = format
|
||||||
|
self.options_param = options if options else {}
|
||||||
|
self.config = self._default_config.copy()
|
||||||
|
self.config['id'] = DatePickerDictionary.generate_id()
|
||||||
|
self.config['picker_type'] = self.picker_type
|
||||||
|
self.config['options'] = self._calculate_options()
|
||||||
|
attrs = attrs if attrs else {}
|
||||||
|
if 'class' not in attrs:
|
||||||
|
attrs['class'] = 'form-control'
|
||||||
|
super().__init__(attrs, self._calculate_format())
|
||||||
|
|
||||||
|
def _calculate_options(self):
|
||||||
|
"""Calculate and Return the options."""
|
||||||
|
_options = self._default_options.copy()
|
||||||
|
_options.update(self.options)
|
||||||
|
if self.options_param:
|
||||||
|
_options.update(self.options_param)
|
||||||
|
return _options
|
||||||
|
|
||||||
|
def _calculate_format(self):
|
||||||
|
"""Calculate and Return the datetime format."""
|
||||||
|
_format = self.format_param if self.format_param else self.format
|
||||||
|
if self.config['options'].get('format'):
|
||||||
|
_format = self.format_js2py(self.config['options'].get('format'))
|
||||||
|
else:
|
||||||
|
self.config['options']['format'] = self.format_py2js(_format)
|
||||||
|
return _format
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
"""Return widget context dictionary."""
|
||||||
|
context = super().get_context(
|
||||||
|
name, value, attrs)
|
||||||
|
context['widget']['attrs']['dp_config'] = json_dumps(self.config)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def start_of(self, event_id):
|
||||||
|
"""
|
||||||
|
Set Date-Picker as the start-date of a date-range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- event_id (string): User-defined unique id for linking two fields
|
||||||
|
"""
|
||||||
|
DatePickerDictionary.items[str(event_id)] = self
|
||||||
|
return self
|
||||||
|
|
||||||
|
def end_of(self, event_id, import_options=True):
|
||||||
|
"""
|
||||||
|
Set Date-Picker as the end-date of a date-range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- event_id (string): User-defined unique id for linking two fields
|
||||||
|
- import_options (bool): inherit options from start-date input,
|
||||||
|
default: TRUE
|
||||||
|
"""
|
||||||
|
event_id = str(event_id)
|
||||||
|
if event_id in DatePickerDictionary.items:
|
||||||
|
linked_picker = DatePickerDictionary.items[event_id]
|
||||||
|
self.config['linked_to'] = linked_picker.config['id']
|
||||||
|
if import_options:
|
||||||
|
backup_moment_format = self.config['options']['format']
|
||||||
|
self.config['options'].update(linked_picker.config['options'])
|
||||||
|
self.config['options'].update(self.options_param)
|
||||||
|
if self.format_param or 'format' in self.options_param:
|
||||||
|
self.config['options']['format'] = backup_moment_format
|
||||||
|
else:
|
||||||
|
self.format = linked_picker.format
|
||||||
|
# Setting useCurrent is necessary, see following issue
|
||||||
|
# https://github.com/Eonasdan/bootstrap-datetimepicker/issues/1075
|
||||||
|
self.config['options']['useCurrent'] = False
|
||||||
|
self._link_to(linked_picker)
|
||||||
|
else:
|
||||||
|
raise KeyError(
|
||||||
|
'start-date not specified for event_id "%s"' % event_id)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def _link_to(self, linked_picker):
|
||||||
|
"""
|
||||||
|
Executed when two date-inputs are linked together.
|
||||||
|
|
||||||
|
This method for sub-classes to override to customize the linking.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DatePickerInput(BasePickerInput):
|
||||||
|
"""
|
||||||
|
Widget to display a Date-Picker Calendar on a DateField property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- attrs (dict): HTML attributes of rendered HTML input
|
||||||
|
- format (string): Python DateTime format eg. "%Y-%m-%d"
|
||||||
|
- options (dict): Options to customize the widget, see README
|
||||||
|
"""
|
||||||
|
|
||||||
|
picker_type = 'DATE'
|
||||||
|
format = '%Y-%m-%d'
|
||||||
|
format_key = 'DATE_INPUT_FORMATS'
|
||||||
|
|
||||||
|
|
||||||
|
class TimePickerInput(BasePickerInput):
|
||||||
|
"""
|
||||||
|
Widget to display a Time-Picker Calendar on a TimeField property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- attrs (dict): HTML attributes of rendered HTML input
|
||||||
|
- format (string): Python DateTime format eg. "%Y-%m-%d"
|
||||||
|
- options (dict): Options to customize the widget, see README
|
||||||
|
"""
|
||||||
|
|
||||||
|
picker_type = 'TIME'
|
||||||
|
format = '%H:%M'
|
||||||
|
format_key = 'TIME_INPUT_FORMATS'
|
||||||
|
template_name = 'bootstrap_datepicker_plus/time_picker.html'
|
||||||
|
|
||||||
|
|
||||||
|
class DateTimePickerInput(BasePickerInput):
|
||||||
|
"""
|
||||||
|
Widget to display a DateTime-Picker Calendar on a DateTimeField property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- attrs (dict): HTML attributes of rendered HTML input
|
||||||
|
- format (string): Python DateTime format eg. "%Y-%m-%d"
|
||||||
|
- options (dict): Options to customize the widget, see README
|
||||||
|
"""
|
||||||
|
|
||||||
|
picker_type = 'DATETIME'
|
||||||
|
format = '%Y-%m-%d %H:%M'
|
||||||
|
format_key = 'DATETIME_INPUT_FORMATS'
|
||||||
|
|
||||||
|
|
||||||
|
class MonthPickerInput(BasePickerInput):
|
||||||
|
"""
|
||||||
|
Widget to display a Month-Picker Calendar on a DateField property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- attrs (dict): HTML attributes of rendered HTML input
|
||||||
|
- format (string): Python DateTime format eg. "%Y-%m-%d"
|
||||||
|
- options (dict): Options to customize the widget, see README
|
||||||
|
"""
|
||||||
|
|
||||||
|
picker_type = 'MONTH'
|
||||||
|
format = '01/%m/%Y'
|
||||||
|
format_key = 'DATE_INPUT_FORMATS'
|
||||||
|
|
||||||
|
|
||||||
|
class YearPickerInput(BasePickerInput):
|
||||||
|
"""
|
||||||
|
Widget to display a Year-Picker Calendar on a DateField property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- attrs (dict): HTML attributes of rendered HTML input
|
||||||
|
- format (string): Python DateTime format eg. "%Y-%m-%d"
|
||||||
|
- options (dict): Options to customize the widget, see README
|
||||||
|
"""
|
||||||
|
|
||||||
|
picker_type = 'YEAR'
|
||||||
|
format = '01/01/%Y'
|
||||||
|
format_key = 'DATE_INPUT_FORMATS'
|
||||||
|
|
||||||
|
def _link_to(self, linked_picker):
|
||||||
|
"""Customize the options when linked with other date-time input"""
|
||||||
|
yformat = self.config['options']['format'].replace('-01-01', '-12-31')
|
||||||
|
self.config['options']['format'] = yformat
|
@ -48,12 +48,10 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.forms',
|
||||||
# API
|
# API
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework.authtoken',
|
'rest_framework.authtoken',
|
||||||
# Autocomplete
|
|
||||||
'dal',
|
|
||||||
'dal_select2',
|
|
||||||
|
|
||||||
# Note apps
|
# Note apps
|
||||||
'activity',
|
'activity',
|
||||||
@ -100,6 +98,8 @@ TEMPLATES = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
|
||||||
|
|
||||||
WSGI_APPLICATION = 'note_kfet.wsgi.application'
|
WSGI_APPLICATION = 'note_kfet.wsgi.application'
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
|
@ -15,13 +15,14 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Include project routers
|
# Include project routers
|
||||||
path('note/', include('note.urls')),
|
path('note/', include('note.urls')),
|
||||||
|
path('accounts/', include('member.urls')),
|
||||||
|
path('activity/', include('activity.urls')),
|
||||||
path('treasury/', include('treasury.urls')),
|
path('treasury/', include('treasury.urls')),
|
||||||
|
|
||||||
# Include Django Contrib and Core routers
|
# Include Django Contrib and Core routers
|
||||||
path('i18n/', include('django.conf.urls.i18n')),
|
path('i18n/', include('django.conf.urls.i18n')),
|
||||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('accounts/', include('member.urls')),
|
|
||||||
path('accounts/login/', CustomLoginView.as_view()),
|
path('accounts/login/', CustomLoginView.as_view()),
|
||||||
path('accounts/', include('django.contrib.auth.urls')),
|
path('accounts/', include('django.contrib.auth.urls')),
|
||||||
path('api/', include('api.urls')),
|
path('api/', include('api.urls')),
|
||||||
|
@ -3,7 +3,6 @@ chardet==3.0.4
|
|||||||
defusedxml==0.6.0
|
defusedxml==0.6.0
|
||||||
Django~=2.2
|
Django~=2.2
|
||||||
django-allauth==0.39.1
|
django-allauth==0.39.1
|
||||||
django-autocomplete-light==3.5.1
|
|
||||||
django-crispy-forms==1.7.2
|
django-crispy-forms==1.7.2
|
||||||
django-extensions==2.1.9
|
django-extensions==2.1.9
|
||||||
django-filter==2.2.0
|
django-filter==2.2.0
|
||||||
|
121
static/bootstrap_datepicker_plus/css/datepicker-widget.css
Normal file
121
static/bootstrap_datepicker_plus/css/datepicker-widget.css
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Glyphicons Halflings';
|
||||||
|
src: url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.eot');
|
||||||
|
src: url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2') format('woff2'),
|
||||||
|
url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff') format('woff'),
|
||||||
|
url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.ttf') format('truetype'),
|
||||||
|
url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: 'Glyphicons Halflings';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-time:before {
|
||||||
|
content: "\e023";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-chevron-left:before {
|
||||||
|
content: "\e079";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-chevron-right:before {
|
||||||
|
content: "\e080";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-chevron-up:before {
|
||||||
|
content: "\e113";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-chevron-down:before {
|
||||||
|
content: "\e114";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-calendar:before {
|
||||||
|
content: "\e109";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-screenshot:before {
|
||||||
|
content: "\e087";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-trash:before {
|
||||||
|
content: "\e020";
|
||||||
|
}
|
||||||
|
|
||||||
|
.glyphicon-remove:before {
|
||||||
|
content: "\e014";
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-datetimepicker-widget .btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
-ms-touch-action: manipulation;
|
||||||
|
touch-action: manipulation;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-datetimepicker-widget.dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
float: left;
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin: 2px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
list-style: none;
|
||||||
|
background-color: #fff;
|
||||||
|
-webkit-background-clip: padding-box;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border: 1px solid rgba(0, 0, 0, .15);
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
|
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-datetimepicker-widget .list-unstyled {
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-datetimepicker-widget .collapse {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-datetimepicker-widget .collapse.in {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fix for bootstrap4 */
|
||||||
|
.bootstrap-datetimepicker-widget .table-condensed > thead > tr > th,
|
||||||
|
.bootstrap-datetimepicker-widget .table-condensed > tbody > tr > td,
|
||||||
|
.bootstrap-datetimepicker-widget .table-condensed > tfoot > tr > td {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
55
static/bootstrap_datepicker_plus/js/datepicker-widget.js
Normal file
55
static/bootstrap_datepicker_plus/js/datepicker-widget.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
jQuery(function ($) {
|
||||||
|
var datepickerDict = {};
|
||||||
|
var isBootstrap4 = $.fn.collapse.Constructor.VERSION.split('.').shift() == "4";
|
||||||
|
function fixMonthEndDate(e, picker) {
|
||||||
|
e.date && picker.val().length && picker.val(e.date.endOf('month').format('YYYY-MM-DD'));
|
||||||
|
}
|
||||||
|
$("[dp_config]:not([disabled])").each(function (i, element) {
|
||||||
|
var $element = $(element), data = {};
|
||||||
|
try {
|
||||||
|
data = JSON.parse($element.attr('dp_config'));
|
||||||
|
}
|
||||||
|
catch (x) { }
|
||||||
|
if (data.id && data.options) {
|
||||||
|
data.$element = $element.datetimepicker(data.options);
|
||||||
|
data.datepickerdata = $element.data("DateTimePicker");
|
||||||
|
datepickerDict[data.id] = data;
|
||||||
|
data.$element.next('.input-group-addon').on('click', function(){
|
||||||
|
data.datepickerdata.show();
|
||||||
|
});
|
||||||
|
if(isBootstrap4){
|
||||||
|
data.$element.on("dp.show", function (e) {
|
||||||
|
$('.collapse.in').addClass('show');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$.each(datepickerDict, function (id, to_picker) {
|
||||||
|
if (to_picker.linked_to) {
|
||||||
|
var from_picker = datepickerDict[to_picker.linked_to];
|
||||||
|
from_picker.datepickerdata.maxDate(to_picker.datepickerdata.date() || false);
|
||||||
|
to_picker.datepickerdata.minDate(from_picker.datepickerdata.date() || false);
|
||||||
|
from_picker.$element.on("dp.change", function (e) {
|
||||||
|
to_picker.datepickerdata.minDate(e.date || false);
|
||||||
|
});
|
||||||
|
to_picker.$element.on("dp.change", function (e) {
|
||||||
|
if (to_picker.picker_type == 'MONTH') fixMonthEndDate(e, to_picker.$element);
|
||||||
|
from_picker.datepickerdata.maxDate(e.date || false);
|
||||||
|
});
|
||||||
|
if (to_picker.picker_type == 'MONTH') {
|
||||||
|
to_picker.$element.on("dp.hide", function (e) {
|
||||||
|
fixMonthEndDate(e, to_picker.$element);
|
||||||
|
});
|
||||||
|
fixMonthEndDate({ date: to_picker.datepickerdata.date() }, to_picker.$element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(isBootstrap4) {
|
||||||
|
$('body').on('show.bs.collapse','.bootstrap-datetimepicker-widget .collapse',function(e){
|
||||||
|
$(e.target).addClass('in');
|
||||||
|
});
|
||||||
|
$('body').on('hidden.bs.collapse','.bootstrap-datetimepicker-widget .collapse',function(e){
|
||||||
|
$(e.target).removeClass('in');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
34
static/js/autocomplete_model.js
Normal file
34
static/js/autocomplete_model.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
$(".autocomplete").keyup(function(e) {
|
||||||
|
let target = $("#" + e.target.id);
|
||||||
|
let prefix = target.attr("id");
|
||||||
|
let api_url = target.attr("api_url");
|
||||||
|
let api_url_suffix = target.attr("api_url_suffix");
|
||||||
|
if (!api_url_suffix)
|
||||||
|
api_url_suffix = "";
|
||||||
|
let name_field = target.attr("name_field");
|
||||||
|
if (!name_field)
|
||||||
|
name_field = "name";
|
||||||
|
let input = target.val();
|
||||||
|
|
||||||
|
$.getJSON(api_url + "?format=json&search=^" + input + api_url_suffix, function(objects) {
|
||||||
|
let html = "";
|
||||||
|
|
||||||
|
objects.results.forEach(function (obj) {
|
||||||
|
html += li(prefix + "_" + obj.id, obj[name_field]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#" + prefix + "_list").html(html);
|
||||||
|
|
||||||
|
objects.results.forEach(function (obj) {
|
||||||
|
$("#" + prefix + "_" + obj.id).click(function() {
|
||||||
|
target.val(obj[name_field]);
|
||||||
|
$("#" + prefix + "_pk").val(obj.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (input === obj[name_field])
|
||||||
|
$("#" + prefix + "_pk").val(obj.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -28,15 +28,35 @@ function addMsg(msg, alert_type) {
|
|||||||
+ msg + "</div>\n";
|
+ msg + "</div>\n";
|
||||||
msgDiv.html(html);
|
msgDiv.html(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add Muliple error message from err_obj
|
* add Muliple error message from err_obj
|
||||||
* @param err_obj {error_code:erro_message}
|
* @param errs_obj [{error_code:erro_message}]
|
||||||
*/
|
*/
|
||||||
function errMsg(errs_obj){
|
function errMsg(errs_obj){
|
||||||
for (const err_msg of Object.values(errs_obj)) {
|
for (const err_msg of Object.values(errs_obj)) {
|
||||||
addMsg(err_msg,'danger');
|
addMsg(err_msg,'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reloadWithTurbolinks = (function () {
|
||||||
|
var scrollPosition;
|
||||||
|
|
||||||
|
function reload () {
|
||||||
|
scrollPosition = [window.scrollX, window.scrollY];
|
||||||
|
Turbolinks.visit(window.location.toString(), { action: 'replace' })
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('turbolinks:load', function () {
|
||||||
|
if (scrollPosition) {
|
||||||
|
window.scrollTo.apply(window, scrollPosition);
|
||||||
|
scrollPosition = null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return reload;
|
||||||
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload the balance of the user on the right top corner
|
* Reload the balance of the user on the right top corner
|
||||||
*/
|
*/
|
||||||
|
139
templates/activity/activity_detail.html
Normal file
139
templates/activity/activity_detail.html
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load pretty_money %}
|
||||||
|
{% load perms %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div id="activity_info" class="card bg-light shadow">
|
||||||
|
<div class="card-header text-center">
|
||||||
|
<h4>{{ activity.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" id="profile_infos">
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-xl-6">{% trans 'description'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6"> {{ activity.description }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'type'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6"> {{ activity.activity_type }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'start date'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.date_start }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'end date'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.date_end }}</dd>
|
||||||
|
|
||||||
|
{% if "view_"|has_perm:activity.creater %}
|
||||||
|
<dt class="col-xl-6">{% trans 'creater'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6"><a href="{% url "member:user_detail" pk=activity.creater.pk %}">{{ activity.creater }}</a></dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'organizer'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6"><a href="{% url "member:club_detail" pk=activity.organizer.pk %}">{{ activity.organizer }}</a></dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'attendees club'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6"><a href="{% url "member:club_detail" pk=activity.attendees_club.pk %}">{{ activity.attendees_club }}</a></dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'can invite'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.activity_type.can_invite|yesno }}</dd>
|
||||||
|
|
||||||
|
{% if activity.activity_type.can_invite %}
|
||||||
|
<dt class="col-xl-6">{% trans 'guest entry fee'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.activity_type.guest_entry_fee|pretty_money }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'valid'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.valid|yesno }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-xl-6">{% trans 'opened'|capfirst %}</dt>
|
||||||
|
<dd class="col-xl-6">{{ activity.open|yesno }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-footer text-center">
|
||||||
|
{% if activity.open and "change__open"|has_perm:activity %}
|
||||||
|
<a class="btn btn-warning btn-sm my-1" href="{% url 'activity:activity_entry' pk=activity.pk %}"> {% trans "Entry page" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if activity.valid and "change__open"|has_perm:activity %}
|
||||||
|
<a class="btn btn-warning btn-sm my-1" id="open_activity"> {% if activity.open %}{% trans "close"|capfirst %}{% else %}{% trans "open"|capfirst %}{% endif %}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if not activity.open and "change__valid"|has_perm:activity %}
|
||||||
|
<a class="btn btn-success btn-sm my-1" id="validate_activity"> {% if activity.valid %}{% trans "invalidate"|capfirst %}{% else %}{% trans "validate"|capfirst %}{% endif %}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if "view_"|has_perm:activity %}
|
||||||
|
<a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_update' pk=activity.pk %}"> {% trans "edit"|capfirst %}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if activity.activity_type.can_invite and not activity_started %}
|
||||||
|
<a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_invite' pk=activity.pk %}"> {% trans "Invite" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if guests.data %}
|
||||||
|
<hr>
|
||||||
|
<h2>{% trans "Guests list" %}</h2>
|
||||||
|
<div id="guests_table">
|
||||||
|
{% render_table guests %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script>
|
||||||
|
function remove_guest(guest_id) {
|
||||||
|
$.ajax({
|
||||||
|
url:"/api/activity/guest/" + guest_id + "/",
|
||||||
|
method:"DELETE",
|
||||||
|
headers: {"X-CSRFTOKEN": CSRF_TOKEN}
|
||||||
|
})
|
||||||
|
.done(function() {
|
||||||
|
addMsg('Invité supprimé','success');
|
||||||
|
$("#guests_table").load(location.href + " #guests_table");
|
||||||
|
})
|
||||||
|
.fail(function(xhr, textStatus, error) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#open_activity").click(function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/activity/activity/{{ activity.pk }}/",
|
||||||
|
type: "PATCH",
|
||||||
|
dataType: "json",
|
||||||
|
headers: {
|
||||||
|
"X-CSRFTOKEN": CSRF_TOKEN
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
open: {{ activity.open|yesno:'false,true' }}
|
||||||
|
}
|
||||||
|
}).done(function () {
|
||||||
|
reloadWithTurbolinks();
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#validate_activity").click(function () {
|
||||||
|
console.log(42);
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/activity/activity/{{ activity.pk }}/",
|
||||||
|
type: "PATCH",
|
||||||
|
dataType: "json",
|
||||||
|
headers: {
|
||||||
|
"X-CSRFTOKEN": CSRF_TOKEN
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
valid: {{ activity.valid|yesno:'false,true' }}
|
||||||
|
}
|
||||||
|
}).done(function () {
|
||||||
|
reloadWithTurbolinks();
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
126
templates/activity/activity_entry.html
Normal file
126
templates/activity/activity_entry.html
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load pretty_money %}
|
||||||
|
{% load perms %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<a href="{% url "activity:activity_detail" pk=activity.pk %}">
|
||||||
|
<button class="btn btn-light">{% trans "Return to activity page" %}</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="entry_table">
|
||||||
|
<h2 class="text-center">{{ entries.count }} {% if entries.count >= 2 %}{% trans "entries" %}{% else %}{% trans "entry" %}{% endif %}</h2>
|
||||||
|
{% render_table table %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script>
|
||||||
|
old_pattern = null;
|
||||||
|
alias_obj = $("#alias");
|
||||||
|
|
||||||
|
function reloadTable(force=false) {
|
||||||
|
let pattern = alias_obj.val();
|
||||||
|
|
||||||
|
if ((pattern === old_pattern || pattern === "") && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$("#entry_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #entry_table", init);
|
||||||
|
refreshBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
alias_obj.keyup(reloadTable);
|
||||||
|
|
||||||
|
$(document).ready(init);
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
$(".table-row").click(function(e) {
|
||||||
|
let target = e.target.parentElement;
|
||||||
|
target = $("#" + target.id);
|
||||||
|
|
||||||
|
let type = target.attr("data-type");
|
||||||
|
let id = target.attr("data-id");
|
||||||
|
let last_name = target.attr("data-last-name");
|
||||||
|
let first_name = target.attr("data-first-name");
|
||||||
|
|
||||||
|
if (type === "membership") {
|
||||||
|
$.post("/api/activity/entry/?format=json", {
|
||||||
|
csrfmiddlewaretoken: CSRF_TOKEN,
|
||||||
|
activity: {{ activity.id }},
|
||||||
|
note: id,
|
||||||
|
guest: null
|
||||||
|
}).done(function () {
|
||||||
|
addMsg("Entrée effectuée !", "success");
|
||||||
|
reloadTable(true);
|
||||||
|
}).fail(function(xhr) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let line_obj = $("#buttons_guest_" + id);
|
||||||
|
if (line_obj.length || target.attr('class').includes("table-success")) {
|
||||||
|
line_obj.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tr = "<tr class='text-center'>" +
|
||||||
|
"<td id='buttons_guest_" + id + "' style='table-danger center' colspan='5'>" +
|
||||||
|
"<button id='transaction_guest_" + id + "' class='btn btn-secondary'>Payer avec la note de l'hôte</button> " +
|
||||||
|
"<button id='transaction_guest_" + id + "_especes' class='btn btn-secondary'>Payer en espèces</button> " +
|
||||||
|
"<button id='transaction_guest_" + id + "_cb' class='btn btn-secondary'>Payer en CB</button></td>" +
|
||||||
|
"<tr>";
|
||||||
|
$(tr).insertAfter(target);
|
||||||
|
|
||||||
|
let makeTransaction = function() {
|
||||||
|
$.post("/api/activity/entry/?format=json", {
|
||||||
|
csrfmiddlewaretoken: CSRF_TOKEN,
|
||||||
|
activity: {{ activity.id }},
|
||||||
|
note: target.attr("data-inviter"),
|
||||||
|
guest: id
|
||||||
|
}).done(function () {
|
||||||
|
addMsg("Entrée effectuée !", "success");
|
||||||
|
reloadTable(true);
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let credit = function(credit_id, credit_name) {
|
||||||
|
return function() {
|
||||||
|
$.post("/api/note/transaction/transaction/",
|
||||||
|
{
|
||||||
|
"csrfmiddlewaretoken": CSRF_TOKEN,
|
||||||
|
"quantity": 1,
|
||||||
|
"amount": {{ activity.activity_type.guest_entry_fee }},
|
||||||
|
"reason": "Crédit " + credit_name + " (invitation {{ activity.name }})",
|
||||||
|
"valid": true,
|
||||||
|
"polymorphic_ctype": {{ notespecial_ctype }},
|
||||||
|
"resourcetype": "SpecialTransaction",
|
||||||
|
"source": credit_id,
|
||||||
|
"destination": target.attr('data-inviter'),
|
||||||
|
"last_name": last_name,
|
||||||
|
"first_name": first_name,
|
||||||
|
"bank": ""
|
||||||
|
}).done(function () {
|
||||||
|
makeTransaction();
|
||||||
|
reset();
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
$("#transaction_guest_" + id).click(makeTransaction);
|
||||||
|
$("#transaction_guest_" + id + "_especes").click(credit(1, "espèces"));
|
||||||
|
$("#transaction_guest_" + id + "_cb").click(credit(2, "carte bancaire"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
11
templates/activity/activity_form.html
Normal file
11
templates/activity/activity_form.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{form|crispy}}
|
||||||
|
<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
15
templates/activity/activity_invite.html
Normal file
15
templates/activity/activity_invite.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load i18n crispy_forms_tags %}
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
33
templates/activity/activity_list.html
Normal file
33
templates/activity/activity_list.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load i18n crispy_forms_tags%}
|
||||||
|
{% block content %}
|
||||||
|
<h2>{% trans "Upcoming activities" %}</h2>
|
||||||
|
{% if upcoming.data %}
|
||||||
|
{% render_table upcoming %}
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans "There is no planned activity." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a class="btn btn-primary" href="{% url 'activity:activity_create' %}">{% trans 'New activity' %}</a>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>{% trans "All activities" %}</h2>
|
||||||
|
|
||||||
|
{% render_table table %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(document).ready(function($) {
|
||||||
|
$(".table-row").click(function() {
|
||||||
|
window.document.location = $(this).data("href");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
@ -91,7 +91,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if "activity.activity"|not_empty_model_list %}
|
{% if "activity.activity"|not_empty_model_list %}
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
<a class="nav-link" href="#"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
|
<a class="nav-link" href="{% url 'activity:activity_list' %}"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if "treasury.invoice"|not_empty_model_change_list %}
|
{% if "treasury.invoice"|not_empty_model_change_list %}
|
||||||
|
6
templates/bootstrap_datepicker_plus/date_picker.html
Normal file
6
templates/bootstrap_datepicker_plus/date_picker.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<div class="input-group date">
|
||||||
|
{% include "bootstrap_datepicker_plus/input.html" %}
|
||||||
|
<div class="input-group-addon input-group-append" data-target="#datetimepicker1" data-toggle="datetimepickerv">
|
||||||
|
<div class="input-group-text"><i class="glyphicon glyphicon-calendar"></i></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
4
templates/bootstrap_datepicker_plus/input.html
Normal file
4
templates/bootstrap_datepicker_plus/input.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None and widget.value != "" %}
|
||||||
|
value="{{ widget.value }}"{% endif %}{% for name, value in widget.attrs.items %}{% ifnotequal value False %}
|
||||||
|
{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}
|
||||||
|
{% endifnotequal %}{% endfor %}/>
|
6
templates/bootstrap_datepicker_plus/time_picker.html
Normal file
6
templates/bootstrap_datepicker_plus/time_picker.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<div class="input-group date">
|
||||||
|
{% include "bootstrap_datepicker_plus/input.html" %}
|
||||||
|
<div class="input-group-addon input-group-append" data-target="#datetimepicker1" data-toggle="datetimepickerv">
|
||||||
|
<div class="input-group-text"><i class="glyphicon glyphicon-time"></i></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
9
templates/member/autocomplete_model.html
Normal file
9
templates/member/autocomplete_model.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<input type="hidden" name="{{ widget.name }}" {% if widget.attrs.model_pk %}value="{{ widget.attrs.model_pk }}"{% endif %} id="{{ widget.attrs.id }}_pk">
|
||||||
|
<input type="text"
|
||||||
|
{% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
|
||||||
|
name="{{ widget.name }}_name" autocomplete="off"
|
||||||
|
{% for name, value in widget.attrs.items %}
|
||||||
|
{% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %}
|
||||||
|
{% endfor %}>
|
||||||
|
<ul class="list-group list-group-flush" id="{{ widget.attrs.id }}_list">
|
||||||
|
</ul>
|
@ -13,8 +13,10 @@
|
|||||||
<dt class="col-xl-6">{% trans 'name'|capfirst %}</dt>
|
<dt class="col-xl-6">{% trans 'name'|capfirst %}</dt>
|
||||||
<dd class="col-xl-6">{{ club.name}}</dd>
|
<dd class="col-xl-6">{{ club.name}}</dd>
|
||||||
|
|
||||||
|
{% if club.parent_club %}
|
||||||
<dt class="col-xl-6"><a href="{% url 'member:club_detail' club.parent_club.pk %}">{% trans 'Club Parent'|capfirst %}</a></dt>
|
<dt class="col-xl-6"><a href="{% url 'member:club_detail' club.parent_club.pk %}">{% trans 'Club Parent'|capfirst %}</a></dt>
|
||||||
<dd class="col-xl-6"> {{ club.parent_club.name}}</dd>
|
<dd class="col-xl-6"> {{ club.parent_club.name}}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<dt class="col-xl-6">{% trans 'membership start'|capfirst %}</dt>
|
<dt class="col-xl-6">{% trans 'membership start'|capfirst %}</dt>
|
||||||
<dd class="col-xl-6">{{ club.membership_start }}</dd>
|
<dd class="col-xl-6">{{ club.membership_start }}</dd>
|
||||||
|
11
templates/note/amount_input.html
Normal file
11
templates/note/amount_input.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<div class="input-group">
|
||||||
|
<input class="form-control mx-auto d-block" type="number" min="0" step="0.01"
|
||||||
|
{% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
|
||||||
|
name="{{ widget.name }}"
|
||||||
|
{% for name, value in widget.attrs.items %}
|
||||||
|
{% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %}
|
||||||
|
{% endfor %}>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text">€</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -126,12 +126,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label for="amount">{% trans "Amount" %} :</label>
|
<label for="amount">{% trans "Amount" %} :</label>
|
||||||
<div class="input-group">
|
{% include "note/amount_input.html" with widget=amount_widget %}
|
||||||
<input class="form-control mx-auto d-block" type="number" min="0" step="0.01" id="amount" />
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">€</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load crispy_forms_tags pretty_money %}
|
{% load crispy_forms_tags %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
|
<p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
|
||||||
<form method="post" action="">
|
<form method="post" action="">
|
||||||
@ -26,18 +26,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<tr class="row-formset">
|
<tr class="row-formset">
|
||||||
<td>{{ form.designation }}</td>
|
<td>{{ form.designation }}</td>
|
||||||
<td>{{ form.quantity }} </td>
|
<td>{{ form.quantity }}</td>
|
||||||
<td>
|
<td>{{ form.amount }}</td>
|
||||||
{# Use custom input for amount, with the € symbol #}
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" name="product_set-{{ forloop.counter0 }}-amount" step="0.01"
|
|
||||||
id="id_product_set-{{ forloop.counter0 }}-amount"
|
|
||||||
value="{{ form.instance.amount|cents_to_euros }}">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">€</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{# These fields are hidden but handled by the formset to link the id and the invoice id #}
|
{# These fields are hidden but handled by the formset to link the id and the invoice id #}
|
||||||
{{ form.invoice }}
|
{{ form.invoice }}
|
||||||
{{ form.id }}
|
{{ form.id }}
|
||||||
@ -64,15 +54,7 @@
|
|||||||
<tr class="row-formset">
|
<tr class="row-formset">
|
||||||
<td>{{ formset.empty_form.designation }}</td>
|
<td>{{ formset.empty_form.designation }}</td>
|
||||||
<td>{{ formset.empty_form.quantity }} </td>
|
<td>{{ formset.empty_form.quantity }} </td>
|
||||||
<td>
|
<td>{{ formset.empty_form.amount }}</td>
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" name="product_set-__prefix__-amount" step="0.01"
|
|
||||||
id="id_product_set-__prefix__-amount">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">€</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{{ formset.empty_form.invoice }}
|
{{ formset.empty_form.invoice }}
|
||||||
{{ formset.empty_form.id }}
|
{{ formset.empty_form.id }}
|
||||||
</tr>
|
</tr>
|
||||||
|
Loading…
Reference in New Issue
Block a user