# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Emmanuel Viennet emmanuel.viennet@viennet.net # ############################################################################## """Table recap formation (avec champs éditables) """ import io from zipfile import ZipFile from flask import Response from flask import send_file, url_for from flask import g, request from flask_login import current_user from app import db from app.models import Formation, FormSemestre, Matiere, Module, UniteEns from app.scodoc.gen_tables import GenTable from app.scodoc.sco_permissions import Permission from app.scodoc import sco_preferences import app.scodoc.sco_utils as scu # ---- Table recap formation def formation_table_recap(formation: Formation, fmt="html") -> Response: """Table recapitulant formation.""" rows = [] ues = formation.ues.order_by(UniteEns.semestre_idx, UniteEns.numero) can_edit = current_user.has_permission(Permission.EditFormation) li = 0 for ue in ues: # L'UE rows.append( { "sem": f"S{ue.semestre_idx}" if ue.semestre_idx is not None else "-", "_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 "", "ects": ue.ects, "_css_row_class": "ue", } ) li += 1 matieres = ue.matieres.order_by(Matiere.numero) for mat in matieres: modules = mat.modules.order_by(Module.numero) for mod in modules: nb_moduleimpls = mod.modimpls.count() # le module (ou ressource ou sae) rows.append( { "sem": ( f"S{mod.semestre_id}" if mod.semestre_id is not None else "-" ), "_sem_order": f"{li:04d}", "code": mod.code, "titre": mod.abbrev or mod.titre, "_titre_target": ( url_for( "notes.module_edit", scodoc_dept=g.scodoc_dept, module_id=mod.id, ) if can_edit else None ), "apo": mod.code_apogee, "_apo_td_attrs": f""" data-oid="{mod.id}" data-value="{mod.code_apogee or ''}" """, "coef": mod.coefficient, "nb_moduleimpls": nb_moduleimpls, "heures_cours": mod.heures_cours, "heures_td": mod.heures_td, "heures_tp": mod.heures_tp, "tags": ", ".join(t.title for t in mod.tags if t.title), "_css_row_class": f"mod {mod.type_abbrv()}", } ) columns_ids = [ "sem", "code", "apo", # "mat", inutile d'afficher la matière "titre", "ects", "nb_moduleimpls", "heures_cours", "heures_td", "heures_tp", "tags", ] if not formation.is_apc(): columns_ids.insert(columns_ids.index("ects"), "coef") titles = { "ue": "UE", "mat": "Matière", "titre": "Titre", "code": "Code", "apo": "Apo", "coef": "Coef.", "sem": "Sem.", "nb_moduleimpls": "Nb utilisé", "heures_cours": "Cours (h)", "heures_td": "TD (h)", "heures_tp": "TP (h)", "tags": "Tags", "ects": "ECTS", } title = f"""Formation {formation.titre} ({formation.acronyme}) [version {formation.version}] code {formation.formation_code}""" html_class = "stripe cell-border compact hover order-column formation_table_recap" if current_user.has_permission(Permission.EditApogee): html_class += " apo_editable" tab = GenTable( columns_ids=columns_ids, rows=rows, titles=titles, origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}", caption=title, html_caption=title, html_class=html_class, html_class_ignore_default=True, html_table_attrs=f""" data-apo_ue_save_url="{ url_for('apiweb.ue_set_code_apogee', scodoc_dept=g.scodoc_dept) }" data-apo_mod_save_url="{ url_for('apiweb.formation_module_set_code_apogee', scodoc_dept=g.scodoc_dept) }" """, html_with_td_classes=True, base_url=f"{request.base_url}", page_title=title, html_title=f"

{title}

", pdf_title=title, preferences=sco_preferences.SemPreferences(), table_id="formation_table_recap", ) return tab.make_page( fmt=fmt, javascripts=["js/formation_recap.js"], template="sco_page_dept.j2" ) def export_recap_formations_annee_scolaire(annee_scolaire): """Exporte un zip des recap (excel) des formations 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_annee_scolaire(annee_scolaire), FormSemestre.date_debut <= scu.date_fin_annee_scolaire(annee_scolaire), ) formation_ids = {formsemestre.formation.id for formsemestre in formsemestres} for formation_id in formation_ids: formation = db.session.get(Formation, formation_id) xls = formation_table_recap(formation, fmt="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, )