diff --git a/app/scodoc/sco_formation_recap.py b/app/scodoc/sco_formation_recap.py index e23b043e..16aa336d 100644 --- a/app/scodoc/sco_formation_recap.py +++ b/app/scodoc/sco_formation_recap.py @@ -27,11 +27,14 @@ """Table recap formation (avec champs éditables) """ -from flask import url_for +import io +from zipfile import ZipFile, BadZipfile + +from flask import send_file, url_for from flask import g, request from flask_login import current_user -from app.models import Formation, UniteEns, Module +from app.models import Formation, FormSemestre, UniteEns, Module from app.models.formations import Matiere from app.scodoc.gen_tables import GenTable @@ -56,6 +59,13 @@ def formation_table_recap(formation_id, format="html"): "_sem_order": f"{li:04d}", "code": ue.acronyme, "titre": ue.titre or "", + "_titre_target": url_for( + "notes.ue_edit", + scodoc_dept=g.scodoc_dept, + ue_id=ue.id, + ) + if can_edit + else None, "apo": ue.code_apogee or "", "_apo_td_attrs": f""" data-oid="{ue.id}" data-value="{ue.code_apogee or ''}" """, "coef": ue.coefficient or "", @@ -151,3 +161,32 @@ def formation_table_recap(formation_id, format="html"): table_id="formation_table_recap", ) return tab.make_page(format=format, javascripts=["js/formation_recap.js"]) + + +def export_recap_formations_annee_scolaire(annee_scolaire): + """Exporte un zip des recap (excel) des formatons de tous les semestres + de l'année scolaire indiquée. + """ + annee_scolaire = int(annee_scolaire) + data = io.BytesIO() + zip_file = ZipFile(data, "w") + formsemestres = FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id).filter( + FormSemestre.date_debut >= scu.date_debut_anne_scolaire(annee_scolaire), + FormSemestre.date_debut <= scu.date_fin_anne_scolaire(annee_scolaire), + ) + formation_ids = {formsemestre.formation.id for formsemestre in formsemestres} + for formation_id in formation_ids: + formation = Formation.query.get(formation_id) + xls = formation_table_recap(formation_id, format="xlsx").data + filename = ( + scu.sanitize_filename(formation.get_titre_version()) + scu.XLSX_SUFFIX + ) + zip_file.writestr(filename, xls) + zip_file.close() + data.seek(0) + return send_file( + data, + mimetype="application/zip", + download_name=f"formations-{g.scodoc_dept}-{annee_scolaire}-{annee_scolaire+1}.zip", + as_attachment=True, + ) diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index d4789201..ff91c149 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -871,6 +871,20 @@ def annee_scolaire_debut(year, month): return int(year) - 1 +def date_debut_anne_scolaire(annee_scolaire: int) -> datetime: + """La date de début de l'année scolaire + = 1er aout + """ + return datetime.datetime(year=annee_scolaire, month=8, day=1) + + +def date_fin_anne_scolaire(annee_scolaire: int) -> datetime: + """La date de fin de l'année scolaire + = 31 juillet de l'année suivante + """ + return datetime.datetime(year=annee_scolaire + 1, month=7, day=31) + + def sem_decale_str(sem): """'D' si semestre decalé, ou ''""" # considère "décalé" les semestre impairs commençant entre janvier et juin diff --git a/app/views/notes.py b/app/views/notes.py index a4d87741..4fc69bdc 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -486,6 +486,11 @@ sco_publish( sco_formation_recap.formation_table_recap, Permission.ScoView, ) +sco_publish( + "/export_recap_formations_annee_scolaire", + sco_formation_recap.export_recap_formations_annee_scolaire, + Permission.ScoView, +) sco_publish( "/formation_add_malus_modules", sco_edit_module.formation_add_malus_modules, @@ -575,6 +580,20 @@ def index_html():