forked from ScoDoc/ScoDoc
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into dev92
This commit is contained in:
commit
f2c3841db9
@ -13,6 +13,7 @@ Les classes de Bonus fournissent deux méthodes:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
|
import math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ class BonusSport:
|
|||||||
etud_moy_gen et etud_moy_ue ne sont PAS modifiés (mais utilisés par certains bonus non additifs).
|
etud_moy_gen et etud_moy_ue ne sont PAS modifiés (mais utilisés par certains bonus non additifs).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# En classique, active un bonus sur les UEs: (dans ce cas bonus_moy_gen reste None)
|
# En classique, active un bonus sur les UEs: (dans ce cas bonus_moy_gen est ajusté pour le prendre en compte)
|
||||||
classic_use_bonus_ues = False
|
classic_use_bonus_ues = False
|
||||||
|
|
||||||
# Attributs virtuels:
|
# Attributs virtuels:
|
||||||
@ -106,6 +107,8 @@ class BonusSport:
|
|||||||
# sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport)
|
# sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport)
|
||||||
# ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
# ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
||||||
nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2]
|
nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2]
|
||||||
|
if nb_etuds == 0 or nb_mod_sport == 0:
|
||||||
|
return # no bonus at all
|
||||||
# Enlève les NaN du numérateur:
|
# Enlève les NaN du numérateur:
|
||||||
sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0)
|
sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0)
|
||||||
|
|
||||||
@ -157,7 +160,8 @@ class BonusSport:
|
|||||||
"""Calcul des bonus: méthode virtuelle à écraser.
|
"""Calcul des bonus: méthode virtuelle à écraser.
|
||||||
Arguments:
|
Arguments:
|
||||||
- sem_modimpl_moys_inscrits:
|
- sem_modimpl_moys_inscrits:
|
||||||
ndarray (nb_etuds, mod_sport) ou en APC (nb_etuds, mods_sport, nb_ue_non_bonus)
|
ndarray (nb_etuds, mod_sport)
|
||||||
|
ou en APC (nb_etuds, mods_sport, nb_ue_non_bonus)
|
||||||
les notes aux modules sports auxquel l'étudiant est inscrit, 0 sinon. Pas de nans.
|
les notes aux modules sports auxquel l'étudiant est inscrit, 0 sinon. Pas de nans.
|
||||||
- modimpl_coefs_etuds_no_nan:
|
- modimpl_coefs_etuds_no_nan:
|
||||||
les coefficients: float ndarray
|
les coefficients: float ndarray
|
||||||
@ -201,7 +205,8 @@ class BonusSportAdditif(BonusSport):
|
|||||||
"""calcul du bonus
|
"""calcul du bonus
|
||||||
sem_modimpl_moys_inscrits: les notes de sport
|
sem_modimpl_moys_inscrits: les notes de sport
|
||||||
En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
||||||
modimpl_coefs_etuds_no_nan:
|
En classic: ndarray (nb_etuds, nb_mod_sport)
|
||||||
|
modimpl_coefs_etuds_no_nan: même shape, les coefs.
|
||||||
"""
|
"""
|
||||||
if 0 in sem_modimpl_moys_inscrits.shape:
|
if 0 in sem_modimpl_moys_inscrits.shape:
|
||||||
# pas d'étudiants ou pas d'UE ou pas de module...
|
# pas d'étudiants ou pas d'UE ou pas de module...
|
||||||
@ -224,22 +229,28 @@ class BonusSportAdditif(BonusSport):
|
|||||||
bonus_moy_arr = np.clip(bonus_moy_arr, 0.0, 20.0, out=bonus_moy_arr)
|
bonus_moy_arr = np.clip(bonus_moy_arr, 0.0, 20.0, out=bonus_moy_arr)
|
||||||
|
|
||||||
# en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus)
|
# en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus)
|
||||||
if self.formsemestre.formation.is_apc() or self.classic_use_bonus_ues:
|
if self.formsemestre.formation.is_apc():
|
||||||
# Bonus sur les UE et None sur moyenne générale
|
# Bonus sur les UE et None sur moyenne générale
|
||||||
ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)]
|
ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)]
|
||||||
self.bonus_ues = pd.DataFrame(
|
self.bonus_ues = pd.DataFrame(
|
||||||
bonus_moy_arr, index=self.etuds_idx, columns=ues_idx, dtype=float
|
bonus_moy_arr, index=self.etuds_idx, columns=ues_idx, dtype=float
|
||||||
)
|
)
|
||||||
|
elif self.classic_use_bonus_ues:
|
||||||
|
# Formations classiques apppliquant le bonus sur les UEs
|
||||||
|
# ici bonus_moy_arr = ndarray 1d nb_etuds
|
||||||
|
ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)]
|
||||||
|
self.bonus_ues = pd.DataFrame(
|
||||||
|
np.stack([bonus_moy_arr] * len(ues_idx)).T,
|
||||||
|
index=self.etuds_idx,
|
||||||
|
columns=ues_idx,
|
||||||
|
dtype=float,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Bonus sur la moyenne générale seulement
|
# Bonus sur la moyenne générale seulement
|
||||||
self.bonus_moy_gen = pd.Series(
|
self.bonus_moy_gen = pd.Series(
|
||||||
bonus_moy_arr, index=self.etuds_idx, dtype=float
|
bonus_moy_arr, index=self.etuds_idx, dtype=float
|
||||||
)
|
)
|
||||||
|
|
||||||
# if len(bonus_moy_arr.shape) > 1:
|
|
||||||
# bonus_moy_arr = bonus_moy_arr.sum(axis=1)
|
|
||||||
# Laisse bonus_moy_gen à None, en APC le bonus moy. gen. sera réparti sur les UEs.
|
|
||||||
|
|
||||||
|
|
||||||
class BonusSportMultiplicatif(BonusSport):
|
class BonusSportMultiplicatif(BonusSport):
|
||||||
"""Bonus sport qui multiplie les moyennes d'UE par un facteur"""
|
"""Bonus sport qui multiplie les moyennes d'UE par un facteur"""
|
||||||
@ -284,6 +295,7 @@ class BonusSportMultiplicatif(BonusSport):
|
|||||||
|
|
||||||
class BonusDirect(BonusSportAdditif):
|
class BonusDirect(BonusSportAdditif):
|
||||||
"""Bonus direct: les points sont directement ajoutés à la moyenne générale.
|
"""Bonus direct: les points sont directement ajoutés à la moyenne générale.
|
||||||
|
|
||||||
Les coefficients sont ignorés: tous les points de bonus sont sommés.
|
Les coefficients sont ignorés: tous les points de bonus sont sommés.
|
||||||
(rappel: la note est ramenée sur 20 avant application).
|
(rappel: la note est ramenée sur 20 avant application).
|
||||||
"""
|
"""
|
||||||
@ -294,8 +306,68 @@ class BonusDirect(BonusSportAdditif):
|
|||||||
proportion_point = 1.0
|
proportion_point = 1.0
|
||||||
|
|
||||||
|
|
||||||
|
class BonusAmiens(BonusSportAdditif):
|
||||||
|
"""Bonus IUT Amiens pour les modules optionnels (sport, culture, ...).
|
||||||
|
|
||||||
|
Toute note non nulle, peu importe sa valeur, entraine un bonus de 0,1 point
|
||||||
|
sur toutes les moyennes d'UE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "bonus_amiens"
|
||||||
|
displayed_name = "IUT d'Amiens"
|
||||||
|
seuil_moy_gen = 0.0 # tous les points sont comptés
|
||||||
|
proportion_point = 1e10
|
||||||
|
bonus_max = 0.1
|
||||||
|
classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP
|
||||||
|
|
||||||
|
|
||||||
|
# Finalement ils n'en veulent pas.
|
||||||
|
# class BonusAnnecy(BonusSport):
|
||||||
|
# """Calcul bonus modules optionnels (sport), règle IUT d'Annecy.
|
||||||
|
|
||||||
|
# Il peut y avoir plusieurs modules de bonus.
|
||||||
|
# Prend pour chaque étudiant la meilleure de ses notes bonus et
|
||||||
|
# ajoute à chaque UE :<br>
|
||||||
|
# 0.05 point si >=10,<br>
|
||||||
|
# 0.1 point si >=12,<br>
|
||||||
|
# 0.15 point si >=14,<br>
|
||||||
|
# 0.2 point si >=16,<br>
|
||||||
|
# 0.25 point si >=18.
|
||||||
|
# """
|
||||||
|
|
||||||
|
# name = "bonus_iut_annecy"
|
||||||
|
# displayed_name = "IUT d'Annecy"
|
||||||
|
|
||||||
|
# def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
|
||||||
|
# """calcul du bonus"""
|
||||||
|
# # if math.prod(sem_modimpl_moys_inscrits.shape) == 0:
|
||||||
|
# # return # no etuds or no mod sport
|
||||||
|
# # Prend la note de chaque modimpl, sans considération d'UE
|
||||||
|
# if len(sem_modimpl_moys_inscrits.shape) > 2: # apc
|
||||||
|
# sem_modimpl_moys_inscrits = sem_modimpl_moys_inscrits[:, :, 0]
|
||||||
|
# # ici sem_modimpl_moys_inscrits est nb_etuds x nb_mods_bonus, en APC et en classic
|
||||||
|
# note_bonus_max = np.max(sem_modimpl_moys_inscrits, axis=1) # 1d, nb_etuds
|
||||||
|
# bonus = np.zeros(note_bonus_max.shape)
|
||||||
|
# bonus[note_bonus_max >= 10.0] = 0.05
|
||||||
|
# bonus[note_bonus_max >= 12.0] = 0.10
|
||||||
|
# bonus[note_bonus_max >= 14.0] = 0.15
|
||||||
|
# bonus[note_bonus_max >= 16.0] = 0.20
|
||||||
|
# bonus[note_bonus_max >= 18.0] = 0.25
|
||||||
|
|
||||||
|
# # Bonus moyenne générale et sur les UE
|
||||||
|
# self.bonus_moy_gen = pd.Series(bonus, index=self.etuds_idx, dtype=float)
|
||||||
|
# ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)]
|
||||||
|
# nb_ues_no_bonus = len(ues_idx)
|
||||||
|
# self.bonus_ues = pd.DataFrame(
|
||||||
|
# np.stack([bonus] * nb_ues_no_bonus, axis=1),
|
||||||
|
# columns=ues_idx,
|
||||||
|
# index=self.etuds_idx,
|
||||||
|
# dtype=float,
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
class BonusBethune(BonusSportMultiplicatif):
|
class BonusBethune(BonusSportMultiplicatif):
|
||||||
"""Calcul bonus modules optionels (sport), règle IUT de Béthune.
|
"""Calcul bonus modules optionnels (sport), règle IUT de Béthune.
|
||||||
|
|
||||||
Les points au dessus de la moyenne de 10 apportent un bonus pour le semestre.
|
Les points au dessus de la moyenne de 10 apportent un bonus pour le semestre.
|
||||||
Ce bonus est égal au nombre de points divisé par 200 et multiplié par la
|
Ce bonus est égal au nombre de points divisé par 200 et multiplié par la
|
||||||
@ -309,7 +381,7 @@ class BonusBethune(BonusSportMultiplicatif):
|
|||||||
|
|
||||||
|
|
||||||
class BonusBezier(BonusSportAdditif):
|
class BonusBezier(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT de Bézier.
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT de Bézier.
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
sport , etc) non rattachés à une unité d'enseignement. Les points
|
sport , etc) non rattachés à une unité d'enseignement. Les points
|
||||||
@ -330,28 +402,91 @@ class BonusBezier(BonusSportAdditif):
|
|||||||
|
|
||||||
|
|
||||||
class BonusBordeaux1(BonusSportMultiplicatif):
|
class BonusBordeaux1(BonusSportMultiplicatif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale
|
||||||
et UE.
|
et UE.
|
||||||
|
<p>
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Bordeaux 1 (sport, théâtre) non rattachés à une unité d'enseignement.
|
de l'Université Bordeaux 1 (sport, théâtre) non rattachés à une unité d'enseignement.
|
||||||
|
</p><p>
|
||||||
Chaque point au-dessus de 10 sur 20 obtenus dans cet enseignement correspond à un %
|
Chaque point au-dessus de 10 sur 20 obtenus dans cet enseignement correspond à un %
|
||||||
qui augmente la moyenne de chaque UE et la moyenne générale.
|
qui augmente la moyenne de chaque UE et la moyenne générale.<br>
|
||||||
Formule : le % = points>moyenne / 2
|
Formule : pourcentage = (points au dessus de 10) / 2
|
||||||
|
</p><p>
|
||||||
Par exemple : sport 13/20 : chaque UE sera multipliée par 1+0,015, ainsi que la moyenne générale.
|
Par exemple : sport 13/20 : chaque UE sera multipliée par 1+0,015, ainsi que la moyenne générale.
|
||||||
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_iutBordeaux1"
|
name = "bonus_iutBordeaux1"
|
||||||
displayed_name = "IUT de Bordeaux 1"
|
displayed_name = "IUT de Bordeaux"
|
||||||
classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP
|
classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP
|
||||||
seuil_moy_gen = 10.0
|
seuil_moy_gen = 10.0
|
||||||
amplitude = 0.005
|
amplitude = 0.005
|
||||||
|
|
||||||
|
|
||||||
|
class BonusCachan1(BonusSportAdditif):
|
||||||
|
"""Calcul bonus optionnels (sport, culture), règle IUT de Cachan 1.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> DUT/LP : la meilleure note d'option, si elle est supérieure à 10,
|
||||||
|
bonifie les moyennes d'UE (<b>sauf l'UE41 dont le code est UE41_E</b>) à raison
|
||||||
|
de <em>bonus = (option - 10)/10</em>.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li> BUT : la meilleure note d'option, si elle est supérieure à 10, bonifie
|
||||||
|
les moyennes d'UE à raison de <em>bonus = (option - 10)*5%</em>.</li>
|
||||||
|
</ul>
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "bonus_cachan1"
|
||||||
|
displayed_name = "IUT de Cachan 1"
|
||||||
|
seuil_moy_gen = 10.0 # tous les points sont comptés
|
||||||
|
proportion_point = 0.05
|
||||||
|
classic_use_bonus_ues = True
|
||||||
|
|
||||||
|
def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
|
||||||
|
"""calcul du bonus, avec réglage différent suivant le type de formation"""
|
||||||
|
# Prend la note de chaque modimpl, sans considération d'UE
|
||||||
|
if len(sem_modimpl_moys_inscrits.shape) > 2: # apc
|
||||||
|
sem_modimpl_moys_inscrits = sem_modimpl_moys_inscrits[:, :, 0]
|
||||||
|
# ici sem_modimpl_moys_inscrits est nb_etuds x nb_mods_bonus, en APC et en classic
|
||||||
|
note_bonus_max = np.max(sem_modimpl_moys_inscrits, axis=1) # 1d, nb_etuds
|
||||||
|
ues = self.formsemestre.query_ues(with_sport=False).all()
|
||||||
|
ues_idx = [ue.id for ue in ues]
|
||||||
|
|
||||||
|
if self.formsemestre.formation.is_apc(): # --- BUT
|
||||||
|
bonus_moy_arr = np.where(
|
||||||
|
note_bonus_max > self.seuil_moy_gen,
|
||||||
|
(note_bonus_max - self.seuil_moy_gen) * self.proportion_point,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
self.bonus_ues = pd.DataFrame(
|
||||||
|
np.stack([bonus_moy_arr] * len(ues)).T,
|
||||||
|
index=self.etuds_idx,
|
||||||
|
columns=ues_idx,
|
||||||
|
dtype=float,
|
||||||
|
)
|
||||||
|
else: # --- DUT
|
||||||
|
# pareil mais proportion différente et exclusion d'une UE
|
||||||
|
proportion_point = 0.1
|
||||||
|
bonus_moy_arr = np.where(
|
||||||
|
note_bonus_max > self.seuil_moy_gen,
|
||||||
|
(note_bonus_max - self.seuil_moy_gen) * proportion_point,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
self.bonus_ues = pd.DataFrame(
|
||||||
|
np.stack([bonus_moy_arr] * len(ues)).T,
|
||||||
|
index=self.etuds_idx,
|
||||||
|
columns=ues_idx,
|
||||||
|
dtype=float,
|
||||||
|
)
|
||||||
|
# Pas de bonus sur la ou les ue de code "UE41_E"
|
||||||
|
ue_exclues = [ue for ue in ues if ue.ue_code == "UE41_E"]
|
||||||
|
for ue in ue_exclues:
|
||||||
|
self.bonus_ues[ue.id] = 0.0
|
||||||
|
|
||||||
|
|
||||||
class BonusColmar(BonusSportAdditif):
|
class BonusColmar(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Colmar.
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Colmar.
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'U.H.A. (sports, musique, deuxième langue, culture, etc) non
|
de l'U.H.A. (sports, musique, deuxième langue, culture, etc) non
|
||||||
@ -374,19 +509,21 @@ class BonusColmar(BonusSportAdditif):
|
|||||||
class BonusGrenobleIUT1(BonusSportMultiplicatif):
|
class BonusGrenobleIUT1(BonusSportMultiplicatif):
|
||||||
"""Bonus IUT1 de Grenoble
|
"""Bonus IUT1 de Grenoble
|
||||||
|
|
||||||
|
<p>
|
||||||
À compter de sept. 2021:
|
À compter de sept. 2021:
|
||||||
La note de sport est sur 20, et on calcule une bonification (en %)
|
La note de sport est sur 20, et on calcule une bonification (en %)
|
||||||
qui va s'appliquer à la moyenne de chaque UE du semestre en appliquant
|
qui va s'appliquer à la moyenne de chaque UE du semestre en appliquant
|
||||||
la formule : bonification (en %) = (note-10)*0,5.
|
la formule : bonification (en %) = (note-10)*0,5.
|
||||||
|
</p><p>
|
||||||
Bonification qui ne s'applique que si la note est >10.
|
<em>La bonification ne s'applique que si la note est supérieure à 10.</em>
|
||||||
|
</p><p>
|
||||||
(Une note de 10 donne donc 0% de bonif ; note de 20 : 5% de bonif)
|
(Une note de 10 donne donc 0% de bonif, et une note de 20 : 5% de bonif)
|
||||||
|
</p><p>
|
||||||
Avant sept. 2021, la note de sport allait de 0 à 5 points (sur 20).
|
Avant sept. 2021, la note de sport allait de 0 à 5 points (sur 20).
|
||||||
Chaque point correspondait à 0.25% d'augmentation de la moyenne
|
Chaque point correspondait à 0.25% d'augmentation de la moyenne
|
||||||
générale.
|
générale.
|
||||||
Par exemple : note de sport 2/5 : la moyenne générale était augmentée de 0.5%.
|
Par exemple : note de sport 2/5 : la moyenne générale était augmentée de 0.5%.
|
||||||
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_iut1grenoble_2017"
|
name = "bonus_iut1grenoble_2017"
|
||||||
@ -411,11 +548,13 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif):
|
|||||||
|
|
||||||
|
|
||||||
class BonusLaRochelle(BonusSportAdditif):
|
class BonusLaRochelle(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT de La Rochelle.
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT de La Rochelle.
|
||||||
|
|
||||||
Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point.
|
<ul>
|
||||||
Si la note de sport est comprise entre 10 et 20 : ajout de 1% de cette
|
<li>Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point.</li>
|
||||||
note sur la moyenne générale du semestre (ou sur les UE en BUT).
|
<li>Si la note de sport est comprise entre 10 et 20 : ajout de 1% de cette
|
||||||
|
note sur la moyenne générale du semestre (ou sur les UE en BUT).</li>
|
||||||
|
</ul>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_iutlr"
|
name = "bonus_iutlr"
|
||||||
@ -440,16 +579,17 @@ class BonusLeHavre(BonusSportMultiplicatif):
|
|||||||
class BonusLeMans(BonusSportAdditif):
|
class BonusLeMans(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionnels (sport, culture), règle IUT Le Mans.
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Le Mans.
|
||||||
|
|
||||||
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières
|
<p>Les points au-dessus de 10 sur 20 obtenus dans chacune des matières
|
||||||
optionnelles sont cumulés.
|
optionnelles sont cumulés.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>En BUT: la moyenne de chacune des UE du semestre est augmentée de
|
||||||
|
2% du cumul des points de bonus;</li>
|
||||||
|
|
||||||
|
<li>En DUT/LP: la moyenne générale est augmentée de 5% du cumul des points bonus.
|
||||||
En BUT: la moyenne de chacune des UE du semestre est augmentée de
|
</li>
|
||||||
2% du cumul des points de bonus,
|
</ul>
|
||||||
|
<p>Dans tous les cas, le bonus est dans la limite de 0,5 point.</p>
|
||||||
En DUT/LP: la moyenne générale est augmentée de 5% du cumul des points bonus.
|
|
||||||
|
|
||||||
Dans tous les cas, le bonus est dans la limite de 0,5 point.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_iutlemans"
|
name = "bonus_iutlemans"
|
||||||
@ -471,14 +611,15 @@ class BonusLeMans(BonusSportAdditif):
|
|||||||
|
|
||||||
# Bonus simple, mais avec changement de paramètres en 2010 !
|
# Bonus simple, mais avec changement de paramètres en 2010 !
|
||||||
class BonusLille(BonusSportAdditif):
|
class BonusLille(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Villeneuve d'Ascq
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
<p>Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Lille (sports, etc) non rattachés à une unité d'enseignement.
|
de l'Université Lille (sports, etc) non rattachés à une unité d'enseignement.
|
||||||
|
</p><p>
|
||||||
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières
|
Les points au-dessus de 10 sur 20 obtenus dans chacune des matières
|
||||||
optionnelles sont cumulés et 4% (2% avant août 2010) de ces points cumulés
|
optionnelles sont cumulés et 4% (2% avant août 2010) de ces points cumulés
|
||||||
s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant.
|
s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||||
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_lille"
|
name = "bonus_lille"
|
||||||
@ -530,17 +671,19 @@ class BonusMulhouse(BonusSportAdditif):
|
|||||||
class BonusNantes(BonusSportAdditif):
|
class BonusNantes(BonusSportAdditif):
|
||||||
"""IUT de Nantes (Septembre 2018)
|
"""IUT de Nantes (Septembre 2018)
|
||||||
|
|
||||||
Nous avons différents types de bonification
|
<p>Nous avons différents types de bonification
|
||||||
(sport, culture, engagement citoyen).
|
(sport, culture, engagement citoyen).
|
||||||
|
</p><p>
|
||||||
Nous ajoutons aux moyennes une bonification de 0,2 pour chaque item
|
Nous ajoutons aux moyennes une bonification de 0,2 pour chaque item
|
||||||
la bonification totale ne doit pas excéder les 0,5 point.
|
la bonification totale ne doit pas excéder les 0,5 point.
|
||||||
Sur le bulletin nous ne mettons pas une note sur 20 mais directement les bonifications.
|
Sur le bulletin nous ne mettons pas une note sur 20 mais directement les bonifications.
|
||||||
|
</p><p>
|
||||||
Dans ScoDoc: on a déclarera une UE "sport&culture" dans laquelle on aura des modules
|
Dans ScoDoc: on a déclarera une UE "sport&culture" dans laquelle on aura
|
||||||
pour chaque activité (Sport, Associations, ...)
|
des modules pour chaque activité (Sport, Associations, ...)
|
||||||
avec à chaque fois une note (ScoDoc l'affichera comme une note sur 20, mais en fait ce sera la
|
avec à chaque fois une note (ScoDoc l'affichera comme une note sur 20,
|
||||||
valeur de la bonification: entrer 0,1/20 signifiera un bonus de 0,1 point la moyenne générale)
|
mais en fait ce sera la valeur de la bonification: entrer 0,1/20 signifiera
|
||||||
|
un bonus de 0,1 point la moyenne générale).
|
||||||
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_nantes"
|
name = "bonus_nantes"
|
||||||
@ -561,11 +704,11 @@ class BonusRoanne(BonusSportAdditif):
|
|||||||
displayed_name = "IUT de Roanne"
|
displayed_name = "IUT de Roanne"
|
||||||
seuil_moy_gen = 0.0
|
seuil_moy_gen = 0.0
|
||||||
bonus_max = 0.6 # plafonnement à 0.6 points
|
bonus_max = 0.6 # plafonnement à 0.6 points
|
||||||
apply_bonus_mg_to_ues = True # sur les UE, même en DUT et LP
|
classic_use_bonus_ues = True # sur les UE, même en DUT et LP
|
||||||
|
|
||||||
|
|
||||||
class BonusStDenis(BonusSportAdditif):
|
class BonusStDenis(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Saint-Denis
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Saint-Denis
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Paris 13 (sports, musique, deuxième langue,
|
de l'Université Paris 13 (sports, musique, deuxième langue,
|
||||||
@ -584,13 +727,14 @@ class BonusStDenis(BonusSportAdditif):
|
|||||||
class BonusTours(BonusDirect):
|
class BonusTours(BonusDirect):
|
||||||
"""Calcul bonus sport & culture IUT Tours.
|
"""Calcul bonus sport & culture IUT Tours.
|
||||||
|
|
||||||
Les notes des UE bonus (ramenées sur 20) sont sommées
|
<p>Les notes des UE bonus (ramenées sur 20) sont sommées
|
||||||
et 1/40 (2,5%) est ajouté aux moyennes: soit à la moyenne générale,
|
et 1/40 (2,5%) est ajouté aux moyennes: soit à la moyenne générale,
|
||||||
soit pour le BUT à chaque moyenne d'UE.
|
soit pour le BUT à chaque moyenne d'UE.
|
||||||
|
</p><p>
|
||||||
Attention: en GEII, facteur 1/40, ailleurs facteur 1.
|
<em>Attention: en GEII, facteur 1/40, ailleurs facteur 1.</em>
|
||||||
|
</p><p>
|
||||||
Le bonus total est limité à 1 point.
|
Le bonus total est limité à 1 point.
|
||||||
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_tours"
|
name = "bonus_tours"
|
||||||
@ -611,15 +755,17 @@ class BonusTours(BonusDirect):
|
|||||||
|
|
||||||
|
|
||||||
class BonusVilleAvray(BonusSport):
|
class BonusVilleAvray(BonusSport):
|
||||||
"""Bonus modules optionels (sport, culture), règle IUT Ville d'Avray.
|
"""Bonus modules optionnels (sport, culture), règle IUT Ville d'Avray.
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.
|
de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.
|
||||||
Si la note est >= 10 et < 12, bonus de 0.1 point
|
<ul>
|
||||||
Si la note est >= 12 et < 16, bonus de 0.2 point
|
<li>Si la note est >= 10 et < 12, bonus de 0.1 point</li>
|
||||||
Si la note est >= 16, bonus de 0.3 point
|
<li>Si la note est >= 12 et < 16, bonus de 0.2 point</li>
|
||||||
Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par
|
<li>Si la note est >= 16, bonus de 0.3 point</li>
|
||||||
l'étudiant.
|
</ul>
|
||||||
|
<p>Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par
|
||||||
|
l'étudiant.</p>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bonus_iutva"
|
name = "bonus_iutva"
|
||||||
@ -645,7 +791,7 @@ class BonusVilleAvray(BonusSport):
|
|||||||
|
|
||||||
|
|
||||||
class BonusIUTV(BonusSportAdditif):
|
class BonusIUTV(BonusSportAdditif):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse
|
"""Calcul bonus modules optionnels (sport, culture), règle IUT Villetaneuse
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Paris 13 (sports, musique, deuxième langue,
|
de l'Université Paris 13 (sports, musique, deuxième langue,
|
||||||
@ -657,7 +803,7 @@ class BonusIUTV(BonusSportAdditif):
|
|||||||
|
|
||||||
name = "bonus_iutv"
|
name = "bonus_iutv"
|
||||||
displayed_name = "IUT de Villetaneuse"
|
displayed_name = "IUT de Villetaneuse"
|
||||||
pass # oui, c'ets le bonus par défaut
|
pass # oui, c'est le bonus par défaut
|
||||||
|
|
||||||
|
|
||||||
def get_bonus_class_dict(start=BonusSport, d=None):
|
def get_bonus_class_dict(start=BonusSport, d=None):
|
||||||
|
@ -335,15 +335,17 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
|||||||
notes_rat / (eval_rat.note_max / 20.0),
|
notes_rat / (eval_rat.note_max / 20.0),
|
||||||
np.nan,
|
np.nan,
|
||||||
)
|
)
|
||||||
|
# "Étend" le rattrapage sur les UE: la note de rattrapage est la même
|
||||||
|
# pour toutes les UE mais ne remplace que là où elle est supérieure
|
||||||
|
notes_rat_ues = np.stack([notes_rat] * nb_ues, axis=1)
|
||||||
# prend le max
|
# prend le max
|
||||||
etuds_use_rattrapage = notes_rat > etuds_moy_module
|
etuds_use_rattrapage = notes_rat_ues > etuds_moy_module
|
||||||
etuds_moy_module = np.where(
|
etuds_moy_module = np.where(
|
||||||
etuds_use_rattrapage[:, np.newaxis],
|
etuds_use_rattrapage, notes_rat_ues, etuds_moy_module
|
||||||
np.tile(notes_rat[:, np.newaxis], nb_ues),
|
|
||||||
etuds_moy_module,
|
|
||||||
)
|
)
|
||||||
|
# Serie indiquant que l'étudiant utilise une note de rattarage sur l'une des UE:
|
||||||
self.etuds_use_rattrapage = pd.Series(
|
self.etuds_use_rattrapage = pd.Series(
|
||||||
etuds_use_rattrapage, index=self.evals_notes.index
|
etuds_use_rattrapage.any(axis=1), index=self.evals_notes.index
|
||||||
)
|
)
|
||||||
self.etuds_moy_module = pd.DataFrame(
|
self.etuds_moy_module = pd.DataFrame(
|
||||||
etuds_moy_module,
|
etuds_moy_module,
|
||||||
@ -359,6 +361,10 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]:
|
|||||||
Les valeurs manquantes (évaluations sans coef vers des UE) sont
|
Les valeurs manquantes (évaluations sans coef vers des UE) sont
|
||||||
remplies: 1 si le coef de ce module dans l'UE est non nul, zéro sinon
|
remplies: 1 si le coef de ce module dans l'UE est non nul, zéro sinon
|
||||||
(sauf pour module bonus, defaut à 1)
|
(sauf pour module bonus, defaut à 1)
|
||||||
|
|
||||||
|
Si le module n'est pas une ressource ou une SAE, ne charge pas de poids
|
||||||
|
et renvoie toujours les poids par défaut.
|
||||||
|
|
||||||
Résultat: (evals_poids, liste de UEs du semestre sauf le sport)
|
Résultat: (evals_poids, liste de UEs du semestre sauf le sport)
|
||||||
"""
|
"""
|
||||||
modimpl: ModuleImpl = ModuleImpl.query.get(moduleimpl_id)
|
modimpl: ModuleImpl = ModuleImpl.query.get(moduleimpl_id)
|
||||||
@ -367,13 +373,17 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]:
|
|||||||
ue_ids = [ue.id for ue in ues]
|
ue_ids = [ue.id for ue in ues]
|
||||||
evaluation_ids = [evaluation.id for evaluation in evaluations]
|
evaluation_ids = [evaluation.id for evaluation in evaluations]
|
||||||
evals_poids = pd.DataFrame(columns=ue_ids, index=evaluation_ids, dtype=float)
|
evals_poids = pd.DataFrame(columns=ue_ids, index=evaluation_ids, dtype=float)
|
||||||
for ue_poids in EvaluationUEPoids.query.join(
|
if (
|
||||||
EvaluationUEPoids.evaluation
|
modimpl.module.module_type == ModuleType.RESSOURCE
|
||||||
).filter_by(moduleimpl_id=moduleimpl_id):
|
or modimpl.module.module_type == ModuleType.SAE
|
||||||
try:
|
):
|
||||||
evals_poids[ue_poids.ue_id][ue_poids.evaluation_id] = ue_poids.poids
|
for ue_poids in EvaluationUEPoids.query.join(
|
||||||
except KeyError as exc:
|
EvaluationUEPoids.evaluation
|
||||||
pass # poids vers des UE qui n'existent plus ou sont dans un autre semestre...
|
).filter_by(moduleimpl_id=moduleimpl_id):
|
||||||
|
try:
|
||||||
|
evals_poids[ue_poids.ue_id][ue_poids.evaluation_id] = ue_poids.poids
|
||||||
|
except KeyError as exc:
|
||||||
|
pass # poids vers des UE qui n'existent plus ou sont dans un autre semestre...
|
||||||
|
|
||||||
# Initialise poids non enregistrés:
|
# Initialise poids non enregistrés:
|
||||||
default_poids = (
|
default_poids = (
|
||||||
|
@ -218,21 +218,25 @@ def compute_ue_moys_apc(
|
|||||||
ues: list,
|
ues: list,
|
||||||
modimpl_inscr_df: pd.DataFrame,
|
modimpl_inscr_df: pd.DataFrame,
|
||||||
modimpl_coefs_df: pd.DataFrame,
|
modimpl_coefs_df: pd.DataFrame,
|
||||||
|
modimpl_mask: np.array,
|
||||||
) -> pd.DataFrame:
|
) -> pd.DataFrame:
|
||||||
"""Calcul de la moyenne d'UE en mode APC (BUT).
|
"""Calcul de la moyenne d'UE en mode APC (BUT).
|
||||||
La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR
|
La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR
|
||||||
NI non inscrit à (au moins un) module de cette UE
|
NI non inscrit à (au moins un) module de cette UE
|
||||||
NA pas de notes disponibles
|
NA pas de notes disponibles
|
||||||
ERR erreur dans une formule utilisateur. [XXX pas encore gérées ici]
|
ERR erreur dans une formule utilisateurs (pas gérées ici).
|
||||||
|
|
||||||
sem_cube: notes moyennes aux modules
|
sem_cube: notes moyennes aux modules
|
||||||
ndarray (etuds x modimpls x UEs)
|
ndarray (etuds x modimpls x UEs)
|
||||||
(floats avec des NaN)
|
(floats avec des NaN)
|
||||||
etuds : liste des étudiants (dim. 0 du cube)
|
etuds : liste des étudiants (dim. 0 du cube)
|
||||||
modimpls : liste des modules à considérer (dim. 1 du cube)
|
modimpls : liste des module_impl (dim. 1 du cube)
|
||||||
ues : liste des UE (dim. 2 du cube)
|
ues : liste des UE (dim. 2 du cube)
|
||||||
modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl)
|
modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl)
|
||||||
modimpl_coefs_df: matrice coefficients (UE x modimpl), sans UEs bonus sport
|
modimpl_coefs_df: matrice coefficients (UE x modimpl), sans UEs bonus sport
|
||||||
|
modimpl_mask: liste de booléens, indiquants le module doit être pris ou pas.
|
||||||
|
(utilisé pour éliminer les bonus, et pourra servir à cacluler
|
||||||
|
sur des sous-ensembles de modules)
|
||||||
|
|
||||||
Résultat: DataFrame columns UE (sans bonus), rows etudid
|
Résultat: DataFrame columns UE (sans bonus), rows etudid
|
||||||
"""
|
"""
|
||||||
@ -249,7 +253,8 @@ def compute_ue_moys_apc(
|
|||||||
assert modimpl_coefs_df.shape[0] == nb_ues_no_bonus
|
assert modimpl_coefs_df.shape[0] == nb_ues_no_bonus
|
||||||
assert modimpl_coefs_df.shape[1] == nb_modules
|
assert modimpl_coefs_df.shape[1] == nb_modules
|
||||||
modimpl_inscr = modimpl_inscr_df.values
|
modimpl_inscr = modimpl_inscr_df.values
|
||||||
modimpl_coefs = modimpl_coefs_df.values
|
# Met à zéro tous les coefs des modules non sélectionnés dans le masque:
|
||||||
|
modimpl_coefs = np.where(modimpl_mask, modimpl_coefs_df.values, 0.0)
|
||||||
|
|
||||||
# Duplique les inscriptions sur les UEs non bonus:
|
# Duplique les inscriptions sur les UEs non bonus:
|
||||||
modimpl_inscr_stacked = np.stack([modimpl_inscr] * nb_ues_no_bonus, axis=2)
|
modimpl_inscr_stacked = np.stack([modimpl_inscr] * nb_ues_no_bonus, axis=2)
|
||||||
@ -266,6 +271,8 @@ def compute_ue_moys_apc(
|
|||||||
)
|
)
|
||||||
# Annule les coefs des modules NaN
|
# Annule les coefs des modules NaN
|
||||||
modimpl_coefs_etuds_no_nan = np.where(np.isnan(sem_cube), 0.0, modimpl_coefs_etuds)
|
modimpl_coefs_etuds_no_nan = np.where(np.isnan(sem_cube), 0.0, modimpl_coefs_etuds)
|
||||||
|
if modimpl_coefs_etuds_no_nan.dtype == np.object: # arrive sur des tableaux vides
|
||||||
|
modimpl_coefs_etuds_no_nan = modimpl_coefs_etuds_no_nan.astype(np.float)
|
||||||
#
|
#
|
||||||
# Version vectorisée
|
# Version vectorisée
|
||||||
#
|
#
|
||||||
@ -348,7 +355,8 @@ def compute_ue_moys_classic(
|
|||||||
modimpl_coefs_etuds_no_nan = np.where(
|
modimpl_coefs_etuds_no_nan = np.where(
|
||||||
np.isnan(sem_matrix), 0.0, modimpl_coefs_etuds
|
np.isnan(sem_matrix), 0.0, modimpl_coefs_etuds
|
||||||
)
|
)
|
||||||
|
if modimpl_coefs_etuds_no_nan.dtype == np.object: # arrive sur des tableaux vides
|
||||||
|
modimpl_coefs_etuds_no_nan = modimpl_coefs_etuds_no_nan.astype(np.float)
|
||||||
# --------------------- Calcul des moyennes d'UE
|
# --------------------- Calcul des moyennes d'UE
|
||||||
ue_modules = np.array(
|
ue_modules = np.array(
|
||||||
[[m.module.ue == ue for m in formsemestre.modimpls_sorted] for ue in ues]
|
[[m.module.ue == ue for m in formsemestre.modimpls_sorted] for ue in ues]
|
||||||
@ -358,6 +366,8 @@ def compute_ue_moys_classic(
|
|||||||
)
|
)
|
||||||
# nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions
|
# nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions
|
||||||
coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2)
|
coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2)
|
||||||
|
if coefs.dtype == np.object: # arrive sur des tableaux vides
|
||||||
|
coefs = coefs.astype(np.float)
|
||||||
with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN)
|
with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN)
|
||||||
etud_moy_ue = (
|
etud_moy_ue = (
|
||||||
np.sum(coefs * sem_matrix_inscrits, axis=2) / np.sum(coefs, axis=2)
|
np.sum(coefs * sem_matrix_inscrits, axis=2) / np.sum(coefs, axis=2)
|
||||||
|
@ -56,14 +56,11 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
# modimpl_coefs_df.columns.get_loc(modimpl.id)
|
# modimpl_coefs_df.columns.get_loc(modimpl.id)
|
||||||
# idx de l'UE: modimpl_coefs_df.index.get_loc(ue.id)
|
# idx de l'UE: modimpl_coefs_df.index.get_loc(ue.id)
|
||||||
|
|
||||||
# Elimine les coefs des modimpl bonus sports:
|
# Masque de tous les modules _sauf_ les bonus (sport)
|
||||||
modimpls_sport = [
|
modimpls_mask = [
|
||||||
modimpl
|
modimpl.module.ue.type != UE_SPORT
|
||||||
for modimpl in self.formsemestre.modimpls_sorted
|
for modimpl in self.formsemestre.modimpls_sorted
|
||||||
if modimpl.module.ue.type == UE_SPORT
|
|
||||||
]
|
]
|
||||||
for modimpl in modimpls_sport:
|
|
||||||
self.modimpl_coefs_df[modimpl.id] = 0
|
|
||||||
|
|
||||||
self.etud_moy_ue = moy_ue.compute_ue_moys_apc(
|
self.etud_moy_ue = moy_ue.compute_ue_moys_apc(
|
||||||
self.sem_cube,
|
self.sem_cube,
|
||||||
@ -72,6 +69,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
self.ues,
|
self.ues,
|
||||||
self.modimpl_inscr_df,
|
self.modimpl_inscr_df,
|
||||||
self.modimpl_coefs_df,
|
self.modimpl_coefs_df,
|
||||||
|
modimpls_mask,
|
||||||
)
|
)
|
||||||
# Les coefficients d'UE ne sont pas utilisés en APC
|
# Les coefficients d'UE ne sont pas utilisés en APC
|
||||||
self.etud_coef_ue_df = pd.DataFrame(
|
self.etud_coef_ue_df = pd.DataFrame(
|
||||||
@ -85,7 +83,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
self.etud_moy_ue -= self.malus
|
self.etud_moy_ue -= self.malus
|
||||||
|
|
||||||
# --- Bonus Sport & Culture
|
# --- Bonus Sport & Culture
|
||||||
if len(modimpls_sport) > 0:
|
if not all(modimpls_mask): # au moins un module bonus
|
||||||
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
||||||
if bonus_class is not None:
|
if bonus_class is not None:
|
||||||
bonus: BonusSport = bonus_class(
|
bonus: BonusSport = bonus_class(
|
||||||
|
@ -60,7 +60,7 @@ class ResultatsSemestreClassic(NotesTableCompat):
|
|||||||
)
|
)
|
||||||
self.modimpl_inscr_df = inscr_mod.df_load_modimpl_inscr(self.formsemestre)
|
self.modimpl_inscr_df = inscr_mod.df_load_modimpl_inscr(self.formsemestre)
|
||||||
self.modimpl_coefs = np.array(
|
self.modimpl_coefs = np.array(
|
||||||
[m.module.coefficient for m in self.formsemestre.modimpls_sorted]
|
[m.module.coefficient or 0.0 for m in self.formsemestre.modimpls_sorted]
|
||||||
)
|
)
|
||||||
self.modimpl_idx = {
|
self.modimpl_idx = {
|
||||||
m.id: i for i, m in enumerate(self.formsemestre.modimpls_sorted)
|
m.id: i for i, m in enumerate(self.formsemestre.modimpls_sorted)
|
||||||
@ -113,11 +113,20 @@ class ResultatsSemestreClassic(NotesTableCompat):
|
|||||||
self.etud_moy_ue += self.bonus_ues # somme les dataframes
|
self.etud_moy_ue += self.bonus_ues # somme les dataframes
|
||||||
self.etud_moy_ue.clip(lower=0.0, upper=20.0, inplace=True)
|
self.etud_moy_ue.clip(lower=0.0, upper=20.0, inplace=True)
|
||||||
bonus_mg = bonus.get_bonus_moy_gen()
|
bonus_mg = bonus.get_bonus_moy_gen()
|
||||||
if bonus_mg is not None:
|
if bonus_mg is None and self.bonus_ues is not None:
|
||||||
|
# pas de bonus explicite sur la moyenne générale
|
||||||
|
# on l'ajuste pour refléter les modifs d'UE, à l'aide des coefs d'UE.
|
||||||
|
bonus_mg = (self.etud_coef_ue_df * self.bonus_ues).sum(
|
||||||
|
axis=1
|
||||||
|
) / self.etud_coef_ue_df.sum(axis=1)
|
||||||
self.etud_moy_gen += bonus_mg
|
self.etud_moy_gen += bonus_mg
|
||||||
self.etud_moy_gen.clip(lower=0.0, upper=20.0, inplace=True)
|
elif bonus_mg is not None:
|
||||||
# compat nt, utilisé pour l'afficher sur les bulletins:
|
# Applique le bonus moyenne générale renvoyé
|
||||||
self.bonus = bonus_mg
|
self.etud_moy_gen += bonus_mg
|
||||||
|
|
||||||
|
self.etud_moy_gen.clip(lower=0.0, upper=20.0, inplace=True)
|
||||||
|
# compat nt, utilisé pour l'afficher sur les bulletins:
|
||||||
|
self.bonus = bonus_mg
|
||||||
# --- UE capitalisées
|
# --- UE capitalisées
|
||||||
self.apply_capitalisation()
|
self.apply_capitalisation()
|
||||||
|
|
||||||
|
@ -55,6 +55,9 @@ def create_dept(acronym: str, visible=True) -> Departement:
|
|||||||
"Create new departement"
|
"Create new departement"
|
||||||
from app.models import ScoPreference
|
from app.models import ScoPreference
|
||||||
|
|
||||||
|
existing = Departement.query.filter_by(acronym=acronym).count()
|
||||||
|
if existing:
|
||||||
|
raise ValueError(f"acronyme {acronym} déjà existant")
|
||||||
departement = Departement(acronym=acronym, visible=visible)
|
departement = Departement(acronym=acronym, visible=visible)
|
||||||
p1 = ScoPreference(name="DeptName", value=acronym, departement=departement)
|
p1 = ScoPreference(name="DeptName", value=acronym, departement=departement)
|
||||||
db.session.add(p1)
|
db.session.add(p1)
|
||||||
|
@ -104,6 +104,11 @@ class FormSemestre(db.Model):
|
|||||||
lazy=True,
|
lazy=True,
|
||||||
backref=db.backref("formsemestres", lazy=True),
|
backref=db.backref("formsemestres", lazy=True),
|
||||||
)
|
)
|
||||||
|
partitions = db.relationship(
|
||||||
|
"Partition",
|
||||||
|
backref=db.backref("formsemestre", lazy=True),
|
||||||
|
lazy="dynamic",
|
||||||
|
)
|
||||||
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
||||||
# ne pas utiliser après migrate_scodoc7_dept_archives
|
# ne pas utiliser après migrate_scodoc7_dept_archives
|
||||||
scodoc7_id = db.Column(db.Text(), nullable=True)
|
scodoc7_id = db.Column(db.Text(), nullable=True)
|
||||||
|
@ -31,6 +31,11 @@ class Partition(db.Model):
|
|||||||
show_in_lists = db.Column(
|
show_in_lists = db.Column(
|
||||||
db.Boolean(), nullable=False, default=True, server_default="true"
|
db.Boolean(), nullable=False, default=True, server_default="true"
|
||||||
)
|
)
|
||||||
|
groups = db.relationship(
|
||||||
|
"GroupDescr",
|
||||||
|
backref=db.backref("partition", lazy=True),
|
||||||
|
lazy="dynamic",
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(Partition, self).__init__(**kwargs)
|
super(Partition, self).__init__(**kwargs)
|
||||||
@ -42,6 +47,9 @@ class Partition(db.Model):
|
|||||||
else:
|
else:
|
||||||
self.numero = 1
|
self.numero = 1
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"""<{self.__class__.__name__} {self.id} "{self.partition_name or '(default)'}">"""
|
||||||
|
|
||||||
|
|
||||||
class GroupDescr(db.Model):
|
class GroupDescr(db.Model):
|
||||||
"""Description d'un groupe d'une partition"""
|
"""Description d'un groupe d'une partition"""
|
||||||
@ -55,6 +63,11 @@ class GroupDescr(db.Model):
|
|||||||
# "A", "C2", ... (NULL for 'all'):
|
# "A", "C2", ... (NULL for 'all'):
|
||||||
group_name = db.Column(db.String(GROUPNAME_STR_LEN))
|
group_name = db.Column(db.String(GROUPNAME_STR_LEN))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return (
|
||||||
|
f"""<{self.__class__.__name__} {self.id} "{self.group_name or '(tous)'}">"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
group_membership = db.Table(
|
group_membership = db.Table(
|
||||||
"group_membership",
|
"group_membership",
|
||||||
|
@ -34,7 +34,7 @@ class Module(db.Model):
|
|||||||
# id de l'element pedagogique Apogee correspondant:
|
# id de l'element pedagogique Apogee correspondant:
|
||||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||||
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
||||||
module_type = db.Column(db.Integer)
|
module_type = db.Column(db.Integer, nullable=False, default=0, server_default="0")
|
||||||
# Relations:
|
# Relations:
|
||||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||||
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
||||||
|
@ -298,6 +298,8 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
u["cur_moy_ue_txt"] = "bonus appliqué sur les UEs"
|
u["cur_moy_ue_txt"] = "bonus appliqué sur les UEs"
|
||||||
else:
|
else:
|
||||||
u["cur_moy_ue_txt"] = "bonus de %.3g points" % x
|
u["cur_moy_ue_txt"] = "bonus de %.3g points" % x
|
||||||
|
if nt.bonus_ues is not None:
|
||||||
|
u["cur_moy_ue_txt"] += " (+ues)"
|
||||||
u["moy_ue_txt"] = scu.fmt_note(ue_status["moy"])
|
u["moy_ue_txt"] = scu.fmt_note(ue_status["moy"])
|
||||||
if ue_status["coef_ue"] != None:
|
if ue_status["coef_ue"] != None:
|
||||||
u["coef_ue_txt"] = scu.fmt_coef(ue_status["coef_ue"])
|
u["coef_ue_txt"] = scu.fmt_coef(ue_status["coef_ue"])
|
||||||
|
@ -500,6 +500,13 @@ def module_edit(module_id=None):
|
|||||||
matieres = matieres.filter(UniteEns.semestre_idx == a_module.ue.semestre_idx)
|
matieres = matieres.filter(UniteEns.semestre_idx == a_module.ue.semestre_idx)
|
||||||
|
|
||||||
if is_apc:
|
if is_apc:
|
||||||
|
# ne conserve que la 1ere matière de chaque UE,
|
||||||
|
# et celle à laquelle ce module est rattaché
|
||||||
|
matieres = [
|
||||||
|
mat
|
||||||
|
for mat in matieres
|
||||||
|
if a_module.matiere.id == mat.id or mat.id == mat.ue.matieres.first().id
|
||||||
|
]
|
||||||
mat_names = [
|
mat_names = [
|
||||||
"S%s / %s" % (mat.ue.semestre_idx, mat.ue.acronyme) for mat in matieres
|
"S%s / %s" % (mat.ue.semestre_idx, mat.ue.acronyme) for mat in matieres
|
||||||
]
|
]
|
||||||
|
@ -601,7 +601,12 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
|||||||
_add_ue_semestre_id(ues_externes, is_apc)
|
_add_ue_semestre_id(ues_externes, is_apc)
|
||||||
ues.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
ues.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||||
ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||||
has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ues])) != len(ues)
|
# Codes dupliqués (pour aider l'utilisateur)
|
||||||
|
seen = set()
|
||||||
|
duplicated_codes = {
|
||||||
|
ue["ue_code"] for ue in ues if ue["ue_code"] in seen or seen.add(ue["ue_code"])
|
||||||
|
}
|
||||||
|
ues_with_duplicated_code = [ue for ue in ues if ue["ue_code"] in duplicated_codes]
|
||||||
|
|
||||||
has_perm_change = current_user.has_permission(Permission.ScoChangeFormation)
|
has_perm_change = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
# editable = (not locked) and has_perm_change
|
# editable = (not locked) and has_perm_change
|
||||||
@ -664,11 +669,17 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
if msg:
|
if msg:
|
||||||
H.append('<p class="msg">' + msg + "</p>")
|
H.append('<p class="msg">' + msg + "</p>")
|
||||||
|
|
||||||
if has_duplicate_ue_codes:
|
if ues_with_duplicated_code:
|
||||||
H.append(
|
H.append(
|
||||||
"""<div class="ue_warning"><span>Attention: plusieurs UE de cette
|
f"""<div class="ue_warning"><span>Attention: plusieurs UE de cette
|
||||||
formation ont le même code. Il faut corriger cela ci-dessous,
|
formation ont le même code : <tt>{
|
||||||
sinon les calculs d'ECTS seront erronés !</span></div>"""
|
', '.join([
|
||||||
|
'<a class="stdlink" href="' + url_for( "notes.ue_edit", scodoc_dept=g.scodoc_dept, ue_id=ue["ue_id"] )
|
||||||
|
+ '">' + ue["acronyme"] + " (code " + ue["ue_code"] + ")</a>"
|
||||||
|
for ue in ues_with_duplicated_code ])
|
||||||
|
}</tt>.
|
||||||
|
Il faut corriger cela, sinon les capitalisations et ECTS seront
|
||||||
|
erronés !</span></div>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Description de la formation
|
# Description de la formation
|
||||||
@ -930,8 +941,8 @@ def _ue_table_ues(
|
|||||||
|
|
||||||
if cur_ue_semestre_id != ue["semestre_id"]:
|
if cur_ue_semestre_id != ue["semestre_id"]:
|
||||||
cur_ue_semestre_id = ue["semestre_id"]
|
cur_ue_semestre_id = ue["semestre_id"]
|
||||||
if iue > 0:
|
# if iue > 0:
|
||||||
H.append("</ul>")
|
# H.append("</ul>")
|
||||||
if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT:
|
if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT:
|
||||||
lab = "Pas d'indication de semestre:"
|
lab = "Pas d'indication de semestre:"
|
||||||
else:
|
else:
|
||||||
@ -953,7 +964,6 @@ def _ue_table_ues(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
H.append(arrow_none)
|
H.append(arrow_none)
|
||||||
iue += 1
|
|
||||||
ue["acro_titre"] = str(ue["acronyme"])
|
ue["acro_titre"] = str(ue["acronyme"])
|
||||||
if ue["titre"] != ue["acronyme"]:
|
if ue["titre"] != ue["acronyme"]:
|
||||||
ue["acro_titre"] += " " + str(ue["titre"])
|
ue["acro_titre"] += " " + str(ue["titre"])
|
||||||
@ -1001,6 +1011,14 @@ def _ue_table_ues(
|
|||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if (iue >= len(ues) - 1) or ue["semestre_id"] != ues[iue + 1]["semestre_id"]:
|
||||||
|
H.append(
|
||||||
|
f"""</ul><ul><li><a href="{url_for('notes.ue_create', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=ue['formation_id'], semestre_idx=ue['semestre_id'])
|
||||||
|
}">Ajouter une UE dans le semestre {ue['semestre_id'] or ''}</a></li></ul>"""
|
||||||
|
)
|
||||||
|
iue += 1
|
||||||
|
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
|||||||
|
|
||||||
|
|
||||||
def apo_semset_maq_status(
|
def apo_semset_maq_status(
|
||||||
semset_id="",
|
semset_id: int,
|
||||||
allow_missing_apo=False,
|
allow_missing_apo=False,
|
||||||
allow_missing_decisions=False,
|
allow_missing_decisions=False,
|
||||||
allow_missing_csv=False,
|
allow_missing_csv=False,
|
||||||
@ -65,7 +65,7 @@ def apo_semset_maq_status(
|
|||||||
):
|
):
|
||||||
"""Page statut / tableau de bord"""
|
"""Page statut / tableau de bord"""
|
||||||
if not semset_id:
|
if not semset_id:
|
||||||
raise ValueError("invalid null semset_id")
|
raise ScoValueError("invalid null semset_id")
|
||||||
semset = sco_semset.SemSet(semset_id=semset_id)
|
semset = sco_semset.SemSet(semset_id=semset_id)
|
||||||
semset.fill_formsemestres()
|
semset.fill_formsemestres()
|
||||||
# autorise export meme si etudiants Apo manquants:
|
# autorise export meme si etudiants Apo manquants:
|
||||||
|
@ -405,7 +405,6 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
|||||||
"""Page avec calendrier de toutes les evaluations de ce semestre"""
|
"""Page avec calendrier de toutes les evaluations de ce semestre"""
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
sem = formsemestre.to_dict()
|
|
||||||
|
|
||||||
evals = nt.get_evaluations_etats()
|
evals = nt.get_evaluations_etats()
|
||||||
nb_evals = len(evals)
|
nb_evals = len(evals)
|
||||||
@ -416,8 +415,8 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
|||||||
|
|
||||||
today = time.strftime("%Y-%m-%d")
|
today = time.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
year = int(sem["annee_debut"])
|
year = formsemestre.date_debut.year
|
||||||
if sem["mois_debut_ord"] < 8:
|
if formsemestre.date_debut.month < 8:
|
||||||
year -= 1 # calendrier septembre a septembre
|
year -= 1 # calendrier septembre a septembre
|
||||||
events = {} # (day, halfday) : event
|
events = {} # (day, halfday) : event
|
||||||
for e in evals:
|
for e in evals:
|
||||||
@ -537,11 +536,10 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
"""Experimental: un tableau indiquant pour chaque évaluation
|
"""Experimental: un tableau indiquant pour chaque évaluation
|
||||||
le nombre de jours avant la publication des notes.
|
le nombre de jours avant la publication des notes.
|
||||||
|
|
||||||
N'indique pas les évaluations de ratrapage ni celles des modules de bonus/malus.
|
N'indique pas les évaluations de rattrapage ni celles des modules de bonus/malus.
|
||||||
"""
|
"""
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
sem = formsemestre.to_dict()
|
|
||||||
|
|
||||||
evals = nt.get_evaluations_etats()
|
evals = nt.get_evaluations_etats()
|
||||||
T = []
|
T = []
|
||||||
@ -607,7 +605,7 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
origin="Généré par %s le " % sco_version.SCONAME
|
origin="Généré par %s le " % sco_version.SCONAME
|
||||||
+ scu.timedate_human_repr()
|
+ scu.timedate_human_repr()
|
||||||
+ "",
|
+ "",
|
||||||
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
filename=scu.make_filename("evaluations_delais_" + formsemestre.titre_annee()),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
@ -635,16 +633,13 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
'<span class="evallink"><a class="stdlink" href="evaluation_listenotes?moduleimpl_id=%s">voir toutes les notes du module</a></span>'
|
'<span class="evallink"><a class="stdlink" href="evaluation_listenotes?moduleimpl_id=%s">voir toutes les notes du module</a></span>'
|
||||||
% moduleimpl_id
|
% moduleimpl_id
|
||||||
)
|
)
|
||||||
mod_descr = (
|
mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s' % (
|
||||||
'<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s'
|
moduleimpl_id,
|
||||||
% (
|
Mod["code"] or "",
|
||||||
moduleimpl_id,
|
Mod["titre"] or "?",
|
||||||
Mod["code"] or "",
|
nomcomplet,
|
||||||
Mod["titre"] or "?",
|
resp,
|
||||||
nomcomplet,
|
link,
|
||||||
resp,
|
|
||||||
link,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
etit = E["description"] or ""
|
etit = E["description"] or ""
|
||||||
|
@ -1286,7 +1286,11 @@ def check_formation_ues(formation_id):
|
|||||||
for x in ue_multiples[ue["ue_id"]]
|
for x in ue_multiples[ue["ue_id"]]
|
||||||
]
|
]
|
||||||
slist = ", ".join(
|
slist = ", ".join(
|
||||||
["%(titreannee)s (<em>semestre %(semestre_id)s</em>)" % s for s in sems]
|
[
|
||||||
|
"""%(titreannee)s (<em>semestre <b class="fontred">%(semestre_id)s</b></em>)"""
|
||||||
|
% s
|
||||||
|
for s in sems
|
||||||
|
]
|
||||||
)
|
)
|
||||||
H.append("<li><b>%s</b> : %s</li>" % (ue["acronyme"], slist))
|
H.append("<li><b>%s</b> : %s</li>" % (ue["acronyme"], slist))
|
||||||
H.append("</ul></div>")
|
H.append("</ul></div>")
|
||||||
|
@ -302,7 +302,12 @@ class DisplayedGroupsInfos(object):
|
|||||||
if group_ids:
|
if group_ids:
|
||||||
group_ids = [group_ids] # cas ou un seul parametre, pas de liste
|
group_ids = [group_ids] # cas ou un seul parametre, pas de liste
|
||||||
else:
|
else:
|
||||||
group_ids = [int(g) for g in group_ids]
|
try:
|
||||||
|
group_ids = [int(g) for g in group_ids]
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ScoValueError(
|
||||||
|
"identifiant de groupe invalide (mettre à jour vos bookmarks ?)"
|
||||||
|
) from exc
|
||||||
if not formsemestre_id and moduleimpl_id:
|
if not formsemestre_id and moduleimpl_id:
|
||||||
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
|
@ -305,7 +305,10 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
|||||||
if can_change:
|
if can_change:
|
||||||
c_link = (
|
c_link = (
|
||||||
'<a class="discretelink" href="moduleimpl_inscriptions_edit?moduleimpl_id=%s">%s</a>'
|
'<a class="discretelink" href="moduleimpl_inscriptions_edit?moduleimpl_id=%s">%s</a>'
|
||||||
% (mod["moduleimpl_id"], mod["descri"])
|
% (
|
||||||
|
mod["moduleimpl_id"],
|
||||||
|
mod["descri"] or "<i>(inscrire des étudiants)</i>",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
c_link = mod["descri"]
|
c_link = mod["descri"]
|
||||||
|
@ -1707,6 +1707,9 @@ ul.notes_ue_list {
|
|||||||
li.notes_ue_list {
|
li.notes_ue_list {
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
border: 1px solid maroon;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
span.ue_type_1 {
|
span.ue_type_1 {
|
||||||
color: green;
|
color: green;
|
||||||
@ -1749,6 +1752,7 @@ ul.notes_matiere_list {
|
|||||||
background-color: rgb(220,220,220);
|
background-color: rgb(220,220,220);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
border-top: 1px solid maroon;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.notes_module_list {
|
ul.notes_module_list {
|
||||||
|
@ -91,7 +91,7 @@ class releveBUT extends HTMLElement {
|
|||||||
<div>
|
<div>
|
||||||
<div class=decision></div>
|
<div class=decision></div>
|
||||||
<div class=dateInscription>Inscrit le </div>
|
<div class=dateInscription>Inscrit le </div>
|
||||||
<em>Les moyennes servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de compétences ou d'UE.</em>
|
<em>Les moyennes ci-dessus servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de compétences ou d'UE.</em>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
<a href="{{ url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept, ) }}">
|
<a href="{{ url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept, ) }}">
|
||||||
Liste des référentiels de compétences chargés</a>
|
Liste des référentiels de compétences chargés</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% if formation is not none %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('notes.refcomp_assoc_formation', scodoc_dept=g.scodoc_dept, formation_id=formation.id) }}">
|
<a href="{{ url_for('notes.refcomp_assoc_formation', scodoc_dept=g.scodoc_dept, formation_id=formation.id) }}">
|
||||||
Association à la formation {{ formation.acronyme }}</a>
|
Association à la formation {{ formation.acronyme }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -65,6 +65,13 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{% if mod.ue.type != 0 and mod.module_type != 0 %}
|
||||||
|
<span class="warning" title="Une UE de type spécial ne
|
||||||
|
devrait contenir que des modules standards">
|
||||||
|
type incompatible avec son UE de rattachement !
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<span class="sco_tag_edit"><form><textarea data-module_id="{{mod.id}}"
|
<span class="sco_tag_edit"><form><textarea data-module_id="{{mod.id}}"
|
||||||
class="{% if tag_editable %}module_tag_editor{% else %}module_tag_editor_ro{% endif %}">{{mod.tags|join(', ', attribute='title')}}</textarea></form></span>
|
class="{% if tag_editable %}module_tag_editor{% else %}module_tag_editor_ro{% endif %}">{{mod.tags|join(', ', attribute='title')}}</textarea></form></span>
|
||||||
|
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
}}">modifier</a>
|
}}">modifier</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if ue.type == 1 and ue.modules.count() == 0 %}
|
||||||
|
<span class="warning" title="pas de module, donc pas de bonus calculé">aucun module rattaché !</span>
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
{# sidebar_common #}
|
{# sidebar_common #}
|
||||||
<a class="scodoc_title" href="{{
|
<a class="scodoc_title" href="{{
|
||||||
url_for('scodoc.index', scodoc_dept=g.scodoc_dept) }}">ScoDoc 9.2a</a>
|
url_for('scodoc.index', scodoc_dept=g.scodoc_dept) }}">ScoDoc {{ sco.SCOVERSION }}</a>
|
||||||
<div id="authuser"><a id="authuserlink" href="{{
|
<div id="authuser"><a id="authuserlink" href="{{
|
||||||
url_for('users.user_info_page', scodoc_dept=g.scodoc_dept, user_name=current_user.user_name)
|
url_for('users.user_info_page', scodoc_dept=g.scodoc_dept, user_name=current_user.user_name)
|
||||||
}}">{{current_user.user_name}}</a>
|
}}">{{current_user.user_name}}</a>
|
||||||
|
@ -16,6 +16,7 @@ from app.scodoc import sco_formsemestre_status
|
|||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
import sco_version
|
||||||
|
|
||||||
scodoc_bp = Blueprint("scodoc", __name__)
|
scodoc_bp = Blueprint("scodoc", __name__)
|
||||||
scolar_bp = Blueprint("scolar", __name__)
|
scolar_bp = Blueprint("scolar", __name__)
|
||||||
@ -53,6 +54,7 @@ class ScoData:
|
|||||||
# Champs utilisés par toutes les pages ScoDoc (sidebar, en-tête)
|
# Champs utilisés par toutes les pages ScoDoc (sidebar, en-tête)
|
||||||
self.Permission = Permission
|
self.Permission = Permission
|
||||||
self.scu = scu
|
self.scu = scu
|
||||||
|
self.SCOVERSION = sco_version.SCOVERSION
|
||||||
# -- Informations étudiant courant, si sélectionné:
|
# -- Informations étudiant courant, si sélectionné:
|
||||||
etudid = g.get("etudid", None)
|
etudid = g.get("etudid", None)
|
||||||
if not etudid:
|
if not etudid:
|
||||||
|
@ -397,7 +397,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/ue_infos/<ue_id>")
|
@bp.route("/ue_infos/<int:ue_id>")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def ue_infos(ue_id):
|
def ue_infos(ue_id):
|
||||||
|
@ -68,7 +68,7 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
|
|
||||||
|
|
||||||
@bp.route("/table_modules_ue_coefs/<int:formation_id>")
|
@bp.route("/table_modules_ue_coefs/<int:formation_id>")
|
||||||
@bp.route("/table_modules_ue_coefs/<int:formation_id>/<semestre_idx>")
|
@bp.route("/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def table_modules_ue_coefs(formation_id, semestre_idx=None):
|
def table_modules_ue_coefs(formation_id, semestre_idx=None):
|
||||||
|
@ -121,7 +121,7 @@ def create_dept():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/ScoDoc/toggle_dept_vis/<dept_id>", methods=["GET", "POST"])
|
@bp.route("/ScoDoc/toggle_dept_vis/<int:dept_id>", methods=["GET", "POST"])
|
||||||
@admin_required
|
@admin_required
|
||||||
def toggle_dept_vis(dept_id):
|
def toggle_dept_vis(dept_id):
|
||||||
"""Cache ou rend visible un dept"""
|
"""Cache ou rend visible un dept"""
|
||||||
|
41
migrations/versions/b9aadc10227f_module_type_non_null.py
Normal file
41
migrations/versions/b9aadc10227f_module_type_non_null.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""module_type_non_null
|
||||||
|
|
||||||
|
Revision ID: b9aadc10227f
|
||||||
|
Revises: bd2c1c3d866e
|
||||||
|
Create Date: 2022-02-15 21:47:29.212329
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
from sqlalchemy.orm import sessionmaker # added by ev
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "b9aadc10227f"
|
||||||
|
down_revision = "bd2c1c3d866e"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
Session = sessionmaker()
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# Added by ev: remove duplicates
|
||||||
|
bind = op.get_bind()
|
||||||
|
session = Session(bind=bind)
|
||||||
|
session.execute(
|
||||||
|
"""UPDATE notes_modules SET module_type=0 WHERE module_type IS NULL;"""
|
||||||
|
)
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column(
|
||||||
|
"notes_modules", "module_type", existing_type=sa.INTEGER(), nullable=False
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column(
|
||||||
|
"notes_modules", "module_type", existing_type=sa.INTEGER(), nullable=True
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
@ -19,31 +19,6 @@ depends_on = None
|
|||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
|
||||||
op.add_column("apc_competence", sa.Column("id_orebut", sa.Text(), nullable=True))
|
|
||||||
op.drop_constraint(
|
|
||||||
"apc_competence_referentiel_id_titre_key", "apc_competence", type_="unique"
|
|
||||||
)
|
|
||||||
op.create_index(
|
|
||||||
op.f("ix_apc_competence_id_orebut"),
|
|
||||||
"apc_competence",
|
|
||||||
["id_orebut"],
|
|
||||||
)
|
|
||||||
op.add_column(
|
|
||||||
"apc_referentiel_competences", sa.Column("annexe", sa.Text(), nullable=True)
|
|
||||||
)
|
|
||||||
op.add_column(
|
|
||||||
"apc_referentiel_competences",
|
|
||||||
sa.Column("type_structure", sa.Text(), nullable=True),
|
|
||||||
)
|
|
||||||
op.add_column(
|
|
||||||
"apc_referentiel_competences",
|
|
||||||
sa.Column("type_departement", sa.Text(), nullable=True),
|
|
||||||
)
|
|
||||||
op.add_column(
|
|
||||||
"apc_referentiel_competences",
|
|
||||||
sa.Column("version_orebut", sa.Text(), nullable=True),
|
|
||||||
)
|
|
||||||
|
|
||||||
op.create_index(
|
op.create_index(
|
||||||
op.f("ix_notes_formsemestre_uecoef_formsemestre_id"),
|
op.f("ix_notes_formsemestre_uecoef_formsemestre_id"),
|
||||||
"notes_formsemestre_uecoef",
|
"notes_formsemestre_uecoef",
|
||||||
@ -80,15 +55,10 @@ def downgrade():
|
|||||||
table_name="notes_formsemestre_uecoef",
|
table_name="notes_formsemestre_uecoef",
|
||||||
)
|
)
|
||||||
|
|
||||||
op.drop_column("apc_referentiel_competences", "version_orebut")
|
|
||||||
op.drop_column("apc_referentiel_competences", "type_departement")
|
|
||||||
op.drop_column("apc_referentiel_competences", "type_structure")
|
|
||||||
op.drop_column("apc_referentiel_competences", "annexe")
|
|
||||||
op.drop_index(op.f("ix_apc_competence_id_orebut"), table_name="apc_competence")
|
op.drop_index(op.f("ix_apc_competence_id_orebut"), table_name="apc_competence")
|
||||||
op.create_unique_constraint(
|
op.create_unique_constraint(
|
||||||
"apc_competence_referentiel_id_titre_key",
|
"apc_competence_referentiel_id_titre_key",
|
||||||
"apc_competence",
|
"apc_competence",
|
||||||
["referentiel_id", "titre"],
|
["referentiel_id", "titre"],
|
||||||
)
|
)
|
||||||
op.drop_column("apc_competence", "id_orebut")
|
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.2a-57"
|
SCOVERSION = "9.2a-61"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -93,6 +93,8 @@ fi
|
|||||||
# nginx:
|
# nginx:
|
||||||
mkdir -p "$slash"/etc/nginx/sites-available || die "can't mkdir nginx config"
|
mkdir -p "$slash"/etc/nginx/sites-available || die "can't mkdir nginx config"
|
||||||
cp -p "$SCODOC_DIR"/tools/etc/scodoc9.nginx "$slash"/etc/nginx/sites-available/scodoc9.nginx.distrib || die "can't copy nginx config"
|
cp -p "$SCODOC_DIR"/tools/etc/scodoc9.nginx "$slash"/etc/nginx/sites-available/scodoc9.nginx.distrib || die "can't copy nginx config"
|
||||||
|
mkdir -p "$slash"/etc/nginx/conf.d || die "can't mkdir nginx conf.d"
|
||||||
|
cp -p "$SCODOC_DIR"/tools/etc/scodoc9-nginx-timeout.conf "$slash"/etc/nginx/conf.d/ || die "can't copy nginx timeout config"
|
||||||
|
|
||||||
# systemd
|
# systemd
|
||||||
mkdir -p "$slash"/etc/systemd/system/ || die "can't mkdir systemd config"
|
mkdir -p "$slash"/etc/systemd/system/ || die "can't mkdir systemd config"
|
||||||
|
5
tools/etc/scodoc9-nginx-timeout.conf
Normal file
5
tools/etc/scodoc9-nginx-timeout.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Reglage des timeout du frontal nginx pour ScoDoc 9 (>= 9.1.59)
|
||||||
|
|
||||||
|
proxy_read_timeout 400;
|
||||||
|
proxy_connect_timeout 400;
|
||||||
|
proxy_send_timeout 400;
|
Loading…
Reference in New Issue
Block a user