1
0
forked from ScoDoc/ScoDoc

Délivrance diplôme BUT: vérifie ECTS du parcours

This commit is contained in:
Emmanuel Viennet 2024-08-25 22:00:29 +02:00
parent 22a0b9912b
commit 73c263b895
4 changed files with 79 additions and 16 deletions

View File

@ -18,7 +18,6 @@ from collections.abc import Iterable
from operator import attrgetter from operator import attrgetter
from flask import g, url_for from flask import g, url_for
from flask_sqlalchemy.query import Query
from app import db, log from app import db, log
from app.comp.res_but import ResultatsSemestreBUT from app.comp.res_but import ResultatsSemestreBUT
@ -38,7 +37,12 @@ from app.models.formsemestre import FormSemestre
from app.models.ues import UniteEns from app.models.ues import UniteEns
from app.models.validations import ScolarFormSemestreValidation from app.models.validations import ScolarFormSemestreValidation
from app.scodoc import codes_cursus as sco_codes from app.scodoc import codes_cursus as sco_codes
from app.scodoc.codes_cursus import code_ue_validant, CODES_UE_VALIDES, UE_STANDARD from app.scodoc.codes_cursus import (
code_ue_validant,
CODES_UE_VALIDES,
CursusBUT,
UE_STANDARD,
)
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
from app.scodoc import sco_cursus_dut from app.scodoc import sco_cursus_dut
@ -56,24 +60,39 @@ class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
return False return False
def parcours_validated(self): def parcours_validated(self):
"True si le parcours (ici diplôme BUT) est validé" """True si le parcours (ici diplôme BUT) est validé.
return but_parcours_validated( Considère le parcours du semestre en cours (res).
self.etud.id, self.cur_sem.formation.referentiel_competence_id
)
def but_parcours_validated(etudid: int, referentiel_competence_id: int) -> bool:
"""Détermine si le parcours BUT est validé:
ne regarde que si une validation BUT3 est enregistrée
""" """
parcour_id = self.nt.etuds_parcour_id.get(self.etud.id)
return but_parcours_validated(self.etud.id, parcour_id)
def but_annee_validated(
etudid: int, referentiel_competence_id: int, annee: int = 3
) -> bool:
"""Vrai si une validation de l'année BUT est enregistrée"""
return any( return any(
sco_codes.code_annee_validant(v.code) sco_codes.code_annee_validant(v.code)
for v in ApcValidationAnnee.query.filter_by( for v in ApcValidationAnnee.query.filter_by(
etudid=etudid, ordre=3, referentiel_competence_id=referentiel_competence_id etudid=etudid,
ordre=annee,
referentiel_competence_id=referentiel_competence_id,
) )
) )
def but_parcours_validated(etudid: int, 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)
ects_acquis = validations_count_ects(validations)
return ects_acquis >= CursusBUT.ECTS_DIPLOME
class EtudCursusBUT: class EtudCursusBUT:
"""L'état de l'étudiant dans son cursus BUT """L'état de l'étudiant dans son cursus BUT
Liste des niveaux validés/à valider Liste des niveaux validés/à valider
@ -395,9 +414,18 @@ def but_ects_valides(
Si annees_but est spécifié, un iterable "BUT1, "BUT2" par exemple, ne prend que ces années. 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(etud, referentiel_competence_id, annees_but)
return validations_count_ects(validations)
def validations_count_ects(validations: list[ScolarFormSemestreValidation]) -> int:
"""Somme les ECTS validés par ces UEs, en éliminant les éventuels
doublons (niveaux de compétences validés plusieurs fois)"""
ects_dict = {} ects_dict = {}
for v in validations: for v in validations:
key = (v.ue.semestre_idx, v.ue.niveau_competence.id) key = (
v.ue.semestre_idx,
v.ue.niveau_competence.id if v.ue.niveau_competence else None,
)
if v.code in CODES_UE_VALIDES: if v.code in CODES_UE_VALIDES:
ects_dict[key] = v.ue.ects or 0.0 ects_dict[key] = v.ue.ects or 0.0
@ -427,8 +455,12 @@ def but_validations_ues(
validations = validations.join(ApcCompetence).filter_by( validations = validations.join(ApcCompetence).filter_by(
referentiel_id=referentiel_competence_id referentiel_id=referentiel_competence_id
) )
return sorted_validations(validations)
# Tri (nb: fait en python pour gérer les validations externes qui n'ont pas de formsemestre)
def sorted_validations(validations) -> list[ScolarFormSemestreValidation]:
"""Tri (nb: fait en python pour gérer les validations externes qui
n'ont pas de formsemestre)"""
return sorted( return sorted(
validations, validations,
key=lambda v: ( key=lambda v: (
@ -439,6 +471,37 @@ def but_validations_ues(
) )
def but_validations_ues_parcours(
etudid: int, parcour_id: int
) -> list[ScolarFormSemestreValidation]:
"""Query les validations d'UEs pour cet étudiant
dans des UEs appartenant à ce parcours ou à son tronc commun.
"""
# Rappel:
# Les UEs associées à un parcours:
# UniteEns.query.join(UEParcours).filter(UEParcours.parcours_id == parcour.id) )
# Les UEs associées au tronc commun (à aucun parcours)
# UniteEns.query.filter(~UniteEns.id.in_(UEParcours.query.with_entities(UEParcours.ue_id)))
# Les validations d'UE de ce parcours ou du tronc commun pour cet étudiant:
validations = (
ScolarFormSemestreValidation.query.filter_by(etudid=etudid)
.filter(ScolarFormSemestreValidation.ue_id != None)
.join(UniteEns)
.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)),
)
)
)
return sorted_validations(validations)
def etud_ues_de_but1_non_validees( def etud_ues_de_but1_non_validees(
etud: Identite, formation: Formation, parcour: ApcParcours etud: Identite, formation: Formation, parcour: ApcParcours
) -> list[UniteEns]: ) -> list[UniteEns]:

View File

@ -113,7 +113,7 @@ class TableJury(TableRecap):
if res.is_apc and res.formsemestre.semestre_id == 6: 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 # on ne vérifie le diplôme que dans ce cas pour ne pas ralentir
if cursus_but.but_parcours_validated( if cursus_but.but_parcours_validated(
etud.id, res.formsemestre.formation.referentiel_competence_id etud.id, res.etuds_parcour_id.get(etud.id)
): ):
row.add_cell( row.add_cell(
"autorisations_inscription", "autorisations_inscription",

View File

@ -44,7 +44,7 @@ une formation utilisant une autre version de référentiel, pensez à revalider
</div> </div>
</form> </form>
{% else %} {% else %}
<div class="warning"> <div class="warning space-before-24">
{% if validation %} {% if validation %}
DUT déjà validé dans cette spécialité DUT déjà validé dans cette spécialité
<b>{{formsemestre.formation.referentiel_competence.get_title()}}</b> <b>{{formsemestre.formation.referentiel_competence.get_title()}}</b>

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.7.11" SCOVERSION = "9.7.12"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"