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