mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 09:12:11 +01: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),
 | 
						|
        }
 |