Corrige Import/Export formations BUT en XML

This commit is contained in:
Emmanuel Viennet 2022-10-24 23:18:45 +02:00
parent 557a0c3f6d
commit 1598537f24
5 changed files with 140 additions and 52 deletions

View File

@ -376,7 +376,9 @@ class ApcAppCritique(db.Model, XMLModel):
query = query.filter(ApcNiveau.competence == competence)
return query
def to_dict(self) -> dict:
def to_dict(self, with_code=False) -> dict:
if with_code:
return {"code": self.code, "libelle": self.libelle}
return {"libelle": self.libelle}
def get_label(self) -> str:

View File

@ -135,7 +135,6 @@ def do_ue_create(args):
formation.invalidate_module_coefs()
# news
ue = UniteEns.query.get(ue_id)
flash(f"UE créée (code {ue.ue_code})")
formation = Formation.query.get(args["formation_id"])
ScolarNews.add(
typ=ScolarNews.NEWS_FORM,
@ -512,7 +511,8 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
"semestre_id": tf[2]["semestre_idx"],
},
)
flash("UE créée")
ue = UniteEns.query.get(ue_id)
flash(f"UE créée (code {ue.ue_code})")
else:
do_ue_edit(tf[2])
flash("UE modifiée")

View File

@ -38,9 +38,15 @@ import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import db
from app import log
from app.models import Formation, Module
from app.models import Formation, Module, UniteEns
from app.models import ScolarNews
from app.models.but_refcomp import ApcParcours, ApcReferentielCompetences
from app.models.but_refcomp import (
ApcAppCritique,
ApcCompetence,
ApcNiveau,
ApcParcours,
ApcReferentielCompetences,
)
from app.scodoc import sco_cache
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_edit_matiere
@ -109,23 +115,32 @@ def formation_export(
in desired format
"""
formation: Formation = Formation.query.get_or_404(formation_id)
F = formation.to_dict(with_refcomp_attrs=True)
f_dict = formation.to_dict(with_refcomp_attrs=True)
selector = {"formation_id": formation_id}
if not export_external_ues:
selector["is_external"] = False
ues = sco_edit_ue.ue_list(selector)
F["ue"] = ues
for ue in ues:
ue_id = ue["ue_id"]
ue["reference"] = ue_id # pour les coefficients
f_dict["ue"] = ues
for ue_dict in ues:
ue_id = ue_dict["ue_id"]
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
if not export_ids:
del ue["id"]
del ue["ue_id"]
del ue["formation_id"]
if ue["ects"] is None:
del ue["ects"]
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"]
if ue_dict["ects"] is None:
del ue_dict["ects"]
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
ue["matiere"] = mats
ue_dict["matiere"] = mats
for mat in mats:
matiere_id = mat["matiere_id"]
if not export_ids:
@ -153,9 +168,15 @@ def formation_export(
p.to_dict(with_annees=False) for p in module.parcours
]
# Et les AC
mod["app_critiques"] = {
x.code: x.to_dict() for x in module.app_critiques
}
if format == "xml":
# XML préfère une liste
mod["app_critiques"] = [
x.to_dict(with_code=True) for x in module.app_critiques
]
else:
mod["app_critiques"] = {
x.code: x.to_dict() for x in module.app_critiques
}
if not export_ids:
del mod["id"]
del mod["ue_id"]
@ -167,7 +188,7 @@ def formation_export(
filename = f"scodoc_formation_{formation.departement.acronym}_{formation.acronyme or ''}_v{formation.version}"
return scu.sendResult(
F,
f_dict,
name="formation",
format=format,
force_outer_xml_tag=False,
@ -176,6 +197,50 @@ def formation_export(
)
def _formation_retreive_refcomp(f_dict: dict) -> int:
"""Recherche si on un référentiel de compétence chargé pour
cette formation: utilise comme clé (version_orebut, specialite, type_titre)
Retourne: referentiel_competence_id ou None
"""
refcomp_version_orebut = f_dict.get("refcomp_version_orebut")
refcomp_specialite = f_dict.get("refcomp_specialite")
refcomp_type_titre = f_dict.get("refcomp_type_titre")
if all((refcomp_version_orebut, refcomp_specialite, refcomp_type_titre)):
refcomp = ApcReferentielCompetences.query.filter_by(
dept_id=g.scodoc_dept_id,
type_titre=refcomp_type_titre,
specialite=refcomp_specialite,
version_orebut=refcomp_version_orebut,
).first()
if refcomp:
return refcomp.id
else:
flash(
f"Impossible de trouver le référentiel de compétence pour {refcomp_specialite} : est-il chargé ?"
)
return None
def _formation_retreive_apc_niveau(
referentiel_competence_id: int, ue_dict: dict
) -> int:
"""Recherche dans le ref. de comp. un niveau pour cette UE
utilise comme clé (libelle, annee, ordre)
"""
libelle = ue_dict.get("apc_niveau_libelle")
annee = ue_dict.get("apc_niveau_annee")
ordre = ue_dict.get("apc_niveau_ordre")
if all((libelle, annee, ordre)):
niveau = (
ApcNiveau.query.filter_by(libelle=libelle, annee=annee, ordre=ordre)
.join(ApcCompetence)
.filter_by(referentiel_id=referentiel_competence_id)
).first()
if niveau is not None:
return niveau.id
return None
def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
"""Create a formation from XML representation
(format dumped by formation_export( format='xml' ))
@ -206,47 +271,32 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
(élément 'formation' inexistant par exemple)."""
) from exc
assert D[0] == "formation"
F = D[1]
F["dept_id"] = g.scodoc_dept_id
f_dict = D[1]
f_dict["dept_id"] = g.scodoc_dept_id
# Pour les clonages, on prend le refcomp_id donné:
referentiel_competence_id = (
F.get("referentiel_competence_id") if use_local_refcomp else None
f_dict.get("referentiel_competence_id") if use_local_refcomp else None
)
# Sinon, on cherche a retrouver le ref. comp.
if referentiel_competence_id is None:
refcomp_version_orebut = F.get("refcomp_version_orebut")
refcomp_specialite = F.get("refcomp_specialite")
refcomp_type_titre = F.get("refcomp_type_titre")
if all((refcomp_version_orebut, refcomp_specialite, refcomp_type_titre)):
refcomp = ApcReferentielCompetences.query.filter_by(
dept_id=g.scodoc_dept_id,
type_titre=refcomp_type_titre,
specialite=refcomp_specialite,
version_orebut=refcomp_version_orebut,
).first()
if refcomp:
referentiel_competence_id = refcomp.id
else:
flash(
f"Impossible de trouver le référentiel de compétence pour {refcomp_specialite} : est-il chargé ?"
)
F["referentiel_competence_id"] = referentiel_competence_id
referentiel_competence_id = _formation_retreive_refcomp(f_dict)
f_dict["referentiel_competence_id"] = referentiel_competence_id
# find new version number
formations = sco_formations.formation_list(
args={
"acronyme": F["acronyme"],
"titre": F["titre"],
"dept_id": F["dept_id"],
"acronyme": f_dict["acronyme"],
"titre": f_dict["titre"],
"dept_id": f_dict["dept_id"],
}
)
if formations:
version = max(f["version"] or 0 for f in formations)
else:
version = 0
F["version"] = version + 1
f_dict["version"] = version + 1
# create formation
formation_id = sco_edit_formation.do_formation_create(F)
formation_id = sco_edit_formation.do_formation_create(f_dict)
log(f"formation {formation_id} created")
ues_old2new = {} # xml ue_id : new ue_id
@ -265,6 +315,13 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
del ue_info[1]["ue_id"]
else:
xml_ue_id = None
if referentiel_competence_id is None:
if "niveau_competence_id" in ue_info[1]:
del ue_info[1]["niveau_competence_id"]
else:
ue_info[1]["niveau_competence_id"] = _formation_retreive_apc_niveau(
referentiel_competence_id, ue_info[1]
)
ue_id = sco_edit_ue.do_ue_create(ue_info[1])
if xml_ue_id:
ues_old2new[xml_ue_id] = ue_id
@ -304,10 +361,26 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
ue_reference = int(child[1]["ue_reference"])
coef = float(child[1]["coef"])
ue_coef_dict[ue_reference] = coef
elif child[0] == "app_critiques" and (
referentiel_competence_id is not None
):
ac_code = child[1]["code"]
ac = (
ApcAppCritique.query.filter_by(code=ac_code)
.join(ApcNiveau)
.join(ApcCompetence)
.filter_by(referentiel_id=referentiel_competence_id)
).first()
if ac is not None:
module.app_critiques.append(ac)
db.session.add(module)
else:
log(f"Warning: AC {ac_code} inexistant !")
elif child[0] == "parcours":
# Si on a un référentiel de compétences,
# associe les parcours de ce module (BUT)
if referentiel_competence_id:
if referentiel_competence_id is not None:
code_parcours = child[1]["code"]
parcours = ApcParcours.query.filter_by(
code=code_parcours,

View File

@ -54,13 +54,14 @@ Solution proposée (nov 2014):
"""
import flask
from flask import request
from flask import flash, request
from flask_login import current_user
from app.models.formsemestre import FormSemestre
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import log
from app.models import UniteEns
from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_edit_matiere
@ -83,8 +84,11 @@ def external_ue_create(
acronyme="",
ue_type=sco_codes_parcours.UE_STANDARD,
ects=0.0,
):
"""Crée UE/matiere/module/evaluation puis saisie les notes"""
) -> int:
"""Crée UE/matiere/module dans la formation du formsemestre
puis un moduleimpl.
Return: moduleimpl_id
"""
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
log(f"creating external UE in {formsemestre}: {acronyme}")
@ -112,7 +116,8 @@ def external_ue_create(
"is_external": True,
},
)
ue = UniteEns.query.get(ue_id)
flash(f"UE créée (code {ue.ue_code})")
matiere_id = sco_edit_matiere.do_matiere_create(
{"ue_id": ue_id, "titre": titre or acronyme, "numero": 1}
)

View File

@ -679,9 +679,17 @@ def formation_import_xml_form():
return f"""
{ html_sco_header.sco_header(page_title="Import d'une formation") }
<h2>Import effectué !</h2>
<p><a class="stdlink" href="{
<ul>
<li><a class="stdlink" href="{
url_for("notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=formation_id
)}">Voir la formation</a></p>
)}">Voir la formation</a>
</li>
<li><a class="stdlink" href="{
url_for("notes.formation_delete", scodoc_dept=g.scodoc_dept, formation_id=formation_id
)}">Supprimer cette formation</a>
(en cas d'erreur, par exemple pour charger auparavant le référentiel de compétences)
</li>
</ul>
{ html_sco_header.sco_footer() }
"""