##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Jury BUT: affichage/formulaire
"""
import re
import numpy as np
import flask
from flask import flash, render_template, url_for
from flask import g, request
from app import db
from app.but import jury_but
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,
UniteEns,
ScolarAutorisationInscription,
ScolarFormSemestreValidation,
ScolarNews,
)
from app.models.config import ScoDocSiteConfig
from app.scodoc import html_sco_header
from app.scodoc import codes_cursus as sco_codes
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu
def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
"""Affichage des décisions annuelles BUT
Si pas read_only, menus sélection codes jury.
"""
H = []
if deca.jury_annuel:
H.append(
f"""
Décision de jury pour l'année : {
_gen_but_select("code_annee", deca.codes, deca.code_valide,
disabled=True, klass="manual")
}
({deca.code_valide or 'non'} enregistrée)
"""
)
formsemestre_1 = deca.formsemestre_impair
formsemestre_2 = deca.formsemestre_pair
# Ordonne selon les dates des 2 semestres considérés (pour les redoublants à cheval):
reverse_semestre = (
deca.formsemestre_pair
and deca.formsemestre_impair
and deca.formsemestre_pair.date_debut < deca.formsemestre_impair.date_debut
)
if reverse_semestre:
formsemestre_1, formsemestre_2 = formsemestre_2, formsemestre_1
H.append(
f"""
Niveaux de compétences et unités d'enseignement du BUT{deca.annee_but}visualiser son cursus
{deca.explanation}
{"S" +str(formsemestre_1.semestre_id)
if formsemestre_1 else "-"}
{formsemestre_1.annee_scolaire_str()
if formsemestre_1 else ""}
{"S"+str(formsemestre_2.semestre_id)
if formsemestre_2 else "-"}
{formsemestre_2.annee_scolaire_str()
if formsemestre_2 else ""}
RCUE
"""
)
for dec_rcue in deca.get_decisions_rcues_annee():
rcue = dec_rcue.rcue
niveau = rcue.niveau
H.append(
f"""
{niveau.competence.titre}
"""
)
ue_impair, ue_pair = rcue.ue_1, rcue.ue_2
# Les UEs à afficher : on regarde si read only et si dispense (non ré-inscription à l'UE)
# tuples (UniteEns, read_only, dispense)
ues_ro_dispense = [
(
ue_impair,
rcue.ue_cur_impair is None,
deca.res_impair
and ue_impair
and (deca.etud.id, ue_impair.id) in deca.res_impair.dispense_ues,
),
(
ue_pair,
rcue.ue_cur_pair is None,
deca.res_pair
and ue_pair
and (deca.etud.id, ue_pair.id) in deca.res_pair.dispense_ues,
),
]
# Ordonne selon les dates des 2 semestres considérés:
if reverse_semestre:
ues_ro_dispense[0], ues_ro_dispense[1] = (
ues_ro_dispense[1],
ues_ro_dispense[0],
)
# Colonnes d'UE:
for ue, ue_read_only, ue_dispense in ues_ro_dispense:
if ue:
H.append(
_gen_but_niveau_ue(
ue,
deca.decisions_ues[ue.id],
disabled=read_only or ue_read_only,
annee_prec=ue_read_only,
niveau_id=ue.niveau_competence.id,
ue_dispense=ue_dispense,
)
)
else:
H.append("""""")
# Colonne RCUE
H.append(_gen_but_rcue(dec_rcue, niveau))
H.append("
") # but_annee
return "\n".join(H)
def _gen_but_select(
name: str,
codes: list[str],
code_valide: str,
disabled: bool = False,
klass: str = "",
data: dict = None,
code_valide_label: str = "",
) -> str:
"Le menu html select avec les codes"
# if disabled: # mauvaise idée car le disabled est traité en JS
# return f"""
{code_valide}
"""
data = data or {}
options_htm = "\n".join(
[
f""""""
for code in codes
]
)
return f"""
"""
def _gen_but_niveau_ue(
ue: UniteEns,
dec_ue: DecisionsProposeesUE,
disabled: bool = False,
annee_prec: bool = False,
niveau_id: int = None,
ue_dispense: bool = False,
) -> str:
if dec_ue.ue_status and dec_ue.ue_status["is_capitalized"]:
moy_ue_str = f"""{
scu.fmt_note(dec_ue.moy_ue_with_cap)}"""
if ue_dispense:
etat_en_cours = """Non (ré)inscrit à cette UE"""
else:
etat_en_cours = f"""UE en cours
{ "sans notes" if np.isnan(dec_ue.moy_ue)
else
("avec moyenne " + scu.fmt_note(dec_ue.moy_ue) + "")
}
"""
scoplement = f"""
UE {ue.acronyme} capitalisée le {dec_ue.ue_status["event_date"].strftime("%d/%m/%Y")}
UE {ue.acronyme} antérieure validée {dec_ue.validation.code}
le {dec_ue.validation.event_date.strftime("%d/%m/%Y")}
Non reprise dans l'année en cours
"""
else:
moy_ue_str = """-"""
scoplement = """
Pas d'UE en cours ou validée dans cette compétence de ce côté.
"""
else:
moy_ue_str = f"""{scu.fmt_note(dec_ue.moy_ue)}"""
if dec_ue.code_valide:
date_str = (
f"""enregistré le {dec_ue.validation.event_date.strftime("%d/%m/%Y")}
à {dec_ue.validation.event_date.strftime("%Hh%M")}
"""
if dec_ue.validation and dec_ue.validation.event_date
else ""
)
scoplement = f"""
Code {dec_ue.code_valide} {date_str}
"""
else:
if dec_ue.ue_status and dec_ue.ue_status["was_capitalized"]:
scoplement = """
UE déjà capitalisée avec résultat moins favorable.
"""
else:
scoplement = ""
ue_class = "" # '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"""
{ue.acronyme}
{moy_ue_str}
{scoplement}
{
_gen_but_select("code_ue_"+str(ue.id),
dec_ue.codes,
dec_ue.code_valide,
disabled=disabled,
klass=f"code_ue ue_rcue_{niveau_id}" if not disabled else ""
)
}
"""
def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
if dec_rcue is None or not dec_rcue.rcue.complete:
return """
Pas de RCUE (UE non capitalisée ?)
"""
code_propose_menu = dec_rcue.code_valide # le code enregistré
code_valide_label = code_propose_menu
if dec_rcue.validation:
if dec_rcue.code_valide == dec_rcue.codes[0]:
descr_validation = dec_rcue.validation.html()
else: # on une validation enregistrée différence de celle proposée
descr_validation = f"""Décision recommandée: {dec_rcue.codes[0]}.
Il y avait {dec_rcue.validation.html()}"""
if (
sco_codes.BUT_CODES_ORDER[dec_rcue.codes[0]]
> sco_codes.BUT_CODES_ORDER[dec_rcue.code_valide]
):
code_propose_menu = dec_rcue.codes[0]
code_valide_label = (
f"{dec_rcue.codes[0]} (actuel {dec_rcue.code_valide})"
)
scoplement = f"""
{descr_validation}
"""
else:
scoplement = "" # "pas de validation"
# Déjà enregistré ?
niveau_rcue_class = ""
if dec_rcue.code_valide is not None and dec_rcue.codes:
if dec_rcue.code_valide == dec_rcue.codes[0]:
niveau_rcue_class = "recorded"
else:
niveau_rcue_class = "recorded_different"
return f"""