diff --git a/app/formations/edit_ue.py b/app/formations/edit_ue.py
index 1b9e3e334..483d9e1fa 100644
--- a/app/formations/edit_ue.py
+++ b/app/formations/edit_ue.py
@@ -49,7 +49,6 @@ from app.models import (
)
from app.models import ApcValidationRCUE, ScolarFormSemestreValidation, ScolarEvent
from app.models import ScolarNews
-import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import ModuleType
from app.scodoc.TrivialFormulator import TrivialFormulator
@@ -65,54 +64,13 @@ from app.scodoc import sco_edit_apc
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
-_ueEditor = ndb.EditableTable(
- "notes_ue",
- "ue_id",
- (
- "ue_id",
- "formation_id",
- "acronyme",
- "numero",
- "titre",
- "semestre_idx",
- "type",
- "ue_code",
- "ects",
- "is_external",
- "code_apogee",
- "code_apogee_rcue",
- "coefficient",
- "coef_rcue",
- "color",
- "niveau_competence_id",
- ),
- convert_empty_to_nulls=False, # necessaire pour ue_code == ""
- sortkey="numero",
- input_formators={
- "type": ndb.int_null_is_zero,
- "is_external": scu.to_bool,
- "ects": ndb.float_null_is_null,
- },
- output_formators={
- "numero": ndb.int_null_is_zero,
- "ects": ndb.float_null_is_null,
- "coefficient": ndb.float_null_is_zero,
- "semestre_idx": ndb.int_null_is_null,
- },
-)
-
-def ue_list(*args, **kw):
- "list UEs"
- cnx = ndb.GetDBConnexion()
- return _ueEditor.list(cnx, *args, **kw)
-
-
-def do_ue_create(args, allow_empty_ue_code=False):
+def do_ue_create(args, allow_empty_ue_code=False) -> UniteEns:
"create an ue"
- cnx = ndb.GetDBConnexion()
# check duplicates
- ues = ue_list({"formation_id": args["formation_id"], "acronyme": args["acronyme"]})
+ ues = UniteEns.query.filter_by(
+ formation_id=args["formation_id"], acronyme=args["acronyme"]
+ ).all()
if ues:
raise ScoValueError(
f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé !
@@ -138,21 +96,21 @@ def do_ue_create(args, allow_empty_ue_code=False):
args["coefficient"] = None
# create
- # XXX TODO utiliser UniteEns.create_from_dict
- ue_id = _ueEditor.create(cnx, args)
- log(f"do_ue_create: created {ue_id} with {args}")
+ ue = UniteEns.create_from_dict(args)
+ db.session.commit()
+ log(f"do_ue_create: created {ue} with {args}")
- formation: Formation = db.session.get(Formation, args["formation_id"])
- formation.invalidate_module_coefs()
+ # caches
+ ue.formation.invalidate_module_coefs()
+ ue.formation.invalidate_cached_sems()
# news
- formation = db.session.get(Formation, args["formation_id"])
ScolarNews.add(
typ=ScolarNews.NEWS_FORM,
obj=args["formation_id"],
- text=f"Modification de la formation {formation.acronyme}",
+ text=f"Modification de la formation {ue.formation.acronyme}",
)
- formation.invalidate_cached_sems()
- return ue_id
+
+ return ue
def do_ue_delete(ue: UniteEns, delete_validations=False, force=False):
@@ -544,13 +502,13 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
tf[2]["numero"] = next_ue_numero(
formation_id, int(tf[2]["semestre_idx"])
)
- ue_id = do_ue_create(tf[2])
+ ue = do_ue_create(tf[2])
matiere_id = None
if is_apc or cursus.UE_IS_MODULE or tf[2]["create_matiere"]:
# rappel: en APC, toutes les UE ont une matière, créée ici
# (inutilisée mais à laquelle les modules sont rattachés)
matiere = Matiere.create_from_dict(
- {"ue_id": ue_id, "titre": tf[2]["titre"], "numero": 1}
+ {"ue_id": ue.id, "titre": tf[2]["titre"], "numero": 1}
)
matiere_id = matiere.id
if cursus.UE_IS_MODULE:
@@ -561,14 +519,13 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
"code": tf[2]["acronyme"],
# tous les modules auront coef 1, et on utilisera les ECTS:
"coefficient": 1.0,
- "ue_id": ue_id,
+ "ue_id": ue.id,
"matiere_id": matiere_id,
"formation_id": formation_id,
"semestre_id": tf[2]["semestre_idx"],
},
)
db.session.commit()
- ue = db.session.get(UniteEns, ue_id)
flash(f"UE créée (code {ue.ue_code})")
else:
if not tf[2]["numero"]:
@@ -1118,12 +1075,12 @@ def _ue_table_ues(
ue.code_apogee or ""
}"""
- if cur_ue_semestre_id != ue.semestre_id:
- cur_ue_semestre_id = ue.semestre_id
- if ue.semestre_id == codes_cursus.UE_SEM_DEFAULT:
+ if cur_ue_semestre_id != ue.get_semestre_id():
+ cur_ue_semestre_id = ue.get_semestre_id()
+ if ue.semestre_idx == codes_cursus.UE_SEM_DEFAULT:
lab = "Pas d'indication de semestre:"
else:
- lab = f"""Semestre {ue.semestre_id}:"""
+ lab = f"""Semestre {ue.get_semestre_id()}:"""
H.append(
f'
{lab}
'
)
@@ -1205,8 +1162,8 @@ def _ue_table_ues(
H.append(
f"""
+ formation_id=ue.formation_id, semestre_idx=ue.get_semestre_id())
+ }">Ajouter une UE dans le semestre {ue.get_semestre_id() or ''}
"""
)
diff --git a/app/formations/formation_io.py b/app/formations/formation_io.py
index f966fdb9e..38fc53d13 100644
--- a/app/formations/formation_io.py
+++ b/app/formations/formation_io.py
@@ -350,16 +350,15 @@ def formation_import_xml(doc: str | bytes, import_tags=True, use_local_refcomp=F
)
# Note: si le code est indiqué "" dans le xml, il faut le conserver vide
# pour la comparaison ultérieure des formations XXX
- ue_id = edit_ue.do_ue_create(ue_info[1], allow_empty_ue_code=True)
- ue: UniteEns = db.session.get(UniteEns, ue_id)
+ ue = edit_ue.do_ue_create(ue_info[1], allow_empty_ue_code=True)
assert ue
if xml_ue_id:
- ues_old2new[xml_ue_id] = ue_id
+ ues_old2new[xml_ue_id] = ue.id
# élément optionnel présent dans les exports BUT:
ue_reference = ue_info[1].get("reference")
if ue_reference:
- ue_reference_to_id[int(ue_reference)] = ue_id
+ ue_reference_to_id[int(ue_reference)] = ue.id
# -- Create matieres
for mat_info in ue_info[2]:
@@ -397,7 +396,7 @@ def formation_import_xml(doc: str | bytes, import_tags=True, use_local_refcomp=F
continue
assert mat_info[0] == "matiere"
- mat_info[1]["ue_id"] = ue_id
+ mat_info[1]["ue_id"] = ue.id
mat = Matiere.create_from_dict(mat_info[1])
mat_id = mat.id
# -- create modules
@@ -410,7 +409,7 @@ def formation_import_xml(doc: str | bytes, import_tags=True, use_local_refcomp=F
xml_module_id = None
mod_info[1]["formation_id"] = formation.id
mod_info[1]["matiere_id"] = mat_id
- mod_info[1]["ue_id"] = ue_id
+ mod_info[1]["ue_id"] = ue.id
if not "module_type" in mod_info[1]:
mod_info[1]["module_type"] = scu.ModuleType.STANDARD
module = Module.create_from_dict(
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 4afd6a3f3..cd2f0e7d2 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -19,6 +19,7 @@ from operator import attrgetter
from flask_login import current_user
from flask import abort, flash, g, url_for
+from flask_sqlalchemy.query import Query
from sqlalchemy.sql import text
from sqlalchemy import func
@@ -799,7 +800,7 @@ class FormSemestre(models.ScoDocModel):
@classmethod
def get_dept_formsemestres_courants(
cls, dept: Departement, date_courante: datetime.datetime | None = None
- ) -> db.Query:
+ ) -> Query:
"""Liste (query) ordonnée des formsemestres courants, c'est
à dire contenant la date courant (si None, la date actuelle)"""
date_courante = date_courante or db.func.current_date()
diff --git a/app/models/ues.py b/app/models/ues.py
index f7ad5ea70..dce90b4e6 100644
--- a/app/models/ues.py
+++ b/app/models/ues.py
@@ -120,7 +120,7 @@ class UniteEns(models.ScoDocModel):
if "is_external" in args:
args["is_external"] = scu.to_bool(args["is_external"])
if "ects" in args:
- args["ects"] = float(args["ects"])
+ args["ects"] = None if args["ects"] is None else float(args["ects"])
return args
@@ -190,7 +190,7 @@ class UniteEns(models.ScoDocModel):
utilisée dans un formsemestre verrouillé ou validations de jury de cette UE.
Renvoie aussi une explication.
"""
- from app.models import FormSemestre, ModuleImpl, ScolarFormSemestreValidation
+ from app.models import ModuleImpl, ScolarFormSemestreValidation
# before 9.7.23: contains modules used in a locked formsemestre
# starting from 9.7.23: + existence de validations de jury de cette UE
diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py
index 1352ea655..99a9b8b93 100644
--- a/app/scodoc/sco_bulletins_json.py
+++ b/app/scodoc/sco_bulletins_json.py
@@ -495,16 +495,16 @@ def dict_decision_jury(
# and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id):
# always publish (car utile pour export Apogee)
for ue_id in decision["decisions_ue"].keys():
- ue = edit_ue.ue_list({"ue_id": ue_id})[0]
+ ue = UniteEns.get_ue(ue_id)
d["decision_ue"].append(
- dict(
- ue_id=ue["ue_id"],
- numero=ue["numero"],
- acronyme=ue["acronyme"],
- titre=ue["titre"],
- code=decision["decisions_ue"][ue_id]["code"],
- ects=ue["ects"] or "",
- )
+ {
+ "ue_id": ue.ue_id,
+ "numero": ue.numero,
+ "acronyme": ue.acronyme,
+ "titre": ue.titre,
+ "code": decision["decisions_ue"][ue.id]["code"],
+ "ects": ue.ects or "",
+ }
)
d["autorisation_inscription"] = []
for aut in decision["autorisations"]:
@@ -515,7 +515,7 @@ def dict_decision_jury(
)
)
else:
- d["decision"] = dict(code="", etat="DEM")
+ d["decision"] = {"code": "", "etat": "DEM"}
# Ajout jury BUT:
if formsemestre.formation.is_apc():
d.update(but_validations.dict_decision_jury(etud, formsemestre))
diff --git a/app/scodoc/sco_bulletins_xml.py b/app/scodoc/sco_bulletins_xml.py
index dfff8feeb..1a2e2d1f3 100644
--- a/app/scodoc/sco_bulletins_xml.py
+++ b/app/scodoc/sco_bulletins_xml.py
@@ -51,7 +51,7 @@ import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import log
from app.but.bulletin_but_xml_compat import bulletin_but_xml_compat
-from app.models import BulAppreciations, Evaluation, FormSemestre
+from app.models import BulAppreciations, Evaluation, FormSemestre, UniteEns
from app.scodoc import sco_assiduites
from app.scodoc import codes_cursus
from app.scodoc import sco_formsemestre
@@ -389,19 +389,19 @@ def make_xml_formsemestre_bulletinetud(
else:
doc.append(Element("decision", code=code, etat=str(etat)))
- if decision[
- "decisions_ue"
- ]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
+ if decision["decisions_ue"]:
+ # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id):
+ # always publish (car utile pour export Apogee)
for ue_id in decision["decisions_ue"].keys():
- ue = edit_ue.ue_list({"ue_id": ue_id})[0]
+ ue = UniteEns.get_ue(ue_id)
doc.append(
Element(
"decision_ue",
- ue_id=str(ue["ue_id"]),
- numero=quote_xml_attr(ue["numero"]),
- acronyme=quote_xml_attr(ue["acronyme"]),
- titre=quote_xml_attr(ue["titre"]),
- code=decision["decisions_ue"][ue_id]["code"],
+ ue_id=str(ue.id),
+ numero=quote_xml_attr(ue.numero),
+ acronyme=quote_xml_attr(ue.acronyme),
+ titre=quote_xml_attr(ue.titre or ""),
+ code=decision["decisions_ue"][ue.id]["code"],
)
)
diff --git a/app/scodoc/sco_formsemestre_exterieurs.py b/app/scodoc/sco_formsemestre_exterieurs.py
index 9b2c59748..6ad279ff0 100644
--- a/app/scodoc/sco_formsemestre_exterieurs.py
+++ b/app/scodoc/sco_formsemestre_exterieurs.py
@@ -453,7 +453,7 @@ def _ue_form_description(
return descr
-def _check_values(formsemestre: FormSemestre, ue_list, values):
+def _check_values(formsemestre: FormSemestre, ue_list: list[UniteEns], values):
"""Check that form values are ok
for each UE:
code != None => note and coef
diff --git a/app/scodoc/sco_ue_external.py b/app/scodoc/sco_ue_external.py
index fa85beebf..4e74e25dc 100644
--- a/app/scodoc/sco_ue_external.py
+++ b/app/scodoc/sco_ue_external.py
@@ -96,7 +96,7 @@ def external_ue_create(
formation_id = formsemestre.formation.id
numero = edit_ue.next_ue_numero(formation_id, semestre_id=formsemestre.semestre_id)
- ue_id = edit_ue.do_ue_create(
+ ue = edit_ue.do_ue_create(
{
"formation_id": formation_id,
"semestre_idx": formsemestre.semestre_id,
@@ -108,10 +108,9 @@ def external_ue_create(
"is_external": True,
},
)
- ue = db.session.get(UniteEns, ue_id)
flash(f"UE créée (code {ue.ue_code})")
matiere = Matiere.create_from_dict(
- {"ue_id": ue_id, "titre": titre or acronyme, "numero": 1}
+ {"ue_id": ue.id, "titre": titre or acronyme, "numero": 1}
)
module = Module.create_from_dict(
@@ -119,7 +118,7 @@ def external_ue_create(
"titre": "UE extérieure",
"code": acronyme,
"coefficient": ects, # tous le coef. module est egal à la quantite d'ECTS
- "ue_id": ue_id,
+ "ue_id": ue.id,
"matiere_id": matiere.id,
"formation_id": formation_id,
"semestre_id": formsemestre.semestre_id,
diff --git a/tests/unit/sco_fake_gen.py b/tests/unit/sco_fake_gen.py
index d9545c961..06a10f3f6 100644
--- a/tests/unit/sco_fake_gen.py
+++ b/tests/unit/sco_fake_gen.py
@@ -197,11 +197,8 @@ class ScoFake(object):
"""
if numero is None:
numero = edit_ue.next_ue_numero(formation_id, 0)
- oid = edit_ue.do_ue_create(locals())
- oids = edit_ue.ue_list(args={"ue_id": oid})
- if not oids:
- raise ScoValueError("ue not created !")
- return oid
+ ue = edit_ue.do_ue_create(locals())
+ return ue.id
@logging_meth
def create_matiere(self, ue_id=None, titre=None, numero=0) -> int:
diff --git a/tests/unit/test_formations.py b/tests/unit/test_formations.py
index a68114891..d047a0708 100644
--- a/tests/unit/test_formations.py
+++ b/tests/unit/test_formations.py
@@ -51,7 +51,7 @@ from app.formations import (
edit_ue,
formation_io,
)
-from app.models import Formation, Matiere, Module, ModuleImpl
+from app.models import Formation, Matiere, Module, ModuleImpl, UniteEns
from app.scodoc import sco_formsemestre
from app.scodoc import sco_exceptions
from app.scodoc import sco_formsemestre_edit
@@ -292,11 +292,9 @@ def test_formations(test_client):
li_mat2 = Matiere.query.all()
assert len(li_mat2) == 3 # verification de la suppression de la matiere
- li_ue = edit_ue.ue_list()
- assert len(li_ue) == 4
+ assert UniteEns.query.count() == 4
edit_ue.ue_delete(ue_id=uet_id, dialog_confirmed=True)
- li_ue2 = edit_ue.ue_list()
- assert len(li_ue2) == 3 # verification de la suppression de l'UE
+ assert UniteEns.query.count() == 3 # verification de la suppression de l'UE
# --- Suppression d'une formation
@@ -321,9 +319,9 @@ def test_import_formation(test_client, filename="formation-exemple-1.xml"):
assert len(f) == 3 # 3-uple
formation_id = f[0]
# --- Vérification des UE
- ues = edit_ue.ue_list({"formation_id": formation_id})
+ ues = UniteEns.query.filter_by(formation_id=formation_id).all()
assert len(ues) == 10
- assert all(not ue["is_external"] for ue in ues) # aucune UE externe dans le XML
+ assert all(not ue.is_external for ue in ues) # aucune UE externe dans le XML
# --- Mise en place de 4 semestres
formsemestre_ids = [
G.create_formsemestre(