forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -36,7 +36,6 @@ from app.models import Scolog, ScolarAutorisationInscription
|
|||||||
from app.models.but_validations import (
|
from app.models.but_validations import (
|
||||||
ApcValidationAnnee,
|
ApcValidationAnnee,
|
||||||
ApcValidationRCUE,
|
ApcValidationRCUE,
|
||||||
RegroupementCoherentUE,
|
|
||||||
)
|
)
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -153,7 +153,7 @@ def pvjury_table_but(
|
|||||||
etudid=etud.id,
|
etudid=etud.id,
|
||||||
),
|
),
|
||||||
"cursus": _descr_cursus_but(etud),
|
"cursus": _descr_cursus_but(etud),
|
||||||
"ects": f"{deca.formsemestre_ects():g}",
|
"ects": f"{deca.ects_annee():g}",
|
||||||
"ues": deca.descr_ues_validation(line_sep=line_sep) if deca else "-",
|
"ues": deca.descr_ues_validation(line_sep=line_sep) if deca else "-",
|
||||||
"niveaux": deca.descr_niveaux_validation(line_sep=line_sep)
|
"niveaux": deca.descr_niveaux_validation(line_sep=line_sep)
|
||||||
if deca
|
if deca
|
||||||
|
@ -48,9 +48,9 @@ def _get_jury_but_etud_result(
|
|||||||
# --- Les RCUEs
|
# --- Les RCUEs
|
||||||
rcue_list = []
|
rcue_list = []
|
||||||
if deca:
|
if deca:
|
||||||
for rcue in deca.rcues_annee:
|
for dec_rcue in deca.get_decisions_rcues_annee():
|
||||||
dec_rcue = deca.dec_rcue_by_ue.get(rcue.ue_1.id)
|
rcue = dec_rcue.rcue
|
||||||
if dec_rcue is not None: # None si l'UE n'est pas associée à un niveau
|
if rcue.complete: # n'exporte que les RCUEs complets
|
||||||
dec_ue1 = deca.decisions_ues[rcue.ue_1.id]
|
dec_ue1 = deca.decisions_ues[rcue.ue_1.id]
|
||||||
dec_ue2 = deca.decisions_ues[rcue.ue_2.id]
|
dec_ue2 = deca.decisions_ues[rcue.ue_2.id]
|
||||||
rcue_dict = {
|
rcue_dict = {
|
||||||
|
@ -93,35 +93,25 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
|||||||
<div class="titre">RCUE</div>
|
<div class="titre">RCUE</div>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
for niveau in deca.niveaux_competences:
|
for dec_rcue in deca.get_decisions_rcues_annee():
|
||||||
|
rcue = dec_rcue.rcue
|
||||||
|
niveau = rcue.niveau
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div class="but_niveau_titre">
|
f"""<div class="but_niveau_titre">
|
||||||
<div title="{niveau.competence.titre_long}">{niveau.competence.titre}</div>
|
<div title="{niveau.competence.titre_long}">{niveau.competence.titre}</div>
|
||||||
</div>"""
|
</div>"""
|
||||||
)
|
)
|
||||||
dec_rcue = deca.decisions_rcue_by_niveau.get(niveau.id) # peut être None
|
ue_impair, ue_pair = rcue.ue_1, rcue.ue_2
|
||||||
ues = [
|
|
||||||
ue
|
|
||||||
for ue in deca.ues_impair
|
|
||||||
if ue.niveau_competence and ue.niveau_competence.id == niveau.id
|
|
||||||
]
|
|
||||||
ue_impair = ues[0] if ues else None
|
|
||||||
ues = [
|
|
||||||
ue
|
|
||||||
for ue in deca.ues_pair
|
|
||||||
if ue.niveau_competence and ue.niveau_competence.id == niveau.id
|
|
||||||
]
|
|
||||||
ue_pair = ues[0] if ues else None
|
|
||||||
# Les UEs à afficher,
|
# Les UEs à afficher,
|
||||||
# qui seront toujours en readonly sur le formsemestre de l'année précédente du redoublant
|
# qui
|
||||||
ues_ro = [
|
ues_ro = [
|
||||||
(
|
(
|
||||||
ue_impair,
|
ue_impair,
|
||||||
(deca.a_cheval and deca.formsemestre_id != deca.formsemestre_impair.id),
|
rcue.ue_cur_impair is None,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
ue_pair,
|
ue_pair,
|
||||||
deca.a_cheval and deca.formsemestre_id != deca.formsemestre_pair.id,
|
rcue.ue_cur_pair is None,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
# Ordonne selon les dates des 2 semestres considérés:
|
# Ordonne selon les dates des 2 semestres considérés:
|
||||||
@ -155,12 +145,13 @@ def _gen_but_select(
|
|||||||
code_valide: str,
|
code_valide: str,
|
||||||
disabled: bool = False,
|
disabled: bool = False,
|
||||||
klass: str = "",
|
klass: str = "",
|
||||||
data: dict = {},
|
data: dict = None,
|
||||||
code_valide_label: str = "",
|
code_valide_label: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
"Le menu html select avec les codes"
|
"Le menu html select avec les codes"
|
||||||
# if disabled: # mauvaise idée car le disabled est traité en JS
|
# if disabled: # mauvaise idée car le disabled est traité en JS
|
||||||
# return f"""<div class="but_code {klass}">{code_valide}</div>"""
|
# return f"""<div class="but_code {klass}">{code_valide}</div>"""
|
||||||
|
data = data or {}
|
||||||
options_htm = "\n".join(
|
options_htm = "\n".join(
|
||||||
[
|
[
|
||||||
f"""<option value="{code}"
|
f"""<option value="{code}"
|
||||||
@ -220,8 +211,14 @@ def _gen_but_niveau_ue(
|
|||||||
else:
|
else:
|
||||||
scoplement = ""
|
scoplement = ""
|
||||||
|
|
||||||
return f"""<div class="but_niveau_ue {
|
ue_class = "" # 'recorded' if dec_ue.code_valide is not None else ''
|
||||||
'recorded' if dec_ue.code_valide is not None else ''}
|
if dec_ue.code_valide is not None and dec_ue.codes:
|
||||||
|
if dec_ue.code_valide == dec_ue.codes[0]:
|
||||||
|
ue_class = "recorded"
|
||||||
|
else:
|
||||||
|
ue_class = "recorded_different"
|
||||||
|
|
||||||
|
return f"""<div class="but_niveau_ue {ue_class}
|
||||||
{'annee_prec' if annee_prec else ''}
|
{'annee_prec' if annee_prec else ''}
|
||||||
">
|
">
|
||||||
<div title="{ue.titre}">{ue.acronyme}</div>
|
<div title="{ue.titre}">{ue.acronyme}</div>
|
||||||
@ -242,7 +239,7 @@ def _gen_but_niveau_ue(
|
|||||||
|
|
||||||
|
|
||||||
def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
|
def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
|
||||||
if dec_rcue is None:
|
if dec_rcue is None or not dec_rcue.rcue.complete:
|
||||||
return """
|
return """
|
||||||
<div class="but_niveau_rcue niveau_vide with_scoplement">
|
<div class="but_niveau_rcue niveau_vide with_scoplement">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
"""
|
"""
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from flask_sqlalchemy.query import Query
|
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import CODE_STR_LEN
|
from app.models import CODE_STR_LEN
|
||||||
@ -13,8 +12,6 @@ from app.models.etudiants import Identite
|
|||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.scodoc import codes_cursus as sco_codes
|
|
||||||
from app.scodoc import sco_utils as scu
|
|
||||||
|
|
||||||
|
|
||||||
class ApcValidationRCUE(db.Model):
|
class ApcValidationRCUE(db.Model):
|
||||||
@ -22,7 +19,7 @@ class ApcValidationRCUE(db.Model):
|
|||||||
|
|
||||||
aka "regroupements cohérents d'UE" dans le jargon BUT.
|
aka "regroupements cohérents d'UE" dans le jargon BUT.
|
||||||
|
|
||||||
Le formsemestre est celui du semestre PAIR du niveau de compétence
|
Le formsemestre est l'origine, utilisé pour effacer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__tablename__ = "apc_validation_rcue"
|
__tablename__ = "apc_validation_rcue"
|
||||||
@ -109,139 +106,6 @@ class ApcValidationRCUE(db.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Attention: ce n'est pas un modèle mais une classe ordinaire:
|
|
||||||
class RegroupementCoherentUE:
|
|
||||||
"""Le regroupement cohérent d'UE, dans la terminologie du BUT, est le couple d'UEs
|
|
||||||
de la même année (BUT1,2,3) liées au *même niveau de compétence*.
|
|
||||||
|
|
||||||
La moyenne (10/20) au RCUE déclenche la compensation des UE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
etud: Identite,
|
|
||||||
formsemestre_1: FormSemestre,
|
|
||||||
dec_ue_1: "DecisionsProposeesUE",
|
|
||||||
formsemestre_2: FormSemestre,
|
|
||||||
dec_ue_2: "DecisionsProposeesUE",
|
|
||||||
inscription_etat: str,
|
|
||||||
):
|
|
||||||
ue_1 = dec_ue_1.ue
|
|
||||||
ue_2 = dec_ue_2.ue
|
|
||||||
# Ordonne les UE dans le sens croissant (S1,S2) ou (S3,S4)...
|
|
||||||
if formsemestre_1.semestre_id > formsemestre_2.semestre_id:
|
|
||||||
(ue_1, formsemestre_1), (ue_2, formsemestre_2) = (
|
|
||||||
(ue_2, formsemestre_2),
|
|
||||||
(ue_1, formsemestre_1),
|
|
||||||
)
|
|
||||||
assert formsemestre_1.semestre_id % 2 == 1
|
|
||||||
assert formsemestre_2.semestre_id % 2 == 0
|
|
||||||
assert abs(formsemestre_1.semestre_id - formsemestre_2.semestre_id) == 1
|
|
||||||
assert ue_1.niveau_competence_id == ue_2.niveau_competence_id
|
|
||||||
self.etud = etud
|
|
||||||
self.formsemestre_1 = formsemestre_1
|
|
||||||
"semestre impair"
|
|
||||||
self.ue_1 = ue_1
|
|
||||||
self.formsemestre_2 = formsemestre_2
|
|
||||||
"semestre pair"
|
|
||||||
self.ue_2 = ue_2
|
|
||||||
# Stocke les moyennes d'UE
|
|
||||||
if inscription_etat != scu.INSCRIT:
|
|
||||||
self.moy_rcue = None
|
|
||||||
self.moy_ue_1 = self.moy_ue_2 = "-"
|
|
||||||
self.moy_ue_1_val = self.moy_ue_2_val = 0.0
|
|
||||||
return
|
|
||||||
self.moy_ue_1 = dec_ue_1.moy_ue_with_cap
|
|
||||||
self.moy_ue_1_val = self.moy_ue_1 if self.moy_ue_1 is not None else 0.0
|
|
||||||
self.moy_ue_2 = dec_ue_2.moy_ue_with_cap
|
|
||||||
self.moy_ue_2_val = self.moy_ue_2 if self.moy_ue_2 is not None else 0.0
|
|
||||||
|
|
||||||
# Calcul de la moyenne au RCUE (utilise les moy d'UE capitalisées)
|
|
||||||
if (self.moy_ue_1 is not None) and (self.moy_ue_2 is not None):
|
|
||||||
# Moyenne RCUE (les pondérations par défaut sont 1.)
|
|
||||||
self.moy_rcue = (
|
|
||||||
self.moy_ue_1 * ue_1.coef_rcue + self.moy_ue_2 * ue_2.coef_rcue
|
|
||||||
) / (ue_1.coef_rcue + ue_2.coef_rcue)
|
|
||||||
else:
|
|
||||||
self.moy_rcue = None
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"""<{self.__class__.__name__} {
|
|
||||||
self.ue_1.acronyme}({self.moy_ue_1}) {
|
|
||||||
self.ue_2.acronyme}({self.moy_ue_2})>"""
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f"""RCUE {
|
|
||||||
self.ue_1.acronyme}({self.moy_ue_1}) + {
|
|
||||||
self.ue_2.acronyme}({self.moy_ue_2})"""
|
|
||||||
|
|
||||||
def query_validations(
|
|
||||||
self,
|
|
||||||
) -> Query: # list[ApcValidationRCUE]
|
|
||||||
"""Les validations de jury enregistrées pour ce RCUE"""
|
|
||||||
niveau = self.ue_2.niveau_competence
|
|
||||||
|
|
||||||
return (
|
|
||||||
ApcValidationRCUE.query.filter_by(
|
|
||||||
etudid=self.etud.id,
|
|
||||||
)
|
|
||||||
.join(UniteEns, UniteEns.id == ApcValidationRCUE.ue2_id)
|
|
||||||
.join(ApcNiveau, UniteEns.niveau_competence_id == ApcNiveau.id)
|
|
||||||
.filter(ApcNiveau.id == niveau.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
def other_ue(self, ue: UniteEns) -> UniteEns:
|
|
||||||
"""L'autre UE du regroupement. Si ue ne fait pas partie du regroupement, ValueError"""
|
|
||||||
if ue.id == self.ue_1.id:
|
|
||||||
return self.ue_2
|
|
||||||
elif ue.id == self.ue_2.id:
|
|
||||||
return self.ue_1
|
|
||||||
raise ValueError(f"ue {ue} hors RCUE {self}")
|
|
||||||
|
|
||||||
def est_enregistre(self) -> bool:
|
|
||||||
"""Vrai si ce RCUE, donc le niveau de compétences correspondant
|
|
||||||
a une décision jury enregistrée
|
|
||||||
"""
|
|
||||||
return self.query_validations().count() > 0
|
|
||||||
|
|
||||||
def est_compensable(self):
|
|
||||||
"""Vrai si ce RCUE est validable (uniquement) par compensation
|
|
||||||
c'est à dire que sa moyenne est > 10 avec une UE < 10.
|
|
||||||
Note: si ADM, est_compensable est faux.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
(self.moy_rcue is not None)
|
|
||||||
and (self.moy_rcue > sco_codes.BUT_BARRE_RCUE)
|
|
||||||
and (
|
|
||||||
(self.moy_ue_1_val < sco_codes.NOTES_BARRE_GEN)
|
|
||||||
or (self.moy_ue_2_val < sco_codes.NOTES_BARRE_GEN)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def est_suffisant(self) -> bool:
|
|
||||||
"""Vrai si ce RCUE est > 8"""
|
|
||||||
return (self.moy_rcue is not None) and (
|
|
||||||
self.moy_rcue > sco_codes.BUT_RCUE_SUFFISANT
|
|
||||||
)
|
|
||||||
|
|
||||||
def est_validable(self) -> bool:
|
|
||||||
"""Vrai si ce RCUE satisfait les conditions pour être validé,
|
|
||||||
c'est à dire que la moyenne des UE qui le constituent soit > 10
|
|
||||||
"""
|
|
||||||
return (self.moy_rcue is not None) and (
|
|
||||||
self.moy_rcue > sco_codes.BUT_BARRE_RCUE
|
|
||||||
)
|
|
||||||
|
|
||||||
def code_valide(self) -> Union[ApcValidationRCUE, None]:
|
|
||||||
"Si ce RCUE est ADM, CMP ou ADJ, la validation. Sinon, None"
|
|
||||||
validation = self.query_validations().first()
|
|
||||||
if (validation is not None) and (
|
|
||||||
validation.code in sco_codes.CODES_RCUE_VALIDES
|
|
||||||
):
|
|
||||||
return validation
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# unused
|
# unused
|
||||||
# def find_rcues(
|
# def find_rcues(
|
||||||
# formsemestre: FormSemestre, ue: UniteEns, etud: Identite, inscription_etat: str
|
# formsemestre: FormSemestre, ue: UniteEns, etud: Identite, inscription_etat: str
|
||||||
@ -319,7 +183,7 @@ class ApcValidationAnnee(db.Model):
|
|||||||
formsemestre_id = db.Column(
|
formsemestre_id = db.Column(
|
||||||
db.Integer, db.ForeignKey("notes_formsemestre.id"), nullable=True
|
db.Integer, db.ForeignKey("notes_formsemestre.id"), nullable=True
|
||||||
)
|
)
|
||||||
"le semestre IMPAIR (le 1er) de l'année"
|
"le semestre origine, normalement l'IMPAIR (le 1er) de l'année"
|
||||||
formation_id = db.Column(
|
formation_id = db.Column(
|
||||||
db.Integer,
|
db.Integer,
|
||||||
db.ForeignKey("notes_formations.id"),
|
db.ForeignKey("notes_formations.id"),
|
||||||
|
@ -265,11 +265,8 @@ class ScolarNews(db.Model):
|
|||||||
|
|
||||||
# Informations générales
|
# Informations générales
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div>
|
f"""<div><a class="discretelink" href="{scu.SCO_ANNONCES_WEBSITE}">
|
||||||
Pour être informé des évolutions de ScoDoc,
|
Pour en savoir plus sur ScoDoc voir le site scodoc.org</a>.
|
||||||
vous pouvez vous
|
|
||||||
<a class="stdlink" href="{scu.SCO_ANNONCES_WEBSITE}">
|
|
||||||
abonner à la liste de diffusion</a>.
|
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -68,7 +68,7 @@ class ScolarFormSemestreValidation(db.Model):
|
|||||||
if self.ue_id:
|
if self.ue_id:
|
||||||
# Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
|
# Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
|
||||||
return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
|
return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
|
||||||
}: {self.code}"""
|
} ({self.ue_id}): {self.code}"""
|
||||||
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
|
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
|
||||||
self.event_date.strftime("%d/%m/%Y")}"""
|
self.event_date.strftime("%d/%m/%Y")}"""
|
||||||
|
|
||||||
|
@ -793,7 +793,13 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
|
|||||||
{tf[1]}
|
{tf[1]}
|
||||||
"""
|
"""
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return "<h4>annulation</h4>"
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"notes.formsemestre_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if tf[2]["gestion_compensation_lst"]:
|
if tf[2]["gestion_compensation_lst"]:
|
||||||
tf[2]["gestion_compensation"] = True
|
tf[2]["gestion_compensation"] = True
|
||||||
|
@ -349,7 +349,7 @@ SCO_DEFAULT_SQL_USERS_CNX = "dbname=SCOUSERS port=%s" % SCO_DEFAULT_SQL_PORT
|
|||||||
# Valeurs utilisées pour affichage seulement, pas de requetes ni de mails envoyés:
|
# Valeurs utilisées pour affichage seulement, pas de requetes ni de mails envoyés:
|
||||||
SCO_WEBSITE = "https://scodoc.org"
|
SCO_WEBSITE = "https://scodoc.org"
|
||||||
SCO_USER_MANUAL = "https://scodoc.org/GuideUtilisateur"
|
SCO_USER_MANUAL = "https://scodoc.org/GuideUtilisateur"
|
||||||
SCO_ANNONCES_WEBSITE = "https://listes.univ-paris13.fr/mailman/listinfo/scodoc-annonces"
|
SCO_ANNONCES_WEBSITE = "https://scodoc.org/Contact"
|
||||||
SCO_DEVEL_LIST = "scodoc-devel@listes.univ-paris13.fr"
|
SCO_DEVEL_LIST = "scodoc-devel@listes.univ-paris13.fr"
|
||||||
SCO_USERS_LIST = "notes@listes.univ-paris13.fr"
|
SCO_USERS_LIST = "notes@listes.univ-paris13.fr"
|
||||||
SCO_LISTS_URL = "https://scodoc.org/Contact"
|
SCO_LISTS_URL = "https://scodoc.org/Contact"
|
||||||
|
@ -1,64 +1,76 @@
|
|||||||
// JS for all ScoDoc pages (using jQuery UI)
|
// JS for all ScoDoc pages (using jQuery UI)
|
||||||
|
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
// Autocomplete recherche etudiants par nom
|
// Autocomplete recherche etudiants par nom
|
||||||
$(".in-expnom").autocomplete(
|
$(".in-expnom").autocomplete({
|
||||||
{
|
|
||||||
delay: 300, // wait 300ms before suggestions
|
delay: 300, // wait 300ms before suggestions
|
||||||
minLength: 2, // min nb of chars before suggest
|
minLength: 2, // min nb of chars before suggest
|
||||||
position: { collision: 'flip' }, // automatic menu position up/down
|
position: { collision: "flip" }, // automatic menu position up/down
|
||||||
source: SCO_URL + "/search_etud_by_name",
|
source: SCO_URL + "/search_etud_by_name",
|
||||||
select: function (event, ui) {
|
select: function (event, ui) {
|
||||||
$(".in-expnom").val(ui.item.value);
|
$(".in-expnom").val(ui.item.value);
|
||||||
$("#form-chercheetud").submit();
|
$("#form-chercheetud").submit();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Date picker
|
// Date picker
|
||||||
$(".datepicker").datepicker({
|
$(".datepicker").datepicker({
|
||||||
showOn: 'button',
|
showOn: "button",
|
||||||
buttonImage: '/ScoDoc/static/icons/calendar_img.png',
|
buttonImage: "/ScoDoc/static/icons/calendar_img.png",
|
||||||
buttonImageOnly: true,
|
buttonImageOnly: true,
|
||||||
dateFormat: 'dd/mm/yy',
|
dateFormat: "dd/mm/yy",
|
||||||
duration: 'fast',
|
duration: "fast",
|
||||||
});
|
});
|
||||||
$('.datepicker').datepicker('option', $.extend({ showMonthAfterYear: false },
|
$(".datepicker").datepicker(
|
||||||
$.datepicker.regional['fr']));
|
"option",
|
||||||
|
$.extend({ showMonthAfterYear: false }, $.datepicker.regional["fr"])
|
||||||
|
);
|
||||||
|
|
||||||
/* Barre menu */
|
/* Barre menu */
|
||||||
var sco_menu_position = { my: "left top", at: "left bottom" };
|
var sco_menu_position = { my: "left top", at: "left bottom" };
|
||||||
$("#sco_menu").menu({
|
$("#sco_menu")
|
||||||
|
.menu({
|
||||||
position: sco_menu_position,
|
position: sco_menu_position,
|
||||||
blur: function () {
|
blur: function () {
|
||||||
$(this).menu("option", "position", sco_menu_position);
|
$(this).menu("option", "position", sco_menu_position);
|
||||||
},
|
},
|
||||||
focus: function (e, ui) {
|
focus: function (e, ui) {
|
||||||
if ($("#sco_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
|
if ($("#sco_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
|
||||||
$(this).menu("option", "position", { my: "left top", at: "right top" });
|
$(this).menu("option", "position", {
|
||||||
|
my: "left top",
|
||||||
|
at: "right top",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}).mouseleave(function (x, y) {
|
})
|
||||||
$("#sco_menu").menu('collapseAll');
|
.mouseleave(function (x, y) {
|
||||||
|
$("#sco_menu").menu("collapseAll");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#sco_menu > li > a > span").switchClass("ui-icon-carat-1-e", "ui-icon-carat-1-s");
|
$("#sco_menu > li > a > span").switchClass(
|
||||||
|
"ui-icon-carat-1-e",
|
||||||
|
"ui-icon-carat-1-s"
|
||||||
|
);
|
||||||
|
|
||||||
/* Les menus isoles dropdown */
|
/* Les menus isoles dropdown */
|
||||||
$(".sco_dropdown_menu").menu({
|
$(".sco_dropdown_menu")
|
||||||
position: sco_menu_position
|
.menu({
|
||||||
}).mouseleave(function (x, y) {
|
position: sco_menu_position,
|
||||||
$(".sco_dropdown_menu").menu('collapseAll');
|
})
|
||||||
}
|
.mouseleave(function (x, y) {
|
||||||
|
$(".sco_dropdown_menu").menu("collapseAll");
|
||||||
|
});
|
||||||
|
$(".sco_dropdown_menu > li > a > span").switchClass(
|
||||||
|
"ui-icon-carat-1-e",
|
||||||
|
"ui-icon-carat-1-s"
|
||||||
);
|
);
|
||||||
$(".sco_dropdown_menu > li > a > span").switchClass("ui-icon-carat-1-e", "ui-icon-carat-1-s");
|
|
||||||
|
|
||||||
/* up-to-date status */
|
/* up-to-date status */
|
||||||
var update_div = document.getElementById("update_warning");
|
var update_div = document.getElementById("update_warning");
|
||||||
if (update_div) {
|
if (update_div) {
|
||||||
fetch('install_info').then(
|
fetch("install_info")
|
||||||
response => response.text()
|
.then((response) => response.text())
|
||||||
).then(text => {
|
.then((text) => {
|
||||||
update_div.innerHTML = text;
|
update_div.innerHTML = text;
|
||||||
if (text) {
|
if (text) {
|
||||||
update_div.style.display = "block";
|
update_div.style.display = "block";
|
||||||
@ -80,58 +92,60 @@ function sco_message(msg, className = "message_custom", duration = 0) {
|
|||||||
if (duration) {
|
if (duration) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
div.remove();
|
div.remove();
|
||||||
}, 3000);
|
}, 8000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sco_error_message(msg) {
|
function sco_error_message(msg) {
|
||||||
sco_message(msg, className = "message_error", duration = 0);
|
sco_message(msg, (className = "message_error"), (duration = 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function get_query_args() {
|
function get_query_args() {
|
||||||
var s = window.location.search; // eg "?x=1&y=2"
|
var s = window.location.search; // eg "?x=1&y=2"
|
||||||
var vars = {};
|
var vars = {};
|
||||||
s.replace(
|
s.replace(
|
||||||
/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
|
/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
|
||||||
function (m, key, value) { // callback
|
function (m, key, value) {
|
||||||
vars[key] = value !== undefined ? value : '';
|
// callback
|
||||||
|
vars[key] = value !== undefined ? value : "";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Tables (gen_tables)
|
// Tables (gen_tables)
|
||||||
$(function () {
|
$(function () {
|
||||||
if ($('table.gt_table').length > 0) {
|
if ($("table.gt_table").length > 0) {
|
||||||
var table_options = {
|
var table_options = {
|
||||||
"paging": false,
|
paging: false,
|
||||||
"searching": false,
|
searching: false,
|
||||||
"info": false,
|
info: false,
|
||||||
/* "autoWidth" : false, */
|
/* "autoWidth" : false, */
|
||||||
"fixedHeader": {
|
fixedHeader: {
|
||||||
"header": true,
|
header: true,
|
||||||
"footer": true
|
footer: true,
|
||||||
},
|
},
|
||||||
"orderCellsTop": true, // cellules ligne 1 pour tri
|
orderCellsTop: true, // cellules ligne 1 pour tri
|
||||||
"aaSorting": [], // Prevent initial sorting
|
aaSorting: [], // Prevent initial sorting
|
||||||
};
|
};
|
||||||
$('table.gt_table').DataTable(table_options);
|
$("table.gt_table").DataTable(table_options);
|
||||||
table_options["searching"] = true;
|
table_options["searching"] = true;
|
||||||
$('table.gt_table_searchable').DataTable(table_options);
|
$("table.gt_table_searchable").DataTable(table_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Show tags (readonly)
|
// Show tags (readonly)
|
||||||
function readOnlyTags(nodes) {
|
function readOnlyTags(nodes) {
|
||||||
// nodes are textareas, hide them and create a span showing tags
|
// nodes are textareas, hide them and create a span showing tags
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
var node = $(nodes[i]);
|
var node = $(nodes[i]);
|
||||||
node.hide();
|
node.hide();
|
||||||
var tags = nodes[i].value.split(',');
|
var tags = nodes[i].value.split(",");
|
||||||
node.after('<span class="ro_tags"><span class="ro_tag">' + tags.join('</span><span class="ro_tag">') + '</span></span>');
|
node.after(
|
||||||
|
'<span class="ro_tags"><span class="ro_tag">' +
|
||||||
|
tags.join('</span><span class="ro_tag">') +
|
||||||
|
"</span></span>"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +178,8 @@ class ScoFieldEditor {
|
|||||||
// id: ${obj.dataset.oid}
|
// id: ${obj.dataset.oid}
|
||||||
// `);
|
// `);
|
||||||
|
|
||||||
$.post(this.save_url,
|
$.post(
|
||||||
|
this.save_url,
|
||||||
{
|
{
|
||||||
oid: obj.dataset.oid,
|
oid: obj.dataset.oid,
|
||||||
value: value,
|
value: value,
|
||||||
@ -185,11 +200,19 @@ class ScoFieldEditor {
|
|||||||
}
|
}
|
||||||
document.body.addEventListener("keydown", this.key);
|
document.body.addEventListener("keydown", this.key);
|
||||||
let editor = this;
|
let editor = this;
|
||||||
this.handleSelectCell = (event) => { editor.selectCell(event) };
|
this.handleSelectCell = (event) => {
|
||||||
this.handleModifCell = (event) => { editor.modifCell(event) };
|
editor.selectCell(event);
|
||||||
this.handleBlur = (event) => { editor.blurCell(event) };
|
};
|
||||||
this.handleKeyCell = (event) => { editor.keyCell(event) };
|
this.handleModifCell = (event) => {
|
||||||
document.querySelectorAll(this.selector).forEach(cellule => {
|
editor.modifCell(event);
|
||||||
|
};
|
||||||
|
this.handleBlur = (event) => {
|
||||||
|
editor.blurCell(event);
|
||||||
|
};
|
||||||
|
this.handleKeyCell = (event) => {
|
||||||
|
editor.keyCell(event);
|
||||||
|
};
|
||||||
|
document.querySelectorAll(this.selector).forEach((cellule) => {
|
||||||
cellule.addEventListener("click", this.handleSelectCell);
|
cellule.addEventListener("click", this.handleSelectCell);
|
||||||
cellule.addEventListener("dblclick", this.handleModifCell);
|
cellule.addEventListener("dblclick", this.handleModifCell);
|
||||||
cellule.addEventListener("blur", this.handleBlur);
|
cellule.addEventListener("blur", this.handleBlur);
|
||||||
@ -224,7 +247,9 @@ class ScoFieldEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unselectCell() {
|
unselectCell() {
|
||||||
document.querySelectorAll(".sco_selected, .sco_modifying").forEach(cellule => {
|
document
|
||||||
|
.querySelectorAll(".sco_selected, .sco_modifying")
|
||||||
|
.forEach((cellule) => {
|
||||||
cellule.classList.remove("sco_selected", "sco_modifying");
|
cellule.classList.remove("sco_selected", "sco_modifying");
|
||||||
cellule.removeAttribute("contentEditable");
|
cellule.removeAttribute("contentEditable");
|
||||||
cellule.removeEventListener("keydown", this.handleKeyCell);
|
cellule.removeEventListener("keydown", this.handleKeyCell);
|
||||||
@ -254,7 +279,7 @@ class ScoFieldEditor {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (!this.save(obj)) {
|
if (!this.save(obj)) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
obj.classList.remove("sco_modifying");
|
obj.classList.remove("sco_modifying");
|
||||||
// ArrowMove(0, 1);
|
// ArrowMove(0, 1);
|
||||||
@ -267,7 +292,7 @@ class ScoFieldEditor {
|
|||||||
|
|
||||||
function getCurrentScriptPath() {
|
function getCurrentScriptPath() {
|
||||||
// Get all the script elements on the page
|
// Get all the script elements on the page
|
||||||
var scripts = document.getElementsByTagName('script');
|
var scripts = document.getElementsByTagName("script");
|
||||||
|
|
||||||
// Find the last script element (which is the currently executing script)
|
// Find the last script element (which is the currently executing script)
|
||||||
var currentScript = scripts[scripts.length - 1];
|
var currentScript = scripts[scripts.length - 1];
|
||||||
@ -279,13 +304,13 @@ function getCurrentScriptPath() {
|
|||||||
}
|
}
|
||||||
function removeLastTwoComponents(path) {
|
function removeLastTwoComponents(path) {
|
||||||
// Split the path into individual components
|
// Split the path into individual components
|
||||||
var components = path.split('/');
|
var components = path.split("/");
|
||||||
|
|
||||||
// Remove the last two components (filename and enclosing directory)
|
// Remove the last two components (filename and enclosing directory)
|
||||||
components.splice(-2);
|
components.splice(-2);
|
||||||
|
|
||||||
// Join the remaining components back into a path
|
// Join the remaining components back into a path
|
||||||
var newPath = components.join('/');
|
var newPath = components.join("/");
|
||||||
|
|
||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
@ -74,9 +74,8 @@ class TableJury(TableRecap):
|
|||||||
self.freq_codes_annuels[deca.code_valide] += 1
|
self.freq_codes_annuels[deca.code_valide] += 1
|
||||||
row.add_nb_rcues_cell()
|
row.add_nb_rcues_cell()
|
||||||
# --- Les RCUEs
|
# --- Les RCUEs
|
||||||
for rcue in deca.rcues_annee:
|
for dec_rcue in deca.get_decisions_rcues_annee():
|
||||||
dec_rcue = deca.dec_rcue_by_ue.get(rcue.ue_1.id)
|
if dec_rcue.rcue.complete:
|
||||||
if dec_rcue is not None: # None si l'UE n'est pas associée à un niveau
|
|
||||||
row.add_rcue_cols(dec_rcue)
|
row.add_rcue_cols(dec_rcue)
|
||||||
self.freq_codes_annuels["total"] = len(self.rows)
|
self.freq_codes_annuels["total"] = len(self.rows)
|
||||||
|
|
||||||
@ -205,7 +204,7 @@ class RowJury(RowRecap):
|
|||||||
else:
|
else:
|
||||||
classes.append("moy_ue_valid")
|
classes.append("moy_ue_valid")
|
||||||
|
|
||||||
if len(deca.rcues_annee) > 0:
|
if len(deca.get_decisions_rcues_annee()) > 0:
|
||||||
# permet un tri par nb de niveaux validables + moyenne gen indicative S_pair
|
# permet un tri par nb de niveaux validables + moyenne gen indicative S_pair
|
||||||
if deca.res_pair and deca.etud.id in deca.res_pair.etud_moy_gen:
|
if deca.res_pair and deca.etud.id in deca.res_pair.etud_moy_gen:
|
||||||
moy = deca.res_pair.etud_moy_gen[deca.etud.id]
|
moy = deca.res_pair.etud_moy_gen[deca.etud.id]
|
||||||
@ -260,9 +259,11 @@ class RowJury(RowRecap):
|
|||||||
|
|
||||||
def add_rcue_cols(self, dec_rcue: DecisionsProposeesRCUE):
|
def add_rcue_cols(self, dec_rcue: DecisionsProposeesRCUE):
|
||||||
"2 cells: moyenne du RCUE, code enregistré"
|
"2 cells: moyenne du RCUE, code enregistré"
|
||||||
self.table.group_titles["rcue"] = "RCUEs en cours"
|
|
||||||
rcue = dec_rcue.rcue
|
rcue = dec_rcue.rcue
|
||||||
col_id = f"moy_rcue_{rcue.ue_1.niveau_competence_id}" # le niveau_id
|
if not rcue.complete:
|
||||||
|
return
|
||||||
|
col_id = f"moy_rcue_{rcue.niveau.id}" # le niveau_id
|
||||||
|
self.table.group_titles["rcue"] = "RCUEs en cours"
|
||||||
note_class = ""
|
note_class = ""
|
||||||
val = rcue.moy_rcue
|
val = rcue.moy_rcue
|
||||||
if isinstance(val, float):
|
if isinstance(val, float):
|
||||||
|
@ -130,6 +130,12 @@
|
|||||||
<td class="amue">CODJ</td>
|
<td class="amue">CODJ</td>
|
||||||
<td>Acquis par décision du jury</td>
|
<td>Acquis par décision du jury</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ADSUP</td>
|
||||||
|
<td>{{codes["ADSUP"]}}</td>
|
||||||
|
<td class="amue"></td>
|
||||||
|
<td>Acquis parce que le niveau de compétence supérieur est acquis</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>AJ</td>
|
<td>AJ</td>
|
||||||
<td>{{codes["AJ"]}}</td>
|
<td>{{codes["AJ"]}}</td>
|
||||||
@ -200,6 +206,12 @@
|
|||||||
<td class="amue"></td>
|
<td class="amue"></td>
|
||||||
<td>Acquis par décision de jury sur le RCUE (ECTS acquis)</td>
|
<td>Acquis par décision de jury sur le RCUE (ECTS acquis)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ADSUP</td>
|
||||||
|
<td>{{codes["ADSUP"]}}</td>
|
||||||
|
<td class="amue"></td>
|
||||||
|
<td>Acquis parce que le niveau de compétence supérieur est acquis</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>AJ</td>
|
<td>AJ</td>
|
||||||
<td>{{codes["AJ"]}}</td>
|
<td>{{codes["AJ"]}}</td>
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Semestre: {{ue.semestre_idx}}</li>
|
<li>Semestre: {{ue.semestre_idx}}</li>
|
||||||
<li>Code: <tt>{{ue.ue_code}}</tt></li>
|
<li>Code: <tt>{{ue.ue_code}}</tt></li>
|
||||||
|
<li>ECTS: <b>{{ue.ects or 0}}</b></li>
|
||||||
<li>Type: {{ue.type}}</li>
|
<li>Type: {{ue.type}}</li>
|
||||||
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
|
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
|
||||||
<li>Code Apogée: {{ue.code_apogee or "aucun"}}</li>
|
<li>Code Apogée: {{ue.code_apogee or "aucun"}}</li>
|
||||||
|
@ -2430,7 +2430,7 @@ def formsemestre_validation_but(
|
|||||||
)
|
)
|
||||||
|
|
||||||
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||||||
if len(deca.rcues_annee) == 0:
|
if len(deca.get_decisions_rcues_annee()) == 0:
|
||||||
return jury_but_view.jury_but_semestriel(
|
return jury_but_view.jury_but_semestriel(
|
||||||
formsemestre, etud, read_only, navigation_div=navigation_div
|
formsemestre, etud, read_only, navigation_div=navigation_div
|
||||||
)
|
)
|
||||||
@ -2459,22 +2459,25 @@ def formsemestre_validation_but(
|
|||||||
|
|
||||||
warning = ""
|
warning = ""
|
||||||
if len(deca.niveaux_competences) != len(deca.decisions_rcue_by_niveau):
|
if len(deca.niveaux_competences) != len(deca.decisions_rcue_by_niveau):
|
||||||
if deca.a_cheval:
|
|
||||||
warning += """<div class="warning">Attention: regroupements RCUE
|
|
||||||
entre années (redoublement).</div>"""
|
|
||||||
else:
|
|
||||||
warning += f"""<div class="warning">Attention: {len(deca.niveaux_competences)}
|
warning += f"""<div class="warning">Attention: {len(deca.niveaux_competences)}
|
||||||
niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.</div>"""
|
niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.</div>"""
|
||||||
if (deca.parcour is None) and len(formsemestre.parcours) > 0:
|
if (deca.parcour is None) and len(formsemestre.parcours) > 0:
|
||||||
warning += (
|
warning += (
|
||||||
"""<div class="warning">L'étudiant n'est pas inscrit à un parcours.</div>"""
|
"""<div class="warning">L'étudiant n'est pas inscrit à un parcours.</div>"""
|
||||||
)
|
)
|
||||||
if deca.formsemestre_impair and deca.inscription_etat_impair != scu.INSCRIT:
|
|
||||||
etat_ins = scu.ETATS_INSCRIPTION.get(deca.inscription_etat_impair, "inconnu?")
|
if deca.formsemestre_impair:
|
||||||
|
inscription = deca.formsemestre_impair.etuds_inscriptions.get(etud.id)
|
||||||
|
if (not inscription) or inscription.etat != scu.INSCRIT:
|
||||||
|
etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
|
||||||
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_impair.semestre_id}</div>"""
|
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_impair.semestre_id}</div>"""
|
||||||
if deca.formsemestre_pair and deca.inscription_etat_pair != scu.INSCRIT:
|
|
||||||
etat_ins = scu.ETATS_INSCRIPTION.get(deca.inscription_etat_pair, "inconnu?")
|
if deca.formsemestre_pair:
|
||||||
|
inscription = deca.formsemestre_pair.etuds_inscriptions.get(etud.id)
|
||||||
|
if (not inscription) or inscription.etat != scu.INSCRIT:
|
||||||
|
etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
|
||||||
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_pair.semestre_id}</div>"""
|
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_pair.semestre_id}</div>"""
|
||||||
|
|
||||||
if deca.has_notes_en_attente():
|
if deca.has_notes_en_attente():
|
||||||
warning += f"""<div class="warning">{etud.nomprenom} a des notes en ATTente.
|
warning += f"""<div class="warning">{etud.nomprenom} a des notes en ATTente.
|
||||||
Vous devriez régler cela avant de statuer en jury !</div>"""
|
Vous devriez régler cela avant de statuer en jury !</div>"""
|
||||||
@ -2531,7 +2534,7 @@ def formsemestre_validation_but(
|
|||||||
else:
|
else:
|
||||||
erase_span = f"""<a href="{
|
erase_span = f"""<a href="{
|
||||||
url_for("notes.formsemestre_jury_but_erase",
|
url_for("notes.formsemestre_jury_but_erase",
|
||||||
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id,
|
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre.id,
|
||||||
etudid=deca.etud.id)}" class="stdlink"
|
etudid=deca.etud.id)}" class="stdlink"
|
||||||
title="efface décisions issues des jurys de cette année"
|
title="efface décisions issues des jurys de cette année"
|
||||||
>effacer décisions de ce jury</a>
|
>effacer décisions de ce jury</a>
|
||||||
@ -2564,15 +2567,7 @@ def formsemestre_validation_but(
|
|||||||
)
|
)
|
||||||
H.append(navigation_div)
|
H.append(navigation_div)
|
||||||
H.append("</form>")
|
H.append("</form>")
|
||||||
if deca.a_cheval:
|
|
||||||
H.append(
|
|
||||||
f"""<div class="but_doc_codes but_warning_rcue_cap">
|
|
||||||
{scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE <b>capitalisées</b> (note > 10)
|
|
||||||
lors d'une année précédente peuvent être prise en compte pour former
|
|
||||||
un RCUE (associé à un niveau de compétence du BUT).
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
# Affichage cursus BUT
|
# Affichage cursus BUT
|
||||||
but_cursus = cursus_but.EtudCursusBUT(etud, deca.formsemestre.formation)
|
but_cursus = cursus_but.EtudCursusBUT(etud, deca.formsemestre.formation)
|
||||||
H += [
|
H += [
|
||||||
@ -2595,7 +2590,14 @@ def formsemestre_validation_but(
|
|||||||
codes=ScoDocSiteConfig.get_codes_apo_dict(),
|
codes=ScoDocSiteConfig.get_codes_apo_dict(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
H.append(
|
||||||
|
f"""<div class="but_doc_codes but_warning_rcue_cap">
|
||||||
|
{scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE <b>capitalisées</b> (note > 10)
|
||||||
|
lors d'une année précédente peuvent être prise en compte pour former
|
||||||
|
un RCUE (associé à un niveau de compétence du BUT).
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
)
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.4.93"
|
SCOVERSION = "9.4.94"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user