forked from ScoDoc/ScoDoc
WIP: jury BUT: enregistrement des décisions
This commit is contained in:
parent
d4a8b74c0a
commit
c17e2bae47
@ -58,9 +58,12 @@ DecisionsProposeesUE: décisions de jury sur une UE du BUT
|
|||||||
DecisionsProposeesRCUE appelera .set_compensable()
|
DecisionsProposeesRCUE appelera .set_compensable()
|
||||||
si on a la possibilité de la compenser dans le RCUE.
|
si on a la possibilité de la compenser dans le RCUE.
|
||||||
"""
|
"""
|
||||||
|
import html
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
import re
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from app import db
|
||||||
from app import log
|
from app import log
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
@ -72,7 +75,7 @@ from app.models.but_refcomp import (
|
|||||||
ApcParcours,
|
ApcParcours,
|
||||||
ApcParcoursNiveauCompetence,
|
ApcParcoursNiveauCompetence,
|
||||||
)
|
)
|
||||||
from app.models import but_validations
|
from app.models import Scolog
|
||||||
from app.models.but_validations import (
|
from app.models.but_validations import (
|
||||||
ApcValidationAnnee,
|
ApcValidationAnnee,
|
||||||
ApcValidationRCUE,
|
ApcValidationRCUE,
|
||||||
@ -122,10 +125,14 @@ class DecisionsProposees:
|
|||||||
self.codes = code + self.codes
|
self.codes = code + self.codes
|
||||||
elif code is not None:
|
elif code is not None:
|
||||||
self.codes = [code] + self.codes
|
self.codes = [code] + self.codes
|
||||||
|
self.validation = None
|
||||||
|
"Validation enregistrée"
|
||||||
self.code_valide: str = code_valide
|
self.code_valide: str = code_valide
|
||||||
"La décision actuelle enregistrée"
|
"Code décision actuel enregistré"
|
||||||
self.explanation: str = explanation
|
self.explanation: str = explanation
|
||||||
"Explication à afficher à côté de la décision"
|
"Explication à afficher à côté de la décision"
|
||||||
|
self.recorded = False
|
||||||
|
"true si la décision vient d'être enregistrée"
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"""<{self.__class__.__name__} valid={self.code_valide
|
return f"""<{self.__class__.__name__} valid={self.code_valide
|
||||||
@ -266,7 +273,15 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
explanation: {self.explanation}
|
explanation: {self.explanation}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def annee_scolaire_sr(self)
|
def annee_scolaire(self) -> int:
|
||||||
|
"L'année de début de l'année scolaire"
|
||||||
|
formsemestre = self.formsemestre_impair or self.formsemestre_pair
|
||||||
|
return formsemestre.annee_scolaire()
|
||||||
|
|
||||||
|
def annee_scolaire_str(self) -> str:
|
||||||
|
"L'année scolaire, eg '2021 - 2022'"
|
||||||
|
formsemestre = self.formsemestre_impair or self.formsemestre_pair
|
||||||
|
return formsemestre.annee_scolaire_str().replace(" ", "")
|
||||||
|
|
||||||
def comp_formsemestres(
|
def comp_formsemestres(
|
||||||
self, formsemestre: FormSemestre
|
self, formsemestre: FormSemestre
|
||||||
@ -397,6 +412,90 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux}
|
decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux}
|
||||||
return decisions_rcue_by_niveau
|
return decisions_rcue_by_niveau
|
||||||
|
|
||||||
|
# def lookup_ue(self, ue_id: int) -> UniteEns:
|
||||||
|
# "check that ue_id belongs to our UE, if not returns None"
|
||||||
|
# ues = [ue for ue in self.ues_impair + self.ues_pair if ue.id == ue_id]
|
||||||
|
# assert len(ues) < 2
|
||||||
|
# if len(ues):
|
||||||
|
# return ues[0]
|
||||||
|
# return None
|
||||||
|
|
||||||
|
def record_form(self, form: dict):
|
||||||
|
"""Enregistre les codes de jury en base
|
||||||
|
form dict:
|
||||||
|
- 'code_ue_1896' : 'AJ' code pour l'UE id 1896
|
||||||
|
- 'code_rcue_6" : 'ADM' code pour le RCUE du niveau 6
|
||||||
|
- 'code_annee' : 'ADM' code pour l'année
|
||||||
|
|
||||||
|
Si les code_rcue et le code_annee ne sont pas fournis,
|
||||||
|
enregistre ceux par défaut.
|
||||||
|
"""
|
||||||
|
for key in form:
|
||||||
|
code = form[key]
|
||||||
|
# Codes d'UE
|
||||||
|
m = re.match(r"^code_ue_(\d+)$", key)
|
||||||
|
if m:
|
||||||
|
ue_id = int(m.group(1))
|
||||||
|
dec_ue = self.decisions_ues.get(ue_id)
|
||||||
|
if not dec_ue:
|
||||||
|
raise ScoValueError(f"UE invalide ue_id={ue_id}")
|
||||||
|
dec_ue.record(code)
|
||||||
|
else:
|
||||||
|
# Codes de RCUE
|
||||||
|
m = re.match(r"^code_rcue_(\d+)$", key)
|
||||||
|
if m:
|
||||||
|
niveau_id = int(m.group(1))
|
||||||
|
dec_rcue = self.decisions_rcue_by_niveau.get(niveau_id)
|
||||||
|
if not dec_rcue:
|
||||||
|
raise ScoValueError(f"RCUE invalide niveau_id={niveau_id}")
|
||||||
|
dec_rcue.record(code)
|
||||||
|
elif key == "code_annee":
|
||||||
|
# Code annuel
|
||||||
|
self.record(code)
|
||||||
|
|
||||||
|
self.record_all()
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
def record(self, code: str):
|
||||||
|
"""Enregistre le code"""
|
||||||
|
if not code in self.codes:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"code annee <tt>{html.escape(code)}</tt> invalide pour formsemestre {html.escape(self.formsemestre)}"
|
||||||
|
)
|
||||||
|
if code == self.code_valide:
|
||||||
|
return # no change
|
||||||
|
if self.validation:
|
||||||
|
db.session.delete(self.validation)
|
||||||
|
db.session.flush()
|
||||||
|
|
||||||
|
self.validation = ApcValidationAnnee(
|
||||||
|
etudid=self.etud.id,
|
||||||
|
formsemestre=self.formsemestre_impair,
|
||||||
|
ordre=self.annee_but,
|
||||||
|
annee_scolaire=self.annee_scolaire(),
|
||||||
|
code=code,
|
||||||
|
)
|
||||||
|
Scolog.logdb(
|
||||||
|
method="jury_but",
|
||||||
|
etudid=self.etud.id,
|
||||||
|
msg=f"Validation année BUT{self.annee_but}: {code}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
|
self.recorded = True
|
||||||
|
|
||||||
|
def record_all(self):
|
||||||
|
"""Enregistre les codes qui n'ont pas été spécifiés par le formulaire,
|
||||||
|
et sont donc en mode "automatique"
|
||||||
|
"""
|
||||||
|
decisions = (
|
||||||
|
list(self.decisions_ues.values())
|
||||||
|
+ list(self.decisions_rcue_by_niveau.values())
|
||||||
|
+ [self]
|
||||||
|
)
|
||||||
|
for dec in decisions:
|
||||||
|
if not dec.recorded:
|
||||||
|
dec.record(dec.codes[0]) # rappel: le code par défaut est en tête
|
||||||
|
|
||||||
|
|
||||||
class DecisionsProposeesRCUE(DecisionsProposees):
|
class DecisionsProposeesRCUE(DecisionsProposees):
|
||||||
"""Liste des codes de décisions que l'on peut proposer pour
|
"""Liste des codes de décisions que l'on peut proposer pour
|
||||||
@ -417,10 +516,10 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
):
|
):
|
||||||
super().__init__(etud=dec_prop_annee.etud)
|
super().__init__(etud=dec_prop_annee.etud)
|
||||||
self.rcue = rcue
|
self.rcue = rcue
|
||||||
|
self.parcour = dec_prop_annee.parcour
|
||||||
validation = rcue.query_validations().first()
|
self.validation = rcue.query_validations().first()
|
||||||
if validation is not None:
|
if self.validation is not None:
|
||||||
self.code_valide = validation.code
|
self.code_valide = self.validation.code
|
||||||
if rcue.est_compensable():
|
if rcue.est_compensable():
|
||||||
self.codes.insert(0, sco_codes.CMP)
|
self.codes.insert(0, sco_codes.CMP)
|
||||||
elif rcue.est_validable():
|
elif rcue.est_validable():
|
||||||
@ -428,6 +527,34 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
else:
|
else:
|
||||||
self.codes.insert(0, sco_codes.AJ)
|
self.codes.insert(0, sco_codes.AJ)
|
||||||
|
|
||||||
|
def record(self, code: str):
|
||||||
|
"""Enregistre le code"""
|
||||||
|
if not code in self.codes:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
||||||
|
)
|
||||||
|
if code == self.code_valide:
|
||||||
|
return # no change
|
||||||
|
parcours_id = self.parcour.id if self.parcour is not None else None
|
||||||
|
if self.validation:
|
||||||
|
db.session.delete(self.validation)
|
||||||
|
db.session.flush()
|
||||||
|
self.validation = ApcValidationRCUE(
|
||||||
|
etudid=self.etud.id,
|
||||||
|
formsemestre_id=self.rcue.formsemestre_2.id,
|
||||||
|
ue1_id=self.rcue.ue_1.id,
|
||||||
|
ue2_id=self.rcue.ue_2.id,
|
||||||
|
parcours_id=parcours_id,
|
||||||
|
code=code,
|
||||||
|
)
|
||||||
|
Scolog.logdb(
|
||||||
|
method="jury_but",
|
||||||
|
etudid=self.etud.id,
|
||||||
|
msg=f"Validation RCUE {repr(self.rcue)}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
|
self.recorded = True
|
||||||
|
|
||||||
|
|
||||||
class DecisionsProposeesUE(DecisionsProposees):
|
class DecisionsProposeesUE(DecisionsProposees):
|
||||||
"""Décisions de jury sur une UE du BUT
|
"""Décisions de jury sur une UE du BUT
|
||||||
@ -460,6 +587,7 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
ue: UniteEns,
|
ue: UniteEns,
|
||||||
):
|
):
|
||||||
super().__init__(etud=etud)
|
super().__init__(etud=etud)
|
||||||
|
self.formsemestre = formsemestre
|
||||||
self.ue: UniteEns = ue
|
self.ue: UniteEns = ue
|
||||||
self.rcue: RegroupementCoherentUE = None
|
self.rcue: RegroupementCoherentUE = None
|
||||||
"Le rcu auquel est rattaché cette UE, ou None"
|
"Le rcu auquel est rattaché cette UE, ou None"
|
||||||
@ -503,6 +631,31 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
self.codes = [sco_codes.AJ, sco_codes.ADJ] + self.codes
|
self.codes = [sco_codes.AJ, sco_codes.ADJ] + self.codes
|
||||||
self.explanation = "notes insuffisantes"
|
self.explanation = "notes insuffisantes"
|
||||||
|
|
||||||
|
def record(self, code: str):
|
||||||
|
"""Enregistre le code"""
|
||||||
|
if not code in self.codes:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
||||||
|
)
|
||||||
|
if code == self.code_valide:
|
||||||
|
return # no change
|
||||||
|
if self.validation:
|
||||||
|
db.session.delete(self.validation)
|
||||||
|
db.session.flush()
|
||||||
|
self.validation = ScolarFormSemestreValidation(
|
||||||
|
etudid=self.etud.id,
|
||||||
|
formsemestre_id=self.formsemestre.id,
|
||||||
|
ue_id=self.ue.id,
|
||||||
|
code=code,
|
||||||
|
)
|
||||||
|
Scolog.logdb(
|
||||||
|
method="jury_but",
|
||||||
|
etudid=self.etud.id,
|
||||||
|
msg=f"Validation UE {self.ue.id}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
|
self.recorded = True
|
||||||
|
|
||||||
|
|
||||||
class BUTCursusEtud: # WIP TODO
|
class BUTCursusEtud: # WIP TODO
|
||||||
"""Validation du cursus d'un étudiant"""
|
"""Validation du cursus d'un étudiant"""
|
||||||
|
@ -277,4 +277,4 @@ class ApcValidationAnnee(db.Model):
|
|||||||
formsemestre = db.relationship("FormSemestre", backref="apc_validations_annees")
|
formsemestre = db.relationship("FormSemestre", backref="apc_validations_annees")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} {self.id} {self.etud} BUT{self.ordre}:{self.code!r}>"
|
return f"<{self.__class__.__name__} {self.id} {self.etud} BUT{self.ordre}/{self.annee_scolaire}:{self.code!r}>"
|
||||||
|
@ -32,6 +32,21 @@ class Scolog(db.Model):
|
|||||||
authenticated_user = db.Column(db.Text) # login, sans contrainte
|
authenticated_user = db.Column(db.Text) # login, sans contrainte
|
||||||
# zope_remote_addr suppressed
|
# zope_remote_addr suppressed
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def logdb(
|
||||||
|
cls, method: str = None, etudid: int = None, msg: str = None, commit=False
|
||||||
|
):
|
||||||
|
"""Add entry in student's log (replacement for old scolog.logdb)"""
|
||||||
|
entry = Scolog(
|
||||||
|
method=method,
|
||||||
|
msg=msg,
|
||||||
|
etudid=etudid,
|
||||||
|
authenticated_user=current_user.user_name,
|
||||||
|
)
|
||||||
|
db.session.add(entry)
|
||||||
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class ScolarNews(db.Model):
|
class ScolarNews(db.Model):
|
||||||
"""Nouvelles pour page d'accueil"""
|
"""Nouvelles pour page d'accueil"""
|
||||||
|
@ -36,7 +36,7 @@ class ScolarFormSemestreValidation(db.Model):
|
|||||||
# NULL pour les UE, True|False pour les semestres:
|
# NULL pour les UE, True|False pour les semestres:
|
||||||
assidu = db.Column(db.Boolean)
|
assidu = db.Column(db.Boolean)
|
||||||
event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||||
# NULL sauf si compense un semestre:
|
# NULL sauf si compense un semestre: (pas utilisé pour BUT)
|
||||||
compense_formsemestre_id = db.Column(
|
compense_formsemestre_id = db.Column(
|
||||||
db.Integer,
|
db.Integer,
|
||||||
db.ForeignKey("notes_formsemestre.id"),
|
db.ForeignKey("notes_formsemestre.id"),
|
||||||
|
@ -65,4 +65,28 @@ div.but_settings {
|
|||||||
span.but_explanation {
|
span.but_explanation {
|
||||||
color: blueviolet;
|
color: blueviolet;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:disabled {
|
||||||
|
font-weight: bold;
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:invalid {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.but_code option.recorded {
|
||||||
|
color: rgb(3, 157, 3);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.but_niveau_ue.recorded,
|
||||||
|
div.but_niveau_rcue.recorded {
|
||||||
|
border-color: rgb(136, 252, 136);
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.but_niveau_ue.modified {
|
||||||
|
background-color: rgb(255, 214, 254);
|
||||||
}
|
}
|
@ -4,3 +4,11 @@
|
|||||||
function enable_manual_codes(elt) {
|
function enable_manual_codes(elt) {
|
||||||
$(".jury_but select.manual").prop("disabled", !elt.checked);
|
$(".jury_but select.manual").prop("disabled", !elt.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// changement menu code:
|
||||||
|
function change_menu_code(elt) {
|
||||||
|
elt.parentElement.parentElement.classList.remove("recorded");
|
||||||
|
// TODO: comparer avec valeur enregistrée (à mettre en data-orig ?)
|
||||||
|
// et colorer en fonction
|
||||||
|
elt.parentElement.parentElement.classList.add("modified");
|
||||||
|
}
|
@ -2231,7 +2231,6 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# XXX TODO Page expérimentale pour les devs
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title="Validation BUT",
|
page_title="Validation BUT",
|
||||||
@ -2244,22 +2243,37 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
<div class="jury_but">
|
<div class="jury_but">
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
etud = Identite.query.get_or_404(etudid)
|
etud = Identite.query.get_or_404(etudid)
|
||||||
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
||||||
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||||||
|
if request.method == "POST":
|
||||||
|
deca.record_form(request.form)
|
||||||
|
flash("codes enregistrés")
|
||||||
|
return flask.redirect(
|
||||||
|
url_for(
|
||||||
|
"notes.formsemestre_validation_but",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre_id,
|
||||||
|
etudid=etudid,
|
||||||
|
)
|
||||||
|
)
|
||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<div class="titre_parcours"><h2>Jury BUT{deca.annee_but} - Parcours {deca.parcour.libelle or "non spécifié"}
|
<div class="titre_parcours">
|
||||||
- {deca.formsemestre_impair.annee_scolaire_str()}</h2>
|
<h2>Jury BUT{deca.annee_but}
|
||||||
|
- Parcours {deca.parcour.libelle or "non spécifié"}
|
||||||
|
- {deca.annee_scolaire_str()}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="but_section_annee">
|
<div class="but_section_annee">
|
||||||
<div>
|
<div>
|
||||||
<b>Décision de jury pour l'année :</b> {
|
<b>Décision de jury pour l'année :</b> {
|
||||||
_gen_but_select("code_annee", deca.codes, deca.code_valide, disabled=True, klass="manual")
|
_gen_but_select("code_annee", deca.codes, deca.code_valide, disabled=True, klass="manual")
|
||||||
}</div>
|
}
|
||||||
|
<span>({'non ' if deca.code_valide is None else ''}enregistrée)</span>
|
||||||
|
</div>
|
||||||
<span class="but_explanation">{deca.explanation}</span>
|
<span class="but_explanation">{deca.explanation}</span>
|
||||||
</div>
|
</div>
|
||||||
<b>Niveaux de compétences et unités d'enseignement :</b>
|
<b>Niveaux de compétences et unités d'enseignement :</b>
|
||||||
@ -2279,36 +2293,26 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
)
|
)
|
||||||
dec_rcue = deca.decisions_rcue_by_niveau[niveau.id]
|
dec_rcue = deca.decisions_rcue_by_niveau[niveau.id]
|
||||||
# Semestre impair
|
# Semestre impair
|
||||||
ue = dec_rcue.rcue.ue_1
|
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div class="but_niveau_ue">
|
_gen_but_niveau_ue(
|
||||||
<div title="{ue.titre}">{ue.acronyme}</div>
|
dec_rcue.rcue.ue_1,
|
||||||
<div class="but_note">{scu.fmt_note(dec_rcue.rcue.moy_ue_1)}</div>
|
dec_rcue.rcue.moy_ue_1,
|
||||||
<div class="but_code">{
|
deca.decisions_ues[dec_rcue.rcue.ue_1.id],
|
||||||
_gen_but_select("code_ue_"+str(ue.id),
|
)
|
||||||
deca.decisions_ues[ue.id].codes,
|
|
||||||
deca.decisions_ues[ue.id].code_valide
|
|
||||||
)
|
|
||||||
}</div>
|
|
||||||
</div>"""
|
|
||||||
)
|
)
|
||||||
# Semestre pair
|
# Semestre pair
|
||||||
ue = dec_rcue.rcue.ue_2
|
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div class="but_niveau_ue">
|
_gen_but_niveau_ue(
|
||||||
<div title="{ue.titre}">{ue.acronyme}</div>
|
dec_rcue.rcue.ue_2,
|
||||||
<div class="but_note">{scu.fmt_note(dec_rcue.rcue.moy_ue_2)}</div>
|
dec_rcue.rcue.moy_ue_2,
|
||||||
<div class="but_code">{
|
deca.decisions_ues[dec_rcue.rcue.ue_2.id],
|
||||||
_gen_but_select("code_ue_"+str(ue.id),
|
)
|
||||||
deca.decisions_ues[ue.id].codes,
|
|
||||||
deca.decisions_ues[ue.id].code_valide
|
|
||||||
)
|
|
||||||
}</div>
|
|
||||||
</div>"""
|
|
||||||
)
|
)
|
||||||
# RCUE
|
# RCUE
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div class="but_niveau_rcue">
|
f"""<div class="but_niveau_rcue
|
||||||
|
{'recorded' if dec_rcue.code_valide is not None else ''}
|
||||||
|
">
|
||||||
<div class="but_note">{scu.fmt_note(dec_rcue.rcue.moy_rcue)}</div>
|
<div class="but_note">{scu.fmt_note(dec_rcue.rcue.moy_rcue)}</div>
|
||||||
<div class="but_code">{
|
<div class="but_code">{
|
||||||
_gen_but_select("code_rcue_"+str(niveau.id),
|
_gen_but_select("code_rcue_"+str(niveau.id),
|
||||||
@ -2322,9 +2326,16 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
H.append("</div>") # but_annee
|
H.append("</div>") # but_annee
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<div class="but_settings"><input type="checkbox" onchange="enable_manual_codes(this)">
|
"""<div class="but_settings">
|
||||||
<em>permettre la saisie manuelles des codes d'année et de niveaux</em>
|
<input type="checkbox" onchange="enable_manual_codes(this)">
|
||||||
</input></div>"""
|
<em>permettre la saisie manuelles des codes d'année et de niveaux.
|
||||||
|
Dans ce cas, il vous revient de vous assurer de la cohérence entre
|
||||||
|
vos codes d'UE/RCUE/Année !</em>
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" value="Enregistrer ces décisions">
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
H.append("</form>") # but_annee
|
H.append("</form>") # but_annee
|
||||||
|
|
||||||
@ -2348,11 +2359,36 @@ def _gen_but_select(
|
|||||||
"Le menu html select avec les codes"
|
"Le menu html select avec les codes"
|
||||||
h = "\n".join(
|
h = "\n".join(
|
||||||
[
|
[
|
||||||
f"""<option value="{code}" {'selected' if code == code_valide else ''}>{code}</option>"""
|
f"""<option value="{code}"
|
||||||
|
{'selected' if code == code_valide else ''}
|
||||||
|
class="{'recorded' if code == code_valide else ''}"
|
||||||
|
>{code}</option>"""
|
||||||
for code in codes
|
for code in codes
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return f"""<select name="{name}" class="{klass}" {"disabled" if disabled else ""}>{h}</select>"""
|
return f"""<select required name="{name}"
|
||||||
|
class="but_code {klass}"
|
||||||
|
onchange="change_menu_code(this);"
|
||||||
|
{"disabled" if disabled else ""}
|
||||||
|
>{h}</select>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _gen_but_niveau_ue(
|
||||||
|
ue: UniteEns, moy_ue: float, dec_ue: jury_but.DecisionsProposeesUE
|
||||||
|
):
|
||||||
|
return f"""<div class="but_niveau_ue {
|
||||||
|
'recorded' if dec_ue.code_valide is not None else ''}
|
||||||
|
">
|
||||||
|
<div title="{ue.titre}">{ue.acronyme}</div>
|
||||||
|
<div class="but_note">{scu.fmt_note(moy_ue)}</div>
|
||||||
|
<div class="but_code">{
|
||||||
|
_gen_but_select("code_ue_"+str(ue.id),
|
||||||
|
dec_ue.codes,
|
||||||
|
dec_ue.code_valide
|
||||||
|
)
|
||||||
|
}</div>
|
||||||
|
</div>"""
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formsemestre_validate_previous_ue", methods=["GET", "POST"])
|
@bp.route("/formsemestre_validate_previous_ue", methods=["GET", "POST"])
|
||||||
|
Loading…
Reference in New Issue
Block a user