forked from ScoDoc/ScoDoc
WIP: jurys BUT
This commit is contained in:
parent
109e00b6eb
commit
483de3ed0b
245
app/but/jury_but.py
Normal file
245
app/but/jury_but.py
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
##############################################################################
|
||||||
|
# ScoDoc
|
||||||
|
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||||
|
# See LICENSE
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Jury BUT: logique de gestion
|
||||||
|
"""
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.models import but_validations
|
||||||
|
from app.models.but_refcomp import (
|
||||||
|
ApcAnneeParcours,
|
||||||
|
ApcCompetence,
|
||||||
|
ApcNiveau,
|
||||||
|
ApcParcoursNiveauCompetence,
|
||||||
|
)
|
||||||
|
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
|
||||||
|
from app.models.etudiants import Identite
|
||||||
|
from app.models.formations import Formation
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
|
from app.models.ues import UniteEns
|
||||||
|
from app.scodoc import sco_codes_parcours as codes
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
from app.scodoc.sco_exceptions import ScoException
|
||||||
|
|
||||||
|
|
||||||
|
class RegroupementCoherentUE:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
etud: Identite,
|
||||||
|
formsemestre_1: FormSemestre,
|
||||||
|
ue_1: UniteEns,
|
||||||
|
formsemestre_2: FormSemestre,
|
||||||
|
ue_2: UniteEns,
|
||||||
|
):
|
||||||
|
self.formsemestre_1 = formsemestre_1
|
||||||
|
self.ue_1 = ue_1
|
||||||
|
self.formsemestre_2 = formsemestre_2
|
||||||
|
self.ue_2 = ue_2
|
||||||
|
# stocke les moyennes d'UE
|
||||||
|
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre_1)
|
||||||
|
if ue_1.id in res.etud_moy_ue and etud.id in res.etud_moy_ue[ue_1.id]:
|
||||||
|
self.moy_ue_1 = res.etud_moy_ue[ue_1.id][etud.id]
|
||||||
|
else:
|
||||||
|
self.moy_ue_1 = None
|
||||||
|
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre_2)
|
||||||
|
if ue_2.id in res.etud_moy_ue and etud.id in res.etud_moy_ue[ue_2.id]:
|
||||||
|
self.moy_ue_2 = res.etud_moy_ue[ue_1.id][etud.id]
|
||||||
|
else:
|
||||||
|
self.moy_ue_2 = None
|
||||||
|
# Calcul de la moyenne au RCUE
|
||||||
|
if (self.moy_ue_1 is not None) and (self.moy_ue_2 is not None):
|
||||||
|
# Moyenne RCUE non pondérée (pour le moment)
|
||||||
|
self.moy_rcue = (self.moy_ue_1 + self.moy_ue_2) / 2
|
||||||
|
else:
|
||||||
|
self.moy_rcue = None
|
||||||
|
|
||||||
|
|
||||||
|
class DecisionsProposees:
|
||||||
|
# Codes toujours proposés sauf si include_communs est faux:
|
||||||
|
codes_communs = [codes.RAT, codes.DEF, codes.ABAN, codes.DEM, codes.UEBSL]
|
||||||
|
|
||||||
|
def __init__(self, code: str = None, explanation="", include_communs=True):
|
||||||
|
if include_communs:
|
||||||
|
self.codes = self.codes_communs
|
||||||
|
else:
|
||||||
|
self.codes = []
|
||||||
|
if isinstance(code, list):
|
||||||
|
self.codes = code + self.codes_communs
|
||||||
|
elif code is not None:
|
||||||
|
self.codes = [code] + self.codes_communs
|
||||||
|
self.explanation = explanation
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"""<{self.__class__.__name__} codes={self.codes} explanation={self.explanation}"""
|
||||||
|
|
||||||
|
|
||||||
|
def decisions_ue_proposees(
|
||||||
|
etud: Identite, formsemestre: FormSemestre, ue: UniteEns
|
||||||
|
) -> DecisionsProposees:
|
||||||
|
"""Liste des codes de décisions que l'on peut proposer pour
|
||||||
|
cette UE de cet étudiant dans ce semestre.
|
||||||
|
|
||||||
|
si DEF ou DEM ou ABAN ou ABL sur année BUT: seulement DEF, DEM, ABAN, ABL
|
||||||
|
|
||||||
|
si moy_ue > 10, ADM
|
||||||
|
sinon si compensation dans RCUE: CMP
|
||||||
|
sinon: ADJ, AJ
|
||||||
|
et proposer toujours: RAT, DEF, ABAN, DEM, UEBSL
|
||||||
|
"""
|
||||||
|
if ue.type == codes.UE_SPORT:
|
||||||
|
return DecisionsProposees(
|
||||||
|
explanation="UE bonus, pas de décision de jury", include_communs=False
|
||||||
|
)
|
||||||
|
# Code sur année ?
|
||||||
|
decision_annee = ApcValidationAnnee.query.filter_by(
|
||||||
|
etudid=etud.id, annee_scolaire=formsemestre.annee_scolaire()
|
||||||
|
).first()
|
||||||
|
if (
|
||||||
|
decision_annee is not None and decision_annee.code in codes.CODES_ANNEE_ARRET
|
||||||
|
): # DEF, DEM, ABAN, ABL
|
||||||
|
return DecisionsProposees(
|
||||||
|
code=decision_annee.code,
|
||||||
|
explanation=f"l'année a le code {decision_annee.code}",
|
||||||
|
include_communs=False,
|
||||||
|
)
|
||||||
|
# Moyenne de l'UE ?
|
||||||
|
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
if not ue.id in res.etud_moy_ue:
|
||||||
|
return DecisionsProposees(explanation="UE sans résultat")
|
||||||
|
if not etud.id in res.etud_moy_ue[ue.id]:
|
||||||
|
return DecisionsProposees(explanation="Étudiant sans résultat dans cette UE")
|
||||||
|
moy_ue = res.etud_moy_ue[ue.id][etud.id]
|
||||||
|
if moy_ue > (codes.ParcoursBUT.BARRE_MOY - codes.NOTES_TOLERANCE):
|
||||||
|
return DecisionsProposees(
|
||||||
|
code=codes.ADM,
|
||||||
|
explanation=f"Moyenne >= {codes.ParcoursBUT.BARRE_MOY}/20",
|
||||||
|
)
|
||||||
|
# Compensation dans le RCUE ?
|
||||||
|
other_ue, other_formsemestre = but_validations.get_other_ue_rcue(ue, etud.id)
|
||||||
|
if other_ue is not None:
|
||||||
|
# inscrit à une autre UE du même RCUE
|
||||||
|
other_res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(
|
||||||
|
other_formsemestre
|
||||||
|
)
|
||||||
|
if (other_ue.id in other_res.etud_moy_ue) and (
|
||||||
|
etud.id in other_res.etud_moy_ue[other_ue.id]
|
||||||
|
):
|
||||||
|
other_moy_ue = other_res.etud_moy_ue[other_ue.id][etud.id]
|
||||||
|
# Moyenne RCUE: non pondérée (pour le moment)
|
||||||
|
moy_rcue = (moy_ue + other_moy_ue) / 2
|
||||||
|
if moy_rcue > codes.NOTES_BARRE_GEN_COMPENSATION: # 10-epsilon
|
||||||
|
return DecisionsProposees(
|
||||||
|
code=codes.CMP,
|
||||||
|
explanation=f"Compensée par {other_ue} (moyenne RCUE={scu.fmt_note(moy_rcue)}/20",
|
||||||
|
)
|
||||||
|
return DecisionsProposees(
|
||||||
|
code=[codes.AJ, codes.ADJ],
|
||||||
|
explanation="notes insuffisantes",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def decisions_rcue_proposees(
|
||||||
|
etud: Identite,
|
||||||
|
formsemestre_1: FormSemestre,
|
||||||
|
ue_1: UniteEns,
|
||||||
|
formsemestre_2: FormSemestre,
|
||||||
|
ue_2: UniteEns,
|
||||||
|
) -> DecisionsProposees:
|
||||||
|
"""Liste des codes de décisions que l'on peut proposer pour
|
||||||
|
le RCUE de cet étudiant dans ces semestres.
|
||||||
|
|
||||||
|
ADM, CMP, ADJ, AJ, RAT, DEF, ABAN
|
||||||
|
|
||||||
|
La validation des deux UE du niveau d’une compétence emporte la validation de
|
||||||
|
l’ensemble des UE du niveau inférieur de cette même compétence.
|
||||||
|
"""
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class BUTCursusEtud:
|
||||||
|
"""Validation du cursus d'un étudiant"""
|
||||||
|
|
||||||
|
def __init__(self, formsemestre: FormSemestre, etud: Identite):
|
||||||
|
if formsemestre.formation.referentiel_competence is None:
|
||||||
|
raise ScoException("BUTCursusEtud: pas de référentiel de compétences")
|
||||||
|
assert len(etud.formsemestre_inscriptions) > 0
|
||||||
|
self.formsemestre = formsemestre
|
||||||
|
self.etud = etud
|
||||||
|
#
|
||||||
|
# La dernière inscription en date va donner le parcours (donc les compétences à valider)
|
||||||
|
self.last_inscription = sorted(
|
||||||
|
etud.formsemestre_inscriptions, key=attrgetter("formsemestre.date_debut")
|
||||||
|
)[-1]
|
||||||
|
|
||||||
|
def est_diplomable(self) -> bool:
|
||||||
|
"""Vrai si toutes les compétences sont validables"""
|
||||||
|
return all(
|
||||||
|
self.competence_validable(competence)
|
||||||
|
for competence in self.competences_du_parcours()
|
||||||
|
)
|
||||||
|
|
||||||
|
def est_diplome(self) -> bool:
|
||||||
|
"""Vrai si BUT déjà validé"""
|
||||||
|
# vrai si la troisième année est validée
|
||||||
|
# On cherche les validations de 3ieme annee (ordre=3) avec le même référentiel
|
||||||
|
# de formation que nous.
|
||||||
|
return (
|
||||||
|
ApcValidationAnnee.query.filter_by(etudid=self.etud.id, ordre=3)
|
||||||
|
.join(FormSemestre, FormSemestre.id == ApcValidationAnnee.formsemestre_id)
|
||||||
|
.join(Formation, FormSemestre.formation_id == Formation.id)
|
||||||
|
.filter(
|
||||||
|
Formation.referentiel_competence_id
|
||||||
|
== self.formsemestre.formation.referentiel_competence_id
|
||||||
|
)
|
||||||
|
.count()
|
||||||
|
> 0
|
||||||
|
)
|
||||||
|
|
||||||
|
def competences_du_parcours(self) -> list[ApcCompetence]:
|
||||||
|
"""Construit liste des compétences du parcours, qui doivent être
|
||||||
|
validées pour obtenir le diplôme.
|
||||||
|
Le parcours est celui de la dernière inscription.
|
||||||
|
"""
|
||||||
|
parcour = self.last_inscription.parcour
|
||||||
|
query = self.formsemestre.formation.formation.query_competences_parcour(parcour)
|
||||||
|
if query is None:
|
||||||
|
return []
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
def competence_validee(self, competence: ApcCompetence) -> bool:
|
||||||
|
"""Vrai si la compétence est validée, c'est à dire que tous ses
|
||||||
|
niveaux sont validés (ApcValidationRCUE).
|
||||||
|
"""
|
||||||
|
validations = (
|
||||||
|
ApcValidationRCUE.query.filter_by(etudid=self.etud.id)
|
||||||
|
.join(UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id)
|
||||||
|
.join(ApcNiveau, ApcNiveau.id == UniteEns.niveau_competence_id)
|
||||||
|
.join(ApcCompetence, ApcCompetence.id == ApcNiveau.competence_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
def competence_validable(self, competence: ApcCompetence):
|
||||||
|
"""Vrai si la compétence est "validable" automatiquement, c'est à dire
|
||||||
|
que les conditions de notes sont satisfaites pour l'acquisition de
|
||||||
|
son niveau le plus élevé, qu'il ne manque que l'enregistrement de la décision.
|
||||||
|
|
||||||
|
En vertu de la règle "La validation des deux UE du niveau d’une compétence
|
||||||
|
emporte la validation de l'ensemble des UE du niveau inférieur de cette
|
||||||
|
même compétence.",
|
||||||
|
il suffit de considérer le dernier niveau dans lequel l'étudiant est inscrit.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ues_emportees(self, niveau: ApcNiveau) -> list[tuple[FormSemestre, UniteEns]]:
|
||||||
|
"""La liste des UE à valider si on valide ce niveau.
|
||||||
|
Ne liste que les UE qui ne sont pas déjà acquises.
|
||||||
|
|
||||||
|
Selon la règle donéne par l'arrêté BUT:
|
||||||
|
* La validation des deux UE du niveau d’une compétence emporte la validation de
|
||||||
|
l'ensemble des UE du niveau inférieur de cette même compétence.
|
||||||
|
"""
|
||||||
|
pass
|
@ -219,7 +219,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
|
|
||||||
def etud_ues_ids(self, etudid: int) -> list[int]:
|
def etud_ues_ids(self, etudid: int) -> list[int]:
|
||||||
"""Liste des id d'UE auxquelles l'étudiant est inscrit (sans bonus).
|
"""Liste des id d'UE auxquelles l'étudiant est inscrit (sans bonus).
|
||||||
(surchargée en BUT pour prendre en compte les parcours)
|
(surchargée ici pour prendre en compte les parcours)
|
||||||
"""
|
"""
|
||||||
s = self.ues_inscr_parcours_df.loc[etudid]
|
s = self.ues_inscr_parcours_df.loc[etudid]
|
||||||
return s.index[s.notna()]
|
return s.index[s.notna()]
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
# -*- coding: UTF-8 -*
|
# -*- coding: UTF-8 -*
|
||||||
|
|
||||||
"""Décisions de jury validations) des RCUE et années du BUT
|
"""Décisions de jury (validations) des RCUE et années du BUT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app import db
|
from sqlalchemy.sql import text
|
||||||
from app import log
|
|
||||||
|
|
||||||
|
from app import db
|
||||||
from app.models import CODE_STR_LEN
|
from app.models import CODE_STR_LEN
|
||||||
|
from app.models.but_refcomp import ApcNiveau
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
from app.models.formsemestre import FormSemestre
|
||||||
|
|
||||||
|
|
||||||
class ApcValidationRCUE(db.Model):
|
class ApcValidationRCUE(db.Model):
|
||||||
@ -51,24 +52,68 @@ class ApcValidationRCUE(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} {self.id} {self.etud} {self.ue1}/{self.ue2}:{self.code!r}>"
|
return f"<{self.__class__.__name__} {self.id} {self.etud} {self.ue1}/{self.ue2}:{self.code!r}>"
|
||||||
|
|
||||||
|
def niveau(self) -> ApcNiveau:
|
||||||
|
"""Le niveau de compétence associé à cet RCUE."""
|
||||||
|
# Par convention, il est donné par la seconde UE
|
||||||
|
return self.ue2.niveau_competence
|
||||||
|
|
||||||
def get_other_ue_rcue(ue: UniteEns, etudid: int) -> UniteEns:
|
|
||||||
"""L'autre UE du RCUE (niveau de compétence) pour cet étudiant,
|
def get_other_ue_rcue(ue: UniteEns, etudid: int) -> tuple[UniteEns, FormSemestre]:
|
||||||
None si pas trouvée.
|
"""L'autre UE du RCUE (niveau de compétence) pour cet étudiant.
|
||||||
|
|
||||||
|
Cherche une UE du même niveau de compétence, à laquelle l'étudiant soit inscrit.
|
||||||
|
Résultat: le couple (UE, FormSemestre), ou (None, None) si pas trouvée.
|
||||||
"""
|
"""
|
||||||
if (ue.niveau_competence is None) or (ue.semestre_idx is None):
|
if (ue.niveau_competence is None) or (ue.semestre_idx is None):
|
||||||
return None
|
return None, None
|
||||||
q = UniteEns.query.filter(
|
|
||||||
FormSemestreInscription.etudid == etudid,
|
if ue.semestre_idx % 2:
|
||||||
FormSemestreInscription.formsemestre_id == FormSemestre.id,
|
other_semestre_idx = ue.semestre_idx + 1
|
||||||
FormSemestre.formation_id == UniteEns.formation_id,
|
else:
|
||||||
FormSemestre.semestre_id == UniteEns.semestre_idx,
|
other_semestre_idx = ue.semestre_idx - 1
|
||||||
UniteEns.niveau_competence_id == ue.niveau_competence_id,
|
|
||||||
UniteEns.semestre_idx != ue.semestre_idx,
|
cursor = db.session.execute(
|
||||||
|
text(
|
||||||
|
"""SELECT
|
||||||
|
ue.id, sem.id
|
||||||
|
FROM
|
||||||
|
notes_ue ue,
|
||||||
|
notes_formsemestre_inscription inscr,
|
||||||
|
notes_formsemestre sem
|
||||||
|
|
||||||
|
WHERE
|
||||||
|
inscr.etudid = :etudid
|
||||||
|
AND inscr.formsemestre_id = sem.id
|
||||||
|
|
||||||
|
AND sem.semestre_id = :other_semestre_idx
|
||||||
|
AND ue.formation_id = sem.formation_id
|
||||||
|
AND ue.niveau_competence_id = :ue_niveau_competence_id
|
||||||
|
AND ue.semestre_idx = :other_semestre_idx
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"etudid": etudid,
|
||||||
|
"other_semestre_idx": other_semestre_idx,
|
||||||
|
"ue_niveau_competence_id": ue.niveau_competence_id,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if q.count() > 1:
|
r = cursor.fetchone()
|
||||||
log("Warning: get_other_ue_rcue: {q.count()} candidates UE")
|
if r is None:
|
||||||
return q.first()
|
return None, None
|
||||||
|
|
||||||
|
return UniteEns.query.get(r[0]), FormSemestre.query.get(r[1])
|
||||||
|
|
||||||
|
# q = UniteEns.query.filter(
|
||||||
|
# FormSemestreInscription.etudid == etudid,
|
||||||
|
# FormSemestreInscription.formsemestre_id == FormSemestre.id,
|
||||||
|
# FormSemestre.formation_id == UniteEns.formation_id,
|
||||||
|
# FormSemestre.semestre_id == UniteEns.semestre_idx,
|
||||||
|
# UniteEns.niveau_competence_id == ue.niveau_competence_id,
|
||||||
|
# UniteEns.semestre_idx != ue.semestre_idx,
|
||||||
|
# )
|
||||||
|
# if q.count() > 1:
|
||||||
|
# log("Warning: get_other_ue_rcue: {q.count()} candidates UE")
|
||||||
|
# return q.first()
|
||||||
|
|
||||||
|
|
||||||
class ApcValidationAnnee(db.Model):
|
class ApcValidationAnnee(db.Model):
|
||||||
|
@ -8,6 +8,7 @@ from app.comp import df_cache
|
|||||||
from app.models import SHORT_STR_LEN
|
from app.models import SHORT_STR_LEN
|
||||||
from app.models.but_refcomp import (
|
from app.models.but_refcomp import (
|
||||||
ApcAnneeParcours,
|
ApcAnneeParcours,
|
||||||
|
ApcCompetence,
|
||||||
ApcNiveau,
|
ApcNiveau,
|
||||||
ApcParcours,
|
ApcParcours,
|
||||||
ApcParcoursNiveauCompetence,
|
ApcParcoursNiveauCompetence,
|
||||||
@ -170,6 +171,27 @@ class Formation(db.Model):
|
|||||||
ApcAnneeParcours.parcours_id == parcour.id,
|
ApcAnneeParcours.parcours_id == parcour.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def query_competences_parcour(
|
||||||
|
self, parcour: ApcParcours
|
||||||
|
) -> flask_sqlalchemy.BaseQuery:
|
||||||
|
"""Les ApcCompetences d'un parcours de la formation.
|
||||||
|
None si pas de référentiel de compétences.
|
||||||
|
"""
|
||||||
|
if self.referentiel_competence_id is None:
|
||||||
|
return None
|
||||||
|
return (
|
||||||
|
ApcCompetence.query.filter_by(referentiel_id=self.referentiel_competence_id)
|
||||||
|
.join(
|
||||||
|
ApcParcoursNiveauCompetence,
|
||||||
|
ApcParcoursNiveauCompetence.competence_id == ApcCompetence.id,
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
ApcAnneeParcours,
|
||||||
|
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
||||||
|
)
|
||||||
|
.filter(ApcAnneeParcours.parcours_id == parcour.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Matiere(db.Model):
|
class Matiere(db.Model):
|
||||||
"""Matières: regroupe les modules d'une UE
|
"""Matières: regroupe les modules d'une UE
|
||||||
|
@ -221,7 +221,7 @@ class FormSemestre(db.Model):
|
|||||||
"""UE que suit l'étudiant dans ce semestre BUT
|
"""UE que suit l'étudiant dans ce semestre BUT
|
||||||
en fonction du parcours dans lequel il est inscrit.
|
en fonction du parcours dans lequel il est inscrit.
|
||||||
|
|
||||||
Si voulez les UE d'un parcour, il est plus efficace de passer par
|
Si voulez les UE d'un parcours, il est plus efficace de passer par
|
||||||
`formation.query_ues_parcour(parcour)`.
|
`formation.query_ues_parcour(parcour)`.
|
||||||
"""
|
"""
|
||||||
return self.query_ues().filter(
|
return self.query_ues().filter(
|
||||||
@ -382,6 +382,11 @@ class FormSemestre(db.Model):
|
|||||||
"True si l'user est l'un des responsables du semestre"
|
"True si l'user est l'un des responsables du semestre"
|
||||||
return user.id in [u.id for u in self.responsables]
|
return user.id in [u.id for u in self.responsables]
|
||||||
|
|
||||||
|
def annee_scolaire(self) -> int:
|
||||||
|
"""L'année de début de l'année scolaire.
|
||||||
|
Par exemple, 2022 si le semestre va de septebre 2022 à février 2023."""
|
||||||
|
return scu.annee_scolaire_debut(self.date_debut.year, self.date_debut.month)
|
||||||
|
|
||||||
def annee_scolaire_str(self):
|
def annee_scolaire_str(self):
|
||||||
"2021 - 2022"
|
"2021 - 2022"
|
||||||
return scu.annee_scolaire_repr(self.date_debut.year, self.date_debut.month)
|
return scu.annee_scolaire_repr(self.date_debut.year, self.date_debut.month)
|
||||||
|
@ -138,9 +138,9 @@ def sco_header(
|
|||||||
# optional args
|
# optional args
|
||||||
page_title="", # page title
|
page_title="", # page title
|
||||||
no_side_bar=False, # hide sidebar
|
no_side_bar=False, # hide sidebar
|
||||||
cssstyles=[], # additionals CSS sheets
|
cssstyles=(), # additionals CSS sheets
|
||||||
javascripts=[], # additionals JS filenames to load
|
javascripts=(), # additionals JS filenames to load
|
||||||
scripts=[], # script to put in page header
|
scripts=(), # script to put in page header
|
||||||
bodyOnLoad="", # JS
|
bodyOnLoad="", # JS
|
||||||
init_qtip=False, # include qTip
|
init_qtip=False, # include qTip
|
||||||
init_google_maps=False, # Google maps
|
init_google_maps=False, # Google maps
|
||||||
@ -148,6 +148,8 @@ def sco_header(
|
|||||||
titrebandeau="", # titre dans bandeau superieur
|
titrebandeau="", # titre dans bandeau superieur
|
||||||
head_message="", # message action (petit cadre jaune en haut)
|
head_message="", # message action (petit cadre jaune en haut)
|
||||||
user_check=True, # verifie passwords temporaires
|
user_check=True, # verifie passwords temporaires
|
||||||
|
etudid=None,
|
||||||
|
formsemestre_id=None,
|
||||||
):
|
):
|
||||||
"Main HTML page header for ScoDoc"
|
"Main HTML page header for ScoDoc"
|
||||||
from app.scodoc.sco_formsemestre_status import formsemestre_page_title
|
from app.scodoc.sco_formsemestre_status import formsemestre_page_title
|
||||||
@ -281,14 +283,14 @@ def sco_header(
|
|||||||
H.append(scu.CUSTOM_HTML_HEADER)
|
H.append(scu.CUSTOM_HTML_HEADER)
|
||||||
#
|
#
|
||||||
if not no_side_bar:
|
if not no_side_bar:
|
||||||
H.append(html_sidebar.sidebar())
|
H.append(html_sidebar.sidebar(etudid))
|
||||||
H.append("""<div id="gtrcontent">""")
|
H.append("""<div id="gtrcontent">""")
|
||||||
# En attendant le replacement complet de cette fonction,
|
# En attendant le replacement complet de cette fonction,
|
||||||
# inclusion ici des messages flask
|
# inclusion ici des messages flask
|
||||||
H.append(render_template("flashed_messages.html"))
|
H.append(render_template("flashed_messages.html"))
|
||||||
#
|
#
|
||||||
# Barre menu semestre:
|
# Barre menu semestre:
|
||||||
H.append(formsemestre_page_title())
|
H.append(formsemestre_page_title(formsemestre_id))
|
||||||
|
|
||||||
# Avertissement si mot de passe à changer
|
# Avertissement si mot de passe à changer
|
||||||
if user_check:
|
if user_check:
|
||||||
|
@ -73,7 +73,7 @@ def sidebar_common():
|
|||||||
return "".join(H)
|
return "".join(H)
|
||||||
|
|
||||||
|
|
||||||
def sidebar():
|
def sidebar(etudid: int = None):
|
||||||
"Main HTML page sidebar"
|
"Main HTML page sidebar"
|
||||||
# rewritten from legacy DTML code
|
# rewritten from legacy DTML code
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
@ -93,14 +93,14 @@ def sidebar():
|
|||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
# ---- Il y-a-t-il un etudiant selectionné ?
|
# ---- Il y-a-t-il un etudiant selectionné ?
|
||||||
etudid = g.get("etudid", None)
|
etudid = etudid if etudid is not None else g.get("etudid", None)
|
||||||
if not etudid:
|
if etudid is None:
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
etudid = request.args.get("etudid", None)
|
etudid = request.args.get("etudid", None)
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
etudid = request.form.get("etudid", None)
|
etudid = request.form.get("etudid", None)
|
||||||
|
|
||||||
if etudid:
|
if etudid is not None:
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
params.update(etud)
|
params.update(etud)
|
||||||
params["fiche_url"] = url_for(
|
params["fiche_url"] = url_for(
|
||||||
|
@ -190,6 +190,7 @@ CODES_SEM_REO = {NAR: 1} # reorientation
|
|||||||
CODES_UE_VALIDES = {ADM: True, CMP: True} # UE validée
|
CODES_UE_VALIDES = {ADM: True, CMP: True} # UE validée
|
||||||
|
|
||||||
# Pour le BUT:
|
# Pour le BUT:
|
||||||
|
CODES_ANNEE_ARRET = {DEF, DEM, ABAN, ABL}
|
||||||
CODES_RCUE = {ADM, AJ, CMP}
|
CODES_RCUE = {ADM, AJ, CMP}
|
||||||
|
|
||||||
|
|
||||||
|
@ -503,20 +503,24 @@ def retreive_formsemestre_from_request() -> int:
|
|||||||
|
|
||||||
|
|
||||||
# Element HTML decrivant un semestre (barre de menu et infos)
|
# Element HTML decrivant un semestre (barre de menu et infos)
|
||||||
def formsemestre_page_title():
|
def formsemestre_page_title(formsemestre_id=None):
|
||||||
"""Element HTML decrivant un semestre (barre de menu et infos)
|
"""Element HTML decrivant un semestre (barre de menu et infos)
|
||||||
Cherche dans la requete si un semestre est défini (formsemestre_id ou moduleimpl ou evaluation ou group)
|
Cherche dans la requete si un semestre est défini (formsemestre_id ou moduleimpl ou evaluation ou group)
|
||||||
"""
|
"""
|
||||||
formsemestre_id = retreive_formsemestre_from_request()
|
formsemestre_id = (
|
||||||
|
formsemestre_id
|
||||||
|
if formsemestre_id is not None
|
||||||
|
else retreive_formsemestre_from_request()
|
||||||
|
)
|
||||||
#
|
#
|
||||||
if not formsemestre_id:
|
if not formsemestre_id:
|
||||||
return ""
|
return ""
|
||||||
try:
|
try:
|
||||||
formsemestre_id = int(formsemestre_id)
|
formsemestre_id = int(formsemestre_id)
|
||||||
formsemestre = FormSemestre.query.get(formsemestre_id)
|
except ValueError:
|
||||||
except:
|
log(f"formsemestre_id: invalid type {formsemestre_id:r}")
|
||||||
log("can't find formsemestre_id %s" % formsemestre_id)
|
|
||||||
return ""
|
return ""
|
||||||
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
|
||||||
h = render_template(
|
h = render_template(
|
||||||
"formsemestre_page_title.html",
|
"formsemestre_page_title.html",
|
||||||
|
@ -865,7 +865,7 @@ def annee_scolaire_repr(year, month):
|
|||||||
return "%s - %s" % (year - 1, year)
|
return "%s - %s" % (year - 1, year)
|
||||||
|
|
||||||
|
|
||||||
def annee_scolaire_debut(year, month):
|
def annee_scolaire_debut(year, month) -> int:
|
||||||
"""Annee scolaire de debut (septembre): heuristique pour l'hémisphère nord..."""
|
"""Annee scolaire de debut (septembre): heuristique pour l'hémisphère nord..."""
|
||||||
if int(month) > 7:
|
if int(month) > 7:
|
||||||
return int(year)
|
return int(year)
|
||||||
|
Loading…
Reference in New Issue
Block a user