forked from ScoDoc/ScoDoc
Compare commits
15 Commits
84f43e1b36
...
ba0062135b
Author | SHA1 | Date | |
---|---|---|---|
|
ba0062135b | ||
|
401a43378d | ||
44123c022e | |||
63784e341a | |||
cca72dfed2 | |||
5c951d58e7 | |||
202ce4e73e | |||
c81c4efb40 | |||
d877648546 | |||
58a8bcb83d | |||
fae11d82ce | |||
7a85ec7466 | |||
091a49cb0d | |||
ab212a5b2b | |||
a67515d560 |
@ -53,9 +53,10 @@ from app.models import ApcReferentielCompetences
|
||||
from app.scodoc.sco_abs import annule_absence, annule_justif
|
||||
from app.scodoc.sco_bulletins import formsemestre_bulletinetud_dict
|
||||
from app.scodoc.sco_bulletins_json import make_json_formsemestre_bulletinetud
|
||||
from app.scodoc.sco_evaluation_db import do_evaluation_get_all_notes
|
||||
from app.scodoc.sco_formations import formation_export
|
||||
from app.scodoc.sco_formsemestre_inscriptions import do_formsemestre_inscription_listinscrits
|
||||
from app.scodoc.sco_groups import setGroups, get_etud_groups
|
||||
from app.scodoc.sco_groups import setGroups, get_etud_groups, get_group_members
|
||||
from app.scodoc.sco_moduleimpl import moduleimpl_list
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
|
||||
@ -63,6 +64,7 @@ from app.scodoc.sco_permissions import Permission
|
||||
############################################### Departements ##########################################################
|
||||
from app.scodoc.sco_prepajury import feuille_preparation_jury
|
||||
from app.scodoc.sco_pvjury import formsemestre_pvjury
|
||||
from app.scodoc.sco_recapcomplet import formsemestre_recapcomplet
|
||||
|
||||
|
||||
@bp.route("/departements", methods=["GET"])
|
||||
@ -441,15 +443,29 @@ def bulletins(formsemestre_id: int):
|
||||
"""
|
||||
Les bulletins d'un formsemestre donné
|
||||
"""
|
||||
return error_response(501, message="Not implemented")
|
||||
# fonction to use : formsemestre_recapcomplet
|
||||
|
||||
try:
|
||||
data = formsemestre_recapcomplet(formsemestre_id)
|
||||
except ValueError:
|
||||
return error_response(409, message="La requête ne peut être traitée en l’état actuel")
|
||||
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@bp.route("/formsemestre/<int:formsemestre_id>/jury", methods=["GET"])
|
||||
def jury(formsemestre_id: int):
|
||||
"""
|
||||
|
||||
Le récapitulatif des décisions jury
|
||||
"""
|
||||
return error_response(501, message="Not implemented")
|
||||
# fonction to use : formsemestre_pvjury
|
||||
|
||||
try:
|
||||
data = formsemestre_pvjury(formsemestre_id)
|
||||
except ValueError:
|
||||
return error_response(409, message="La requête ne peut être traitée en l’état actuel")
|
||||
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
############################################### Partitions ############################################################
|
||||
@ -467,15 +483,30 @@ def partition(formsemestre_id: int):
|
||||
return error_response(501, message="Not implemented")
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/partitions/formsemestre/<int:formsemestre_id>/groups/group_ids?with_codes=&all_groups=&etat=",
|
||||
methods=["GET"],
|
||||
)
|
||||
def groups(formsemestre_id: int, group_ids: int):
|
||||
# @bp.route(
|
||||
# "/partitions/formsemestre/<int:formsemestre_id>/groups/group_ids?with_codes=&all_groups=&etat=",
|
||||
# methods=["GET"],
|
||||
# )
|
||||
@bp.route("/partitions/groups/<int:group_id>", methods=["GET"])
|
||||
@bp.route("/partitions/groups/<int:group_id>/etat/<string:etat>", methods=["GET"])
|
||||
def etud_in_group(group_id: int, etat=None):
|
||||
"""
|
||||
Liste des étudiants dans un groupe
|
||||
"""
|
||||
return error_response(501, message="Not implemented")
|
||||
# fonction to use : get_group_members
|
||||
|
||||
if etat is None:
|
||||
try:
|
||||
data = get_group_members(group_id)
|
||||
except ValueError:
|
||||
return error_response(409, message="La requête ne peut être traitée en l’état actuel")
|
||||
else:
|
||||
try:
|
||||
data = get_group_members(group_id, etat)
|
||||
except ValueError:
|
||||
return error_response(409, message="La requête ne peut être traitée en l’état actuel")
|
||||
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@bp.route(
|
||||
@ -516,12 +547,13 @@ def evaluation_notes(evaluation_id: int):
|
||||
"""
|
||||
Liste des notes à partir de l'id d'une évaluation donnée
|
||||
"""
|
||||
notes = models.NotesNotes.query.filter_by(evaluation_id=evaluation_id).all()
|
||||
|
||||
data = [d.to_dict() for d in notes]
|
||||
# fonction to use : do_evaluation_get_all_notes
|
||||
try:
|
||||
data = do_evaluation_get_all_notes(evaluation_id)
|
||||
except ValueError:
|
||||
return error_response(409, message="La requête ne peut être traitée en l’état actuel")
|
||||
|
||||
return jsonify(data)
|
||||
# return error_response(501, message="Not implemented")
|
||||
|
||||
|
||||
@bp.route(
|
||||
@ -705,7 +737,7 @@ def abs_groupe_etat(
|
||||
Liste des absences d'un ou plusieurs groupes entre deux dates
|
||||
"""
|
||||
|
||||
# list_abs_date
|
||||
# list_abs_date<
|
||||
return error_response(501, message="Not implemented")
|
||||
|
||||
|
||||
|
@ -205,7 +205,8 @@ class BonusSportAdditif(BonusSport):
|
||||
"""calcul du bonus
|
||||
sem_modimpl_moys_inscrits: les notes de sport
|
||||
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:
|
||||
# pas d'étudiants ou pas d'UE ou pas de module...
|
||||
@ -228,12 +229,22 @@ class BonusSportAdditif(BonusSport):
|
||||
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)
|
||||
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
|
||||
ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)]
|
||||
self.bonus_ues = pd.DataFrame(
|
||||
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:
|
||||
# Bonus sur la moyenne générale seulement
|
||||
self.bonus_moy_gen = pd.Series(
|
||||
@ -284,6 +295,7 @@ class BonusSportMultiplicatif(BonusSport):
|
||||
|
||||
class BonusDirect(BonusSportAdditif):
|
||||
"""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.
|
||||
(rappel: la note est ramenée sur 20 avant application).
|
||||
"""
|
||||
@ -294,47 +306,64 @@ class BonusDirect(BonusSportAdditif):
|
||||
proportion_point = 1.0
|
||||
|
||||
|
||||
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 :
|
||||
0.05 point si >=10,
|
||||
0.1 point si >=12,
|
||||
0.15 point si >=14,
|
||||
0.2 point si >=16,
|
||||
0.25 point si >=18.
|
||||
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_iut_annecy"
|
||||
displayed_name = "IUT d'Annecy"
|
||||
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
|
||||
|
||||
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 >= 18.0] = 0.25
|
||||
bonus[note_bonus_max >= 16.0] = 0.20
|
||||
bonus[note_bonus_max >= 14.0] = 0.15
|
||||
bonus[note_bonus_max >= 12.0] = 0.10
|
||||
bonus[note_bonus_max >= 10.0] = 0.05
|
||||
|
||||
# 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,
|
||||
)
|
||||
# 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):
|
||||
@ -375,15 +404,16 @@ class BonusBezier(BonusSportAdditif):
|
||||
class BonusBordeaux1(BonusSportMultiplicatif):
|
||||
"""Calcul bonus modules optionnels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale
|
||||
et UE.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
</p><p>
|
||||
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.
|
||||
Formule : le % = points>moyenne / 2
|
||||
qui augmente la moyenne de chaque UE et la moyenne générale.<br>
|
||||
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.
|
||||
|
||||
</p>
|
||||
"""
|
||||
|
||||
name = "bonus_iutBordeaux1"
|
||||
@ -393,6 +423,68 @@ class BonusBordeaux1(BonusSportMultiplicatif):
|
||||
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):
|
||||
"""Calcul bonus modules optionnels (sport, culture), règle IUT Colmar.
|
||||
|
||||
@ -417,19 +509,21 @@ class BonusColmar(BonusSportAdditif):
|
||||
class BonusGrenobleIUT1(BonusSportMultiplicatif):
|
||||
"""Bonus IUT1 de Grenoble
|
||||
|
||||
<p>
|
||||
À compter de sept. 2021:
|
||||
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
|
||||
la formule : bonification (en %) = (note-10)*0,5.
|
||||
|
||||
Bonification qui ne s'applique que si la note est >10.
|
||||
|
||||
(Une note de 10 donne donc 0% de bonif ; note de 20 : 5% de bonif)
|
||||
|
||||
</p><p>
|
||||
<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, et une note de 20 : 5% de bonif)
|
||||
</p><p>
|
||||
Avant sept. 2021, la note de sport allait de 0 à 5 points (sur 20).
|
||||
Chaque point correspondait à 0.25% d'augmentation de la moyenne
|
||||
générale.
|
||||
Par exemple : note de sport 2/5 : la moyenne générale était augmentée de 0.5%.
|
||||
</p>
|
||||
"""
|
||||
|
||||
name = "bonus_iut1grenoble_2017"
|
||||
@ -456,9 +550,11 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif):
|
||||
class BonusLaRochelle(BonusSportAdditif):
|
||||
"""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.
|
||||
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).
|
||||
<ul>
|
||||
<li>Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point.</li>
|
||||
<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"
|
||||
@ -483,16 +579,17 @@ class BonusLeHavre(BonusSportMultiplicatif):
|
||||
class BonusLeMans(BonusSportAdditif):
|
||||
"""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.
|
||||
</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>
|
||||
|
||||
|
||||
En BUT: la moyenne de chacune des UE du semestre est augmentée de
|
||||
2% du cumul des points de bonus,
|
||||
|
||||
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.
|
||||
<li>En DUT/LP: la moyenne générale est augmentée de 5% du cumul des points bonus.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Dans tous les cas, le bonus est dans la limite de 0,5 point.</p>
|
||||
"""
|
||||
|
||||
name = "bonus_iutlemans"
|
||||
@ -516,12 +613,13 @@ class BonusLeMans(BonusSportAdditif):
|
||||
class BonusLille(BonusSportAdditif):
|
||||
"""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.
|
||||
|
||||
</p><p>
|
||||
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
|
||||
s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||
</p>
|
||||
"""
|
||||
|
||||
name = "bonus_lille"
|
||||
@ -573,17 +671,19 @@ class BonusMulhouse(BonusSportAdditif):
|
||||
class BonusNantes(BonusSportAdditif):
|
||||
"""IUT de Nantes (Septembre 2018)
|
||||
|
||||
Nous avons différents types de bonification
|
||||
<p>Nous avons différents types de bonification
|
||||
(sport, culture, engagement citoyen).
|
||||
|
||||
</p><p>
|
||||
Nous ajoutons aux moyennes une bonification de 0,2 pour chaque item
|
||||
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.
|
||||
|
||||
Dans ScoDoc: on a déclarera une UE "sport&culture" dans laquelle on aura 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
|
||||
valeur de la bonification: entrer 0,1/20 signifiera un bonus de 0,1 point la moyenne générale)
|
||||
</p><p>
|
||||
Dans ScoDoc: on a déclarera une UE "sport&culture" dans laquelle on aura
|
||||
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 valeur de la bonification: entrer 0,1/20 signifiera
|
||||
un bonus de 0,1 point la moyenne générale).
|
||||
</p>
|
||||
"""
|
||||
|
||||
name = "bonus_nantes"
|
||||
@ -604,7 +704,7 @@ class BonusRoanne(BonusSportAdditif):
|
||||
displayed_name = "IUT de Roanne"
|
||||
seuil_moy_gen = 0.0
|
||||
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):
|
||||
@ -627,13 +727,14 @@ class BonusStDenis(BonusSportAdditif):
|
||||
class BonusTours(BonusDirect):
|
||||
"""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,
|
||||
soit pour le BUT à chaque moyenne d'UE.
|
||||
|
||||
Attention: en GEII, facteur 1/40, ailleurs facteur 1.
|
||||
|
||||
</p><p>
|
||||
<em>Attention: en GEII, facteur 1/40, ailleurs facteur 1.</em>
|
||||
</p><p>
|
||||
Le bonus total est limité à 1 point.
|
||||
</p>
|
||||
"""
|
||||
|
||||
name = "bonus_tours"
|
||||
@ -658,11 +759,13 @@ class BonusVilleAvray(BonusSport):
|
||||
|
||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||
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
|
||||
Si la note est >= 12 et < 16, bonus de 0.2 point
|
||||
Si la note est >= 16, bonus de 0.3 point
|
||||
Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par
|
||||
l'étudiant.
|
||||
<ul>
|
||||
<li>Si la note est >= 10 et < 12, bonus de 0.1 point</li>
|
||||
<li>Si la note est >= 12 et < 16, bonus de 0.2 point</li>
|
||||
<li>Si la note est >= 16, bonus de 0.3 point</li>
|
||||
</ul>
|
||||
<p>Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par
|
||||
l'étudiant.</p>
|
||||
"""
|
||||
|
||||
name = "bonus_iutva"
|
||||
@ -700,7 +803,7 @@ class BonusIUTV(BonusSportAdditif):
|
||||
|
||||
name = "bonus_iutv"
|
||||
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):
|
||||
|
@ -335,15 +335,17 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
||||
notes_rat / (eval_rat.note_max / 20.0),
|
||||
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
|
||||
etuds_use_rattrapage = notes_rat > etuds_moy_module
|
||||
etuds_use_rattrapage = notes_rat_ues > etuds_moy_module
|
||||
etuds_moy_module = np.where(
|
||||
etuds_use_rattrapage[:, np.newaxis],
|
||||
np.tile(notes_rat[:, np.newaxis], nb_ues),
|
||||
etuds_moy_module,
|
||||
etuds_use_rattrapage, notes_rat_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(
|
||||
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(
|
||||
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
|
||||
remplies: 1 si le coef de ce module dans l'UE est non nul, zéro sinon
|
||||
(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)
|
||||
"""
|
||||
modimpl: ModuleImpl = ModuleImpl.query.get(moduleimpl_id)
|
||||
@ -367,6 +373,10 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]:
|
||||
ue_ids = [ue.id for ue in ues]
|
||||
evaluation_ids = [evaluation.id for evaluation in evaluations]
|
||||
evals_poids = pd.DataFrame(columns=ue_ids, index=evaluation_ids, dtype=float)
|
||||
if (
|
||||
modimpl.module.module_type == ModuleType.RESSOURCE
|
||||
or modimpl.module.module_type == ModuleType.SAE
|
||||
):
|
||||
for ue_poids in EvaluationUEPoids.query.join(
|
||||
EvaluationUEPoids.evaluation
|
||||
).filter_by(moduleimpl_id=moduleimpl_id):
|
||||
|
@ -55,6 +55,9 @@ def create_dept(acronym: str, visible=True) -> Departement:
|
||||
"Create new departement"
|
||||
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)
|
||||
p1 = ScoPreference(name="DeptName", value=acronym, departement=departement)
|
||||
db.session.add(p1)
|
||||
|
@ -500,6 +500,13 @@ def module_edit(module_id=None):
|
||||
matieres = matieres.filter(UniteEns.semestre_idx == a_module.ue.semestre_idx)
|
||||
|
||||
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 = [
|
||||
"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)
|
||||
ues.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)
|
||||
# editable = (not locked) and has_perm_change
|
||||
@ -664,11 +669,17 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
||||
if msg:
|
||||
H.append('<p class="msg">' + msg + "</p>")
|
||||
|
||||
if has_duplicate_ue_codes:
|
||||
if ues_with_duplicated_code:
|
||||
H.append(
|
||||
"""<div class="ue_warning"><span>Attention: plusieurs UE de cette
|
||||
formation ont le même code. Il faut corriger cela ci-dessous,
|
||||
sinon les calculs d'ECTS seront erronés !</span></div>"""
|
||||
f"""<div class="ue_warning"><span>Attention: plusieurs UE de cette
|
||||
formation ont le même code : <tt>{
|
||||
', '.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
|
||||
@ -930,8 +941,8 @@ def _ue_table_ues(
|
||||
|
||||
if cur_ue_semestre_id != ue["semestre_id"]:
|
||||
cur_ue_semestre_id = ue["semestre_id"]
|
||||
if iue > 0:
|
||||
H.append("</ul>")
|
||||
# if iue > 0:
|
||||
# H.append("</ul>")
|
||||
if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT:
|
||||
lab = "Pas d'indication de semestre:"
|
||||
else:
|
||||
@ -953,7 +964,6 @@ def _ue_table_ues(
|
||||
)
|
||||
else:
|
||||
H.append(arrow_none)
|
||||
iue += 1
|
||||
ue["acro_titre"] = str(ue["acronyme"])
|
||||
if ue["titre"] != ue["acronyme"]:
|
||||
ue["acro_titre"] += " " + str(ue["titre"])
|
||||
@ -1001,6 +1011,14 @@ def _ue_table_ues(
|
||||
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)
|
||||
|
||||
|
||||
|
@ -53,7 +53,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def apo_semset_maq_status(
|
||||
semset_id="",
|
||||
semset_id: int,
|
||||
allow_missing_apo=False,
|
||||
allow_missing_decisions=False,
|
||||
allow_missing_csv=False,
|
||||
@ -65,7 +65,7 @@ def apo_semset_maq_status(
|
||||
):
|
||||
"""Page statut / tableau de bord"""
|
||||
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.fill_formsemestres()
|
||||
# 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"""
|
||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
sem = formsemestre.to_dict()
|
||||
|
||||
evals = nt.get_evaluations_etats()
|
||||
nb_evals = len(evals)
|
||||
@ -416,8 +415,8 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
||||
|
||||
today = time.strftime("%Y-%m-%d")
|
||||
|
||||
year = int(sem["annee_debut"])
|
||||
if sem["mois_debut_ord"] < 8:
|
||||
year = formsemestre.date_debut.year
|
||||
if formsemestre.date_debut.month < 8:
|
||||
year -= 1 # calendrier septembre a septembre
|
||||
events = {} # (day, halfday) : event
|
||||
for e in evals:
|
||||
@ -537,11 +536,10 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
||||
"""Experimental: un tableau indiquant pour chaque évaluation
|
||||
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)
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
sem = formsemestre.to_dict()
|
||||
|
||||
evals = nt.get_evaluations_etats()
|
||||
T = []
|
||||
@ -607,7 +605,7 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
||||
origin="Généré par %s le " % sco_version.SCONAME
|
||||
+ 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)
|
||||
|
||||
@ -635,9 +633,7 @@ 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>'
|
||||
% moduleimpl_id
|
||||
)
|
||||
mod_descr = (
|
||||
'<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s'
|
||||
% (
|
||||
mod_descr = '<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 "",
|
||||
Mod["titre"] or "?",
|
||||
@ -645,7 +641,6 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
||||
resp,
|
||||
link,
|
||||
)
|
||||
)
|
||||
|
||||
etit = E["description"] or ""
|
||||
if etit:
|
||||
|
@ -1286,7 +1286,11 @@ def check_formation_ues(formation_id):
|
||||
for x in ue_multiples[ue["ue_id"]]
|
||||
]
|
||||
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("</ul></div>")
|
||||
|
@ -305,7 +305,10 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
||||
if can_change:
|
||||
c_link = (
|
||||
'<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:
|
||||
c_link = mod["descri"]
|
||||
|
@ -1707,6 +1707,9 @@ ul.notes_ue_list {
|
||||
li.notes_ue_list {
|
||||
margin-top: 9px;
|
||||
list-style-type: none;
|
||||
border: 1px solid maroon;
|
||||
border-radius: 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
span.ue_type_1 {
|
||||
color: green;
|
||||
@ -1749,6 +1752,7 @@ ul.notes_matiere_list {
|
||||
background-color: rgb(220,220,220);
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
border-top: 1px solid maroon;
|
||||
}
|
||||
|
||||
ul.notes_module_list {
|
||||
|
@ -18,10 +18,12 @@
|
||||
<a href="{{ url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept, ) }}">
|
||||
Liste des référentiels de compétences chargés</a>
|
||||
</li>
|
||||
{% if formation is not none %}
|
||||
<li>
|
||||
<a href="{{ url_for('notes.refcomp_assoc_formation', scodoc_dept=g.scodoc_dept, formation_id=formation.id) }}">
|
||||
Association à la formation {{ formation.acronyme }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -65,6 +65,13 @@
|
||||
{% endfor %}
|
||||
</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}}"
|
||||
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>
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.1.58"
|
||||
SCOVERSION = "9.1.61"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
@ -93,6 +93,8 @@ fi
|
||||
# nginx:
|
||||
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"
|
||||
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
|
||||
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