Compare commits
3 Commits
8ec0171ca0
...
bd9bf87112
Author | SHA1 | Date |
---|---|---|
Emmanuel Viennet | bd9bf87112 | |
Emmanuel Viennet | a0e2af481f | |
Emmanuel Viennet | 42e8f97441 |
|
@ -0,0 +1,134 @@
|
|||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""Code expérimental: si deux référentiel sont presques identiques
|
||||
(mêmes compétences, niveaux, parcours)
|
||||
essaie de changer une formation de référentiel.
|
||||
"""
|
||||
|
||||
from app import clear_scodoc_cache, db
|
||||
|
||||
from app.models import (
|
||||
ApcParcours,
|
||||
ApcReferentielCompetences,
|
||||
ApcValidationRCUE,
|
||||
Formation,
|
||||
FormSemestreInscription,
|
||||
Module,
|
||||
UniteEns,
|
||||
)
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def map_referentiels(
|
||||
ref1: ApcReferentielCompetences, ref2: ApcReferentielCompetences
|
||||
) -> str | tuple[dict[int, int], dict[int, int], dict[int, int]]:
|
||||
"""Build mapping between two referentiels"""
|
||||
if ref1.type_structure != ref2.type_structure:
|
||||
return "type_structure mismatch"
|
||||
if ref1.type_departement != ref2.type_departement:
|
||||
return "type_departement mismatch"
|
||||
# mêmes parcours ?
|
||||
parcours_by_code_1 = {p.code: p for p in ref1.parcours}
|
||||
parcours_by_code_2 = {p.code: p for p in ref2.parcours}
|
||||
if parcours_by_code_1.keys() != parcours_by_code_2.keys():
|
||||
return "parcours mismatch"
|
||||
parcours_map = {
|
||||
parcours_by_code_1[code].id: parcours_by_code_2[code].id
|
||||
for code in parcours_by_code_1
|
||||
}
|
||||
# mêmes compétences ?
|
||||
competence_by_code_1 = {c.titre: c for c in ref1.competences}
|
||||
competence_by_code_2 = {c.titre: c for c in ref2.competences}
|
||||
if competence_by_code_1.keys() != competence_by_code_2.keys():
|
||||
return "competences mismatch"
|
||||
competences_map = {
|
||||
competence_by_code_1[titre].id: competence_by_code_2[titre].id
|
||||
for titre in competence_by_code_1
|
||||
}
|
||||
# mêmes niveaux (dans chaque compétence) ?
|
||||
niveaux_map = {}
|
||||
for titre in competence_by_code_1:
|
||||
c1 = competence_by_code_1[titre]
|
||||
c2 = competence_by_code_2[titre]
|
||||
niveau_by_attr_1 = {(n.annee, n.ordre, n.libelle): n for n in c1.niveaux}
|
||||
niveau_by_attr_2 = {(n.annee, n.ordre, n.libelle): n for n in c2.niveaux}
|
||||
if niveau_by_attr_1.keys() != niveau_by_attr_2.keys():
|
||||
return f"niveaux mismatch in comp. '{titre}'"
|
||||
niveaux_map.update(
|
||||
{niveau_by_attr_1[a].id: niveau_by_attr_2[a].id for a in niveau_by_attr_1}
|
||||
)
|
||||
return parcours_map, competences_map, niveaux_map
|
||||
|
||||
|
||||
def formation_change_referentiel(
|
||||
formation: Formation, new_ref: ApcReferentielCompetences
|
||||
):
|
||||
"""Try to change ref."""
|
||||
if not formation.referentiel_competence:
|
||||
raise ScoValueError("formation non associée à un référentiel")
|
||||
if not isinstance(new_ref, ApcReferentielCompetences):
|
||||
raise ScoValueError("nouveau référentiel invalide")
|
||||
|
||||
r = map_referentiels(formation.referentiel_competence, new_ref)
|
||||
if isinstance(r, str):
|
||||
raise ScoValueError(f"référentiels incompatibles: {r}")
|
||||
parcours_map, competences_map, niveaux_map = r
|
||||
|
||||
formation.referentiel_competence = new_ref
|
||||
db.session.add(formation)
|
||||
# UEs - Niveaux et UEs - parcours
|
||||
for ue in formation.ues:
|
||||
if ue.niveau_competence:
|
||||
ue.niveau_competence_id = niveaux_map[ue.niveau_competence_id]
|
||||
db.session.add(ue)
|
||||
if ue.parcours:
|
||||
new_list = [ApcParcours.query.get(parcours_map[p.id]) for p in ue.parcours]
|
||||
ue.parcours.clear()
|
||||
ue.parcours.extend(new_list)
|
||||
db.session.add(ue)
|
||||
# Modules / parcours et app_critiques
|
||||
for module in formation.modules:
|
||||
if module.parcours:
|
||||
new_list = [
|
||||
ApcParcours.query.get(parcours_map[p.id]) for p in module.parcours
|
||||
]
|
||||
module.parcours.clear()
|
||||
module.parcours.extend(new_list)
|
||||
db.session.add(module)
|
||||
if module.app_critiques: # efface les apprentissages critiques
|
||||
module.app_critiques.clear()
|
||||
db.session.add(module)
|
||||
# ApcValidationRCUE
|
||||
for valid_rcue in ApcValidationRCUE.query.join(
|
||||
UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id
|
||||
).filter_by(formation_id=formation.id):
|
||||
if valid_rcue.parcour:
|
||||
valid_rcue.parcour_id = parcours_map[valid_rcue.parcour.id]
|
||||
db.session.add(valid_rcue)
|
||||
for valid_rcue in ApcValidationRCUE.query.join(
|
||||
UniteEns, UniteEns.id == ApcValidationRCUE.ue2_id
|
||||
).filter_by(formation_id=formation.id):
|
||||
if valid_rcue.parcour:
|
||||
valid_rcue.parcour_id = parcours_map[valid_rcue.parcour.id]
|
||||
db.session.add(valid_rcue)
|
||||
# FormSemestre / parcours_formsemestre
|
||||
for formsemestre in formation.formsemestres:
|
||||
new_list = [
|
||||
ApcParcours.query.get(parcours_map[p.id]) for p in formsemestre.parcours
|
||||
]
|
||||
formsemestre.parcours.clear()
|
||||
formsemestre.parcours.extend(new_list)
|
||||
db.session.add(formsemestre)
|
||||
# FormSemestreInscription.parcour_id
|
||||
for inscr in FormSemestreInscription.query.filter_by(
|
||||
formsemestre_id=formsemestre.id
|
||||
).filter(FormSemestreInscription.parcour_id != None):
|
||||
if inscr.parcour_id is not None:
|
||||
inscr.parcour_id = parcours_map[inscr.parcour_id]
|
||||
#
|
||||
db.session.commit()
|
||||
clear_scodoc_cache()
|
|
@ -62,7 +62,7 @@ from flask import g
|
|||
import app.scodoc.sco_utils as scu
|
||||
from config import Config
|
||||
from app import log
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
||||
|
||||
|
||||
class BaseArchiver:
|
||||
|
|
|
@ -148,7 +148,7 @@ def _convert_formsemestres_to_dicts(
|
|||
),
|
||||
"formsemestre_id": formsemestre.id,
|
||||
"groupicon": groupicon if nb_inscrits > 0 else emptygroupicon,
|
||||
"lockimg": lockicon,
|
||||
"lockimg": "" if formsemestre.etat else lockicon,
|
||||
"modalite": formsemestre.modalite,
|
||||
"mois_debut": formsemestre.mois_debut(),
|
||||
"mois_fin": formsemestre.mois_fin(),
|
||||
|
|
|
@ -489,9 +489,10 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||
return formation.id, modules_old2new, ues_old2new
|
||||
|
||||
|
||||
def formation_list_table() -> GenTable:
|
||||
def formation_list_table(detail: bool) -> GenTable:
|
||||
"""List formation, grouped by titre and sorted by versions
|
||||
and listing associated semestres
|
||||
and listing associated semestres.
|
||||
If detail, add column with more details.
|
||||
returns a table
|
||||
"""
|
||||
formations: list[Formation] = Formation.query.filter_by(dept_id=g.scodoc_dept_id)
|
||||
|
@ -534,6 +535,15 @@ def formation_list_table() -> GenTable:
|
|||
if formation.referentiel_competence
|
||||
else ""
|
||||
),
|
||||
"_referentiel_target": (
|
||||
url_for(
|
||||
"notes.refcomp_show",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
refcomp_id=formation.referentiel_competence.id,
|
||||
)
|
||||
if formation.referentiel_competence
|
||||
else ""
|
||||
),
|
||||
}
|
||||
# Ajoute les semestres associés à chaque formation:
|
||||
row["formsemestres"] = formation.formsemestres.order_by(
|
||||
|
@ -561,10 +571,15 @@ def formation_list_table() -> GenTable:
|
|||
else []
|
||||
)
|
||||
)
|
||||
# Répartition des UEs dans les semestres
|
||||
# utilise pour voir si la formation couvre tous les semestres
|
||||
row["semestres_ues"] = ", ".join(
|
||||
"S" + str(x if (x is not None and x > 0) else "-")
|
||||
for x in sorted({ue.semestre_idx for ue in formation.ues})
|
||||
)
|
||||
# Date surtout utilisées pour le tri:
|
||||
if row["formsemestres"]:
|
||||
row["date_fin_dernier_sem"] = (
|
||||
row["formsemestres"][-1].date_fin.isoformat(),
|
||||
)
|
||||
row["date_fin_dernier_sem"] = row["formsemestres"][-1].date_fin.isoformat()
|
||||
row["annee_dernier_sem"] = row["formsemestres"][-1].date_fin.year
|
||||
else:
|
||||
row["date_fin_dernier_sem"] = ""
|
||||
|
@ -617,6 +632,8 @@ def formation_list_table() -> GenTable:
|
|||
"commentaire",
|
||||
"sems_list_txt",
|
||||
)
|
||||
if detail:
|
||||
columns_ids += ("annee_dernier_sem", "semestres_ues")
|
||||
titles = {
|
||||
"buttons": "",
|
||||
"commentaire": "Commentaire",
|
||||
|
@ -627,6 +644,9 @@ def formation_list_table() -> GenTable:
|
|||
"formation_code": "Code",
|
||||
"sems_list_txt": "Semestres",
|
||||
"referentiel": "Réf.",
|
||||
"date_fin_dernier_sem": "Fin dernier sem.",
|
||||
"annee_dernier_sem": "Année dernier sem.",
|
||||
"semestres_ues": "Semestres avec UEs",
|
||||
}
|
||||
return GenTable(
|
||||
columns_ids=columns_ids,
|
||||
|
@ -639,7 +659,7 @@ def formation_list_table() -> GenTable:
|
|||
html_class="formation_list_table table_leftalign",
|
||||
html_with_td_classes=True,
|
||||
html_sortable=True,
|
||||
base_url=f"{request.base_url}",
|
||||
base_url=f"{request.base_url}" + ("?detail=on" if detail else ""),
|
||||
page_title=title,
|
||||
pdf_title=title,
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
|
|
|
@ -2411,10 +2411,10 @@ li.notes_formation_list {
|
|||
padding-top: 10px;
|
||||
}
|
||||
|
||||
table.formation_list_table {
|
||||
width: 100%;
|
||||
table.dataTable.formation_list_table.gt_table {
|
||||
border-collapse: collapse;
|
||||
background-color: rgb(0%, 90%, 90%);
|
||||
margin-right: 12px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
table#formation_list_table tr.gt_hl {
|
||||
|
@ -2455,8 +2455,8 @@ table.formation_list_table td.buttons span.but_placeholder {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.formation_list_table td.titre {
|
||||
width: 45%;
|
||||
.formation_list_table td.sems_list_txt {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.formation_list_table td.commentaire {
|
||||
|
|
|
@ -691,15 +691,23 @@ def module_clone():
|
|||
def index_html():
|
||||
"Page accueil formations"
|
||||
fmt = request.args.get("fmt", "html")
|
||||
detail = scu.to_bool(request.args.get("detail", False))
|
||||
|
||||
editable = current_user.has_permission(Permission.EditFormation)
|
||||
table = sco_formations.formation_list_table()
|
||||
table = sco_formations.formation_list_table(detail=detail)
|
||||
|
||||
if fmt != "html":
|
||||
return table.make_page(fmt=fmt, filename=f"Formations-{g.scodoc_dept}")
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(page_title="Formations (programmes)"),
|
||||
"""<h2>Formations (programmes pédagogiques)</h2>
|
||||
f"""<h2>Formations (programmes pédagogiques)</h2>
|
||||
<form>
|
||||
<input type="checkbox" id="detailCheckbox" name="detail"
|
||||
onchange="this.form.submit();"
|
||||
{'checked' if detail else ''}>
|
||||
<label for="detailCheckbox">Informations détaillées</label>
|
||||
</form>
|
||||
""",
|
||||
table.html(),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue