Compare commits

...

3 Commits

Author SHA1 Message Date
Cléo Baras 802e8f4648 Ajout de l'option "Générer les moyennes sur les tags" 2024-02-27 17:11:00 +01:00
Cléo Baras cf7d7d2db8 Merge remote-tracking branch 'scodoc/cleo-pe-BUT-v2' into pe-but-options
# Conflicts:
#	app/pe/pe_view.py
#	app/templates/pe/pe_view_sem_recap.j2
2024-02-27 16:45:15 +01:00
Emmanuel Viennet bcb801662a WIP: PE : form paramétrage pe_view_sem_recap 2024-02-09 21:52:33 +01:00
6 changed files with 141 additions and 50 deletions

View File

@ -0,0 +1,51 @@
##############################################################################
#
# ScoDoc
#
# 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
#
##############################################################################
"""
Formulaire options génération table poursuite études (PE)
"""
from flask_wtf import FlaskForm
from wtforms import BooleanField, HiddenField, SubmitField
class ParametrageClasseurPE(FlaskForm):
"Formulaire paramétrage génération classeur PE"
cohorte_restreinte = BooleanField(
"Restreindre aux étudiants inscrits dans le semestre"
)
moyennes_tags = BooleanField(
"Générer les moyennes sur les tags de modules personnalisés (cf. programme de formation)"
)
moyennes_ue_res_sae = BooleanField(
"Générer les moyennes des ressources et des SAEs par UE"
)
moyennes_ues_rcues = BooleanField("Générer moyennes des UEs et RCUEs (compétences)")
min_max_moy = BooleanField("Colonnes min/max/moy")
synthese_individuelle_etud = BooleanField(
"Générer la feuille synthèse avec un onglet par étudiant"
)
submit = SubmitField("Générer les classeurs poursuites d'études")
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})

View File

@ -56,10 +56,11 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
Il s'appuie principalement sur un ResultatsSemestreBUT.
"""
def __init__(self, formsemestre: FormSemestre):
def __init__(self, formsemestre: FormSemestre, options={}):
"""
Args:
formsemestre: le ``FormSemestre`` sur lequel il se base
options: Un dictionnaire d'options
"""
ResultatsSemestreBUT.__init__(self, formsemestre)
pe_tabletags.TableTag.__init__(self)
@ -118,7 +119,11 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
pe_affichage.pe_print(f"--> UEs/Compétences : {aff}")
# Les tags personnalisés et auto:
tags_dict = self._get_tags_dict()
if "moyennes_tags" in options:
tags_dict = self._get_tags_dict(avec_moyennes_tags=options["moyennes_tags"])
else:
tags_dict = self._get_tags_dict()
pe_affichage.pe_print(
f"""--> {pe_affichage.aff_tags_par_categories(tags_dict)}"""
)
@ -347,7 +352,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
return df_ues
def _get_tags_dict(self):
def _get_tags_dict(self, avec_moyennes_tags=True):
"""Renvoie les tags personnalisés (déduits des modules du semestre)
et les tags automatiques ('but'), et toutes leurs informations,
dans un dictionnaire de la forme :
@ -359,10 +364,12 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
Le dictionnaire structuré des tags ("personnalises" vs. "auto")
"""
dict_tags = {"personnalises": dict(), "auto": dict()}
# Les tags perso
dict_tags["personnalises"] = get_synthese_tags_personnalises_semestre(
self.formsemestre
)
if avec_moyennes_tags:
# Les tags perso (seulement si l'option d'utiliser les tags perso est choisie)
dict_tags["personnalises"] = get_synthese_tags_personnalises_semestre(
self.formsemestre
)
# Les tags automatiques
# Déduit des compétences

View File

@ -127,10 +127,15 @@ def aff_tags_par_categories(dict_tags):
"""
noms_tags_perso = sorted(list(set(dict_tags["personnalises"].keys())))
noms_tags_auto = sorted(list(set(dict_tags["auto"].keys()))) # + noms_tags_comp
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
aff_tags_perso = ", ".join([f"👜{nom}" for nom in noms_tags_perso])
if noms_tags_perso:
aff_tags_perso = ", ".join([f"👜{nom}" for nom in noms_tags_perso])
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
return f"Tags du programme de formation : {aff_tags_perso} + Automatiques : {aff_tags_auto}"
else:
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
return f"Tags automatiques {aff_tags_auto} (aucun tag personnalisé)"
# Affichage
return f"Tags du programme de formation : {aff_tags_perso} + Automatiques : {aff_tags_auto}"
def aff_trajectoires_suivies_par_etudiants(etudiants):

View File

@ -75,22 +75,46 @@ class JuryPE(object):
1. l'année d'obtention du DUT,
2. tous les étudiants susceptibles à ce stade (au regard de leur parcours) d'être diplomés.
Les options sont :
``
options = {
"cohorte_restreinte": False,
"moyennes_tags": True,
"moyennes_ue_res_sae": True,
"moyennes_ues_rcues": True,
"min_max_moy": False,
"synthese_individuelle_etud": False,
}
Args:
diplome : l'année d'obtention du diplome BUT et du jury de PE (généralement février XXXX)
"""
def __init__(self, diplome: int):
def __init__(self, diplome: int, formsemestre_id_base, options=None):
pe_affichage.pe_start_log()
self.diplome = diplome
"L'année du diplome"
self.formsemestre_id_base = formsemestre_id_base
"""L'identifiant du formsemestre ayant servi à lancer le jury"""
self.nom_export_zip = f"Jury_PE_{self.diplome}"
"Nom du zip où ranger les fichiers générés"
# Les options
self.options = options
"""Options de configuration"""
pe_affichage.pe_print(
f"Données de poursuite d'étude générées le {time.strftime('%d/%m/%Y à %H:%M')}\n",
info=True,
)
pe_affichage.pe_print("Options", info=True)
for cle, val in self.options.items():
pe_affichage.pe_print(f" > {cle} -> {val}", info=True)
# Chargement des étudiants à prendre en compte dans le jury
pe_affichage.pe_print(
f"""***********************************************************"""
@ -180,7 +204,7 @@ class JuryPE(object):
self.ressembuttags = {}
for frmsem_id, formsemestre in formsemestres.items():
# Crée le semestre_tag et exécute les calculs de moyennes
ressembuttag = pe_ressemtag.ResSemBUTTag(formsemestre)
ressembuttag = pe_ressemtag.ResSemBUTTag(formsemestre, options=self.options)
self.ressembuttags[frmsem_id] = ressembuttag
# Ajoute les étudiants découverts dans les ressembuttags aux données des étudiants
# nbre_etudiants_ajoutes = self.etudiants.add_etudiants(
@ -529,9 +553,10 @@ class JuryPE(object):
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}", info=True)
output.seek(0)
self.add_file_to_zip(
zipfile, f"synthese_jury_{self.diplome}_par_tag.xlsx", output.read()
)
if onglets:
self.add_file_to_zip(
zipfile, f"synthese_jury_{self.diplome}_par_tag.xlsx", output.read()
)
def _gen_html_synthese_par_etudiant(self, zipfile: ZipFile):
"""Synthèse des éléments du jury PE, étudiant par étudiant"""

View File

@ -38,6 +38,7 @@
from flask import flash, g, redirect, render_template, request, send_file, url_for
from app.decorators import permission_required, scodoc
from app.forms.pe.pe_sem_recap import ParametrageClasseurPE
from app.models import FormSemestre
from app.pe import pe_comp
from app.pe import pe_jury
@ -72,35 +73,51 @@ def pe_view_sem_recap(formsemestre_id: int):
# Cosemestres diplomants
cosemestres = pe_comp.get_cosemestres_diplomants(annee_diplome)
form = ParametrageClasseurPE()
cosemestres_tries = pe_comp.tri_semestres_par_rang(cosemestres)
affichage_cosemestres_tries = {rang: ", ".join([sem.titre_annee() for sem in cosemestres_tries[rang]]) for rang in cosemestres_tries}
affichage_cosemestres_tries = {
rang: ", ".join([sem.titre_annee() for sem in cosemestres_tries[rang]])
for rang in cosemestres_tries
}
if request.method == "GET":
return render_template(
"pe/pe_view_sem_recap.j2",
annee_diplome=annee_diplome,
form=form,
formsemestre=formsemestre,
sco=ScoData(formsemestre=formsemestre),
cosemestres=affichage_cosemestres_tries,
rangs_tries=sorted(affichage_cosemestres_tries.keys())
rangs_tries=sorted(affichage_cosemestres_tries.keys()),
)
# request.method == "POST"
jury = pe_jury.JuryPE(annee_diplome)
if not jury.diplomes_ids:
flash("aucun étudiant à considérer !")
return redirect(
url_for(
"notes.pe_view_sem_recap",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
if form.validate_on_submit():
jury = pe_jury.JuryPE(annee_diplome, formsemestre_id, options=form.data)
if not jury.diplomes_ids:
flash("aucun étudiant à considérer !")
return redirect(
url_for(
"notes.pe_view_sem_recap",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
)
data = jury.get_zipped_data()
return send_file(
data,
mimetype="application/zip",
download_name=scu.sanitize_filename(jury.nom_export_zip + ".zip"),
as_attachment=True,
)
data = jury.get_zipped_data()
return send_file(
data,
mimetype="application/zip",
download_name=scu.sanitize_filename(jury.nom_export_zip + ".zip"),
as_attachment=True,
return redirect(
url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
)

View File

@ -1,4 +1,5 @@
{% extends "sco_page.j2" %}
{% import 'wtf.j2' as wtf %}
{% block styles %}
{{super()}}
@ -42,7 +43,7 @@
<h3>Avis de poursuites d'études de la promo {{ annee_diplome }}</h3>
<div class="help">
Seront pris en compte les étudiants ayant (au moins) été inscrits à l'un des semestres suivants :
<ul>
@ -52,24 +53,9 @@
</li>
{% endfor %}
</ul>
</div>
<div>
<progress id="pe_progress" style="visibility: hidden"></progress>
<br>
<button onclick="submitPEGeneration()">Générer les documents de la promo {{ annee_diplome }}</button>
</div>
<h3>Options</h3>
{{ wtf.quick_form(form) }}
<form method="post" id="pe_generation" style="visibility: hidden">
<input type="submit"
onclick="submitPEGeneration()" value=""/>
<input type="hidden" name="formsemestre_id" value="{{formsemestre.id}}">
</form>
<script>
function submitPEGeneration() {
// document.getElementById("pe_progress").style.visibility = 'visible';
document.getElementById("pe_generation").submit(); //attach an id to your form
}
</script>
{% endblock app_content %}