forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -776,8 +776,10 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
# UEs
|
||||
for dec_ue in self.decisions_ues.values():
|
||||
if (
|
||||
not dec_ue.recorded
|
||||
) and dec_ue.formsemestre.annee_scolaire() == annee_scolaire:
|
||||
dec_ue.formsemestre
|
||||
and (not dec_ue.recorded)
|
||||
and dec_ue.formsemestre.annee_scolaire() == annee_scolaire
|
||||
):
|
||||
# rappel: le code par défaut est en tête
|
||||
code = dec_ue.codes[0] if dec_ue.codes else None
|
||||
if (not only_validantes) or code in sco_codes.CODES_UE_VALIDES_DE_DROIT:
|
||||
@ -1457,7 +1459,12 @@ class DecisionsProposeesUE(DecisionsProposees):
|
||||
) or self.formsemestre.modalite == "EXT":
|
||||
self.codes.insert(0, sco_codes.ADM)
|
||||
self.explanation = f"Moyenne >= {sco_codes.CursusBUT.BARRE_MOY}/20"
|
||||
elif self.rcue and self.rcue.est_compensable():
|
||||
elif (
|
||||
self.rcue
|
||||
and self.rcue.est_compensable()
|
||||
and self.ue_status
|
||||
and not self.ue_status["is_capitalized"]
|
||||
):
|
||||
self.codes.insert(0, sco_codes.CMP)
|
||||
self.explanation = "compensable dans le RCUE"
|
||||
else:
|
||||
|
@ -1090,7 +1090,7 @@ Etudiants:
|
||||
"S1.2": 12.0000
|
||||
attendu: # les codes jury que l'on doit vérifier
|
||||
deca:
|
||||
passage_de_droit: False
|
||||
passage_de_droit: True
|
||||
nb_competences: 2
|
||||
nb_rcue_annee: 0
|
||||
decisions_ues:
|
||||
|
@ -30,6 +30,26 @@ from config import TestConfig
|
||||
DEPT = TestConfig.DEPT_TEST
|
||||
|
||||
|
||||
def setup_and_test_jurys(yaml_filename: str):
|
||||
"Charge YAML et lance test jury BUT"
|
||||
app.set_sco_dept(DEPT)
|
||||
# Construit la base de test GB une seule fois
|
||||
# puis lance les tests de jury
|
||||
doc, formation, formsemestre_titres = yaml_setup.setup_from_yaml(yaml_filename)
|
||||
|
||||
for formsemestre_titre in formsemestre_titres:
|
||||
formsemestre = yaml_setup.create_formsemestre_with_etuds(
|
||||
doc, formation, formsemestre_titre
|
||||
)
|
||||
# Vérifie les champs de DecisionsProposeesAnnee de ce semestre
|
||||
yaml_setup_but.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury "automatiques"
|
||||
# et vérification des résultats attendus:
|
||||
formsemestre_validation_auto_but(formsemestre, only_adm=False)
|
||||
yaml_setup_but.but_test_jury(formsemestre, doc)
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.but_gb
|
||||
def test_but_jury_GB(test_client):
|
||||
@ -40,76 +60,21 @@ def test_but_jury_GB(test_client):
|
||||
- vérification jury de S3
|
||||
- vérification jury de S1 avec redoublants et capitalisations
|
||||
"""
|
||||
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/ressources/yaml/cursus_but_gb.yaml")
|
||||
|
||||
# Vérifie les deca de tous les semestres:
|
||||
for formsemestre in FormSemestre.query:
|
||||
yaml_setup_but.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury
|
||||
for formsemestre in FormSemestre.query.order_by(FormSemestre.semestre_id):
|
||||
formsemestre_validation_auto_but(formsemestre, only_adm=False)
|
||||
|
||||
# Vérifie résultats attendus:
|
||||
S1: FormSemestre = FormSemestre.query.filter_by(titre="S1_SEE").first()
|
||||
yaml_setup_but.but_test_jury(S1, doc)
|
||||
S2: FormSemestre = FormSemestre.query.filter_by(titre="S2_SEE").first()
|
||||
yaml_setup_but.but_test_jury(S2, doc)
|
||||
S3: FormSemestre = FormSemestre.query.filter_by(titre="S3").first()
|
||||
yaml_setup_but.but_test_jury(S3, doc)
|
||||
# _test_but_jury(S1_redoublant, doc)
|
||||
setup_and_test_jurys("tests/ressources/yaml/cursus_but_gb.yaml")
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.lemans
|
||||
def test_but_jury_GMP_lm(test_client):
|
||||
"""Tests sur un cursus GMP fourni 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/ressources/yaml/cursus_but_gmp_iutlm.yaml")
|
||||
|
||||
formsemestres = FormSemestre.query.order_by(
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
||||
# Vérifie les deca de tous les semestres:
|
||||
for formsemestre in formsemestres:
|
||||
yaml_setup_but.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury qui ne le seraient pas déjà
|
||||
for formsemestre in formsemestres:
|
||||
formsemestre_validation_auto_but(formsemestre, only_adm=False)
|
||||
|
||||
# Vérifie résultats attendus:
|
||||
for formsemestre in formsemestres:
|
||||
yaml_setup_but.but_test_jury(formsemestre, doc)
|
||||
setup_and_test_jurys("tests/ressources/yaml/cursus_but_gmp_iutlm.yaml")
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.lyon
|
||||
def test_but_jury_GEII_lyon(test_client):
|
||||
"""Tests sur un cursus GEII fourni par Lyon"""
|
||||
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/ressources/yaml/cursus_but_geii_lyon.yaml")
|
||||
formsemestres = FormSemestre.query.order_by(
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
||||
# Vérifie les champs de DecisionsProposeesAnnee de tous les semestres:
|
||||
for formsemestre in formsemestres:
|
||||
yaml_setup_but.check_deca_fields(formsemestre)
|
||||
|
||||
# Saisie de toutes les décisions de jury "automatiques"
|
||||
# et vérification des résultats attendus:
|
||||
for formsemestre in formsemestres:
|
||||
formsemestre_validation_auto_but(formsemestre, only_adm=False)
|
||||
yaml_setup_but.but_test_jury(formsemestre, doc)
|
||||
setup_and_test_jurys("tests/ressources/yaml/cursus_but_geii_lyon.yaml")
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@ -118,7 +83,14 @@ def test_but_jury_GCCD_CY(test_client):
|
||||
"""Tests sur un cursus BUT GCCD de S1 à S6"""
|
||||
# WIP
|
||||
app.set_sco_dept(DEPT)
|
||||
doc = yaml_setup.setup_from_yaml("tests/ressources/yaml/cursus_but_gccd_cy.yaml")
|
||||
doc, formation, formsemestre_titres = yaml_setup.setup_from_yaml(
|
||||
"tests/ressources/yaml/cursus_but_gccd_cy.yaml"
|
||||
)
|
||||
for formsemestre_titre in formsemestre_titres:
|
||||
_ = yaml_setup.create_formsemestre_with_etuds(
|
||||
doc, formation, formsemestre_titre
|
||||
)
|
||||
|
||||
formsemestres = FormSemestre.query.order_by(
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
@ -17,7 +17,7 @@ setup_from_yaml()
|
||||
- import de la formation (le test utilise une seule formation)
|
||||
- associe_ues_et_parcours():
|
||||
- crée les associations formation <-> référentiel de compétence
|
||||
- setup_formsemestres()
|
||||
- setup_formsemestre()
|
||||
- crée les formsemestres décrits dans le YAML
|
||||
avec tous les modules du semestre ou des parcours si indiqués
|
||||
et une évaluation dans chaque moduleimpl.
|
||||
@ -166,19 +166,20 @@ def create_evaluations(formsemestre: FormSemestre, publish_incomplete=True):
|
||||
evaluation.set_ue_poids_dict(ue_coef_dict)
|
||||
|
||||
|
||||
def note_les_modules(doc: dict):
|
||||
"""Saisie les notes des étudiants
|
||||
def note_les_modules(doc: dict, formsemestre_titre: str = ""):
|
||||
"""Saisie les notes des étudiants pour ce formsemestre
|
||||
doc : données YAML
|
||||
"""
|
||||
a_user = User.query.first()
|
||||
formsemestre: FormSemestre = FormSemestre.query.filter_by(
|
||||
titre=formsemestre_titre
|
||||
).first()
|
||||
assert formsemestre is not None
|
||||
for nom, infos in doc["Etudiants"].items():
|
||||
etud: Identite = Identite.query.filter_by(nom=nom).first()
|
||||
assert etud is not None
|
||||
for titre, sem_infos in infos["formsemestres"].items():
|
||||
formsemestre: FormSemestre = FormSemestre.query.filter_by(
|
||||
titre=titre
|
||||
).first()
|
||||
assert formsemestre is not None
|
||||
sem_infos = infos["formsemestres"].get(formsemestre_titre)
|
||||
if sem_infos:
|
||||
for code_module, note in sem_infos.get("notes_modules", {}).items():
|
||||
modimpl = (
|
||||
formsemestre.modimpls.join(Module)
|
||||
@ -209,11 +210,14 @@ def note_les_modules(doc: dict):
|
||||
)
|
||||
|
||||
|
||||
def setup_formsemestres(formation: Formation, doc: str):
|
||||
"""Création des formsemestres
|
||||
Le cas échéant associés à leur(s) parcours.
|
||||
def setup_formsemestre(
|
||||
formation: Formation, doc: str, formsemestre_titre: str = ""
|
||||
) -> FormSemestre:
|
||||
"""Création du formsemestre de titre indiqué.
|
||||
Le cas échéant associé à son parcours.
|
||||
"""
|
||||
for titre, infos in doc["FormSemestres"].items():
|
||||
infos = doc["FormSemestres"][formsemestre_titre]
|
||||
|
||||
codes_parcours = infos.get("codes_parcours", [])
|
||||
assert formation.is_apc() or not codes_parcours # parcours seulement en APC
|
||||
parcours = []
|
||||
@ -224,42 +228,51 @@ def setup_formsemestres(formation: Formation, doc: str):
|
||||
assert parcour is not None
|
||||
parcours.append(parcour)
|
||||
|
||||
_ = create_formsemestre(
|
||||
formsemestre = create_formsemestre(
|
||||
formation,
|
||||
parcours,
|
||||
infos["idx"],
|
||||
titre,
|
||||
formsemestre_titre,
|
||||
infos["date_debut"],
|
||||
infos["date_fin"],
|
||||
)
|
||||
|
||||
db.session.flush()
|
||||
assert FormSemestre.query.count() == len(doc["FormSemestres"])
|
||||
return formsemestre
|
||||
|
||||
|
||||
def inscrit_les_etudiants(formation: Formation, doc: dict):
|
||||
def inscrit_les_etudiants(doc: dict, formsemestre_titre: str = ""):
|
||||
"""Inscrit les étudiants dans chacun de leurs formsemestres"""
|
||||
etudiants = doc.get("Etudiants")
|
||||
if not etudiants:
|
||||
return
|
||||
for nom, infos in etudiants.items():
|
||||
etud = Identite.create_etud(
|
||||
dept_id=g.scodoc_dept_id,
|
||||
nom=nom,
|
||||
prenom=infos.get("prenom", "prénom"),
|
||||
civilite=infos.get("civilite", "X"),
|
||||
)
|
||||
db.session.add(etud)
|
||||
db.session.commit()
|
||||
# L'inscrire à ses formsemestres
|
||||
for titre, sem_infos in infos["formsemestres"].items():
|
||||
formsemestre: FormSemestre = FormSemestre.query.filter_by(
|
||||
titre=titre
|
||||
titre=formsemestre_titre
|
||||
).first()
|
||||
assert formsemestre is not None
|
||||
partition_parcours = formsemestre.partitions.filter_by(
|
||||
partition_name=scu.PARTITION_PARCOURS
|
||||
).first()
|
||||
for nom, infos in etudiants.items():
|
||||
# Création des étudiants (sauf si déjà existants)
|
||||
prenom = infos.get("prenom", "prénom")
|
||||
civilite = infos.get("civilite", "X")
|
||||
etud = Identite.query.filter_by(
|
||||
nom=nom, prenom=prenom, civilite=civilite
|
||||
).first()
|
||||
if etud is None:
|
||||
etud = Identite.create_etud(
|
||||
dept_id=g.scodoc_dept_id,
|
||||
nom=nom,
|
||||
prenom=prenom,
|
||||
civilite=civilite,
|
||||
)
|
||||
db.session.add(etud)
|
||||
db.session.commit()
|
||||
|
||||
# L'inscrire au formsemestre
|
||||
sem_infos = infos["formsemestres"].get(formsemestre_titre)
|
||||
if sem_infos:
|
||||
if partition_parcours is not None and "parcours" in sem_infos:
|
||||
group = partition_parcours.groups.filter_by(
|
||||
group_name=sem_infos["parcours"]
|
||||
@ -279,7 +292,6 @@ def inscrit_les_etudiants(formation: Formation, doc: dict):
|
||||
method="tests/unit/inscrit_les_etudiants",
|
||||
)
|
||||
# Met à jour les inscriptions:
|
||||
for formsemestre in formation.formsemestres:
|
||||
formsemestre.update_inscriptions_parcours_from_groups()
|
||||
|
||||
|
||||
@ -296,7 +308,7 @@ def etud_dispense_ues(
|
||||
db.session.add(disp)
|
||||
|
||||
|
||||
def setup_from_yaml(filename: str) -> dict:
|
||||
def setup_from_yaml(filename: str) -> tuple[dict, Formation, list[str]]:
|
||||
"""Lit le fichier yaml et construit l'ensemble des objets"""
|
||||
with open(filename, encoding="utf-8") as f:
|
||||
doc = yaml.safe_load(f.read())
|
||||
@ -307,9 +319,20 @@ def setup_from_yaml(filename: str) -> dict:
|
||||
formation = setup_formation(doc["Formation"])
|
||||
|
||||
yaml_setup_but.associe_ues_et_parcours(formation, doc["Formation"])
|
||||
setup_formsemestres(formation, doc)
|
||||
|
||||
formsemestre_titres = list(doc["FormSemestres"].keys())
|
||||
return doc, formation, formsemestre_titres
|
||||
|
||||
|
||||
def create_formsemestre_with_etuds(
|
||||
doc: dict, formation: Formation, formsemestre_titre: str
|
||||
) -> FormSemestre:
|
||||
"""Création formsemestre de titre indiqué, puis inscrit ses étudianst et les note"""
|
||||
formsemestre = setup_formsemestre(
|
||||
formation, doc, formsemestre_titre=formsemestre_titre
|
||||
)
|
||||
etudiants = doc.get("Etudiants")
|
||||
if etudiants:
|
||||
inscrit_les_etudiants(formation, doc)
|
||||
note_les_modules(doc)
|
||||
return doc
|
||||
inscrit_les_etudiants(doc, formsemestre_titre=formsemestre_titre)
|
||||
note_les_modules(doc, formsemestre_titre=formsemestre_titre)
|
||||
return formsemestre
|
||||
|
@ -272,9 +272,7 @@ def check_deca_fields(formsemestre: FormSemestre, etud: Identite = None):
|
||||
etud = etud or formsemestre.etuds.first()
|
||||
assert etud # il faut au moins un étudiant dans le semestre
|
||||
deca = DecisionsProposeesAnnee(etud, formsemestre)
|
||||
assert deca.validation is None # pas encore de validation enregistrée
|
||||
assert False is deca.recorded
|
||||
assert deca.code_valide is None
|
||||
parcour = deca.parcour
|
||||
formation: Formation = formsemestre.formation
|
||||
ues = (
|
||||
@ -310,7 +308,7 @@ def check_deca_fields(formsemestre: FormSemestre, etud: Identite = None):
|
||||
if deca.formsemestre_impair
|
||||
else 0
|
||||
)
|
||||
assert len(deca.decisions_ues) == nb_ues
|
||||
assert nb_ues > 0
|
||||
|
||||
assert len(deca.niveaux_competences) == len(ues)
|
||||
assert deca.nb_competences == len(ues)
|
||||
|
Loading…
Reference in New Issue
Block a user