mirror of https://gitlab.crans.org/bde/nk20
Compare commits
19 Commits
434a393f3b
...
e23eafd56c
Author | SHA1 | Date |
---|---|---|
Yohann D'ANELLO | e23eafd56c | |
Yohann D'ANELLO | 3e28ed8716 | |
Yohann D'ANELLO | 5c01c0bb6c | |
Yohann D'ANELLO | 979628b02d | |
Yohann D'ANELLO | bb8e3aaccf | |
Yohann D'ANELLO | 86ff23357c | |
Yohann D'ANELLO | fd2f426f55 | |
Yohann D'ANELLO | 48a7128370 | |
Yohann D'ANELLO | f222ba134d | |
Yohann D'ANELLO | d95cd8c7c7 | |
Yohann D'ANELLO | 5b3361f086 | |
Yohann D'ANELLO | 9c7cb07dec | |
Yohann D'ANELLO | dd4b24d999 | |
Yohann D'ANELLO | eb3d426947 | |
Yohann D'ANELLO | d8c7018b9a | |
Yohann D'ANELLO | f47a0b8c9d | |
Yohann D'ANELLO | c859fc7821 | |
Yohann D'ANELLO | a4702fca86 | |
Yohann D'ANELLO | de5e0c958e |
|
@ -4,6 +4,7 @@
|
|||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Pot",
|
||||
"manage_entries": true,
|
||||
"can_invite": true,
|
||||
"guest_entry_fee": 500
|
||||
}
|
||||
|
@ -13,6 +14,7 @@
|
|||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Soir\u00e9e de club",
|
||||
"manage_entries": false,
|
||||
"can_invite": false,
|
||||
"guest_entry_fee": 0
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from django import forms
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from member.models import Club
|
||||
from note.models import NoteUser, Note
|
||||
|
@ -41,7 +43,7 @@ class GuestForm(forms.ModelForm):
|
|||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
if self.activity.date_start > datetime.now():
|
||||
if timezone.now() > timezone.localtime(self.activity.date_start):
|
||||
self.add_error("inviter", _("You can't invite someone once the activity is started."))
|
||||
|
||||
if not self.activity.valid:
|
||||
|
@ -50,19 +52,20 @@ class GuestForm(forms.ModelForm):
|
|||
one_year = timedelta(days=365)
|
||||
|
||||
qs = Guest.objects.filter(
|
||||
first_name=cleaned_data["first_name"],
|
||||
last_name=cleaned_data["last_name"],
|
||||
first_name__iexact=cleaned_data["first_name"],
|
||||
last_name__iexact=cleaned_data["last_name"],
|
||||
activity__date_start__gte=self.activity.date_start - one_year,
|
||||
entry__isnull=False,
|
||||
)
|
||||
if len(qs) >= 5:
|
||||
if qs.count() >= 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:
|
||||
if "inviter" in cleaned_data:
|
||||
if Guest.objects.filter(inviter=cleaned_data["inviter"], activity=self.activity).count() >= 3:
|
||||
self.add_error("inviter", _("You can't invite more than 3 people to this activity."))
|
||||
|
||||
return cleaned_data
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from datetime import timedelta
|
||||
from threading import Thread
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -27,11 +27,21 @@ class ActivityType(models.Model):
|
|||
verbose_name=_('name'),
|
||||
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(
|
||||
verbose_name=_('can invite'),
|
||||
default=False,
|
||||
)
|
||||
|
||||
guest_entry_fee = models.PositiveIntegerField(
|
||||
verbose_name=_('guest entry fee'),
|
||||
default=0,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
@ -236,18 +246,18 @@ class Guest(models.Model):
|
|||
one_year = timedelta(days=365)
|
||||
|
||||
if not force_insert:
|
||||
if self.activity.date_start > datetime.now():
|
||||
if timezone.now() > timezone.localtime(self.activity.date_start):
|
||||
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,
|
||||
first_name__iexact=self.first_name,
|
||||
last_name__iexact=self.last_name,
|
||||
activity__date_start__gte=self.activity.date_start - one_year,
|
||||
)
|
||||
if len(qs) >= 5:
|
||||
if qs.count() >= 5:
|
||||
raise ValidationError(_("This person has been already invited 5 times this year."))
|
||||
|
||||
qs = qs.filter(activity=self.activity)
|
||||
|
@ -255,7 +265,7 @@ class Guest(models.Model):
|
|||
raise ValidationError(_("This person is already invited."))
|
||||
|
||||
qs = Guest.objects.filter(inviter=self.inviter, activity=self.activity)
|
||||
if len(qs) >= 3:
|
||||
if qs.count() >= 3:
|
||||
raise ValidationError(_("You can't invite more than 3 people to this activity."))
|
||||
|
||||
return super().save(force_insert, force_update, using, update_fields)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.utils import timezone
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import django_tables2 as tables
|
||||
|
@ -66,6 +66,10 @@ def get_row_class(record):
|
|||
qs = Entry.objects.filter(note=record.note, activity=record.activity, guest=None)
|
||||
if qs.exists():
|
||||
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:
|
||||
c += " table-danger"
|
||||
return c
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from django.conf import settings
|
||||
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.utils import timezone
|
||||
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_tables2.views import SingleTableView
|
||||
|
@ -46,12 +45,17 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now())
|
||||
upcoming_activities = Activity.objects.filter(date_end__gt=timezone.now())
|
||||
context['upcoming'] = ActivityTable(
|
||||
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
|
||||
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
|
||||
|
||||
|
||||
|
@ -67,7 +71,7 @@ class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view")))
|
||||
context["guests"] = table
|
||||
|
||||
context["activity_started"] = datetime.now(timezone.utc) > self.object.date_start
|
||||
context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start)
|
||||
|
||||
return context
|
||||
|
||||
|
@ -125,7 +129,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
|||
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\
|
||||
.order_by('last_name', 'first_name').distinct()
|
||||
|
||||
if "search" in self.request.GET:
|
||||
if "search" in self.request.GET and self.request.GET["search"]:
|
||||
pattern = self.request.GET["search"]
|
||||
if pattern[0] != "^":
|
||||
pattern = "^" + pattern
|
||||
|
@ -148,7 +152,12 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
|||
username=F("note__noteuser__user__username"),
|
||||
note_name=F("name"),
|
||||
balance=F("note__balance"))\
|
||||
.filter(note__polymorphic_ctype__model="noteuser")\
|
||||
.filter(note__noteuser__isnull=False)\
|
||||
.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"))
|
||||
if pattern:
|
||||
note_qs = note_qs.filter(
|
||||
|
|
|
@ -54,7 +54,7 @@ class UserViewSet(ReadProtectedModelViewSet):
|
|||
serializer_class = UserSerializer
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter]
|
||||
filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ]
|
||||
search_fields = ['$username', '$first_name', '$last_name', ]
|
||||
search_fields = ['$username', '$first_name', '$last_name', '$note__alias__name', '$note__alias__normalized_name', ]
|
||||
|
||||
|
||||
# This ViewSet is the only one that is accessible from all authenticated users!
|
||||
|
|
|
@ -37,6 +37,8 @@ class ProfileForm(forms.ModelForm):
|
|||
"""
|
||||
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"))
|
||||
|
||||
def save(self, commit=True):
|
||||
|
|
|
@ -185,9 +185,9 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
|||
Q(first_name__iregex=pattern)
|
||||
| Q(last_name__iregex=pattern)
|
||||
| Q(profile__section__iregex=pattern)
|
||||
| Q(username__iregex="^" + pattern)
|
||||
| Q(alias__iregex="^" + pattern)
|
||||
| Q(normalized_alias__iregex=Alias.normalize("^" + pattern))
|
||||
| Q(username__iregex=pattern)
|
||||
| Q(alias__iregex=pattern)
|
||||
| Q(normalized_alias__iregex=Alias.normalize(pattern))
|
||||
)
|
||||
else:
|
||||
qs = qs.none()
|
||||
|
@ -326,8 +326,8 @@ class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
|||
|
||||
qs = qs.filter(
|
||||
Q(name__iregex=pattern)
|
||||
| Q(note__alias__name__iregex="^" + pattern)
|
||||
| Q(note__alias__normalized_name__iregex=Alias.normalize("^" + pattern))
|
||||
| Q(note__alias__name__iregex=pattern)
|
||||
| Q(note__alias__normalized_name__iregex=Alias.normalize(pattern))
|
||||
)
|
||||
|
||||
return qs
|
||||
|
@ -484,7 +484,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
|
|||
additional_fee_renewal = 0
|
||||
while c.parent_club is not None:
|
||||
c = c.parent_club
|
||||
if not Membership.objects.filter(
|
||||
if c.membership_start and not Membership.objects.filter(
|
||||
club=c,
|
||||
user=user,
|
||||
date_start__gte=c.membership_start,
|
||||
|
@ -562,7 +562,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
|
|||
|
||||
fee = 0
|
||||
c = club
|
||||
while c is not None:
|
||||
while c is not None and c.membership_start:
|
||||
if not Membership.objects.filter(
|
||||
club=c,
|
||||
user=user,
|
||||
|
|
|
@ -202,8 +202,6 @@ class Transaction(PolymorphicModel):
|
|||
When saving, also transfer money between two notes
|
||||
"""
|
||||
with transaction.atomic():
|
||||
if self.pk:
|
||||
self.refresh_from_db()
|
||||
self.source.refresh_from_db()
|
||||
self.destination.refresh_from_db()
|
||||
self.validate(False)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3806feb67fcb1fe822cfdedddbbc4ca7eeef3829
|
||||
Subproject commit 4984159a61642a0d3668e85daf39472b59b86447
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
from django.contrib import admin
|
||||
from note_kfet.admin import admin_site
|
||||
from .forms import ProductForm
|
||||
|
||||
from .models import RemittanceType, Remittance, SogeCredit
|
||||
from .models import RemittanceType, Remittance, SogeCredit, Invoice, Product
|
||||
|
||||
|
||||
@admin.register(RemittanceType, site=admin_site)
|
||||
|
@ -39,3 +40,20 @@ class SogeCreditAdmin(admin.ModelAdmin):
|
|||
def has_add_permission(self, request):
|
||||
# Don't create a credit manually
|
||||
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,)
|
||||
|
|
|
@ -55,7 +55,7 @@ class Invoice(models.Model):
|
|||
|
||||
date = models.DateField(
|
||||
default=timezone.now,
|
||||
verbose_name=_("Place"),
|
||||
verbose_name=_("Date"),
|
||||
)
|
||||
|
||||
acquitted = models.BooleanField(
|
||||
|
@ -82,7 +82,7 @@ class Product(models.Model):
|
|||
verbose_name=_("Designation"),
|
||||
)
|
||||
|
||||
quantity = models.IntegerField(
|
||||
quantity = models.PositiveIntegerField(
|
||||
verbose_name=_("Quantity")
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# 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)
|
|
@ -141,11 +141,10 @@ class InvoiceRenderView(LoginRequiredMixin, View):
|
|||
invoice = Invoice.objects.filter(PermissionBackend.filter_queryset(request.user, Invoice, "view")).get(pk=pk)
|
||||
products = Product.objects.filter(invoice=invoice).all()
|
||||
|
||||
# Informations of the BDE. Should be updated when the school will move.
|
||||
invoice.place = "Cachan"
|
||||
invoice.place = "Gif-sur-Yvette"
|
||||
invoice.my_name = "BDE ENS Cachan"
|
||||
invoice.my_address_street = "61 avenue du Président Wilson"
|
||||
invoice.my_city = "94230 Cachan"
|
||||
invoice.my_address_street = "4 avenue des Sciences"
|
||||
invoice.my_city = "91190 Gif-sur-Yvette"
|
||||
invoice.bank_code = 30003
|
||||
invoice.desk_code = 3894
|
||||
invoice.account_number = 37280662
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,8 @@ $(document).ready(function () {
|
|||
if (!name_field)
|
||||
name_field = "name";
|
||||
let input = target.val();
|
||||
target.addClass("is-invalid");
|
||||
target.removeClass("is-valid");
|
||||
$("#" + prefix + "_reset").removeClass("d-none");
|
||||
|
||||
$.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) {
|
||||
|
@ -27,6 +29,10 @@ $(document).ready(function () {
|
|||
target.val(obj[name_field]);
|
||||
$("#" + prefix + "_pk").val(obj.id);
|
||||
|
||||
results_list.html("");
|
||||
target.removeClass("is-invalid");
|
||||
target.addClass("is-valid");
|
||||
|
||||
if (typeof autocompleted != 'undefined')
|
||||
autocompleted(obj, prefix)
|
||||
});
|
||||
|
|
|
@ -7,70 +7,7 @@
|
|||
|
||||
{% 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 ".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>
|
||||
{% include "activity/activity_info.html" %}
|
||||
|
||||
{% if guests.data %}
|
||||
<hr>
|
||||
|
|
|
@ -76,6 +76,9 @@
|
|||
note: id,
|
||||
guest: null
|
||||
}).done(function () {
|
||||
if (target.hasClass("table-info"))
|
||||
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);
|
||||
}).fail(function(xhr) {
|
||||
|
@ -104,6 +107,9 @@
|
|||
note: target.attr("data-inviter"),
|
||||
guest: id
|
||||
}).done(function () {
|
||||
if (target.hasClass("table-info"))
|
||||
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);
|
||||
}).fail(function (xhr) {
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
{% 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>
|
|
@ -2,6 +2,14 @@
|
|||
{% load render_table from django_tables2 %}
|
||||
{% load i18n crispy_forms_tags%}
|
||||
{% 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>
|
||||
{% if upcoming.data %}
|
||||
{% render_table upcoming %}
|
||||
|
|
|
@ -57,6 +57,12 @@
|
|||
window.document.location = $(this).data("href");
|
||||
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();
|
||||
|
|
|
@ -19,11 +19,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
<input type="radio" name="transaction_type" id="type_credit">
|
||||
{% trans "Credit" %}
|
||||
</label>
|
||||
{% if not activities_open %}
|
||||
<label type="type_debit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_debit">
|
||||
{% trans "Debit" %}
|
||||
</label>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% for activity in activities_open %}
|
||||
<a href="{% url "activity:activity_entry" pk=activity.pk %}" class="btn btn-sm btn-outline-primary">
|
||||
{% trans "Entries" %} {{ activity.name }}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
{% load escape_tex %}
|
||||
{% load l10n %}
|
||||
|
||||
\nonstopmode
|
||||
\documentclass[11pt]{article}
|
||||
|
||||
|
@ -22,14 +25,13 @@
|
|||
\FPround{\prix}{#3}{2}
|
||||
\FPround{\montant}{#4}{2}
|
||||
\FPadd{\TotalHT}{\TotalHT}{\montant}
|
||||
|
||||
\eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr}
|
||||
}
|
||||
|
||||
\newcommand{\AfficheResultat}{%
|
||||
\ListeProduits
|
||||
|
||||
\FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
|
||||
\FPmul{\TotalTVA}{\TotalHT}{\TVA}
|
||||
\FPdiv{\TotalTVA}{\TotalTVA}{100}
|
||||
\FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
|
||||
\FPround{\TotalHT}{\TotalHT}{2}
|
||||
\FPround{\TotalTVA}{\TotalTVA}{2}
|
||||
|
@ -45,15 +47,14 @@
|
|||
\textbf{Total TTC} & & & \TotalTTC
|
||||
}
|
||||
|
||||
\newcommand*\eaddto[2]{% version développée de \addto
|
||||
\edef\tmp{#2}%
|
||||
\expandafter\addto
|
||||
\expandafter#1%
|
||||
\expandafter{\tmp}%
|
||||
\newcommand {\ListeProduits}{
|
||||
{% localize off %}
|
||||
{% for product in products %}
|
||||
{{ 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
|
||||
{% endfor %}
|
||||
{% endlocalize %}
|
||||
}
|
||||
|
||||
\newcommand {\ListeProduits}{}
|
||||
|
||||
% Logo du BDE
|
||||
\AddToShipoutPicture*{
|
||||
\put(0,0){
|
||||
|
@ -81,22 +82,22 @@
|
|||
\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib}
|
||||
\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\FactureLieu {{"{"}}{{ obj.place }}} % Lieu de l'édition de la facture
|
||||
\def\FactureLieu {{"{"}}{{ obj.place|safe|escape_tex }}} % Lieu de l'édition de la facture
|
||||
\def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture
|
||||
\def\FactureObjet {{"{"}}{{ obj.object|safe }} } % Objet du document
|
||||
\def\FactureObjet {{"{"}}{{ obj.object|safe|escape_tex }} } % Objet du document
|
||||
% Description de la facture
|
||||
\def\FactureDescr {{"{"}}{{ obj.description|safe }}}
|
||||
\def\FactureDescr {{"{"}}{{ obj.description|safe|escape_tex }}}
|
||||
|
||||
% Infos Client
|
||||
\def\ClientNom{{"{"}}{{obj.name|safe}}} % Nom du client
|
||||
\def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client
|
||||
\def\ClientNom{{"{"}}{{ obj.name|safe|escape_tex }}} % Nom du client
|
||||
\def\ClientAdresse{{"{"}}{{ obj.address|safe|escape_tex }}} % Adresse du client
|
||||
|
||||
% Liste des produits facturés : Désignation, quantité, prix unitaire HT
|
||||
|
||||
{% for product in products %}
|
||||
\AjouterProduit{ {{product.designation|safe}}} { {{product.quantity|safe}}} { {{product.amount_euros|safe}}} { {{product.total_euros|safe}}}
|
||||
\AjouterProduit{{"{"}}{{ product.designation|safe|escape_tex }}} {{"{"}}{{ product.quantity|safe|escape_tex }}} {{"{"}}{{ product.amount_euros|safe|escape_tex }}} {{"{"}}{{ product.total_euros|safe|escape_tex }}}
|
||||
{% endfor %}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
Loading…
Reference in New Issue