Compare commits

..

No commits in common. "e23eafd56cf9c9550d2fb909f45532af7a5af02b" and "434a393f3bea27b3e442f21ddad304ab25b2c889" have entirely different histories.

24 changed files with 740 additions and 889 deletions

View File

@ -4,7 +4,6 @@
"pk": 1, "pk": 1,
"fields": { "fields": {
"name": "Pot", "name": "Pot",
"manage_entries": true,
"can_invite": true, "can_invite": true,
"guest_entry_fee": 500 "guest_entry_fee": 500
} }
@ -14,7 +13,6 @@
"pk": 2, "pk": 2,
"fields": { "fields": {
"name": "Soir\u00e9e de club", "name": "Soir\u00e9e de club",
"manage_entries": false,
"can_invite": false, "can_invite": false,
"guest_entry_fee": 0 "guest_entry_fee": 0
} }

View File

@ -1,11 +1,9 @@
# 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 datetime import timedelta
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from member.models import Club from member.models import Club
from note.models import NoteUser, Note from note.models import NoteUser, Note
@ -43,7 +41,7 @@ class GuestForm(forms.ModelForm):
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()
if timezone.now() > timezone.localtime(self.activity.date_start): if self.activity.date_start > datetime.now():
self.add_error("inviter", _("You can't invite someone once the activity is started.")) self.add_error("inviter", _("You can't invite someone once the activity is started."))
if not self.activity.valid: if not self.activity.valid:
@ -52,21 +50,20 @@ class GuestForm(forms.ModelForm):
one_year = timedelta(days=365) one_year = timedelta(days=365)
qs = Guest.objects.filter( qs = Guest.objects.filter(
first_name__iexact=cleaned_data["first_name"], first_name=cleaned_data["first_name"],
last_name__iexact=cleaned_data["last_name"], last_name=cleaned_data["last_name"],
activity__date_start__gte=self.activity.date_start - one_year, activity__date_start__gte=self.activity.date_start - one_year,
entry__isnull=False,
) )
if qs.count() >= 5: if len(qs) >= 5:
self.add_error("last_name", _("This person has been already invited 5 times this year.")) self.add_error("last_name", _("This person has been already invited 5 times this year."))
qs = qs.filter(activity=self.activity) qs = qs.filter(activity=self.activity)
if qs.exists(): if qs.exists():
self.add_error("last_name", _("This person is already invited.")) self.add_error("last_name", _("This person is already invited."))
if "inviter" in cleaned_data: qs = Guest.objects.filter(inviter=cleaned_data["inviter"], activity=self.activity)
if Guest.objects.filter(inviter=cleaned_data["inviter"], activity=self.activity).count() >= 3: if len(qs) >= 3:
self.add_error("inviter", _("You can't invite more than 3 people to this activity.")) self.add_error("inviter", _("You can't invite more than 3 people to this activity."))
return cleaned_data return cleaned_data

View File

@ -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 datetime import timedelta from datetime import timedelta, datetime
from threading import Thread from threading import Thread
from django.conf import settings from django.conf import settings
@ -27,21 +27,11 @@ class ActivityType(models.Model):
verbose_name=_('name'), verbose_name=_('name'),
max_length=255, max_length=255,
) )
manage_entries = models.BooleanField(
verbose_name=_('manage entries'),
help_text=_('Enable the support of entries for this activity.'),
default=False,
)
can_invite = models.BooleanField( can_invite = models.BooleanField(
verbose_name=_('can invite'), verbose_name=_('can invite'),
default=False,
) )
guest_entry_fee = models.PositiveIntegerField( guest_entry_fee = models.PositiveIntegerField(
verbose_name=_('guest entry fee'), verbose_name=_('guest entry fee'),
default=0,
) )
class Meta: class Meta:
@ -246,18 +236,18 @@ class Guest(models.Model):
one_year = timedelta(days=365) one_year = timedelta(days=365)
if not force_insert: if not force_insert:
if timezone.now() > timezone.localtime(self.activity.date_start): if self.activity.date_start > datetime.now():
raise ValidationError(_("You can't invite someone once the activity is started.")) raise ValidationError(_("You can't invite someone once the activity is started."))
if not self.activity.valid: if not self.activity.valid:
raise ValidationError(_("This activity is not validated yet.")) raise ValidationError(_("This activity is not validated yet."))
qs = Guest.objects.filter( qs = Guest.objects.filter(
first_name__iexact=self.first_name, first_name=self.first_name,
last_name__iexact=self.last_name, last_name=self.last_name,
activity__date_start__gte=self.activity.date_start - one_year, activity__date_start__gte=self.activity.date_start - one_year,
) )
if qs.count() >= 5: if len(qs) >= 5:
raise ValidationError(_("This person has been already invited 5 times this year.")) raise ValidationError(_("This person has been already invited 5 times this year."))
qs = qs.filter(activity=self.activity) qs = qs.filter(activity=self.activity)
@ -265,7 +255,7 @@ class Guest(models.Model):
raise ValidationError(_("This person is already invited.")) raise ValidationError(_("This person is already invited."))
qs = Guest.objects.filter(inviter=self.inviter, activity=self.activity) qs = Guest.objects.filter(inviter=self.inviter, activity=self.activity)
if qs.count() >= 3: if len(qs) >= 3:
raise ValidationError(_("You can't invite more than 3 people to this activity.")) raise ValidationError(_("You can't invite more than 3 people to this activity."))
return super().save(force_insert, force_update, using, update_fields) return super().save(force_insert, force_update, using, update_fields)

View File

@ -1,6 +1,6 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.utils import timezone
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
@ -66,10 +66,6 @@ def get_row_class(record):
qs = Entry.objects.filter(note=record.note, activity=record.activity, guest=None) qs = Entry.objects.filter(note=record.note, activity=record.activity, guest=None)
if qs.exists(): if qs.exists():
c += " table-success" c += " table-success"
elif not record.note.user.memberships.filter(club=record.activity.attendees_club,
date_start__lte=timezone.now(),
date_end__gte=timezone.now()).exists():
c += " table-info"
elif record.note.balance < 0: elif record.note.balance < 0:
c += " table-danger" c += " table-danger"
return c return c

View File

@ -1,12 +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 datetime, timezone
from django.conf import settings from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import F, Q from django.db.models import F, Q
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils import timezone
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_tables2.views import SingleTableView from django_tables2.views import SingleTableView
@ -45,17 +46,12 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
upcoming_activities = Activity.objects.filter(date_end__gt=timezone.now()) upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now())
context['upcoming'] = ActivityTable( context['upcoming'] = ActivityTable(
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")), data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
prefix='upcoming-', prefix='upcoming-',
) )
started_activities = Activity.objects\
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
.filter(open=True, valid=True).all()
context["started_activities"] = started_activities
return context return context
@ -71,7 +67,7 @@ class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))) .filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view")))
context["guests"] = table context["guests"] = table
context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start) context["activity_started"] = datetime.now(timezone.utc) > self.object.date_start
return context return context
@ -129,7 +125,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\ .filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\
.order_by('last_name', 'first_name').distinct() .order_by('last_name', 'first_name').distinct()
if "search" in self.request.GET and self.request.GET["search"]: if "search" in self.request.GET:
pattern = self.request.GET["search"] pattern = self.request.GET["search"]
if pattern[0] != "^": if pattern[0] != "^":
pattern = "^" + pattern pattern = "^" + pattern
@ -152,12 +148,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
username=F("note__noteuser__user__username"), username=F("note__noteuser__user__username"),
note_name=F("name"), note_name=F("name"),
balance=F("note__balance"))\ balance=F("note__balance"))\
.filter(note__noteuser__isnull=False)\ .filter(note__polymorphic_ctype__model="noteuser")\
.filter(
note__noteuser__user__memberships__club=activity.attendees_club,
note__noteuser__user__memberships__date_start__lte=timezone.now(),
note__noteuser__user__memberships__date_end__gte=timezone.now(),
)\
.filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view")) .filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))
if pattern: if pattern:
note_qs = note_qs.filter( note_qs = note_qs.filter(

View File

@ -54,7 +54,7 @@ class UserViewSet(ReadProtectedModelViewSet):
serializer_class = UserSerializer serializer_class = UserSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ] filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ]
search_fields = ['$username', '$first_name', '$last_name', '$note__alias__name', '$note__alias__normalized_name', ] search_fields = ['$username', '$first_name', '$last_name', ]
# This ViewSet is the only one that is accessible from all authenticated users! # This ViewSet is the only one that is accessible from all authenticated users!

View File

@ -37,8 +37,6 @@ class ProfileForm(forms.ModelForm):
""" """
A form for the extras field provided by the :model:`member.Profile` model. A form for the extras field provided by the :model:`member.Profile` model.
""" """
report_frequency = forms.IntegerField(required=False, initial=0, label=_("Report frequency"))
last_report = forms.DateField(required=False, disabled=True, label=_("Last report date")) last_report = forms.DateField(required=False, disabled=True, label=_("Last report date"))
def save(self, commit=True): def save(self, commit=True):

View File

@ -185,9 +185,9 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
Q(first_name__iregex=pattern) Q(first_name__iregex=pattern)
| Q(last_name__iregex=pattern) | Q(last_name__iregex=pattern)
| Q(profile__section__iregex=pattern) | Q(profile__section__iregex=pattern)
| Q(username__iregex=pattern) | Q(username__iregex="^" + pattern)
| Q(alias__iregex=pattern) | Q(alias__iregex="^" + pattern)
| Q(normalized_alias__iregex=Alias.normalize(pattern)) | Q(normalized_alias__iregex=Alias.normalize("^" + pattern))
) )
else: else:
qs = qs.none() qs = qs.none()
@ -326,8 +326,8 @@ class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
qs = qs.filter( qs = qs.filter(
Q(name__iregex=pattern) Q(name__iregex=pattern)
| Q(note__alias__name__iregex=pattern) | Q(note__alias__name__iregex="^" + pattern)
| Q(note__alias__normalized_name__iregex=Alias.normalize(pattern)) | Q(note__alias__normalized_name__iregex=Alias.normalize("^" + pattern))
) )
return qs return qs
@ -484,7 +484,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
additional_fee_renewal = 0 additional_fee_renewal = 0
while c.parent_club is not None: while c.parent_club is not None:
c = c.parent_club c = c.parent_club
if c.membership_start and not Membership.objects.filter( if not Membership.objects.filter(
club=c, club=c,
user=user, user=user,
date_start__gte=c.membership_start, date_start__gte=c.membership_start,
@ -562,7 +562,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
fee = 0 fee = 0
c = club c = club
while c is not None and c.membership_start: while c is not None:
if not Membership.objects.filter( if not Membership.objects.filter(
club=c, club=c,
user=user, user=user,

View File

@ -202,6 +202,8 @@ class Transaction(PolymorphicModel):
When saving, also transfer money between two notes When saving, also transfer money between two notes
""" """
with transaction.atomic(): with transaction.atomic():
if self.pk:
self.refresh_from_db()
self.source.refresh_from_db() self.source.refresh_from_db()
self.destination.refresh_from_db() self.destination.refresh_from_db()
self.validate(False) self.validate(False)

@ -1 +1 @@
Subproject commit 4984159a61642a0d3668e85daf39472b59b86447 Subproject commit 3806feb67fcb1fe822cfdedddbbc4ca7eeef3829

View File

@ -3,9 +3,8 @@
from django.contrib import admin from django.contrib import admin
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .forms import ProductForm
from .models import RemittanceType, Remittance, SogeCredit, Invoice, Product from .models import RemittanceType, Remittance, SogeCredit
@admin.register(RemittanceType, site=admin_site) @admin.register(RemittanceType, site=admin_site)
@ -40,20 +39,3 @@ class SogeCreditAdmin(admin.ModelAdmin):
def has_add_permission(self, request): def has_add_permission(self, request):
# Don't create a credit manually # Don't create a credit manually
return False return False
class ProductInline(admin.StackedInline):
"""
Inline product in invoice admin
"""
model = Product
form = ProductForm
@admin.register(Invoice, site=admin_site)
class InvoiceAdmin(admin.ModelAdmin):
"""
Admin customisation for Invoice
"""
list_display = ('object', 'id', 'bde', 'name', 'date', 'acquitted',)
inlines = (ProductInline,)

View File

@ -55,7 +55,7 @@ class Invoice(models.Model):
date = models.DateField( date = models.DateField(
default=timezone.now, default=timezone.now,
verbose_name=_("Date"), verbose_name=_("Place"),
) )
acquitted = models.BooleanField( acquitted = models.BooleanField(
@ -82,7 +82,7 @@ class Product(models.Model):
verbose_name=_("Designation"), verbose_name=_("Designation"),
) )
quantity = models.PositiveIntegerField( quantity = models.IntegerField(
verbose_name=_("Quantity") verbose_name=_("Quantity")
) )

View File

@ -1,20 +0,0 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django import template
def do_latex_escape(value):
return (
value.replace("&", "\\&")
.replace("$", "\\$")
.replace("%", "\\%")
.replace("#", "\\#")
.replace("_", "\\_")
.replace("{", "\\{")
.replace("}", "\\}")
)
register = template.Library()
register.filter("escape_tex", do_latex_escape)

View File

@ -141,10 +141,11 @@ class InvoiceRenderView(LoginRequiredMixin, View):
invoice = Invoice.objects.filter(PermissionBackend.filter_queryset(request.user, Invoice, "view")).get(pk=pk) invoice = Invoice.objects.filter(PermissionBackend.filter_queryset(request.user, Invoice, "view")).get(pk=pk)
products = Product.objects.filter(invoice=invoice).all() products = Product.objects.filter(invoice=invoice).all()
invoice.place = "Gif-sur-Yvette" # Informations of the BDE. Should be updated when the school will move.
invoice.place = "Cachan"
invoice.my_name = "BDE ENS Cachan" invoice.my_name = "BDE ENS Cachan"
invoice.my_address_street = "4 avenue des Sciences" invoice.my_address_street = "61 avenue du Président Wilson"
invoice.my_city = "91190 Gif-sur-Yvette" invoice.my_city = "94230 Cachan"
invoice.bank_code = 30003 invoice.bank_code = 30003
invoice.desk_code = 3894 invoice.desk_code = 3894
invoice.account_number = 37280662 invoice.account_number = 37280662

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@ $(document).ready(function () {
if (!name_field) if (!name_field)
name_field = "name"; name_field = "name";
let input = target.val(); let input = target.val();
target.addClass("is-invalid");
target.removeClass("is-valid");
$("#" + prefix + "_reset").removeClass("d-none"); $("#" + prefix + "_reset").removeClass("d-none");
$.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) { $.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) {
@ -29,10 +27,6 @@ $(document).ready(function () {
target.val(obj[name_field]); target.val(obj[name_field]);
$("#" + prefix + "_pk").val(obj.id); $("#" + prefix + "_pk").val(obj.id);
results_list.html("");
target.removeClass("is-invalid");
target.addClass("is-valid");
if (typeof autocompleted != 'undefined') if (typeof autocompleted != 'undefined')
autocompleted(obj, prefix) autocompleted(obj, prefix)
}); });

View File

@ -7,7 +7,70 @@
{% block content %} {% block content %}
{% include "activity/activity_info.html" %} <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 ".change_"|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 %} {% if guests.data %}
<hr> <hr>

View File

@ -76,10 +76,7 @@
note: id, note: id,
guest: null guest: null
}).done(function () { }).done(function () {
if (target.hasClass("table-info")) addMsg("Entrée effectuée !", "success", 4000);
addMsg("Entrée effectuée, mais attention : la personne n'est plus adhérente Kfet.", "warning", 10000);
else
addMsg("Entrée effectuée !", "success", 4000);
reloadTable(true); reloadTable(true);
}).fail(function(xhr) { }).fail(function(xhr) {
errMsg(xhr.responseJSON, 4000); errMsg(xhr.responseJSON, 4000);
@ -107,10 +104,7 @@
note: target.attr("data-inviter"), note: target.attr("data-inviter"),
guest: id guest: id
}).done(function () { }).done(function () {
if (target.hasClass("table-info")) addMsg("Entrée effectuée !", "success", 4000);
addMsg("Entrée effectuée, mais attention : la personne n'est plus adhérente Kfet.", "warning", 10000);
else
addMsg("Entrée effectuée !", "success", 4000);
reloadTable(true); reloadTable(true);
}).fail(function (xhr) { }).fail(function (xhr) {
errMsg(xhr.responseJSON, 4000); errMsg(xhr.responseJSON, 4000);

View File

@ -1,78 +0,0 @@
{% load i18n %}
{% load perms %}
{% load pretty_money %}
{% url 'activity:activity_detail' activity.pk as activity_detail_url %}
<div id="activity_info" class="card bg-light shadow">
<div class="card-header text-center">
<h4>
{% if request.path_info != activity_detail_url %}
<a href="{{ activity_detail_url }}">{{ activity.name }}</a>
{% else %}
{{ activity.name }}
{% endif %}
</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 activity.activity_type.manage_entries 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 request.path_info == activity_detail_url %}
{% 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 ".change_"|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 %}
{% endif %}
</div>
</div>

View File

@ -2,14 +2,6 @@
{% load render_table from django_tables2 %} {% load render_table from django_tables2 %}
{% load i18n crispy_forms_tags%} {% load i18n crispy_forms_tags%}
{% block content %} {% block content %}
{% if started_activities %}
<h2>{% trans "Current activity" %}</h2>
{% for activity in started_activities %}
{% include "activity/activity_info.html" %}
<hr>
{% endfor %}
{% endif %}
<h2>{% trans "Upcoming activities" %}</h2> <h2>{% trans "Upcoming activities" %}</h2>
{% if upcoming.data %} {% if upcoming.data %}
{% render_table upcoming %} {% render_table upcoming %}

View File

@ -57,12 +57,6 @@
window.document.location = $(this).data("href"); window.document.location = $(this).data("href");
timer_on = false; timer_on = false;
}); });
$("tr").each(function() {
$(this).find("td:eq(0), td:eq(1), td:eq(2), td:eq(3), td:eq(5)").each(function() {
$(this).html($(this).text().replace(new RegExp(searchbar_obj.val(), 'i'), "<mark>$&</mark>"));
});
});
} }
init(); init();

View File

@ -19,12 +19,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
<input type="radio" name="transaction_type" id="type_credit"> <input type="radio" name="transaction_type" id="type_credit">
{% trans "Credit" %} {% trans "Credit" %}
</label> </label>
{% if not activities_open %} <label type="type_debit" class="btn btn-sm btn-outline-primary">
<label type="type_debit" class="btn btn-sm btn-outline-primary"> <input type="radio" name="transaction_type" id="type_debit">
<input type="radio" name="transaction_type" id="type_debit"> {% trans "Debit" %}
{% trans "Debit" %} </label>
</label>
{% endif %}
{% endif %} {% endif %}
{% for activity in activities_open %} {% for activity in activities_open %}
<a href="{% url "activity:activity_entry" pk=activity.pk %}" class="btn btn-sm btn-outline-primary"> <a href="{% url "activity:activity_entry" pk=activity.pk %}" class="btn btn-sm btn-outline-primary">

View File

@ -1,6 +1,3 @@
{% load escape_tex %}
{% load l10n %}
\nonstopmode \nonstopmode
\documentclass[11pt]{article} \documentclass[11pt]{article}
@ -25,13 +22,14 @@
\FPround{\prix}{#3}{2} \FPround{\prix}{#3}{2}
\FPround{\montant}{#4}{2} \FPround{\montant}{#4}{2}
\FPadd{\TotalHT}{\TotalHT}{\montant} \FPadd{\TotalHT}{\TotalHT}{\montant}
\eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr}
} }
\newcommand{\AfficheResultat}{% \newcommand{\AfficheResultat}{%
\ListeProduits \ListeProduits
\FPmul{\TotalTVA}{\TotalHT}{\TVA} \FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
\FPdiv{\TotalTVA}{\TotalTVA}{100}
\FPadd{\TotalTTC}{\TotalHT}{\TotalTVA} \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
\FPround{\TotalHT}{\TotalHT}{2} \FPround{\TotalHT}{\TotalHT}{2}
\FPround{\TotalTVA}{\TotalTVA}{2} \FPround{\TotalTVA}{\TotalTVA}{2}
@ -47,14 +45,15 @@
\textbf{Total TTC} & & & \TotalTTC \textbf{Total TTC} & & & \TotalTTC
} }
\newcommand {\ListeProduits}{ \newcommand*\eaddto[2]{% version développée de \addto
{% localize off %} \edef\tmp{#2}%
{% for product in products %} \expandafter\addto
{{ product.designation|safe|escape_tex }} & {{ product.amount_euros|safe|escape_tex|floatformat:2 }} & {{ product.quantity|safe|escape_tex|floatformat:2 }} & {{ product.total_euros|safe|escape_tex|floatformat:2 }} \cr \expandafter#1%
{% endfor %} \expandafter{\tmp}%
{% endlocalize %}
} }
\newcommand {\ListeProduits}{}
% Logo du BDE % Logo du BDE
\AddToShipoutPicture*{ \AddToShipoutPicture*{
\put(0,0){ \put(0,0){
@ -82,22 +81,22 @@
\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib} \def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib}
\def\CodeBic{{"{"}}{{ obj.bic }}} \def\CodeBic{{"{"}}{{ obj.bic }}}
\def\FactureNum {{"{"}}{{ obj.id }}} % Numéro de facture \def\FactureNum {{"{"}}{{obj.id}}} % Numéro de facture
\def\FactureAcquittee {% if obj.acquitted %} {oui} {% else %} {non} {% endif %} % Facture acquittée : oui/non \def\FactureAcquittee {% if obj.acquitted %} {oui} {% else %} {non} {% endif %} % Facture acquittée : oui/non
\def\FactureLieu {{"{"}}{{ obj.place|safe|escape_tex }}} % Lieu de l'édition de la facture \def\FactureLieu {{"{"}}{{ obj.place }}} % Lieu de l'édition de la facture
\def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture \def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture
\def\FactureObjet {{"{"}}{{ obj.object|safe|escape_tex }} } % Objet du document \def\FactureObjet {{"{"}}{{ obj.object|safe }} } % Objet du document
% Description de la facture % Description de la facture
\def\FactureDescr {{"{"}}{{ obj.description|safe|escape_tex }}} \def\FactureDescr {{"{"}}{{ obj.description|safe }}}
% Infos Client % Infos Client
\def\ClientNom{{"{"}}{{ obj.name|safe|escape_tex }}} % Nom du client \def\ClientNom{{"{"}}{{obj.name|safe}}} % Nom du client
\def\ClientAdresse{{"{"}}{{ obj.address|safe|escape_tex }}} % Adresse du client \def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client
% Liste des produits facturés : Désignation, quantité, prix unitaire HT % Liste des produits facturés : Désignation, quantité, prix unitaire HT
{% for product in products %} {% for product in products %}
\AjouterProduit{{"{"}}{{ product.designation|safe|escape_tex }}} {{"{"}}{{ product.quantity|safe|escape_tex }}} {{"{"}}{{ product.amount_euros|safe|escape_tex }}} {{"{"}}{{ product.total_euros|safe|escape_tex }}} \AjouterProduit{ {{product.designation|safe}}} { {{product.quantity|safe}}} { {{product.amount_euros|safe}}} { {{product.total_euros|safe}}}
{% endfor %} {% endfor %}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%