############################################################################## # 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")}
{ etat_en_cours }
""" elif dec_ue.formsemestre is None: # Validation d'UE antérieure (semestre hors année scolaire courante) if dec_ue.validation: moy_ue_str = f"""{scu.fmt_note(dec_ue.validation.moy_ue)}""" scoplement = f"""
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"""
{scu.fmt_note(dec_rcue.rcue.moy_rcue)}
{scoplement}
{_gen_but_select("code_rcue_"+str(niveau.id), dec_rcue.codes, code_propose_menu, disabled=True, klass="manual code_rcue", data = { "niveau_id" : str(niveau.id)}, code_valide_label = code_valide_label, )}
""" # ------------- def infos_fiche_etud_html(etudid: int) -> str: """Section html pour fiche etudiant provisoire pour BUT 2022 """ etud = Identite.get_etud(etudid) inscriptions = ( FormSemestreInscription.query.join(FormSemestreInscription.formsemestre) .filter( FormSemestreInscription.etudid == etud.id, ) .order_by(FormSemestre.date_debut) ) formsemestres_but = [ i.formsemestre for i in inscriptions if i.formsemestre.formation.is_apc() ] if len(formsemestres_but) == 0: return "" # temporaire quick & dirty: affiche le dernier try: deca = DecisionsProposeesAnnee(etud, formsemestres_but[-1]) return f"""
{show_etud(deca, read_only=True)}
""" except ScoValueError: pass return ""