Améliore détection décisions jurys avant désinscription ou suppression de semestre

This commit is contained in:
Emmanuel Viennet 2023-02-27 17:45:20 +01:00
parent 7e6d1ebba0
commit 56ec2b4b42
6 changed files with 76 additions and 25 deletions

View File

@ -17,6 +17,7 @@ from app.comp.bonus_spo import BonusSport
from app.models import ScoDocSiteConfig from app.models import ScoDocSiteConfig
from app.models.moduleimpls import ModuleImpl from app.models.moduleimpls import ModuleImpl
from app.models.ues import DispenseUE, UniteEns from app.models.ues import DispenseUE, UniteEns
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc.codes_cursus import UE_SPORT from app.scodoc.codes_cursus import UE_SPORT
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
@ -261,3 +262,18 @@ class ResultatsSemestreBUT(NotesTableCompat):
""" """
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()]
def etud_has_decision(self, etudid):
"""True s'il y a une décision de jury pour cet étudiant émanant de ce formsemestre.
prend aussi en compte les autorisations de passage.
Sous-classée en BUT pour les RCUEs et années.
"""
return (
super().etud_has_decision(etudid)
or ApcValidationAnnee.query.filter_by(
formsemestre_id=self.formsemestre.id, etudid=etudid
).count()
or ApcValidationRCUE.query.filter_by(
formsemestre_id=self.formsemestre.id, etudid=etudid
).count()
)

View File

@ -15,9 +15,7 @@ from app import log
from app.comp import moy_sem from app.comp import moy_sem
from app.comp.aux_stats import StatsMoyenne from app.comp.aux_stats import StatsMoyenne
from app.comp.res_common import ResultatsSemestre from app.comp.res_common import ResultatsSemestre
from app.models import FormSemestre from app.models import Identite, FormSemestre, ModuleImpl, ScolarAutorisationInscription
from app.models import Identite
from app.models import ModuleImpl
from app.scodoc.codes_cursus import UE_SPORT, DEF from app.scodoc.codes_cursus import UE_SPORT, DEF
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
@ -280,8 +278,17 @@ class NotesTableCompat(ResultatsSemestre):
return True return True
def etud_has_decision(self, etudid): def etud_has_decision(self, etudid):
"""True s'il y a une décision de jury pour cet étudiant""" """True s'il y a une décision de jury pour cet étudiant émanant de ce formsemestre.
return self.get_etud_decisions_ue(etudid) or self.get_etud_decision_sem(etudid) prend aussi en compte les autorisations de passage.
Sous-classée en BUT pour les RCUEs et années.
"""
return (
self.get_etud_decisions_ue(etudid)
or self.get_etud_decision_sem(etudid)
or ScolarAutorisationInscription.query.filter_by(
origin_formsemestre_id=self.formsemestre.id, etudid=etudid
).count()
)
def get_etud_decisions_ue(self, etudid: int) -> dict: def get_etud_decisions_ue(self, etudid: int) -> dict:
"""Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu. """Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu.

View File

@ -131,7 +131,7 @@ class ScolarAutorisationInscription(db.Model):
etudid: int, etudid: int,
origin_formsemestre_id: int, origin_formsemestre_id: int,
): ):
"""Efface les autorisations de cette étudiant venant du sem. origine""" """Efface les autorisations de cet étudiant venant du sem. origine"""
autorisations = cls.query.filter_by( autorisations = cls.query.filter_by(
etudid=etudid, origin_formsemestre_id=origin_formsemestre_id etudid=etudid, origin_formsemestre_id=origin_formsemestre_id
) )

View File

@ -35,8 +35,18 @@ from flask_login import current_user
from app import db from app import db
from app.auth.models import User from app.auth.models import User
from app.models import APO_CODE_STR_LEN, SHORT_STR_LEN from app.models import APO_CODE_STR_LEN, SHORT_STR_LEN
from app.models import Module, ModuleImpl, Evaluation, EvaluationUEPoids, UniteEns from app.models import (
from app.models import ScolarNews Module,
ModuleImpl,
Evaluation,
EvaluationUEPoids,
UniteEns,
ScolarFormSemestreValidation,
ScolarAutorisationInscription,
ApcValidationAnnee,
ApcValidationRCUE,
ScolarNews,
)
from app.models.formations import Formation from app.models.formations import Formation
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
from app.models.but_refcomp import ApcParcours from app.models.but_refcomp import ApcParcours
@ -1524,9 +1534,11 @@ Ceci n'est possible que si :
cancelbutton="Annuler", cancelbutton="Annuler",
) )
if tf[0] == 0: if tf[0] == 0:
if formsemestre_has_decisions_or_compensations(formsemestre_id): if formsemestre_has_decisions_or_compensations(formsemestre):
H.append( H.append(
"""<p><b>Ce semestre ne peut pas être supprimé ! (il y a des décisions de jury ou des compensations par d'autres semestres)</b></p>""" """<p><b>Ce semestre ne peut pas être supprimé !
(il y a des décisions de jury ou des compensations par d'autres semestres)</b>
</p>"""
) )
else: else:
H.append(tf[1]) H.append(tf[1])
@ -1560,18 +1572,32 @@ def formsemestre_delete2(formsemestre_id, dialog_confirmed=False):
return flask.redirect(scu.ScoURL() + "?head_message=Semestre%20supprimé") return flask.redirect(scu.ScoURL() + "?head_message=Semestre%20supprimé")
def formsemestre_has_decisions_or_compensations(formsemestre_id): def formsemestre_has_decisions_or_compensations(formsemestre: FormSemestre):
"""True if decision de jury dans ce semestre """True if decision de jury (sem. UE, RCUE, année) émanant de ce semestre
ou bien compensation de ce semestre par d'autre ssemestres. ou compensation de ce semestre par d'autres semestres
ou autorisations de passage.
""" """
r = ndb.SimpleDictFetch( # Validations de semestre ou d'UEs
"""SELECT v.id AS formsemestre_validation_id, v.* if ScolarFormSemestreValidation.query.filter_by(
FROM scolar_formsemestre_validation v formsemestre_id=formsemestre.id
WHERE v.formsemestre_id = %(formsemestre_id)s ).count():
OR v.compense_formsemestre_id = %(formsemestre_id)s""", return True
{"formsemestre_id": formsemestre_id}, if ScolarFormSemestreValidation.query.filter_by(
) compense_formsemestre_id=formsemestre.id
return r ).count():
return True
# Autorisations d'inscription:
if ScolarAutorisationInscription.query.filter_by(
origin_formsemestre_id=formsemestre.id
).count():
return True
# Validations d'années BUT
if ApcValidationAnnee.query.filter_by(formsemestre_id=formsemestre.id).count():
return True
# Validations de RCUEs
if ApcValidationRCUE.query.filter_by(formsemestre_id=formsemestre.id).count():
return True
return False
def do_formsemestre_delete(formsemestre_id): def do_formsemestre_delete(formsemestre_id):

View File

@ -154,7 +154,7 @@ def dict_pvjury(
etudid=etudid, origin_formsemestre_id=formsemestre_id etudid=etudid, origin_formsemestre_id=formsemestre_id
).all() ).all()
d["autorisations"] = [a.to_dict() for a in autorisations] d["autorisations"] = [a.to_dict() for a in autorisations]
d["autorisations_descr"] = _descr_autorisations(autorisations) d["autorisations_descr"] = descr_autorisations(autorisations)
d["validation_parcours"] = Se.parcours_validated() d["validation_parcours"] = Se.parcours_validated()
d["parcours"] = Se.get_cursus_descr(filter_futur=True) d["parcours"] = Se.get_cursus_descr(filter_futur=True)
@ -259,7 +259,7 @@ def _comp_ects_by_ue_code(nt, decisions_ue):
return ects_by_ue_code return ects_by_ue_code
def _descr_autorisations(autorisations: list[ScolarAutorisationInscription]) -> str: def descr_autorisations(autorisations: list[ScolarAutorisationInscription]) -> str:
"résumé textuel des autorisations d'inscription (-> 'S1, S3' )" "résumé textuel des autorisations d'inscription (-> 'S1, S3' )"
return ", ".join([f"S{a.semestre_id}" for a in autorisations]) return ", ".join([f"S{a.semestre_id}" for a in autorisations])

View File

@ -50,7 +50,7 @@ from app.but import jury_but_view
from app.comp import res_sem from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.models import ScolarNews, Scolog from app.models import ScolarAutorisationInscription, ScolarNews, Scolog
from app.models.but_refcomp import ApcNiveau, ApcParcours from app.models.but_refcomp import ApcNiveau, ApcParcours
from app.models.config import ScoDocSiteConfig from app.models.config import ScoDocSiteConfig
from app.models.etudiants import Identite from app.models.etudiants import Identite
@ -137,8 +137,8 @@ from app.scodoc import sco_tag_module
from app.scodoc import sco_ue_external from app.scodoc import sco_ue_external
from app.scodoc import sco_undo_notes from app.scodoc import sco_undo_notes
from app.scodoc import sco_users from app.scodoc import sco_users
from app.scodoc import sco_xml
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_pv_dict import descr_autorisations
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.TrivialFormulator import TrivialFormulator
from app.views import ScoData from app.views import ScoData
@ -2770,6 +2770,8 @@ def formsemestre_validation_suppress_etud(
<li>Année BUT: {descr_annee}</li> <li>Année BUT: {descr_annee}</li>
<li>UEs : {", ".join(descr_ues)}</li> <li>UEs : {", ".join(descr_ues)}</li>
<li>RCUEs: {len(d.get("decision_rcue", []))} décisions</li> <li>RCUEs: {len(d.get("decision_rcue", []))} décisions</li>
<li>Autorisations: {descr_autorisations(ScolarAutorisationInscription.query.filter_by(origin_formsemestre_id=formsemestre_id,
etudid=etudid))}
</ul> </ul>
""" """
return scu.confirm_dialog( return scu.confirm_dialog(