+ Validations de {{sco.etud.html_link_fiche()|safe}}
+ {% if parcour %}
+ parcours {{parcour.code}} « {{parcour.libelle}} »
+ {% else %}
+ non inscrit à un parcours de la spécialité
+ {% endif %}
+
+
+{% for comp in competences_parcour %}
+{% set color_idx = 1 + loop.index0 % 6 %}
+
Cette page montre les validations d'UEs et de niveaux de compétences (RCUEs)
+de {{sco.etud.html_link_fiche()|safe}}
+dans le
+{%if parcour %}
+parcours {{parcour.code}}
+{% else %}
+tronc commun
+{% endif %}
+du référentiel de compétence {{formation.referentiel_competence.specialite}}
+
+
+
Seuls les UEs et niveaux de ce référentiel sont montrés. Si le référentiel a
+changé, enregistrer des validations "antérieures".
+
+
+
Le symbole TC désigne un niveau du tronc commun
+(c'est à dire présent dans tous les parcours de la spécialité).
+
+{% if edit %}
+
Les validations sont enregistrées au fur et à mesure.
+{% endif %}
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/views/__init__.py b/app/views/__init__.py
index 9d342dbbf..26a241601 100644
--- a/app/views/__init__.py
+++ b/app/views/__init__.py
@@ -50,7 +50,7 @@ def close_dept_db_connection(arg):
class ScoData:
"""Classe utilisée pour passer des valeurs aux vues (templates)"""
- def __init__(self, etud=None, formsemestre=None):
+ def __init__(self, etud: Identite = None, formsemestre: FormSemestre = None):
# Champs utilisés par toutes les pages ScoDoc (sidebar, en-tête)
self.Permission = Permission
self.scu = scu
@@ -96,6 +96,7 @@ class ScoData:
self.sem_menu_bar = sco_formsemestre_status.formsemestre_status_menubar(
self.sem
)
+ self.formsemestre = formsemestre
# --- Préférences
# prefs fallback to global pref if sem is None:
if formsemestre:
diff --git a/app/views/but_formation.py b/app/views/but_formation.py
index d15d90c87..64e4d90af 100644
--- a/app/views/but_formation.py
+++ b/app/views/but_formation.py
@@ -30,7 +30,8 @@ Emmanuel Viennet, 2023
from flask import flash, g, redirect, render_template, request, url_for
-from app import db, log
+from app import db
+from app.but import cursus_but, validations_view
from app.decorators import (
scodoc,
permission_required,
@@ -39,16 +40,16 @@ from app.decorators import (
from app.forms.formation.ue_parcours_ects import UEParcoursECTSForm
from app.models import (
- ApcCompetence,
- ApcNiveau,
ApcParcours,
ApcReferentielCompetences,
Formation,
+ FormSemestre,
+ Identite,
UniteEns,
)
from app.scodoc.codes_cursus import UE_STANDARD
from app.scodoc.sco_permissions import Permission
-from app.scodoc.sco_exceptions import ScoValueError
+from app.scodoc.sco_exceptions import ScoPermissionDenied, ScoValueError
from app.views import notes_bp as bp
from app.views import ScoData
@@ -74,7 +75,9 @@ def parcour_formation(formation_id: int, parcour_id: int = None) -> str:
raise ScoValueError("parcours invalide ou hors référentiel de formation")
competences_parcour = (
- parcour_formation_competences(parcour, formation) if parcour else None
+ cursus_but.parcour_formation_competences(parcour, formation)
+ if parcour
+ else None
)
return render_template(
@@ -87,103 +90,32 @@ def parcour_formation(formation_id: int, parcour_id: int = None) -> str:
)
-def ue_associee_au_niveau_du_parcours(
- ues_possibles: list[UniteEns], niveau: ApcNiveau, sem_name: str = "S"
-) -> UniteEns:
- "L'UE associée à ce niveau, ou None"
- ues = [ue for ue in ues_possibles if ue.niveau_competence_id == niveau.id]
- if len(ues) > 1:
- # plusieurs UEs associées à ce niveau: élimine celles sans parcours
- ues_pair_avec_parcours = [ue for ue in ues if ue.parcours]
- if ues_pair_avec_parcours:
- ues = ues_pair_avec_parcours
- if len(ues) > 1:
- log(f"_niveau_ues: {len(ues)} associées au niveau {niveau} / {sem_name}")
- return ues[0] if ues else None
-
-
-def parcour_formation_competences(parcour: ApcParcours, formation: Formation) -> list:
+@bp.route(
+ "/validation_rcues///edit",
+ defaults={"edit": True},
+ endpoint="validation_rcues_edit",
+)
+@bp.route("/validation_rcues//")
+@scodoc
+@permission_required(Permission.ScoView)
+def validation_rcues(
+ formsemestre_id: int, etudid: int = None, edit: bool = False
+) -> str:
+ """Visualisation des résultats UEs et RCUEs d'un étudiant
+ et saisie des validation de RCUE antérieures.
"""
- [
- {
- 'competence' : ApcCompetence,
- 'niveaux' : {
- 1 : { ... },
- 2 : { ... },
- 3 : {
- 'niveau' : ApcNiveau,
- 'ue_impair' : UniteEns, # actuellement associée
- 'ues_impair' : list[UniteEns], # choix possibles
- 'ue_pair' : UniteEns,
- 'ues_pair' : list[UniteEns],
- }
- }
- }
- ]
- """
-
- def _niveau_ues(competence: ApcCompetence, annee: int) -> dict:
- "niveau et ues pour cette compétence de cette année du parcours"
- niveaux = ApcNiveau.niveaux_annee_de_parcours(
- parcour, annee, competence=competence
- )
- if len(niveaux) > 0:
- if len(niveaux) > 1:
- log(
- f"""_niveau_ues: plus d'un niveau pour {competence}
- annee {annee} parcours {parcour.code}"""
+ etud: Identite = Identite.query.get_or_404(etudid)
+ formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
+ if edit: # check permission
+ if not formsemestre.can_edit_jury():
+ raise ScoPermissionDenied(
+ dest_url=url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre_id,
)
- niveau = niveaux[0]
- elif len(niveaux) == 0:
- return {
- "niveau": None,
- "ue_pair": None,
- "ue_impair": None,
- "ues_pair": [],
- "ues_impair": [],
- }
- # Toutes les UEs de la formation dans ce parcours ou tronc commun
- ues = [
- ue
- for ue in formation.ues
- if ((not ue.parcours) or (parcour.id in (p.id for p in ue.parcours)))
- and ue.type == UE_STANDARD
- ]
- ues_pair_possibles = [ue for ue in ues if ue.semestre_idx == (2 * annee)]
- ues_impair_possibles = [ue for ue in ues if ue.semestre_idx == (2 * annee - 1)]
-
- # UE associée au niveau dans ce parcours
- ue_pair = ue_associee_au_niveau_du_parcours(
- ues_pair_possibles, niveau, f"S{2*annee}"
- )
- ue_impair = ue_associee_au_niveau_du_parcours(
- ues_impair_possibles, niveau, f"S{2*annee-1}"
- )
-
- return {
- "niveau": niveau,
- "ue_pair": ue_pair,
- "ues_pair": [
- ue
- for ue in ues_pair_possibles
- if (not ue.niveau_competence) or ue.niveau_competence.id == niveau.id
- ],
- "ue_impair": ue_impair,
- "ues_impair": [
- ue
- for ue in ues_impair_possibles
- if (not ue.niveau_competence) or ue.niveau_competence.id == niveau.id
- ],
- }
-
- competences = [
- {
- "competence": competence,
- "niveaux": {annee: _niveau_ues(competence, annee) for annee in (1, 2, 3)},
- }
- for competence in parcour.query_competences()
- ]
- return competences
+ )
+ return validations_view.validation_rcues(etud, formsemestre, edit)
@bp.route("/ue_parcours_ects/", methods=["GET", "POST"])
diff --git a/tests/api/test_api_jury.py b/tests/api/test_api_jury.py
index 64f59c273..a0bd8a32a 100644
--- a/tests/api/test_api_jury.py
+++ b/tests/api/test_api_jury.py
@@ -16,8 +16,9 @@ Utilisation :
Lancer :
pytest tests/api/test_api_jury.py
"""
+import requests
-
+from app.scodoc import sco_utils as scu
from tests.api.setup_test_api import (
API_URL,
CHECK_CERTIFICATE,
@@ -37,4 +38,29 @@ def test_jury_decisions(api_headers):
decisions_jury = GET(
f"/formsemestre/{formsemestre_id}/decisions_jury", headers=api_headers
)
+ assert len(etudiants) > 0
assert len(etudiants) == len(decisions_jury)
+ # TODO La suite de ce test est a compléter: il faut modifier le formation test RT
+ # pour avoir au moins le S2 et le S2: actuellement seulement le S1
+ # # Récupère la formation de ce semestre pour avoir les UEs
+ # r = requests.get(
+ # API_URL + "/formation/1/export",
+ # headers=api_headers,
+ # verify=CHECK_CERTIFICATE,
+ # timeout=scu.SCO_TEST_API_TIMEOUT,
+ # )
+ # assert r.status_code == 200
+ # export_formation = r.json()
+ # ues = export_formation["ue"]
+ # # Enregistre une validation d'RCUE
+ # etudid = etudiants[0]["id"]
+ # validation = POST_JSON(
+ # f"/etudiant/{etudid}/jury/validation_rcue/record",
+ # data={
+ # "code": "ADM",
+ # "ue1_id": XXX,
+ # "ue2_id": XXX,
+ # },
+ # headers=api_headers,
+ # )
+ # assert validation