forked from ScoDoc/ScoDoc
WIP: jurys BUT: force jury annuel (en attendant page dédiée pour semestres isolés)
This commit is contained in:
parent
c17e2bae47
commit
0939feb9fc
@ -87,6 +87,7 @@ from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
|||||||
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 sco_codes_parcours as sco_codes
|
from app.scodoc import sco_codes_parcours as sco_codes
|
||||||
|
from app.scodoc.sco_codes_parcours import UE_STANDARD
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
||||||
|
|
||||||
@ -211,13 +212,17 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
for ue in self.ues_pair
|
for ue in self.ues_pair
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert self.parcour is not None
|
|
||||||
self.rcues_annee = self.compute_rcues_annee()
|
self.rcues_annee = self.compute_rcues_annee()
|
||||||
"RCUEs de l'année"
|
"RCUEs de l'année"
|
||||||
|
|
||||||
|
formation = (
|
||||||
|
self.formsemestre_impair.formation
|
||||||
|
if self.formsemestre_impair
|
||||||
|
else self.formsemestre_pair.formation
|
||||||
|
)
|
||||||
self.niveaux_competences = ApcNiveau.niveaux_annee_de_parcours(
|
self.niveaux_competences = ApcNiveau.niveaux_annee_de_parcours(
|
||||||
self.parcour, self.annee_but
|
self.parcour, self.annee_but, formation.referentiel_competence
|
||||||
).all() # XXX à trier, selon l'ordre des UE associées ?
|
).all() # non triés
|
||||||
"liste des niveaux de compétences associés à cette année"
|
"liste des niveaux de compétences associés à cette année"
|
||||||
self.decisions_rcue_by_niveau = self.compute_decisions_niveaux()
|
self.decisions_rcue_by_niveau = self.compute_decisions_niveaux()
|
||||||
"les décisions rcue associées aux niveau_id"
|
"les décisions rcue associées aux niveau_id"
|
||||||
@ -327,7 +332,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
# Parcour dans lequel l'étudiant est inscrit, et liste des UEs
|
# Parcour dans lequel l'étudiant est inscrit, et liste des UEs
|
||||||
if res.etuds_parcour_id[etudid] is None:
|
if res.etuds_parcour_id[etudid] is None:
|
||||||
# pas de parcour: prend toutes les UEs (non bonus)
|
# pas de parcour: prend toutes les UEs (non bonus)
|
||||||
ues = list(res.etud_ues(etudid))
|
ues = [ue for ue in res.etud_ues(etudid) if ue.type == UE_STANDARD]
|
||||||
else:
|
else:
|
||||||
parcour = ApcParcours.query.get(res.etuds_parcour_id[etudid])
|
parcour = ApcParcours.query.get(res.etuds_parcour_id[etudid])
|
||||||
if parcour is not None:
|
if parcour is not None:
|
||||||
@ -402,11 +407,12 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
if rc.ue_1.niveau_competence_id == niveau.id:
|
if rc.ue_1.niveau_competence_id == niveau.id:
|
||||||
rcue = rc
|
rcue = rc
|
||||||
break
|
break
|
||||||
dec_rcue = DecisionsProposeesRCUE(self, rcue)
|
if rcue is not None:
|
||||||
rc_niveaux.append((dec_rcue, niveau.id))
|
dec_rcue = DecisionsProposeesRCUE(self, rcue)
|
||||||
# prévient les UE concernées :-)
|
rc_niveaux.append((dec_rcue, niveau.id))
|
||||||
self.decisions_ues[dec_rcue.rcue.ue_1.id].set_rcue(dec_rcue.rcue)
|
# prévient les UE concernées :-)
|
||||||
self.decisions_ues[dec_rcue.rcue.ue_2.id].set_rcue(dec_rcue.rcue)
|
self.decisions_ues[dec_rcue.rcue.ue_1.id].set_rcue(dec_rcue.rcue)
|
||||||
|
self.decisions_ues[dec_rcue.rcue.ue_2.id].set_rcue(dec_rcue.rcue)
|
||||||
# Ordonne par numéro d'UE
|
# Ordonne par numéro d'UE
|
||||||
rc_niveaux.sort(key=lambda x: x[0].rcue.ue_1.numero)
|
rc_niveaux.sort(key=lambda x: x[0].rcue.ue_1.numero)
|
||||||
decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux}
|
decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux}
|
||||||
@ -458,7 +464,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
|
|
||||||
def record(self, code: str):
|
def record(self, code: str):
|
||||||
"""Enregistre le code"""
|
"""Enregistre le code"""
|
||||||
if not code in self.codes:
|
if code and not code in self.codes:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
f"code annee <tt>{html.escape(code)}</tt> invalide pour formsemestre {html.escape(self.formsemestre)}"
|
f"code annee <tt>{html.escape(code)}</tt> invalide pour formsemestre {html.escape(self.formsemestre)}"
|
||||||
)
|
)
|
||||||
@ -467,20 +473,22 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
if self.validation:
|
if self.validation:
|
||||||
db.session.delete(self.validation)
|
db.session.delete(self.validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
if code is None:
|
||||||
self.validation = ApcValidationAnnee(
|
self.validation = None
|
||||||
etudid=self.etud.id,
|
else:
|
||||||
formsemestre=self.formsemestre_impair,
|
self.validation = ApcValidationAnnee(
|
||||||
ordre=self.annee_but,
|
etudid=self.etud.id,
|
||||||
annee_scolaire=self.annee_scolaire(),
|
formsemestre=self.formsemestre_impair,
|
||||||
code=code,
|
ordre=self.annee_but,
|
||||||
)
|
annee_scolaire=self.annee_scolaire(),
|
||||||
Scolog.logdb(
|
code=code,
|
||||||
method="jury_but",
|
)
|
||||||
etudid=self.etud.id,
|
Scolog.logdb(
|
||||||
msg=f"Validation année BUT{self.annee_but}: {code}",
|
method="jury_but",
|
||||||
)
|
etudid=self.etud.id,
|
||||||
db.session.add(self.validation)
|
msg=f"Validation année BUT{self.annee_but}: {code}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
self.recorded = True
|
self.recorded = True
|
||||||
|
|
||||||
def record_all(self):
|
def record_all(self):
|
||||||
@ -494,7 +502,10 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
)
|
)
|
||||||
for dec in decisions:
|
for dec in decisions:
|
||||||
if not dec.recorded:
|
if not dec.recorded:
|
||||||
dec.record(dec.codes[0]) # rappel: le code par défaut est en tête
|
# rappel: le code par défaut est en tête
|
||||||
|
code = dec.codes[0] if dec.codes else None
|
||||||
|
# s'il n'y a pas de codee, efface
|
||||||
|
dec.record(dec.codes[0])
|
||||||
|
|
||||||
|
|
||||||
class DecisionsProposeesRCUE(DecisionsProposees):
|
class DecisionsProposeesRCUE(DecisionsProposees):
|
||||||
@ -516,6 +527,9 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
):
|
):
|
||||||
super().__init__(etud=dec_prop_annee.etud)
|
super().__init__(etud=dec_prop_annee.etud)
|
||||||
self.rcue = rcue
|
self.rcue = rcue
|
||||||
|
if rcue is None: # RCUE non dispo, eg un seul semestre
|
||||||
|
self.codes = []
|
||||||
|
return
|
||||||
self.parcour = dec_prop_annee.parcour
|
self.parcour = dec_prop_annee.parcour
|
||||||
self.validation = rcue.query_validations().first()
|
self.validation = rcue.query_validations().first()
|
||||||
if self.validation is not None:
|
if self.validation is not None:
|
||||||
@ -529,7 +543,7 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
|
|
||||||
def record(self, code: str):
|
def record(self, code: str):
|
||||||
"""Enregistre le code"""
|
"""Enregistre le code"""
|
||||||
if not code in self.codes:
|
if code and not code in self.codes:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
||||||
)
|
)
|
||||||
@ -539,20 +553,23 @@ class DecisionsProposeesRCUE(DecisionsProposees):
|
|||||||
if self.validation:
|
if self.validation:
|
||||||
db.session.delete(self.validation)
|
db.session.delete(self.validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
self.validation = ApcValidationRCUE(
|
if code is None:
|
||||||
etudid=self.etud.id,
|
self.validation = None
|
||||||
formsemestre_id=self.rcue.formsemestre_2.id,
|
else:
|
||||||
ue1_id=self.rcue.ue_1.id,
|
self.validation = ApcValidationRCUE(
|
||||||
ue2_id=self.rcue.ue_2.id,
|
etudid=self.etud.id,
|
||||||
parcours_id=parcours_id,
|
formsemestre_id=self.rcue.formsemestre_2.id,
|
||||||
code=code,
|
ue1_id=self.rcue.ue_1.id,
|
||||||
)
|
ue2_id=self.rcue.ue_2.id,
|
||||||
Scolog.logdb(
|
parcours_id=parcours_id,
|
||||||
method="jury_but",
|
code=code,
|
||||||
etudid=self.etud.id,
|
)
|
||||||
msg=f"Validation RCUE {repr(self.rcue)}",
|
Scolog.logdb(
|
||||||
)
|
method="jury_but",
|
||||||
db.session.add(self.validation)
|
etudid=self.etud.id,
|
||||||
|
msg=f"Validation RCUE {repr(self.rcue)}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
self.recorded = True
|
self.recorded = True
|
||||||
|
|
||||||
|
|
||||||
@ -633,7 +650,7 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
|
|
||||||
def record(self, code: str):
|
def record(self, code: str):
|
||||||
"""Enregistre le code"""
|
"""Enregistre le code"""
|
||||||
if not code in self.codes:
|
if code and not code in self.codes:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
f"code UE invalide pour ue_id={self.ue.id}: {html.escape(code)}"
|
||||||
)
|
)
|
||||||
@ -642,18 +659,21 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
if self.validation:
|
if self.validation:
|
||||||
db.session.delete(self.validation)
|
db.session.delete(self.validation)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
self.validation = ScolarFormSemestreValidation(
|
if code is None:
|
||||||
etudid=self.etud.id,
|
self.validation = None
|
||||||
formsemestre_id=self.formsemestre.id,
|
else:
|
||||||
ue_id=self.ue.id,
|
self.validation = ScolarFormSemestreValidation(
|
||||||
code=code,
|
etudid=self.etud.id,
|
||||||
)
|
formsemestre_id=self.formsemestre.id,
|
||||||
Scolog.logdb(
|
ue_id=self.ue.id,
|
||||||
method="jury_but",
|
code=code,
|
||||||
etudid=self.etud.id,
|
)
|
||||||
msg=f"Validation UE {self.ue.id}",
|
Scolog.logdb(
|
||||||
)
|
method="jury_but",
|
||||||
db.session.add(self.validation)
|
etudid=self.etud.id,
|
||||||
|
msg=f"Validation UE {self.ue.id}",
|
||||||
|
)
|
||||||
|
db.session.add(self.validation)
|
||||||
self.recorded = True
|
self.recorded = True
|
||||||
|
|
||||||
|
|
||||||
|
@ -228,5 +228,5 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
return s.index[s.notna()]
|
return s.index[s.notna()]
|
||||||
|
|
||||||
def etud_ues(self, etudid: int) -> Generator[UniteEns]:
|
def etud_ues(self, etudid: int) -> Generator[UniteEns]:
|
||||||
"""Liste des UE auxquelles l'étudiant est inscrit (sans bonus)."""
|
"""Liste des UE auxquelles l'étudiant est inscrit."""
|
||||||
return (UniteEns.query.get(ue_id) for ue_id in self.etud_ues_ids(etudid))
|
return (UniteEns.query.get(ue_id) for ue_id in self.etud_ues_ids(etudid))
|
||||||
|
@ -270,21 +270,33 @@ class ApcNiveau(db.Model, XMLModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def niveaux_annee_de_parcours(
|
def niveaux_annee_de_parcours(
|
||||||
cls, parcour: "ApcParcours", annee: int
|
cls,
|
||||||
|
parcour: "ApcParcours",
|
||||||
|
annee: int,
|
||||||
|
referentiel_competence: ApcReferentielCompetences = None,
|
||||||
) -> flask_sqlalchemy.BaseQuery:
|
) -> flask_sqlalchemy.BaseQuery:
|
||||||
"""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
|
||||||
|
"""
|
||||||
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")
|
||||||
annee_formation = f"BUT{annee}"
|
annee_formation = f"BUT{annee}"
|
||||||
return ApcNiveau.query.filter(
|
if parcour is None:
|
||||||
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
return ApcNiveau.query.filter(
|
||||||
ApcParcours.id == ApcAnneeParcours.parcours_id,
|
ApcNiveau.annee == annee_formation,
|
||||||
ApcParcours.referentiel == parcour.referentiel,
|
ApcCompetence.id == ApcNiveau.competence_id,
|
||||||
ApcParcoursNiveauCompetence.competence_id == ApcCompetence.id,
|
ApcCompetence.referentiel_id == referentiel_competence.id,
|
||||||
ApcCompetence.id == ApcNiveau.competence_id,
|
)
|
||||||
ApcAnneeParcours.parcours == parcour,
|
else:
|
||||||
ApcNiveau.annee == annee_formation,
|
return ApcNiveau.query.filter(
|
||||||
)
|
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
||||||
|
ApcParcours.id == ApcAnneeParcours.parcours_id,
|
||||||
|
ApcParcours.referentiel == parcour.referentiel,
|
||||||
|
ApcParcoursNiveauCompetence.competence_id == ApcCompetence.id,
|
||||||
|
ApcCompetence.id == ApcNiveau.competence_id,
|
||||||
|
ApcAnneeParcours.parcours == parcour,
|
||||||
|
ApcNiveau.annee == annee_formation,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
app_critiques_modules = db.Table(
|
app_critiques_modules = db.Table(
|
||||||
|
@ -18,6 +18,7 @@ from app.models.ues import UniteEns
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
from app.scodoc.sco_codes_parcours import UE_STANDARD
|
||||||
|
|
||||||
|
|
||||||
class Formation(db.Model):
|
class Formation(db.Model):
|
||||||
@ -166,6 +167,7 @@ class Formation(db.Model):
|
|||||||
"""
|
"""
|
||||||
return UniteEns.query.filter_by(formation=self).filter(
|
return UniteEns.query.filter_by(formation=self).filter(
|
||||||
UniteEns.niveau_competence_id == ApcNiveau.id,
|
UniteEns.niveau_competence_id == ApcNiveau.id,
|
||||||
|
UniteEns.type == UE_STANDARD,
|
||||||
ApcParcoursNiveauCompetence.competence_id == ApcNiveau.competence_id,
|
ApcParcoursNiveauCompetence.competence_id == ApcNiveau.competence_id,
|
||||||
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id,
|
||||||
ApcAnneeParcours.parcours_id == parcour.id,
|
ApcAnneeParcours.parcours_id == parcour.id,
|
||||||
|
@ -2248,6 +2248,8 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
etud = Identite.query.get_or_404(etudid)
|
etud = Identite.query.get_or_404(etudid)
|
||||||
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
||||||
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||||||
|
if len(deca.rcues_annee) == 0:
|
||||||
|
raise ScoValueError("année incomplète: pas de jury BUT annuel possible")
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
deca.record_form(request.form)
|
deca.record_form(request.form)
|
||||||
flash("codes enregistrés")
|
flash("codes enregistrés")
|
||||||
@ -2264,7 +2266,7 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
<form method="POST">
|
<form method="POST">
|
||||||
<div class="titre_parcours">
|
<div class="titre_parcours">
|
||||||
<h2>Jury BUT{deca.annee_but}
|
<h2>Jury BUT{deca.annee_but}
|
||||||
- Parcours {deca.parcour.libelle or "non spécifié"}
|
- Parcours {(deca.parcour.libelle if deca.parcour else False) or "non spécifié"}
|
||||||
- {deca.annee_scolaire_str()}</h2>
|
- {deca.annee_scolaire_str()}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="but_section_annee">
|
<div class="but_section_annee">
|
||||||
@ -2339,13 +2341,6 @@ def formsemestre_validation_but(formsemestre_id: int, etudid: int):
|
|||||||
)
|
)
|
||||||
H.append("</form>") # but_annee
|
H.append("</form>") # but_annee
|
||||||
|
|
||||||
# ---- Toutes les UEs, pour infos
|
|
||||||
H.append(f"<ul>")
|
|
||||||
for ue in formsemestre.query_ues(): # volontairement toutes les UE
|
|
||||||
dec_proposee = jury_but.DecisionsProposeesUE(etud, formsemestre, ue)
|
|
||||||
H.append("<li>" + html.escape(f"""{ue} : {dec_proposee}""") + "</li>")
|
|
||||||
H.append(f"</ul>")
|
|
||||||
H.append(f"</div>")
|
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user