diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 9815b9fd4a..6b832a8821 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -257,6 +257,11 @@ class FormSemestre(db.Model): d["etapes_apo_str"] = self.etapes_apo_str() return d + def flip_lock(self): + """Flip etat (lock)""" + self.etat = not self.etat + db.session.add(self) + def get_parcours_apc(self) -> list[ApcParcours]: """Liste des parcours proposés par ce semestre. Si aucun n'est coché et qu'il y a un référentiel, tous ceux du référentiel. diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 96c85d69aa..7230bffa13 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -908,7 +908,8 @@ def formsemestre_bulletinetud( )[0] if format not in {"html", "pdfmail"}: filename = scu.bul_filename(formsemestre, etud, format) - return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0]) + mime, suffix = scu.get_mime_suffix(format) + return scu.send_file(bulletin, filename, mime=mime, suffix=suffix) elif format == "pdfmail": return "" H = [ diff --git a/app/scodoc/sco_cost_formation.py b/app/scodoc/sco_cost_formation.py index 09d1e12290..16429881b8 100644 --- a/app/scodoc/sco_cost_formation.py +++ b/app/scodoc/sco_cost_formation.py @@ -32,12 +32,12 @@ """ from flask import request -import app.scodoc.sco_utils as scu +from app.models import FormSemestre from app.scodoc.gen_tables import GenTable from app.scodoc import sco_formsemestre from app.scodoc import sco_moduleimpl -from app.scodoc import sco_formsemestre_status from app.scodoc import sco_preferences +import app.scodoc.sco_utils as scu import sco_version @@ -57,37 +57,35 @@ def formsemestre_table_estim_cost( peut conduire à une sur-estimation du coût s'il y a des modules optionnels (dans ce cas, retoucher le tableau excel exporté). """ - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - sco_formsemestre_status.fill_formsemestre(sem) - Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id) - T = [] - for M in Mlist: - Mod = M["module"] - T.append( + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + + rows = [] + for modimpl in formsemestre.modimpls: + rows.append( { - "code": Mod["code"] or "", - "titre": Mod["titre"], - "heures_cours": Mod["heures_cours"], - "heures_td": Mod["heures_td"] * n_group_td, - "heures_tp": Mod["heures_tp"] * n_group_tp, + "code": modimpl.module.code or "", + "titre": modimpl.module.titre, + "heures_cours": modimpl.module.heures_cours, + "heures_td": modimpl.module.heures_td * n_group_td, + "heures_tp": modimpl.module.heures_tp * n_group_tp, } ) # calcul des heures: - for t in T: + for t in rows: t["HeqTD"] = ( t["heures_td"] + coef_cours * t["heures_cours"] + coef_tp * t["heures_tp"] ) - sum_cours = sum([t["heures_cours"] for t in T]) - sum_td = sum([t["heures_td"] for t in T]) - sum_tp = sum([t["heures_tp"] for t in T]) + sum_cours = sum([t["heures_cours"] for t in rows]) + sum_td = sum([t["heures_td"] for t in rows]) + sum_tp = sum([t["heures_tp"] for t in rows]) sum_heqtd = sum_td + coef_cours * sum_cours + coef_tp * sum_tp - assert abs(sum([t["HeqTD"] for t in T]) - sum_heqtd) < 0.01, "%s != %s" % ( - sum([t["HeqTD"] for t in T]), + assert abs(sum([t["HeqTD"] for t in rows]) - sum_heqtd) < 0.01, "%s != %s" % ( + sum([t["HeqTD"] for t in rows]), sum_heqtd, ) - T.append( + rows.append( { "code": "TOTAL SEMESTRE", "heures_cours": sum_cours, @@ -117,13 +115,15 @@ def formsemestre_table_estim_cost( "heures_tp", "HeqTD", ), - rows=T, + rows=rows, html_sortable=True, preferences=sco_preferences.SemPreferences(formsemestre_id), html_class="table_leftalign table_listegroupe", xls_before_table=[ - ["%(titre)s %(num_sem)s %(modalitestr)s" % sem], - ["Formation %(titre)s version %(version)s" % sem["formation"]], + [formsemestre.titre_annee()], + [ + f"Formation {formsemestre.formation.titre} version {formsemestre.formation.version}" + ], [], ["", "TD", "TP"], ["Nombre de groupes", n_group_td, n_group_tp], @@ -140,10 +140,8 @@ def formsemestre_table_estim_cost( (dans ce cas, retoucher le tableau excel exporté). """, - origin="Généré par %s le " % sco_version.SCONAME - + scu.timedate_human_repr() - + "", - filename="EstimCout-S%s" % sem["semestre_id"], + origin=f"""Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}""", + filename=f"EstimCout-S{formsemestre.semestre_id}", ) return tab diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py index 84a6039be6..29103d94c9 100644 --- a/app/scodoc/sco_formations.py +++ b/app/scodoc/sco_formations.py @@ -485,7 +485,7 @@ def formation_list_table() -> GenTable: ) + f""", ajouter diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index 584f591adb..3280b1be50 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -1659,20 +1659,6 @@ def formsemestre_edit_options(formsemestre_id): return sco_preferences.SemPreferences(formsemestre_id).edit(categories=["bul"]) -def formsemestre_change_lock(formsemestre_id) -> None: - """Change etat (verrouille si ouvert, déverrouille si fermé) - nota: etat (1 ouvert, 0 fermé) - """ - ok, err = sco_permissions_check.check_access_diretud(formsemestre_id) - if not ok: - return err - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - etat = not sem["etat"] - - args = {"formsemestre_id": formsemestre_id, "etat": etat} - sco_formsemestre.do_formsemestre_edit(args) - - def formsemestre_change_publication_bul( formsemestre_id, dialog_confirmed=False, redirect=True ): diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index d3ac77400c..32478d0b52 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -200,7 +200,7 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str: }, { "title": change_lock_msg, - "endpoint": "notes.formsemestre_change_lock", + "endpoint": "notes.formsemestre_flip_lock", "args": {"formsemestre_id": formsemestre_id}, "enabled": has_perm_change_sem, "helpmsg": "", @@ -546,59 +546,6 @@ def formsemestre_page_title(formsemestre_id=None): ) -def fill_formsemestre(sem): - """Add some useful fields to help display formsemestres""" - sem["notes_url"] = scu.NotesURL() - formsemestre_id = sem["formsemestre_id"] - if not sem["etat"]: - sem[ - "locklink" - ] = f"""{scu.icontag("lock_img", border="0", title="Semestre verrouillé")}""" - else: - sem["locklink"] = "" - if sco_preferences.get_preference("bul_display_publication", formsemestre_id): - if sem["bul_hide_xml"]: - eyeicon = scu.icontag("hide_img", border="0", title="Bulletins NON publiés") - else: - eyeicon = scu.icontag("eye_img", border="0", title="Bulletins publiés") - sem[ - "eyelink" - ] = f"""{eyeicon}""" - else: - sem["eyelink"] = "" - sem["formation"] = Formation.query.get_or_404(sem["formation_id"]).to_dict( - with_departement=False - ) - parcours = codes_cursus.get_cursus_from_code(F["type_parcours"]) - if sem["semestre_id"] != -1: - sem["num_sem"] = f""", {parcours.SESSION_NAME} {sem["semestre_id"]}""" - else: - sem["num_sem"] = "" # formation sans semestres - if sem["modalite"]: - sem["modalitestr"] = f""" en {sem["modalite"]}""" - else: - sem["modalitestr"] = "" - - sem["etape_apo_str"] = "Code étape Apogée: " + ( - sco_formsemestre.formsemestre_etape_apo_str(sem) or "Pas de code étape" - ) - - inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( - args={"formsemestre_id": formsemestre_id} - ) - sem["nbinscrits"] = len(inscrits) - uresps = [ - sco_users.user_info(responsable_id) for responsable_id in sem["responsables"] - ] - sem["resp"] = ", ".join([u["prenomnom"] for u in uresps]) - sem["nomcomplet"] = ", ".join([u["nomcomplet"] for u in uresps]) - - # Description du semestre sous forme de table exportable def formsemestre_description_table( formsemestre_id: int, with_evals=False, with_parcours=False @@ -645,7 +592,7 @@ def formsemestre_description_table( titles["publish_incomplete_str"] = "Toujours utilisée" title = f"{parcours.SESSION_NAME.capitalize()} {formsemestre.titre_mois()}" - R = [] + rows = [] sum_coef = 0 sum_ects = 0 last_ue_id = None @@ -671,7 +618,7 @@ def formsemestre_description_table( if use_ue_coefs: ue_info["Coef."] = ue.coefficient ue_info["Coef._class"] = "ue_coef" - R.append(ue_info) + rows.append(ue_info) mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list( moduleimpl_id=modimpl.id @@ -713,14 +660,15 @@ def formsemestre_description_table( sorted([pa.code for pa in modimpl.module.parcours]) ) - R.append(l) + rows.append(l) if with_evals: # Ajoute lignes pour evaluations evals = nt.get_mod_evaluation_etat_list(modimpl.id) evals.reverse() # ordre chronologique # Ajoute etat: - for e in evals: + for eval_dict in evals: + e = eval_dict.copy() e["_jour_order"] = e["jour"].isoformat() e["jour"] = e["jour"].strftime("%d/%m/%Y") if e["jour"] else "" e["UE"] = l["UE"] @@ -749,14 +697,14 @@ def formsemestre_description_table( e[f"_ue_{ue_id}_class"] = "poids" e[f"_ue_{ue_id}_help"] = "poids vers l'UE" - R += evals + rows += evals sums = {"_css_row_class": "moyenne sortbottom", "ects": sum_ects, "Coef.": sum_coef} - R.append(sums) + rows.append(sums) return GenTable( columns_ids=columns_ids, - rows=R, + rows=rows, titles=titles, origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}", caption=title, diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 011a570850..f03bab04c0 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -294,9 +294,8 @@ def _formsemestre_recapcomplet_to_file( include_evaluations=include_evaluations, filename=filename, ) - return scu.send_file( - data, filename=filename, mime=scu.get_mime_suffix(tabformat) - ) + mime, suffix = scu.get_mime_suffix(tabformat) + return scu.send_file(data, filename=filename, mime=mime, suffix=suffix) elif tabformat == "xml": data = gen_formsemestre_recapcomplet_xml( formsemestre.id, diff --git a/app/static/css/gt_table.css b/app/static/css/gt_table.css index 90c9bf08c5..f4b644df4a 100644 --- a/app/static/css/gt_table.css +++ b/app/static/css/gt_table.css @@ -10,6 +10,7 @@ table.dataTable { width: 100%; margin: 0 auto; + margin-left: 0px; clear: both; border-collapse: separate; border-spacing: 0; @@ -643,10 +644,12 @@ table.dataTable.order-column.stripe.hover tbody tr.even:hover td.sorting_1 { /* Reglage largeur de la table */ table.dataTable.gt_table { width: auto; + margin-left: 32px; + margin-top: 8px; padding-right: 5px; } -/* Tables non centrées */ +/* Tables non centrées (inutile) */ table.dataTable.gt_table.gt_left { margin-left: 16px; } \ No newline at end of file diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 1a88fa5444..9676f89e0c 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -2069,9 +2069,11 @@ table#formation_list_table tr.gt_hl { table.formation_list_table td.buttons { white-space: nowrap; } + table.formation_list_table td.buttons a { margin-left: 8px; } + table.formation_list_table td.buttons span.but_placeholder { display: inline-block; width: 15px; @@ -4036,7 +4038,8 @@ div.table_recap { } */ -div.table_recap table.table_recap { +div.table_recap table.table_recap, +div.evaluations_recap table.evaluations_recap { width: auto; margin-left: 0px; /* font-family: Consolas, monaco, monospace; */ @@ -4230,9 +4233,10 @@ table.table_recap th.col_res { border-right: 1px dashed green; border-left: 1px dashed green; } + table.table_recap td.abs, table.table_recap th.abs { - color:rgb(80, 0, 0); + color: rgb(80, 0, 0); border-right: 1px dashed green; border-left: 1px dashed green; } diff --git a/app/templates/formsemestre_header.j2 b/app/templates/formsemestre_header.j2 index fae42f00ff..a768582329 100644 --- a/app/templates/formsemestre_header.j2 +++ b/app/templates/formsemestre_header.j2 @@ -21,7 +21,7 @@ title="{{sco.sem.responsables_str(abbrev_prenom=False)}}">{{sco.sem.responsables_str()}} {{sco.sem.inscriptions|length}} inscrits{% if - not sco.sem.etat %}{{sco.scu.icontag("lock_img", border="0", title="Semestre verrouillé")|safe}}{% endif %} {% if sco.prefs["bul_display_publication"] %} diff --git a/app/templates/formsemestre_page_title.j2 b/app/templates/formsemestre_page_title.j2 index 14c7f6ea51..95774dae41 100644 --- a/app/templates/formsemestre_page_title.j2 +++ b/app/templates/formsemestre_page_title.j2 @@ -21,7 +21,7 @@ scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id) }}">{{formsemestre.etuds_inscriptions|length}} inscrits {%-if not formsemestre.etat -%} - {{ scu.icontag("lock_img", border="0", title="Semestre verrouillé")|safe }} diff --git a/app/views/notes.py b/app/views/notes.py index 545ba9f5b7..2bf9b17238 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -820,20 +820,22 @@ sco_publish( ) -@bp.route("/formsemestre_change_lock", methods=["GET", "POST"]) +@bp.route("/formsemestre_flip_lock", methods=["GET", "POST"]) @scodoc -@permission_required(Permission.ScoView) # acces vérifié dans la fonction +@permission_required(Permission.ScoView) # acces vérifié dans la vue @scodoc7func -def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False): +def formsemestre_flip_lock(formsemestre_id, dialog_confirmed=False): "Changement de l'état de verrouillage du semestre" - + formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) + dest_url = url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre.id, + ) + if not formsemestre.est_chef_or_diretud(): + raise ScoPermissionDenied("opération non autorisée", dest_url=dest_url) if not dialog_confirmed: - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - etat = not sem["etat"] - if etat: - msg = "déverrouillage" - else: - msg = "verrouillage" + msg = "verrouillage" if formsemestre.etat else "déverrouillage" return scu.confirm_dialog( f"

Confirmer le {msg} du semestre ?

", helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées. @@ -843,23 +845,14 @@ def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False): Le programme d'une formation qui a un semestre verrouillé ne peut plus être modifié. """, dest_url="", - cancel_url=url_for( - "notes.formsemestre_status", - scodoc_dept=g.scodoc_dept, - formsemestre_id=formsemestre_id, - ), + cancel_url=dest_url, parameters={"formsemestre_id": formsemestre_id}, ) - sco_formsemestre_edit.formsemestre_change_lock(formsemestre_id) + formsemestre.flip_lock() + db.session.commit() - return flask.redirect( - url_for( - "notes.formsemestre_status", - scodoc_dept=g.scodoc_dept, - formsemestre_id=formsemestre_id, - ) - ) + return flask.redirect(dest_url) sco_publish( diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index a0291f0699..dc5a532f1a 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -1 +1,17 @@ -# Unit tests +# ScoDoc Unit Tests + +"""Set of unit tests for ScoDoc +""" + + +def call_view(view_function, *args, **kwargs): + """Undecorate a view and call it directly.""" + # On a 3 décorateurs: @scodoc, @permission_required, @scodoc7func + func = ( + view_function.__closure__[0] + .cell_contents.__closure__[0] + .cell_contents.__closure__[0] + .cell_contents + ) + assert func + return func(*args, **kwargs) diff --git a/tests/unit/test_but_jury.py b/tests/unit/test_but_jury.py index e4ea40e0e2..14d0343452 100644 --- a/tests/unit/test_but_jury.py +++ b/tests/unit/test_but_jury.py @@ -42,7 +42,7 @@ def test_but_jury_GB(test_client): 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_gb.yaml") + 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: @@ -69,7 +69,7 @@ def test_but_jury_GMP_lm(test_client): 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") + 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 @@ -95,7 +95,7 @@ def test_but_jury_GEII_lyon(test_client): 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_geii_lyon.yaml") + 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() diff --git a/tests/unit/test_formsemestre.py b/tests/unit/test_formsemestre.py index 3cb516afe6..ee25669531 100644 --- a/tests/unit/test_formsemestre.py +++ b/tests/unit/test_formsemestre.py @@ -3,12 +3,37 @@ """ Test création/accès/clonage formsemestre """ +from flask import Response import pytest -from tests.unit import yaml_setup +from tests.unit import yaml_setup, call_view import app -from app.models import Formation -from app.scodoc import sco_formsemestre_edit +from app import db +from app.models import Formation, FormSemestre +from app.scodoc import ( + sco_archives, + sco_cost_formation, + sco_debouche, + sco_edit_ue, + sco_evaluations, + sco_evaluation_check_abs, + sco_evaluation_recap, + sco_formsemestre_edit, + sco_formsemestre_inscriptions, + sco_formsemestre_status, + sco_groups, + sco_inscr_passage, + sco_lycee, + sco_moduleimpl_inscriptions, + sco_poursuite_dut, + sco_preferences, + sco_recapcomplet, + sco_report, + sco_undo_notes, +) + +from app.scodoc import sco_utils as scu +from app.views import notes, scolar from config import TestConfig DEPT = TestConfig.DEPT_TEST @@ -34,3 +59,128 @@ def test_formsemestres_associate_new_version(test_client): assert new_formation assert formsemestres[0].formation_id == new_formation.id assert formsemestres[1].formation_id == new_formation.id + + +def test_formsemestre_misc_views(test_client): + """Test de nombreuses vues: test juste que la page ne plante, + pas de vérif du contenu ni de soumission si c'est un formulaire. + + Note: les anciennes vues renvoient souvent des str au lieu de Response. + """ + app.set_sco_dept(DEPT) + yaml_setup.setup_from_yaml("tests/ressources/yaml/simple_formsemestres.yaml") + formsemestre: FormSemestre = FormSemestre.query.first() + + # ----- MENU SEMESTRE + _ = sco_formsemestre_status.formsemestre_status(formsemestre_id=formsemestre.id) + _ = sco_edit_ue.ue_table(formsemestre.formation_id) + _ = sco_formsemestre_edit.formsemestre_editwithmodules(formsemestre.id) + _ = sco_preferences.SemPreferences(formsemestre_id=formsemestre.id).edit() + _ = sco_formsemestre_edit.formsemestre_edit_options(formsemestre.id) + assert formsemestre.etat + formsemestre.flip_lock() + assert not formsemestre.etat + formsemestre.flip_lock() + assert formsemestre.etat + ans = sco_formsemestre_status.formsemestre_description( + formsemestre.id, with_evals=True + ) + assert isinstance(ans, (str, Response)) # ici c'est une str + ans = sco_formsemestre_status.formsemestre_description( + formsemestre.id, with_evals=True, format="xls" + ) + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.XLSX_MIMETYPE + ans = sco_formsemestre_status.formsemestre_description( + formsemestre.id, with_evals=True, format="pdf" + ) + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.PDF_MIMETYPE + ans = sco_evaluation_check_abs.formsemestre_check_absences_html(formsemestre.id) + assert isinstance(ans, (str, Response)) + # Appel direct de la vue: enlève les décorateurs: + ans = call_view(notes.formsemestre_enseignants_list, formsemestre.id) + assert isinstance(ans, (str, Response)) # ici str + # Juste la page dialogue avant opération:: + ans = sco_formsemestre_edit.formsemestre_clone(formsemestre.id) + ans = sco_formsemestre_edit.formsemestre_associate_new_version(formsemestre.id) + ans = sco_formsemestre_edit.formsemestre_delete(formsemestre.id) + + # ----- MENU INSCRIPTIONS + ans = sco_moduleimpl_inscriptions.moduleimpl_inscriptions_stats(formsemestre.id) + ans = sco_inscr_passage.formsemestre_inscr_passage(formsemestre.id) + ans = call_view(scolar.form_students_import_excel, formsemestre.id) + assert isinstance(ans, str) + ans = call_view(scolar.form_students_import_infos_admissions, formsemestre.id) + ans = sco_formsemestre_inscriptions.formsemestre_inscrits_ailleurs(formsemestre.id) + + # ----- MENU GROUPES + ans = call_view(scolar.groups_view, formsemestre.id) + ans = call_view(scolar.partition_editor, formsemestre.id) + ans = sco_groups.edit_partition_form(formsemestre.id) + + # ----- MENU NOTES + ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id) + ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="evals") + ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="xlsx") + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.XLSX_MIMETYPE + ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="json") + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.JSON_MIMETYPE + ans = sco_evaluation_recap.evaluations_recap(formsemestre.id) + + # Bulletins pdf: + ans = call_view(notes.formsemestre_bulletins_pdf_choice, formsemestre.id) + assert isinstance(ans, str) # sans version, on a le formulaire de choix, une str + ans = call_view( + notes.formsemestre_bulletins_pdf_choice, formsemestre.id, version="long" + ) + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.PDF_MIMETYPE + # on ne teste pas les mails :) + ans = sco_evaluations.formsemestre_evaluations_cal(formsemestre.id) + assert isinstance(ans, str) + sco_undo_notes.formsemestre_list_saisies_notes(formsemestre.id) + + # ----- MENU JURY + ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, mode_jury=True) + ans = sco_recapcomplet.formsemestre_recapcomplet( + formsemestre.id, mode_jury=True, tabformat="xlsx" + ) + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.XLSX_MIMETYPE + ans = sco_recapcomplet.formsemestre_recapcomplet( + formsemestre.id, mode_jury=True, tabformat="json" + ) + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.JSON_MIMETYPE + ans = sco_archives.formsemestre_archive(formsemestre.id) + ans = sco_archives.formsemestre_list_archives(formsemestre.id) + + # ----- MENU STATISTIQUES + ans = sco_report.formsemestre_report_counts(formsemestre.id) + ans = sco_report.formsemestre_report_counts(formsemestre.id, format="xls") + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.XLSX_MIMETYPE + ans = sco_report.formsemestre_suivi_cohorte(formsemestre.id) + ans = sco_report.formsemestre_suivi_cohorte(formsemestre.id, format="pdf") + assert isinstance(ans, Response) + assert ans.status == "200 OK" + assert ans.mimetype == scu.PDF_MIMETYPE + ans = sco_report.formsemestre_graph_cursus(formsemestre.id) + ans = sco_report.formsemestre_suivi_cursus(formsemestre.id) + ans = sco_lycee.formsemestre_etuds_lycees(formsemestre.id) + ans = sco_poursuite_dut.formsemestre_poursuite_report(formsemestre.id) + # pas de test des avis de poursuite + ans = sco_debouche.report_debouche_date(start_year=2000) + ans = sco_cost_formation.formsemestre_estim_cost(formsemestre.id) + # pas de test des indicateurs de suivi BUT