diff --git a/app/but/change_refcomp.py b/app/but/change_refcomp.py new file mode 100644 index 00000000..22efb30f --- /dev/null +++ b/app/but/change_refcomp.py @@ -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()