diff --git a/app/but/jury_but.py b/app/but/jury_but.py index f862ae34..69fefd51 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -297,10 +297,18 @@ class DecisionsProposeesAnnee(DecisionsProposees): if self.formsemestre_impair else self.formsemestre_pair.formation ) - self.niveaux_competences = ApcNiveau.niveaux_annee_de_parcours( - self.parcour, self.annee_but, formation.referentiel_competence - ).all() # non triés - "liste des niveaux de compétences associés à cette année" + ( + parcours, + niveaux_by_parcours, + ) = formation.referentiel_competence.get_niveaux_by_parcours( + self.annee_but, self.parcour + ) + self.niveaux_competences = niveaux_by_parcours["TC"] + ( + niveaux_by_parcours[self.parcour.id] if self.parcour else [] + ) + """liste non triée des niveaux de compétences associés à cette année pour cet étudiant. + = niveaux du tronc commun + niveau du parcours de l'étudiant. + """ self.decisions_rcue_by_niveau = self.compute_decisions_niveaux() "les décisions rcue associées aux niveau_id" self.dec_rcue_by_ue = self._dec_rcue_by_ue() @@ -482,7 +490,8 @@ class DecisionsProposeesAnnee(DecisionsProposees): def compute_ues_annee(self) -> list[list[UniteEns], list[UniteEns]]: """UEs à valider cette année pour cet étudiant, selon son parcours. - Ramène [ listes des UE du semestre impair, liste des UE du semestre pair ]. + Affecte self.parcour suivant l'inscription de l'étudiant et + ramène [ listes des UE du semestre impair, liste des UE du semestre pair ]. """ ues_sems = [] for (formsemestre, res) in ( @@ -685,6 +694,7 @@ class DecisionsProposeesAnnee(DecisionsProposees): ) self.recorded = True + db.session.commit() self.invalidate_formsemestre_cache() def invalidate_formsemestre_cache(self): @@ -709,7 +719,7 @@ class DecisionsProposeesAnnee(DecisionsProposees): if not dec.recorded: # rappel: le code par défaut est en tête code = dec.codes[0] if dec.codes else None - # s'il n'y a pas de code, efface + # enregistre le code jury seulement s'il n'y a pas déjà de code dec.record(code, no_overwrite=True) def erase(self, only_one_sem=False): diff --git a/app/models/but_refcomp.py b/app/models/but_refcomp.py index 38bf1711..c7330877 100644 --- a/app/models/but_refcomp.py +++ b/app/models/but_refcomp.py @@ -114,7 +114,7 @@ class ApcReferentielCompetences(db.Model, XMLModel): } def get_niveaux_by_parcours( - self, annee, parcour: "ApcParcours" = None + self, annee: int, parcour: "ApcParcours" = None ) -> tuple[list["ApcParcours"], dict]: """ Construit la liste des niveaux de compétences pour chaque parcours diff --git a/app/models/but_validations.py b/app/models/but_validations.py index 7d5802e5..298cb98b 100644 --- a/app/models/but_validations.py +++ b/app/models/but_validations.py @@ -274,7 +274,7 @@ class ApcValidationAnnee(db.Model): __tablename__ = "apc_validation_annee" # Assure unicité de la décision: - __table_args__ = (db.UniqueConstraint("etudid", "annee_scolaire"),) + __table_args__ = (db.UniqueConstraint("etudid", "annee_scolaire", "ordre"),) id = db.Column(db.Integer, primary_key=True) etudid = db.Column( db.Integer, diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 1fd88386..fb84fb02 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -15,7 +15,7 @@ from functools import cached_property import flask_sqlalchemy from flask import flash, g -from sqlalchemy import or_ +from sqlalchemy import and_, or_ from sqlalchemy.sql import text import app.scodoc.sco_utils as scu @@ -262,7 +262,7 @@ class FormSemestre(db.Model): les modules mis en place dans ce semestre. - Formations APC / BUT: les UEs de la formation qui - ont le même numéro de semestre que ce formsemestre - - sont associées à l'un des parcours de la formation (ou à aucun) + - sont associées à l'un des parcours de ce formsemestre (ou à aucun) """ if self.formation.get_parcours().APC_SAE: @@ -287,8 +287,11 @@ class FormSemestre(db.Model): return sem_ues.order_by(UniteEns.numero) def query_ues_parcours_etud(self, etudid: int) -> flask_sqlalchemy.BaseQuery: - """UE que suit l'étudiant dans ce semestre BUT + """XXX inutilisé à part pour un test unitaire => supprimer ? + UEs que suit l'étudiant dans ce semestre BUT en fonction du parcours dans lequel il est inscrit. + Si l'étudiant n'est inscrit à aucun parcours, + renvoie uniquement les UEs de tronc commun (sans parcours). Si voulez les UE d'un parcours, il est plus efficace de passer par `formation.query_ues_parcour(parcour)`. @@ -299,7 +302,13 @@ class FormSemestre(db.Model): UniteEns.niveau_competence_id == ApcNiveau.id, ApcParcoursNiveauCompetence.competence_id == ApcNiveau.competence_id, ApcParcoursNiveauCompetence.annee_parcours_id == ApcAnneeParcours.id, - ApcAnneeParcours.parcours_id == FormSemestreInscription.parcour_id, + or_( + ApcAnneeParcours.parcours_id == FormSemestreInscription.parcour_id, + and_( + FormSemestreInscription.parcour_id.is_(None), + UniteEns.parcour_id.is_(None), + ), + ), ) @cached_property diff --git a/migrations/versions/3c12f5850cff_apcvalidationannee_modifie_contrainte.py b/migrations/versions/3c12f5850cff_apcvalidationannee_modifie_contrainte.py new file mode 100644 index 00000000..69b158af --- /dev/null +++ b/migrations/versions/3c12f5850cff_apcvalidationannee_modifie_contrainte.py @@ -0,0 +1,40 @@ +"""ApcValidationAnnee: modifie contrainte + +Revision ID: 3c12f5850cff +Revises: f95656fdd3ef +Create Date: 2022-12-19 23:12:29.382528 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "3c12f5850cff" +down_revision = "f95656fdd3ef" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint( + "apc_validation_annee_etudid_annee_scolaire_key", + "apc_validation_annee", + type_="unique", + ) + op.create_unique_constraint( + None, "apc_validation_annee", ["etudid", "annee_scolaire", "ordre"] + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, "apc_validation_annee", type_="unique") + op.create_unique_constraint( + "apc_validation_annee_etudid_annee_scolaire_key", + "apc_validation_annee", + ["etudid", "annee_scolaire"], + ) + # ### end Alembic commands ### diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..a73c5d60 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + slow: marks tests as slow (deselect with '-m "not slow"') + lemans diff --git a/tests/ressources/formations/scodoc_formation_BUT_GMP_lm.xml b/tests/ressources/formations/scodoc_formation_BUT_GMP_lm.xml new file mode 100644 index 00000000..e7ec5ca8 --- /dev/null +++ b/tests/ressources/formations/scodoc_formation_BUT_GMP_lm.xml @@ -0,0 +1,680 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/unit/cursus_but_gmp_iutlm.yaml b/tests/unit/cursus_but_gmp_iutlm.yaml new file mode 100644 index 00000000..e7899733 --- /dev/null +++ b/tests/unit/cursus_but_gmp_iutlm.yaml @@ -0,0 +1,421 @@ +# Tests unitaires jury BUT - IUTLM GMP +# Essais avec un BUT GMP, 4 UE + 1 bonus et deux parcours sur S3 S4 +# Contrib Martin M. + +ReferentielCompetences: + filename: but-GMP-05012022-081650.xml + specialite: GMP + +Formation: + filename: scodoc_formation_BUT_GMP_lm.xml + # Association des UE aux compétences: + ues: + # S1 : Tronc commun GMP + 'UE1.1-C1': + annee: BUT1 + competence: Spécifier + 'UE1.2-C2': + annee: BUT1 + competence: Développer + 'UE1.3-C3': + annee: BUT1 + competence: Réaliser + 'UE1.4-C4': + annee: BUT1 + competence: Exploiter + + # S2 : Tronc commun GMP + 'UE2.1-C1': + annee: BUT1 + competence: Spécifier + 'UE2.2-C2': + annee: BUT1 + competence: Développer + 'UE2.3-C3': + annee: BUT1 + competence: Réaliser + 'UE2.4-C4': + annee: BUT1 + competence: Exploiter + + # S3 : Tronc commun GMP + 'UE3.1-C1': + annee: BUT2 + competence: Spécifier + 'UE3.2-C2': + annee: BUT2 + competence: Développer + 'UE3.3-C3': + annee: BUT2 + competence: Réaliser + 'UE3.4-C4': + annee: BUT2 + competence: Exploiter + # S3 : Parcours II + 'UE3.5.IPI': + annee: BUT2 + competence: Innover + parcours: II + # S3 : Parcour SNRV + 'UE3.5.SNRV': + annee: BUT2 + competence: Virtualiser + parcours: SNRV + + # S4 : Tronc commun GMP + 'UE4.1-C1': + annee: BUT2 + competence: Spécifier + 'UE4.2-C2': + annee: BUT2 + competence: Développer + 'UE4.3-C3': + annee: BUT2 + competence: Réaliser + 'UE4.4-C4': + annee: BUT2 + competence: Exploiter + # S4 : Parcours II + 'UE4.5.II': + annee: BUT2 + competence: Innover + parcours: II + # S4 : Parcour SNRV + 'UE4.5.SNRV': + annee: BUT2 + competence: Virtualiser + parcours: SNRV + + modules_parcours: + # cette section permet d'associer des modules à des parcours + # les codes modules peuvent être des regexp + II: [ .*II.* ] + SNRV: [ .*SNRV.* ] + +FormSemestres: + # S1 et S2 : + S1 : + idx: 1 + date_debut: 2022-09-01 + date_fin: 2023-01-15 + S2 : + idx: 2 + date_debut: 2023-01-16 + date_fin: 2023-06-30 + # S3 avec les deux parcours réunis: + S3: + idx: 3 + date_debut: 2023-09-01 + date_fin: 2024-01-13 + codes_parcours: ['II', 'SNRV'] + + +Etudiants: + gmp01: + prenom: etugmp01 + civilite: M + formsemestres: + S1: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE1.1": 11.8 + "SAE1.2": 14.30 + "SAE1.3": 14.45 + "SAE1.4": 9.6 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: False + nb_competences: 4 + nb_rcue_annee: 0 + decisions_ues: + "UE1.1-C1": + codes: [ "ADM", "..." ] + moy_ue: 11.8 + "UE1.2-C2": + codes: [ "ADM", "..." ] + moy_ue: 14.30 + "UE1.3-C3": + codes: [ "ADM", "..." ] + moy_ue: 14.45 + "UE1.4-C4": + codes: [ "AJ", "..." ] + moy_ue: 9.6 + + S2: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE2.01": 10.08 + "SAE2.02": 07.14 + "SAE2.03": 10.67 + "SAE2.04": 08.55 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: True + nb_competences: 4 + nb_rcue_annee: 4 + valide_moitie_rcue: True + codes: [ "PASD", "..." ] + decisions_ues: + "UE2.1-C1": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 10.08 + "UE2.2-C2": + codes: [ "CMP", "..." ] + code_valide: CMP + moy_ue: 07.14 + "UE2.3-C3": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 10.67 + "UE2.4-C4": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 08.55 + decisions_rcues: # on repère ici les RCUE par l'acronyme de leur 1ere UE (donc du S1) + "UE1.1-C1": + code_valide: ADM + rcue: + moy_rcue: 10.94 + est_compensable: False + "UE1.2-C2": + code_valide: CMP + rcue: + moy_rcue: 10.72 + est_compensable: True + "UE1.3-C3": + code_valide: ADM + rcue: + moy_rcue: 12.56 + est_compensable: False + "UE1.4-C4": + code_valide: AJ + rcue: + moy_rcue: 9.075 + est_compensable: False + + + + S3: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "S3.01": 9 + "S3.SNRV.02": 12.5 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: False + nb_competences: 4 # et non 5 car pas inscrit à un parcours + nb_rcue_annee: 0 + decisions_ues: + "UE3.1-C1": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9 + "UE3.2-C2": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9 + "UE3.3-C3": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9 + "UE3.4-C4": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9 + # "UE3.5.SNRV": + # codes: [ "ADM", "..." ] + # code_valide: ADM + # moy_ue: 12.5 + + gmp02: + prenom: etugmp02 + civilite: F + formsemestres: + S1: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE1.1": 14.5 + "SAE1.2": 13.2 + "SAE1.3": 9.5 + "SAE1.4": 8.7 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: False + nb_competences: 4 + nb_rcue_annee: 0 + decisions_ues: + "UE1.1-C1": + codes: [ "ADM", "..." ] + moy_ue: 14.5 + "UE1.2-C2": + codes: [ "ADM", "..." ] + moy_ue: 13.2 + "UE1.3-C3": + codes: [ "AJ", "..." ] + moy_ue: 9.5 + "UE1.4-C4": + codes: [ "AJ", "..." ] + moy_ue: 8.7 + + S2: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE2.01": 14.4 + "SAE2.02": 17.8 + "SAE2.03": 11.2 + "SAE2.04": 9.2 + attendu: # les codes jury que l'on doit vérifier + deca: + #passage_de_droit: true + nb_competences: 4 + nb_rcue_annee: 4 + #res_pair: None + valide_moitie_rcue: true + codes: [ "PASD", "..." ] + decisions_ues: + "UE2.1-C1": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 14.4 + "UE2.2-C2": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 17.8 + "UE2.3-C3": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 11.2 + "UE2.4-C4": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9.2 + decisions_rcues: # on repère ici les RCUE par l'acronyme de leur 1ere UE + "UE1.1-C1": + code_valide: ADM + rcue: + moy_rcue: 14.45 + est_compensable: False + "UE1.2-C2": + code_valide: ADM + rcue: + moy_rcue: 15.5 + est_compensable: False + "UE1.3-C3": + code_valide: CMP + rcue: + moy_rcue: 10.35 + est_compensable: True + "UE1.4-C4": + code_valide: AJ + rcue: + moy_rcue: 8.95 + est_compensable: False + + + + S3: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "S3.01": 12 + "S3.SNRV.02": 14 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: False + nb_competences: 4 # et non 5 car pas inscrit à un parcours + nb_rcue_annee: 0 + decisions_ues: + "UE3.1-C1": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 12 + "UE3.2-C2": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 12 + "UE3.3-C3": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 12 + "UE3.4-C4": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 12 + # "UE3.5.SNRV": + # codes: [ "ADM", "..." ] + # code_valide: ADM + # moy_ue: 14 + + gmp03: + prenom: etugmp03 + civilite: X + formsemestres: + S1: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE1.1": 12.7 + "SAE1.2": 8.4 + "SAE1.3": 10.1 + "SAE1.4": 9.8 + attendu: # les codes jury que l'on doit vérifier + deca: + passage_de_droit: False + nb_competences: 4 + nb_rcue_annee: 0 + decisions_ues: + "UE1.1-C1": + codes: [ "ADM", "..." ] + moy_ue: 12.7 + "UE1.2-C2": + codes: [ "AJ", "..." ] + moy_ue: 8.4 + "UE1.3-C3": + codes: [ "ADM", "..." ] + moy_ue: 10.1 + "UE1.4-C4": + codes: [ "AJ", "..." ] + moy_ue: 9.8 + + S2: + notes_modules: # on joue avec les SAE seulement car elles sont "diagonales" + "SAE2.01": 10.2 + "SAE2.02": 9.6 + "SAE2.03": 14.3 + "SAE2.04": 8.4 + attendu: # les codes jury que l'on doit vérifier + deca: + nb_competences: 4 # et non 5 car pas inscrit à un parcours + nb_rcue_annee: 4 + valide_moitie_rcue: false + codes: [ "RED", "..." ] + decisions_ues: + "UE2.1-C1": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 10.2 + "UE2.2-C2": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 9.6 + "UE2.3-C3": + codes: [ "ADM", "..." ] + code_valide: ADM + moy_ue: 14.3 + "UE2.4-C4": + codes: [ "AJ", "..." ] + code_valide: AJ + moy_ue: 8.4 + decisions_rcues: # on repère ici les RCUE par l'acronyme de leur 1ere UE (du S1 donc) + "UE1.1-C1": + code_valide: ADM + rcue: + moy_rcue: 11.45 + est_compensable: False + "UE1.2-C2": + code_valide: AJ + rcue: + moy_rcue: 9 + est_compensable: False + "UE1.3-C3": + code_valide: ADM + rcue: + moy_rcue: 12.2 + est_compensable: False + "UE1.4-C4": + code_valide: AJ + rcue: + moy_rcue: 9.1 + est_compensable: False \ No newline at end of file diff --git a/tests/unit/test_but_jury.py b/tests/unit/test_but_jury.py index 47cce49c..b52a432a 100644 --- a/tests/unit/test_but_jury.py +++ b/tests/unit/test_but_jury.py @@ -1,6 +1,7 @@ """ Test jury BUT avec parcours """ +import pytest from tests.unit import yaml_setup import app @@ -18,6 +19,7 @@ from config import TestConfig DEPT = TestConfig.DEPT_TEST +@pytest.mark.slow def test_but_jury_GB(test_client): """Tests sur un cursus GB - construction des semestres et de leurs étudianst à partir du yaml @@ -49,6 +51,29 @@ def test_but_jury_GB(test_client): # _test_but_jury(S1_redoublant, doc) +@pytest.mark.slow +@pytest.mark.lemans +def test_but_jury_GMP_lm(test_client): + """Tests sur un cursus GMP fournit par Le Mans""" + app.set_sco_dept(DEPT) + # Construit la base de test GB une seule fois + # puis lance les tests de jury + doc = yaml_setup.setup_from_yaml("tests/unit/cursus_but_gmp_iutlm.yaml") + + formsemestres = FormSemestre.query.order_by(FormSemestre.semestre_id).all() + # Vérifie les deca de tous les semestres: + for formsemestre in formsemestres: + _check_deca(formsemestre) + + # Saisie de toutes les décisions de jury + for formsemestre in formsemestres: + formsemestre_validation_auto_but(formsemestre, only_adm=False) + + # Vérifie résultats attendus: + for formsemestre in formsemestres: + _test_but_jury(formsemestre, doc) + + def _check_deca(formsemestre: FormSemestre, etud: Identite = None): """vérifie les champs principaux de l'instance de DecisionsProposeesAnnee""" etud = etud or formsemestre.etuds.first() @@ -68,7 +93,9 @@ def _check_deca(formsemestre: FormSemestre, etud: Identite = None): assert deca.rcues_annee == [] # S1, pas de RCUEs assert deca.inscription_etat == scu.INSCRIT assert deca.inscription_etat_impair == scu.INSCRIT - assert deca.parcour == formsemestre.parcours[0] # un seul parcours dans ce sem. + assert (deca.parcour is None) or ( + deca.parcour.id in {p.id for p in formsemestre.parcours} + ) nb_ues = ( len(deca.formsemestre_pair.query_ues_parcours_etud(etud.id).all()) diff --git a/tests/unit/yaml_setup.py b/tests/unit/yaml_setup.py index 6812c41e..18c922aa 100644 --- a/tests/unit/yaml_setup.py +++ b/tests/unit/yaml_setup.py @@ -249,7 +249,7 @@ def setup_formsemestres(formation: Formation, doc: str): """Création des formsemestres pour tester les parcours BUT""" for titre, infos in doc["FormSemestres"].items(): parcours = [] - for code_parcour in infos["codes_parcours"]: + for code_parcour in infos.get("codes_parcours", []): parcour = formation.referentiel_competence.parcours.filter_by( code=code_parcour ).first() @@ -274,8 +274,8 @@ def inscrit_les_etudiants(formation: Formation, doc: dict): etud = Identite.create_etud( dept_id=g.scodoc_dept_id, nom=nom, - prenom=infos["prenom"], - civilite=infos["civilite"], + prenom=infos.get("prenom", "prénom"), + civilite=infos.get("civilite", "X"), ) db.session.add(etud) db.session.commit() @@ -288,14 +288,14 @@ def inscrit_les_etudiants(formation: Formation, doc: dict): partition_parcours = formsemestre.partitions.filter_by( partition_name=scu.PARTITION_PARCOURS ).first() - if partition_parcours is None: - group_ids = [] - else: + if partition_parcours is not None and "parcours" in sem_infos: group = partition_parcours.groups.filter_by( group_name=sem_infos["parcours"] ).first() assert group is not None # le groupe de parcours doit exister group_ids = [group.id] + else: + group_ids = [] sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( formsemestre.id, etud.id, @@ -379,7 +379,10 @@ def _check_decisions_rcues( # Descend dans le RCUE: if "rcue" in dec_rcue_att: if "moy_rcue" in dec_rcue_att["rcue"]: - assert dec_rcue.rcue.moy_rcue == dec_rcue_att["rcue"]["moy_rcue"] + assert ( + abs(dec_rcue.rcue.moy_rcue - dec_rcue_att["rcue"]["moy_rcue"]) + < scu.NOTES_PRECISION + ) if "est_compensable" in dec_rcue_att["rcue"]: assert ( dec_rcue.rcue.est_compensable()