Améliore visu jury BUT. + minor code cleaning.
This commit is contained in:
parent
7e1b0177f0
commit
9566551e7e
@ -8,6 +8,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
import numpy as np
|
||||
|
||||
import flask
|
||||
from flask import flash, url_for
|
||||
@ -15,10 +16,15 @@ from flask import g, request
|
||||
|
||||
from app import db
|
||||
from app.but import jury_but
|
||||
from app.but.jury_but import DecisionsProposeesAnnee, DecisionsProposeesUE
|
||||
from app.but.jury_but import (
|
||||
DecisionsProposeesAnnee,
|
||||
DecisionsProposeesRCUE,
|
||||
DecisionsProposeesUE,
|
||||
)
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_but import ResultatsSemestreBUT
|
||||
from app.models import (
|
||||
ApcNiveau,
|
||||
FormSemestre,
|
||||
FormSemestreInscription,
|
||||
Identite,
|
||||
@ -59,19 +65,9 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
"""
|
||||
)
|
||||
else:
|
||||
H.append("""<div><em>Pas de décision annuelle (sem. impair)</em></div>""")
|
||||
H.append("""<div><em>Pas de décision annuelle (sem. impair).</em></div>""")
|
||||
H.append("""</div>""")
|
||||
|
||||
if deca.formsemestre_pair is not None:
|
||||
annee_sco_pair = deca.formsemestre_pair.annee_scolaire()
|
||||
avertissement_redoublement = (
|
||||
f"année {annee_sco_pair}-{annee_sco_pair+1}"
|
||||
if annee_sco_pair != deca.annee_scolaire()
|
||||
else ""
|
||||
)
|
||||
else:
|
||||
avertissement_redoublement = ""
|
||||
|
||||
formsemestre_1 = deca.formsemestre_impair
|
||||
formsemestre_2 = deca.formsemestre_pair
|
||||
# Ordonne selon les dates des 2 semestres considérés (pour les redoublants à cheval):
|
||||
@ -84,16 +80,19 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
formsemestre_1, formsemestre_2 = formsemestre_2, formsemestre_1
|
||||
H.append(
|
||||
f"""
|
||||
<div class="titre_niveaux"><b>Niveaux de compétences et unités d'enseignement du BUT{deca.annee_but}</b></div>
|
||||
<div class="titre_niveaux"><b>Niveaux de compétences et unités d'enseignement du BUT{
|
||||
deca.annee_but}</b></div>
|
||||
<div class="but_annee">
|
||||
<div class="titre"></div>
|
||||
<div class="titre">S{formsemestre_1.semestre_id
|
||||
<div class="titre">{"S" +str(formsemestre_1.semestre_id)
|
||||
if formsemestre_1 else "-"}
|
||||
<span class="avertissement_redoublement">{formsemestre_1.annee_scolaire_str() if formsemestre_1 else ""}</span>
|
||||
<span class="avertissement_redoublement">{formsemestre_1.annee_scolaire_str()
|
||||
if formsemestre_1 else ""}</span>
|
||||
</div>
|
||||
<div class="titre">S{formsemestre_2.semestre_id
|
||||
<div class="titre">{"S"+str(formsemestre_2.semestre_id)
|
||||
if formsemestre_2 else "-"}
|
||||
<span class="avertissement_redoublement">{formsemestre_2.annee_scolaire_str() if formsemestre_2 else ""}</span>
|
||||
<span class="avertissement_redoublement">{formsemestre_2.annee_scolaire_str()
|
||||
if formsemestre_2 else ""}</span>
|
||||
</div>
|
||||
<div class="titre">RCUE</div>
|
||||
"""
|
||||
@ -109,7 +108,8 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
ue_impair = ues[0] if ues else None
|
||||
ues = [ue for ue in deca.ues_pair if ue.niveau_competence.id == niveau.id]
|
||||
ue_pair = ues[0] if ues else None
|
||||
# Les UEs à afficher, toujours en readonly sur le formsemestre de l'année précédente du redoublant
|
||||
# Les UEs à afficher, toujours en readonly
|
||||
# sur le formsemestre de l'année précédente du redoublant
|
||||
ues_ro = [
|
||||
(
|
||||
ue_impair,
|
||||
@ -137,24 +137,9 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
else:
|
||||
H.append("""<div class="niveau_vide"></div>""")
|
||||
|
||||
# RCUE
|
||||
if dec_rcue is None:
|
||||
H.append("""<div class="niveau_vide"></div>""")
|
||||
else:
|
||||
H.append(
|
||||
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_code">{
|
||||
_gen_but_select("code_rcue_"+str(niveau.id),
|
||||
dec_rcue.codes,
|
||||
dec_rcue.code_valide,
|
||||
disabled=True, klass="manual"
|
||||
)
|
||||
}</div>
|
||||
</div>"""
|
||||
)
|
||||
# Colonne RCUE
|
||||
H.append(_gen_but_rcue(dec_rcue, niveau))
|
||||
|
||||
H.append("</div>") # but_annee
|
||||
return "\n".join(H)
|
||||
|
||||
@ -169,7 +154,7 @@ def _gen_but_select(
|
||||
"Le menu html select avec les codes"
|
||||
# if disabled: # mauvaise idée car le disabled est traité en JS
|
||||
# return f"""<div class="but_code {klass}">{code_valide}</div>"""
|
||||
h = "\n".join(
|
||||
options_htm = "\n".join(
|
||||
[
|
||||
f"""<option value="{code}"
|
||||
{'selected' if code == code_valide else ''}
|
||||
@ -182,7 +167,7 @@ def _gen_but_select(
|
||||
class="but_code {klass}"
|
||||
onchange="change_menu_code(this);"
|
||||
{"disabled" if disabled else ""}
|
||||
>{h}</select>
|
||||
>{options_htm}</select>
|
||||
"""
|
||||
|
||||
|
||||
@ -191,18 +176,21 @@ def _gen_but_niveau_ue(
|
||||
dec_ue: DecisionsProposeesUE,
|
||||
disabled: bool = False,
|
||||
annee_prec: bool = False,
|
||||
):
|
||||
) -> str:
|
||||
if dec_ue.ue_status and dec_ue.ue_status["is_capitalized"]:
|
||||
moy_ue_str = f"""<span class="ue_cap">{
|
||||
scu.fmt_note(dec_ue.moy_ue_with_cap)}</span>"""
|
||||
scoplement = f"""<div class="scoplement">
|
||||
<div>
|
||||
<b>UE {ue.acronyme} capitalisée le
|
||||
{dec_ue.ue_status["event_date"].strftime("%d/%m/%Y")}
|
||||
</b>
|
||||
<b>UE {ue.acronyme} capitalisée </b>
|
||||
<span>le {dec_ue.ue_status["event_date"].strftime("%d/%m/%Y")}
|
||||
</span>
|
||||
</div>
|
||||
<div>UE en cours avec moyenne
|
||||
{scu.fmt_note(dec_ue.moy_ue)}
|
||||
<div>UE en cours
|
||||
{ "sans notes" if np.isnan(dec_ue.moy_ue)
|
||||
else
|
||||
("avec moyenne" + scu.fmt_note(dec_ue.moy_ue))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@ -229,6 +217,43 @@ def _gen_but_niveau_ue(
|
||||
</div>"""
|
||||
|
||||
|
||||
def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
|
||||
if dec_rcue is None:
|
||||
return """
|
||||
<div class="but_niveau_rcue niveau_vide with_scoplement">
|
||||
<div></div>
|
||||
<div class="scoplement">Pas de RCUE (UE non capitalisée ?)</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
scoplement = (
|
||||
f"""<div class="scoplement">{
|
||||
dec_rcue.validation.to_html()
|
||||
}</div>"""
|
||||
if dec_rcue.validation
|
||||
else ""
|
||||
)
|
||||
|
||||
return f"""
|
||||
<div class="but_niveau_rcue
|
||||
{'recorded' if dec_rcue.code_valide is not None else ''}
|
||||
">
|
||||
<div class="but_note with_scoplement">
|
||||
<div>{scu.fmt_note(dec_rcue.rcue.moy_rcue)}</div>
|
||||
{scoplement}
|
||||
</div>
|
||||
<div class="but_code">
|
||||
<div>{_gen_but_select("code_rcue_"+str(niveau.id),
|
||||
dec_rcue.codes,
|
||||
dec_rcue.code_valide,
|
||||
disabled=True, klass="manual"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
def jury_but_semestriel(
|
||||
formsemestre: FormSemestre,
|
||||
etud: Identite,
|
||||
@ -265,9 +290,9 @@ def jury_but_semestriel(
|
||||
for key in request.form:
|
||||
code = request.form[key]
|
||||
# Codes d'UE
|
||||
m = re.match(r"^code_ue_(\d+)$", key)
|
||||
if m:
|
||||
ue_id = int(m.group(1))
|
||||
code_match = re.match(r"^code_ue_(\d+)$", key)
|
||||
if code_match:
|
||||
ue_id = int(code_match.group(1))
|
||||
dec_ue = decisions_ues.get(ue_id)
|
||||
if not dec_ue:
|
||||
raise ScoValueError(f"UE invalide ue_id={ue_id}")
|
||||
@ -285,7 +310,8 @@ def jury_but_semestriel(
|
||||
)
|
||||
db.session.commit()
|
||||
flash(
|
||||
f"autorisation de passage en S{formsemestre.semestre_id + 1} enregistrée"
|
||||
f"""autorisation de passage en S{formsemestre.semestre_id + 1
|
||||
} enregistrée"""
|
||||
)
|
||||
else:
|
||||
if est_autorise_a_passer:
|
||||
@ -442,11 +468,10 @@ def infos_fiche_etud_html(etudid: int) -> str:
|
||||
# temporaire quick & dirty: affiche le dernier
|
||||
try:
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestres_but[-1])
|
||||
if True: # len(deca.rcues_annee) > 0:
|
||||
return f"""<div class="infos_but">
|
||||
return f"""<div class="infos_but">
|
||||
{show_etud(deca, read_only=True)}
|
||||
</div>
|
||||
"""
|
||||
"""
|
||||
except ScoValueError:
|
||||
pass
|
||||
|
||||
|
@ -2,19 +2,17 @@
|
||||
|
||||
"""Décisions de jury (validations) des RCUE et années du BUT
|
||||
"""
|
||||
|
||||
import flask_sqlalchemy
|
||||
from sqlalchemy.sql import text
|
||||
from typing import Union
|
||||
|
||||
from app import db
|
||||
import flask_sqlalchemy
|
||||
|
||||
from app import db
|
||||
from app.models import CODE_STR_LEN
|
||||
from app.models.but_refcomp import ApcNiveau
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.ues import UniteEns
|
||||
from app.models.formations import Formation
|
||||
from app.models.formsemestre import FormSemestre
|
||||
from app.models.ues import UniteEns
|
||||
from app.scodoc import sco_codes_parcours as sco_codes
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
@ -63,7 +61,14 @@ class ApcValidationRCUE(db.Model):
|
||||
self.ue1}/{self.ue2}:{self.code!r}>"""
|
||||
|
||||
def __str__(self):
|
||||
return f"""décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}: {self.code}"""
|
||||
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}: {
|
||||
self.code} enregistrée le {self.date.strftime("%d/%m/%Y")}"""
|
||||
|
||||
def to_html(self) -> str:
|
||||
"description en HTML"
|
||||
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}:
|
||||
<b>{self.code}</b>
|
||||
<em>enregistrée le {self.date.strftime("%d/%m/%Y")}</em>"""
|
||||
|
||||
def niveau(self) -> ApcNiveau:
|
||||
"""Le niveau de compétence associé à cet RCUE."""
|
||||
@ -96,10 +101,6 @@ class RegroupementCoherentUE:
|
||||
dec_ue_2: "DecisionsProposeesUE",
|
||||
inscription_etat: str,
|
||||
):
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_but import ResultatsSemestreBUT
|
||||
|
||||
# from app.but.jury_but import DecisionsProposeesUE
|
||||
ue_1 = dec_ue_1.ue
|
||||
ue_2 = dec_ue_2.ue
|
||||
# Ordonne les UE dans le sens croissant (S1,S2) ou (S3,S4)...
|
||||
@ -296,7 +297,8 @@ class ApcValidationAnnee(db.Model):
|
||||
formsemestre = db.relationship("FormSemestre", backref="apc_validations_annees")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {self.id} {self.etud} BUT{self.ordre}/{self.annee_scolaire}:{self.code!r}>"
|
||||
return f"""<{self.__class__.__name__} {self.id} {self.etud
|
||||
} BUT{self.ordre}/{self.annee_scolaire}:{self.code!r}>"""
|
||||
|
||||
def __str__(self):
|
||||
return f"""décision sur année BUT{self.ordre} {self.annee_scolaire} : {self.code}"""
|
||||
@ -333,7 +335,8 @@ def dict_decision_jury(etud: Identite, formsemestre: FormSemestre) -> dict:
|
||||
titres_rcues.append(f"""pas de compétence: code {dec_rcue["code"]}""")
|
||||
else:
|
||||
titres_rcues.append(
|
||||
f"""{niveau["competence"]["titre"]} {niveau["ordre"]}: {dec_rcue["code"]}"""
|
||||
f"""{niveau["competence"]["titre"]} {niveau["ordre"]}: {
|
||||
dec_rcue["code"]}"""
|
||||
)
|
||||
decisions["descr_decisions_rcue"] = ", ".join(titres_rcues)
|
||||
decisions["descr_decisions_niveaux"] = (
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
.niveau_vide {
|
||||
background-color: rgb(195, 195, 195) !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.but_annee>* {
|
||||
@ -209,3 +210,7 @@ div.but_doc table tr td.amue {
|
||||
color: rgb(127, 127, 206);
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.but_niveau_rcue .scoplement {
|
||||
font-weight: normal;
|
||||
}
|
@ -630,7 +630,8 @@ def index_html():
|
||||
réfèrent.</p>
|
||||
|
||||
<ul>
|
||||
<li><a class="stdlink" href="formation_create" id="link-create-formation">Créer une formation</a>
|
||||
<li><a class="stdlink" href="formation_create" id="link-create-formation">Créer une
|
||||
formation</a>
|
||||
</li>
|
||||
<li><a class="stdlink" href="formation_import_xml_form">Importer une formation (xml)</a>
|
||||
</li>
|
||||
@ -656,8 +657,7 @@ def index_html():
|
||||
}">Liste des référentiels chargés</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
"""
|
||||
"""
|
||||
)
|
||||
|
||||
H.append(html_sco_header.sco_footer())
|
||||
@ -855,7 +855,7 @@ def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False):
|
||||
else:
|
||||
msg = "verrouillage"
|
||||
return scu.confirm_dialog(
|
||||
"<h2>Confirmer le %s du semestre ?</h2>" % msg,
|
||||
f"<h2>Confirmer le {msg} du semestre ?</h2>",
|
||||
helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées.
|
||||
Un semestre verrouillé peut cependant être déverrouillé facilement à tout moment
|
||||
(par son responsable ou un administrateur).
|
||||
@ -863,7 +863,11 @@ def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False):
|
||||
Le programme d'une formation qui a un semestre verrouillé ne peut plus être modifié.
|
||||
""",
|
||||
dest_url="",
|
||||
cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id,
|
||||
cancel_url=url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
),
|
||||
parameters={"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
||||
@ -940,21 +944,24 @@ def edit_enseignants_form(moduleimpl_id):
|
||||
H.append(
|
||||
f"""
|
||||
<li>{nom} (<a class="stdlink" href="{
|
||||
url_for('notes.edit_enseignants_form_delete', scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id, ens_id=ens["ens_id"])
|
||||
url_for('notes.edit_enseignants_form_delete',
|
||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id,
|
||||
ens_id=ens["ens_id"])
|
||||
}">supprimer</a>)
|
||||
</li>"""
|
||||
)
|
||||
H.append("</ul>")
|
||||
F = """<p class="help">Les enseignants d'un module ont le droit de
|
||||
F = f"""<p class="help">Les enseignants d'un module ont le droit de
|
||||
saisir et modifier toutes les notes des évaluations de ce module.
|
||||
</p>
|
||||
<p class="help">Pour changer le responsable du module, passez par la
|
||||
page "<a class="stdlink" href="formsemestre_editwithmodules?formation_id=%s&formsemestre_id=%s">Modification du semestre</a>", accessible uniquement au responsable de la formation (chef de département)
|
||||
page "<a class="stdlink" href="{
|
||||
url_for("notes.formsemestre_editwithmodules", scodoc_dept=g.scodoc_dept,
|
||||
formation_id=sem["formation_id"], formsemestre_id=M["formsemestre_id"])
|
||||
}">Modification du semestre</a>",
|
||||
accessible uniquement au responsable de la formation (chef de département)
|
||||
</p>
|
||||
""" % (
|
||||
sem["formation_id"],
|
||||
M["formsemestre_id"],
|
||||
)
|
||||
"""
|
||||
|
||||
modform = [
|
||||
("moduleimpl_id", {"input_type": "hidden"}),
|
||||
@ -1009,14 +1016,18 @@ def edit_enseignants_form(moduleimpl_id):
|
||||
or ens_id == M["responsable_id"]
|
||||
):
|
||||
H.append(
|
||||
'<p class="help">Enseignant %s déjà dans la liste !</p>' % ens_id
|
||||
f"""<p class="help">Enseignant {ens_id} déjà dans la liste !</p>"""
|
||||
)
|
||||
else:
|
||||
sco_moduleimpl.do_ens_create(
|
||||
{"moduleimpl_id": moduleimpl_id, "ens_id": ens_id}
|
||||
)
|
||||
return flask.redirect(
|
||||
"edit_enseignants_form?moduleimpl_id=%s" % moduleimpl_id
|
||||
url_for(
|
||||
"notes.edit_enseignants_form",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=moduleimpl_id,
|
||||
)
|
||||
)
|
||||
return header + "\n".join(H) + tf[1] + F + footer
|
||||
|
||||
@ -1448,7 +1459,7 @@ def edit_enseignants_form_delete(moduleimpl_id, ens_id: int):
|
||||
ok = True
|
||||
break
|
||||
if not ok:
|
||||
raise ScoValueError("invalid ens_id (%s)" % ens_id)
|
||||
raise ScoValueError(f"invalid ens_id ({ens_id})")
|
||||
ndb.SimpleQuery(
|
||||
"""DELETE FROM notes_modules_enseignants
|
||||
WHERE moduleimpl_id = %(moduleimpl_id)s
|
||||
@ -1456,7 +1467,13 @@ def edit_enseignants_form_delete(moduleimpl_id, ens_id: int):
|
||||
""",
|
||||
{"moduleimpl_id": moduleimpl_id, "ens_id": ens_id},
|
||||
)
|
||||
return flask.redirect("edit_enseignants_form?moduleimpl_id=%s" % moduleimpl_id)
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.edit_enseignants_form",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=moduleimpl_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# --- Gestion des inscriptions aux semestres
|
||||
@ -2403,10 +2420,16 @@ def formsemestre_validation_but(
|
||||
|
||||
warning = ""
|
||||
if len(deca.niveaux_competences) != len(deca.decisions_rcue_by_niveau):
|
||||
warning += f"""<div class="warning">Attention: {len(deca.niveaux_competences)}
|
||||
niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.</div>"""
|
||||
if deca.parcour is None:
|
||||
warning += """<div class="warning">L'étudiant n'est pas inscrit à un parcours.</div>"""
|
||||
if deca.a_cheval:
|
||||
warning += f"""<div class="warning">Attention: regroupements RCUE
|
||||
entre années (redoublement).</div>"""
|
||||
else:
|
||||
warning += f"""<div class="warning">Attention: {len(deca.niveaux_competences)}
|
||||
niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.</div>"""
|
||||
if (deca.parcour is None) and len(formsemestre.parcours) > 0:
|
||||
warning += (
|
||||
"""<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?")
|
||||
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_impair.semestre_id}"""
|
||||
|
Loading…
Reference in New Issue
Block a user