diff --git a/app/api/jury.py b/app/api/jury.py index 6103d11649..6f0710770d 100644 --- a/app/api/jury.py +++ b/app/api/jury.py @@ -114,16 +114,16 @@ def _validation_ue_delete(etudid: int, validation_id: int): # rattachées à un formsemestre) if not g.scodoc_dept: # accès API if not current_user.has_permission(Permission.ScoEtudInscrit): - return json_error(403, "validation_delete: non autorise") + return json_error(403, "opération non autorisée (117)") else: if validation.formsemestre: if ( validation.formsemestre.dept_id != g.scodoc_dept_id ) or not validation.formsemestre.can_edit_jury(): - return json_error(403, "validation_delete: non autorise") + return json_error(403, "opération non autorisée (123)") elif not current_user.has_permission(Permission.ScoEtudInscrit): # Validation non rattachée à un semestre: on doit être chef - return json_error(403, "validation_delete: non autorise") + return json_error(403, "opération non autorisée (126)") log(f"validation_ue_delete: etuid={etudid} {validation}") db.session.delete(validation) diff --git a/app/models/but_validations.py b/app/models/but_validations.py index aedf4cbaf9..fcab132bd0 100644 --- a/app/models/but_validations.py +++ b/app/models/but_validations.py @@ -158,8 +158,16 @@ class ApcValidationAnnee(db.Model): if self.date else "(sans date)" ) + link = ( + self.formsemestre.html_link_status( + label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}", + title=self.formsemestre.titre_annee(), + ) + if self.formsemestre + else "externe/antérieure" + ) return f"""Validation année BUT{self.ordre} émise par - {self.formsemestre.html_link_status() if self.formsemestre else "-"} + {link} : {self.code} {date_str} """ diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index cd296353f6..64668fa168 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -163,12 +163,12 @@ class FormSemestre(db.Model): def __repr__(self): return f"<{self.__class__.__name__} {self.id} {self.titre_annee()}>" - def html_link_status(self) -> str: + def html_link_status(self, label=None, title=None) -> str: "html link to status page" return f"""{self.titre_mois()} + }" title="{title or ''}">{label or self.titre_mois()} """ @classmethod diff --git a/app/models/validations.py b/app/models/validations.py index 9e2cf5e27d..91f17f605a 100644 --- a/app/models/validations.py +++ b/app/models/validations.py @@ -94,6 +94,14 @@ class ScolarFormSemestreValidation(db.Model): if self.moy_ue is not None else "" ) + link = ( + self.formsemestre.html_link_status( + label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}", + title=self.formsemestre.titre_annee(), + ) + if self.formsemestre + else "externe/antérieure" + ) return f"""Validation {'externe' if self.is_external else ""} de l'UE {self.ue.acronyme} @@ -101,9 +109,7 @@ class ScolarFormSemestreValidation(db.Model): + ", ".join([p.code for p in self.ue.parcours])) + "" if self.ue.parcours else ""} - de {self.ue.formation.acronyme} - {("émise par " + self.formsemestre.html_link_status()) - if self.formsemestre else "externe/antérieure"} + {("émise par " + link)} : {self.code}{moyenne} le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")} """ @@ -149,10 +155,16 @@ class ScolarAutorisationInscription(db.Model): def html(self) -> str: "Affichage html" + link = ( + self.origin_formsemestre.html_link_status( + label=f"{self.origin_formsemestre.titre_formation(with_sem_idx=1)}", + title=self.origin_formsemestre.titre_annee(), + ) + if self.origin_formsemestre + else "externe/antérieure" + ) return f"""Autorisation de passage vers S{self.semestre_id} émise par - {self.origin_formsemestre.html_link_status() - if self.origin_formsemestre - else "-"} + {link} le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")} """ diff --git a/app/scodoc/codes_cursus.py b/app/scodoc/codes_cursus.py index 85d14b957b..dff4ead7b3 100644 --- a/app/scodoc/codes_cursus.py +++ b/app/scodoc/codes_cursus.py @@ -196,6 +196,8 @@ CODES_SEM_ATTENTES = {ATT, ATB, ATJ} # semestre en attente CODES_SEM_REO = {NAR} # reorientation +# Les codes d'UEs +CODES_JURY_UE = {ADM, CMP, ADJ, ADJR, ADSUP, AJ, ATJ, RAT, DEF, ABAN, DEM, UEBSL} CODES_UE_VALIDES_DE_DROIT = {ADM, CMP} # validation "de droit" CODES_UE_VALIDES = CODES_UE_VALIDES_DE_DROIT | {ADJ, ADJR, ADSUP} "UE validée" diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index 6234e5f53f..f8ce984713 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -398,7 +398,7 @@ def formsemestre_validation_etud( selected_choice = choice break if not selected_choice: - raise ValueError("code choix invalide ! (%s)" % codechoice) + raise ValueError(f"code choix invalide ! ({codechoice})") # Se.valide_decision(selected_choice) # enregistre return _redirect_valid_choice( @@ -1132,6 +1132,7 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite }, ) ) + ue_codes = sorted(codes_cursus.CODES_JURY_UE) form_descr += [ ( "date", @@ -1152,6 +1153,18 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite "title": "Moyenne (/20) obtenue dans cette UE:", }, ), + ( + "code_jury", + { + "input_type": "menu", + "title": "Code jury", + "explanation": " code donné par le jury (ADM si validée normalement)", + "allow_null": True, + "allowed_values": [""] + ue_codes, + "labels": ["-"] + ue_codes, + "default": ADM, + }, + ), ] tf = TrivialFormulator( request.base_url, @@ -1173,17 +1186,20 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite de {etud.html_link_fiche()} -
Utiliser cette page pour enregistrer une UE validée antérieurement, +
Utiliser cette page pour enregistrer des UEs validées antérieurement, dans un semestre hors ScoDoc.
-Les UE validées dans ScoDoc sont déjà - automatiquement prises en compte. Cette page n'est utile que pour les étudiants ayant - suivi un début de cursus dans un autre établissement, ou bien dans un semestre géré - sans ScoDoc et qui redouble ce semestre - (pour les semestres précédents gérés avec ScoDoc, - passer par la page jury normale)). +
Les UE validées dans ScoDoc sont + automatiquement prises en compte. +
+Cette page est surtout utile pour les étudiants ayant + suivi un début de cursus dans un autre établissement, ou qui + ont suivi une UE à l'étranger ou dans un semestre géré sans ScoDoc. +
+Pour les semestres précédents gérés avec ScoDoc, passer par la page jury normale. +
+Notez que l'UE est validée, avec enregistrement immédiat de la décision et + l'attribution des ECTS si le code jury est validant (ADM).
-Notez que l'UE est validée (ADM), avec enregistrement immédiat de la décision et - l'attribution des ECTS.
On ne peut valider ici que les UEs du cursus {formation.titre}
{_get_etud_ue_cap_html(etud, formsemestre)} @@ -1221,12 +1237,16 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite else: semestre_id = None + if tf[2]["code_jury"] not in CODES_JURY_UE: + flash("Code UE invalide") + return flask.redirect(dest_url) do_formsemestre_validate_previous_ue( formsemestre, etud.id, tf[2]["ue_id"], tf[2]["moy_ue"], tf[2]["date"], + code=tf[2]["code_jury"], semestre_id=semestre_id, ) flash("Validation d'UE enregistrée") @@ -1258,7 +1278,7 @@ def _get_etud_ue_cap_html(etud: Identite, formsemestre: FormSemestre) -> str:" + grlink + " | " + menu + " |