This commit is contained in:
Emmanuel Viennet 2024-10-28 22:20:30 +01:00
commit d1a2e52fef
7 changed files with 48 additions and 160 deletions

View File

@ -1121,7 +1121,7 @@ def _ue_table_ues(
# Cas spécial: si l'UE externe a plus d'un module, c'est peut être une UE # Cas spécial: si l'UE externe a plus d'un module, c'est peut être une UE
# qui a été déclarée externe par erreur (ou suite à un bug d'import/export xml) # qui a été déclarée externe par erreur (ou suite à un bug d'import/export xml)
# Dans ce cas, propose de changer le type (même si verrouillée) # Dans ce cas, propose de changer le type (même si verrouillée)
if len(sco_moduleimpl.moduleimpls_in_external_ue(ue.id)) > 1: if ue.modules.count() > 1:
H.append('<span class="ue_is_external">') H.append('<span class="ue_is_external">')
if has_perm_change: if has_perm_change:
H.append( H.append(

View File

@ -960,19 +960,15 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
modimpl.id}: aucun etudiant inscrit""" modimpl.id}: aucun etudiant inscrit"""
) )
# #
ok, diag = formsemestre_delete_moduleimpls(formsemestre.id, module_ids_todelete) ok, diag = formsemestre_delete_moduleimpls(formsemestre, module_ids_todelete)
msg += diag msg += diag
for module_id in module_ids_toedit: for module_id in module_ids_toedit:
moduleimpl_id = sco_moduleimpl.moduleimpl_list( modimpl = formsemestre.modimpls.filter_by(module_id=module_id).first()
formsemestre_id=formsemestre.id, module_id=module_id if not modimpl:
)[0]["moduleimpl_id"] raise ScoValueError("Module introuvable ! Veuillez recharger la page.")
modargs = { modimpl.responsable_id = tf[2]["MI" + str(module_id)]
"moduleimpl_id": moduleimpl_id, db.session.add(modimpl)
"module_id": module_id, db.session.commit()
"formsemestre_id": formsemestre.id,
"responsable_id": tf[2]["MI" + str(module_id)],
}
sco_moduleimpl.do_moduleimpl_edit(modargs, formsemestre_id=formsemestre.id)
# --- Etapes # --- Etapes
_set_apo_etapes(formsemestre, tf[2], etapes) _set_apo_etapes(formsemestre, tf[2], etapes)
# --- id edt du groupe par défault # --- id edt du groupe par défault
@ -984,6 +980,7 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
db.session.add(formsemestre) db.session.add(formsemestre)
db.session.commit() db.session.commit()
sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre.id)
# --- Crée ou met à jour les groupes de parcours BUT # --- Crée ou met à jour les groupes de parcours BUT
formsemestre.setup_parcours_groups() formsemestre.setup_parcours_groups()
@ -1110,7 +1107,9 @@ def _formsemestre_check_ue_bonus_unicity(module_ids):
) )
def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del): def formsemestre_delete_moduleimpls(
formsemestre: FormSemestre, module_ids_to_del: list[int]
) -> tuple[bool, list[str]]:
"""Delete moduleimpls """Delete moduleimpls
module_ids_to_del: list of module_id (warning: not moduleimpl) module_ids_to_del: list of module_id (warning: not moduleimpl)
Moduleimpls must have no associated evaluations. Moduleimpls must have no associated evaluations.
@ -1122,7 +1121,7 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
if module is None: if module is None:
continue # ignore invalid ids continue # ignore invalid ids
modimpls = ModuleImpl.query.filter_by( modimpls = ModuleImpl.query.filter_by(
formsemestre_id=formsemestre_id, module_id=module_id formsemestre_id=formsemestre.id, module_id=module_id
) )
for modimpl in modimpls: for modimpl in modimpls:
nb_evals = modimpl.evaluations.count() nb_evals = modimpl.evaluations.count()

View File

@ -35,7 +35,13 @@ from flask import flash, url_for, g, render_template, request
from app import db from app import db
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 Formation, FormSemestre, FormSemestreInscription, Scolog from app.models import (
Formation,
FormSemestre,
FormSemestreInscription,
ModuleImpl,
Scolog,
)
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.models.groups import Partition, GroupDescr from app.models.groups import Partition, GroupDescr
from app.models.scolar_event import ScolarEvent from app.models.scolar_event import ScolarEvent
@ -729,23 +735,22 @@ def do_moduleimpl_incription_options(
# inscriptions # inscriptions
for moduleimpl_id in a_inscrire: for moduleimpl_id in a_inscrire:
# verifie que ce module existe bien # verifie que ce module existe bien
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id) modimpl = db.session.query(ModuleImpl).get(moduleimpl_id)
if len(mods) != 1: if modimpl is None:
raise ScoValueError(f"inscription: invalid moduleimpl_id: {moduleimpl_id}") raise ScoValueError(f"inscription: invalid moduleimpl_id: {moduleimpl_id}")
mod = mods[0]
sco_moduleimpl.do_moduleimpl_inscription_create( sco_moduleimpl.do_moduleimpl_inscription_create(
{"moduleimpl_id": moduleimpl_id, "etudid": etudid}, {"moduleimpl_id": moduleimpl_id, "etudid": etudid},
formsemestre_id=mod["formsemestre_id"], formsemestre_id=modimpl.formsemestre_id,
) )
# desinscriptions # desinscriptions
for moduleimpl_id in a_desinscrire: for moduleimpl_id in a_desinscrire:
# verifie que ce module existe bien # verifie que ce module existe bien
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id) modimpl = db.session.query(ModuleImpl).get(moduleimpl_id)
if len(mods) != 1: if modimpl is None:
raise ScoValueError( raise ScoValueError(
f"desinscription: invalid moduleimpl_id: {moduleimpl_id}" f"desinscription: invalid moduleimpl_id: {moduleimpl_id}"
) )
mod = mods[0]
inscr = sco_moduleimpl.do_moduleimpl_inscription_list( inscr = sco_moduleimpl.do_moduleimpl_inscription_list(
moduleimpl_id=moduleimpl_id, etudid=etudid moduleimpl_id=moduleimpl_id, etudid=etudid
) )
@ -755,7 +760,7 @@ def do_moduleimpl_incription_options(
) )
oid = inscr[0]["moduleimpl_inscription_id"] oid = inscr[0]["moduleimpl_inscription_id"]
sco_moduleimpl.do_moduleimpl_inscription_delete( sco_moduleimpl.do_moduleimpl_inscription_delete(
oid, formsemestre_id=mod["formsemestre_id"] oid, formsemestre_id=modimpl.formsemestre_id
) )
H = [ H = [

View File

@ -40,13 +40,12 @@ from flask import url_for, g, render_template, request
from flask_login import current_user from flask_login import current_user
from app import db, log from app import db, log
from app.models import FormSemestre, Identite, ScolarEvent from app.models import FormSemestre, Identite, ModuleImpl, ScolarEvent
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import sco_assiduites as scass from app.scodoc import sco_assiduites as scass
from app.scodoc import sco_excel from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_cursus from app.scodoc import sco_cursus
from app.scodoc import sco_portal_apogee from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
@ -364,10 +363,10 @@ class DisplayedGroupsInfos:
"identifiant de groupe invalide (mettre à jour vos bookmarks ?)" "identifiant de groupe invalide (mettre à jour vos bookmarks ?)"
) from exc ) from exc
if not formsemestre_id and moduleimpl_id: if not formsemestre_id and moduleimpl_id:
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id) modimpl = db.session.get(ModuleImpl, moduleimpl_id)
if len(mods) != 1: if modimpl is None:
raise ValueError("invalid moduleimpl_id") raise ValueError("invalid moduleimpl_id")
formsemestre_id = mods[0]["formsemestre_id"] formsemestre_id = modimpl.formsemestre_id
if not group_ids: # appel sans groupe (eg page accueil) if not group_ids: # appel sans groupe (eg page accueil)
if not formsemestre_id: if not formsemestre_id:

View File

@ -35,81 +35,6 @@ from app.scodoc import sco_cache
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
# --- Gestion des "Implémentations de Modules"
# Un "moduleimpl" correspond a la mise en oeuvre d'un module
# dans une formation spécifique, à une date spécifique.
_moduleimplEditor = ndb.EditableTable(
"notes_moduleimpl",
"moduleimpl_id",
(
"moduleimpl_id",
"module_id",
"formsemestre_id",
"responsable_id",
"computation_expr",
),
)
def do_moduleimpl_delete(oid, formsemestre_id=None):
"delete moduleimpl (desinscrit tous les etudiants)"
cnx = ndb.GetDBConnexion()
# --- desinscription des etudiants
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
req = (
"DELETE FROM notes_moduleimpl_inscription WHERE moduleimpl_id=%(moduleimpl_id)s"
)
cursor.execute(req, {"moduleimpl_id": oid})
# --- suppression des enseignants
cursor.execute(
"DELETE FROM notes_modules_enseignants WHERE moduleimpl_id=%(moduleimpl_id)s",
{"moduleimpl_id": oid},
)
# --- suppression des references dans les absences
cursor.execute(
"UPDATE absences SET moduleimpl_id=NULL WHERE moduleimpl_id=%(moduleimpl_id)s",
{"moduleimpl_id": oid},
)
# --- destruction du moduleimpl
_moduleimplEditor.delete(cnx, oid)
sco_cache.invalidate_formsemestre(
formsemestre_id=formsemestre_id
) # > moduleimpl_delete
def moduleimpl_list(
moduleimpl_id=None, formsemestre_id=None, module_id=None
) -> list[dict]:
"list moduleimpls"
args = locals()
cnx = ndb.GetDBConnexion()
modimpls = _moduleimplEditor.list(cnx, args)
return modimpls
def do_moduleimpl_edit(args, formsemestre_id=None, cnx=None):
"edit a moduleimpl"
if not cnx:
cnx = ndb.GetDBConnexion()
_moduleimplEditor.edit(cnx, args)
sco_cache.invalidate_formsemestre(
formsemestre_id=formsemestre_id
) # > modif moduleimpl
def moduleimpls_in_external_ue(ue_id):
"""List of modimpls in this ue"""
cursor = ndb.SimpleQuery(
"""SELECT DISTINCT mi.*
FROM notes_ue u, notes_moduleimpl mi, notes_modules m
WHERE u.is_external is true
AND mi.module_id = m.id AND m.ue_id = %(ue_id)s
""",
{"ue_id": ue_id},
)
return cursor.dictfetchall()
def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None): def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
"list moduleimpl_inscriptions" "list moduleimpl_inscriptions"
@ -118,38 +43,6 @@ def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
return _moduleimpl_inscriptionEditor.list(cnx, args) return _moduleimpl_inscriptionEditor.list(cnx, args)
def moduleimpl_listeetuds(moduleimpl_id): # XXX OBSOLETE
"retourne liste des etudids inscrits a ce module"
req = """SELECT DISTINCT Im.etudid
FROM notes_moduleimpl_inscription Im,
notes_formsemestre_inscription Isem,
notes_moduleimpl M
WHERE Isem.etudid = Im.etudid
and Im.moduleimpl_id = M.id
and M.id = %(moduleimpl_id)s
"""
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(req, {"moduleimpl_id": moduleimpl_id})
res = cursor.fetchall()
return [x[0] for x in res]
def do_moduleimpl_inscrit_tout_semestre(moduleimpl_id, formsemestre_id):
"inscrit tous les etudiants inscrit au semestre a ce module"
# UNUSED
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
req = """INSERT INTO notes_moduleimpl_inscription
(moduleimpl_id, etudid)
SELECT %(moduleimpl_id)s, I.etudid
FROM notes_formsemestre_inscription I
WHERE I.formsemestre_id=%(formsemestre_id)s
"""
args = {"moduleimpl_id": moduleimpl_id, "formsemestre_id": formsemestre_id}
cursor.execute(req, args)
# --- Inscriptions aux modules # --- Inscriptions aux modules
_moduleimpl_inscriptionEditor = ndb.EditableTable( _moduleimpl_inscriptionEditor = ndb.EditableTable(
"notes_moduleimpl_inscription", "notes_moduleimpl_inscription",

View File

@ -2588,23 +2588,20 @@ def check_sem_integrity(formsemestre_id, fix=False):
Check that ue and module formations are consistents Check that ue and module formations are consistents
""" """
formsemestre = FormSemestre.get_formsemestre(formsemestre_id) formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id) modimpls = formsemestre.modimpls.all()
bad_ue = [] bad_ue = []
bad_sem = [] bad_sem = []
formations_set = set() # les formations mentionnées dans les UE et modules formations_set = set() # les formations mentionnées dans les UE et modules
for modimpl in modimpls: for modimpl in modimpls:
mod = Module.get_instance(modimpl["module_id"]) mod = modimpl.module
formations_set.add(mod.formation_id) formations_set.add(mod.formation_id)
ue = mod.ue ue = mod.ue
ue_dict = ue.to_dict() ue_dict = ue.to_dict()
formations_set.add(ue_dict["formation_id"]) formations_set.add(ue_dict["formation_id"])
if ue_dict["formation_id"] != mod.formation_id: if ue_dict["formation_id"] != mod.formation_id:
modimpl["mod"] = mod.to_dict()
modimpl["ue"] = ue_dict
bad_ue.append(modimpl) bad_ue.append(modimpl)
if formsemestre.formation_id != mod.formation_id: if formsemestre.formation_id != mod.formation_id:
bad_sem.append(modimpl) bad_sem.append(modimpl)
modimpl["mod"] = mod.to_dict()
H = [ H = [
f"""<p>formation_id={formsemestre.formation_id}""", f"""<p>formation_id={formsemestre.formation_id}""",

View File

@ -31,7 +31,6 @@
# - create_moduleimpl # - create_moduleimpl
# - formation_export # - formation_export
# - formsemestre_list # - formsemestre_list
# - moduleimpl_list
# - do_module_impl_with_module_list # - do_module_impl_with_module_list
# - do_formsemestre_delete # - do_formsemestre_delete
# - Module.delete # - Module.delete
@ -231,25 +230,18 @@ def test_formations(test_client):
# --- Liste des modules # --- Liste des modules
lim_sem1 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem1["formsemestre_id"]) lim_sem1 = (
db.session.query(ModuleImpl)
.filter_by(formsemestre_id=sem1["formsemestre_id"])
.all()
)
assert len(lim_sem1) == 2 assert len(lim_sem1) == 2
assert module_id in ( assert module_id in (lim_sem1[0].module_id, lim_sem1[1].module_id)
lim_sem1[0]["module_id"], assert module_id2 in (lim_sem1[0].module_id, lim_sem1[1].module_id)
lim_sem1[1]["module_id"],
)
assert module_id2 in (
lim_sem1[0]["module_id"],
lim_sem1[1]["module_id"],
)
lim_modid = sco_moduleimpl.moduleimpl_list(module_id=module_id)
lim_modid = db.session.query(ModuleImpl).filter_by(module_id=module_id).all()
assert len(lim_modid) == 1 assert len(lim_modid) == 1
lim_modimpl_id = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
assert lim_modid == lim_modimpl_id
# --- Suppression du module, matiere et ue test du semestre 2 # --- Suppression du module, matiere et ue test du semestre 2
# on doit d'abord supprimer le semestre: # on doit d'abord supprimer le semestre:
@ -280,8 +272,11 @@ def test_formations(test_client):
len(li_module2_after) == len(li_module2_before) - 2 len(li_module2_after) == len(li_module2_before) - 2
) # verification de la suppression ) # verification de la suppression
lim_sem2 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem2["formsemestre_id"]) lim_sem2 = (
db.session.query(ModuleImpl)
.filter_by(formsemestre_id=sem2["formsemestre_id"])
.all()
)
assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup
li_mat = Matiere.query.all() li_mat = Matiere.query.all()
@ -344,8 +339,8 @@ def test_import_formation(test_client, filename="formation-exemple-1.xml"):
module_id=mod.id, module_id=mod.id,
formsemestre_id=formsemestre_ids[mod.semestre_id - 1], formsemestre_id=formsemestre_ids[mod.semestre_id - 1],
) )
mi = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0] mi = db.session.query(ModuleImpl).get(moduleimpl_id)
assert mi["module_id"] == mod.id assert mi.module_id == mod.id
# --- Export formation en XML # --- Export formation en XML
doc1 = formation_io.formation_export(formation_id, fmt="xml").get_data(as_text=True) doc1 = formation_io.formation_export(formation_id, fmt="xml").get_data(as_text=True)