forked from ScoDoc/ScoDoc
Compare commits
10 Commits
fce23aa066
...
04d1fbe272
Author | SHA1 | Date | |
---|---|---|---|
04d1fbe272 | |||
c270c24c5b | |||
8b751608e1 | |||
0fb45fc9ca | |||
8652ef2e7b | |||
9be77e4f37 | |||
a00e2da461 | |||
3481f7c1c2 | |||
64d7e1ed42 | |||
d310304e9e |
|
@ -311,6 +311,13 @@ def group_create(partition_id: int): # partition-group-create
|
||||||
args["group_name"] = args["group_name"].strip()
|
args["group_name"] = args["group_name"].strip()
|
||||||
if not GroupDescr.check_name(partition, args["group_name"]):
|
if not GroupDescr.check_name(partition, args["group_name"]):
|
||||||
return json_error(API_CLIENT_ERROR, "invalid group_name")
|
return json_error(API_CLIENT_ERROR, "invalid group_name")
|
||||||
|
|
||||||
|
# le numero est optionnel
|
||||||
|
numero = args.get("numero")
|
||||||
|
if numero is None:
|
||||||
|
numeros = [gr.numero or 0 for gr in partition.groups]
|
||||||
|
numero = (max(numeros) + 1) if numeros else 0
|
||||||
|
args["numero"] = numero
|
||||||
args["partition_id"] = partition_id
|
args["partition_id"] = partition_id
|
||||||
try:
|
try:
|
||||||
group = GroupDescr(**args)
|
group = GroupDescr(**args)
|
||||||
|
|
|
@ -667,10 +667,12 @@ class BonusCalais(BonusSportAdditif):
|
||||||
sur 20 obtenus dans chacune des matières optionnelles sont cumulés
|
sur 20 obtenus dans chacune des matières optionnelles sont cumulés
|
||||||
dans la limite de 10 points. 6% de ces points cumulés s'ajoutent :
|
dans la limite de 10 points. 6% de ces points cumulés s'ajoutent :
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>en DUT</b> à la moyenne générale du semestre déjà obtenue par l'étudiant.
|
<li><b>en BUT</b> à la moyenne de chaque UE;
|
||||||
</li>
|
</li>
|
||||||
<li><b>en BUT et LP</b> à la moyenne des UE dont l'acronyme fini par <b>BS</b>
|
<li><b>en DUT</b> à la moyenne générale du semestre déjà obtenue par l'étudiant;
|
||||||
(ex : UE2.1BS, UE32BS)
|
</li>
|
||||||
|
<li><b>en LP</b>, et en BUT avant 2023-2024, à la moyenne de chaque UE dont
|
||||||
|
l'acronyme termine par <b>BS</b> (comme UE2.1BS, UE32BS).
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
"""
|
"""
|
||||||
|
@ -692,12 +694,17 @@ class BonusCalais(BonusSportAdditif):
|
||||||
else:
|
else:
|
||||||
self.classic_use_bonus_ues = True # pour les LP
|
self.classic_use_bonus_ues = True # pour les LP
|
||||||
super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan)
|
super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan)
|
||||||
ues = self.formsemestre.get_ues(with_sport=False)
|
if (
|
||||||
ues_sans_bs = [
|
self.formsemestre.annee_scolaire() < 2023
|
||||||
ue for ue in ues if ue.acronyme[-2:].upper() != "BS"
|
or not self.formsemestre.formation.is_apc()
|
||||||
] # les 2 derniers cars forcés en majus
|
):
|
||||||
for ue in ues_sans_bs:
|
# LP et anciens semestres: ne s'applique qu'aux UE dont l'acronyme termine par BS
|
||||||
self.bonus_ues[ue.id] = 0.0
|
ues = self.formsemestre.get_ues(with_sport=False)
|
||||||
|
ues_sans_bs = [
|
||||||
|
ue for ue in ues if ue.acronyme[-2:].upper() != "BS"
|
||||||
|
] # les 2 derniers cars forcés en majus
|
||||||
|
for ue in ues_sans_bs:
|
||||||
|
self.bonus_ues[ue.id] = 0.0
|
||||||
|
|
||||||
|
|
||||||
class BonusColmar(BonusSportAdditif):
|
class BonusColmar(BonusSportAdditif):
|
||||||
|
|
|
@ -98,142 +98,162 @@ class JuryPE(object):
|
||||||
self.nom_export_zip = f"Jury_PE_{self.diplome}"
|
self.nom_export_zip = f"Jury_PE_{self.diplome}"
|
||||||
"Nom du zip où ranger les fichiers générés"
|
"Nom du zip où ranger les fichiers générés"
|
||||||
|
|
||||||
|
# Chargement des étudiants à prendre en compte dans le jury
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
f"""*** Recherche et chargement des étudiants diplômés en {
|
||||||
|
self.diplome} pour la formation {self.formation_id}"""
|
||||||
|
)
|
||||||
|
self.etudiants = EtudiantsJuryPE(self.diplome) # Les infos sur les étudiants
|
||||||
|
self.etudiants.find_etudiants(self.formation_id)
|
||||||
|
self.diplomes_ids = self.etudiants.diplomes_ids
|
||||||
|
|
||||||
self.zipdata = io.BytesIO()
|
self.zipdata = io.BytesIO()
|
||||||
|
|
||||||
with ZipFile(self.zipdata, "w") as zipfile:
|
with ZipFile(self.zipdata, "w") as zipfile:
|
||||||
# Chargement des étudiants à prendre en compte dans le jury
|
|
||||||
pe_affichage.pe_print(
|
|
||||||
f"""*** Recherche et chargement des étudiants diplômés en {
|
|
||||||
self.diplome} pour la formation {self.formation_id}"""
|
|
||||||
)
|
|
||||||
self.etudiants = EtudiantsJuryPE(
|
|
||||||
self.diplome
|
|
||||||
) # Les infos sur les étudiants
|
|
||||||
self.etudiants.find_etudiants(self.formation_id)
|
|
||||||
self.diplomes_ids = self.etudiants.diplomes_ids
|
|
||||||
|
|
||||||
# Intègre le bilan des semestres taggués au zip final
|
|
||||||
output = io.BytesIO()
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
|
||||||
if self.diplomes_ids:
|
|
||||||
onglet = "diplômés"
|
|
||||||
df_diplome = self.etudiants.df_administratif(self.diplomes_ids)
|
|
||||||
df_diplome.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
if self.etudiants.abandons_ids:
|
|
||||||
onglet = "redoublants-réorientés"
|
|
||||||
df_abandon = self.etudiants.df_administratif(
|
|
||||||
self.etudiants.abandons_ids
|
|
||||||
)
|
|
||||||
df_abandon.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
self.add_file_to_zip(
|
|
||||||
zipfile,
|
|
||||||
f"etudiants_{self.diplome}.xlsx",
|
|
||||||
output.read(),
|
|
||||||
path="details",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not self.diplomes_ids:
|
if not self.diplomes_ids:
|
||||||
pe_affichage.pe_tools("*** Aucun étudiant diplômé")
|
pe_affichage.pe_print("*** Aucun étudiant diplômé")
|
||||||
else:
|
else:
|
||||||
# Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE
|
self._gen_xls_diplomes(zipfile)
|
||||||
pe_affichage.pe_print("*** Génère les semestres taggués")
|
self._gen_xls_semestre_taggues(zipfile)
|
||||||
self.semestres_taggues = compute_semestres_tag(self.etudiants)
|
self._gen_xls_trajectoires(zipfile)
|
||||||
|
self._gen_xls_aggregats(zipfile)
|
||||||
# Intègre le bilan des semestres taggués au zip final
|
self._gen_xls_synthese(zipfile)
|
||||||
output = io.BytesIO()
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
|
||||||
for formsemestretag in self.semestres_taggues.values():
|
|
||||||
onglet = formsemestretag.nom
|
|
||||||
df = formsemestretag.df_moyennes_et_classements()
|
|
||||||
# écriture dans l'onglet
|
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
self.add_file_to_zip(
|
|
||||||
zipfile,
|
|
||||||
f"semestres_taggues_{self.diplome}.xlsx",
|
|
||||||
output.read(),
|
|
||||||
path="details",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Génère les trajectoires (combinaison de semestres suivis
|
|
||||||
# par un étudiant pour atteindre le semestre final d'un aggrégat)
|
|
||||||
pe_affichage.pe_print(
|
|
||||||
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
|
||||||
)
|
|
||||||
self.trajectoires = TrajectoiresJuryPE(self.diplome)
|
|
||||||
self.trajectoires.cree_trajectoires(self.etudiants)
|
|
||||||
|
|
||||||
# Génère les moyennes par tags des trajectoires
|
|
||||||
pe_affichage.pe_print(
|
|
||||||
"*** Calcule les moyennes par tag des trajectoires possibles"
|
|
||||||
)
|
|
||||||
self.trajectoires_tagguees = compute_trajectoires_tag(
|
|
||||||
self.trajectoires, self.etudiants, self.semestres_taggues
|
|
||||||
)
|
|
||||||
|
|
||||||
# Intègre le bilan des trajectoires tagguées au zip final
|
|
||||||
output = io.BytesIO()
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
|
||||||
for trajectoire_tagguee in self.trajectoires_tagguees.values():
|
|
||||||
onglet = trajectoire_tagguee.get_repr()
|
|
||||||
df = trajectoire_tagguee.df_moyennes_et_classements()
|
|
||||||
# écriture dans l'onglet
|
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
self.add_file_to_zip(
|
|
||||||
zipfile,
|
|
||||||
f"trajectoires_taggues_{self.diplome}.xlsx",
|
|
||||||
output.read(),
|
|
||||||
path="details",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Génère les interclassements (par promo et) par (nom d') aggrégat
|
|
||||||
pe_affichage.pe_print("*** Génère les interclassements par aggrégat")
|
|
||||||
self.interclassements_taggues = compute_interclassements(
|
|
||||||
self.etudiants, self.trajectoires, self.trajectoires_tagguees
|
|
||||||
)
|
|
||||||
|
|
||||||
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
|
|
||||||
output = io.BytesIO()
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
|
||||||
for interclass_tag in self.interclassements_taggues.values():
|
|
||||||
if interclass_tag.significatif: # Avec des notes
|
|
||||||
onglet = interclass_tag.get_repr()
|
|
||||||
df = interclass_tag.df_moyennes_et_classements()
|
|
||||||
# écriture dans l'onglet
|
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
self.add_file_to_zip(
|
|
||||||
zipfile,
|
|
||||||
f"interclassements_taggues_{self.diplome}.xlsx",
|
|
||||||
output.read(),
|
|
||||||
path="details",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Synthèse des éléments du jury PE
|
|
||||||
self.synthese = self.synthetise_juryPE()
|
|
||||||
|
|
||||||
# Export des données => mode 1 seule feuille -> supprimé
|
|
||||||
pe_affichage.pe_print("*** Export du jury de synthese")
|
|
||||||
output = io.BytesIO()
|
|
||||||
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
|
||||||
for onglet, df in self.synthese.items():
|
|
||||||
# écriture dans l'onglet:
|
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
self.add_file_to_zip(
|
|
||||||
zipfile, f"synthese_jury_{self.diplome}.xlsx", output.read()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Fin !!!! Tada :)
|
# Fin !!!! Tada :)
|
||||||
|
|
||||||
|
def _gen_xls_diplomes(self, zipfile: ZipFile):
|
||||||
|
"Intègre le bilan des semestres taggués au zip"
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
if self.diplomes_ids:
|
||||||
|
onglet = "diplômés"
|
||||||
|
df_diplome = self.etudiants.df_administratif(self.diplomes_ids)
|
||||||
|
df_diplome.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
if self.etudiants.abandons_ids:
|
||||||
|
onglet = "redoublants-réorientés"
|
||||||
|
df_abandon = self.etudiants.df_administratif(
|
||||||
|
self.etudiants.abandons_ids
|
||||||
|
)
|
||||||
|
df_abandon.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile,
|
||||||
|
f"etudiants_{self.diplome}.xlsx",
|
||||||
|
output.read(),
|
||||||
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _gen_xls_semestre_taggues(self, zipfile: ZipFile):
|
||||||
|
"Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE"
|
||||||
|
pe_affichage.pe_print("*** Génère les semestres taggués")
|
||||||
|
self.semestres_taggues = compute_semestres_tag(self.etudiants)
|
||||||
|
|
||||||
|
# Intègre le bilan des semestres taggués au zip final
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
for formsemestretag in self.semestres_taggues.values():
|
||||||
|
onglet = formsemestretag.nom
|
||||||
|
df = formsemestretag.df_moyennes_et_classements()
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile,
|
||||||
|
f"semestres_taggues_{self.diplome}.xlsx",
|
||||||
|
output.read(),
|
||||||
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _gen_xls_trajectoires(self, zipfile: ZipFile):
|
||||||
|
"""Génère les trajectoires (combinaison de semestres suivis
|
||||||
|
par un étudiant pour atteindre le semestre final d'un aggrégat)
|
||||||
|
"""
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
||||||
|
)
|
||||||
|
self.trajectoires = TrajectoiresJuryPE(self.diplome)
|
||||||
|
self.trajectoires.cree_trajectoires(self.etudiants)
|
||||||
|
|
||||||
|
# Génère les moyennes par tags des trajectoires
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
"*** Calcule les moyennes par tag des trajectoires possibles"
|
||||||
|
)
|
||||||
|
self.trajectoires_tagguees = compute_trajectoires_tag(
|
||||||
|
self.trajectoires, self.etudiants, self.semestres_taggues
|
||||||
|
)
|
||||||
|
|
||||||
|
# Intègre le bilan des trajectoires tagguées au zip final
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
for trajectoire_tagguee in self.trajectoires_tagguees.values():
|
||||||
|
onglet = trajectoire_tagguee.get_repr()
|
||||||
|
df = trajectoire_tagguee.df_moyennes_et_classements()
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile,
|
||||||
|
f"trajectoires_taggues_{self.diplome}.xlsx",
|
||||||
|
output.read(),
|
||||||
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _gen_xls_aggregats(self, zipfile: ZipFile):
|
||||||
|
"""Intègre le bilan des aggrégats (interclassé par promo) au zip"""
|
||||||
|
# Génère les interclassements (par promo et) par (nom d') aggrégat
|
||||||
|
pe_affichage.pe_print("*** Génère les interclassements par aggrégat")
|
||||||
|
self.interclassements_taggues = compute_interclassements(
|
||||||
|
self.etudiants, self.trajectoires, self.trajectoires_tagguees
|
||||||
|
)
|
||||||
|
|
||||||
|
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
for interclass_tag in self.interclassements_taggues.values():
|
||||||
|
if interclass_tag.significatif: # Avec des notes
|
||||||
|
onglet = interclass_tag.get_repr()
|
||||||
|
df = interclass_tag.df_moyennes_et_classements()
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile,
|
||||||
|
f"interclassements_taggues_{self.diplome}.xlsx",
|
||||||
|
output.read(),
|
||||||
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _gen_xls_synthese(self, zipfile: ZipFile):
|
||||||
|
"""Synthèse des éléments du jury PE"""
|
||||||
|
# Synthèse des éléments du jury PE
|
||||||
|
self.synthese = self.synthetise_juryPE()
|
||||||
|
|
||||||
|
# Export des données => mode 1 seule feuille -> supprimé
|
||||||
|
pe_affichage.pe_print("*** Export du jury de synthese")
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
for onglet, df in self.synthese.items():
|
||||||
|
# écriture dans l'onglet:
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile, f"synthese_jury_{self.diplome}.xlsx", output.read()
|
||||||
|
)
|
||||||
|
|
||||||
def add_file_to_zip(self, zipfile: ZipFile, filename: str, data, path=""):
|
def add_file_to_zip(self, zipfile: ZipFile, filename: str, data, path=""):
|
||||||
"""Add a file to given zip
|
"""Add a file to given zip
|
||||||
All files under NOM_EXPORT_ZIP/
|
All files under NOM_EXPORT_ZIP/
|
||||||
|
|
|
@ -150,6 +150,10 @@ class TrajectoireTag(TableTag):
|
||||||
etudids_communs, tags_communs
|
etudids_communs, tags_communs
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Supprime tout ce qui n'est pas numérique
|
||||||
|
for col in df.columns:
|
||||||
|
df[col] = pd.to_numeric(df[col], errors="coerce")
|
||||||
|
|
||||||
"""Stocke le df"""
|
"""Stocke le df"""
|
||||||
dfs[frmsem_id] = df
|
dfs[frmsem_id] = df
|
||||||
|
|
||||||
|
|
|
@ -35,113 +35,59 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import send_file, request
|
from flask import flash, g, redirect, render_template, request, send_file, url_for
|
||||||
|
|
||||||
|
from app.decorators import permission_required, scodoc
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
from app.scodoc import html_sco_header
|
|
||||||
from app.scodoc import sco_preferences
|
|
||||||
|
|
||||||
from app.pe import pe_comp
|
from app.pe import pe_comp
|
||||||
from app.pe import pe_jury
|
from app.pe import pe_jury
|
||||||
|
from app.views import ScoData
|
||||||
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
from app.views import notes_bp as bp
|
||||||
|
|
||||||
|
|
||||||
def _pe_view_sem_recap_form(formsemestre_id):
|
@bp.route("/pe_view_sem_recap/<int:formsemestre_id>", methods=("GET", "POST"))
|
||||||
sem_base = FormSemestre.get_formsemestre(formsemestre_id)
|
@scodoc
|
||||||
if not sem_base.formation.is_apc() or sem_base.formation.get_cursus().NB_SEM < 6:
|
@permission_required(Permission.ScoView)
|
||||||
H = [
|
def pe_view_sem_recap(formsemestre_id: int):
|
||||||
html_sco_header.sco_header(page_title="Avis de poursuite d'études"),
|
|
||||||
"""<h2 class="formsemestre">Génération des avis de poursuites d'études (V2 BUT EXPERIMENTALE)</h2>
|
|
||||||
<p class="help">
|
|
||||||
Cette fonction génère un ensemble de fichiers permettant d'éditer des avis de
|
|
||||||
poursuites d'études.
|
|
||||||
<br>
|
|
||||||
De nombreux aspects sont paramétrables:
|
|
||||||
<a href="https://scodoc.org/AvisPoursuiteEtudes"
|
|
||||||
target="_blank" rel="noopener noreferrer">
|
|
||||||
voir la documentation (en cours de révision)
|
|
||||||
</a>.
|
|
||||||
Cette fonction (en Scodoc9) n'est prévue que pour le BUT.
|
|
||||||
<br>
|
|
||||||
Rendez-vous donc sur un semestre de BUT.
|
|
||||||
</p>
|
|
||||||
""",
|
|
||||||
]
|
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
|
||||||
|
|
||||||
# L'année du diplome
|
|
||||||
diplome = pe_comp.get_annee_diplome_semestre(sem_base)
|
|
||||||
|
|
||||||
H = [
|
|
||||||
html_sco_header.sco_header(page_title="Avis de poursuite d'études"),
|
|
||||||
f"""<h2 class="formsemestre">Génération des avis de poursuites d'études (V2 BUT EXPERIMENTALE)</h2>
|
|
||||||
|
|
||||||
<div class="alert-warning">
|
|
||||||
Fonction expérimentale pour le BUT : travaux en cours, merci de tester
|
|
||||||
et de faire part de vos expériences sur le Discord.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="help">
|
|
||||||
Cette fonction génère un ensemble de fichiers permettant d'éditer des avis de
|
|
||||||
poursuites d'études pour les étudiants diplômés en {diplome}.
|
|
||||||
<br>
|
|
||||||
De nombreux aspects sont paramétrables:
|
|
||||||
<a href="https://scodoc.org/AvisPoursuiteEtudes"
|
|
||||||
target="_blank" rel="noopener noreferrer">
|
|
||||||
voir la documentation
|
|
||||||
</a> (en cours de révision).
|
|
||||||
</p>
|
|
||||||
<form method="post" action="pe_view_sem_recap" id="pe_view_sem_recap_form"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
<div class="pe_template_up">
|
|
||||||
Les templates sont généralement installés sur le serveur ou dans le
|
|
||||||
paramétrage de ScoDoc.
|
|
||||||
<br>
|
|
||||||
Au besoin, vous pouvez spécifier ici votre propre fichier de template
|
|
||||||
(<tt>un_avis.tex</tt>):
|
|
||||||
<div class="pe_template_upb">Template:
|
|
||||||
<input type="file" size="30" name="avis_tmpl_file"/>
|
|
||||||
</div>
|
|
||||||
<div class="pe_template_upb">Pied de page:
|
|
||||||
<input type="file" size="30" name="footer_tmpl_file"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="submit" value="Générer les documents"/>
|
|
||||||
<input type="hidden" name="formsemestre_id" value="{formsemestre_id}">
|
|
||||||
</form>
|
|
||||||
""",
|
|
||||||
]
|
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
|
||||||
|
|
||||||
|
|
||||||
# called from the web, POST or GET
|
|
||||||
def pe_view_sem_recap(
|
|
||||||
formsemestre_id,
|
|
||||||
avis_tmpl_file=None,
|
|
||||||
footer_tmpl_file=None,
|
|
||||||
):
|
|
||||||
"""Génération des avis de poursuite d'étude"""
|
"""Génération des avis de poursuite d'étude"""
|
||||||
if request.method == "GET":
|
|
||||||
return _pe_view_sem_recap_form(formsemestre_id)
|
|
||||||
prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
|
|
||||||
|
|
||||||
sem_base = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
if not sem_base.formation.is_apc():
|
if not formsemestre.formation.is_apc():
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"Le module de Poursuites d'Etudes avec Scodoc 9 n'est disponible que pour des formations BUT"
|
"""Le module de Poursuites d'Etudes
|
||||||
|
n'est disponible que pour des formations BUT"""
|
||||||
)
|
)
|
||||||
|
|
||||||
if sem_base.formation.get_cursus().NB_SEM < 6:
|
if formsemestre.formation.get_cursus().NB_SEM < 6:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"Le module de Poursuites d'Etudes avec Scodoc 9 n'est pas prévu pour une formation de moins de 6 semestres"
|
"""Le module de Poursuites d'Etudes n'est pas prévu
|
||||||
|
pour une formation de moins de 6 semestres"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# L'année du diplome
|
# L'année du diplome
|
||||||
diplome = pe_comp.get_annee_diplome_semestre(sem_base)
|
annee_diplome = pe_comp.get_annee_diplome_semestre(formsemestre)
|
||||||
|
|
||||||
jury = pe_jury.JuryPE(diplome, sem_base.formation.formation_id)
|
if request.method == "GET":
|
||||||
|
return render_template(
|
||||||
|
"pe/pe_view_sem_recap.j2",
|
||||||
|
annee_diplome=annee_diplome,
|
||||||
|
formsemestre=formsemestre,
|
||||||
|
sco=ScoData(formsemestre=formsemestre),
|
||||||
|
)
|
||||||
|
|
||||||
|
jury = pe_jury.JuryPE(annee_diplome, formsemestre.formation.formation_id)
|
||||||
|
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()
|
data = jury.get_zipped_data()
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,9 @@ from app.scodoc.sco_formsemestre_custommenu import formsemestre_custommenu_html
|
||||||
import sco_version
|
import sco_version
|
||||||
|
|
||||||
|
|
||||||
def _build_menu_stats(formsemestre_id):
|
def _build_menu_stats(formsemestre: FormSemestre):
|
||||||
"Définition du menu 'Statistiques'"
|
"Définition du menu 'Statistiques'"
|
||||||
|
formsemestre_id = formsemestre.id
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"title": "Statistiques...",
|
"title": "Statistiques...",
|
||||||
|
@ -123,7 +124,8 @@ def _build_menu_stats(formsemestre_id):
|
||||||
"title": "Documents Avis Poursuite Etudes (xp)",
|
"title": "Documents Avis Poursuite Etudes (xp)",
|
||||||
"endpoint": "notes.pe_view_sem_recap",
|
"endpoint": "notes.pe_view_sem_recap",
|
||||||
"args": {"formsemestre_id": formsemestre_id},
|
"args": {"formsemestre_id": formsemestre_id},
|
||||||
"enabled": True, # current_app.config["TESTING"] or current_app.config["DEBUG"],
|
"enabled": formsemestre.formation.is_apc(),
|
||||||
|
# current_app.config["TESTING"] or current_app.config["DEBUG"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": 'Table "débouchés"',
|
"title": 'Table "débouchés"',
|
||||||
|
@ -462,7 +464,7 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str:
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
menu_stats = _build_menu_stats(formsemestre_id)
|
menu_stats = _build_menu_stats(formsemestre)
|
||||||
H = [
|
H = [
|
||||||
'<ul id="sco_menu">',
|
'<ul id="sco_menu">',
|
||||||
htmlutils.make_menu("Semestre", menu_semestre),
|
htmlutils.make_menu("Semestre", menu_semestre),
|
||||||
|
|
|
@ -197,13 +197,15 @@ def formsemestre_poursuite_report(formsemestre_id, fmt="html"):
|
||||||
info = etud_get_poursuite_info(sem, etud)
|
info = etud_get_poursuite_info(sem, etud)
|
||||||
idd = _flatten_info(info)
|
idd = _flatten_info(info)
|
||||||
# On recupere la totalite des UEs dans ids
|
# On recupere la totalite des UEs dans ids
|
||||||
for id in idd:
|
for key in idd:
|
||||||
if id not in ids:
|
if key not in ids:
|
||||||
ids += [id]
|
ids += [key]
|
||||||
|
info["etudid"] = etud["etudid"]
|
||||||
infos.append(info)
|
infos.append(info)
|
||||||
#
|
#
|
||||||
column_ids = (
|
column_ids = (
|
||||||
("civilite_str", "nom", "prenom", "annee", "date_naissance")
|
(("etudid",) if fmt.startswith("xls") else ())
|
||||||
|
+ ("civilite_str", "nom", "prenom", "annee", "date_naissance")
|
||||||
+ tuple(ids)
|
+ tuple(ids)
|
||||||
+ ("debouche",)
|
+ ("debouche",)
|
||||||
)
|
)
|
||||||
|
|
48
app/templates/pe/pe_view_sem_recap.j2
Normal file
48
app/templates/pe/pe_view_sem_recap.j2
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends "sco_page.j2" %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{super()}}
|
||||||
|
<style>
|
||||||
|
.div-warning {
|
||||||
|
color: red;
|
||||||
|
background-color: yellow;
|
||||||
|
font-size: 120%;
|
||||||
|
border: 2px solid red;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock styles %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
|
<h2>Génération des avis de poursuites d'études (V2 BUT EXPERIMENTALE)</h2>
|
||||||
|
|
||||||
|
<div class="div-warning">
|
||||||
|
Fonction expérimentale pour le BUT : travaux en cours, merci de tester
|
||||||
|
et de faire part de vos expériences sur le Discord.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="help">
|
||||||
|
<p>
|
||||||
|
Cette fonction génère un ensemble de feuilles de calcul (xlsx)
|
||||||
|
permettant d'éditer des avis de poursuites d'études pour les étudiants
|
||||||
|
de BUT diplômés en {{annee_diplome}}.
|
||||||
|
<br>
|
||||||
|
De nombreux aspects sont paramétrables:
|
||||||
|
<a href="https://scodoc.org/AvisPoursuiteEtudes"
|
||||||
|
target="_blank" rel="noopener noreferrer">
|
||||||
|
voir la documentation
|
||||||
|
</a> (en cours de révision).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<input type="submit" value="Générer les documents"/>
|
||||||
|
<input type="hidden" name="formsemestre_id" value="{{formsemestre.id}}">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock app_content %}
|
|
@ -87,22 +87,18 @@ from app.decorators import (
|
||||||
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
|
from app.pe import pe_view # ne pas enlever, ajoute des vues
|
||||||
from app.scodoc import sco_bulletins_json, sco_utils as scu
|
from app.scodoc import sco_bulletins_json, sco_utils as scu
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app import log, send_scodoc_alarm
|
from app import log, send_scodoc_alarm
|
||||||
|
|
||||||
from app.scodoc.scolog import logdb
|
|
||||||
|
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
ScoInvalidIdType,
|
ScoInvalidIdType,
|
||||||
)
|
)
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.pe import pe_view
|
|
||||||
from app.scodoc import sco_apogee_compare
|
from app.scodoc import sco_apogee_compare
|
||||||
from app.scodoc import sco_archives
|
|
||||||
from app.scodoc import sco_archives_formsemestre
|
from app.scodoc import sco_archives_formsemestre
|
||||||
from app.scodoc import sco_assiduites
|
from app.scodoc import sco_assiduites
|
||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
|
@ -139,7 +135,6 @@ from app.scodoc import sco_lycee
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_moduleimpl_inscriptions
|
from app.scodoc import sco_moduleimpl_inscriptions
|
||||||
from app.scodoc import sco_moduleimpl_status
|
from app.scodoc import sco_moduleimpl_status
|
||||||
from app.scodoc import sco_permissions_check
|
|
||||||
from app.scodoc import sco_placement
|
from app.scodoc import sco_placement
|
||||||
from app.scodoc import sco_poursuite_dut
|
from app.scodoc import sco_poursuite_dut
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
|
@ -3253,12 +3248,6 @@ sco_publish(
|
||||||
sco_poursuite_dut.formsemestre_poursuite_report,
|
sco_poursuite_dut.formsemestre_poursuite_report,
|
||||||
Permission.ScoView,
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
sco_publish(
|
|
||||||
"/pe_view_sem_recap",
|
|
||||||
pe_view.pe_view_sem_recap,
|
|
||||||
Permission.ScoView,
|
|
||||||
methods=["GET", "POST"],
|
|
||||||
)
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/report_debouche_date", sco_debouche.report_debouche_date, Permission.ScoView
|
"/report_debouche_date", sco_debouche.report_debouche_date, Permission.ScoView
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.6.86"
|
SCOVERSION = "9.6.88"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user