From 34aab0a46fa2ae8841ae9c16ac877820d999c4ae Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 26 Jun 2024 21:26:51 +0200 Subject: [PATCH] =?UTF-8?q?Element=20de=20passage=20dans=20apog=C3=A9e.=20?= =?UTF-8?q?Close=20#937?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_apogee_csv.py | 39 ++++++++++++++++++++++++++++----- app/scodoc/sco_apogee_reader.py | 7 +++++- app/scodoc/sco_exceptions.py | 27 ++++++++++++----------- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py index c56f497f..f2dba69c 100644 --- a/app/scodoc/sco_apogee_csv.py +++ b/app/scodoc/sco_apogee_csv.py @@ -221,7 +221,8 @@ class ApoEtud(dict): except KeyError as exc: raise ScoFormatError( f"""Fichier Apogee invalide : ligne mal formatée ?
colonne { - col_id} non déclarée ?""" + col_id} non déclarée ?""", + safe=True, ) from exc else: try: @@ -326,9 +327,14 @@ class ApoEtud(dict): self.log.append("export étape désactivé") return VOID_APO_RES + # Element passage + res_passage = self.search_elt_passage(code, res) + if res_passage: + return res_passage + # Elements UE res_ue = self.search_elt_ue(code, res) - if res_ue != {}: + if res_ue: return res_ue # Elements Modules @@ -403,6 +409,25 @@ class ApoEtud(dict): return VOID_APO_RES return {} # no UE result found for this code + def search_elt_passage(self, code: str, res: NotesTableCompat) -> dict: + """Cherche un résultat de type "passage" pour ce code Apogée. + dict vide si pas de résultat trouvé pour ce code. + L'élement est rempli si: + - code est dans les codes passage du formsemestre (sem) + - autorisation d'inscription enregistre de sem vers sem d'indice suivant + """ + if res.formsemestre.semestre_id < 1: + return {} + next_semestre_id = res.formsemestre.semestre_id + 1 + if code in res.formsemestre.get_codes_apogee(category="passage"): + if next_semestre_id in res.get_autorisations_inscription().get( + self.etud.id, set() + ): + return dict( + N="", B=20, J="", R=ScoDocSiteConfig.get_code_apo("ADM"), M="" + ) + return {} + def comp_elt_semestre(self, nt: NotesTableCompat, decision: dict, etudid: int): """Calcul résultat apo semestre. Toujours vide pour en BUT/APC. @@ -703,7 +728,8 @@ class ApoData: filename = self.orig_filename or e.filename raise ScoFormatError( f"""

Erreur lecture du fichier Apogée {filename}

-

{e.args[0]}

""" +

{e.args[0]}

""", + safe=True, ) from e self.etape_apogee = self.get_etape_apogee() # 'V1RT' self.vdi_apogee = self.get_vdi_apogee() # '111' @@ -795,7 +821,9 @@ class ApoData: self.sems_periode = None def get_etape_apogee(self) -> str: - """Le code etape: 'V1RT', donné par le code de l'élément VET""" + """Le code etape: 'V1RT', donné par le code de l'élément VET. + Le VET doit être parmi les colonnes de la section XX-APO_COLONNES-XX + """ for elt in self.apo_csv.apo_elts.values(): if elt.type_objet == "VET": return elt.code @@ -860,7 +888,8 @@ class ApoData: log(f"Colonnes presentes: {present}") raise ScoFormatError( f"""Fichier Apogee invalide
Colonnes declarees: {declared} -
Colonnes presentes: {present}""" +
Colonnes presentes: {present}""", + safe=True, ) from exc # l'ensemble de tous les codes des elements apo des semestres: sem_elems = reduce(set.union, list(self.get_codes_by_sem().values()), set()) diff --git a/app/scodoc/sco_apogee_reader.py b/app/scodoc/sco_apogee_reader.py index 44ab7fa6..32c7f872 100644 --- a/app/scodoc/sco_apogee_reader.py +++ b/app/scodoc/sco_apogee_reader.py @@ -299,11 +299,14 @@ class ApoCSVReadWrite: for i, field in enumerate(fields): cols[self.col_ids[i]] = field except IndexError as exc: - raise raise ScoFormatError( f"Fichier Apogee incorrect (colonnes excédentaires ? ({i}/{field}))", filename=self.get_filename(), + safe=True, ) from exc + # Ajoute colonnes vides manquantes, pratique si on a édité le fichier Apo à la main... + for i in range(len(fields), len(self.col_ids)): + cols[self.col_ids[i]] = "" etud_tuples.append( ApoEtudTuple( nip=fields[0], # id etudiant @@ -337,6 +340,8 @@ class ApoCSVReadWrite: fields = line.split(APO_SEP) if len(fields) == 2: k, v = fields + elif len(fields) == 1: + k, v = fields[0], "" else: log(f"Error read CSV: \nline={line}\nfields={fields}") log(dir(f)) diff --git a/app/scodoc/sco_exceptions.py b/app/scodoc/sco_exceptions.py index 2e61608c..53b1711c 100644 --- a/app/scodoc/sco_exceptions.py +++ b/app/scodoc/sco_exceptions.py @@ -61,12 +61,12 @@ class ScoValueError(ScoException): class ScoPermissionDenied(ScoValueError): """Permission non accordée (appli web)""" - def __init__(self, msg=None, dest_url=None): + def __init__(self, msg=None, dest_url=None, safe=False): if msg is None: msg = f"""Opération non autorisée pour { current_user.get_nomcomplet() if current_user else "?" }. Pas la permission, ou objet verrouillé.""" - super().__init__(msg, dest_url=dest_url) + super().__init__(msg, dest_url=dest_url, safe=safe) class ScoBugCatcher(ScoException): @@ -84,8 +84,8 @@ class InvalidEtudId(NoteProcessError): class ScoFormatError(ScoValueError): "Erreur lecture d'un fichier fourni par l'utilisateur" - def __init__(self, msg, filename="", dest_url=None): - super().__init__(msg, dest_url=dest_url) + def __init__(self, msg, filename="", dest_url=None, safe=False): + super().__init__(msg, dest_url=dest_url, safe=safe) self.filename = filename @@ -95,15 +95,15 @@ class ScoInvalidParamError(ScoValueError): (id strings, ...) """ - def __init__(self, msg=None, dest_url=None): + def __init__(self, msg=None, dest_url=None, safe=False): msg = msg or "Adresse invalide. Vérifiez vos signets." - super().__init__(msg, dest_url=dest_url) + super().__init__(msg, dest_url=dest_url, safe=safe) class ScoPDFFormatError(ScoValueError): "erreur génération PDF (templates platypus, ...)" - def __init__(self, msg, dest_url=None): + def __init__(self, msg, dest_url=None, safe=False): super().__init__( f"""Erreur dans un format pdf:

{msg}

@@ -112,6 +112,7 @@ class ScoPDFFormatError(ScoValueError):

""", dest_url=dest_url, + safe=safe, ) @@ -130,33 +131,33 @@ class ScoConfigurationError(ScoValueError): class ScoLockedFormError(ScoValueError): "Modification d'une formation verrouillée" - def __init__(self, msg="", dest_url=None): + def __init__(self, msg="", dest_url=None, safe=False): msg = ( "Cette formation est verrouillée (car il y a un semestre verrouillé qui s'y réfère). " + str(msg) ) - super().__init__(msg=msg, dest_url=dest_url) + super().__init__(msg=msg, dest_url=dest_url, safe=safe) class ScoLockedSemError(ScoValueError): "Modification d'un formsemestre verrouillé" - def __init__(self, msg="", dest_url=None): + def __init__(self, msg="", dest_url=None, safe=False): msg = "Ce semestre est verrouillé ! " + str(msg) - super().__init__(msg=msg, dest_url=dest_url) + super().__init__(msg=msg, dest_url=dest_url, safe=safe) class ScoNonEmptyFormationObject(ScoValueError): """On ne peut pas supprimer un module/matiere ou UE si des formsemestre s'y réfèrent""" - def __init__(self, type_objet="objet'", msg="", dest_url=None): + def __init__(self, type_objet="objet'", msg="", dest_url=None, safe=False): msg = f"""

{type_objet} "{msg}" utilisé(e) dans des semestres: suppression impossible.

Il faut d'abord supprimer le semestre (ou en retirer ce {type_objet}). Mais il est peut-être préférable de laisser ce programme intact et d'en créer une nouvelle version pour la modifier sans affecter les semestres déjà en place.

""" - super().__init__(msg=msg, dest_url=dest_url) + super().__init__(msg=msg, dest_url=dest_url, safe=safe) class ScoInvalidIdType(ScoValueError):