|
|
@ -37,6 +37,7 @@ Created on 17/01/2024
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
import pandas as pd
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from app import ScoValueError
|
|
|
|
from app.models import FormSemestre, Identite, Formation
|
|
|
|
from app.models import FormSemestre, Identite, Formation
|
|
|
|
from app.pe import pe_comp, pe_affichage
|
|
|
|
from app.pe import pe_comp, pe_affichage
|
|
|
|
from app.scodoc import codes_cursus
|
|
|
|
from app.scodoc import codes_cursus
|
|
|
@ -87,7 +88,7 @@ class EtudiantsJuryPE:
|
|
|
|
self.abandons_ids = {}
|
|
|
|
self.abandons_ids = {}
|
|
|
|
"""Les etudids des étudiants redoublants/réorientés"""
|
|
|
|
"""Les etudids des étudiants redoublants/réorientés"""
|
|
|
|
|
|
|
|
|
|
|
|
def find_etudiants(self):
|
|
|
|
def find_etudiants(self, formsemestre_base: FormSemestre):
|
|
|
|
"""Liste des étudiants à prendre en compte dans le jury PE, en les recherchant
|
|
|
|
"""Liste des étudiants à prendre en compte dans le jury PE, en les recherchant
|
|
|
|
de manière automatique par rapport à leur année de diplomation ``annee_diplome``.
|
|
|
|
de manière automatique par rapport à leur année de diplomation ``annee_diplome``.
|
|
|
|
|
|
|
|
|
|
|
@ -116,7 +117,7 @@ class EtudiantsJuryPE:
|
|
|
|
self.identites[etudid] = Identite.get_etud(etudid)
|
|
|
|
self.identites[etudid] = Identite.get_etud(etudid)
|
|
|
|
|
|
|
|
|
|
|
|
# Analyse son cursus
|
|
|
|
# Analyse son cursus
|
|
|
|
self.analyse_etat_etudiant(etudid, cosemestres)
|
|
|
|
self.analyse_etat_etudiant(etudid, cosemestres, formsemestre_base)
|
|
|
|
|
|
|
|
|
|
|
|
# Analyse son parcours pour atteindre chaque semestre de la formation
|
|
|
|
# Analyse son parcours pour atteindre chaque semestre de la formation
|
|
|
|
self.structure_cursus_etudiant(etudid)
|
|
|
|
self.structure_cursus_etudiant(etudid)
|
|
|
@ -187,7 +188,12 @@ class EtudiantsJuryPE:
|
|
|
|
etudiants = {etudid: self.identites[etudid] for etudid in etudids}
|
|
|
|
etudiants = {etudid: self.identites[etudid] for etudid in etudids}
|
|
|
|
return etudiants
|
|
|
|
return etudiants
|
|
|
|
|
|
|
|
|
|
|
|
def analyse_etat_etudiant(self, etudid: int, cosemestres: dict[int, FormSemestre]):
|
|
|
|
def analyse_etat_etudiant(
|
|
|
|
|
|
|
|
self,
|
|
|
|
|
|
|
|
etudid: int,
|
|
|
|
|
|
|
|
cosemestres: dict[int, FormSemestre],
|
|
|
|
|
|
|
|
formsemestre_base: FormSemestre,
|
|
|
|
|
|
|
|
):
|
|
|
|
"""Analyse le cursus d'un étudiant pouvant être :
|
|
|
|
"""Analyse le cursus d'un étudiant pouvant être :
|
|
|
|
|
|
|
|
|
|
|
|
* l'un de ceux sur lesquels le jury va statuer (année de diplômation du jury considéré)
|
|
|
|
* l'un de ceux sur lesquels le jury va statuer (année de diplômation du jury considéré)
|
|
|
@ -198,8 +204,10 @@ class EtudiantsJuryPE:
|
|
|
|
|
|
|
|
|
|
|
|
* à insérer une entrée dans ``self.cursus`` pour mémoriser son identité,
|
|
|
|
* à insérer une entrée dans ``self.cursus`` pour mémoriser son identité,
|
|
|
|
avec son nom, prénom, etc...
|
|
|
|
avec son nom, prénom, etc...
|
|
|
|
* à analyser son parcours, pour déterminer s'il n'a (ou non) abandonné l'IUT en cours de
|
|
|
|
* à analyser son parcours, pour déterminer s'il a démissionné, redoublé (autre année de diplôme)
|
|
|
|
route (cf. clé abandon)
|
|
|
|
ou a abandonné l'IUT en cours de route (cf. clé abandon). Un étudiant est considéré en abandon s'il n'est
|
|
|
|
|
|
|
|
inscrit à aucun cosemestres de rang supérieur ou égal (et donc de dates)
|
|
|
|
|
|
|
|
à celui ayant servi à lancer le jury (`formsemestre_base`)
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
Args:
|
|
|
|
etudid: L'etudid d'un étudiant, à ajouter à ceux traiter par le jury
|
|
|
|
etudid: L'etudid d'un étudiant, à ajouter à ceux traiter par le jury
|
|
|
@ -232,15 +240,19 @@ class EtudiantsJuryPE:
|
|
|
|
"abandon": False, # va être traité en dessous
|
|
|
|
"abandon": False, # va être traité en dessous
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Si l'étudiant est succeptible d'être diplomé
|
|
|
|
|
|
|
|
if self.cursus[etudid]["diplome"] == self.annee_diplome:
|
|
|
|
# Est-il démissionnaire : charge son dernier semestre pour connaitre son état ?
|
|
|
|
# Est-il démissionnaire : charge son dernier semestre pour connaitre son état ?
|
|
|
|
dernier_semes_etudiant = formsemestres[0]
|
|
|
|
dernier_semes_etudiant = formsemestres[0]
|
|
|
|
res = load_formsemestre_results(dernier_semes_etudiant)
|
|
|
|
res = load_formsemestre_results(dernier_semes_etudiant)
|
|
|
|
etud_etat = res.get_etud_etat(etudid)
|
|
|
|
etud_etat = res.get_etud_etat(etudid)
|
|
|
|
if etud_etat == scu.DEMISSION:
|
|
|
|
if etud_etat == scu.DEMISSION:
|
|
|
|
self.cursus[etudid]["abandon"] |= True
|
|
|
|
self.cursus[etudid]["abandon"] = True
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
# Est-il réorienté ou a-t-il arrêté volontairement sa formation ?
|
|
|
|
# Est-il réorienté ou a-t-il arrêté (volontairement) sa formation ?
|
|
|
|
self.cursus[etudid]["abandon"] |= arret_de_formation(identite, cosemestres)
|
|
|
|
self.cursus[etudid]["abandon"] = arret_de_formation(
|
|
|
|
|
|
|
|
identite, cosemestres, formsemestre_base
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def get_semestres_significatifs(self, etudid: int):
|
|
|
|
def get_semestres_significatifs(self, etudid: int):
|
|
|
|
"""Ensemble des semestres d'un étudiant, qui l'auraient amené à être diplomé
|
|
|
|
"""Ensemble des semestres d'un étudiant, qui l'auraient amené à être diplomé
|
|
|
@ -446,8 +458,10 @@ def get_semestres_apc(identite: Identite) -> list:
|
|
|
|
return semestres_apc
|
|
|
|
return semestres_apc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def arret_de_formation(etud: Identite, cosemestres: list[FormSemestre]) -> bool:
|
|
|
|
def arret_de_formation(
|
|
|
|
"""Détermine si un étudiant a arrêté sa formation. Il peut s'agir :
|
|
|
|
etud: Identite, cosemestres: dict[int, FormSemestre], formsemestre_base: FormSemestre
|
|
|
|
|
|
|
|
) -> bool:
|
|
|
|
|
|
|
|
"""Détermine si un étudiant a arrêté sa formation (volontairement ou non). Il peut s'agir :
|
|
|
|
|
|
|
|
|
|
|
|
* d'une réorientation à l'initiative du jury de semestre ou d'une démission
|
|
|
|
* d'une réorientation à l'initiative du jury de semestre ou d'une démission
|
|
|
|
(on pourrait utiliser les code NAR pour réorienté & DEM pour démissionnaire
|
|
|
|
(on pourrait utiliser les code NAR pour réorienté & DEM pour démissionnaire
|
|
|
@ -458,7 +472,9 @@ def arret_de_formation(etud: Identite, cosemestres: list[FormSemestre]) -> bool:
|
|
|
|
|
|
|
|
|
|
|
|
Dans les cas, on considérera que l'étudiant a arrêté sa formation s'il n'est pas
|
|
|
|
Dans les cas, on considérera que l'étudiant a arrêté sa formation s'il n'est pas
|
|
|
|
dans l'un des "derniers" cosemestres (semestres conduisant à la même année de diplômation)
|
|
|
|
dans l'un des "derniers" cosemestres (semestres conduisant à la même année de diplômation)
|
|
|
|
connu dans Scodoc.
|
|
|
|
connu dans Scodoc. Par "derniers" cosemestres, est fait le choix d'analyser tous les cosemestres
|
|
|
|
|
|
|
|
de rang/semestre_id supérieur ou égal (et donc de dates) à celui du ``formsemestre_base`` ayant servi à lancer
|
|
|
|
|
|
|
|
le jury PE.
|
|
|
|
|
|
|
|
|
|
|
|
Par ex: au moment du jury PE en fin de S5 (pas de S6 renseigné dans Scodoc),
|
|
|
|
Par ex: au moment du jury PE en fin de S5 (pas de S6 renseigné dans Scodoc),
|
|
|
|
l'étudiant doit appartenir à une instance des S5 qui conduisent à la diplomation dans
|
|
|
|
l'étudiant doit appartenir à une instance des S5 qui conduisent à la diplomation dans
|
|
|
@ -493,42 +509,79 @@ def arret_de_formation(etud: Identite, cosemestres: list[FormSemestre]) -> bool:
|
|
|
|
if not semestres_apc:
|
|
|
|
if not semestres_apc:
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
# Son dernier semestre APC en date
|
|
|
|
# Les cosemestres de rang supérieur ou égal à celui de formsemestre, triés par rang,
|
|
|
|
dernier_formsemestre = get_dernier_semestre_en_date(semestres_apc)
|
|
|
|
# sous la forme ``{semestre_id: [liste des comestres associé à ce semestre_id]}``
|
|
|
|
numero_dernier_formsemestre = dernier_formsemestre.semestre_id
|
|
|
|
cosemestres_tries_par_rang = pe_comp.tri_semestres_par_rang(cosemestres)
|
|
|
|
|
|
|
|
|
|
|
|
# Les numéro de semestres possible dans lesquels il pourrait s'incrire
|
|
|
|
cosemestres_superieurs = {}
|
|
|
|
# semestre impair => passage de droit en semestre pair suivant (effet de l'annualisation)
|
|
|
|
for rang in cosemestres_tries_par_rang:
|
|
|
|
if numero_dernier_formsemestre % 2 == 1:
|
|
|
|
if rang >= formsemestre_base.semestre_id:
|
|
|
|
numeros_possibles = list(
|
|
|
|
cosemestres_superieurs[rang] = cosemestres_tries_par_rang[rang]
|
|
|
|
range(numero_dernier_formsemestre + 1, pe_comp.NBRE_SEMESTRES_DIPLOMANT)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
# semestre pair => passage en année supérieure ou redoublement
|
|
|
|
|
|
|
|
else: #
|
|
|
|
|
|
|
|
numeros_possibles = list(
|
|
|
|
|
|
|
|
range(
|
|
|
|
|
|
|
|
max(numero_dernier_formsemestre - 1, 1),
|
|
|
|
|
|
|
|
pe_comp.NBRE_SEMESTRES_DIPLOMANT,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Y-a-t-il des cosemestres dans lesquels il aurait pu s'incrire ?
|
|
|
|
|
|
|
|
formsestres_superieurs_possibles = []
|
|
|
|
|
|
|
|
for fid, sem in cosemestres.items(): # Les semestres ayant des inscrits
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
fid != dernier_formsemestre.formsemestre_id
|
|
|
|
|
|
|
|
and sem.semestre_id in numeros_possibles
|
|
|
|
|
|
|
|
and sem.date_debut.year >= dernier_formsemestre.date_debut.year
|
|
|
|
|
|
|
|
):
|
|
|
|
|
|
|
|
# date de debut des semestres possibles postérieur au dernier semestre de l'étudiant
|
|
|
|
|
|
|
|
# et de niveau plus élevé que le dernier semestre valide de l'étudiant
|
|
|
|
|
|
|
|
formsestres_superieurs_possibles.append(fid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(formsestres_superieurs_possibles) > 0:
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Si pas d'autres cosemestres postérieurs
|
|
|
|
|
|
|
|
if not cosemestres_superieurs:
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Pour chaque rang de (co)semestres, y-a-il un dans lequel il est inscrit ?
|
|
|
|
|
|
|
|
etat_inscriptions = {rang: False for rang in cosemestres_superieurs}
|
|
|
|
|
|
|
|
for rang in etat_inscriptions:
|
|
|
|
|
|
|
|
for sem in cosemestres_superieurs[rang]:
|
|
|
|
|
|
|
|
etudiants_du_sem = {ins.etudid for ins in sem.inscriptions}
|
|
|
|
|
|
|
|
if etud.etudid in etudiants_du_sem:
|
|
|
|
|
|
|
|
etat_inscriptions[rang] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Vérifie qu'il n'y a pas de "trous" dans les rangs des cosemestres
|
|
|
|
|
|
|
|
rangs = etat_inscriptions.keys()
|
|
|
|
|
|
|
|
if list(rangs) != list(range(min(rangs), max(rangs)+1)):
|
|
|
|
|
|
|
|
difference = set(range(min(rangs), max(rangs)+1)) - set(rangs)
|
|
|
|
|
|
|
|
affichage = ",".join([f"S{val}" for val in difference])
|
|
|
|
|
|
|
|
raise ScoValueError(f"Il manque le(s) semestre(s) {affichage} au cursus de vos étudiants.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Est-il inscrit à tous les semestres de rang supérieur ? Si non, est démissionnaire
|
|
|
|
|
|
|
|
est_demissionnaire = sum(etat_inscriptions.values()) != len(rangs)
|
|
|
|
|
|
|
|
if est_demissionnaire:
|
|
|
|
|
|
|
|
non_inscrit_a = [rang for rang in etat_inscriptions if not etat_inscriptions[rang]]
|
|
|
|
|
|
|
|
affichage = ",".join([f"S{val}" for val in non_inscrit_a])
|
|
|
|
|
|
|
|
pe_affichage.pe_print(f"{etud.etat_civil} ({etud.etudid} considéré en abandon car non inscrit dans un (ou des) semestre(s) {affichage} amenant à diplômation")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return est_demissionnaire
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # Son dernier semestre APC en date
|
|
|
|
|
|
|
|
# dernier_formsemestre = get_dernier_semestre_en_date(semestres_apc)
|
|
|
|
|
|
|
|
# numero_dernier_formsemestre = dernier_formsemestre.semestre_id
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# # Les numéro de semestres possible dans lesquels il pourrait s'incrire
|
|
|
|
|
|
|
|
# # semestre impair => passage de droit en semestre pair suivant (effet de l'annualisation)
|
|
|
|
|
|
|
|
# if numero_dernier_formsemestre % 2 == 1:
|
|
|
|
|
|
|
|
# numeros_possibles = list(
|
|
|
|
|
|
|
|
# range(numero_dernier_formsemestre + 1, pe_comp.NBRE_SEMESTRES_DIPLOMANT)
|
|
|
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
# # semestre pair => passage en année supérieure ou redoublement
|
|
|
|
|
|
|
|
# else: #
|
|
|
|
|
|
|
|
# numeros_possibles = list(
|
|
|
|
|
|
|
|
# range(
|
|
|
|
|
|
|
|
# max(numero_dernier_formsemestre - 1, 1),
|
|
|
|
|
|
|
|
# pe_comp.NBRE_SEMESTRES_DIPLOMANT,
|
|
|
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# # Y-a-t-il des cosemestres dans lesquels il aurait pu s'incrire ?
|
|
|
|
|
|
|
|
# formsestres_superieurs_possibles = []
|
|
|
|
|
|
|
|
# for fid, sem in cosemestres.items(): # Les semestres ayant des inscrits
|
|
|
|
|
|
|
|
# if (
|
|
|
|
|
|
|
|
# fid != dernier_formsemestre.formsemestre_id
|
|
|
|
|
|
|
|
# and sem.semestre_id in numeros_possibles
|
|
|
|
|
|
|
|
# and sem.date_debut.year >= dernier_formsemestre.date_debut.year
|
|
|
|
|
|
|
|
# ):
|
|
|
|
|
|
|
|
# # date de debut des semestres possibles postérieur au dernier semestre de l'étudiant
|
|
|
|
|
|
|
|
# # et de niveau plus élevé que le dernier semestre valide de l'étudiant
|
|
|
|
|
|
|
|
# formsestres_superieurs_possibles.append(fid)
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# if len(formsestres_superieurs_possibles) > 0:
|
|
|
|
|
|
|
|
# return True
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_dernier_semestre_en_date(semestres: dict[int, FormSemestre]) -> FormSemestre:
|
|
|
|
def get_dernier_semestre_en_date(semestres: dict[int, FormSemestre]) -> FormSemestre:
|
|
|
|
"""Renvoie le dernier semestre en **date de fin** d'un dictionnaire
|
|
|
|
"""Renvoie le dernier semestre en **date de fin** d'un dictionnaire
|
|
|
|