diff --git a/app/models/formations.py b/app/models/formations.py index 55de77f7a0..3abbf38820 100644 --- a/app/models/formations.py +++ b/app/models/formations.py @@ -2,11 +2,12 @@ """ from app import db +from app.comp import df_cache from app.models import SHORT_STR_LEN from app.scodoc import notesdb as ndb -from app.scodoc import sco_utils as scu +from app.scodoc import sco_cache from app.scodoc import sco_codes_parcours -from app.comp import df_cache +from app.scodoc import sco_utils as scu class Formation(db.Model): @@ -76,6 +77,10 @@ class Formation(db.Model): df_cache.ModuleCoefsCache.set(key, modules_coefficients) return modules_coefficients + def has_locked_sems(self): + "True if there is a locked formsemestre in this formation" + 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, @@ -86,6 +91,36 @@ class Formation(db.Model): else: keys = f"{self.id}.{semestre_idx}" df_cache.ModuleCoefsCache.delete_many(keys | {f"{self.id}"}) + sco_cache.invalidate_formsemestre() + + def invalidate_cached_sems(self): + for sem in self.formsemestres: + sco_cache.invalidate_formsemestre(formsemestre_id=sem.id) + + def force_semestre_modules_aux_ues(self) -> None: + """ + Affecte à chaque module de cette formation le semestre de son UE de rattachement, + si elle en a une. + Devrait être appelé lorsqu'on change le type de formation vers le BUT, et aussi + lorsqu'on change le semestre d'une UE BUT. + Utile pour la migration des anciennes formations vers le BUT. + Invalide les caches coefs/poids. + """ + if not self.is_apc(): + return + change = False + for mod in self.modules: + if ( + mod.ue.semestre_idx is not None + and mod.ue.semestre_idx > 0 + and mod.semestre_id != mod.ue.semestre_idx + ): + mod.semestre_id = mod.ue.semestre_idx + db.session.add(mod) + change = True + db.session.commit() + if change: + self.invalidate_module_coefs() class Matiere(db.Model): diff --git a/app/models/modules.py b/app/models/modules.py index d1affad024..00a6d4c9ba 100644 --- a/app/models/modules.py +++ b/app/models/modules.py @@ -27,6 +27,7 @@ class Module(db.Model): formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id")) matiere_id = db.Column(db.Integer, db.ForeignKey("notes_matieres.id")) # pas un id mais le numéro du semestre: 1, 2, ... + # note: en APC, le semestre qui fait autorité est celui de l'UE semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1") numero = db.Column(db.Integer) # ordre de présentation # id de l'element pedagogique Apogee correspondant: diff --git a/app/scodoc/sco_edit_formation.py b/app/scodoc/sco_edit_formation.py index a609a84182..f532758435 100644 --- a/app/scodoc/sco_edit_formation.py +++ b/app/scodoc/sco_edit_formation.py @@ -33,6 +33,7 @@ from flask import g, url_for, request from app import db from app import log +from app.models.formations import Formation from app.models.modules import Module import app.scodoc.notesdb as ndb @@ -301,17 +302,9 @@ def do_formation_edit(args): cnx = ndb.GetDBConnexion() sco_formations._formationEditor.edit(cnx, args) - invalidate_sems_in_formation(args["formation_id"]) - - -def invalidate_sems_in_formation(formation_id): - "Invalide les semestres utilisant cette formation" - for sem in sco_formsemestre.do_formsemestre_list( - args={"formation_id": formation_id} - ): - sco_cache.invalidate_formsemestre( - formsemestre_id=sem["formsemestre_id"] - ) # > formation modif. + formation = Formation.query.get(args["formation_id"]) + formation.invalidate_cached_sems() + formation.force_semestre_modules_aux_ues() def objects_renumber(obj_list) -> None: diff --git a/app/scodoc/sco_edit_matiere.py b/app/scodoc/sco_edit_matiere.py index f07b9b588a..8e957ab8b4 100644 --- a/app/scodoc/sco_edit_matiere.py +++ b/app/scodoc/sco_edit_matiere.py @@ -34,6 +34,7 @@ from flask import g, url_for, request import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app import log +from app.models import Formation from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError from app.scodoc import html_sco_header @@ -66,7 +67,7 @@ def do_matiere_edit(*args, **kw): # edit _matiereEditor.edit(cnx, *args, **kw) formation_id = sco_edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]["formation_id"] - sco_edit_formation.invalidate_sems_in_formation(formation_id) + Formation.query.get(formation_id).invalidate_cached_sems() def do_matiere_create(args): diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py index 5e804b3244..24232164a7 100644 --- a/app/scodoc/sco_edit_module.py +++ b/app/scodoc/sco_edit_module.py @@ -39,6 +39,7 @@ import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import ModuleType from app import log from app import models +from app.models import Formation from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.sco_permissions import Permission from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError, ScoGenError @@ -411,7 +412,7 @@ def do_module_edit(val): # edit cnx = ndb.GetDBConnexion() _moduleEditor.edit(cnx, val) - sco_edit_formation.invalidate_sems_in_formation(mod["formation_id"]) + Formation.query.get(mod["formation_id"]).invalidate_cached_sems() def check_module_code_unicity(code, field, formation_id, module_id=None): diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 6e05fc4a99..cd5dcb7e3b 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -1155,9 +1155,11 @@ def do_ue_edit(args, bypass_lock=False, dont_invalidate_cache=False): cnx = ndb.GetDBConnexion() _ueEditor.edit(cnx, args) + formation = Formation.query.get(ue["formation_id"]) if not dont_invalidate_cache: # Invalide les semestres utilisant cette formation: - sco_edit_formation.invalidate_sems_in_formation(ue["formation_id"]) + formation.invalidate_cached_sems() + formation.force_semestre_modules_aux_ues() # essai edition en ligne: diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py index 81dede6307..b2eaef9817 100644 --- a/app/scodoc/sco_formations.py +++ b/app/scodoc/sco_formations.py @@ -86,12 +86,10 @@ def formation_list(formation_id=None, args={}): return r -def formation_has_locked_sems(formation_id): - "True if there is a locked formsemestre in this formation" - sems = sco_formsemestre.do_formsemestre_list( - args={"formation_id": formation_id, "etat": False} - ) - return sems +def formation_has_locked_sems(formation_id): # XXX to remove + "backward compat: True if there is a locked formsemestre in this formation" + formation = Formation.query.get(formation_id) + return formation.has_locked_sems() def formation_export( diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index ac0751281a..4de3920925 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1619,6 +1619,9 @@ li.module_malus span.formation_module_tit { text-decoration: underline; } +span.formation_module_ue { + background-color: #b7d2fa; +} span.notes_module_list_buts { margin-right: 5px; } diff --git a/app/templates/pn/form_mods.html b/app/templates/pn/form_mods.html index 045491f6e2..90faee024b 100644 --- a/app/templates/pn/form_mods.html +++ b/app/templates/pn/form_mods.html @@ -46,11 +46,13 @@ {% endif %} + ({{mod.ue.acronyme}}), {{formation.get_parcours().SESSION_NAME}} {{mod.semestre_id}} - ({{mod.heures_cours|default(" ",true)|safe}}/{{mod.heures_td|default(" ",true)|safe}}/{{mod.heures_tp|default(" ",true)|safe}}, - - Apo: diff --git a/app/views/notes.py b/app/views/notes.py index 9a8797e61c..8ec4702bb9 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -402,7 +402,8 @@ def ue_set_internal(ue_id): db.session.add(ue) db.session.commit() # Invalide les semestres de cette formation - sco_edit_formation.invalidate_sems_in_formation(ue.formation_id) + ue.formation.invalidate_cached_sems() + return redirect( url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=ue.formation_id diff --git a/app/views/pn_modules.py b/app/views/pn_modules.py index 0dc52d1bbd..c3b18f3556 100644 --- a/app/views/pn_modules.py +++ b/app/views/pn_modules.py @@ -144,7 +144,8 @@ def set_module_ue_coef(): return scu.json_error(f"UE not found ({ue_id})", 404) module.set_ue_coef(ue, coef) db.session.commit() - sco_edit_formation.invalidate_sems_in_formation(module.formation_id) + module.formation.invalidate_cached_sems() + return scu.json_error("ok", success=True, status=201)