mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-30 13:11:09 +02:00
Compare commits
2 Commits
11223430fd
...
nix-shell
Author | SHA1 | Date | |
---|---|---|---|
dde1baa25c | |||
7a7ee47e0b |
2
.gitignore
vendored
2
.gitignore
vendored
@ -42,13 +42,11 @@ map.json
|
||||
backups/
|
||||
/static/
|
||||
/media/
|
||||
/tmp/
|
||||
|
||||
# Virtualenv
|
||||
env/
|
||||
venv/
|
||||
db.sqlite3
|
||||
shell.nix
|
||||
|
||||
# ansibles customs host
|
||||
ansible/host_vars/*.yaml
|
||||
|
@ -1,5 +0,0 @@
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
|
||||
class CustomPagination(PageNumberPagination):
|
||||
page_size_query_param = 'page_size'
|
||||
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.2.26 on 2022-09-04 21:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('member', '0008_auto_20211005_1544'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='profile',
|
||||
name='promotion',
|
||||
field=models.PositiveSmallIntegerField(default=2022, help_text='Year of entry to the school (None if not ENS student)', null=True, verbose_name='promotion'),
|
||||
),
|
||||
]
|
@ -1967,7 +1967,7 @@
|
||||
"note",
|
||||
"transaction"
|
||||
],
|
||||
"query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]]",
|
||||
"query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]]",
|
||||
"type": "change",
|
||||
"mask": 2,
|
||||
"field": "valid",
|
||||
@ -2607,7 +2607,7 @@
|
||||
"note",
|
||||
"transaction"
|
||||
],
|
||||
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]",
|
||||
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]",
|
||||
"type": "change",
|
||||
"mask": 2,
|
||||
"field": "valid",
|
||||
@ -2623,7 +2623,7 @@
|
||||
"note",
|
||||
"transaction"
|
||||
],
|
||||
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]",
|
||||
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]",
|
||||
"type": "change",
|
||||
"mask": 2,
|
||||
"field": "invalidity_reason",
|
||||
|
Submodule apps/scripts updated: 4471307b37...86bc2d2698
@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.2.28 on 2023-01-29 22:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('treasury', '0004_auto_20211005_1544'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='invoice',
|
||||
name='bde',
|
||||
field=models.CharField(choices=[('TotalistSpies', 'Tota[list]Spies'), ('Saperlistpopette', 'Saper[list]popette'), ('Finalist', 'Fina[list]'), ('Listorique', '[List]orique'), ('Satellist', 'Satel[list]'), ('Monopolist', 'Monopo[list]'), ('Kataclist', 'Katac[list]')], default='TotalistSpies', max_length=32, verbose_name='BDE'),
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.2.28 on 2023-04-14 14:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('treasury', '0005_auto_20230129_2348'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='invoice',
|
||||
name='bde',
|
||||
field=models.CharField(choices=[('SecretStorlist', 'SecretStor[list]'), ('TotalistSpies', 'Tota[list]Spies'), ('Saperlistpopette', 'Saper[list]popette'), ('Finalist', 'Fina[list]'), ('Listorique', '[List]orique'), ('Satellist', 'Satel[list]'), ('Monopolist', 'Monopo[list]'), ('Kataclist', 'Katac[list]')], default='SecretStorlist', max_length=32, verbose_name='BDE'),
|
||||
),
|
||||
]
|
@ -28,10 +28,8 @@ class Invoice(models.Model):
|
||||
|
||||
bde = models.CharField(
|
||||
max_length=32,
|
||||
default='SecretStorlist',
|
||||
default='Saperlistpopette',
|
||||
choices=(
|
||||
('SecretStorlist', 'SecretStor[list]'),
|
||||
('TotalistSpies', 'Tota[list]Spies'),
|
||||
('Saperlistpopette', 'Saper[list]popette'),
|
||||
('Finalist', 'Fina[list]'),
|
||||
('Listorique', '[List]orique'),
|
||||
@ -97,7 +95,7 @@ class Invoice(models.Model):
|
||||
products = self.products.all()
|
||||
|
||||
self.place = "Gif-sur-Yvette"
|
||||
self.my_name = "BDE ENS Paris Saclay"
|
||||
self.my_name = "BDE ENS Cachan"
|
||||
self.my_address_street = "4 avenue des Sciences"
|
||||
self.my_city = "91190 Gif-sur-Yvette"
|
||||
self.bank_code = 30003
|
||||
@ -312,8 +310,8 @@ class SogeCredit(models.Model):
|
||||
amount = sum(transaction.total for transaction in self.transactions.all())
|
||||
if 'wei' in settings.INSTALLED_APPS:
|
||||
from wei.models import WEIMembership
|
||||
if not WEIMembership.objects\
|
||||
.filter(club__weiclub__year=self.credit_transaction.created_at.year, user=self.user).exists():
|
||||
if not WEIMembership.objects.filter(club__weiclub__year=datetime.date.today().year, user=self.user)\
|
||||
.exists():
|
||||
# 80 € for people that don't go to WEI
|
||||
amount += 8000
|
||||
return amount
|
||||
@ -331,18 +329,17 @@ class SogeCredit(models.Model):
|
||||
bde_qs = Membership.objects.filter(user=self.user, club=bde, date_start__gte=bde.membership_start)
|
||||
kfet_qs = Membership.objects.filter(user=self.user, club=kfet, date_start__gte=kfet.membership_start)
|
||||
|
||||
## Soge do not pay BDE and kfet memberships this year (2022-2023)
|
||||
# if bde_qs.exists():
|
||||
# m = bde_qs.get()
|
||||
# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
# if m.transaction not in self.transactions.all():
|
||||
# self.transactions.add(m.transaction)
|
||||
#
|
||||
# if kfet_qs.exists():
|
||||
# m = kfet_qs.get()
|
||||
# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
# if m.transaction not in self.transactions.all():
|
||||
# self.transactions.add(m.transaction)
|
||||
if bde_qs.exists():
|
||||
m = bde_qs.get()
|
||||
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
|
||||
if kfet_qs.exists():
|
||||
m = kfet_qs.get()
|
||||
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
|
||||
if 'wei' in settings.INSTALLED_APPS:
|
||||
from wei.models import WEIClub
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 690 KiB |
Binary file not shown.
Before Width: | Height: | Size: 77 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
Before Width: | Height: | Size: 35 KiB |
@ -105,8 +105,8 @@
|
||||
|
||||
\renewcommand{\headrulewidth}{0pt}
|
||||
\cfoot{
|
||||
\small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)7 78 17 22 34\newline
|
||||
Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00029
|
||||
\small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)6 89 88 56 50\newline
|
||||
Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm
|
||||
from .wei2023 import WEISurvey2023
|
||||
from .wei2022 import WEISurvey2022
|
||||
|
||||
|
||||
__all__ = [
|
||||
'WEISurvey', 'WEISurveyInformation', 'WEISurveyAlgorithm', 'CurrentSurvey',
|
||||
]
|
||||
|
||||
CurrentSurvey = WEISurvey2023
|
||||
CurrentSurvey = WEISurvey2022
|
||||
|
@ -14,17 +14,14 @@ from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInf
|
||||
from ...models import WEIMembership
|
||||
|
||||
WORDS = [
|
||||
'ABBA', 'After', 'Alcoolique anonyme', 'Ambiance festive', 'Années 2000', 'Apéro', 'Art',
|
||||
'Baby foot billard biere pong', 'BBQ', 'Before', 'Bière pong', 'Bon enfant', 'Calme', 'Canapé',
|
||||
'Chanson paillarde', 'Chanson populaire', 'Chartreuse', 'Cheerleader', 'Chill', 'Choré',
|
||||
'Cinéma', 'Cocktail', 'Comédie musicle', 'Commercial', 'Copaing', 'Danse', 'Dancefloor',
|
||||
'Electro', 'Fanfare', 'Gin tonic', 'Inclusif', 'Jazz', "Jeux d'alcool", 'Jeux de carte',
|
||||
'Jeux de rôle', 'Jeux de société', 'JUL', 'Jus de fruit', 'Kfet', 'Kleptomanie assurée',
|
||||
'LGBTQ+', 'Livre', 'Morning beer', 'Musique', 'NAPS', 'Paillettes', 'Pastis', 'Paté Hénaff',
|
||||
'Peluche', 'Pena baiona', "Peu d'alcool", 'Pilier de bar', 'PMU', 'Poulpe', 'Punch', 'Rap',
|
||||
'Réveil', 'Rock', 'Rugby', 'Sandwich', 'Serge', 'Shot', 'Sociable', 'Spectacle', 'Techno',
|
||||
'Techno house', 'Thérapie Taxi', 'Tradition kchanaises', 'Troisième mi-temps', 'Turn up',
|
||||
'Vodka', 'Vodka pomme', 'Volley', 'Vomi stratégique'
|
||||
'13 organisé', '3ième mi temps', 'Années 2000', 'Apéro', 'BBQ', 'BP', 'Beauf', 'Binge drinking', 'Bon enfant',
|
||||
'Cartouche', 'Catacombes', 'Chansons paillardes', 'Chansons populaires', 'Chanteur', 'Chartreuse', 'Chill',
|
||||
'Core', 'DJ', 'Dancefloor', 'Danse', 'David Guetta', 'Disco', 'Eau de vie', 'Électro', 'Escalade', 'Familial',
|
||||
'Fanfare', 'Fracassage', 'Féria', 'Hard rock', 'Hoeggarden', 'House', 'Huit-six', 'IPA', 'Inclusif', 'Inferno',
|
||||
'Introverti', 'Jager bomb', 'Jazz', 'Jeux d\'alcool', 'Jeux de rôles', 'Jeux vidéo', 'Jul', 'Jus de fruit',
|
||||
'Karaoké', 'LGBTQI+', 'Lady Gaga', 'Loup garou', 'Morning beer', 'Métal', 'Nuit blanche', 'Ovalie', 'Psychedelic',
|
||||
'Pétanque', 'Rave', 'Reggae', 'Rhum', 'Ricard', 'Rock', 'Rosé', 'Rétro', 'Séducteur', 'Techno', 'Thérapie taxi',
|
||||
'Théâtre', 'Trap', 'Turn up', 'Underground', 'Volley', 'Wati B', 'Zinédine Zidane',
|
||||
]
|
||||
|
||||
|
||||
|
@ -1,296 +0,0 @@
|
||||
# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import time
|
||||
from functools import lru_cache
|
||||
from random import Random
|
||||
|
||||
from django import forms
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
|
||||
from ...models import WEIMembership
|
||||
|
||||
WORDS = [
|
||||
'ABBA', 'After', 'Alcoolique anonyme', 'Ambiance festive', 'Années 2000', 'Apéro', 'Art',
|
||||
'Baby foot billard biere pong', 'BBQ', 'Before', 'Bière pong', 'Bon enfant', 'Calme', 'Canapé',
|
||||
'Chanson paillarde', 'Chanson populaire', 'Chartreuse', 'Cheerleader', 'Chill', 'Choré',
|
||||
'Cinéma', 'Cocktail', 'Comédie musicle', 'Commercial', 'Copaing', 'Danse', 'Dancefloor',
|
||||
'Electro', 'Fanfare', 'Gin tonic', 'Inclusif', 'Jazz', "Jeux d'alcool", 'Jeux de carte',
|
||||
'Jeux de rôle', 'Jeux de société', 'JUL', 'Jus de fruit', 'Kfet', 'Kleptomanie assurée',
|
||||
'LGBTQ+', 'Livre', 'Morning beer', 'Musique', 'NAPS', 'Paillettes', 'Pastis', 'Paté Hénaff',
|
||||
'Peluche', 'Pena baiona', "Peu d'alcool", 'Pilier de bar', 'PMU', 'Poulpe', 'Punch', 'Rap',
|
||||
'Réveil', 'Rock', 'Rugby', 'Sandwich', 'Serge', 'Shot', 'Sociable', 'Spectacle', 'Techno',
|
||||
'Techno house', 'Thérapie Taxi', 'Tradition kchanaises', 'Troisième mi-temps', 'Turn up',
|
||||
'Vodka', 'Vodka pomme', 'Volley', 'Vomi stratégique'
|
||||
]
|
||||
|
||||
|
||||
class WEISurveyForm2023(forms.Form):
|
||||
"""
|
||||
Survey form for the year 2023.
|
||||
Members choose 20 words, from which we calculate the best associated bus.
|
||||
"""
|
||||
|
||||
word = forms.ChoiceField(
|
||||
label=_("Choose a word:"),
|
||||
widget=forms.RadioSelect(),
|
||||
)
|
||||
|
||||
def set_registration(self, registration):
|
||||
"""
|
||||
Filter the bus selector with the buses of the current WEI.
|
||||
"""
|
||||
information = WEISurveyInformation2023(registration)
|
||||
if not information.seed:
|
||||
information.seed = int(1000 * time.time())
|
||||
information.save(registration)
|
||||
registration._force_save = True
|
||||
registration.save()
|
||||
|
||||
if self.data:
|
||||
self.fields["word"].choices = [(w, w) for w in WORDS]
|
||||
if self.is_valid():
|
||||
return
|
||||
|
||||
rng = Random((information.step + 1) * information.seed)
|
||||
|
||||
words = None
|
||||
|
||||
buses = WEISurveyAlgorithm2023.get_buses()
|
||||
informations = {bus: WEIBusInformation2023(bus) for bus in buses}
|
||||
scores = sum((list(informations[bus].scores.values()) for bus in buses), [])
|
||||
average_score = sum(scores) / len(scores)
|
||||
|
||||
preferred_words = {bus: [word for word in WORDS
|
||||
if informations[bus].scores[word] >= average_score]
|
||||
for bus in buses}
|
||||
while words is None or len(set(words)) != len(words):
|
||||
# Ensure that there is no the same word 2 times
|
||||
words = [rng.choice(words) for _ignored2, words in preferred_words.items()]
|
||||
rng.shuffle(words)
|
||||
words = [(w, w) for w in words]
|
||||
self.fields["word"].choices = words
|
||||
|
||||
|
||||
class WEIBusInformation2023(WEIBusInformation):
|
||||
"""
|
||||
For each word, the bus has a score
|
||||
"""
|
||||
scores: dict
|
||||
|
||||
def __init__(self, bus):
|
||||
self.scores = {}
|
||||
for word in WORDS:
|
||||
self.scores[word] = 0.0
|
||||
super().__init__(bus)
|
||||
|
||||
|
||||
class WEISurveyInformation2023(WEISurveyInformation):
|
||||
"""
|
||||
We store the id of the selected bus. We store only the name, but is not used in the selection:
|
||||
that's only for humans that try to read data.
|
||||
"""
|
||||
# Random seed that is stored at the first time to ensure that words are generated only once
|
||||
seed = 0
|
||||
step = 0
|
||||
|
||||
def __init__(self, registration):
|
||||
for i in range(1, 21):
|
||||
setattr(self, "word" + str(i), None)
|
||||
super().__init__(registration)
|
||||
|
||||
|
||||
class WEISurvey2023(WEISurvey):
|
||||
"""
|
||||
Survey for the year 2023.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_year(cls):
|
||||
return 2023
|
||||
|
||||
@classmethod
|
||||
def get_survey_information_class(cls):
|
||||
return WEISurveyInformation2023
|
||||
|
||||
def get_form_class(self):
|
||||
return WEISurveyForm2023
|
||||
|
||||
def update_form(self, form):
|
||||
"""
|
||||
Filter the bus selector with the buses of the WEI.
|
||||
"""
|
||||
form.set_registration(self.registration)
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
word = form.cleaned_data["word"]
|
||||
self.information.step += 1
|
||||
setattr(self.information, "word" + str(self.information.step), word)
|
||||
self.save()
|
||||
|
||||
@classmethod
|
||||
def get_algorithm_class(cls):
|
||||
return WEISurveyAlgorithm2023
|
||||
|
||||
def is_complete(self) -> bool:
|
||||
"""
|
||||
The survey is complete once the bus is chosen.
|
||||
"""
|
||||
return self.information.step == 20
|
||||
|
||||
@classmethod
|
||||
@lru_cache()
|
||||
def word_mean(cls, word):
|
||||
"""
|
||||
Calculate the mid-score given by all buses.
|
||||
"""
|
||||
buses = cls.get_algorithm_class().get_buses()
|
||||
return sum([cls.get_algorithm_class().get_bus_information(bus).scores[word] for bus in buses]) / buses.count()
|
||||
|
||||
@lru_cache()
|
||||
def score(self, bus):
|
||||
if not self.is_complete():
|
||||
raise ValueError("Survey is not ended, can't calculate score")
|
||||
|
||||
bus_info = self.get_algorithm_class().get_bus_information(bus)
|
||||
# Score is the given score by the bus subtracted to the mid-score of the buses.
|
||||
s = sum(bus_info.scores[getattr(self.information, 'word' + str(i))]
|
||||
- self.word_mean(getattr(self.information, 'word' + str(i))) for i in range(1, 21)) / 20
|
||||
return s
|
||||
|
||||
@lru_cache()
|
||||
def scores_per_bus(self):
|
||||
return {bus: self.score(bus) for bus in self.get_algorithm_class().get_buses()}
|
||||
|
||||
@lru_cache()
|
||||
def ordered_buses(self):
|
||||
values = list(self.scores_per_bus().items())
|
||||
values.sort(key=lambda item: -item[1])
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def clear_cache(cls):
|
||||
cls.word_mean.cache_clear()
|
||||
return super().clear_cache()
|
||||
|
||||
|
||||
class WEISurveyAlgorithm2023(WEISurveyAlgorithm):
|
||||
"""
|
||||
The algorithm class for the year 2023.
|
||||
We use Gale-Shapley algorithm to attribute 1y students into buses.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_survey_class(cls):
|
||||
return WEISurvey2023
|
||||
|
||||
@classmethod
|
||||
def get_bus_information_class(cls):
|
||||
return WEIBusInformation2023
|
||||
|
||||
def run_algorithm(self, display_tqdm=False):
|
||||
"""
|
||||
Gale-Shapley algorithm implementation.
|
||||
We modify it to allow buses to have multiple "weddings".
|
||||
"""
|
||||
surveys = list(self.get_survey_class()(r) for r in self.get_registrations()) # All surveys
|
||||
surveys = [s for s in surveys if s.is_complete()] # Don't consider invalid surveys
|
||||
# Don't manage hardcoded people
|
||||
surveys = [s for s in surveys if not hasattr(s.information, 'hardcoded') or not s.information.hardcoded]
|
||||
|
||||
# Reset previous algorithm run
|
||||
for survey in surveys:
|
||||
survey.free()
|
||||
survey.save()
|
||||
|
||||
non_men = [s for s in surveys if s.registration.gender != 'male']
|
||||
men = [s for s in surveys if s.registration.gender == 'male']
|
||||
|
||||
quotas = {}
|
||||
registrations = self.get_registrations()
|
||||
non_men_total = registrations.filter(~Q(gender='male')).count()
|
||||
for bus in self.get_buses():
|
||||
free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
|
||||
# Remove hardcoded people
|
||||
free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
|
||||
registration__information_json__icontains="hardcoded").count()
|
||||
quotas[bus] = 4 + int(non_men_total / registrations.count() * free_seats)
|
||||
|
||||
tqdm_obj = None
|
||||
if display_tqdm:
|
||||
from tqdm import tqdm
|
||||
tqdm_obj = tqdm(total=len(non_men), desc="Non-hommes")
|
||||
|
||||
# Repartition for non men people first
|
||||
self.make_repartition(non_men, quotas, tqdm_obj=tqdm_obj)
|
||||
|
||||
quotas = {}
|
||||
for bus in self.get_buses():
|
||||
free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
|
||||
free_seats -= sum(1 for s in non_men if s.information.selected_bus_pk == bus.pk)
|
||||
# Remove hardcoded people
|
||||
free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
|
||||
registration__information_json__icontains="hardcoded").count()
|
||||
quotas[bus] = free_seats
|
||||
|
||||
if display_tqdm:
|
||||
tqdm_obj.close()
|
||||
|
||||
from tqdm import tqdm
|
||||
tqdm_obj = tqdm(total=len(men), desc="Hommes")
|
||||
|
||||
self.make_repartition(men, quotas, tqdm_obj=tqdm_obj)
|
||||
|
||||
if display_tqdm:
|
||||
tqdm_obj.close()
|
||||
|
||||
# Clear cache information after running algorithm
|
||||
WEISurvey2023.clear_cache()
|
||||
|
||||
def make_repartition(self, surveys, quotas=None, tqdm_obj=None):
|
||||
free_surveys = surveys.copy() # Remaining surveys
|
||||
while free_surveys: # Some students are not affected
|
||||
survey = free_surveys[0]
|
||||
buses = survey.ordered_buses() # Preferences of the student
|
||||
for bus, current_score in buses:
|
||||
if self.get_bus_information(bus).has_free_seats(surveys, quotas):
|
||||
# Selected bus has free places. Put student in the bus
|
||||
survey.select_bus(bus)
|
||||
survey.save()
|
||||
free_surveys.remove(survey)
|
||||
break
|
||||
else:
|
||||
# Current bus has not enough places. Remove the least preferred student from the bus if existing
|
||||
least_preferred_survey = None
|
||||
least_score = -1
|
||||
# Find the least student in the bus that has a lower score than the current student
|
||||
for survey2 in surveys:
|
||||
if not survey2.information.valid or survey2.information.get_selected_bus() != bus:
|
||||
continue
|
||||
score2 = survey2.score(bus)
|
||||
if current_score <= score2: # Ignore better students
|
||||
continue
|
||||
if least_preferred_survey is None or score2 < least_score:
|
||||
least_preferred_survey = survey2
|
||||
least_score = score2
|
||||
|
||||
if least_preferred_survey is not None:
|
||||
# Remove the least student from the bus and put the current student in.
|
||||
# If it does not exist, choose the next bus.
|
||||
least_preferred_survey.free()
|
||||
least_preferred_survey.save()
|
||||
free_surveys.append(least_preferred_survey)
|
||||
survey.select_bus(bus)
|
||||
survey.save()
|
||||
free_surveys.remove(survey)
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"User {survey.registration.user} has no free seat")
|
||||
|
||||
if tqdm_obj is not None:
|
||||
tqdm_obj.n = len(surveys) - len(free_surveys)
|
||||
tqdm_obj.refresh()
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.2.26 on 2022-09-04 21:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wei', '0003_bus_size'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='weiclub',
|
||||
name='year',
|
||||
field=models.PositiveIntegerField(default=2022, unique=True, verbose_name='year'),
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.2.28 on 2023-01-28 17:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wei', '0004_auto_20220904_2325'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='weiclub',
|
||||
name='year',
|
||||
field=models.PositiveIntegerField(default=2023, unique=True, verbose_name='year'),
|
||||
),
|
||||
]
|
@ -1,110 +0,0 @@
|
||||
# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import random
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
|
||||
from ..forms.surveys.wei2023 import WEIBusInformation2023, WEISurvey2023, WORDS, WEISurveyInformation2023
|
||||
from ..models import Bus, WEIClub, WEIRegistration
|
||||
|
||||
|
||||
class TestWEIAlgorithm(TestCase):
|
||||
"""
|
||||
Run some tests to ensure that the WEI algorithm is working well.
|
||||
"""
|
||||
fixtures = ('initial',)
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create some test data, with one WEI and 10 buses with random score attributions.
|
||||
"""
|
||||
self.wei = WEIClub.objects.create(
|
||||
name="WEI 2023",
|
||||
email="wei2023@example.com",
|
||||
date_start='2023-09-16',
|
||||
date_end='2023-09-18',
|
||||
year=2023,
|
||||
)
|
||||
|
||||
self.buses = []
|
||||
for i in range(10):
|
||||
bus = Bus.objects.create(wei=self.wei, name=f"Bus {i}", size=10)
|
||||
self.buses.append(bus)
|
||||
information = WEIBusInformation2023(bus)
|
||||
for word in WORDS:
|
||||
information.scores[word] = random.randint(0, 101)
|
||||
information.save()
|
||||
bus.save()
|
||||
|
||||
def test_survey_algorithm_small(self):
|
||||
"""
|
||||
There are only a few people in each bus, ensure that each person has its best bus
|
||||
"""
|
||||
# Add a few users
|
||||
for i in range(10):
|
||||
user = User.objects.create(username=f"user{i}")
|
||||
registration = WEIRegistration.objects.create(
|
||||
user=user,
|
||||
wei=self.wei,
|
||||
first_year=True,
|
||||
birth_date='2000-01-01',
|
||||
)
|
||||
information = WEISurveyInformation2023(registration)
|
||||
for j in range(1, 21):
|
||||
setattr(information, f'word{j}', random.choice(WORDS))
|
||||
information.step = 20
|
||||
information.save(registration)
|
||||
registration.save()
|
||||
|
||||
# Run algorithm
|
||||
WEISurvey2023.get_algorithm_class()().run_algorithm()
|
||||
|
||||
# Ensure that everyone has its first choice
|
||||
for r in WEIRegistration.objects.filter(wei=self.wei).all():
|
||||
survey = WEISurvey2023(r)
|
||||
preferred_bus = survey.ordered_buses()[0][0]
|
||||
chosen_bus = survey.information.get_selected_bus()
|
||||
self.assertEqual(preferred_bus, chosen_bus)
|
||||
|
||||
def test_survey_algorithm_full(self):
|
||||
"""
|
||||
Buses are full of first year people, ensure that they are happy
|
||||
"""
|
||||
# Add a lot of users
|
||||
for i in range(95):
|
||||
user = User.objects.create(username=f"user{i}")
|
||||
registration = WEIRegistration.objects.create(
|
||||
user=user,
|
||||
wei=self.wei,
|
||||
first_year=True,
|
||||
birth_date='2000-01-01',
|
||||
)
|
||||
information = WEISurveyInformation2023(registration)
|
||||
for j in range(1, 21):
|
||||
setattr(information, f'word{j}', random.choice(WORDS))
|
||||
information.step = 20
|
||||
information.save(registration)
|
||||
registration.save()
|
||||
|
||||
# Run algorithm
|
||||
WEISurvey2023.get_algorithm_class()().run_algorithm()
|
||||
|
||||
penalty = 0
|
||||
# Ensure that everyone seems to be happy
|
||||
# We attribute a penalty for each user that didn't have its first choice
|
||||
# The penalty is the square of the distance between the score of the preferred bus
|
||||
# and the score of the attributed bus
|
||||
# We consider it acceptable if the mean of this distance is lower than 5 %
|
||||
for r in WEIRegistration.objects.filter(wei=self.wei).all():
|
||||
survey = WEISurvey2023(r)
|
||||
chosen_bus = survey.information.get_selected_bus()
|
||||
buses = survey.ordered_buses()
|
||||
score = min(v for bus, v in buses if bus == chosen_bus)
|
||||
max_score = buses[0][1]
|
||||
penalty += (max_score - score) ** 2
|
||||
|
||||
self.assertLessEqual(max_score - score, 25) # Always less than 25 % of tolerance
|
||||
|
||||
self.assertLessEqual(penalty / 100, 25) # Tolerance of 5 %
|
@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2023 by BDE ENS Paris-Saclay
|
||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import subprocess
|
||||
@ -782,7 +782,7 @@ class TestDefaultWEISurvey(TestCase):
|
||||
WEISurvey.update_form(None, None)
|
||||
|
||||
self.assertEqual(CurrentSurvey.get_algorithm_class().get_survey_class(), CurrentSurvey)
|
||||
self.assertEqual(CurrentSurvey.get_year(), 2023)
|
||||
self.assertEqual(CurrentSurvey.get_year(), 2022)
|
||||
|
||||
|
||||
class TestWeiAPI(TestAPI):
|
||||
|
@ -7,9 +7,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-31 17:08+0200\n"
|
||||
"POT-Creation-Date: 2022-04-10 22:34+0200\n"
|
||||
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
|
||||
"Last-Translator: bleizi <bleizi@crans.org>\n"
|
||||
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
|
||||
"Language-Team: German <http://translate.ynerant.fr/projects/nk20/nk20/de/>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -115,7 +115,7 @@ msgid "type"
|
||||
msgstr "Type"
|
||||
|
||||
#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:286
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:285
|
||||
#: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13
|
||||
#: apps/wei/templates/wei/survey.html:15
|
||||
msgid "user"
|
||||
@ -258,7 +258,7 @@ msgstr "Eingetreten um "
|
||||
msgid "remove"
|
||||
msgstr "entfernen"
|
||||
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:200
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
@ -1570,7 +1570,7 @@ msgstr "Sondertranskationen"
|
||||
msgid "membership transaction"
|
||||
msgstr "Mitgliedschafttransaktion"
|
||||
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:293
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:292
|
||||
msgid "membership transactions"
|
||||
msgstr "Mitgliedschaftttransaktionen"
|
||||
|
||||
@ -1689,7 +1689,7 @@ msgid "Amount"
|
||||
msgstr "Anzahl"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:132
|
||||
#: apps/treasury/models.py:55
|
||||
#: apps/treasury/models.py:54
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@ -2183,7 +2183,7 @@ msgstr "Ungültige Vorregistrierung"
|
||||
msgid "Treasury"
|
||||
msgstr "Quaestor"
|
||||
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:94
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:93
|
||||
#: apps/treasury/templates/treasury/invoice_form.html:22
|
||||
msgid "This invoice is locked and can no longer be edited."
|
||||
msgstr "Diese Rechnung ist gesperrt und kann nicht mehr bearbeitet werden."
|
||||
@ -2196,7 +2196,7 @@ msgstr "Überweisung ist bereits geschlossen."
|
||||
msgid "You can't change the type of the remittance."
|
||||
msgstr "Sie können die Art der Überweisung nicht ändern."
|
||||
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:268
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:267
|
||||
#: apps/treasury/tables.py:97 apps/treasury/tables.py:105
|
||||
#: apps/treasury/templates/treasury/invoice_list.html:16
|
||||
#: apps/treasury/templates/treasury/remittance_list.html:16
|
||||
@ -2212,116 +2212,116 @@ msgstr "Keine beigefügte Überweisung"
|
||||
msgid "Invoice identifier"
|
||||
msgstr "Rechnungskennung"
|
||||
|
||||
#: apps/treasury/models.py:41
|
||||
#: apps/treasury/models.py:40
|
||||
msgid "BDE"
|
||||
msgstr "BDE"
|
||||
|
||||
#: apps/treasury/models.py:46
|
||||
#: apps/treasury/models.py:45
|
||||
msgid "Object"
|
||||
msgstr "Objekt"
|
||||
|
||||
#: apps/treasury/models.py:50
|
||||
#: apps/treasury/models.py:49
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: apps/treasury/models.py:59
|
||||
#: apps/treasury/models.py:58
|
||||
msgid "Address"
|
||||
msgstr "Adresse"
|
||||
|
||||
#: apps/treasury/models.py:64 apps/treasury/models.py:194
|
||||
#: apps/treasury/models.py:63 apps/treasury/models.py:193
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
||||
#: apps/treasury/models.py:68
|
||||
#: apps/treasury/models.py:67
|
||||
msgid "Acquitted"
|
||||
msgstr "Bezahlt"
|
||||
|
||||
#: apps/treasury/models.py:73
|
||||
#: apps/treasury/models.py:72
|
||||
msgid "Locked"
|
||||
msgstr "Gesperrt"
|
||||
|
||||
#: apps/treasury/models.py:74
|
||||
#: apps/treasury/models.py:73
|
||||
msgid "An invoice can't be edited when it is locked."
|
||||
msgstr "Eine Rechnung kann nicht bearbeitet werden, wenn sie gesperrt ist."
|
||||
|
||||
#: apps/treasury/models.py:80
|
||||
#: apps/treasury/models.py:79
|
||||
msgid "tex source"
|
||||
msgstr "Tex Quelle"
|
||||
|
||||
#: apps/treasury/models.py:114 apps/treasury/models.py:130
|
||||
#: apps/treasury/models.py:113 apps/treasury/models.py:129
|
||||
msgid "invoice"
|
||||
msgstr "Rechnung"
|
||||
|
||||
#: apps/treasury/models.py:115
|
||||
#: apps/treasury/models.py:114
|
||||
msgid "invoices"
|
||||
msgstr "Rechnungen"
|
||||
|
||||
#: apps/treasury/models.py:118
|
||||
#: apps/treasury/models.py:117
|
||||
#, python-brace-format
|
||||
msgid "Invoice #{id}"
|
||||
msgstr "Rechnung #{id}"
|
||||
|
||||
#: apps/treasury/models.py:135
|
||||
#: apps/treasury/models.py:134
|
||||
msgid "Designation"
|
||||
msgstr "Bezeichnung"
|
||||
|
||||
#: apps/treasury/models.py:141
|
||||
#: apps/treasury/models.py:140
|
||||
msgid "Quantity"
|
||||
msgstr "Qualität"
|
||||
|
||||
#: apps/treasury/models.py:146
|
||||
#: apps/treasury/models.py:145
|
||||
msgid "Unit price"
|
||||
msgstr "Einzelpreis"
|
||||
|
||||
#: apps/treasury/models.py:162
|
||||
#: apps/treasury/models.py:161
|
||||
msgid "product"
|
||||
msgstr "Produkt"
|
||||
|
||||
#: apps/treasury/models.py:163
|
||||
#: apps/treasury/models.py:162
|
||||
msgid "products"
|
||||
msgstr "Produkten"
|
||||
|
||||
#: apps/treasury/models.py:183
|
||||
#: apps/treasury/models.py:182
|
||||
msgid "remittance type"
|
||||
msgstr "Überweisungstyp"
|
||||
|
||||
#: apps/treasury/models.py:184
|
||||
#: apps/treasury/models.py:183
|
||||
msgid "remittance types"
|
||||
msgstr "Überweisungstypen"
|
||||
|
||||
#: apps/treasury/models.py:205
|
||||
#: apps/treasury/models.py:204
|
||||
msgid "Comment"
|
||||
msgstr "Kommentar"
|
||||
|
||||
#: apps/treasury/models.py:210
|
||||
#: apps/treasury/models.py:209
|
||||
msgid "Closed"
|
||||
msgstr "Geschlossen"
|
||||
|
||||
#: apps/treasury/models.py:214
|
||||
#: apps/treasury/models.py:213
|
||||
msgid "remittance"
|
||||
msgstr "Überweisung"
|
||||
|
||||
#: apps/treasury/models.py:215
|
||||
#: apps/treasury/models.py:214
|
||||
msgid "remittances"
|
||||
msgstr "Überweisungen"
|
||||
|
||||
#: apps/treasury/models.py:248
|
||||
#: apps/treasury/models.py:247
|
||||
msgid "Remittance #{:d}: {}"
|
||||
msgstr "Überweisung #{:d}:{}"
|
||||
|
||||
#: apps/treasury/models.py:272
|
||||
#: apps/treasury/models.py:271
|
||||
msgid "special transaction proxy"
|
||||
msgstr "spezielle Transaktion Proxy"
|
||||
|
||||
#: apps/treasury/models.py:273
|
||||
#: apps/treasury/models.py:272
|
||||
msgid "special transaction proxies"
|
||||
msgstr "spezielle Transaktion Proxies"
|
||||
|
||||
#: apps/treasury/models.py:299
|
||||
#: apps/treasury/models.py:298
|
||||
msgid "credit transaction"
|
||||
msgstr "Kredit Transaktion"
|
||||
|
||||
#: apps/treasury/models.py:432
|
||||
#: apps/treasury/models.py:430
|
||||
msgid ""
|
||||
"This user doesn't have enough money to pay the memberships with its note. "
|
||||
"Please ask her/him to credit the note before invalidating this credit."
|
||||
@ -2329,16 +2329,16 @@ msgstr ""
|
||||
"Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner "
|
||||
"Note zu bezahlen."
|
||||
|
||||
#: apps/treasury/models.py:453
|
||||
#: apps/treasury/models.py:451
|
||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||
msgid "Credit from the Société générale"
|
||||
msgstr "Kredit von der Société générale"
|
||||
|
||||
#: apps/treasury/models.py:454
|
||||
#: apps/treasury/models.py:452
|
||||
msgid "Credits from the Société générale"
|
||||
msgstr "Krediten von der Société générale"
|
||||
|
||||
#: apps/treasury/models.py:457
|
||||
#: apps/treasury/models.py:455
|
||||
#, python-brace-format
|
||||
msgid "Soge credit for {user}"
|
||||
msgstr "Kredit von der Société générale für {user}"
|
||||
@ -2640,7 +2640,7 @@ msgstr "Wählen Sie die Rollen aus, an denen Sie interessiert sind."
|
||||
msgid "This team doesn't belong to the given bus."
|
||||
msgstr "Dieses Team gehört nicht zum angegebenen Bus."
|
||||
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35
|
||||
msgid "Choose a word:"
|
||||
msgstr "Wählen Sie ein Wort:"
|
||||
|
||||
@ -3361,10 +3361,6 @@ msgstr "Kontakt"
|
||||
msgid "Technical Support"
|
||||
msgstr ""
|
||||
|
||||
#: note_kfet/templates/base.html:198
|
||||
msgid "FAQ (FR)"
|
||||
msgstr "FAQ (FR)"
|
||||
|
||||
#: note_kfet/templates/base_search.html:15
|
||||
msgid "Search by attribute such as name…"
|
||||
msgstr "Suche nach Attributen wie Name…"
|
||||
@ -3615,6 +3611,7 @@ msgstr ""
|
||||
#~ msgid "This user didn't give her/his caution check."
|
||||
#~ msgstr "Dieser User hat seine / ihre Vorsicht nicht überprüft."
|
||||
|
||||
#, python-format
|
||||
#~ msgid ""
|
||||
#~ "A new version of the application is available. This instance runs "
|
||||
#~ "%(VERSION)s and the last version is %(LAST_VERSION)s. Please consider "
|
||||
|
@ -7,9 +7,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-31 17:08+0200\n"
|
||||
"POT-Creation-Date: 2022-04-10 22:34+0200\n"
|
||||
"PO-Revision-Date: 2022-04-11 23:12+0200\n"
|
||||
"Last-Translator: bleizi <bleizi@crans.org>\n"
|
||||
"Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -114,7 +114,7 @@ msgid "type"
|
||||
msgstr "tipo"
|
||||
|
||||
#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:286
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:285
|
||||
#: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13
|
||||
#: apps/wei/templates/wei/survey.html:15
|
||||
msgid "user"
|
||||
@ -257,7 +257,7 @@ msgstr "Entrado el "
|
||||
msgid "remove"
|
||||
msgstr "quitar"
|
||||
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:200
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
@ -1557,7 +1557,7 @@ msgstr "Transacciones especiales"
|
||||
msgid "membership transaction"
|
||||
msgstr "transacción de afiliación"
|
||||
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:293
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:292
|
||||
msgid "membership transactions"
|
||||
msgstr "transacciones de afiliación"
|
||||
|
||||
@ -1676,7 +1676,7 @@ msgid "Amount"
|
||||
msgstr "Monto"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:132
|
||||
#: apps/treasury/models.py:55
|
||||
#: apps/treasury/models.py:54
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
@ -2163,7 +2163,7 @@ msgstr "Invalidar la afiliación"
|
||||
msgid "Treasury"
|
||||
msgstr "Tesorería"
|
||||
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:94
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:93
|
||||
#: apps/treasury/templates/treasury/invoice_form.html:22
|
||||
msgid "This invoice is locked and can no longer be edited."
|
||||
msgstr "Esta factura esta bloqueada y no puede ser modificada."
|
||||
@ -2176,7 +2176,7 @@ msgstr "El descuento ya esta cerrado."
|
||||
msgid "You can't change the type of the remittance."
|
||||
msgstr "No puede cambiar el tipo de descuento."
|
||||
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:268
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:267
|
||||
#: apps/treasury/tables.py:97 apps/treasury/tables.py:105
|
||||
#: apps/treasury/templates/treasury/invoice_list.html:16
|
||||
#: apps/treasury/templates/treasury/remittance_list.html:16
|
||||
@ -2192,116 +2192,116 @@ msgstr "No hay descuento relacionado"
|
||||
msgid "Invoice identifier"
|
||||
msgstr "Numero de factura"
|
||||
|
||||
#: apps/treasury/models.py:41
|
||||
#: apps/treasury/models.py:40
|
||||
msgid "BDE"
|
||||
msgstr "BDE"
|
||||
|
||||
#: apps/treasury/models.py:46
|
||||
#: apps/treasury/models.py:45
|
||||
msgid "Object"
|
||||
msgstr "Asunto"
|
||||
|
||||
#: apps/treasury/models.py:50
|
||||
#: apps/treasury/models.py:49
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
||||
#: apps/treasury/models.py:59
|
||||
#: apps/treasury/models.py:58
|
||||
msgid "Address"
|
||||
msgstr "Dirección"
|
||||
|
||||
#: apps/treasury/models.py:64 apps/treasury/models.py:194
|
||||
#: apps/treasury/models.py:63 apps/treasury/models.py:193
|
||||
msgid "Date"
|
||||
msgstr "Fecha"
|
||||
|
||||
#: apps/treasury/models.py:68
|
||||
#: apps/treasury/models.py:67
|
||||
msgid "Acquitted"
|
||||
msgstr "Pagada"
|
||||
|
||||
#: apps/treasury/models.py:73
|
||||
#: apps/treasury/models.py:72
|
||||
msgid "Locked"
|
||||
msgstr "Bloqueada"
|
||||
|
||||
#: apps/treasury/models.py:74
|
||||
#: apps/treasury/models.py:73
|
||||
msgid "An invoice can't be edited when it is locked."
|
||||
msgstr "Une factura no puede ser modificada cuando esta bloqueada."
|
||||
|
||||
#: apps/treasury/models.py:80
|
||||
#: apps/treasury/models.py:79
|
||||
msgid "tex source"
|
||||
msgstr "código fuente TeX"
|
||||
|
||||
#: apps/treasury/models.py:114 apps/treasury/models.py:130
|
||||
#: apps/treasury/models.py:113 apps/treasury/models.py:129
|
||||
msgid "invoice"
|
||||
msgstr "factura"
|
||||
|
||||
#: apps/treasury/models.py:115
|
||||
#: apps/treasury/models.py:114
|
||||
msgid "invoices"
|
||||
msgstr "facturas"
|
||||
|
||||
#: apps/treasury/models.py:118
|
||||
#: apps/treasury/models.py:117
|
||||
#, python-brace-format
|
||||
msgid "Invoice #{id}"
|
||||
msgstr "Factura n°{id}"
|
||||
|
||||
#: apps/treasury/models.py:135
|
||||
#: apps/treasury/models.py:134
|
||||
msgid "Designation"
|
||||
msgstr "Designación"
|
||||
|
||||
#: apps/treasury/models.py:141
|
||||
#: apps/treasury/models.py:140
|
||||
msgid "Quantity"
|
||||
msgstr "Cantidad"
|
||||
|
||||
#: apps/treasury/models.py:146
|
||||
#: apps/treasury/models.py:145
|
||||
msgid "Unit price"
|
||||
msgstr "Precio unitario"
|
||||
|
||||
#: apps/treasury/models.py:162
|
||||
#: apps/treasury/models.py:161
|
||||
msgid "product"
|
||||
msgstr "producto"
|
||||
|
||||
#: apps/treasury/models.py:163
|
||||
#: apps/treasury/models.py:162
|
||||
msgid "products"
|
||||
msgstr "productos"
|
||||
|
||||
#: apps/treasury/models.py:183
|
||||
#: apps/treasury/models.py:182
|
||||
msgid "remittance type"
|
||||
msgstr "tipo de descuento"
|
||||
|
||||
#: apps/treasury/models.py:184
|
||||
#: apps/treasury/models.py:183
|
||||
msgid "remittance types"
|
||||
msgstr "tipos de descuentos"
|
||||
|
||||
#: apps/treasury/models.py:205
|
||||
#: apps/treasury/models.py:204
|
||||
msgid "Comment"
|
||||
msgstr "Comentario"
|
||||
|
||||
#: apps/treasury/models.py:210
|
||||
#: apps/treasury/models.py:209
|
||||
msgid "Closed"
|
||||
msgstr "Cerrada"
|
||||
|
||||
#: apps/treasury/models.py:214
|
||||
#: apps/treasury/models.py:213
|
||||
msgid "remittance"
|
||||
msgstr "descuento"
|
||||
|
||||
#: apps/treasury/models.py:215
|
||||
#: apps/treasury/models.py:214
|
||||
msgid "remittances"
|
||||
msgstr "descuentos"
|
||||
|
||||
#: apps/treasury/models.py:248
|
||||
#: apps/treasury/models.py:247
|
||||
msgid "Remittance #{:d}: {}"
|
||||
msgstr "Descuento n°{:d} : {}"
|
||||
|
||||
#: apps/treasury/models.py:272
|
||||
#: apps/treasury/models.py:271
|
||||
msgid "special transaction proxy"
|
||||
msgstr "proxy de transacción especial"
|
||||
|
||||
#: apps/treasury/models.py:273
|
||||
#: apps/treasury/models.py:272
|
||||
msgid "special transaction proxies"
|
||||
msgstr "proxys de transacciones especiales"
|
||||
|
||||
#: apps/treasury/models.py:299
|
||||
#: apps/treasury/models.py:298
|
||||
msgid "credit transaction"
|
||||
msgstr "transacción de crédito"
|
||||
|
||||
#: apps/treasury/models.py:432
|
||||
#: apps/treasury/models.py:430
|
||||
msgid ""
|
||||
"This user doesn't have enough money to pay the memberships with its note. "
|
||||
"Please ask her/him to credit the note before invalidating this credit."
|
||||
@ -2310,16 +2310,16 @@ msgstr ""
|
||||
"afiliaciones. Por favor pídelo acreditar su note antes de invalidar este "
|
||||
"crédito."
|
||||
|
||||
#: apps/treasury/models.py:453
|
||||
#: apps/treasury/models.py:451
|
||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||
msgid "Credit from the Société générale"
|
||||
msgstr "Crédito de la Société Générale"
|
||||
|
||||
#: apps/treasury/models.py:454
|
||||
#: apps/treasury/models.py:452
|
||||
msgid "Credits from the Société générale"
|
||||
msgstr "Créditos de la Société Générale"
|
||||
|
||||
#: apps/treasury/models.py:457
|
||||
#: apps/treasury/models.py:455
|
||||
#, python-brace-format
|
||||
msgid "Soge credit for {user}"
|
||||
msgstr "Crédito de la Société Générale para {user}"
|
||||
@ -2612,7 +2612,7 @@ msgstr "Elegir los papeles que le interesa."
|
||||
msgid "This team doesn't belong to the given bus."
|
||||
msgstr "Este equipo no pertenece al bus dado."
|
||||
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35
|
||||
msgid "Choose a word:"
|
||||
msgstr "Elegir una palabra :"
|
||||
|
||||
@ -3316,10 +3316,6 @@ msgstr "Contactarnos"
|
||||
msgid "Technical Support"
|
||||
msgstr "Soporte técnico"
|
||||
|
||||
#: note_kfet/templates/base.html:198
|
||||
msgid "FAQ (FR)"
|
||||
msgstr "FAQ (FR)"
|
||||
|
||||
#: note_kfet/templates/base_search.html:15
|
||||
msgid "Search by attribute such as name…"
|
||||
msgstr "Buscar con atributo, como el nombre…"
|
||||
|
@ -7,9 +7,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-31 17:08+0200\n"
|
||||
"POT-Creation-Date: 2022-04-10 22:34+0200\n"
|
||||
"PO-Revision-Date: 2022-04-11 22:05+0200\n"
|
||||
"Last-Translator: bleizi <bleizi@crans.org>\n"
|
||||
"Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n"
|
||||
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -115,7 +115,7 @@ msgid "type"
|
||||
msgstr "type"
|
||||
|
||||
#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:307
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:286
|
||||
#: apps/note/models/notes.py:148 apps/treasury/models.py:285
|
||||
#: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13
|
||||
#: apps/wei/templates/wei/survey.html:15
|
||||
msgid "user"
|
||||
@ -258,7 +258,7 @@ msgstr "Entré le "
|
||||
msgid "remove"
|
||||
msgstr "supprimer"
|
||||
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:200
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
@ -1563,7 +1563,7 @@ msgstr "Transactions de crédit/retrait"
|
||||
msgid "membership transaction"
|
||||
msgstr "transaction d'adhésion"
|
||||
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:293
|
||||
#: apps/note/models/transactions.py:385 apps/treasury/models.py:292
|
||||
msgid "membership transactions"
|
||||
msgstr "transactions d'adhésion"
|
||||
|
||||
@ -1682,7 +1682,7 @@ msgid "Amount"
|
||||
msgstr "Montant"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:132
|
||||
#: apps/treasury/models.py:55
|
||||
#: apps/treasury/models.py:54
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
@ -2171,7 +2171,7 @@ msgstr "Invalider l'inscription"
|
||||
msgid "Treasury"
|
||||
msgstr "Trésorerie"
|
||||
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:94
|
||||
#: apps/treasury/forms.py:26 apps/treasury/models.py:93
|
||||
#: apps/treasury/templates/treasury/invoice_form.html:22
|
||||
msgid "This invoice is locked and can no longer be edited."
|
||||
msgstr "Cette facture est verrouillée et ne peut plus être éditée."
|
||||
@ -2184,7 +2184,7 @@ msgstr "La remise est déjà fermée."
|
||||
msgid "You can't change the type of the remittance."
|
||||
msgstr "Vous ne pouvez pas changer le type de la remise."
|
||||
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:268
|
||||
#: apps/treasury/forms.py:125 apps/treasury/models.py:267
|
||||
#: apps/treasury/tables.py:97 apps/treasury/tables.py:105
|
||||
#: apps/treasury/templates/treasury/invoice_list.html:16
|
||||
#: apps/treasury/templates/treasury/remittance_list.html:16
|
||||
@ -2200,116 +2200,116 @@ msgstr "Pas de remise associée"
|
||||
msgid "Invoice identifier"
|
||||
msgstr "Numéro de facture"
|
||||
|
||||
#: apps/treasury/models.py:41
|
||||
#: apps/treasury/models.py:40
|
||||
msgid "BDE"
|
||||
msgstr "BDE"
|
||||
|
||||
#: apps/treasury/models.py:46
|
||||
#: apps/treasury/models.py:45
|
||||
msgid "Object"
|
||||
msgstr "Objet"
|
||||
|
||||
#: apps/treasury/models.py:50
|
||||
#: apps/treasury/models.py:49
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: apps/treasury/models.py:59
|
||||
#: apps/treasury/models.py:58
|
||||
msgid "Address"
|
||||
msgstr "Adresse"
|
||||
|
||||
#: apps/treasury/models.py:64 apps/treasury/models.py:194
|
||||
#: apps/treasury/models.py:63 apps/treasury/models.py:193
|
||||
msgid "Date"
|
||||
msgstr "Date"
|
||||
|
||||
#: apps/treasury/models.py:68
|
||||
#: apps/treasury/models.py:67
|
||||
msgid "Acquitted"
|
||||
msgstr "Acquittée"
|
||||
|
||||
#: apps/treasury/models.py:73
|
||||
#: apps/treasury/models.py:72
|
||||
msgid "Locked"
|
||||
msgstr "Verrouillée"
|
||||
|
||||
#: apps/treasury/models.py:74
|
||||
#: apps/treasury/models.py:73
|
||||
msgid "An invoice can't be edited when it is locked."
|
||||
msgstr "Une facture ne peut plus être modifiée si elle est verrouillée."
|
||||
|
||||
#: apps/treasury/models.py:80
|
||||
#: apps/treasury/models.py:79
|
||||
msgid "tex source"
|
||||
msgstr "fichier TeX source"
|
||||
|
||||
#: apps/treasury/models.py:114 apps/treasury/models.py:130
|
||||
#: apps/treasury/models.py:113 apps/treasury/models.py:129
|
||||
msgid "invoice"
|
||||
msgstr "facture"
|
||||
|
||||
#: apps/treasury/models.py:115
|
||||
#: apps/treasury/models.py:114
|
||||
msgid "invoices"
|
||||
msgstr "factures"
|
||||
|
||||
#: apps/treasury/models.py:118
|
||||
#: apps/treasury/models.py:117
|
||||
#, python-brace-format
|
||||
msgid "Invoice #{id}"
|
||||
msgstr "Facture n°{id}"
|
||||
|
||||
#: apps/treasury/models.py:135
|
||||
#: apps/treasury/models.py:134
|
||||
msgid "Designation"
|
||||
msgstr "Désignation"
|
||||
|
||||
#: apps/treasury/models.py:141
|
||||
#: apps/treasury/models.py:140
|
||||
msgid "Quantity"
|
||||
msgstr "Quantité"
|
||||
|
||||
#: apps/treasury/models.py:146
|
||||
#: apps/treasury/models.py:145
|
||||
msgid "Unit price"
|
||||
msgstr "Prix unitaire"
|
||||
|
||||
#: apps/treasury/models.py:162
|
||||
#: apps/treasury/models.py:161
|
||||
msgid "product"
|
||||
msgstr "produit"
|
||||
|
||||
#: apps/treasury/models.py:163
|
||||
#: apps/treasury/models.py:162
|
||||
msgid "products"
|
||||
msgstr "produits"
|
||||
|
||||
#: apps/treasury/models.py:183
|
||||
#: apps/treasury/models.py:182
|
||||
msgid "remittance type"
|
||||
msgstr "type de remise"
|
||||
|
||||
#: apps/treasury/models.py:184
|
||||
#: apps/treasury/models.py:183
|
||||
msgid "remittance types"
|
||||
msgstr "types de remises"
|
||||
|
||||
#: apps/treasury/models.py:205
|
||||
#: apps/treasury/models.py:204
|
||||
msgid "Comment"
|
||||
msgstr "Commentaire"
|
||||
|
||||
#: apps/treasury/models.py:210
|
||||
#: apps/treasury/models.py:209
|
||||
msgid "Closed"
|
||||
msgstr "Fermée"
|
||||
|
||||
#: apps/treasury/models.py:214
|
||||
#: apps/treasury/models.py:213
|
||||
msgid "remittance"
|
||||
msgstr "remise"
|
||||
|
||||
#: apps/treasury/models.py:215
|
||||
#: apps/treasury/models.py:214
|
||||
msgid "remittances"
|
||||
msgstr "remises"
|
||||
|
||||
#: apps/treasury/models.py:248
|
||||
#: apps/treasury/models.py:247
|
||||
msgid "Remittance #{:d}: {}"
|
||||
msgstr "Remise n°{:d} : {}"
|
||||
|
||||
#: apps/treasury/models.py:272
|
||||
#: apps/treasury/models.py:271
|
||||
msgid "special transaction proxy"
|
||||
msgstr "proxy de transaction spéciale"
|
||||
|
||||
#: apps/treasury/models.py:273
|
||||
#: apps/treasury/models.py:272
|
||||
msgid "special transaction proxies"
|
||||
msgstr "proxys de transactions spéciales"
|
||||
|
||||
#: apps/treasury/models.py:299
|
||||
#: apps/treasury/models.py:298
|
||||
msgid "credit transaction"
|
||||
msgstr "transaction de crédit"
|
||||
|
||||
#: apps/treasury/models.py:432
|
||||
#: apps/treasury/models.py:430
|
||||
msgid ""
|
||||
"This user doesn't have enough money to pay the memberships with its note. "
|
||||
"Please ask her/him to credit the note before invalidating this credit."
|
||||
@ -2317,16 +2317,16 @@ msgstr ""
|
||||
"Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa "
|
||||
"note. Merci de lui demander de recharger sa note avant d'invalider ce crédit."
|
||||
|
||||
#: apps/treasury/models.py:453
|
||||
#: apps/treasury/models.py:451
|
||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||
msgid "Credit from the Société générale"
|
||||
msgstr "Crédit de la Société générale"
|
||||
|
||||
#: apps/treasury/models.py:454
|
||||
#: apps/treasury/models.py:452
|
||||
msgid "Credits from the Société générale"
|
||||
msgstr "Crédits de la Société générale"
|
||||
|
||||
#: apps/treasury/models.py:457
|
||||
#: apps/treasury/models.py:455
|
||||
#, python-brace-format
|
||||
msgid "Soge credit for {user}"
|
||||
msgstr "Crédit de la société générale pour l'utilisateur {user}"
|
||||
@ -2624,7 +2624,7 @@ msgstr "Sélectionnez les rôles qui vous intéressent."
|
||||
msgid "This team doesn't belong to the given bus."
|
||||
msgstr "Cette équipe n'appartient pas à ce bus."
|
||||
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:38
|
||||
#: apps/wei/forms/surveys/wei2021.py:35 apps/wei/forms/surveys/wei2022.py:35
|
||||
msgid "Choose a word:"
|
||||
msgstr "Choisissez un mot :"
|
||||
|
||||
@ -3335,10 +3335,6 @@ msgstr "Nous contacter"
|
||||
msgid "Technical Support"
|
||||
msgstr "Support technique"
|
||||
|
||||
#: note_kfet/templates/base.html:198
|
||||
msgid "FAQ (FR)"
|
||||
msgstr "FAQ (FR)"
|
||||
|
||||
#: note_kfet/templates/base_search.html:15
|
||||
msgid "Search by attribute such as name…"
|
||||
msgstr "Chercher par un attribut tel que le nom …"
|
||||
|
@ -18,7 +18,7 @@ MAILTO=notekfet2020@lists.crans.org
|
||||
# Spammer les gens en négatif
|
||||
00 5 * * 2 root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --spam --negative-amount 1 -v 0
|
||||
# Envoyer le rapport mensuel aux trésoriers et respos info
|
||||
00 8 * * 5 root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report --add-years 1 -v 0
|
||||
00 8 6 * * root cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report --add-years 1 -v 0
|
||||
# Envoyer les rapports aux gens
|
||||
55 6 * * * root cd /var/www/note_kfet && env/bin/python manage.py send_reports -v 0
|
||||
# Mettre à jour les boutons mis en avant
|
||||
|
@ -252,7 +252,7 @@ REST_FRAMEWORK = {
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
|
||||
],
|
||||
'DEFAULT_PAGINATION_CLASS': 'apps.api.pagination.CustomPagination',
|
||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||
'PAGE_SIZE': 20,
|
||||
}
|
||||
|
||||
|
72
note_kfet/static/css/custom.css
Executable file → Normal file
72
note_kfet/static/css/custom.css
Executable file → Normal file
@ -65,10 +65,7 @@ mark {
|
||||
|
||||
/* Last BDE colors */
|
||||
.bg-primary {
|
||||
/* background-color: rgb(18, 67, 4) !important; */
|
||||
/* MODE VIEUXCON=ON */
|
||||
/* background-color: rgb(166, 0, 2) !important; */
|
||||
background-color: rgb(0, 0, 0) !important;
|
||||
background-color: rgb(102, 83, 105) !important;
|
||||
}
|
||||
|
||||
html {
|
||||
@ -83,15 +80,15 @@ body {
|
||||
.btn-outline-primary:hover,
|
||||
.btn-outline-primary:not(:disabled):not(.disabled).active,
|
||||
.btn-outline-primary:not(:disabled):not(.disabled):active {
|
||||
color: rgb(241, 229, 52);
|
||||
background-color: rgb(228, 35, 132);
|
||||
border-color: rgb(228, 35, 132);
|
||||
color: #fff;
|
||||
background-color: rgb(102, 83, 105);
|
||||
border-color: rgb(102, 83, 105);
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
border-color: #464647;
|
||||
color: rgb(102, 83, 105);
|
||||
background-color: rgba(248, 249, 250, 0.9);
|
||||
border-color: rgb(102, 83, 105);
|
||||
}
|
||||
|
||||
.turbolinks-progress-bar {
|
||||
@ -101,63 +98,36 @@ body {
|
||||
.btn-primary:hover,
|
||||
.btn-primary:not(:disabled):not(.disabled).active,
|
||||
.btn-primary:not(:disabled):not(.disabled):active {
|
||||
color: rgb(241, 229, 52);
|
||||
background-color: rgb(228, 35, 132);
|
||||
border-color: rgb(228, 35, 132);
|
||||
color: #fff;
|
||||
background-color: rgb(102, 83, 105);
|
||||
border-color: rgb(102, 83, 105);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
border-color: #adb5bd;
|
||||
color: rgba(248, 249, 250, 0.9);
|
||||
background-color: rgb(102, 83, 105);
|
||||
border-color: rgb(102, 83, 105);
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border-color: rgb(228, 35, 132) !important;
|
||||
border-color: rgb(115, 15, 115) !important;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
border-color: #adb5bd;
|
||||
}
|
||||
|
||||
.btn-secondary:hover,
|
||||
.btn-secondary:not(:disabled):not(.disabled).active,
|
||||
.btn-secondary:not(:disabled):not(.disabled):active {
|
||||
color: rgb(241, 229, 52);
|
||||
background-color: rgb(228, 35, 132);
|
||||
border-color: rgb(228, 35, 132);
|
||||
}
|
||||
|
||||
|
||||
.btn-outline-dark {
|
||||
color: #343a40;
|
||||
border-color: #343a40;
|
||||
}
|
||||
|
||||
.btn-outline-dark:hover,
|
||||
.btn-outline-dark:not(:disabled):not(.disabled).active,
|
||||
.btn-outline-dark:not(:disabled):not(.disabled):active {
|
||||
color: rgb(241, 229, 52);
|
||||
background-color: rgb(228, 35, 132);
|
||||
border-color: rgb(228, 35, 132);
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
color: rgb(228, 35, 132);
|
||||
color: rgb(102, 83, 105);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: rgb(228, 35, 132);
|
||||
color: rgb(200, 30, 200);
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
box-shadow: 0 0 0 0.25rem rgb(228 35 132 / 50%);
|
||||
border-color: rgb(228, 35, 132);
|
||||
box-shadow: 0 0 0 0.25rem rgba(200, 30, 200, 0.25);
|
||||
border-color: rgb(200, 30, 200);
|
||||
}
|
||||
|
||||
.btn-outline-primary.focus {
|
||||
box-shadow: 0 0 0 0.25rem rgb(228 35 132 / 10%);
|
||||
box-shadow: 0 0 0 0.25rem rgba(200, 30, 200, 0.5);
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,8 +194,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
class="text-muted">{% trans "Contact us" %}</a> —
|
||||
<a href="mailto:{{ "SUPPORT_EMAIL" | getenv }}"
|
||||
class="text-muted">{% trans "Technical Support" %}</a> —
|
||||
<a href="https://note.crans.org/doc/faq/"
|
||||
class="text-muted">{% trans "FAQ (FR)" %}</a> —
|
||||
</span>
|
||||
{% csrf_token %}
|
||||
<select title="language" name="language"
|
||||
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{{ profile_form|crispy }}
|
||||
{% comment "Soge not for membership (only WEI)" %} {{ soge_form|crispy }} {% endcomment %}
|
||||
{{ soge_form|crispy }}
|
||||
<button class="btn btn-success" type="submit">
|
||||
{% trans "Sign up" %}
|
||||
</button>
|
||||
|
34
shell-static.nix
Executable file
34
shell-static.nix
Executable file
@ -0,0 +1,34 @@
|
||||
# This is a workaround meant for use with the nix package manager. If you don't know what it is or don't use it, please ignore this file.
|
||||
#
|
||||
# The nk20 javascript static location are hardcoded for imperative system.
|
||||
# This make ./manage.py collectstatic hard to use with nixos.
|
||||
#
|
||||
# A workaround is to enter a FHSUserEnv with the static placed under /share/javascript/<static>.
|
||||
# This emulate a debian like system and enable collecting static normally with ./manage.py collectstatics.
|
||||
# The regular shell.nix should be enough for other configurations.
|
||||
#
|
||||
# Warning, you are still supposed to use pip package with a venv !
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
(pkgs.buildFHSUserEnv {
|
||||
name = "pipzone";
|
||||
targetPkgs = pkgs: (with pkgs;
|
||||
let
|
||||
fhs-static = stdenv.mkDerivation {
|
||||
name = "fhs-static";
|
||||
buildCommand = ''
|
||||
mkdir -p $out/share/javascript/bootstrap4
|
||||
mkdir -p $out/share/javascript/jquery
|
||||
ln -s ${python39Packages.xstatic-bootstrap}/lib/python3.9/site-packages/xstatic/pkg/bootstrap/data/* $out/share/javascript/bootstrap4
|
||||
ln -s ${python39Packages.xstatic-jquery}/lib/python3.9/site-packages/xstatic/pkg/jquery/data/* $out/share/javascript/jquery
|
||||
'';
|
||||
};
|
||||
in [
|
||||
fhs-static
|
||||
python39
|
||||
gettext
|
||||
python39Packages.pip
|
||||
python39Packages.virtualenv
|
||||
python39Packages.setuptools
|
||||
]);
|
||||
runScript = "bash";
|
||||
}).env
|
23
shell.nix
Executable file
23
shell.nix
Executable file
@ -0,0 +1,23 @@
|
||||
# This is meant for use with the nix package manager. If you don't know what it is or don't use it, please ignore this file.
|
||||
#
|
||||
# This shell.nix contains all dependencies require to create a venv and pip install -r requirements.txt.
|
||||
#
|
||||
# Please check shell-static.nix for running ./manage.py collectstatics.
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
python39
|
||||
python39Packages.pip
|
||||
python39Packages.setuptools
|
||||
gettext
|
||||
|
||||
];
|
||||
shellHook = ''
|
||||
# Tells pip to put packages into $PIP_PREFIX instead of the usual locations.
|
||||
# See https://pip.pypa.io/en/stable/user_guide/#environment-variables.
|
||||
export PIP_PREFIX=$(pwd)/_build/pip_packages
|
||||
export PYTHONPATH="$PIP_PREFIX/${pkgs.python39.sitePackages}:$PYTHONPATH"
|
||||
export PATH="$PIP_PREFIX/bin:$PATH"
|
||||
unset SOURCE_DATE_EPOCH
|
||||
'';
|
||||
}
|
Reference in New Issue
Block a user