forked from ScoDoc/ScoDoc
Jury BUT: cas avec redoublement en changeant de parcours. Fix #988 : détermination parcours, compte ECTS, DUT120.
This commit is contained in:
parent
322870c7e9
commit
495aac82ae
@ -64,7 +64,7 @@ class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
||||
Considère le parcours du semestre en cours (res).
|
||||
"""
|
||||
parcour_id = self.nt.etuds_parcour_id.get(self.etud.id)
|
||||
return but_parcours_validated(self.etud.id, parcour_id)
|
||||
return but_parcours_validated(self.etud, parcour_id)
|
||||
|
||||
|
||||
def but_annee_validated(
|
||||
@ -81,14 +81,14 @@ def but_annee_validated(
|
||||
)
|
||||
|
||||
|
||||
def but_parcours_validated(etudid: int, parcour_id: int | None) -> bool:
|
||||
def but_parcours_validated(etud: Identite, parcour_id: int | None) -> bool:
|
||||
"""Détermine si le parcours BUT est validé.
|
||||
= 180 ECTS acquis dans les UEs du parcours.
|
||||
"""
|
||||
if parcour_id is None:
|
||||
return False # étudiant non inscrit à un parcours
|
||||
# Les ECTS
|
||||
validations = but_validations_ues_parcours(etudid, parcour_id)
|
||||
validations = but_validations_ues_parcours(etud, parcour_id)
|
||||
ects_acquis = validations_count_ects(validations)
|
||||
return ects_acquis >= CursusBUT.ECTS_DIPLOME
|
||||
|
||||
@ -113,20 +113,10 @@ class EtudCursusBUT:
|
||||
#
|
||||
self.etud = etud
|
||||
self.formation = formation
|
||||
self.inscriptions = sorted(
|
||||
[
|
||||
ins
|
||||
for ins in etud.formsemestre_inscriptions
|
||||
if ins.formsemestre.formation.referentiel_competence
|
||||
and (
|
||||
ins.formsemestre.formation.referentiel_competence.id
|
||||
== formation.referentiel_competence.id
|
||||
)
|
||||
],
|
||||
key=lambda s: (s.formsemestre.semestre_id, s.formsemestre.date_debut),
|
||||
)
|
||||
"Liste des inscriptions aux sem. de la formation, triées par indice et chronologie"
|
||||
self.parcour: ApcParcours = self.inscriptions[-1].parcour
|
||||
self.parcour: ApcParcours = get_etud_parcours(
|
||||
etud, formation.referentiel_competence_id
|
||||
)
|
||||
"Le parcours à valider: celui du DERNIER semestre suivi (peut être None)"
|
||||
self.niveaux_by_annee: dict[int, list[ApcNiveau]] = {}
|
||||
"{ annee:int : liste des niveaux à valider }"
|
||||
@ -229,8 +219,12 @@ class EtudCursusBUT:
|
||||
return annee in [n.annee for n in self.competences[competence_id].niveaux]
|
||||
|
||||
def get_ects_acquis(self) -> int:
|
||||
"Nombre d'ECTS validés par etud dans le BUT de ce référentiel"
|
||||
return but_ects_valides(self.etud, self.formation.referentiel_competence.id)
|
||||
"Nombre d'ECTS validés par etud dans le parcours BUT de ce référentiel"
|
||||
return but_ects_valides(
|
||||
self.etud,
|
||||
self.formation.referentiel_competence.id,
|
||||
parcour_id=self.parcour.id if self.parcour is not None else None,
|
||||
)
|
||||
|
||||
def load_validation_by_niveau(self) -> dict[int, list[ApcValidationRCUE]]:
|
||||
"""Cherche les validations de jury enregistrées pour chaque niveau
|
||||
@ -403,17 +397,48 @@ class FormSemestreCursusBUT:
|
||||
# "cache { competence_id : competence }"
|
||||
|
||||
|
||||
def get_etud_parcours(
|
||||
etud: Identite, referentiel_competence_id: int | None
|
||||
) -> ApcParcours | None:
|
||||
"""Le parcours de l'étudiant dans ce réf. de compétence, ou None.
|
||||
= celui du DERNIER semestre suivi dans le référentiel de compétence
|
||||
(peut être None si l'incription n'a pas de parcours)
|
||||
"""
|
||||
inscriptions = sorted(
|
||||
[
|
||||
ins
|
||||
for ins in etud.formsemestre_inscriptions
|
||||
if ins.formsemestre.formation.referentiel_competence
|
||||
and (
|
||||
ins.formsemestre.formation.referentiel_competence.id
|
||||
== referentiel_competence_id
|
||||
)
|
||||
],
|
||||
key=lambda s: (s.formsemestre.date_debut, s.formsemestre.semestre_id),
|
||||
)
|
||||
return inscriptions[-1].parcour if inscriptions else None
|
||||
|
||||
|
||||
def but_ects_valides(
|
||||
etud: Identite,
|
||||
referentiel_competence_id: int,
|
||||
referentiel_competence_id: int | None = None,
|
||||
annees_but: None | Iterable[str] = None,
|
||||
parcour_id: int | None = None,
|
||||
) -> int:
|
||||
"""Nombre d'ECTS validés par etud dans le BUT de référentiel indiqué.
|
||||
Ne prend que les UE associées à des niveaux de compétences,
|
||||
et ne les compte qu'une fois même en cas de redoublement avec re-validation.
|
||||
|
||||
On peut spécifier soit le referentiel_competence_id, soit le parcour.
|
||||
Si parcour est spécifié, ne prend que les UEs de ce parcours et du tronc commun.
|
||||
|
||||
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)
|
||||
validations = (
|
||||
but_validations_ues_parcours(etud, parcour_id, annees_but)
|
||||
if parcour_id is not None
|
||||
else but_validations_ues(etud, referentiel_competence_id, annees_but)
|
||||
)
|
||||
return validations_count_ects(validations)
|
||||
|
||||
|
||||
@ -472,7 +497,7 @@ def sorted_validations(validations) -> list[ScolarFormSemestreValidation]:
|
||||
|
||||
|
||||
def but_validations_ues_parcours(
|
||||
etudid: int, parcour_id: int
|
||||
etud: Identite, parcour_id: int, annees_but: None | Iterable[str] = None
|
||||
) -> list[ScolarFormSemestreValidation]:
|
||||
"""Query les validations d'UEs pour cet étudiant
|
||||
dans des UEs appartenant à ce parcours ou à son tronc commun.
|
||||
@ -485,7 +510,7 @@ def but_validations_ues_parcours(
|
||||
|
||||
# Les validations d'UE de ce parcours ou du tronc commun pour cet étudiant:
|
||||
validations = (
|
||||
ScolarFormSemestreValidation.query.filter_by(etudid=etudid)
|
||||
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
|
||||
.filter(ScolarFormSemestreValidation.ue_id != None)
|
||||
.join(UniteEns)
|
||||
.filter(
|
||||
@ -499,6 +524,11 @@ def but_validations_ues_parcours(
|
||||
)
|
||||
)
|
||||
)
|
||||
# restreint à certaines années (utile pour les ECTS du DUT120)
|
||||
if annees_but:
|
||||
validations = validations.join(ApcNiveau).filter(
|
||||
ApcNiveau.annee.in_(annees_but)
|
||||
)
|
||||
return sorted_validations(validations)
|
||||
|
||||
|
||||
|
@ -11,8 +11,7 @@ from flask import g, request, url_for
|
||||
from openpyxl.styles import Alignment
|
||||
|
||||
from app import log
|
||||
from app.but import jury_but
|
||||
from app.but.cursus_but import but_ects_valides
|
||||
from app.but import cursus_but, jury_but
|
||||
from app.models.but_validations import ValidationDUT120
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.formsemestre import FormSemestre
|
||||
@ -155,7 +154,14 @@ def pvjury_table_but(
|
||||
except ScoValueError:
|
||||
deca = None
|
||||
|
||||
ects_but_valides = but_ects_valides(etud, referentiel_competence_id)
|
||||
parcour = cursus_but.get_etud_parcours(
|
||||
etud, formsemestre.formation.referentiel_competence_id
|
||||
)
|
||||
ects_but_valides = (
|
||||
cursus_but.but_ects_valides(etud, parcour_id=parcour.id)
|
||||
if parcour
|
||||
else cursus_but.but_ects_valides(etud, referentiel_competence_id)
|
||||
)
|
||||
has_diplome = deca.valide_diplome() if deca else False
|
||||
diplome_lst = ["ADM"] if has_diplome else []
|
||||
validation_dut120 = ValidationDUT120.query.filter_by(
|
||||
|
@ -27,12 +27,22 @@ from app.views import ScoData
|
||||
|
||||
def etud_valide_dut120(etud: Identite, referentiel_competence_id: int) -> bool:
|
||||
"""Vrai si l'étudiant satisfait les conditions pour valider le DUT120"""
|
||||
ects_but1_but2 = cursus_but.but_ects_valides(
|
||||
etud, referentiel_competence_id, annees_but=("BUT1", "BUT2")
|
||||
)
|
||||
ects_but1_but2 = etud_ects_but1_but2(etud, referentiel_competence_id)
|
||||
return ects_but1_but2 >= 120
|
||||
|
||||
|
||||
def etud_ects_but1_but2(etud, referentiel_competence_id: int) -> float:
|
||||
"""Les ECTS enregistré en BUT1 et BUT2 de ce ref. et du parcours"""
|
||||
# parcours de la dernière inscription
|
||||
parcour = cursus_but.get_etud_parcours(etud, referentiel_competence_id)
|
||||
return cursus_but.but_ects_valides(
|
||||
etud,
|
||||
referentiel_competence_id,
|
||||
parcour_id=parcour.id if parcour else None,
|
||||
annees_but=("BUT1", "BUT2"),
|
||||
)
|
||||
|
||||
|
||||
class ValidationDUT120Form(FlaskForm):
|
||||
"Formulaire validation DUT120"
|
||||
submit = SubmitField("Enregistrer le diplôme DUT 120")
|
||||
@ -61,16 +71,13 @@ def validate_dut120_etud(etudid: int, formsemestre_id: int):
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
|
||||
ects_but1_but2 = cursus_but.but_ects_valides(
|
||||
etud, refcomp.id, annees_but=("BUT1", "BUT2")
|
||||
)
|
||||
|
||||
ects_but1_but2 = etud_ects_but1_but2(etud, refcomp.id)
|
||||
form = ValidationDUT120Form()
|
||||
# Check if ValidationDUT120 instance already exists
|
||||
existing_validation = ValidationDUT120.query.filter_by(
|
||||
etudid=etud.id, referentiel_competence_id=refcomp.id
|
||||
).first()
|
||||
|
||||
if existing_validation:
|
||||
flash("DUT120 déjà validé", "info")
|
||||
etud_can_validate_dut = False
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
from flask import render_template
|
||||
|
||||
from app import log
|
||||
from app import db, log
|
||||
from app.but import cursus_but
|
||||
from app.models import (
|
||||
ApcCompetence,
|
||||
@ -20,10 +20,11 @@ from app.models import (
|
||||
Formation,
|
||||
FormSemestre,
|
||||
Identite,
|
||||
UniteEns,
|
||||
# ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
UniteEns,
|
||||
)
|
||||
from app.models.ues import UEParcours
|
||||
from app.scodoc import codes_cursus
|
||||
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
||||
from app.views import ScoData
|
||||
@ -49,7 +50,9 @@ def validation_rcues(etud: Identite, formsemestre: FormSemestre, edit: bool = Fa
|
||||
)
|
||||
|
||||
ue_validation_by_niveau = get_ue_validation_by_niveau(refcomp, etud)
|
||||
rcue_validation_by_niveau = get_rcue_validation_by_niveau(refcomp, etud)
|
||||
rcue_validation_by_niveau = get_rcue_validation_by_niveau(
|
||||
refcomp, etud, None if parcour is None else parcour.id
|
||||
)
|
||||
ects_acquis = sum((v.ects() for v in ue_validation_by_niveau.values()))
|
||||
|
||||
return render_template(
|
||||
@ -71,17 +74,18 @@ def validation_rcues(etud: Identite, formsemestre: FormSemestre, edit: bool = Fa
|
||||
def get_ue_validation_by_niveau(
|
||||
refcomp: ApcReferentielCompetences, etud: Identite
|
||||
) -> dict[tuple[int, str], ScolarFormSemestreValidation]:
|
||||
"""Les validations d'UEs de cet étudiant liées à ce référentiel de compétences.
|
||||
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation
|
||||
"""Les validations d'UEs de cet étudiant liées à ce référentiel de compétences
|
||||
dans le parcours suivi par l'étudiant (celui de son semestre le plus récent
|
||||
dans un semestre de ce référentiel).
|
||||
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation.
|
||||
"""
|
||||
validations: list[ScolarFormSemestreValidation] = (
|
||||
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
|
||||
.join(UniteEns)
|
||||
.join(ApcNiveau)
|
||||
.join(ApcCompetence)
|
||||
.filter_by(referentiel_id=refcomp.id)
|
||||
.all()
|
||||
parcour = cursus_but.get_etud_parcours(etud, refcomp.id)
|
||||
validations = (
|
||||
cursus_but.but_validations_ues_parcours(etud, parcour.id)
|
||||
if parcour is not None
|
||||
else cursus_but.but_validations_ues(etud, refcomp.id)
|
||||
)
|
||||
|
||||
# La meilleure validation pour chaque UE
|
||||
ue_validation_by_niveau = {} # { (niveau_id, pair|impair) : validation }
|
||||
for validation in validations:
|
||||
@ -104,10 +108,12 @@ def get_ue_validation_by_niveau(
|
||||
|
||||
|
||||
def get_rcue_validation_by_niveau(
|
||||
refcomp: ApcReferentielCompetences, etud: Identite
|
||||
refcomp: ApcReferentielCompetences, etud: Identite, parcour_id: int | None
|
||||
) -> dict[int, ApcValidationRCUE]:
|
||||
"""Les validations d'UEs de cet étudiant liées à ce référentiel de compétences.
|
||||
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation
|
||||
Si parcour_id n'est pas None, restreint aux niveaux de ce parcours
|
||||
et du tronc commun.
|
||||
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation.
|
||||
"""
|
||||
validations: list[ApcValidationRCUE] = (
|
||||
ApcValidationRCUE.query.filter_by(etudid=etud.id)
|
||||
@ -115,6 +121,16 @@ def get_rcue_validation_by_niveau(
|
||||
.join(ApcNiveau, UniteEns.niveau_competence_id == ApcNiveau.id)
|
||||
.join(ApcCompetence)
|
||||
.filter_by(referentiel_id=refcomp.id)
|
||||
.filter(
|
||||
db.or_(
|
||||
UniteEns.id.in_(
|
||||
UEParcours.query.with_entities(UEParcours.ue_id).filter(
|
||||
UEParcours.parcours_id == parcour_id
|
||||
)
|
||||
),
|
||||
~UniteEns.id.in_(UEParcours.query.with_entities(UEParcours.ue_id)),
|
||||
)
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return {
|
||||
|
@ -113,7 +113,7 @@ class TableJury(TableRecap):
|
||||
if res.is_apc and res.formsemestre.semestre_id == 6:
|
||||
# on ne vérifie le diplôme que dans ce cas pour ne pas ralentir
|
||||
if cursus_but.but_parcours_validated(
|
||||
etud.id, res.etuds_parcour_id.get(etud.id)
|
||||
etud, res.etuds_parcour_id.get(etud.id)
|
||||
):
|
||||
row.add_cell(
|
||||
"autorisations_inscription",
|
||||
@ -143,15 +143,20 @@ class TableJury(TableRecap):
|
||||
group="jury_code_sem",
|
||||
classes=["recorded_code"],
|
||||
)
|
||||
# ECTS acquis en BUT
|
||||
# ECTS acquis en BUT (dans le parcours du semestre affiché)
|
||||
if res.formsemestre.formation.referentiel_competence_id:
|
||||
parcour_id = res.etuds_parcour_id.get(etud.id)
|
||||
row.add_cell(
|
||||
"ects_acquis",
|
||||
"ECTS",
|
||||
# res.get_etud_ects_valides(etud.id),
|
||||
# cette recherche augmente de 10% le temps de construction de la table
|
||||
cursus_but.but_ects_valides(
|
||||
(
|
||||
cursus_but.but_ects_valides(etud, parcour_id=parcour_id)
|
||||
if parcour_id is not None
|
||||
else cursus_but.but_ects_valides(
|
||||
etud, res.formsemestre.formation.referentiel_competence_id
|
||||
)
|
||||
),
|
||||
group="jury_code_sem",
|
||||
classes=["recorded_code"],
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<div class="bull_head jury_but">
|
||||
<div>
|
||||
<div class="titre_parcours">Validation du DUT en 120 ECTS dans un parcours BUT</div>
|
||||
<h2>Validation du DUT en 120 ECTS dans un parcours BUT</h2>
|
||||
<div class="nom_etud">{{etud.html_link_fiche()|safe}}</div>
|
||||
</div>
|
||||
<div class="bull_photo">
|
||||
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help">
|
||||
<div class="scobox explanation help">
|
||||
<p>Les étudiants de BUT peuvent demander l’attribution du <em>diplôme universitaire de technologie</em>
|
||||
(DUT) au terme de l’acquisition des 120 premiers crédits européens du cursus.
|
||||
</p>
|
||||
@ -29,7 +29,8 @@ une formation utilisant une autre version de référentiel, pensez à revalider
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 16px;">
|
||||
<div class="scobox">
|
||||
<div>
|
||||
{{etud.html_link_fiche()|safe}} a acquis <b>{{ects_but1_but2}} ECTS</b> en BUT1 et BUT2.
|
||||
{% if not validation %}
|
||||
Son DUT n'est pas encore enregistré dans cette spécialité.
|
||||
@ -65,4 +66,6 @@ une formation utilisant une autre version de référentiel, pensez à revalider
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -52,7 +52,7 @@
|
||||
{% if parcour %}
|
||||
parcours {{parcour.code}} « {{parcour.libelle}} »
|
||||
{% else %}
|
||||
non inscrit{{sco.etud.e}} à un parcours de la spécialité
|
||||
<span class="warning">non inscrit{{sco.etud.e}} à un parcours de la spécialité</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -164,7 +164,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="help">
|
||||
<div class="scobox explanation help">
|
||||
|
||||
<p>Cette page montre les validations d'UEs et de niveaux de compétences (RCUEs)
|
||||
de {{sco.etud.html_link_fiche()|safe}}
|
||||
|
@ -920,7 +920,7 @@ def jury_delete_manual(etudid: int):
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def etud_bilan_ects(etudid: int):
|
||||
"""Page bilan de tous els ECTS acquis par un étudiant.
|
||||
"""Page bilan de tous les ECTS acquis par un étudiant.
|
||||
Plusieurs formations (eg DUT, LP) peuvent être concernées.
|
||||
"""
|
||||
etud = Identite.get_etud(etudid)
|
||||
|
Loading…
Reference in New Issue
Block a user