From cf18520e9c5de95012f888e8d8ccff058965f45d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 8 Jan 2023 15:36:05 -0300 Subject: [PATCH] =?UTF-8?q?Jury=20BUT:=20am=C3=A9lioration=20gestion=20red?= =?UTF-8?q?oublants=20+=20#547=20(WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/but/jury_but.py | 19 ++++++++-- app/but/jury_but_view.py | 59 +++++++++++++++----------------- app/models/but_validations.py | 5 +-- app/scodoc/sco_codes_parcours.py | 14 ++++++++ app/static/css/jury_but.css | 13 +++++-- app/static/js/jury_but.js | 10 +++++- app/views/notes.py | 31 ++++++++++------- 7 files changed, 99 insertions(+), 52 deletions(-) diff --git a/app/but/jury_but.py b/app/but/jury_but.py index 86a5e4a9..e01703ad 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -350,8 +350,9 @@ class DecisionsProposeesAnnee(DecisionsProposees): ) "vrai si l'année est réussie, tous niveaux validables ou validés par le jury" self.valide_moitie_rcue = self.nb_validables > (self.nb_competences // 2) - "Peut passer si plus de la moitié validables et tous > 8" + "Vrai si plus de la moitié des RCUE validables" self.passage_de_droit = self.valide_moitie_rcue and (self.nb_rcues_under_8 == 0) + "Vrai si peut passer dans l'année BUT suivante: plus de la moitié validables et tous > 8" # XXX TODO ajouter condition pour passage en S5 # Enfin calcule les codes des UE: @@ -752,8 +753,9 @@ class DecisionsProposeesAnnee(DecisionsProposees): pour cette année: décisions d'UE, de RCUE, d'année, et autorisations d'inscription émises. Efface même si étudiant DEM ou DEF. + Si à cheval, n'efface que pour le semestre d'origine du deca. """ - if only_one_sem: + if only_one_sem or self.a_cheval: # N'efface que les autorisations venant de ce semestre, # et les validations de ses UEs ScolarAutorisationInscription.delete_autorisation_etud( @@ -906,6 +908,19 @@ class DecisionsProposeesRCUE(DecisionsProposees): or dec_prop_annee.formsemestre_pair.modalite == "EXT" ): self.codes.insert(0, sco_codes.ADM) + # S'il y a une décision enregistrée: si elle est plus favorable que celle que l'on + # proposerait, la place en tête. + # Sinon, la place en seconde place + if self.code_valide and self.code_valide != self.codes[0]: + code_default = self.codes[0] + if self.code_valide in self.codes: + self.codes.remove(self.code_valide) + if sco_codes.BUT_CODES_ORDERED.get( + self.code_valide, 0 + ) > sco_codes.BUT_CODES_ORDERED.get(code_default, 0): + self.codes.insert(0, self.code_valide) + else: + self.codes.insert(1, self.code_valide) def record(self, code: str, no_overwrite=False): """Enregistre le code""" diff --git a/app/but/jury_but_view.py b/app/but/jury_but_view.py index 24224d62..d08329ea 100644 --- a/app/but/jury_but_view.py +++ b/app/but/jury_but_view.py @@ -41,32 +41,21 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str: Si pas read_only, menus sélection codes jury. """ H = [] - if deca.code_valide and not read_only: - erase_span = f"""effacer décisions""" - else: - erase_span = "" H.append("""
""") - 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") - } - ({'non ' if deca.code_valide is None else ''}enregistrée) - {erase_span} -
+ 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") + } + ({'non ' if deca.code_valide is None else ''}enregistrée) +
""" - ) - div_explanation = f"""
{deca.explanation}
""" - else: - H.append("""
Pas de décision annuelle (sem. impair).
""") - div_explanation = "" + ) + div_explanation = f"""
{deca.explanation}
""" + H.append("""
""") formsemestre_1 = deca.formsemestre_impair @@ -245,9 +234,16 @@ def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str: else "" ) + # 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)}
@@ -351,7 +347,7 @@ def jury_but_semestriel( warning = "" H = [ html_sco_header.sco_header( - page_title="Validation BUT", + page_title=f"Validation BUT S{formsemestre.semestre_id}", formsemestre_id=formsemestre.id, etudid=etud.id, cssstyles=("css/jury_but.css",), @@ -376,21 +372,21 @@ def jury_but_semestriel( {warning}
-
+ """, ] if (not read_only) and any([dec.code_valide for dec in decisions_ues.values()]): erase_span = f"""effacer les décisions enregistrées""" + etudid=etud.id, only_one_sem=1) + }" class="stdlink">effacer les décisions enregistrées""" else: erase_span = "Cet étudiant n'a aucune décision enregistrée pour ce semestre." H.append( f"""
- {erase_span}
Unités d'enseignement de S{formsemestre.semestre_id}:
""" @@ -447,9 +443,10 @@ def jury_but_semestriel( else: H.append("""
dernier semestre de la formation.
""") H.append( - """ + f"""
- + + {erase_span}
""" ) diff --git a/app/models/but_validations.py b/app/models/but_validations.py index ad191d29..ab820bc3 100644 --- a/app/models/but_validations.py +++ b/app/models/but_validations.py @@ -180,8 +180,9 @@ class RegroupementCoherentUE: return self.query_validations().count() > 0 def est_compensable(self): - """Vrai si ce RCUE est validable par compensation - c'est à dire que sa moyenne est > 10 avec une UE < 10 + """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) diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py index 299ccdde..7d90edbc 100644 --- a/app/scodoc/sco_codes_parcours.py +++ b/app/scodoc/sco_codes_parcours.py @@ -205,6 +205,20 @@ BUT_CODES_PASSAGE = { PAS1NCI, ATJ, } +# les codes, du plus "défavorable" à l'étudiant au plus favorable: +# (valeur par défaut 0) +BUT_CODES_ORDERED = { + "NAR": 0, + "DEF": 0, + "AJ": 10, + "ATJ": 20, + "CMP": 50, + "ADC": 50, + "PASD": 50, + "PAS1NCI": 60, + "ADJ": 100, + "ADM": 100, +} def code_semestre_validant(code: str) -> bool: diff --git a/app/static/css/jury_but.css b/app/static/css/jury_but.css index 955aed94..f865400a 100644 --- a/app/static/css/jury_but.css +++ b/app/static/css/jury_but.css @@ -22,7 +22,7 @@ margin-left: 32px; display: inline-grid; grid-template-columns: repeat(4, auto); - gap: 4px; + gap: 8px; } .but_annee_caption { @@ -143,8 +143,14 @@ div.but_code { div.but_niveau_ue.recorded, div.but_niveau_rcue.recorded { - border-color: rgb(136, 252, 136); - border-width: 2px; + border-color: rgb(0, 169, 0); + border-width: 3px; +} + +div.but_niveau_ue.recorded_different, +div.but_niveau_rcue.recorded_different { + box-shadow: 0 0 0 3px red; + outline: dashed 3px rgb(0, 169, 0); } div.but_niveau_ue.annee_prec { @@ -160,6 +166,7 @@ div.but_buttons { } div.but_buttons span { + margin-left: 16px; margin-right: 16px; } diff --git a/app/static/js/jury_but.js b/app/static/js/jury_but.js index c90f95d6..54d28a84 100644 --- a/app/static/js/jury_but.js +++ b/app/static/js/jury_but.js @@ -63,6 +63,8 @@ $(function () { // ----- Etat du formulaire jury pour éviter sortie sans enregistrer let FORM_STATE = ""; +let IS_SUBMITTING = false; + // Une chaine décrivant l'état du form function get_form_state() { let codes = []; @@ -73,13 +75,19 @@ function get_form_state() { $('document').ready(function () { FORM_STATE = get_form_state(); + document.querySelector("form#jury_but").addEventListener('submit', jury_form_submit); }); function is_modified() { return FORM_STATE != get_form_state(); } + +function jury_form_submit(event) { + IS_SUBMITTING = true; +} + window.addEventListener("beforeunload", function (e) { - if (is_modified()) { + if ((!IS_SUBMITTING) && is_modified()) { var confirmationMessage = 'Changements non enregistrés !'; (e || window.event).returnValue = confirmationMessage; return confirmationMessage; diff --git a/app/views/notes.py b/app/views/notes.py index 48fb28ae..06d62445 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -2327,17 +2327,17 @@ def formsemestre_validation_but( # provisoires avec NEXT et PREV try: etudid = int(etudid) - except: + except ValueError: abort(404, "invalid etudid") read_only = not sco_permissions_check.can_validate_sem(formsemestre_id) # --- Navigation - prev = f"""{scu.EMO_PREV_ARROW} précédent """ - next = f"""suivant {scu.EMO_NEXT_ARROW} @@ -2345,7 +2345,7 @@ def formsemestre_validation_but( navigation_div = f"""
""" H = [ html_sco_header.sco_header( - page_title="Validation BUT", + page_title=f"Validation BUT S{formsemestre.semestre_id}", formsemestre_id=formsemestre_id, etudid=etudid, cssstyles=("css/jury_but.css",), javascripts=("js/jury_but.js",), ), - f""" -
+ """
""", ] @@ -2401,7 +2400,6 @@ def formsemestre_validation_but( deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre) if len(deca.rcues_annee) == 0: - # raise ScoValueError("année incomplète: pas de jury BUT annuel possible") return jury_but_view.jury_but_semestriel( formsemestre, etud, read_only, navigation_div=navigation_div ) @@ -2421,7 +2419,7 @@ def formsemestre_validation_but( warning = "" if len(deca.niveaux_competences) != len(deca.decisions_rcue_by_niveau): if deca.a_cheval: - warning += f"""
Attention: regroupements RCUE + warning += """
Attention: regroupements RCUE entre années (redoublement).
""" else: warning += f"""
Attention: {len(deca.niveaux_competences)} @@ -2454,7 +2452,7 @@ def formsemestre_validation_but( {warning}
- + """ ) @@ -2467,6 +2465,10 @@ def formsemestre_validation_but( Les champs entourés en vert sont enregistrés.
""" ) else: + erase_span = f"""effacer décisions""" H.append( f"""
@@ -2477,7 +2479,8 @@ def formsemestre_validation_but(
- + + {erase_span}
""" ) @@ -2790,7 +2793,9 @@ def formsemestre_jury_but_erase( explanation=f"""Les validations d'UE et autorisations de passage du semestre S{formsemestre.semestre_id} seront effacées.""" if only_one_sem - else """Les validations de toutes les UE, RCUE (compétences) et année seront effacées.""", + else """Les validations de toutes les UE, RCUE (compétences) et année seront effacées. + Les décisions de l'année scolaire précédente ne seront pas modifiées. + """, cancel_url=dest_url, )