diff --git a/app/but/cursus_but.py b/app/but/cursus_but.py index 3a63a4db5..8ed3fd782 100644 --- a/app/but/cursus_but.py +++ b/app/but/cursus_but.py @@ -18,6 +18,7 @@ from collections.abc import Iterable from operator import attrgetter from flask import g, url_for +from flask_sqlalchemy.query import Query from app import db, log from app.comp.res_but import ResultatsSemestreBUT @@ -393,6 +394,26 @@ def but_ects_valides( et ne les compte qu'une fois même en cas de redoublement avec re-validation. Si annees_but est spécifié, un iterable "BUT1, "BUT2" par exemple, ne prend que ces années. """ + validations = but_validations_ues(etud, referentiel_competence_id, annees_but) + ects_dict = {} + for v in validations: + key = (v.ue.semestre_idx, v.ue.niveau_competence.id) + if v.code in CODES_UE_VALIDES: + ects_dict[key] = v.ue.ects + + return int(sum(ects_dict.values())) if ects_dict else 0 + + +def but_validations_ues( + etud: Identite, + referentiel_competence_id: int, + annees_but: None | Iterable[str] = None, +) -> Query: + """Query les validations d'UEs pour cet étudiant + dans des UEs appartenant à ce référentiel de compétence + et en option pour les années BUT indiquées. + annees_but : None (tout) ou liste [ "BUT1", ... ] + """ validations = ( ScolarFormSemestreValidation.query.filter_by(etudid=etud.id) .filter(ScolarFormSemestreValidation.ue_id != None) @@ -403,18 +424,10 @@ def but_ects_valides( if annees_but: validations = validations.filter(ApcNiveau.annee.in_(annees_but)) # Et restreint au référentiel de compétence: - validations = validations.join(ApcCompetence).filter_by( + return validations.join(ApcCompetence).filter_by( referentiel_id=referentiel_competence_id ) - ects_dict = {} - for v in validations: - key = (v.ue.semestre_idx, v.ue.niveau_competence.id) - if v.code in CODES_UE_VALIDES: - ects_dict[key] = v.ue.ects - - return int(sum(ects_dict.values())) if ects_dict else 0 - def etud_ues_de_but1_non_validees( etud: Identite, formation: Formation, parcour: ApcParcours diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 4d23118ee..8ac11d39f 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -845,11 +845,11 @@ class FormSemestre(models.ScoDocModel): else: return ", ".join([u.get_nomcomplet() for u in self.responsables]) - def est_responsable(self, user: User): + def est_responsable(self, user: User) -> bool: "True si l'user est l'un des responsables du semestre" return user.id in [u.id for u in self.responsables] - def est_chef_or_diretud(self, user: User = None): + def est_chef_or_diretud(self, user: User | None = None) -> bool: "Vrai si utilisateur (par def. current) est admin, chef dept ou responsable du semestre" user = user or current_user return user.has_permission(Permission.EditFormSemestre) or self.est_responsable( @@ -867,7 +867,7 @@ class FormSemestre(models.ScoDocModel): return True # typiquement admin, chef dept return self.est_responsable(user) - def can_edit_jury(self, user: User = None): + def can_edit_jury(self, user: User | None = None): """Vrai si utilisateur (par def. current) peut saisir decision de jury dans ce semestre: vérifie permission et verrouillage. """ diff --git a/app/models/validations.py b/app/models/validations.py index 8595b3d2f..e54bc6283 100644 --- a/app/models/validations.py +++ b/app/models/validations.py @@ -2,12 +2,15 @@ """Notes, décisions de jury """ +from flask_sqlalchemy.query import Query from app import db from app import log from app.models import SHORT_STR_LEN from app.models import CODE_STR_LEN from app.models.events import Scolog +from app.models.formations import Formation +from app.models.ues import UniteEns from app.scodoc import sco_cache from app.scodoc import sco_utils as scu from app.scodoc.codes_cursus import CODES_UE_VALIDES @@ -113,6 +116,7 @@ class ScolarFormSemestreValidation(db.Model): if self.ue.parcours else ""} {("émise par " + link)} : {self.code}{moyenne} + {self.ue.ects:g} ECTS le {self.event_date.strftime(scu.DATEATIME_FMT)} """ else: @@ -131,6 +135,27 @@ class ScolarFormSemestreValidation(db.Model): else 0.0 ) + @classmethod + def validations_ues( + cls, etud: "Identite", formation_code: str | None = None + ) -> Query: + """Query les validations d'UE pour cet étudiant dans des UEs de formations + du code indiqué, ou toutes si le formation_code est None. + """ + from app.models.formsemestre import FormSemestre + + query = ( + ScolarFormSemestreValidation.query.filter_by(etudid=etud.id) + .filter(ScolarFormSemestreValidation.ue_id != None) + .join(UniteEns) + .join(FormSemestre, ScolarFormSemestreValidation.formsemestre) + ) + if formation_code is not None: + query = query.join(Formation).filter_by(formation_code=formation_code) + return query.order_by( + FormSemestre.semestre_id, UniteEns.numero, UniteEns.acronyme + ) + class ScolarAutorisationInscription(db.Model): """Autorisation d'inscription dans un semestre""" diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index 1598abc55..e685fbc7e 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -31,7 +31,7 @@ import time import flask from flask import url_for, flash, g, request -from flask_login import current_user +from flask.templating import render_template import sqlalchemy as sa from app.models import Identite, Evaluation @@ -64,7 +64,6 @@ from app.scodoc import sco_cursus_dut from app.scodoc.sco_cursus_dut import etud_est_inscrit_ue from app.scodoc import sco_preferences from app.scodoc import sco_pv_dict -from app.scodoc.sco_permissions import Permission # ------------------------------------------------------------------------------------ @@ -1249,7 +1248,7 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite
On ne peut valider ici que les UEs du cursus {formation.titre}
- {_get_etud_ue_cap_html(etud, formsemestre)} + {_get_etud_ue_validations_html(etud, formsemestre)}Étudiant{etud.e} non inscrit{etud.e}"""]
@@ -331,6 +337,7 @@ def fiche_etud(etudid=None):
info["liste_inscriptions"] = "\n".join(l)
info["link_bul_pdf"] = ""
info["link_inscrire_ailleurs"] = ""
+ info["link_bilan_ects"] = ""
# Liste des annotations
html_annotations_list = "\n".join(
@@ -433,7 +440,9 @@ def fiche_etud(etudid=None):
"inscriptions_mkup"
] = f"""Bilan des ECTS de {{etud.html_link_fiche()|safe}}
+
+
+ {% for validation in validations %}
+
+
+ {% if total_ects %}
+