Améliore import/export formations APC.

This commit is contained in:
Emmanuel Viennet 2023-01-25 11:17:52 -03:00
parent 3ba553c090
commit fca090649c
14 changed files with 81 additions and 34 deletions

View File

@ -55,7 +55,8 @@ class Formation(db.Model):
modules = db.relationship("Module", lazy="dynamic", backref="formation")
def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme!r}')>"
return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
def to_html(self) -> str:
"titre complet pour affichage"

View File

@ -111,6 +111,7 @@ class UniteEns(db.Model):
e["ects"] = e["ects"]
e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
e["code_apogee"] = e["code_apogee"] or "" # pas de None
e["parcour"] = self.parcour.to_dict() if self.parcour else None
if with_module_ue_coefs:
if convert_objects:
e["module_ue_coefs"] = [

View File

@ -99,7 +99,7 @@ def html_edit_formation_apc(
H = [
render_template(
"pn/form_ues.html",
"pn/form_ues.j2",
formation=formation,
semestre_ids=semestre_ids,
editable=editable,
@ -122,7 +122,7 @@ def html_edit_formation_apc(
).first()
H += [
render_template(
"pn/form_mods.html",
"pn/form_mods.j2",
formation=formation,
titre=f"Ressources du S{semestre_idx}",
create_element_msg="créer une nouvelle ressource",
@ -138,7 +138,7 @@ def html_edit_formation_apc(
if ues_by_sem[semestre_idx].count() > 0
else "",
render_template(
"pn/form_mods.html",
"pn/form_mods.j2",
formation=formation,
titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}",
create_element_msg="créer une nouvelle SAÉ",
@ -154,7 +154,7 @@ def html_edit_formation_apc(
if ues_by_sem[semestre_idx].count() > 0
else "",
render_template(
"pn/form_mods.html",
"pn/form_mods.j2",
formation=formation,
titre=f"Autres modules (non BUT) du S{semestre_idx}",
create_element_msg="créer un nouveau module",
@ -196,7 +196,7 @@ def html_ue_infos(ue):
and ue.matieres.count() == 0
)
return render_template(
"pn/ue_infos.html",
"pn/ue_infos.j2",
titre=f"UE {ue.acronyme} {ue.titre}",
ue=ue,
formsemestres=formsemestres,

View File

@ -723,7 +723,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
"libjs/jQuery-tagEditor/jquery.caret.min.js",
"js/module_tag_editor.js",
],
page_title=f"Programme {formation.acronyme}",
page_title=f"Programme {formation.acronyme} v{formation.version}",
),
f"""<h2>{formation.to_html()} {lockicon}
</h2>
@ -765,7 +765,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
# Description de la formation
H.append(
render_template(
"pn/form_descr.html",
"pn/form_descr.j2",
formation=formation,
parcours=parcours,
editable=editable,
@ -913,8 +913,12 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
<li><a class="stdlink" href="{
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
formation_id=formation_id, format='xml')
}">Export XML de la formation</a>
(permet de la sauvegarder pour l'échanger avec un autre site)
}">Export XML de la formation</a> ou
<a class="stdlink" href="{
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
formation_id=formation_id, format='xml', export_codes_apo=0)
}">sans codes Apogée</a>
(permet de l'enregistrer pour l'échanger avec un autre site)
</li>
<li><a class="stdlink" href="{

View File

@ -109,6 +109,7 @@ def formation_export(
export_ids=False,
export_tags=True,
export_external_ues=False,
export_codes_apo=True,
format=None,
):
"""Get a formation, with UE, matieres, modules
@ -116,30 +117,45 @@ def formation_export(
"""
formation: Formation = Formation.query.get_or_404(formation_id)
f_dict = formation.to_dict(with_refcomp_attrs=True)
selector = {"formation_id": formation_id}
if not export_ids:
del f_dict["formation_id"]
del f_dict["dept_id"]
ues = formation.ues
if not export_external_ues:
selector["is_external"] = False
ues = sco_edit_ue.ue_list(selector)
f_dict["ue"] = ues
for ue_dict in ues:
ue_id = ue_dict["ue_id"]
ues = ues.filter_by(is_external=False)
ues = ues.all()
ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
f_dict["ue"] = []
for ue in ues:
ue_dict = ue.to_dict()
f_dict["ue"].append(ue_dict)
ue_dict.pop("module_ue_coefs", None)
if formation.is_apc():
# BUT: indique niveau de compétence associé à l'UE
ue = UniteEns.query.get(ue_id)
if ue.niveau_competence:
ue_dict["apc_niveau_libelle"] = ue.niveau_competence.libelle
ue_dict["apc_niveau_annee"] = ue.niveau_competence.annee
ue_dict["apc_niveau_ordre"] = ue.niveau_competence.ordre
ue_dict["reference"] = ue_id # pour les coefficients
# Et le parcour:
if ue.parcour:
ue_dict["parcour"] = [ue.parcour.to_dict(with_annees=False)]
ue_dict["reference"] = ue.id # pour les coefficients
if not export_ids:
del ue_dict["id"]
del ue_dict["ue_id"]
del ue_dict["formation_id"]
if "niveau_competence_id" in ue_dict:
del ue_dict["niveau_competence_id"]
for id_id in (
"id",
"ue_id",
"formation_id",
"parcour_id",
"niveau_competence_id",
):
ue_dict.pop(id_id, None)
if not export_codes_apo:
ue_dict.pop("code_apogee", None)
if ue_dict["ects"] is None:
del ue_dict["ects"]
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
mats.sort(key=lambda m: m["numero"] or 0)
ue_dict["matiere"] = mats
for mat in mats:
matiere_id = mat["matiere_id"]
@ -148,6 +164,7 @@ def formation_export(
del mat["matiere_id"]
del mat["ue_id"]
mods = sco_edit_module.module_list({"matiere_id": matiere_id})
mods.sort(key=lambda m: (m["numero"] or 0, m["code"]))
mat["module"] = mods
for mod in mods:
module_id = mod["module_id"]
@ -183,6 +200,8 @@ def formation_export(
del mod["matiere_id"]
del mod["module_id"]
del mod["formation_id"]
if not export_codes_apo:
del mod["code_apogee"]
if mod["ects"] is None:
del mod["ects"]
@ -323,14 +342,30 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
referentiel_competence_id, ue_info[1]
)
ue_id = sco_edit_ue.do_ue_create(ue_info[1])
ue: UniteEns = UniteEns.query.get(ue_id)
assert ue
if xml_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
# -- create matieres
for mat_info in ue_info[2]:
if mat_info[0] == "parcour":
# Parcours (BUT)
code_parcours = mat_info[1]["code"]
parcour = ApcParcours.query.filter_by(
code=code_parcours,
referentiel_id=referentiel_competence_id,
).first()
if parcour:
ue.parcour = parcour
db.session.add(ue)
else:
log(f"Warning: parcours {code_parcours} inexistant !")
continue
assert mat_info[0] == "matiere"
mat_info[1]["ue_id"] = ue_id
mat_id = sco_edit_matiere.do_matiere_create(mat_info[1])
@ -382,12 +417,12 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
# associe les parcours de ce module (BUT)
if referentiel_competence_id is not None:
code_parcours = child[1]["code"]
parcours = ApcParcours.query.filter_by(
parcour = ApcParcours.query.filter_by(
code=code_parcours,
referentiel_id=referentiel_competence_id,
).first()
if parcours:
module.parcours.append(parcours)
if parcour:
module.parcours.append(parcour)
db.session.add(module)
else:
log(

View File

@ -200,7 +200,7 @@ def etud_photo_html(etud: dict = None, etudid=None, title=None, size="small") ->
return abort(404, "etudiant inconnu")
etud = etuds[0]
else:
raise ValueError("etud_photo_html: either etud or etudid must be specified")
abort(404, "etud_photo_html: either etud or etudid must be specified")
photo_url = etud_photo_url(etud, size=size)
nom = etud.get("nomprenom", etud["nom_disp"])
if title is None:
@ -244,7 +244,7 @@ def photo_pathname(photo_filename: str, size="orig"):
elif size == "orig":
version = ""
else:
raise ValueError("invalid size parameter for photo")
abort(404, "invalid size parameter for photo")
if not photo_filename:
return False
path = os.path.join(PHOTO_DIR, photo_filename) + version + IMAGE_EXT

View File

@ -49,7 +49,8 @@
<span class="formation_module_ue">(<a title="UE de rattachement">{{mod.ue.acronyme}}</a>)</span>,
{% endif %}
parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun', true)|safe
- parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun',
true)|safe
}}</b>
{% if mod.heures_cours or mod.heures_td or mod.heures_tp %}
({{mod.heures_cours|default("&nbsp;",true)|safe}}/{{mod.heures_td|default("&nbsp;",true)|safe}}/{{mod.heures_tp|default("&nbsp;",true)|safe}},

View File

@ -704,10 +704,15 @@ def formation_list(format=None, formation_id=None, args={}):
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def formation_export(formation_id, export_ids=False, format=None):
def formation_export(
formation_id, export_ids=False, format=None, export_codes_apo=True
):
"Export de la formation au format indiqué (xml ou json)"
return sco_formations.formation_export(
formation_id, export_ids=export_ids, format=format
formation_id,
export_ids=export_ids,
format=format,
export_codes_apo=export_codes_apo,
)

View File

@ -216,7 +216,7 @@ def edit_modules_ue_coefs():
</h2>
""",
render_template(
"pn/form_modules_ue_coefs.html",
"pn/form_modules_ue_coefs.j2",
formation=formation,
data_source=url_for(
"notes.table_modules_ue_coefs",

View File

@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
SCOVERSION = "9.4.31"
SCOVERSION = "9.4.32"
SCONAME = "ScoDoc"