mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-08-03 06:03:58 +02:00
401 lines
14 KiB
Python
401 lines
14 KiB
Python
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from datetime import date
|
|
|
|
import django_tables2 as tables
|
|
from django.db.models import Q
|
|
from django.urls import reverse_lazy
|
|
from django.utils.html import format_html
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django_tables2 import A
|
|
from note_kfet.middlewares import get_current_request
|
|
from permission.backends import PermissionBackend
|
|
|
|
from .models import WEIClub, WEIRegistration, Bus, BusTeam, WEIMembership
|
|
|
|
|
|
class WEITable(tables.Table):
|
|
"""
|
|
List all WEI.
|
|
"""
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
model = WEIClub
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('name', 'year', 'date_start', 'date_end',)
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
'data-href': lambda record: reverse_lazy('wei:wei_detail', args=(record.pk,))
|
|
}
|
|
|
|
|
|
class WEIRegistrationTable(tables.Table):
|
|
"""
|
|
List all WEI registrations.
|
|
"""
|
|
user = tables.LinkColumn(
|
|
'member:user_detail',
|
|
args=[A('user__pk')],
|
|
)
|
|
|
|
edit = tables.LinkColumn(
|
|
'wei:wei_update_registration',
|
|
orderable=False,
|
|
args=[A('pk')],
|
|
verbose_name=_("Edit"),
|
|
text=_("Edit"),
|
|
attrs={
|
|
'a': {
|
|
'class': 'btn btn-warning',
|
|
'data-turbolinks': 'false',
|
|
}
|
|
}
|
|
)
|
|
|
|
validate = tables.Column(
|
|
verbose_name=_("Validate"),
|
|
orderable=True,
|
|
accessor='validate_status',
|
|
attrs={
|
|
'th': {
|
|
'id': 'validate-membership-header'
|
|
}
|
|
}
|
|
)
|
|
|
|
delete = tables.LinkColumn(
|
|
'wei:wei_delete_registration',
|
|
args=[A('pk')],
|
|
orderable=False,
|
|
verbose_name=_("Delete"),
|
|
text=_("Delete"),
|
|
attrs={
|
|
'th': {
|
|
'id': 'delete-membership-header'
|
|
},
|
|
'a': {
|
|
'class': 'btn btn-danger',
|
|
'data-type': 'delete-membership'
|
|
}
|
|
},
|
|
)
|
|
|
|
def render_deposit_type(self, record):
|
|
if record.first_year:
|
|
return format_html("∅")
|
|
if record.deposit_type == 'check':
|
|
# TODO Install Font Awesome 6 to acces more icons (and keep compaibility with current used v4)
|
|
return format_html("""
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1.5em" height="1.5em"
|
|
fill="currentColor" style="position: relative; left: -0.15em;">
|
|
<path d="
|
|
M128 128C92.7 128 64 156.7 64 192L64 448C64 483.3 92.7 512 128 512L512 512
|
|
C547.3 512 576 483.3 576 448L576 192C576 156.7 547.3 128 512 128L128 128z
|
|
M360 352L488 352C501.3 352 512 362.7 512 376C512 389.3 501.3 400 488 400L360 400
|
|
C346.7 400 336 389.3 336 376C336 362.7 346.7 352 360 352z
|
|
M336 264C336 250.7 346.7 240 360 240L488 240C501.3 240 512 250.7 512 264
|
|
C512 277.3 501.3 288 488 288L360 288C346.7 288 336 277.3 336 264z
|
|
M212 208C223 208 232 217 232 228L232 232L240 232C251 232 260 241 260 252
|
|
C260 263 251 272 240 272L192.5 272C185.6 272 180 277.6 180 284.5
|
|
C180 290.6 184.4 295.8 190.4 296.8L232.1 303.8C257.4 308 276 329.9 276 355.6
|
|
C276 381.7 257 403.3 232 407.4L232 412.1C232 423.1 223 432.1 212 432.1
|
|
C201 432.1 192 423.1 192 412.1L192 408.1L168 408.1C157 408.1 148 399.1 148 388.1
|
|
C148 377.1 157 368.1 168 368.1L223.5 368.1C230.4 368.1 236 362.5 236 355.6
|
|
C236 349.5 231.6 344.3 225.6 343.3L183.9 336.3C158.5 332 140 310.1 140 284.5
|
|
C140 255.7 163.2 232.3 192 232L192 228C192 217 201 208 212 208z
|
|
" />
|
|
</svg>
|
|
""")
|
|
if record.deposit_type == 'note':
|
|
return format_html("<i class=\"fa fa-exchange\"></i>")
|
|
|
|
def render_validate(self, record):
|
|
hasperm = PermissionBackend.check_perm(
|
|
get_current_request(), "wei.add_weimembership", WEIMembership(
|
|
club=record.wei,
|
|
user=record.user,
|
|
date_start=date.today(),
|
|
date_end=date.today(),
|
|
fee=0,
|
|
registration=record,
|
|
)
|
|
)
|
|
if not hasperm:
|
|
return format_html("<span class='no-perm'></span>")
|
|
|
|
url = reverse_lazy('wei:validate_registration', args=(record.pk,))
|
|
text = _('Validate')
|
|
status = record.validation_status
|
|
if status == 2:
|
|
btn_class = 'btn-secondary'
|
|
tooltip = _("The user does not have enough money.")
|
|
elif status == 1:
|
|
btn_class = 'btn-info'
|
|
tooltip = _("The user is in first year. You may validate the credit, the algorithm will run later.")
|
|
else:
|
|
btn_class = 'btn-success'
|
|
tooltip = _("The user has enough money, you can validate the registration.")
|
|
|
|
return format_html(f"<a class=\"btn {btn_class}\" data-type='validate-membership' data-toggle=\"tooltip\" "
|
|
f"title=\"{tooltip}\" href=\"{url}\">{text}</a>")
|
|
|
|
def render_delete(self, record):
|
|
hasperm = PermissionBackend.check_perm(get_current_request(), "wei.delete_weimembership", record)
|
|
return _("Delete") if hasperm else format_html("<span class='no-perm'></span>")
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
order_by = ('validate', 'user',)
|
|
model = WEIRegistration
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('user', 'user__first_name', 'user__last_name', 'first_year', 'deposit_given',
|
|
'deposit_type', 'edit', 'validate', 'delete',)
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
'data-href': lambda record: record.pk
|
|
}
|
|
|
|
|
|
class WEIMembershipTable(tables.Table):
|
|
user = tables.LinkColumn(
|
|
'wei:wei_update_membership',
|
|
args=[A('pk')],
|
|
)
|
|
|
|
year = tables.Column(
|
|
accessor=A("pk"),
|
|
verbose_name=_("Year"),
|
|
)
|
|
|
|
bus = tables.LinkColumn(
|
|
'wei:manage_bus',
|
|
args=[A('bus__pk')],
|
|
)
|
|
|
|
team = tables.LinkColumn(
|
|
'wei:manage_bus_team',
|
|
args=[A('team__pk')],
|
|
)
|
|
|
|
def render_year(self, record):
|
|
return str(record.user.profile.ens_year) + "A"
|
|
|
|
def render_registration__deposit_type(self, record):
|
|
if record.registration.first_year:
|
|
return format_html("∅")
|
|
if record.registration.deposit_type == 'check':
|
|
# TODO Install Font Awesome 6 to acces more icons (and keep compaibility with current used v4)
|
|
return format_html("""
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1.5em" height="1.5em"
|
|
fill="currentColor" style="position: relative; left: -0.15em;">
|
|
<path d="
|
|
M128 128C92.7 128 64 156.7 64 192L64 448C64 483.3 92.7 512 128 512L512 512
|
|
C547.3 512 576 483.3 576 448L576 192C576 156.7 547.3 128 512 128L128 128z
|
|
M360 352L488 352C501.3 352 512 362.7 512 376C512 389.3 501.3 400 488 400L360 400
|
|
C346.7 400 336 389.3 336 376C336 362.7 346.7 352 360 352z
|
|
M336 264C336 250.7 346.7 240 360 240L488 240C501.3 240 512 250.7 512 264
|
|
C512 277.3 501.3 288 488 288L360 288C346.7 288 336 277.3 336 264z
|
|
M212 208C223 208 232 217 232 228L232 232L240 232C251 232 260 241 260 252
|
|
C260 263 251 272 240 272L192.5 272C185.6 272 180 277.6 180 284.5
|
|
C180 290.6 184.4 295.8 190.4 296.8L232.1 303.8C257.4 308 276 329.9 276 355.6
|
|
C276 381.7 257 403.3 232 407.4L232 412.1C232 423.1 223 432.1 212 432.1
|
|
C201 432.1 192 423.1 192 412.1L192 408.1L168 408.1C157 408.1 148 399.1 148 388.1
|
|
C148 377.1 157 368.1 168 368.1L223.5 368.1C230.4 368.1 236 362.5 236 355.6
|
|
C236 349.5 231.6 344.3 225.6 343.3L183.9 336.3C158.5 332 140 310.1 140 284.5
|
|
C140 255.7 163.2 232.3 192 232L192 228C192 217 201 208 212 208z
|
|
" />
|
|
</svg>
|
|
""")
|
|
if record.registration.deposit_type == 'note':
|
|
return format_html("<i class=\"fa fa-exchange\"></i>")
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
model = WEIMembership
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('user', 'user__last_name', 'user__first_name', 'registration__gender', 'user__profile__department',
|
|
'year', 'bus', 'team', 'registration__deposit_given', 'registration__deposit_type')
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
}
|
|
|
|
|
|
class WEIRegistration1ATable(tables.Table):
|
|
user = tables.LinkColumn(
|
|
'wei:wei_bus_1A',
|
|
args=[A('pk')],
|
|
)
|
|
|
|
preferred_bus = tables.Column(
|
|
verbose_name=_('preferred bus').capitalize,
|
|
accessor='pk',
|
|
orderable=False,
|
|
)
|
|
|
|
def render_preferred_bus(self, record):
|
|
information = record.information
|
|
return information['selected_bus_name'] if 'selected_bus_name' in information else "—"
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
model = WEIRegistration
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('user', 'user__last_name', 'user__first_name', 'gender',
|
|
'user__profile__department', 'preferred_bus', 'membership__bus', )
|
|
row_attrs = {
|
|
'class': lambda record: '' if 'selected_bus_pk' in record.information else 'bg-danger',
|
|
}
|
|
|
|
|
|
class BusTable(tables.Table):
|
|
name = tables.LinkColumn(
|
|
'wei:manage_bus',
|
|
args=[A('pk')],
|
|
)
|
|
|
|
teams = tables.Column(
|
|
accessor=A("teams"),
|
|
verbose_name=_("Teams"),
|
|
attrs={
|
|
"td": {
|
|
"class": "text-truncate",
|
|
}
|
|
}
|
|
)
|
|
|
|
count = tables.Column(
|
|
verbose_name=_("Members count"),
|
|
)
|
|
|
|
def render_teams(self, value):
|
|
return ", ".join(team.name for team in value.order_by('name').all())
|
|
|
|
def render_count(self, value):
|
|
return str(value) + " " + (str(_("members")) if value > 1 else str(_("member")))
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
model = Bus
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('name', 'teams', )
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
}
|
|
|
|
|
|
class BusTeamTable(tables.Table):
|
|
name = tables.LinkColumn(
|
|
'wei:manage_bus_team',
|
|
args=[A('pk')],
|
|
)
|
|
|
|
color = tables.Column(
|
|
attrs={
|
|
"td": {
|
|
"style": lambda record: "background-color: #{:06X}; color: #{:06X};"
|
|
.format(record.color, 0xFFFFFF - record.color, )
|
|
}
|
|
}
|
|
)
|
|
|
|
def render_count(self, value):
|
|
return str(value) + " " + (str(_("members")) if value > 1 else str(_("member")))
|
|
|
|
count = tables.Column(
|
|
verbose_name=_("Members count"),
|
|
)
|
|
|
|
def render_color(self, value):
|
|
return "#{:06X}".format(value)
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
model = BusTeam
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('name', 'color',)
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
'data-href': lambda record: reverse_lazy('wei:manage_bus_team', args=(record.pk, ))
|
|
}
|
|
|
|
|
|
class BusRepartitionTable(tables.Table):
|
|
name = tables.Column(
|
|
verbose_name=_("name").capitalize,
|
|
accessor='name',
|
|
)
|
|
|
|
suggested_first_year = tables.Column(
|
|
verbose_name=_("suggested first year").capitalize,
|
|
accessor='pk',
|
|
orderable=False,
|
|
)
|
|
|
|
validated_first_year = tables.Column(
|
|
verbose_name=_("validated first year").capitalize,
|
|
accessor='pk',
|
|
orderable=False,
|
|
)
|
|
|
|
validated_staff = tables.Column(
|
|
verbose_name=_("validated staff").capitalize,
|
|
accessor='pk',
|
|
orderable=False,
|
|
)
|
|
|
|
size = tables.Column(
|
|
verbose_name=_("seat count in the bus").capitalize,
|
|
accessor='size',
|
|
)
|
|
|
|
free_seats = tables.Column(
|
|
verbose_name=_("free seats").capitalize,
|
|
accessor='pk',
|
|
orderable=False,
|
|
)
|
|
|
|
def render_suggested_first_year(self, record):
|
|
registrations = WEIRegistration.objects.filter(Q(membership__isnull=True) | Q(membership__bus__isnull=True),
|
|
first_year=True, wei=record.wei)
|
|
registrations = [r for r in registrations if 'selected_bus_pk' in r.information]
|
|
return sum(1 for r in registrations if r.information['selected_bus_pk'] == record.pk)
|
|
|
|
def render_validated_first_year(self, record):
|
|
return WEIRegistration.objects.filter(first_year=True, membership__bus=record).count()
|
|
|
|
def render_validated_staff(self, record):
|
|
return WEIRegistration.objects.filter(first_year=False, membership__bus=record).count()
|
|
|
|
def render_free_seats(self, record):
|
|
return record.size - self.render_validated_staff(record) - self.render_validated_first_year(record)
|
|
|
|
class Meta:
|
|
attrs = {
|
|
'class': 'table table-condensed table-striped table-hover'
|
|
}
|
|
models = Bus
|
|
template_name = 'django_tables2/bootstrap4.html'
|
|
fields = ('name', )
|
|
row_attrs = {
|
|
'class': 'table-row',
|
|
'id': lambda record: "row-" + str(record.pk),
|
|
}
|