forked from ScoDoc/ScoDoc
Backend 'UniteEns': utilise uniquement modèles. + code modernization.
This commit is contained in:
parent
ae02dc5821
commit
612f95efaa
@ -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 ""
|
||||
}</span>"""
|
||||
|
||||
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'<div class="ue_list_div"><div class="ue_list_tit_sem">{lab}</div>'
|
||||
)
|
||||
@ -1205,8 +1162,8 @@ def _ue_table_ues(
|
||||
H.append(
|
||||
f"""</ul><ul><li><a href="{
|
||||
url_for('notes.ue_create', scodoc_dept=g.scodoc_dept,
|
||||
formation_id=ue.formation_id, semestre_idx=ue.semestre_id)
|
||||
}">Ajouter une UE dans le semestre {ue.semestre_id or ''}</a></li></ul>
|
||||
formation_id=ue.formation_id, semestre_idx=ue.get_semestre_id())
|
||||
}">Ajouter une UE dans le semestre {ue.get_semestre_id() or ''}</a></li></ul>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
|
@ -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(
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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"],
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user