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
|
return len(self.formsemestres.filter_by(etat=False).all()) > 0
|
||||||
|
|
||||||
def invalidate_module_coefs(self, semestre_idx: int = None):
|
def invalidate_module_coefs(self, semestre_idx: int = None):
|
||||||
"""Invalide les coefficients de modules cachés.
|
"""Invalide le cache des coefficients de modules.
|
||||||
Si semestre_idx est None, invalide tous les semestres,
|
Si semestre_idx est None, invalide les coefs de tous les semestres,
|
||||||
sinon invalide le semestre indiqué et le cache de la formation.
|
sinon invalide le semestre indiqué et le cache de la formation.
|
||||||
|
|
||||||
|
Dans tous les cas, invalide tous les formsemestres.
|
||||||
"""
|
"""
|
||||||
if semestre_idx is None:
|
if semestre_idx is None:
|
||||||
keys = {f"{self.id}.{m.semestre_id}" for m in self.modules}
|
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)
|
return sco_edit_ue.ue_is_locked(self.id)
|
||||||
|
|
||||||
def can_be_deleted(self) -> bool:
|
def can_be_deleted(self) -> bool:
|
||||||
"""True si l'UE n'est pas utilisée dans des formsemestre
|
"""True si l'UE n'a pas de moduleimpl rattachés
|
||||||
et n'a pas de module 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(
|
return (self.modules.count() == 0) or not any(
|
||||||
m.modimpls.all() for m in self.modules
|
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)
|
def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=False)
|
||||||
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.
|
Si pdfonly, n'expire que les bulletins pdf cachés.
|
||||||
"""
|
"""
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
|
@ -42,7 +42,7 @@ from app.models import ScolarNews
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
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 html_sco_header
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
@ -100,26 +100,38 @@ def formation_delete(formation_id=None, dialog_confirmed=False):
|
|||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def do_formation_delete(oid):
|
def do_formation_delete(formation_id):
|
||||||
"""delete a formation (and all its UE, matieres, modules)
|
"""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]
|
formation: Formation = Formation.query.get(formation_id)
|
||||||
if sco_formations.formation_has_locked_sems(oid):
|
if formation is None:
|
||||||
raise ScoLockedFormError()
|
return
|
||||||
cnx = ndb.GetDBConnexion()
|
acronyme = formation.acronyme
|
||||||
# delete all UE in this formation
|
if formation.formsemestres.count():
|
||||||
ues = sco_edit_ue.ue_list({"formation_id": oid})
|
raise ScoNonEmptyFormationObject(
|
||||||
for ue in ues:
|
type_objet="formation",
|
||||||
sco_edit_ue.do_ue_delete(ue["ue_id"], force=True)
|
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
|
# news
|
||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_FORM,
|
typ=ScolarNews.NEWS_FORM,
|
||||||
obj=oid,
|
obj=formation_id,
|
||||||
text=f"Suppression de la formation {F['acronyme']}",
|
text=f"Suppression de la formation {acronyme}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +37,14 @@ from app import db
|
|||||||
from app import log
|
from app import log
|
||||||
from app.but import apc_edit_ue
|
from app.but import apc_edit_ue
|
||||||
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 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 import ScolarNews
|
||||||
from app.models.formations import Matiere
|
from app.models.formations import Matiere
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
@ -138,12 +145,11 @@ def do_ue_create(args):
|
|||||||
return ue_id
|
return ue_id
|
||||||
|
|
||||||
|
|
||||||
def do_ue_delete(ue_id, delete_validations=False, force=False):
|
def do_ue_delete(ue: UniteEns, delete_validations=False, force=False):
|
||||||
"delete UE and attached matieres (but not modules)"
|
"""delete UE and attached matieres (but not modules).
|
||||||
from app.scodoc import sco_cursus_dut
|
Si force, pas de confirmation dialog et pas de redirect
|
||||||
|
"""
|
||||||
ue = UniteEns.query.get_or_404(ue_id)
|
formation: Formation = ue.formation
|
||||||
formation = ue.formation
|
|
||||||
semestre_idx = ue.semestre_idx
|
semestre_idx = ue.semestre_idx
|
||||||
if not ue.can_be_deleted():
|
if not ue.can_be_deleted():
|
||||||
raise ScoNonEmptyFormationObject(
|
raise ScoNonEmptyFormationObject(
|
||||||
@ -157,20 +163,22 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
log(f"do_ue_delete: ue_id={ue.id}, delete_validations={delete_validations}")
|
||||||
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue.id, delete_validations))
|
|
||||||
# check
|
|
||||||
# if ue_is_locked(ue.id):
|
|
||||||
# raise ScoLockedFormError()
|
|
||||||
# Il y a-t-il des etudiants ayant validé cette UE ?
|
# Il y a-t-il des etudiants ayant validé cette UE ?
|
||||||
# si oui, propose de supprimer les validations
|
# si oui, propose de supprimer les validations
|
||||||
validations = sco_cursus_dut.scolar_formsemestre_validation_list(
|
validations_ue = ScolarFormSemestreValidation.query.filter_by(ue_id=ue.id).all()
|
||||||
cnx, args={"ue_id": ue.id}
|
validations_rcue = ApcValidationRCUE.query.filter(
|
||||||
)
|
(ApcValidationRCUE.ue1_id == ue.id) | (ApcValidationRCUE.ue2_id == ue.id)
|
||||||
if validations and not delete_validations and not force:
|
).all()
|
||||||
|
if (
|
||||||
|
(len(validations_ue) > 0 or len(validations_rcue) > 0)
|
||||||
|
and not delete_validations
|
||||||
|
and not force
|
||||||
|
):
|
||||||
return scu.confirm_dialog(
|
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>"
|
f"""<p>Des étudiants ont une décision de jury sur l'UE {ue.acronyme} ({ue.titre})</p>
|
||||||
% (len(validations), ue.acronyme, ue.titre),
|
<p>Si vous supprimez cette UE, ces décisions vont être supprimées !</p>""",
|
||||||
dest_url="",
|
dest_url="",
|
||||||
target_variable="delete_validations",
|
target_variable="delete_validations",
|
||||||
cancel_url=url_for(
|
cancel_url=url_for(
|
||||||
@ -183,31 +191,34 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
)
|
)
|
||||||
if delete_validations:
|
if delete_validations:
|
||||||
log(f"deleting all validations of UE {ue.id}")
|
log(f"deleting all validations of UE {ue.id}")
|
||||||
ndb.SimpleQuery(
|
for v in validations_ue:
|
||||||
"DELETE FROM scolar_formsemestre_validation WHERE ue_id=%(ue_id)s",
|
db.session.delete(v)
|
||||||
{"ue_id": ue.id},
|
for v in validations_rcue:
|
||||||
)
|
db.session.delete(v)
|
||||||
|
|
||||||
# delete old formulas
|
# delete old formulas
|
||||||
ndb.SimpleQuery(
|
formulas = FormSemestreUEComputationExpr.query.filter_by(ue_id=ue.id).all()
|
||||||
"DELETE FROM notes_formsemestre_ue_computation_expr WHERE ue_id=%(ue_id)s",
|
for formula in formulas:
|
||||||
{"ue_id": ue.id},
|
db.session.delete(formula)
|
||||||
)
|
|
||||||
# delete all matiere in this UE
|
# delete all matieres in this UE
|
||||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
|
for mat in Matiere.query.filter_by(ue_id=ue.id):
|
||||||
for mat in mats:
|
db.session.delete(mat)
|
||||||
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
|
|
||||||
# delete uecoef and events
|
# delete uecoefs
|
||||||
ndb.SimpleQuery(
|
for uecoef in FormSemestreUECoef.query.filter_by(ue_id=ue.id):
|
||||||
"DELETE FROM notes_formsemestre_uecoef WHERE ue_id=%(ue_id)s",
|
db.session.delete(uecoef)
|
||||||
{"ue_id": ue.id},
|
# delete events
|
||||||
)
|
for event in ScolarEvent.query.filter_by(ue_id=ue.id):
|
||||||
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue.id})
|
db.session.delete(event)
|
||||||
cnx = ndb.GetDBConnexion()
|
db.session.flush()
|
||||||
_ueEditor.delete(cnx, ue.id)
|
|
||||||
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement
|
db.session.delete(ue)
|
||||||
# utilisé: acceptable de tout invalider):
|
db.session.commit()
|
||||||
|
|
||||||
|
# cas compliqué, mais rarement utilisé: acceptable de tout invalider
|
||||||
formation.invalidate_module_coefs()
|
formation.invalidate_module_coefs()
|
||||||
# -> invalide aussi .invalidate_formsemestre()
|
# -> invalide aussi les formsemestres
|
||||||
# news
|
# news
|
||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_FORM,
|
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
|
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"""
|
"""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):
|
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}).
|
<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
|
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.
|
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
|
# --- 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)
|
lif3 = notes.formation_list(format="json").get_data(as_text=True)
|
||||||
assert isinstance(lif3, str)
|
assert isinstance(lif3, str)
|
||||||
load_lif3 = json.loads(lif3)
|
load_lif3 = json.loads(lif3)
|
||||||
|
Loading…
Reference in New Issue
Block a user