forked from ScoDoc/ScoDoc
BUT ref. Comp.: fix calcul niveaux/parcours, ajoute tests unitaires GCCD et MLT.
This commit is contained in:
parent
8af5c3ffa0
commit
65b87049ca
@ -85,7 +85,11 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
|||||||
lazy="dynamic",
|
lazy="dynamic",
|
||||||
cascade="all, delete-orphan",
|
cascade="all, delete-orphan",
|
||||||
)
|
)
|
||||||
formations = db.relationship("Formation", backref="referentiel_competence")
|
formations = db.relationship(
|
||||||
|
"Formation",
|
||||||
|
backref="referentiel_competence",
|
||||||
|
order_by="Formation.acronyme, Formation.version",
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<ApcReferentielCompetences {self.id} {self.specialite!r} {self.departement!r}>"
|
return f"<ApcReferentielCompetences {self.id} {self.specialite!r} {self.departement!r}>"
|
||||||
@ -360,32 +364,36 @@ class ApcNiveau(db.Model, XMLModel):
|
|||||||
parcour: "ApcParcours",
|
parcour: "ApcParcours",
|
||||||
annee: int,
|
annee: int,
|
||||||
referentiel_competence: ApcReferentielCompetences = None,
|
referentiel_competence: ApcReferentielCompetences = None,
|
||||||
) -> flask_sqlalchemy.BaseQuery:
|
) -> list["ApcNiveau"]:
|
||||||
"""Les niveaux de l'année du parcours
|
"""Les niveaux de l'année du parcours
|
||||||
Si le parcour est None, tous les niveaux de l'année
|
Si le parcour est None, tous les niveaux de l'année
|
||||||
"""
|
"""
|
||||||
if annee not in {1, 2, 3}:
|
if annee not in {1, 2, 3}:
|
||||||
raise ValueError("annee invalide pour un parcours BUT")
|
raise ValueError("annee invalide pour un parcours BUT")
|
||||||
|
referentiel_competence = (
|
||||||
|
parcour.referentiel if parcour else referentiel_competence
|
||||||
|
)
|
||||||
if referentiel_competence is None:
|
if referentiel_competence is None:
|
||||||
raise ScoNoReferentielCompetences()
|
raise ScoNoReferentielCompetences()
|
||||||
|
if not parcour:
|
||||||
annee_formation = f"BUT{annee}"
|
annee_formation = f"BUT{annee}"
|
||||||
if parcour is None:
|
|
||||||
return ApcNiveau.query.filter(
|
return ApcNiveau.query.filter(
|
||||||
ApcNiveau.annee == annee_formation,
|
ApcNiveau.annee == annee_formation,
|
||||||
ApcCompetence.id == ApcNiveau.competence_id,
|
ApcCompetence.id == ApcNiveau.competence_id,
|
||||||
ApcCompetence.referentiel_id == referentiel_competence.id,
|
ApcCompetence.referentiel_id == referentiel_competence.id,
|
||||||
)
|
)
|
||||||
else:
|
annee_parcour = parcour.annees.filter_by(ordre=annee).first()
|
||||||
return ApcNiveau.query.filter(
|
if not annee_parcour:
|
||||||
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
return []
|
||||||
ApcParcours.id == ApcAnneeParcours.parcours_id,
|
|
||||||
ApcParcours.referentiel == parcour.referentiel,
|
parcour_niveaux: list[
|
||||||
ApcParcoursNiveauCompetence.competence_id == ApcCompetence.id,
|
ApcParcoursNiveauCompetence
|
||||||
ApcCompetence.id == ApcNiveau.competence_id,
|
] = annee_parcour.niveaux_competences
|
||||||
ApcAnneeParcours.parcours == parcour,
|
niveaux: list[ApcNiveau] = [
|
||||||
ApcNiveau.annee == annee_formation,
|
pn.competence.niveaux.filter_by(ordre=pn.niveau).first()
|
||||||
)
|
for pn in parcour_niveaux
|
||||||
|
]
|
||||||
|
return niveaux
|
||||||
|
|
||||||
|
|
||||||
app_critiques_modules = db.Table(
|
app_critiques_modules = db.Table(
|
||||||
|
@ -554,7 +554,7 @@ def formation_list_table() -> GenTable:
|
|||||||
row["_buttons_html"] = but_locked + but_suppr + but_edit
|
row["_buttons_html"] = but_locked + but_suppr + but_edit
|
||||||
rows.append(row)
|
rows.append(row)
|
||||||
# Tri par annee_dernier_sem, type, acronyme, titre, version décroissante
|
# Tri par annee_dernier_sem, type, acronyme, titre, version décroissante
|
||||||
# donc plus récemment utilsiée en tête
|
# donc plus récemment utilisée en tête
|
||||||
rows.sort(
|
rows.sort(
|
||||||
key=lambda row: (
|
key=lambda row: (
|
||||||
-row["annee_dernier_sem"],
|
-row["annee_dernier_sem"],
|
||||||
|
@ -19,7 +19,20 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="part2">
|
<div class="part2">
|
||||||
<a class="stdlink" href="{{url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)}}">liste des référentiels</a>
|
<ul>
|
||||||
|
<li>Formations se référant à ce référentiel:
|
||||||
|
<ul>
|
||||||
|
{% for formation in ref.formations %}
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=formation.id )
|
||||||
|
}}">{{ formation.get_titre_version() }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a class="stdlink" href="{{url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)}}">Liste des référentiels</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -33,31 +33,21 @@ Emmanuel Viennet, 2021
|
|||||||
|
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from flask import current_app, g, request
|
from flask import g, request
|
||||||
from flask.templating import render_template
|
from flask.templating import render_template
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from werkzeug.utils import redirect
|
|
||||||
from app.scodoc.codes_cursus import UE_SPORT
|
from app.scodoc.codes_cursus import UE_SPORT
|
||||||
|
|
||||||
from config import Config
|
|
||||||
|
|
||||||
from app import db
|
from app import db, models
|
||||||
from app import models
|
|
||||||
from app.auth.models import User
|
|
||||||
|
|
||||||
from app.comp import moy_ue
|
from app.comp import moy_ue
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
|
from app.models import ApcParcours, Formation, Module
|
||||||
from app.views import notes_bp as bp
|
from app.views import notes_bp as bp
|
||||||
|
|
||||||
# ---------------
|
|
||||||
|
|
||||||
from app.scodoc import sco_utils as scu
|
|
||||||
from app.scodoc import sco_formations
|
|
||||||
from app import log
|
|
||||||
|
|
||||||
from app.models import ApcParcours, Formation, UniteEns, Module
|
|
||||||
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,17 +44,17 @@ def refcomp(refcomp_id):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def refcomp_show(refcomp_id):
|
def refcomp_show(refcomp_id):
|
||||||
"""Affichage du référentiel de compétences."""
|
"""Affichage du référentiel de compétences."""
|
||||||
ref = ApcReferentielCompetences.query.get_or_404(refcomp_id)
|
referentiel_competence = ApcReferentielCompetences.query.get_or_404(refcomp_id)
|
||||||
return render_template(
|
return render_template(
|
||||||
"but/refcomp_show.j2",
|
"but/refcomp_show.j2",
|
||||||
ref=ref,
|
ref=referentiel_competence,
|
||||||
title="Référentiel de compétences",
|
title="Référentiel de compétences",
|
||||||
sco=ScoData(),
|
|
||||||
data_source=url_for(
|
data_source=url_for(
|
||||||
"notes.refcomp",
|
"notes.refcomp",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
refcomp_id=refcomp_id,
|
refcomp_id=refcomp_id,
|
||||||
),
|
),
|
||||||
|
sco=ScoData(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.4.70"
|
SCOVERSION = "9.4.71"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -24,6 +24,12 @@ from tests.unit import setup
|
|||||||
REF_RT_XML = open(
|
REF_RT_XML = open(
|
||||||
"ressources/referentiels/but2022/competences/but-RT-05012022-081735.xml"
|
"ressources/referentiels/but2022/competences/but-RT-05012022-081735.xml"
|
||||||
).read()
|
).read()
|
||||||
|
REF_MLT_XML = open(
|
||||||
|
"ressources/referentiels/but2022/competences/but-MLT-05012022-081603.xml"
|
||||||
|
).read()
|
||||||
|
REF_GCCD_XML = open(
|
||||||
|
"ressources/referentiels/but2022/competences/but-GCCD-05012022-081630.xml"
|
||||||
|
).read()
|
||||||
|
|
||||||
|
|
||||||
def test_but_refcomp(test_client):
|
def test_but_refcomp(test_client):
|
||||||
@ -84,3 +90,110 @@ def test_but_assoc_refcomp(test_client):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
formation.refcomp_desassoc()
|
formation.refcomp_desassoc()
|
||||||
assert ue.niveau_competence_id is None
|
assert ue.niveau_competence_id is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_refcomp_niveaux_mlt(test_client):
|
||||||
|
"""Test calcul niveaux / parcours pour un BUT MLT
|
||||||
|
avec en parcours "Mobilité et Supply Chain Connectées"
|
||||||
|
une compétence "Transporter" sur BUT1, BUT2
|
||||||
|
et une compétence "Digitaliser" sur BUT2, BUT3
|
||||||
|
"""
|
||||||
|
# Charger le ref. comp. MLT
|
||||||
|
dept_id = models.Departement.query.first().id
|
||||||
|
ref_comp: ApcReferentielCompetences = orebut_import_refcomp(REF_MLT_XML, dept_id)
|
||||||
|
# Vérifier qu'on a 2 parcours et 4 compétences dans chaque
|
||||||
|
nb_parcours = ref_comp.parcours.count()
|
||||||
|
assert nb_parcours == 2
|
||||||
|
assert [len(p.query_competences().all()) for p in ref_comp.parcours] == [
|
||||||
|
4
|
||||||
|
] * nb_parcours
|
||||||
|
# 3 niveaux en 1ere année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 1, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [3, 3]
|
||||||
|
# 2 niveaux en 2ème année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 2, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [4, 4]
|
||||||
|
# 3 niveaux en 3ème année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 3, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [3, 3]
|
||||||
|
# Vérifier les niveaux_by_parcours
|
||||||
|
parcour = ref_comp.parcours.first()
|
||||||
|
# BUT 1
|
||||||
|
parcours, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(1, parcour)
|
||||||
|
assert parcours == [parcour] # le parcours indiqué
|
||||||
|
assert (tuple(niveaux_by_parcours.keys())) == (parcour.id, "TC")
|
||||||
|
assert niveaux_by_parcours[parcour.id] == [] # tout en tronc commun en BUT1 MLT
|
||||||
|
assert niveaux_by_parcours["TC"][0].competence.titre == "Transporter"
|
||||||
|
assert len(niveaux_by_parcours["TC"]) == 3
|
||||||
|
# BUT 2
|
||||||
|
parcours, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(2, parcour)
|
||||||
|
assert parcours == [parcour] # le parcours indiqué
|
||||||
|
assert (tuple(niveaux_by_parcours.keys())) == (parcour.id, "TC")
|
||||||
|
assert len(niveaux_by_parcours[parcour.id]) == 1
|
||||||
|
assert len(niveaux_by_parcours["TC"]) == 3
|
||||||
|
# BUT 3
|
||||||
|
parcours, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(3, parcour)
|
||||||
|
assert parcours == [parcour] # le parcours indiqué
|
||||||
|
assert (tuple(niveaux_by_parcours.keys())) == (parcour.id, "TC")
|
||||||
|
assert len(niveaux_by_parcours[parcour.id]) == 1
|
||||||
|
assert len(niveaux_by_parcours["TC"]) == 2
|
||||||
|
# Vérifier les niveaux de chaque année
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 1)) == 3
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 2)) == 4
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 3)) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_refcomp_niveaux_gccd(test_client):
|
||||||
|
"""Test calcul niveaux / parcours pour un BUT GCCD
|
||||||
|
avec en parcours "Travaux Bâtiment" 5 compétences
|
||||||
|
dont la première "Solutions Bâtiment" sur BUT1, BUT2, BUT3
|
||||||
|
et en parcours "Travaux Publics" la même sur BUT1, BUT2 seulement.
|
||||||
|
"""
|
||||||
|
# Charger le ref. comp. GCCD
|
||||||
|
dept_id = models.Departement.query.first().id
|
||||||
|
ref_comp: ApcReferentielCompetences = orebut_import_refcomp(REF_GCCD_XML, dept_id)
|
||||||
|
# Vérifier qu'on a 4 parcours et 5 compétences dans chaque
|
||||||
|
nb_parcours = ref_comp.parcours.count()
|
||||||
|
assert nb_parcours == 4
|
||||||
|
assert [len(p.query_competences().all()) for p in ref_comp.parcours] == [
|
||||||
|
5
|
||||||
|
] * nb_parcours
|
||||||
|
# 5 niveaux en 1ere année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 1, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [5] * nb_parcours
|
||||||
|
# 5 niveaux en 2ème année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 2, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [5] * nb_parcours
|
||||||
|
# 3 niveaux en 3ème année (dans chaque parcours):
|
||||||
|
assert [
|
||||||
|
len(ApcNiveau.niveaux_annee_de_parcours(p, 3, ref_comp))
|
||||||
|
for p in ref_comp.parcours
|
||||||
|
] == [3] * nb_parcours
|
||||||
|
# Vérifier les niveaux_by_parcours
|
||||||
|
parcour = ref_comp.parcours.first()
|
||||||
|
# BUT 1
|
||||||
|
parcours, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(1, parcour)
|
||||||
|
assert parcours == [parcour] # le parcours indiqué
|
||||||
|
assert (tuple(niveaux_by_parcours.keys())) == (parcour.id, "TC")
|
||||||
|
assert len(niveaux_by_parcours[parcour.id]) == 0
|
||||||
|
assert len(niveaux_by_parcours["TC"]) == 5
|
||||||
|
# BUT 3
|
||||||
|
parcours, niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(3, parcour)
|
||||||
|
assert parcours == [parcour] # le parcours indiqué
|
||||||
|
assert (tuple(niveaux_by_parcours.keys())) == (parcour.id, "TC")
|
||||||
|
assert len(niveaux_by_parcours[parcour.id]) == 3
|
||||||
|
assert len(niveaux_by_parcours["TC"]) == 0
|
||||||
|
# Vérifier les niveaux de chaque année
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 1)) == 5
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 2)) == 5
|
||||||
|
assert len(ApcNiveau.niveaux_annee_de_parcours(parcour, 3)) == 3
|
||||||
|
Loading…
Reference in New Issue
Block a user