forked from ScoDoc/ScoDoc
Modernisation suppressions UE et formations
This commit is contained in:
parent
9480e15b83
commit
48e31b5f39
@ -105,9 +105,11 @@ class Formation(db.Model):
|
||||
return len(self.formsemestres.filter_by(etat=False).all()) > 0
|
||||
|
||||
def invalidate_module_coefs(self, semestre_idx: int = None):
|
||||
"""Invalide les coefficients de modules cachés.
|
||||
Si semestre_idx est None, invalide tous les semestres,
|
||||
"""Invalide le cache des coefficients de modules.
|
||||
Si semestre_idx est None, invalide les coefs de tous les semestres,
|
||||
sinon invalide le semestre indiqué et le cache de la formation.
|
||||
|
||||
Dans tous les cas, invalide tous les formsemestres.
|
||||
"""
|
||||
if semestre_idx is None:
|
||||
keys = {f"{self.id}.{m.semestre_id}" for m in self.modules}
|
||||
|
@ -83,10 +83,9 @@ class UniteEns(db.Model):
|
||||
return sco_edit_ue.ue_is_locked(self.id)
|
||||
|
||||
def can_be_deleted(self) -> bool:
|
||||
"""True si l'UE n'est pas utilisée dans des formsemestre
|
||||
et n'a pas de module rattachés
|
||||
"""True si l'UE n'a pas de moduleimpl rattachés
|
||||
(pas un seul module de cette UE n'a de modimpl)
|
||||
"""
|
||||
# "pas un seul module de cette UE n'a de modimpl...""
|
||||
return (self.modules.count() == 0) or not any(
|
||||
m.modimpls.all() for m in self.modules
|
||||
)
|
||||
|
@ -228,7 +228,7 @@ class TableRecapWithEvalsCache(ScoDocCache):
|
||||
def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=False)
|
||||
formsemestre_id=None, pdfonly=False
|
||||
):
|
||||
"""expire cache pour un semestre (ou tous si formsemestre_id non spécifié).
|
||||
"""expire cache pour un semestre (ou tous ceux du département si formsemestre_id non spécifié).
|
||||
Si pdfonly, n'expire que les bulletins pdf cachés.
|
||||
"""
|
||||
from app.models.formsemestre import FormSemestre
|
||||
|
@ -42,7 +42,7 @@ from app.models import ScolarNews
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoNonEmptyFormationObject
|
||||
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_codes_parcours
|
||||
@ -100,26 +100,38 @@ def formation_delete(formation_id=None, dialog_confirmed=False):
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def do_formation_delete(oid):
|
||||
def do_formation_delete(formation_id):
|
||||
"""delete a formation (and all its UE, matieres, modules)
|
||||
XXX delete all ues, will break if there are validations ! USE WITH CARE !
|
||||
Warning: delete all ues, will ask if there are validations !
|
||||
"""
|
||||
F = sco_formations.formation_list(args={"formation_id": oid})[0]
|
||||
if sco_formations.formation_has_locked_sems(oid):
|
||||
raise ScoLockedFormError()
|
||||
cnx = ndb.GetDBConnexion()
|
||||
# delete all UE in this formation
|
||||
ues = sco_edit_ue.ue_list({"formation_id": oid})
|
||||
for ue in ues:
|
||||
sco_edit_ue.do_ue_delete(ue["ue_id"], force=True)
|
||||
formation: Formation = Formation.query.get(formation_id)
|
||||
if formation is None:
|
||||
return
|
||||
acronyme = formation.acronyme
|
||||
if formation.formsemestres.count():
|
||||
raise ScoNonEmptyFormationObject(
|
||||
type_objet="formation",
|
||||
msg=formation.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation.id
|
||||
),
|
||||
)
|
||||
|
||||
sco_formations._formationEditor.delete(cnx, oid)
|
||||
# Suppression des modules
|
||||
for module in formation.modules:
|
||||
db.session.delete(module)
|
||||
db.session.flush()
|
||||
# Suppression des UEs
|
||||
for ue in formation.ues:
|
||||
sco_edit_ue.do_ue_delete(ue, force=True)
|
||||
|
||||
db.session.delete(formation)
|
||||
|
||||
# news
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_FORM,
|
||||
obj=oid,
|
||||
text=f"Suppression de la formation {F['acronyme']}",
|
||||
obj=formation_id,
|
||||
text=f"Suppression de la formation {acronyme}",
|
||||
)
|
||||
|
||||
|
||||
|
@ -37,7 +37,14 @@ from app import db
|
||||
from app import log
|
||||
from app.but import apc_edit_ue
|
||||
from app.models import APO_CODE_STR_LEN, SHORT_STR_LEN
|
||||
from app.models import Formation, UniteEns, ModuleImpl, Module
|
||||
from app.models import (
|
||||
Formation,
|
||||
FormSemestreUEComputationExpr,
|
||||
FormSemestreUECoef,
|
||||
Matiere,
|
||||
UniteEns,
|
||||
)
|
||||
from app.models import ApcValidationRCUE, ScolarFormSemestreValidation, ScolarEvent
|
||||
from app.models import ScolarNews
|
||||
from app.models.formations import Matiere
|
||||
import app.scodoc.notesdb as ndb
|
||||
@ -138,12 +145,11 @@ def do_ue_create(args):
|
||||
return ue_id
|
||||
|
||||
|
||||
def do_ue_delete(ue_id, delete_validations=False, force=False):
|
||||
"delete UE and attached matieres (but not modules)"
|
||||
from app.scodoc import sco_cursus_dut
|
||||
|
||||
ue = UniteEns.query.get_or_404(ue_id)
|
||||
formation = ue.formation
|
||||
def do_ue_delete(ue: UniteEns, delete_validations=False, force=False):
|
||||
"""delete UE and attached matieres (but not modules).
|
||||
Si force, pas de confirmation dialog et pas de redirect
|
||||
"""
|
||||
formation: Formation = ue.formation
|
||||
semestre_idx = ue.semestre_idx
|
||||
if not ue.can_be_deleted():
|
||||
raise ScoNonEmptyFormationObject(
|
||||
@ -157,20 +163,22 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
||||
),
|
||||
)
|
||||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue.id, delete_validations))
|
||||
# check
|
||||
# if ue_is_locked(ue.id):
|
||||
# raise ScoLockedFormError()
|
||||
log(f"do_ue_delete: ue_id={ue.id}, delete_validations={delete_validations}")
|
||||
|
||||
# Il y a-t-il des etudiants ayant validé cette UE ?
|
||||
# si oui, propose de supprimer les validations
|
||||
validations = sco_cursus_dut.scolar_formsemestre_validation_list(
|
||||
cnx, args={"ue_id": ue.id}
|
||||
)
|
||||
if validations and not delete_validations and not force:
|
||||
validations_ue = ScolarFormSemestreValidation.query.filter_by(ue_id=ue.id).all()
|
||||
validations_rcue = ApcValidationRCUE.query.filter(
|
||||
(ApcValidationRCUE.ue1_id == ue.id) | (ApcValidationRCUE.ue2_id == ue.id)
|
||||
).all()
|
||||
if (
|
||||
(len(validations_ue) > 0 or len(validations_rcue) > 0)
|
||||
and not delete_validations
|
||||
and not force
|
||||
):
|
||||
return scu.confirm_dialog(
|
||||
"<p>%d étudiants ont validé l'UE %s (%s)</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p>"
|
||||
% (len(validations), ue.acronyme, ue.titre),
|
||||
f"""<p>Des étudiants ont une décision de jury sur l'UE {ue.acronyme} ({ue.titre})</p>
|
||||
<p>Si vous supprimez cette UE, ces décisions vont être supprimées !</p>""",
|
||||
dest_url="",
|
||||
target_variable="delete_validations",
|
||||
cancel_url=url_for(
|
||||
@ -183,31 +191,34 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
||||
)
|
||||
if delete_validations:
|
||||
log(f"deleting all validations of UE {ue.id}")
|
||||
ndb.SimpleQuery(
|
||||
"DELETE FROM scolar_formsemestre_validation WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue.id},
|
||||
)
|
||||
for v in validations_ue:
|
||||
db.session.delete(v)
|
||||
for v in validations_rcue:
|
||||
db.session.delete(v)
|
||||
|
||||
# delete old formulas
|
||||
ndb.SimpleQuery(
|
||||
"DELETE FROM notes_formsemestre_ue_computation_expr WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue.id},
|
||||
)
|
||||
# delete all matiere in this UE
|
||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
|
||||
for mat in mats:
|
||||
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
|
||||
# delete uecoef and events
|
||||
ndb.SimpleQuery(
|
||||
"DELETE FROM notes_formsemestre_uecoef WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue.id},
|
||||
)
|
||||
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue.id})
|
||||
cnx = ndb.GetDBConnexion()
|
||||
_ueEditor.delete(cnx, ue.id)
|
||||
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement
|
||||
# utilisé: acceptable de tout invalider):
|
||||
formulas = FormSemestreUEComputationExpr.query.filter_by(ue_id=ue.id).all()
|
||||
for formula in formulas:
|
||||
db.session.delete(formula)
|
||||
|
||||
# delete all matieres in this UE
|
||||
for mat in Matiere.query.filter_by(ue_id=ue.id):
|
||||
db.session.delete(mat)
|
||||
|
||||
# delete uecoefs
|
||||
for uecoef in FormSemestreUECoef.query.filter_by(ue_id=ue.id):
|
||||
db.session.delete(uecoef)
|
||||
# delete events
|
||||
for event in ScolarEvent.query.filter_by(ue_id=ue.id):
|
||||
db.session.delete(event)
|
||||
db.session.flush()
|
||||
|
||||
db.session.delete(ue)
|
||||
db.session.commit()
|
||||
|
||||
# cas compliqué, mais rarement utilisé: acceptable de tout invalider
|
||||
formation.invalidate_module_coefs()
|
||||
# -> invalide aussi .invalidate_formsemestre()
|
||||
# -> invalide aussi les formsemestres
|
||||
# news
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_FORM,
|
||||
@ -601,7 +612,7 @@ def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
|
||||
),
|
||||
)
|
||||
|
||||
return do_ue_delete(ue.id, delete_validations=delete_validations)
|
||||
return do_ue_delete(ue, delete_validations=delete_validations)
|
||||
|
||||
|
||||
def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
||||
|
@ -116,7 +116,7 @@ class ScoNonEmptyFormationObject(ScoValueError):
|
||||
"""On ne peut pas supprimer un module/matiere ou UE si des formsemestre s'y réfèrent"""
|
||||
|
||||
def __init__(self, type_objet="objet'", msg="", dest_url=None):
|
||||
msg = f"""<h3>{type_objet} "{msg}" utilisé dans des semestres: suppression impossible.</h3>
|
||||
msg = f"""<h3>{type_objet} "{msg}" utilisé(e) dans des semestres: suppression impossible.</h3>
|
||||
<p class="help">Il faut d'abord supprimer le semestre (ou en retirer ce {type_objet}).
|
||||
Mais il est peut-être préférable de laisser ce programme intact et d'en créer une
|
||||
nouvelle version pour la modifier sans affecter les semestres déjà en place.
|
||||
|
@ -327,7 +327,7 @@ def test_formations(test_client):
|
||||
|
||||
# --- Suppression d'une formation
|
||||
|
||||
sco_edit_formation.do_formation_delete(oid=formation_id2)
|
||||
sco_edit_formation.do_formation_delete(formation_id=formation_id2)
|
||||
lif3 = notes.formation_list(format="json").get_data(as_text=True)
|
||||
assert isinstance(lif3, str)
|
||||
load_lif3 = json.loads(lif3)
|
||||
|
Loading…
Reference in New Issue
Block a user